This commit is contained in:
Ali 2020-12-22 18:51:36 +04:00
parent ea73e0b9af
commit 03fa913557
14 changed files with 621 additions and 423 deletions

View File

@ -1162,11 +1162,20 @@ swift_library(
module_name = "WidgetExtensionLib",
srcs = glob([
"WidgetKitWidget/**/*.swift",
"Generated/**/*.swift",
]),
data = [
"SiriIntents/Intents.intentdefinition",
],
deps = [
"//submodules/BuildConfig:BuildConfig",
"//submodules/WidgetItems:WidgetItems",
"//submodules/AppLockState:AppLockState",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Postbox:Postbox",
"//submodules/TelegramCore:TelegramCore",
"//submodules/SyncCore:SyncCore",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
],
)
@ -1188,7 +1197,12 @@ ios_extension(
provides_main = True,
provisioning_profile = "//build-input/data/provisioning-profiles:Widget.mobileprovision",
deps = [":WidgetExtensionLib"],
frameworks = [],
frameworks = [
":SwiftSignalKitFramework",
":PostboxFramework",
":SyncCoreFramework",
":TelegramCoreFramework",
],
)
plist_fragment(
@ -1219,6 +1233,7 @@ plist_fragment(
<string>INSearchForMessagesIntent</string>
<string>INSetMessageAttributeIntent</string>
<string>INSearchCallHistoryIntent</string>
<string>SelectFriendsIntent</string>
</array>
</dict>
<key>NSExtensionPointIdentifier</key>
@ -1236,7 +1251,11 @@ swift_library(
module_name = "IntentsExtensionLib",
srcs = glob([
"SiriIntents/**/*.swift",
"Generated/**/*.swift",
]),
data = [
"SiriIntents/Intents.intentdefinition",
],
deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Postbox:Postbox",
@ -1528,12 +1547,13 @@ ios_application(
strings = [
":AppStringResources",
],
extensions = [] if telegram_disable_extensions else [
extensions = [
] if telegram_disable_extensions else [
":ShareExtension",
":NotificationContentExtension",
":NotificationServiceExtension",
":IntentsExtension",
#":WidgetExtension",
":WidgetExtension",
],
watch_application = ":TelegramWatchApp",
deps = [

View File

@ -0,0 +1,36 @@
//
// Contents.swift
//
// This file was automatically generated and should not be edited.
//
#if canImport(Intents)
import Intents
@available(iOS 12.0, macOS 10.16, watchOS 5.0, *) @available(tvOS, unavailable)
@objc public enum Contents: Int {
case `unknown` = 0
case `recent` = 1
case `custom` = 2
}
@available(iOS 13.0, macOS 10.16, watchOS 6.0, *) @available(tvOS, unavailable)
@objc(ContentsResolutionResult)
public class ContentsResolutionResult: INEnumResolutionResult {
// This resolution result is for when the app extension wants to tell Siri to proceed, with a given Contents. The resolvedValue can be different than the original Contents. This allows app extensions to apply business logic constraints.
// Use notRequired() to continue with a 'nil' value.
@objc(successWithResolvedContents:)
public class func success(with resolvedValue: Contents) -> Self {
return __success(withResolvedValue: resolvedValue.rawValue)
}
// This resolution result is to ask Siri to confirm if this is the value with which the user wants to continue.
@objc(confirmationRequiredWithContentsToConfirm:)
public class func confirmationRequired(with valueToConfirm: Contents) -> Self {
return __confirmationRequiredWithValue(toConfirm: valueToConfirm.rawValue)
}
}
#endif

View File

@ -0,0 +1,60 @@
//
// Friend.swift
//
// This file was automatically generated and should not be edited.
//
#if canImport(Intents)
import Intents
@available(iOS 12.0, macOS 10.16, watchOS 5.0, *) @available(tvOS, unavailable)
@objc(Friend)
public class Friend: INObject {
@available(iOS 13.0, macOS 10.16, watchOS 6.0, *)
@NSManaged public var subtitle: String?
}
@available(iOS 13.0, macOS 10.16, watchOS 6.0, *) @available(tvOS, unavailable)
@objc(FriendResolutionResult)
public class FriendResolutionResult: INObjectResolutionResult {
// This resolution result is for when the app extension wants to tell Siri to proceed, with a given Friend. The resolvedValue can be different than the original Friend. This allows app extensions to apply business logic constraints.
// Use notRequired() to continue with a 'nil' value.
@objc(successWithResolvedFriend:)
public class func success(with resolvedObject: Friend) -> Self {
return super.success(with: resolvedObject) as! Self
}
// This resolution result is to ask Siri to disambiguate between the provided Friend.
@objc(disambiguationWithFriendsToDisambiguate:)
public class func disambiguation(with objectsToDisambiguate: [Friend]) -> Self {
return super.disambiguation(with: objectsToDisambiguate) as! Self
}
// This resolution result is to ask Siri to confirm if this is the value with which the user wants to continue.
@objc(confirmationRequiredWithFriendToConfirm:)
public class func confirmationRequired(with objectToConfirm: Friend?) -> Self {
return super.confirmationRequired(with: objectToConfirm) as! Self
}
@available(*, unavailable)
override public class func success(with resolvedObject: INObject) -> Self {
fatalError()
}
@available(*, unavailable)
override public class func disambiguation(with objectsToDisambiguate: [INObject]) -> Self {
fatalError()
}
@available(*, unavailable)
override public class func confirmationRequired(with objectToConfirm: INObject?) -> Self {
fatalError()
}
}
#endif

View File

@ -0,0 +1,120 @@
//
// SelectFriendsIntent.swift
//
// This file was automatically generated and should not be edited.
//
#if canImport(Intents)
import Intents
@available(iOS 12.0, macOS 10.16, watchOS 5.0, *) @available(tvOS, unavailable)
@objc(SelectFriendsIntent)
public class SelectFriendsIntent: INIntent {
@NSManaged public var contents: Contents
@NSManaged public var friends: [Friend]?
}
/*!
@abstract Protocol to declare support for handling a SelectFriendsIntent. By implementing this protocol, a class can provide logic for resolving, confirming and handling the intent.
@discussion The minimum requirement for an implementing class is that it should be able to handle the intent. The confirmation method is optional. The handling method is always called last, after confirming the intent.
*/
@available(iOS 12.0, macOS 10.16, watchOS 5.0, *) @available(tvOS, unavailable)
@objc(SelectFriendsIntentHandling)
public protocol SelectFriendsIntentHandling: NSObjectProtocol {
/*!
@abstract Dynamic options methods - provide options for the parameter at runtime
@discussion Called to query dynamic options for the parameter and this intent in its current form.
@param intent The input intent
@param completion The response block contains options for the parameter
*/
@available(iOS 14.0, macOS 10.16, watchOS 7.0, *)
@objc(provideFriendsOptionsCollectionForSelectFriends:withCompletion:)
func provideFriendsOptionsCollection(for intent: SelectFriendsIntent, with completion: @escaping (INObjectCollection<Friend>?, Error?) -> Swift.Void)
/*!
@abstract Confirmation method - Validate that this intent is ready for the next step (i.e. handling)
@discussion Called prior to asking the app to handle the intent. The app should return a response object that contains additional information about the intent, which may be relevant for the system to show the user prior to handling. If unimplemented, the system will assume the intent is valid, and will assume there is no additional information relevant to this intent.
@param intent The input intent
@param completion The response block contains a SelectFriendsIntentResponse containing additional details about the intent that may be relevant for the system to show the user prior to handling.
@see SelectFriendsIntentResponse
*/
@objc(confirmSelectFriends:completion:)
optional func confirm(intent: SelectFriendsIntent, completion: @escaping (SelectFriendsIntentResponse) -> Swift.Void)
/*!
@abstract Handling method - Execute the task represented by the SelectFriendsIntent that's passed in
@discussion Called to actually execute the intent. The app must return a response for this intent.
@param intent The input intent
@param completion The response handling block takes a SelectFriendsIntentResponse containing the details of the result of having executed the intent
@see SelectFriendsIntentResponse
*/
@objc(handleSelectFriends:completion:)
optional func handle(intent: SelectFriendsIntent, completion: @escaping (SelectFriendsIntentResponse) -> Swift.Void)
/*!
@abstract Default values for parameters with dynamic options
@discussion Called to query the parameter default value.
*/
@available(iOS 14.0, macOS 10.16, watchOS 7.0, *)
@objc(defaultFriendsForSelectFriends:)
optional func defaultFriends(for intent: SelectFriendsIntent) -> [Friend]?
/*!
@abstract Deprecated dynamic options methods.
*/
@available(iOS, introduced: 13.0, deprecated: 14.0, message: "")
@available(watchOS, introduced: 6.0, deprecated: 7.0, message: "")
@objc(provideFriendsOptionsForSelectFriends:withCompletion:)
optional func provideFriendsOptions(for intent: SelectFriendsIntent, with completion: @escaping ([Friend]?, Error?) -> Swift.Void)
}
/*!
@abstract Constants indicating the state of the response.
*/
@available(iOS 12.0, macOS 10.16, watchOS 5.0, *) @available(tvOS, unavailable)
@objc public enum SelectFriendsIntentResponseCode: Int {
case unspecified = 0
case ready
case continueInApp
case inProgress
case success
case failure
case failureRequiringAppLaunch
}
@available(iOS 12.0, macOS 10.16, watchOS 5.0, *) @available(tvOS, unavailable)
@objc(SelectFriendsIntentResponse)
public class SelectFriendsIntentResponse: INIntentResponse {
/*!
@abstract The response code indicating your success or failure in confirming or handling the intent.
*/
@objc public fileprivate(set) var code: SelectFriendsIntentResponseCode = .unspecified
/*!
@abstract Initializes the response object with the specified code and user activity object.
@discussion The app extension has the option of capturing its private state as an NSUserActivity and returning it as the 'currentActivity'. If the app is launched, an NSUserActivity will be passed in with the private state. The NSUserActivity may also be used to query the app's UI extension (if provided) for a view controller representing the current intent handling state. In the case of app launch, the NSUserActivity will have its activityType set to the name of the intent. This intent object will also be available in the NSUserActivity.interaction property.
@param code The response code indicating your success or failure in confirming or handling the intent.
@param userActivity The user activity object to use when launching your app. Provide an object if you want to add information that is specific to your app. If you specify nil, the system automatically creates a user activity object for you, sets its type to the class name of the intent being handled, and fills it with an INInteraction object containing the intent and your response.
*/
@objc(initWithCode:userActivity:)
public convenience init(code: SelectFriendsIntentResponseCode, userActivity: NSUserActivity?) {
self.init()
self.code = code
self.userActivity = userActivity
}
}
#endif

View File

@ -8,6 +8,7 @@ import BuildConfig
import Contacts
import OpenSSLEncryptionProvider
import AppLockState
import UIKit
private var accountCache: Account?
@ -52,7 +53,7 @@ enum IntentHandlingError {
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
@objc(IntentHandler)
public class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling, INStartAudioCallIntentHandling, INSearchCallHistoryIntentHandling {
class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling, INStartAudioCallIntentHandling, INSearchCallHistoryIntentHandling, SelectFriendsIntentHandling {
private let accountPromise = Promise<Account?>()
private let resolvePersonsDisposable = MetaDisposable()
@ -697,4 +698,47 @@ public class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo
completion(response)
}))
}
@available(iOSApplicationExtension 14.0, iOS 14.0, *)
func provideFriendsOptionsCollection(for intent: SelectFriendsIntent, with completion: @escaping (INObjectCollection<Friend>?, Error?) -> Void) {
let _ = (self.accountPromise.get()
|> take(1)
|> mapToSignal { account -> Signal<[Friend], NoError> in
guard let account = account else {
return .single([])
}
return account.postbox.transaction { transaction -> [Friend] in
var peers: [Peer] = []
outer: for peerId in transaction.getContactPeerIds() {
if let peer = transaction.getPeer(peerId) as? TelegramUser {
peers.append(peer)
}
}
peers.sort(by: { lhs, rhs in
return lhs.debugDisplayTitle < rhs.debugDisplayTitle
})
var result: [Friend] = []
for peer in peers {
let profileImage = smallestImageRepresentation(peer.profileImageRepresentations).flatMap { representation in
return account.postbox.mediaBox.resourcePath(representation.resource)
}.flatMap { path -> INImage? in
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
return INImage(imageData: data)
} else {
return nil
}
}
result.append(Friend(identifier: "\(peer.id.toInt64())", display: peer.debugDisplayTitle, subtitle: nil, image: nil))
}
return result
}
}
|> deliverOnMainQueue).start(next: { result in
let collection = INObjectCollection(items: result)
completion(collection, nil)
})
}
}

View File

@ -4115,7 +4115,6 @@ Unused sets are archived when you add more.";
"LogoutOptions.ContactSupportText" = "Tell us about any issues; logging out doesn't usually help.";
"LogoutOptions.LogOut" = "Log Out";
"LogoutOptions.LogOutInfo" = "Remember, logging out kills all your Secret Chats.";
"LogoutOptions.LogOutWalletInfo" = "Logging out will cancel all your secret chats and unlink your Gram wallet from the app.";
"GroupPermission.PermissionGloballyDisabled" = "This permission is disabled in this group.";
@ -4830,251 +4829,6 @@ Sorry for the inconvenience.";
"ChatSearch.ResultsTooltip" = "Tap to view as a list.";
"Wallet.Updated.JustNow" = "updated just now";
"Wallet.Updated.MinutesAgo_0" = "%@ minutes ago"; //three to ten
"Wallet.Updated.MinutesAgo_1" = "1 minute ago"; //one
"Wallet.Updated.MinutesAgo_2" = "2 minutes ago"; //two
"Wallet.Updated.MinutesAgo_3_10" = "%@ minutes ago"; //three to ten
"Wallet.Updated.MinutesAgo_many" = "%@ minutes ago"; // more than ten
"Wallet.Updated.MinutesAgo_any" = "%@ minutes ago"; // more than ten
"Wallet.Updated.HoursAgo_0" = "%@ hours ago";
"Wallet.Updated.HoursAgo_1" = "1 hour ago";
"Wallet.Updated.HoursAgo_2" = "2 hours ago";
"Wallet.Updated.HoursAgo_3_10" = "%@ hours ago";
"Wallet.Updated.HoursAgo_any" = "%@ hours ago";
"Wallet.Updated.HoursAgo_many" = "%@ hours ago";
"Wallet.Updated.HoursAgo_0" = "%@ hours ago";
"Wallet.Updated.YesterdayAt" = "yesterday at %@";
"Wallet.Updated.AtDate" = "%@";
"Wallet.Updated.TodayAt" = "today at %@";
"Wallet.Info.WalletCreated" = "Wallet Created";
"Wallet.Info.Address" = "Your wallet address";
"Wallet.Info.YourBalance" = "your balance";
"Wallet.Info.Receive" = "Receive";
"Wallet.Info.ReceiveGrams" = "Receive Grams";
"Wallet.Info.Send" = "Send";
"Wallet.Info.RefreshErrorTitle" = "No network";
"Wallet.Info.RefreshErrorText" = "Couldn't refresh balance. Please make sure your internet connection is working and try again.";
"Wallet.Info.RefreshErrorNetworkText" = "Wallet state can not be retrieved at this time. Please try again later.";
"Wallet.Info.UnknownTransaction" = "Empty Transaction";
"Wallet.Info.TransactionTo" = "to";
"Wallet.Info.TransactionFrom" = "from";
"Wallet.Info.Updating" = "updating";
"Wallet.Info.TransactionBlockchainFee" = "%@ blockchain fees";
"Wallet.Info.TransactionPendingHeader" = "Pending";
"Wallet.Qr.ScanCode" = "Scan QR Code";
"Wallet.Qr.Title" = "QR Code";
"Wallet.Receive.Title" = "Receive Grams";
"Wallet.Receive.AddressHeader" = "YOUR WALLET ADDRESS";
"Wallet.Receive.InvoiceUrlHeader" = "INVOICE URL";
"Wallet.Receive.CopyAddress" = "Copy Wallet Address";
"Wallet.Receive.CopyInvoiceUrl" = "Copy Invoice URL";
"Wallet.Receive.ShareAddress" = "Share Wallet Address";
"Wallet.Receive.ShareInvoiceUrl" = "Share Invoice URL";
"Wallet.Receive.ShareUrlInfo" = "Share this link with other Gram wallet owners to receive Grams from them. Note: this link won't work for real Grams.";
"Wallet.Receive.AmountHeader" = "AMOUNT";
"Wallet.Receive.AmountText" = "Grams to receive";
"Wallet.Receive.AmountInfo" = "You can specify the amount and purpose of the payment to save the sender some time.";
"Wallet.Receive.CommentHeader" = "COMMENT (OPTIONAL)";
"Wallet.Receive.CommentInfo" = "Description of the payment";
"Wallet.Receive.AddressCopied" = "Address copied to clipboard.";
"Wallet.Receive.InvoiceUrlCopied" = "Invoice URL copied to clipboard.";
"Wallet.Send.Title" = "Send Grams";
"Wallet.Send.AddressHeader" = "RECIPIENT WALLET ADDRESS";
"Wallet.Send.AddressText" = "Enter wallet address...";
"Wallet.Send.AddressInfo" = "Paste the 48-letter address of the recipient here or ask them to send you a ton:// link.";
"Wallet.Send.Balance" = "Balance: %@";
"Wallet.Send.AmountText" = "Grams to send";
"Wallet.Send.Confirmation" = "Confirmation";
"Wallet.Send.ConfirmationText" = "Do you want to send **%1$@** Grams to\n\n%2$@?\n\nBlockchain fees: ~%3$@ grams";
"Wallet.Send.ConfirmationConfirm" = "Confirm";
"Wallet.Send.Send" = "Send";
"Wallet.Send.OwnAddressAlertTitle" = "Warning";
"Wallet.Send.OwnAddressAlertText" = "Sending Grams from a wallet to the same wallet doesn't make sense, you will simply waste a portion of the value on blockchain fees.";
"Wallet.Send.OwnAddressAlertProceed" = "Proceed";
"Wallet.Send.TransactionInProgress" = "Please wait until the current transaction is completed.";
"Wallet.Send.SyncInProgress" = "Please wait while the wallet finishes syncing with the TON Blockchain.";
"Wallet.Send.EncryptComment" = "Encrypt Text";
"Wallet.Settings.Title" = "Settings";
"Wallet.Settings.Configuration" = "Server Settings";
"Wallet.Settings.ConfigurationInfo" = "Advanced Settings";
"Wallet.Settings.BackupWallet" = "Backup Wallet";
"Wallet.Settings.DeleteWallet" = "Delete Wallet";
"Wallet.Settings.DeleteWalletInfo" = "This will disconnect the wallet from this app. You will be able to restore your wallet using 24 secret words or import another wallet.\n\nGram Wallets are located in the decentralized TON Blockchain. If you want a wallet to be deleted, simply transfer all the grams from it and leave it empty.";
"Wallet.Intro.NotNow" = "Not Now";
"Wallet.Intro.ImportExisting" = "Import existing wallet";
"Wallet.Intro.CreateErrorTitle" = "An Error Occurred";
"Wallet.Intro.CreateErrorText" = "Sorry. Please try again.";
"Wallet.Intro.Title" = "Gram Wallet";
"AppWallet.Intro.Text" = "The gram wallet allows you to make fast and secure blockchain-based payments without intermediaries.";
"Wallet.Intro.Text" = "Gram wallet allows you to make fast and secure blockchain-based payments without intermediaries.";
"Wallet.Intro.CreateWallet" = "Create My Wallet";
"Wallet.Intro.Terms" = "By creating a wallet you accept the\n[Terms of Conditions]().";
"TelegramWallet.Intro.TermsUrl" = "https://telegram.org/tos/wallet";
"Wallet.Created.Title" = "Congratulations";
"Wallet.Created.Text" = "Your Gram wallet has just been created. Only you control it.\n\nTo be able to always have access to it, please write down your secret words and\nset up a secure passcode.";
"Wallet.Created.Proceed" = "Proceed";
"Wallet.Created.ExportErrorTitle" = "Error";
"Wallet.Created.ExportErrorText" = "Encryption error. Please make sure you have enabled a device passcode in iOS settings and try again.";
"Wallet.Completed.Title" = "Ready to go!";
"Wallet.Completed.Text" = "Youre all set. Now you have a wallet that only you control - directly, without middlemen or bankers.";
"Wallet.Completed.ViewWallet" = "View My Wallet";
"Wallet.RestoreFailed.Title" = "Too Bad";
"Wallet.RestoreFailed.Text" = "Without the secret words, you can't\nrestore access to your wallet.";
"Wallet.RestoreFailed.CreateWallet" = "Create a New Wallet";
"Wallet.RestoreFailed.EnterWords" = "Enter 24 words";
"Wallet.Sending.Title" = "Sending Grams";
"Wallet.Sending.Text" = "Please wait a few seconds for your transaction to be processed...";
"Wallet.Sending.Title" = "Sending Grams";
"Wallet.Sent.Title" = "Done!";
"Wallet.Sent.Text" = "**%@ Grams** have been sent.";
"Wallet.Sent.ViewWallet" = "View My Wallet";
"Wallet.SecureStorageNotAvailable.Title" = "Set a Passcode";
"Wallet.SecureStorageNotAvailable.Text" = "Please set up a Passcode on your device to enable secure payments with your Gram wallet.";
"Wallet.SecureStorageReset.Title" = "Security Settings Have Changed";
"Wallet.SecureStorageReset.BiometryTouchId" = "Touch ID";
"Wallet.SecureStorageReset.BiometryFaceId" = "Face ID";
"Wallet.SecureStorageReset.BiometryText" = "Unfortunately, your wallet is no longer available because your system Passcode or %@ has been turned off. Please enable them before proceeding.";
"Wallet.SecureStorageReset.PasscodeText" = "Unfortunately, your wallet is no longer available because your system Passcode has been turned off. Please enable it before proceeding.";
"Wallet.SecureStorageChanged.BiometryText" = "Unfortunately, your wallet is no longer available due to the change in your system security settings (Passcode/%@). To restore your wallet, tap \"Import existing wallet\".";
"Wallet.SecureStorageChanged.PasscodeText" = "Unfortunately, your wallet is no longer available due to the change in your system security settings (Passcode). To restore your wallet, tap \"Import existing wallet\".";
"Wallet.SecureStorageChanged.ImportWallet" = "Import Existing Wallet";
"Wallet.SecureStorageChanged.CreateWallet" = "Create New Wallet";
"Wallet.TransactionInfo.Title" = "Transaction";
"Wallet.TransactionInfo.NoAddress" = "No Address";
"Wallet.TransactionInfo.RecipientHeader" = "RECIPIENT";
"Wallet.TransactionInfo.SenderHeader" = "SENDER";
"Wallet.TransactionInfo.CopyAddress" = "Copy Wallet Address";
"Wallet.TransactionInfo.AddressCopied" = "Address copied to clipboard.";
"Wallet.TransactionInfo.SendGrams" = "Send Grams to This Address";
"Wallet.TransactionInfo.CommentHeader" = "COMMENT";
"Wallet.TransactionInfo.StorageFeeHeader" = "STORAGE FEE";
"Wallet.TransactionInfo.OtherFeeHeader" = "TRANSACTION FEE";
"Wallet.TransactionInfo.StorageFeeInfo" = "Blockchain validators collect a tiny fee for storing information about your decentralized wallet and processing your transactions.";
"Wallet.TransactionInfo.StorageFeeInfoUrl" = "Blockchain validators collect a tiny fee for storing information about your decentralized wallet and processing your transactions. [More info]()";
"Wallet.TransactionInfo.OtherFeeInfo" = "Blockchain validators collect a tiny fee for processing your decentralized transactions.";
"Wallet.TransactionInfo.OtherFeeInfoUrl" = "Blockchain validators collect a tiny fee for processing your decentralized transactions. [More info]()";
"AppWallet.TransactionInfo.FeeInfoURL" = "https://telegram.org/wallet/fee";
"Wallet.WordCheck.Title" = "Test Time!";
"Wallet.WordCheck.Text" = "Lets check that you wrote them down correctly. Please enter the words\n**%1$@**, **%2$@** and **%3$@**";
"Wallet.WordCheck.Continue" = "Continue";
"Wallet.WordCheck.IncorrectHeader" = "Incorrect words!";
"Wallet.WordCheck.IncorrectText" = "The secret words you have entered do not match the ones in the list.";
"Wallet.WordCheck.TryAgain" = "Try Again";
"Wallet.WordCheck.ViewWords" = "View Words";
"Wallet.WordImport.Title" = "24 Secret Words";
"Wallet.WordImport.Text" = "Please restore access to your wallet by\nentering the 24 secret words you wrote down when creating the wallet.";
"Wallet.WordImport.Continue" = "Continue";
"Wallet.WordImport.CanNotRemember" = "I don't have them";
"Wallet.WordImport.IncorrectTitle" = "Incorrect words";
"Wallet.WordImport.IncorrectText" = "Sorry, you have entered incorrect secret words. Please double check and try again.";
"Wallet.Words.Title" = "24 Secret Words";
"Wallet.Words.Text" = "Write down these 24 words in the correct order and store them in a secret place.\n\nUse these secret words to restore access to your wallet if you lose your passcode or device.";
"Wallet.Words.Done" = "Done";
"Wallet.Words.NotDoneTitle" = "Sure Done?";
"Wallet.Words.NotDoneText" = "You didn't have enough time to write those words down.";
"Wallet.Words.NotDoneOk" = "OK, Sorry";
"Wallet.Words.NotDoneResponse" = "Apologies Accepted";
"Wallet.Send.NetworkErrorTitle" = "No network";
"Wallet.Send.NetworkErrorText" = "Couldn't send grams. Please make sure your internet connection is working and try again.";
"Wallet.Send.ErrorNotEnoughFundsTitle" = "Insufficient Grams";
"Wallet.Send.ErrorNotEnoughFundsText" = "Unfortunately, your transfer couldn't be completed. You don't have enough grams.";
"Wallet.Send.ErrorInvalidAddress" = "Invalid wallet address. Please correct and try again.";
"Wallet.Send.ErrorDecryptionFailed" = "Please make sure that your device has a passcode set in iOS Settings and try again.";
"Wallet.Send.UninitializedTitle" = "Warning";
"Wallet.Send.UninitializedText" = "This address belongs to an empty wallet. Are you sure you want to transfer grams to it?";
"Wallet.Send.SendAnyway" = "Send Anyway";
"Wallet.Receive.CreateInvoice" = "Create Invoice";
"Wallet.Receive.CreateInvoiceInfo" = "You can specify the amount and purpose of the payment to save the sender some time.";
"Conversation.WalletRequiredTitle" = "Gram Wallet Required";
"Conversation.WalletRequiredText" = "This link can be used to send money on the TON Blockchain. To do this, you need to set up a Gram wallet first.";
"Conversation.WalletRequiredNotNow" = "Not Now";
"Conversation.WalletRequiredSetup" = "Set Up";
"Wallet.Configuration.Title" = "Server Settings";
"Wallet.Configuration.Apply" = "Save";
"Wallet.Configuration.SourceHeader" = "SOURCE";
"Wallet.Configuration.SourceURL" = "URL";
"Wallet.Configuration.SourceJSON" = "JSON";
"Wallet.Configuration.SourceInfo" = "Using a different configuration allows you to change Lite Server addresses.";
"Wallet.Configuration.BlockchainIdHeader" = "BLOCKCHAIN ID";
"Wallet.Configuration.BlockchainIdPlaceholder" = "Blockchain ID";
"Wallet.Configuration.BlockchainIdInfo" = "This setting is for developers. Change it only if you are working on creating your own TON network.";
"Wallet.Configuration.ApplyErrorTitle" = "Error";
"Wallet.Configuration.ApplyErrorTextURLInvalid" = "The URL you have entered is invalid. Please try again.";
"Wallet.Configuration.ApplyErrorTextURLUnreachable" = "There was an error while downloading configuration from %@\nPlease try again.";
"Wallet.Configuration.ApplyErrorTextURLInvalidData" = "This blockchain configuration is invalid. Please try again.";
"Wallet.Configuration.ApplyErrorTextJSONInvalidData" = "This blockchain configuration is invalid. Please try again.";
"Wallet.Configuration.BlockchainNameChangedTitle" = "Warning";
"Wallet.Configuration.BlockchainNameChangedText" = "Are you sure you want to change the blockchain ID? You don't need this unless you're testing your own TON network.\n\nIf you proceed, you will need to reconnect your wallet using 24 secret words.";
"Wallet.Configuration.BlockchainNameChangedProceed" = "Proceed";
"Wallet.CreateInvoice.Title" = "Create Invoice";
"Wallet.Navigation.Close" = "Close";
"Wallet.Navigation.Back" = "Back";
"Wallet.Navigation.Done" = "Done";
"Wallet.Navigation.Cancel" = "Cancel";
"Wallet.Alert.OK" = "OK";
"Wallet.Alert.Cancel" = "Cancel";
"Wallet.Month.GenJanuary" = "January";
"Wallet.Month.GenFebruary" = "February";
"Wallet.Month.GenMarch" = "March";
"Wallet.Month.GenApril" = "April";
"Wallet.Month.GenMay" = "May";
"Wallet.Month.GenJune" = "June";
"Wallet.Month.GenJuly" = "July";
"Wallet.Month.GenAugust" = "August";
"Wallet.Month.GenSeptember" = "September";
"Wallet.Month.GenOctober" = "October";
"Wallet.Month.GenNovember" = "November";
"Wallet.Month.GenDecember" = "December";
"Wallet.Month.ShortJanuary" = "Jan";
"Wallet.Month.ShortFebruary" = "Feb";
"Wallet.Month.ShortMarch" = "Mar";
"Wallet.Month.ShortApril" = "Apr";
"Wallet.Month.ShortMay" = "May";
"Wallet.Month.ShortJune" = "Jun";
"Wallet.Month.ShortJuly" = "Jul";
"Wallet.Month.ShortAugust" = "Aug";
"Wallet.Month.ShortSeptember" = "Sep";
"Wallet.Month.ShortOctober" = "Oct";
"Wallet.Month.ShortNovember" = "Nov";
"Wallet.Month.ShortDecember" = "Dec";
"Wallet.Weekday.Today" = "Today";
"Wallet.Weekday.Yesterday" = "Yesterday";
"Wallet.Info.TransactionDateHeader" = "%1$@ %2$@";
"Wallet.Info.TransactionDateHeaderYear" = "%1$@ %2$@, %3$@";
"Wallet.UnknownError" = "An error occurred. Please try again later.";
"Wallet.ContextMenuCopy" = "Copy";
"Wallet.Time.PreciseDate_m1" = "Jan %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m2" = "Feb %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m3" = "Mar %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m4" = "Apr %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m5" = "May %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m6" = "Jun %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m7" = "Jul %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m8" = "Aug %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m9" = "Sep %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m10" = "Oct %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m11" = "Nov %1$@, %2$@ at %3$@";
"Wallet.Time.PreciseDate_m12" = "Dec %1$@, %2$@ at %3$@";
"Wallet.VoiceOver.Editing.ClearText" = "Clear text";
"Wallet.Receive.ShareInvoiceUrlInfo" = "Share this link with other Gram wallet owners to receive %@ Grams from them.";
"Settings.Wallet" = "Gram Wallet";
"SettingsSearch.Synonyms.Wallet" = "TON Telegram Open Network Crypto";
"Conversation.ClearCache" = "Clear Cache";
"ClearCache.Description" = "Media files will be deleted from your phone, but available for re-downloading when necessary.";
"ClearCache.FreeSpaceDescription" = "If you want to save space on your device, you don't need to delete anything.\n\nYou can use cache settings to remove unnecessary media — and re-download files if you need them again.";
@ -5153,10 +4907,6 @@ Sorry for the inconvenience.";
"UserInfo.StartSecretChatConfirmation" = "Are you sure you want to start a secret chat with\n%@?";
"UserInfo.StartSecretChatStart" = "Start";
"Wallet.AccessDenied.Title" = "Please Allow Access";
"Wallet.AccessDenied.Camera" = "TON Wallet needs access to your camera to take photos and videos.\n\nPlease go to Settings > Privacy > Camera and set TON Wallet to ON.";
"Wallet.AccessDenied.Settings" = "Settings";
"GroupInfo.ShowMoreMembers_0" = "%@ more";
"GroupInfo.ShowMoreMembers_1" = "%@ more";
"GroupInfo.ShowMoreMembers_2" = "%@ more";
@ -5996,9 +5746,9 @@ Sorry for the inconvenience.";
"VoiceChat.CreateNewVoiceChatText" = "Voice chat ended. Start a new one?";
"VoiceChat.CreateNewVoiceChatStart" = "Start";
"CHAT_VOICECHAT_START" = "%1$@ has started voice chat in the group %2$@";
"CHAT_VOICECHAT_INVITE" = "%1$@ has invited %3$@ in the group %2$@";
"CHAT_VOICECHAT_INVITE_YOU" = "%1$@ has invited you to voice chat in the group %2$@";
"PUSH_CHAT_VOICECHAT_START" = "%2$@|%1$@ started a voice chat";
"PUSH_CHAT_VOICECHAT_INVITE" = "%2$@|%1$@ invited %3$@ to the voice chat";
"PUSH_CHAT_VOICECHAT_INVITE_YOU" = "%2$|@%1$@ invited you to the voice chat";
"Call.VoiceChatInProgressTitle" = "Voice Chat in Progress";
"Call.VoiceChatInProgressMessageCall" = "Leave voice chat in %1$@ and start a call with %2$@?";

View File

@ -5,47 +5,186 @@ import WidgetItems
import AppLockState
import SwiftUI
import WidgetKit
import Intents
import OpenSSLEncryptionProvider
import SwiftSignalKit
import Postbox
import SyncCore
import TelegramCore
import OpenSSLEncryptionProvider
private var installedSharedLogger = false
private func setupSharedLogger(rootPath: String, path: String) {
if !installedSharedLogger {
installedSharedLogger = true
Logger.setSharedLogger(Logger(rootPath: rootPath, basePath: path))
}
}
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
return interfaceState
}, fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { _ in
return nil
})
private struct ApplicationSettings {
let logging: LoggingSettings
}
private func applicationSettings(accountManager: AccountManager) -> Signal<ApplicationSettings, NoError> {
return accountManager.transaction { transaction -> ApplicationSettings in
let loggingSettings: LoggingSettings
if let value = transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings {
loggingSettings = value
} else {
loggingSettings = LoggingSettings.defaultSettings
}
return ApplicationSettings(logging: loggingSettings)
}
}
private func rootPathForBasePath(_ appGroupPath: String) -> String {
return appGroupPath + "/telegram-data"
}
struct Provider: TimelineProvider {
struct Provider: IntentTimelineProvider {
public typealias Entry = SimpleEntry
func placeholder(in context: Context) -> SimpleEntry {
return SimpleEntry(date: Date())
return SimpleEntry(date: Date(), contents: .recent)
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
let entry = SimpleEntry(date: Date())
func getSnapshot(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let contents: SimpleEntry.Contents
switch configuration.contents {
case .unknown, .recent:
contents = .recent
case .custom:
contents = .recent
}
let entry = SimpleEntry(date: Date(), contents: contents)
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
var entries: [SimpleEntry] = []
func getTimeline(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
for hourOffset in 0 ..< 1 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate)
entries.append(entry)
let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)!
switch configuration.contents {
case .unknown, .recent:
completion(Timeline(entries: [SimpleEntry(date: entryDate, contents: .recent)], policy: .atEnd))
case .custom:
guard let appBundleIdentifier = Bundle.main.bundleIdentifier, let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
completion(Timeline(entries: [SimpleEntry(date: entryDate, contents: .recent)], policy: .atEnd))
return
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
let appGroupName = "group.\(baseAppBundleId)"
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
guard let appGroupUrl = maybeAppGroupUrl else {
completion(Timeline(entries: [SimpleEntry(date: entryDate, contents: .recent)], policy: .atEnd))
return
}
let rootPath = rootPathForBasePath(appGroupUrl.path)
let dataPath = rootPath + "/widget-data"
guard let data = try? Data(contentsOf: URL(fileURLWithPath: dataPath)), let widgetData = try? JSONDecoder().decode(WidgetData.self, from: data), case let .peers(widgetPeers) = widgetData.content else {
completion(Timeline(entries: [SimpleEntry(date: entryDate, contents: .recent)], policy: .atEnd))
return
}
TempBox.initializeShared(basePath: rootPath, processType: "widget", launchSpecificId: arc4random64())
let logsPath = rootPath + "/widget-logs"
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
setupSharedLogger(rootPath: rootPath, path: logsPath)
initializeAccountManagement()
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
let encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!)
let _ = (accountTransaction(rootPath: rootPath, id: AccountRecordId(rawValue: widgetData.accountId), encryptionParameters: encryptionParameters, transaction: { postbox, transaction -> WidgetDataPeers in
var peers: [WidgetDataPeer] = []
if let items = configuration.friends {
for item in items {
guard let identifier = item.identifier, let peerIdValue = Int64(identifier) else {
continue
}
guard let peer = transaction.getPeer(PeerId(peerIdValue)) else {
continue
}
var name: String = ""
var lastName: String?
if let user = peer as? TelegramUser {
if let firstName = user.firstName {
name = firstName
lastName = user.lastName
} else if let lastName = user.lastName {
name = lastName
} else if let phone = user.phone, !phone.isEmpty {
name = phone
}
} else {
name = peer.debugDisplayTitle
}
var badge: WidgetDataPeer.Badge?
if let readState = transaction.getCombinedPeerReadState(peer.id), readState.count > 0 {
var isMuted = false
if let notificationSettings = transaction.getPeerNotificationSettings(peer.id) as? TelegramPeerNotificationSettings {
isMuted = notificationSettings.isRemovedFromTotalUnreadCount(default: false)
}
badge = WidgetDataPeer.Badge(
count: Int(readState.count),
isMuted: isMuted
)
}
peers.append(WidgetDataPeer(id: peer.id.toInt64(), name: name, lastName: lastName, letters: peer.displayLetters, avatarPath: smallestImageRepresentation(peer.profileImageRepresentations).flatMap { representation in
return postbox.mediaBox.resourcePath(representation.resource)
}, badge: badge))
}
}
return WidgetDataPeers(accountPeerId: widgetPeers.accountPeerId, peers: peers)
})
|> deliverOnMainQueue).start(next: { peers in
completion(Timeline(entries: [SimpleEntry(date: entryDate, contents: .peers(peers))], policy: .atEnd))
})
}
}
}
struct SimpleEntry: TimelineEntry {
enum Contents {
case recent
case peers(WidgetDataPeers)
}
let date: Date
let contents: Contents
}
enum PeersWidgetData {
case placeholder
case empty
case locked
case data(WidgetData)
case peers(WidgetDataPeers)
}
extension PeersWidgetData {
@ -60,6 +199,7 @@ struct AvatarItemView: View {
var body: some View {
return ZStack {
Image(uiImage: avatarImage(accountPeerId: accountPeerId, peer: peer, size: CGSize(width: itemSize, height: itemSize)))
.clipShape(Circle())
if let badge = peer.badge, badge.count > 0 {
Text("\(badge.count)")
.font(Font.system(size: 16.0))
@ -117,11 +257,19 @@ struct WidgetView: View {
switch self.widgetFamily {
case .systemLarge:
rowCount = 4
rowHeight = 88.0
topOffset = 12.0
default:
rowHeight = 80.0
topOffset = 10.0
case .systemMedium:
rowCount = 2
rowHeight = 76.0
rowHeight = 70.0
topOffset = 0.0
case .systemSmall:
rowCount = 2
rowHeight = 72.0
topOffset = 0.0
@unknown default:
rowCount = 2
rowHeight = 72.0
topOffset = 0.0
}
let columnCount = Int(round(geometry.size.width / (defaultItemSize * (1.0 + defaultPaddingFraction))))
@ -162,17 +310,10 @@ struct WidgetView: View {
return AnyView(VStack {
Text(presentationData.applicationLockedString)
})
case let .data(data):
switch data {
case let .peers(peers):
return AnyView(GeometryReader { geometry in
peersView(geometry: geometry, peers: peers)
})
default:
return AnyView(ZStack {
Circle()
})
}
}
}
@ -227,7 +368,9 @@ private let presentationData: WidgetPresentationData = {
}
}()
func getWidgetData() -> PeersWidgetData {
func getWidgetData(contents: SimpleEntry.Contents) -> PeersWidgetData {
switch contents {
case .recent:
let appBundleIdentifier = Bundle.main.bundleIdentifier!
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
return .placeholder
@ -250,10 +393,20 @@ func getWidgetData() -> PeersWidgetData {
let dataPath = rootPath + "/widget-data"
if let data = try? Data(contentsOf: URL(fileURLWithPath: dataPath)), let widgetData = try? JSONDecoder().decode(WidgetData.self, from: data) {
return .data(widgetData)
switch widgetData.content {
case let .peers(peers):
return .peers(peers)
case .disabled:
return .placeholder
case .notAuthorized:
return .locked
}
} else {
return .placeholder
}
case let .peers(peers):
return .peers(peers)
}
}
@main
@ -261,13 +414,9 @@ struct Static_Widget: Widget {
private let kind: String = "Static_Widget"
public var body: some WidgetConfiguration {
return StaticConfiguration(
kind: kind,
provider: Provider(),
content: { entry in
WidgetView(data: getWidgetData())
}
)
return IntentConfiguration(kind: kind, intent: SelectFriendsIntent.self, provider: Provider(), content: { entry in
WidgetView(data: getWidgetData(contents: entry.contents))
})
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
.configurationDisplayName(presentationData.widgetGalleryTitle)
.description(presentationData.widgetGalleryDescription)

View File

@ -1105,7 +1105,7 @@ func debugRestoreState(basePath:String, name: String) {
private let sharedQueue = Queue(name: "org.telegram.postbox.Postbox")
public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32) -> Signal<PostboxResult, NoError> {
public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool) -> Signal<PostboxResult, NoError> {
let queue = sharedQueue
return Signal { subscriber in
queue.async {
@ -1130,6 +1130,10 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
if let userVersion = userVersion {
if userVersion != currentUserVersion {
if isTemporary {
subscriber.putNext(.upgrading(0.0))
return
} else {
if userVersion > currentUserVersion {
postboxLog("Version \(userVersion) is newer than supported")
assertionFailure("Version \(userVersion) is newer than supported")
@ -1170,6 +1174,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
}
}
}
}
} else {
metadataTable.setUserVersion(currentUserVersion)
}
@ -1177,7 +1182,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
let endTime = CFAbsoluteTimeGetCurrent()
print("Postbox load took \((endTime - startTime) * 1000.0) ms")
subscriber.putNext(.postbox(Postbox(queue: queue, basePath: basePath, seedConfiguration: seedConfiguration, valueBox: valueBox, timestampForAbsoluteTimeBasedOperations: timestampForAbsoluteTimeBasedOperations)))
subscriber.putNext(.postbox(Postbox(queue: queue, basePath: basePath, seedConfiguration: seedConfiguration, valueBox: valueBox, timestampForAbsoluteTimeBasedOperations: timestampForAbsoluteTimeBasedOperations, isTemporary: isTemporary)))
subscriber.putCompletion()
break
}
@ -1330,7 +1335,7 @@ public final class Postbox {
var installedMessageActionsByPeerId: [PeerId: Bag<([StoreMessage], Transaction) -> Void>] = [:]
init(queue: Queue, basePath: String, seedConfiguration: SeedConfiguration, valueBox: SqliteValueBox, timestampForAbsoluteTimeBasedOperations: Int32) {
init(queue: Queue, basePath: String, seedConfiguration: SeedConfiguration, valueBox: SqliteValueBox, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool) {
assert(queue.isCurrent())
let startTime = CFAbsoluteTimeGetCurrent()
@ -1531,6 +1536,7 @@ public final class Postbox {
self.messageHistoryMetadataTable.setShouldReindexUnreadCounts(value: false)
}
if !isTemporary {
for id in self.messageHistoryUnsentTable.get() {
transaction.updateMessage(id, update: { message in
if !message.flags.contains(.Failed) {
@ -1551,6 +1557,7 @@ public final class Postbox {
}
})
}
}
}).start()
}

View File

@ -69,14 +69,16 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
}, additionalChatListIndexNamespace: Namespaces.Message.Cloud, messageNamespacesRequiringGroupStatsValidation: [Namespaces.Message.Cloud], defaultMessageNamespaceReadStates: [Namespaces.Message.Local: .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false)], chatMessagesNamespaces: Set([Namespaces.Message.Cloud, Namespaces.Message.Local, Namespaces.Message.SecretIncoming]), globalNotificationSettingsPreferencesKey: PreferencesKeys.globalNotifications, defaultGlobalNotificationSettings: GlobalNotificationSettings.defaultSettings)
}()
public func accountTransaction<T>(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, transaction: @escaping (Transaction) -> T) -> Signal<T, NoError> {
public func accountTransaction<T>(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, transaction: @escaping (Postbox, Transaction) -> T) -> Signal<T, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970))
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true)
return postbox
|> mapToSignal { value -> Signal<T, NoError> in
switch value {
case let .postbox(postbox):
return postbox.transaction(transaction)
return postbox.transaction { t in
transaction(postbox, t)
}
default:
return .complete()
}

View File

@ -160,7 +160,7 @@ public enum AccountPreferenceEntriesResult {
public func accountPreferenceEntries(rootPath: String, id: AccountRecordId, keys: Set<ValueBoxKey>, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountPreferenceEntriesResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970))
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true)
return postbox
|> mapToSignal { value -> Signal<AccountPreferenceEntriesResult, NoError> in
switch value {
@ -187,7 +187,7 @@ public enum AccountNoticeEntriesResult {
public func accountNoticeEntries(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountNoticeEntriesResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970))
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true)
return postbox
|> mapToSignal { value -> Signal<AccountNoticeEntriesResult, NoError> in
switch value {
@ -208,7 +208,7 @@ public enum LegacyAccessChallengeDataResult {
public func accountLegacyAccessChallengeData(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<LegacyAccessChallengeDataResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970))
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true)
return postbox
|> mapToSignal { value -> Signal<LegacyAccessChallengeDataResult, NoError> in
switch value {
@ -225,7 +225,7 @@ public func accountLegacyAccessChallengeData(rootPath: String, id: AccountRecord
public func accountWithId(accountManager: AccountManager, networkArguments: NetworkInitializationArguments, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, supplementary: Bool, rootPath: String, beginWithTestingEnvironment: Bool, backupData: AccountBackupData?, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal<AccountResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970))
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false)
return postbox
|> mapToSignal { result -> Signal<AccountResult, NoError> in

View File

@ -210,7 +210,7 @@ public func temporaryAccount(manager: AccountManager, rootPath: String, encrypti
return manager.allocatedTemporaryAccountId()
|> mapToSignal { id -> Signal<TemporaryAccount, NoError> in
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
return openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970))
return openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false)
|> mapToSignal { result -> Signal<TemporaryAccount, NoError> in
switch result {
case .upgrading:

View File

@ -290,7 +290,7 @@ public func upgradedAccounts(accountManager: AccountManager, rootPath: String, e
|> mapToSignal { globalSettings, ids -> Signal<Never, NoError> in
var importSignal: Signal<Never, NoError> = .complete()
for id in ids {
let importInfoAccounttSignal = accountTransaction(rootPath: rootPath, id: id, encryptionParameters: encryptionParameters, transaction: { transaction -> Void in
let importInfoAccounttSignal = accountTransaction(rootPath: rootPath, id: id, encryptionParameters: encryptionParameters, transaction: { _, transaction -> Void in
transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in
var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings
settings.synchronizeContacts = globalSettings._legacySynchronizeDeviceContacts

View File

@ -22,7 +22,7 @@ final class WidgetDataContext {
})
|> mapToSignal { account -> Signal<WidgetData, NoError> in
guard let account = account else {
return .single(.notAuthorized)
return .single(WidgetData(accountId: 0, content: .notAuthorized))
}
enum CombinedRecentPeers {
@ -106,9 +106,9 @@ final class WidgetDataContext {
|> map { result -> WidgetData in
switch result {
case .disabled:
return .disabled
return WidgetData(accountId: account.id.int64, content: .disabled)
case let .peers(peers, unread):
return .peers(WidgetDataPeers(accountPeerId: account.peerId.toInt64(), peers: peers.compactMap { peer -> WidgetDataPeer? in
return WidgetData(accountId: account.id.int64, content: .peers(WidgetDataPeers(accountPeerId: account.peerId.toInt64(), peers: peers.compactMap { peer -> WidgetDataPeer? in
var name: String = ""
var lastName: String?
@ -136,7 +136,7 @@ final class WidgetDataContext {
return WidgetDataPeer(id: peer.id.toInt64(), name: name, lastName: lastName, letters: peer.displayLetters, avatarPath: smallestImageRepresentation(peer.profileImageRepresentations).flatMap { representation in
return account.postbox.mediaBox.resourcePath(representation.resource)
}, badge: badge)
}))
})))
}
}
|> distinctUntilChanged

View File

@ -60,7 +60,8 @@ public func widgetPresentationDataPath(rootPath: String) -> String {
return rootPath + "/widgetPresentationData.json"
}
public enum WidgetData: Codable, Equatable {
public struct WidgetData: Codable, Equatable {
public enum Content: Codable, Equatable {
private enum CodingKeys: CodingKey {
case discriminator
case peers
@ -102,3 +103,12 @@ public enum WidgetData: Codable, Equatable {
}
}
}
public var accountId: Int64
public var content: Content
public init(accountId: Int64, content: Content) {
self.accountId = accountId
self.content = content
}
}