mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 03:40:18 +00:00
Added support for derived localizations
Added support for confirming two-step verification email via code
This commit is contained in:
parent
532285b062
commit
eecd183a28
@ -113,6 +113,8 @@
|
|||||||
D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495D1E118F790057C89A /* AccountStateManager.swift */; };
|
D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495D1E118F790057C89A /* AccountStateManager.swift */; };
|
||||||
D01749601E118FC30057C89A /* AccountIntermediateState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495F1E118FC30057C89A /* AccountIntermediateState.swift */; };
|
D01749601E118FC30057C89A /* AccountIntermediateState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495F1E118FC30057C89A /* AccountIntermediateState.swift */; };
|
||||||
D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */; };
|
D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */; };
|
||||||
|
D01843A82190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01843A72190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift */; };
|
||||||
|
D01843A92190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01843A72190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift */; };
|
||||||
D018D3371E648ACF00C5E089 /* ChannelCreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018D3361E648ACF00C5E089 /* ChannelCreation.swift */; };
|
D018D3371E648ACF00C5E089 /* ChannelCreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018D3361E648ACF00C5E089 /* ChannelCreation.swift */; };
|
||||||
D018D3381E648ACF00C5E089 /* ChannelCreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018D3361E648ACF00C5E089 /* ChannelCreation.swift */; };
|
D018D3381E648ACF00C5E089 /* ChannelCreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018D3361E648ACF00C5E089 /* ChannelCreation.swift */; };
|
||||||
D018EE002044939F00CBB130 /* SecretApiLayer73.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018EDFF2044939F00CBB130 /* SecretApiLayer73.swift */; };
|
D018EE002044939F00CBB130 /* SecretApiLayer73.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018EDFF2044939F00CBB130 /* SecretApiLayer73.swift */; };
|
||||||
@ -807,6 +809,7 @@
|
|||||||
D017495D1E118F790057C89A /* AccountStateManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountStateManager.swift; sourceTree = "<group>"; };
|
D017495D1E118F790057C89A /* AccountStateManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountStateManager.swift; sourceTree = "<group>"; };
|
||||||
D017495F1E118FC30057C89A /* AccountIntermediateState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountIntermediateState.swift; sourceTree = "<group>"; };
|
D017495F1E118FC30057C89A /* AccountIntermediateState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountIntermediateState.swift; sourceTree = "<group>"; };
|
||||||
D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatState.swift; sourceTree = "<group>"; };
|
D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatState.swift; sourceTree = "<group>"; };
|
||||||
|
D01843A72190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmTwoStepRecoveryEmail.swift; sourceTree = "<group>"; };
|
||||||
D018D3361E648ACF00C5E089 /* ChannelCreation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelCreation.swift; sourceTree = "<group>"; };
|
D018D3361E648ACF00C5E089 /* ChannelCreation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelCreation.swift; sourceTree = "<group>"; };
|
||||||
D018EDFF2044939F00CBB130 /* SecretApiLayer73.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer73.swift; sourceTree = "<group>"; };
|
D018EDFF2044939F00CBB130 /* SecretApiLayer73.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer73.swift; sourceTree = "<group>"; };
|
||||||
D018EE0120458E1E00CBB130 /* SecretChatLayerNegotiation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretChatLayerNegotiation.swift; sourceTree = "<group>"; };
|
D018EE0120458E1E00CBB130 /* SecretChatLayerNegotiation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretChatLayerNegotiation.swift; sourceTree = "<group>"; };
|
||||||
@ -1552,6 +1555,7 @@
|
|||||||
D0B1671C1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift */,
|
D0B1671C1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift */,
|
||||||
D06ECFC720B810D300C576C2 /* TermsOfService.swift */,
|
D06ECFC720B810D300C576C2 /* TermsOfService.swift */,
|
||||||
D051DB16215ECC4D00F30F92 /* AppChangelog.swift */,
|
D051DB16215ECC4D00F30F92 /* AppChangelog.swift */,
|
||||||
|
D01843A72190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift */,
|
||||||
);
|
);
|
||||||
name = Account;
|
name = Account;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2209,6 +2213,7 @@
|
|||||||
D0ADF911212B00DD00310BBC /* SecureIdConfiguration.swift in Sources */,
|
D0ADF911212B00DD00310BBC /* SecureIdConfiguration.swift in Sources */,
|
||||||
D0448CA51E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */,
|
D0448CA51E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */,
|
||||||
D0C26D661FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift in Sources */,
|
D0C26D661FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift in Sources */,
|
||||||
|
D01843A82190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift in Sources */,
|
||||||
D03C53771DAFF20F004C17B3 /* MultipartUpload.swift in Sources */,
|
D03C53771DAFF20F004C17B3 /* MultipartUpload.swift in Sources */,
|
||||||
D00C7CE01E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */,
|
D00C7CE01E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */,
|
||||||
C2E0646D1ECF171D00387BB8 /* TelegramMediaWebDocument.swift in Sources */,
|
C2E0646D1ECF171D00387BB8 /* TelegramMediaWebDocument.swift in Sources */,
|
||||||
@ -2790,6 +2795,7 @@
|
|||||||
D0B844301DAB91E0005F29E1 /* NBNumberFormat.m in Sources */,
|
D0B844301DAB91E0005F29E1 /* NBNumberFormat.m in Sources */,
|
||||||
D001F3F71E128A1C007A8C60 /* ApplyUpdateMessage.swift in Sources */,
|
D001F3F71E128A1C007A8C60 /* ApplyUpdateMessage.swift in Sources */,
|
||||||
D0B418971D7E0580004562A4 /* TelegramMediaImage.swift in Sources */,
|
D0B418971D7E0580004562A4 /* TelegramMediaImage.swift in Sources */,
|
||||||
|
D01843A92190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift in Sources */,
|
||||||
D041E3F91E535A88008C24B4 /* RemovePeerMember.swift in Sources */,
|
D041E3F91E535A88008C24B4 /* RemovePeerMember.swift in Sources */,
|
||||||
D049EAF61E44DF3300A2CD3A /* AccountState.swift in Sources */,
|
D049EAF61E44DF3300A2CD3A /* AccountState.swift in Sources */,
|
||||||
D0467D1620D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */,
|
D0467D1620D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */,
|
||||||
|
|||||||
@ -153,7 +153,7 @@ public class UnauthorizedAccount {
|
|||||||
return self.postbox.transaction { transaction -> (LocalizationSettings?, ProxySettings?, NetworkSettings?) in
|
return self.postbox.transaction { transaction -> (LocalizationSettings?, ProxySettings?, NetworkSettings?) in
|
||||||
return (transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings, transaction.getPreferencesEntry(key: PreferencesKeys.proxySettings) as? ProxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings) as? NetworkSettings)
|
return (transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings, transaction.getPreferencesEntry(key: PreferencesKeys.proxySettings) as? ProxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings) as? NetworkSettings)
|
||||||
} |> mapToSignal { (localizationSettings, proxySettings, networkSettings) -> Signal<UnauthorizedAccount, NoError> in
|
} |> mapToSignal { (localizationSettings, proxySettings, networkSettings) -> Signal<UnauthorizedAccount, NoError> in
|
||||||
return initializedNetwork(arguments: self.networkArguments, supplementary: false, datacenterId: Int(masterDatacenterId), keychain: keychain, basePath: self.basePath, testingEnvironment: self.testingEnvironment, languageCode: localizationSettings?.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil)
|
return initializedNetwork(arguments: self.networkArguments, supplementary: false, datacenterId: Int(masterDatacenterId), keychain: keychain, basePath: self.basePath, testingEnvironment: self.testingEnvironment, languageCode: localizationSettings?.primaryComponent.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil)
|
||||||
|> map { network in
|
|> map { network in
|
||||||
let updated = UnauthorizedAccount(networkArguments: self.networkArguments, id: self.id, rootPath: self.rootPath, basePath: self.basePath, testingEnvironment: self.testingEnvironment, postbox: self.postbox, network: network)
|
let updated = UnauthorizedAccount(networkArguments: self.networkArguments, id: self.id, rootPath: self.rootPath, basePath: self.basePath, testingEnvironment: self.testingEnvironment, postbox: self.postbox, network: network)
|
||||||
updated.shouldBeServiceTaskMaster.set(self.shouldBeServiceTaskMaster.get())
|
updated.shouldBeServiceTaskMaster.set(self.shouldBeServiceTaskMaster.get())
|
||||||
@ -340,7 +340,7 @@ public func accountWithId(networkArguments: NetworkInitializationArguments, id:
|
|||||||
if let accountState = accountState {
|
if let accountState = accountState {
|
||||||
switch accountState {
|
switch accountState {
|
||||||
case let unauthorizedState as UnauthorizedAccountState:
|
case let unauthorizedState as UnauthorizedAccountState:
|
||||||
return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: Int(unauthorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: unauthorizedState.isTestingEnvironment, languageCode: localizationSettings?.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil)
|
return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: Int(unauthorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: unauthorizedState.isTestingEnvironment, languageCode: localizationSettings?.primaryComponent.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil)
|
||||||
|> map { network -> AccountResult in
|
|> map { network -> AccountResult in
|
||||||
return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: unauthorizedState.isTestingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection))
|
return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: unauthorizedState.isTestingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection))
|
||||||
}
|
}
|
||||||
@ -349,7 +349,7 @@ public func accountWithId(networkArguments: NetworkInitializationArguments, id:
|
|||||||
return (transaction.getPeer(authorizedState.peerId) as? TelegramUser)?.phone
|
return (transaction.getPeer(authorizedState.peerId) as? TelegramUser)?.phone
|
||||||
}
|
}
|
||||||
|> mapToSignal { phoneNumber in
|
|> mapToSignal { phoneNumber in
|
||||||
return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: Int(authorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: authorizedState.isTestingEnvironment, languageCode: localizationSettings?.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: phoneNumber)
|
return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: Int(authorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: authorizedState.isTestingEnvironment, languageCode: localizationSettings?.primaryComponent.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: phoneNumber)
|
||||||
|> map { network -> AccountResult in
|
|> map { network -> AccountResult in
|
||||||
return .authorized(Account(id: id, basePath: path, testingEnvironment: authorizedState.isTestingEnvironment, postbox: postbox, network: network, networkArguments: networkArguments, peerId: authorizedState.peerId, auxiliaryMethods: auxiliaryMethods))
|
return .authorized(Account(id: id, basePath: path, testingEnvironment: authorizedState.isTestingEnvironment, postbox: postbox, network: network, networkArguments: networkArguments, peerId: authorizedState.peerId, auxiliaryMethods: auxiliaryMethods))
|
||||||
}
|
}
|
||||||
@ -359,7 +359,7 @@ public func accountWithId(networkArguments: NetworkInitializationArguments, id:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: 2, keychain: keychain, basePath: path, testingEnvironment: beginWithTestingEnvironment, languageCode: localizationSettings?.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil)
|
return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: 2, keychain: keychain, basePath: path, testingEnvironment: beginWithTestingEnvironment, languageCode: localizationSettings?.primaryComponent.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil)
|
||||||
|> map { network -> AccountResult in
|
|> map { network -> AccountResult in
|
||||||
return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: beginWithTestingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection))
|
return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: beginWithTestingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection))
|
||||||
}
|
}
|
||||||
@ -963,6 +963,9 @@ public class Account {
|
|||||||
})
|
})
|
||||||
self.localInputActivityManager = PeerInputActivityManager()
|
self.localInputActivityManager = PeerInputActivityManager()
|
||||||
self.accountPresenceManager = AccountPresenceManager(shouldKeepOnlinePresence: self.shouldKeepOnlinePresence.get(), network: network)
|
self.accountPresenceManager = AccountPresenceManager(shouldKeepOnlinePresence: self.shouldKeepOnlinePresence.get(), network: network)
|
||||||
|
let _ = (postbox.transaction { transaction -> Void in
|
||||||
|
transaction.updatePeerPresencesInternal([peerId: TelegramUserPresence(status: .present(until: Int32.max - 1))])
|
||||||
|
}).start()
|
||||||
self.notificationAutolockReportManager = NotificationAutolockReportManager(deadline: self.autolockReportDeadline.get(), network: network)
|
self.notificationAutolockReportManager = NotificationAutolockReportManager(deadline: self.autolockReportDeadline.get(), network: network)
|
||||||
self.autolockReportDeadline.set(
|
self.autolockReportDeadline.set(
|
||||||
postbox.combinedView(keys: [.accessChallengeData])
|
postbox.combinedView(keys: [.accessChallengeData])
|
||||||
@ -1128,27 +1131,27 @@ public class Account {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
let shouldBeMaster = combineLatest(shouldBeServiceTaskMaster.get(), postbox.isMasterClient())
|
let shouldBeMaster = combineLatest(shouldBeServiceTaskMaster.get(), postbox.isMasterClient())
|
||||||
|> map { [weak self] shouldBeMaster, isMaster -> Bool in
|
|> map { [weak self] shouldBeMaster, isMaster -> Bool in
|
||||||
if shouldBeMaster == .always && !isMaster {
|
if shouldBeMaster == .always && !isMaster {
|
||||||
self?.postbox.becomeMasterClient()
|
self?.postbox.becomeMasterClient()
|
||||||
}
|
|
||||||
return (shouldBeMaster == .now || shouldBeMaster == .always) && isMaster
|
|
||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
return (shouldBeMaster == .now || shouldBeMaster == .always) && isMaster
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged
|
||||||
|
|
||||||
self.network.shouldKeepConnection.set(shouldBeMaster)
|
self.network.shouldKeepConnection.set(shouldBeMaster)
|
||||||
self.network.shouldExplicitelyKeepWorkerConnections.set(self.shouldExplicitelyKeepWorkerConnections.get())
|
self.network.shouldExplicitelyKeepWorkerConnections.set(self.shouldExplicitelyKeepWorkerConnections.get())
|
||||||
|
|
||||||
let serviceTasksMaster = shouldBeMaster
|
let serviceTasksMaster = shouldBeMaster
|
||||||
|> deliverOn(self.serviceQueue)
|
|> deliverOn(self.serviceQueue)
|
||||||
|> mapToSignal { [weak self] value -> Signal<Void, NoError> in
|
|> mapToSignal { [weak self] value -> Signal<Void, NoError> in
|
||||||
if let strongSelf = self, value {
|
if let strongSelf = self, value {
|
||||||
Logger.shared.log("Account", "Became master")
|
Logger.shared.log("Account", "Became master")
|
||||||
return managedServiceViews(accountPeerId: peerId, network: strongSelf.network, postbox: strongSelf.postbox, stateManager: strongSelf.stateManager, pendingMessageManager: strongSelf.pendingMessageManager)
|
return managedServiceViews(accountPeerId: peerId, network: strongSelf.network, postbox: strongSelf.postbox, stateManager: strongSelf.stateManager, pendingMessageManager: strongSelf.pendingMessageManager)
|
||||||
} else {
|
} else {
|
||||||
Logger.shared.log("Account", "Resigned master")
|
Logger.shared.log("Account", "Resigned master")
|
||||||
return .never()
|
return .never()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.managedServiceViewsDisposable.set(serviceTasksMaster.start())
|
self.managedServiceViewsDisposable.set(serviceTasksMaster.start())
|
||||||
|
|
||||||
@ -1214,39 +1217,6 @@ public class Account {
|
|||||||
let settings: CacheStorageSettings = ((view.views[storagePreferencesKey] as? PreferencesView)?.values[PreferencesKeys.cacheStorageSettings] as? CacheStorageSettings) ?? CacheStorageSettings.defaultSettings
|
let settings: CacheStorageSettings = ((view.views[storagePreferencesKey] as? PreferencesView)?.values[PreferencesKeys.cacheStorageSettings] as? CacheStorageSettings) ?? CacheStorageSettings.defaultSettings
|
||||||
mediaBox.setMaxStoreTime(settings.defaultCacheStorageTimeout)
|
mediaBox.setMaxStoreTime(settings.defaultCacheStorageTimeout)
|
||||||
})
|
})
|
||||||
|
|
||||||
/*let updatedPresence = self.shouldKeepOnlinePresence.get()
|
|
||||||
|> distinctUntilChanged
|
|
||||||
|> mapToSignal { [weak self] online -> Signal<Void, NoError> in
|
|
||||||
if let strongSelf = self {
|
|
||||||
let delayRequest: Signal<Void, NoError> = .complete()
|
|
||||||
|> delay(60.0, queue: Queue.concurrentDefaultQueue())
|
|
||||||
let pushStatusOnce = strongSelf.network.request(Api.functions.account.updateStatus(offline: online ? .boolFalse : .boolTrue))
|
|
||||||
|> retryRequest
|
|
||||||
|> mapToSignal { _ -> Signal<Void, NoError> in return .complete() }
|
|
||||||
|
|
||||||
let pushStatusRepeatedly = (pushStatusOnce
|
|
||||||
|> then(delayRequest))
|
|
||||||
|> restart
|
|
||||||
|
|
||||||
let peerId = strongSelf.peerId
|
|
||||||
let updatePresenceLocally = strongSelf.postbox.transaction { transaction -> Void in
|
|
||||||
let timestamp: Double
|
|
||||||
if online {
|
|
||||||
timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60.0 * 60.0 * 24.0 * 356.0
|
|
||||||
} else {
|
|
||||||
timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - 1.0
|
|
||||||
}
|
|
||||||
transaction.updatePeerPresences([peerId: TelegramUserPresence(status: .present(until: Int32(timestamp)))])
|
|
||||||
}
|
|
||||||
return combineLatest(pushStatusRepeatedly, updatePresenceLocally)
|
|
||||||
|> mapToSignal { _ -> Signal<Void, NoError> in return .complete()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return .complete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.updatedPresenceDisposable.set(updatedPresence.start())*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
|||||||
@ -172,10 +172,14 @@ public final class AccountStateManager {
|
|||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return network.request(Api.functions.messages.receivedQueue(maxQts: value))
|
if value == 0 {
|
||||||
|> ignoreValues
|
|
||||||
|> `catch` { _ -> Signal<Never, NoError> in
|
|
||||||
return .complete()
|
return .complete()
|
||||||
|
} else {
|
||||||
|
return network.request(Api.functions.messages.receivedQueue(maxQts: value))
|
||||||
|
|> ignoreValues
|
||||||
|
|> `catch` { _ -> Signal<Never, NoError> in
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start())
|
}).start())
|
||||||
|
|||||||
@ -416,7 +416,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[182649427] = { return Api.MessageRange.parse_messageRange($0) }
|
dict[182649427] = { return Api.MessageRange.parse_messageRange($0) }
|
||||||
dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) }
|
dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) }
|
||||||
dict[904138920] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultArchive($0) }
|
dict[904138920] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultArchive($0) }
|
||||||
dict[840162234] = { return Api.Config.parse_config($0) }
|
dict[-422959626] = { return Api.Config.parse_config($0) }
|
||||||
dict[-75283823] = { return Api.TopPeerCategoryPeers.parse_topPeerCategoryPeers($0) }
|
dict[-75283823] = { return Api.TopPeerCategoryPeers.parse_topPeerCategoryPeers($0) }
|
||||||
dict[-1107729093] = { return Api.Game.parse_game($0) }
|
dict[-1107729093] = { return Api.Game.parse_game($0) }
|
||||||
dict[4883767] = { return Api.SecurePasswordKdfAlgo.parse_securePasswordKdfAlgoUnknown($0) }
|
dict[4883767] = { return Api.SecurePasswordKdfAlgo.parse_securePasswordKdfAlgoUnknown($0) }
|
||||||
|
|||||||
@ -10170,13 +10170,13 @@ extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
enum Config: TypeConstructorDescription {
|
enum Config: TypeConstructorDescription {
|
||||||
case config(flags: Int32, date: Int32, expires: Int32, testMode: Api.Bool, thisDc: Int32, dcOptions: [Api.DcOption], dcTxtDomainName: String, chatSizeMax: Int32, megagroupSizeMax: Int32, forwardedCountMax: Int32, onlineUpdatePeriodMs: Int32, offlineBlurTimeoutMs: Int32, offlineIdleTimeoutMs: Int32, onlineCloudTimeoutMs: Int32, notifyCloudDelayMs: Int32, notifyDefaultDelayMs: Int32, pushChatPeriodMs: Int32, pushChatLimit: Int32, savedGifsLimit: Int32, editTimeLimit: Int32, revokeTimeLimit: Int32, revokePmTimeLimit: Int32, ratingEDecay: Int32, stickersRecentLimit: Int32, stickersFavedLimit: Int32, channelsReadMediaPeriod: Int32, tmpSessions: Int32?, pinnedDialogsCountMax: Int32, callReceiveTimeoutMs: Int32, callRingTimeoutMs: Int32, callConnectTimeoutMs: Int32, callPacketTimeoutMs: Int32, meUrlPrefix: String, autoupdateUrlPrefix: String?, gifSearchUsername: String?, venueSearchUsername: String?, imgSearchUsername: String?, staticMapsProvider: String?, captionLengthMax: Int32, messageLengthMax: Int32, webfileDcId: Int32, suggestedLangCode: String?, langPackVersion: Int32?)
|
case config(flags: Int32, date: Int32, expires: Int32, testMode: Api.Bool, thisDc: Int32, dcOptions: [Api.DcOption], dcTxtDomainName: String, chatSizeMax: Int32, megagroupSizeMax: Int32, forwardedCountMax: Int32, onlineUpdatePeriodMs: Int32, offlineBlurTimeoutMs: Int32, offlineIdleTimeoutMs: Int32, onlineCloudTimeoutMs: Int32, notifyCloudDelayMs: Int32, notifyDefaultDelayMs: Int32, pushChatPeriodMs: Int32, pushChatLimit: Int32, savedGifsLimit: Int32, editTimeLimit: Int32, revokeTimeLimit: Int32, revokePmTimeLimit: Int32, ratingEDecay: Int32, stickersRecentLimit: Int32, stickersFavedLimit: Int32, channelsReadMediaPeriod: Int32, tmpSessions: Int32?, pinnedDialogsCountMax: Int32, callReceiveTimeoutMs: Int32, callRingTimeoutMs: Int32, callConnectTimeoutMs: Int32, callPacketTimeoutMs: Int32, meUrlPrefix: String, autoupdateUrlPrefix: String?, gifSearchUsername: String?, venueSearchUsername: String?, imgSearchUsername: String?, staticMapsProvider: String?, captionLengthMax: Int32, messageLengthMax: Int32, webfileDcId: Int32, suggestedLangCode: String?, langPackVersion: Int32?, baseLangPackVersion: Int32?)
|
||||||
|
|
||||||
func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let dcTxtDomainName, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let revokeTimeLimit, let revokePmTimeLimit, let ratingEDecay, let stickersRecentLimit, let stickersFavedLimit, let channelsReadMediaPeriod, let tmpSessions, let pinnedDialogsCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let autoupdateUrlPrefix, let gifSearchUsername, let venueSearchUsername, let imgSearchUsername, let staticMapsProvider, let captionLengthMax, let messageLengthMax, let webfileDcId, let suggestedLangCode, let langPackVersion):
|
case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let dcTxtDomainName, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let revokeTimeLimit, let revokePmTimeLimit, let ratingEDecay, let stickersRecentLimit, let stickersFavedLimit, let channelsReadMediaPeriod, let tmpSessions, let pinnedDialogsCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let autoupdateUrlPrefix, let gifSearchUsername, let venueSearchUsername, let imgSearchUsername, let staticMapsProvider, let captionLengthMax, let messageLengthMax, let webfileDcId, let suggestedLangCode, let langPackVersion, let baseLangPackVersion):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(840162234)
|
buffer.appendInt32(-422959626)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt32(date, buffer: buffer, boxed: false)
|
serializeInt32(date, buffer: buffer, boxed: false)
|
||||||
@ -10225,14 +10225,15 @@ extension Api {
|
|||||||
serializeInt32(webfileDcId, buffer: buffer, boxed: false)
|
serializeInt32(webfileDcId, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 2) != 0 {serializeString(suggestedLangCode!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 2) != 0 {serializeString(suggestedLangCode!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(langPackVersion!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(langPackVersion!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(baseLangPackVersion!, buffer: buffer, boxed: false)}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func descriptionFields() -> (String, [(String, Any)]) {
|
func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let dcTxtDomainName, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let revokeTimeLimit, let revokePmTimeLimit, let ratingEDecay, let stickersRecentLimit, let stickersFavedLimit, let channelsReadMediaPeriod, let tmpSessions, let pinnedDialogsCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let autoupdateUrlPrefix, let gifSearchUsername, let venueSearchUsername, let imgSearchUsername, let staticMapsProvider, let captionLengthMax, let messageLengthMax, let webfileDcId, let suggestedLangCode, let langPackVersion):
|
case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let dcTxtDomainName, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let revokeTimeLimit, let revokePmTimeLimit, let ratingEDecay, let stickersRecentLimit, let stickersFavedLimit, let channelsReadMediaPeriod, let tmpSessions, let pinnedDialogsCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let autoupdateUrlPrefix, let gifSearchUsername, let venueSearchUsername, let imgSearchUsername, let staticMapsProvider, let captionLengthMax, let messageLengthMax, let webfileDcId, let suggestedLangCode, let langPackVersion, let baseLangPackVersion):
|
||||||
return ("config", [("flags", flags), ("date", date), ("expires", expires), ("testMode", testMode), ("thisDc", thisDc), ("dcOptions", dcOptions), ("dcTxtDomainName", dcTxtDomainName), ("chatSizeMax", chatSizeMax), ("megagroupSizeMax", megagroupSizeMax), ("forwardedCountMax", forwardedCountMax), ("onlineUpdatePeriodMs", onlineUpdatePeriodMs), ("offlineBlurTimeoutMs", offlineBlurTimeoutMs), ("offlineIdleTimeoutMs", offlineIdleTimeoutMs), ("onlineCloudTimeoutMs", onlineCloudTimeoutMs), ("notifyCloudDelayMs", notifyCloudDelayMs), ("notifyDefaultDelayMs", notifyDefaultDelayMs), ("pushChatPeriodMs", pushChatPeriodMs), ("pushChatLimit", pushChatLimit), ("savedGifsLimit", savedGifsLimit), ("editTimeLimit", editTimeLimit), ("revokeTimeLimit", revokeTimeLimit), ("revokePmTimeLimit", revokePmTimeLimit), ("ratingEDecay", ratingEDecay), ("stickersRecentLimit", stickersRecentLimit), ("stickersFavedLimit", stickersFavedLimit), ("channelsReadMediaPeriod", channelsReadMediaPeriod), ("tmpSessions", tmpSessions), ("pinnedDialogsCountMax", pinnedDialogsCountMax), ("callReceiveTimeoutMs", callReceiveTimeoutMs), ("callRingTimeoutMs", callRingTimeoutMs), ("callConnectTimeoutMs", callConnectTimeoutMs), ("callPacketTimeoutMs", callPacketTimeoutMs), ("meUrlPrefix", meUrlPrefix), ("autoupdateUrlPrefix", autoupdateUrlPrefix), ("gifSearchUsername", gifSearchUsername), ("venueSearchUsername", venueSearchUsername), ("imgSearchUsername", imgSearchUsername), ("staticMapsProvider", staticMapsProvider), ("captionLengthMax", captionLengthMax), ("messageLengthMax", messageLengthMax), ("webfileDcId", webfileDcId), ("suggestedLangCode", suggestedLangCode), ("langPackVersion", langPackVersion)])
|
return ("config", [("flags", flags), ("date", date), ("expires", expires), ("testMode", testMode), ("thisDc", thisDc), ("dcOptions", dcOptions), ("dcTxtDomainName", dcTxtDomainName), ("chatSizeMax", chatSizeMax), ("megagroupSizeMax", megagroupSizeMax), ("forwardedCountMax", forwardedCountMax), ("onlineUpdatePeriodMs", onlineUpdatePeriodMs), ("offlineBlurTimeoutMs", offlineBlurTimeoutMs), ("offlineIdleTimeoutMs", offlineIdleTimeoutMs), ("onlineCloudTimeoutMs", onlineCloudTimeoutMs), ("notifyCloudDelayMs", notifyCloudDelayMs), ("notifyDefaultDelayMs", notifyDefaultDelayMs), ("pushChatPeriodMs", pushChatPeriodMs), ("pushChatLimit", pushChatLimit), ("savedGifsLimit", savedGifsLimit), ("editTimeLimit", editTimeLimit), ("revokeTimeLimit", revokeTimeLimit), ("revokePmTimeLimit", revokePmTimeLimit), ("ratingEDecay", ratingEDecay), ("stickersRecentLimit", stickersRecentLimit), ("stickersFavedLimit", stickersFavedLimit), ("channelsReadMediaPeriod", channelsReadMediaPeriod), ("tmpSessions", tmpSessions), ("pinnedDialogsCountMax", pinnedDialogsCountMax), ("callReceiveTimeoutMs", callReceiveTimeoutMs), ("callRingTimeoutMs", callRingTimeoutMs), ("callConnectTimeoutMs", callConnectTimeoutMs), ("callPacketTimeoutMs", callPacketTimeoutMs), ("meUrlPrefix", meUrlPrefix), ("autoupdateUrlPrefix", autoupdateUrlPrefix), ("gifSearchUsername", gifSearchUsername), ("venueSearchUsername", venueSearchUsername), ("imgSearchUsername", imgSearchUsername), ("staticMapsProvider", staticMapsProvider), ("captionLengthMax", captionLengthMax), ("messageLengthMax", messageLengthMax), ("webfileDcId", webfileDcId), ("suggestedLangCode", suggestedLangCode), ("langPackVersion", langPackVersion), ("baseLangPackVersion", baseLangPackVersion)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10327,6 +10328,8 @@ extension Api {
|
|||||||
if Int(_1!) & Int(1 << 2) != 0 {_42 = parseString(reader) }
|
if Int(_1!) & Int(1 << 2) != 0 {_42 = parseString(reader) }
|
||||||
var _43: Int32?
|
var _43: Int32?
|
||||||
if Int(_1!) & Int(1 << 2) != 0 {_43 = reader.readInt32() }
|
if Int(_1!) & Int(1 << 2) != 0 {_43 = reader.readInt32() }
|
||||||
|
var _44: Int32?
|
||||||
|
if Int(_1!) & Int(1 << 2) != 0 {_44 = reader.readInt32() }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -10370,8 +10373,9 @@ extension Api {
|
|||||||
let _c41 = _41 != nil
|
let _c41 = _41 != nil
|
||||||
let _c42 = (Int(_1!) & Int(1 << 2) == 0) || _42 != nil
|
let _c42 = (Int(_1!) & Int(1 << 2) == 0) || _42 != nil
|
||||||
let _c43 = (Int(_1!) & Int(1 << 2) == 0) || _43 != nil
|
let _c43 = (Int(_1!) & Int(1 << 2) == 0) || _43 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 && _c34 && _c35 && _c36 && _c37 && _c38 && _c39 && _c40 && _c41 && _c42 && _c43 {
|
let _c44 = (Int(_1!) & Int(1 << 2) == 0) || _44 != nil
|
||||||
return Api.Config.config(flags: _1!, date: _2!, expires: _3!, testMode: _4!, thisDc: _5!, dcOptions: _6!, dcTxtDomainName: _7!, chatSizeMax: _8!, megagroupSizeMax: _9!, forwardedCountMax: _10!, onlineUpdatePeriodMs: _11!, offlineBlurTimeoutMs: _12!, offlineIdleTimeoutMs: _13!, onlineCloudTimeoutMs: _14!, notifyCloudDelayMs: _15!, notifyDefaultDelayMs: _16!, pushChatPeriodMs: _17!, pushChatLimit: _18!, savedGifsLimit: _19!, editTimeLimit: _20!, revokeTimeLimit: _21!, revokePmTimeLimit: _22!, ratingEDecay: _23!, stickersRecentLimit: _24!, stickersFavedLimit: _25!, channelsReadMediaPeriod: _26!, tmpSessions: _27, pinnedDialogsCountMax: _28!, callReceiveTimeoutMs: _29!, callRingTimeoutMs: _30!, callConnectTimeoutMs: _31!, callPacketTimeoutMs: _32!, meUrlPrefix: _33!, autoupdateUrlPrefix: _34, gifSearchUsername: _35, venueSearchUsername: _36, imgSearchUsername: _37, staticMapsProvider: _38, captionLengthMax: _39!, messageLengthMax: _40!, webfileDcId: _41!, suggestedLangCode: _42, langPackVersion: _43)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 && _c34 && _c35 && _c36 && _c37 && _c38 && _c39 && _c40 && _c41 && _c42 && _c43 && _c44 {
|
||||||
|
return Api.Config.config(flags: _1!, date: _2!, expires: _3!, testMode: _4!, thisDc: _5!, dcOptions: _6!, dcTxtDomainName: _7!, chatSizeMax: _8!, megagroupSizeMax: _9!, forwardedCountMax: _10!, onlineUpdatePeriodMs: _11!, offlineBlurTimeoutMs: _12!, offlineIdleTimeoutMs: _13!, onlineCloudTimeoutMs: _14!, notifyCloudDelayMs: _15!, notifyDefaultDelayMs: _16!, pushChatPeriodMs: _17!, pushChatLimit: _18!, savedGifsLimit: _19!, editTimeLimit: _20!, revokeTimeLimit: _21!, revokePmTimeLimit: _22!, ratingEDecay: _23!, stickersRecentLimit: _24!, stickersFavedLimit: _25!, channelsReadMediaPeriod: _26!, tmpSessions: _27, pinnedDialogsCountMax: _28!, callReceiveTimeoutMs: _29!, callRingTimeoutMs: _30!, callConnectTimeoutMs: _31!, callPacketTimeoutMs: _32!, meUrlPrefix: _33!, autoupdateUrlPrefix: _34, gifSearchUsername: _35, venueSearchUsername: _36, imgSearchUsername: _37, staticMapsProvider: _38, captionLengthMax: _39!, messageLengthMax: _40!, webfileDcId: _41!, suggestedLangCode: _42, langPackVersion: _43, baseLangPackVersion: _44)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
33
TelegramCore/ConfirmTwoStepRecoveryEmail.swift
Normal file
33
TelegramCore/ConfirmTwoStepRecoveryEmail.swift
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import Foundation
|
||||||
|
#if os(macOS)
|
||||||
|
import SwiftSignalKitMac
|
||||||
|
import MtProtoKitMac
|
||||||
|
#else
|
||||||
|
import SwiftSignalKit
|
||||||
|
import MtProtoKitDynamic
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public enum ConfirmTwoStepRecoveryEmailError {
|
||||||
|
case invalidEmail
|
||||||
|
case invalidCode
|
||||||
|
case flood
|
||||||
|
case expired
|
||||||
|
case generic
|
||||||
|
}
|
||||||
|
|
||||||
|
public func confirmTwoStepRecoveryEmail(network: Network, email: String, code: String) -> Signal<Never, ConfirmTwoStepRecoveryEmailError> {
|
||||||
|
return network.request(Api.functions.account.confirmPasswordEmail(email: email, code: code), automaticFloodWait: false)
|
||||||
|
|> mapError { error -> ConfirmTwoStepRecoveryEmailError in
|
||||||
|
if error.errorDescription == "EMAIL_INVALID" {
|
||||||
|
return .invalidEmail
|
||||||
|
} else if error.errorDescription == "CODE_INVALID" {
|
||||||
|
return .invalidCode
|
||||||
|
} else if error.errorDescription == "EMAIL_HASH_EXPIRED" {
|
||||||
|
return .expired
|
||||||
|
} else if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||||
|
return .flood
|
||||||
|
}
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
|> ignoreValues
|
||||||
|
}
|
||||||
@ -8,15 +8,17 @@ import Foundation
|
|||||||
public final class LocalizationInfo: PostboxCoding {
|
public final class LocalizationInfo: PostboxCoding {
|
||||||
public let languageCode: String
|
public let languageCode: String
|
||||||
public let baseLanguageCode: String?
|
public let baseLanguageCode: String?
|
||||||
|
public let customPluralizationCode: String?
|
||||||
public let title: String
|
public let title: String
|
||||||
public let localizedTitle: String
|
public let localizedTitle: String
|
||||||
public let isOfficial: Bool
|
public let isOfficial: Bool
|
||||||
public let totalStringCount: Int32
|
public let totalStringCount: Int32
|
||||||
public let translatedStringCount: Int32
|
public let translatedStringCount: Int32
|
||||||
|
|
||||||
public init(languageCode: String, baseLanguageCode: String?, title: String, localizedTitle: String, isOfficial: Bool, totalStringCount: Int32, translatedStringCount: Int32) {
|
public init(languageCode: String, baseLanguageCode: String?, customPluralizationCode: String?, title: String, localizedTitle: String, isOfficial: Bool, totalStringCount: Int32, translatedStringCount: Int32) {
|
||||||
self.languageCode = languageCode
|
self.languageCode = languageCode
|
||||||
self.baseLanguageCode = baseLanguageCode
|
self.baseLanguageCode = baseLanguageCode
|
||||||
|
self.customPluralizationCode = customPluralizationCode
|
||||||
self.title = title
|
self.title = title
|
||||||
self.localizedTitle = localizedTitle
|
self.localizedTitle = localizedTitle
|
||||||
self.isOfficial = isOfficial
|
self.isOfficial = isOfficial
|
||||||
@ -27,6 +29,7 @@ public final class LocalizationInfo: PostboxCoding {
|
|||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
self.languageCode = decoder.decodeStringForKey("lc", orElse: "")
|
self.languageCode = decoder.decodeStringForKey("lc", orElse: "")
|
||||||
self.baseLanguageCode = decoder.decodeOptionalStringForKey("nlc")
|
self.baseLanguageCode = decoder.decodeOptionalStringForKey("nlc")
|
||||||
|
self.customPluralizationCode = decoder.decodeOptionalStringForKey("cpc")
|
||||||
self.title = decoder.decodeStringForKey("t", orElse: "")
|
self.title = decoder.decodeStringForKey("t", orElse: "")
|
||||||
self.localizedTitle = decoder.decodeStringForKey("lt", orElse: "")
|
self.localizedTitle = decoder.decodeStringForKey("lt", orElse: "")
|
||||||
self.isOfficial = decoder.decodeInt32ForKey("of", orElse: 0) != 0
|
self.isOfficial = decoder.decodeInt32ForKey("of", orElse: 0) != 0
|
||||||
@ -41,6 +44,11 @@ public final class LocalizationInfo: PostboxCoding {
|
|||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "nlc")
|
encoder.encodeNil(forKey: "nlc")
|
||||||
}
|
}
|
||||||
|
if let customPluralizationCode = self.customPluralizationCode {
|
||||||
|
encoder.encodeString(customPluralizationCode, forKey: "cpc")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "cpc")
|
||||||
|
}
|
||||||
encoder.encodeString(self.title, forKey: "t")
|
encoder.encodeString(self.title, forKey: "t")
|
||||||
encoder.encodeString(self.localizedTitle, forKey: "lt")
|
encoder.encodeString(self.localizedTitle, forKey: "lt")
|
||||||
encoder.encodeInt32(self.isOfficial ? 1 : 0, forKey: "of")
|
encoder.encodeInt32(self.isOfficial ? 1 : 0, forKey: "of")
|
||||||
@ -53,7 +61,7 @@ extension LocalizationInfo {
|
|||||||
convenience init(apiLanguage: Api.LangPackLanguage) {
|
convenience init(apiLanguage: Api.LangPackLanguage) {
|
||||||
switch apiLanguage {
|
switch apiLanguage {
|
||||||
case let .langPackLanguage(language):
|
case let .langPackLanguage(language):
|
||||||
self.init(languageCode: language.langCode, baseLanguageCode: nil/*language.baseLangCode*/, title: language.name, localizedTitle: language.nativeName, isOfficial: true/*(language.flags & (1 << 0)) != 0*/, totalStringCount: 1/*language.stringsCount*/, translatedStringCount: 1/*language.translatedCount*/)
|
self.init(languageCode: language.langCode, baseLanguageCode: language.baseLangCode, customPluralizationCode: language.pluralCode, title: language.name, localizedTitle: language.nativeName, isOfficial: (language.flags & (1 << 0)) != 0, totalStringCount: language.stringsCount, translatedStringCount: language.translatedCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,13 +12,12 @@ public enum RequestLocalizationPreviewError {
|
|||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
public func requestLocalizationPreview(postbox: Postbox, network: Network, identifier: String) -> Signal<LocalizationInfo, RequestLocalizationPreviewError> {
|
public func requestLocalizationPreview(network: Network, identifier: String) -> Signal<LocalizationInfo, RequestLocalizationPreviewError> {
|
||||||
return .never()
|
return network.request(Api.functions.langpack.getLanguage(langPack: "", langCode: identifier))
|
||||||
/*return network.request(Api.functions.langpack.getLanguage(langPack: "", langCode: identifier))
|
|
||||||
|> mapError { _ -> RequestLocalizationPreviewError in
|
|> mapError { _ -> RequestLocalizationPreviewError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|> map { language -> LocalizationInfo in
|
|> map { language -> LocalizationInfo in
|
||||||
return LocalizationInfo(apiLanguage: language)
|
return LocalizationInfo(apiLanguage: language)
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,23 +5,73 @@ import Foundation
|
|||||||
import Postbox
|
import Postbox
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public final class LocalizationSettings: PreferencesEntry, Equatable {
|
public final class LocalizationComponent: Equatable, PostboxCoding {
|
||||||
public let languageCode: String
|
public let languageCode: String
|
||||||
public let localization: Localization
|
public let localization: Localization
|
||||||
|
public let customPluralizationCode: String?
|
||||||
|
|
||||||
public init(languageCode: String, localization: Localization) {
|
public init(languageCode: String, localization: Localization, customPluralizationCode: String?) {
|
||||||
self.languageCode = languageCode
|
self.languageCode = languageCode
|
||||||
self.localization = localization
|
self.localization = localization
|
||||||
|
self.customPluralizationCode = customPluralizationCode
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
self.languageCode = decoder.decodeStringForKey("lc", orElse: "en")
|
self.languageCode = decoder.decodeStringForKey("lc", orElse: "")
|
||||||
self.localization = decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization
|
self.localization = decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization
|
||||||
|
self.customPluralizationCode = decoder.decodeOptionalStringForKey("cpl")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
encoder.encodeString(self.languageCode, forKey: "lc")
|
encoder.encodeString(self.languageCode, forKey: "lc")
|
||||||
encoder.encodeObject(self.localization, forKey: "loc")
|
encoder.encodeObject(self.localization, forKey: "loc")
|
||||||
|
if let customPluralizationCode = self.customPluralizationCode {
|
||||||
|
encoder.encodeString(customPluralizationCode, forKey: "cpl")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "cpl")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: LocalizationComponent, rhs: LocalizationComponent) -> Bool {
|
||||||
|
if lhs.languageCode != rhs.languageCode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.localization != rhs.localization {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.customPluralizationCode != rhs.customPluralizationCode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class LocalizationSettings: PreferencesEntry, Equatable {
|
||||||
|
public let primaryComponent: LocalizationComponent
|
||||||
|
public let secondaryComponent: LocalizationComponent?
|
||||||
|
|
||||||
|
public init(primaryComponent: LocalizationComponent, secondaryComponent: LocalizationComponent?) {
|
||||||
|
self.primaryComponent = primaryComponent
|
||||||
|
self.secondaryComponent = secondaryComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(decoder: PostboxDecoder) {
|
||||||
|
if let languageCode = decoder.decodeOptionalStringForKey("lc") {
|
||||||
|
self.primaryComponent = LocalizationComponent(languageCode: languageCode, localization: decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization, customPluralizationCode: nil)
|
||||||
|
self.secondaryComponent = nil
|
||||||
|
} else {
|
||||||
|
self.primaryComponent = decoder.decodeObjectForKey("primaryComponent", decoder: { LocalizationComponent(decoder: $0) }) as! LocalizationComponent
|
||||||
|
self.secondaryComponent = decoder.decodeObjectForKey("secondaryComponent", decoder: { LocalizationComponent(decoder: $0) }) as? LocalizationComponent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
|
encoder.encodeObject(self.primaryComponent, forKey: "primaryComponent")
|
||||||
|
if let secondaryComponent = self.secondaryComponent {
|
||||||
|
encoder.encodeObject(secondaryComponent, forKey: "secondaryComponent")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "secondaryComponent")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isEqual(to: PreferencesEntry) -> Bool {
|
public func isEqual(to: PreferencesEntry) -> Bool {
|
||||||
@ -33,6 +83,6 @@ public final class LocalizationSettings: PreferencesEntry, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: LocalizationSettings, rhs: LocalizationSettings) -> Bool {
|
public static func ==(lhs: LocalizationSettings, rhs: LocalizationSettings) -> Bool {
|
||||||
return lhs.languageCode == rhs.languageCode && lhs.localization == rhs.localization
|
return lhs.primaryComponent == rhs.primaryComponent && lhs.secondaryComponent == rhs.secondaryComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -114,35 +114,53 @@ public func downloadLocalization(network: Network, languageCode: String) -> Sign
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DownoadAndApplyLocalizationError {
|
public enum DownloadAndApplyLocalizationError {
|
||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
public func downoadAndApplyLocalization(postbox: Postbox, network: Network, languageCode: String) -> Signal<Void, DownoadAndApplyLocalizationError> {
|
public func downloadAndApplyLocalization(postbox: Postbox, network: Network, languageCode: String) -> Signal<Void, DownloadAndApplyLocalizationError> {
|
||||||
return downloadLocalization(network: network, languageCode: languageCode)
|
return requestLocalizationPreview(network: network, identifier: languageCode)
|
||||||
|> mapError { _ -> DownoadAndApplyLocalizationError in
|
|> mapError { _ -> DownloadAndApplyLocalizationError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|> mapToSignal { language -> Signal<Void, DownoadAndApplyLocalizationError> in
|
|> mapToSignal { preview -> Signal<Void, DownloadAndApplyLocalizationError> in
|
||||||
return postbox.transaction { transaction -> Signal<Void, DownoadAndApplyLocalizationError> in
|
var primaryAndSecondaryLocalizations: [Signal<Localization, DownloadLocalizationError>] = []
|
||||||
transaction.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in
|
primaryAndSecondaryLocalizations.append(downloadLocalization(network: network, languageCode: preview.languageCode))
|
||||||
return LocalizationSettings(languageCode: languageCode, localization: language)
|
if let secondaryCode = preview.baseLanguageCode {
|
||||||
})
|
primaryAndSecondaryLocalizations.append(downloadLocalization(network: network, languageCode: secondaryCode))
|
||||||
|
}
|
||||||
network.context.updateApiEnvironment { current in
|
return combineLatest(primaryAndSecondaryLocalizations)
|
||||||
return current?.withUpdatedLangPackCode(languageCode)
|
|> mapError { _ -> DownloadAndApplyLocalizationError in
|
||||||
}
|
return .generic
|
||||||
|
}
|
||||||
return network.request(Api.functions.help.test())
|
|> mapToSignal { components -> Signal<Void, DownloadAndApplyLocalizationError> in
|
||||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
guard let primaryLocalization = components.first else {
|
||||||
return .complete()
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
var secondaryComponent: LocalizationComponent?
|
||||||
return .complete()
|
if let secondaryCode = preview.baseLanguageCode, components.count > 1 {
|
||||||
}
|
secondaryComponent = LocalizationComponent(languageCode: secondaryCode, localization: components[1], customPluralizationCode: nil)
|
||||||
|> introduceError(DownoadAndApplyLocalizationError.self)
|
}
|
||||||
|
return postbox.transaction { transaction -> Signal<Void, DownloadAndApplyLocalizationError> in
|
||||||
|
transaction.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in
|
||||||
|
return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: preview.languageCode, localization: primaryLocalization, customPluralizationCode: preview.customPluralizationCode), secondaryComponent: secondaryComponent)
|
||||||
|
})
|
||||||
|
|
||||||
|
network.context.updateApiEnvironment { current in
|
||||||
|
return current?.withUpdatedLangPackCode(preview.languageCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return network.request(Api.functions.help.test())
|
||||||
|
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
|> introduceError(DownloadAndApplyLocalizationError.self)
|
||||||
|
}
|
||||||
|
|> introduceError(DownloadAndApplyLocalizationError.self)
|
||||||
|
|> switchToLatest
|
||||||
}
|
}
|
||||||
|> introduceError(DownoadAndApplyLocalizationError.self)
|
|
||||||
|> switchToLatest
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,8 +68,17 @@ func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<V
|
|||||||
return configuration
|
return configuration
|
||||||
})
|
})
|
||||||
|
|
||||||
let (_, version, _) = getLocalization(transaction)
|
let (primary, secondary) = getLocalization(transaction)
|
||||||
if version != config.langPackVersion {
|
var invalidateLocalization = false
|
||||||
|
if primary.version != config.langPackVersion {
|
||||||
|
invalidateLocalization = true
|
||||||
|
}
|
||||||
|
if let secondary = secondary, let baseLangPackVersion = config.baseLangPackVersion {
|
||||||
|
if secondary.version != baseLangPackVersion {
|
||||||
|
invalidateLocalization = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if invalidateLocalization {
|
||||||
addSynchronizeLocalizationUpdatesOperation(transaction: transaction)
|
addSynchronizeLocalizationUpdatesOperation(transaction: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -120,7 +120,7 @@ private enum SynchronizeLocalizationUpdatesError {
|
|||||||
case reset
|
case reset
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLocalization(_ transaction: Transaction) -> (String, Int32, [LocalizationEntry]) {
|
func getLocalization(_ transaction: Transaction) -> (primary: (code: String, version: Int32, entries: [LocalizationEntry]), secondary: (code: String, version: Int32, entries: [LocalizationEntry])?) {
|
||||||
let localizationSettings: LocalizationSettings?
|
let localizationSettings: LocalizationSettings?
|
||||||
if let current = transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings {
|
if let current = transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings {
|
||||||
localizationSettings = current
|
localizationSettings = current
|
||||||
@ -128,76 +128,98 @@ func getLocalization(_ transaction: Transaction) -> (String, Int32, [Localizatio
|
|||||||
localizationSettings = nil
|
localizationSettings = nil
|
||||||
}
|
}
|
||||||
if let localizationSettings = localizationSettings {
|
if let localizationSettings = localizationSettings {
|
||||||
return (localizationSettings.languageCode, localizationSettings.localization.version, localizationSettings.localization.entries)
|
return (primary: (localizationSettings.primaryComponent.languageCode, localizationSettings.primaryComponent.localization.version, localizationSettings.primaryComponent.localization.entries), secondary: localizationSettings.secondaryComponent.flatMap({ ($0.languageCode, $0.localization.version, $0.localization.entries) }))
|
||||||
} else {
|
} else {
|
||||||
return ("en", 0, [])
|
return (primary: ("en", 0, []), secondary: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func parseLangPackDifference(_ difference: Api.LangPackDifference) -> (code: String, fromVersion: Int32, version: Int32, entries: [LocalizationEntry]) {
|
||||||
|
switch difference {
|
||||||
|
case let .langPackDifference(code, fromVersion, version, strings):
|
||||||
|
var entries: [LocalizationEntry] = []
|
||||||
|
for string in strings {
|
||||||
|
switch string {
|
||||||
|
case let .langPackString(key, value):
|
||||||
|
entries.append(.string(key: key, value: value))
|
||||||
|
case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue):
|
||||||
|
entries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue))
|
||||||
|
case let .langPackStringDeleted(key):
|
||||||
|
entries.append(.string(key: key, value: ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (code, fromVersion, version, entries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||||
let currentLanguageAndVersion = postbox.transaction { transaction -> (String, Int32) in
|
let currentLanguageAndVersion = postbox.transaction { transaction -> (primary: (code: String, version: Int32), secondary: (code: String, version: Int32)?) in
|
||||||
let (code, version, _) = getLocalization(transaction)
|
let (primary, secondary) = getLocalization(transaction)
|
||||||
return (code, version)
|
return ((primary.code, primary.version), secondary.flatMap({ ($0.code, $0.version) }))
|
||||||
}
|
}
|
||||||
|
|
||||||
let poll = currentLanguageAndVersion
|
let poll = currentLanguageAndVersion
|
||||||
|> mapError { _ -> SynchronizeLocalizationUpdatesError in return .done }
|
|> introduceError(SynchronizeLocalizationUpdatesError.self)
|
||||||
|> mapToSignal { (languageCode, fromVersion) -> Signal<Void, SynchronizeLocalizationUpdatesError> in
|
|> mapToSignal { (primary, secondary) -> Signal<Void, SynchronizeLocalizationUpdatesError> in
|
||||||
return network.request(Api.functions.langpack.getDifference(langCode: languageCode, fromVersion: fromVersion))
|
var differences: [Signal<Api.LangPackDifference, MTRpcError>] = []
|
||||||
|> mapError { _ -> SynchronizeLocalizationUpdatesError in return .reset }
|
differences.append(network.request(Api.functions.langpack.getDifference(langCode: primary.code, fromVersion: primary.version)))
|
||||||
|> mapToSignal { result -> Signal<Void, SynchronizeLocalizationUpdatesError> in
|
if let secondary = secondary {
|
||||||
let updatedCode: String
|
differences.append(network.request(Api.functions.langpack.getDifference(langCode: secondary.code, fromVersion: secondary.version)))
|
||||||
let updatedVersion: Int32
|
}
|
||||||
var updatedEntries: [LocalizationEntry] = []
|
|
||||||
switch result {
|
return combineLatest(differences)
|
||||||
case let .langPackDifference(code, _, versionValue, strings):
|
|> mapError { _ -> SynchronizeLocalizationUpdatesError in return .reset }
|
||||||
updatedCode = code
|
|> mapToSignal { differences -> Signal<Void, SynchronizeLocalizationUpdatesError> in
|
||||||
updatedVersion = versionValue
|
let parsedDifferences = differences.map(parseLangPackDifference)
|
||||||
for string in strings {
|
return postbox.transaction { transaction -> Signal<Void, SynchronizeLocalizationUpdatesError> in
|
||||||
switch string {
|
let (primary, secondary) = getLocalization(transaction)
|
||||||
case let .langPackString(key, value):
|
|
||||||
updatedEntries.append(.string(key: key, value: value))
|
|
||||||
case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue):
|
|
||||||
updatedEntries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue))
|
|
||||||
case let .langPackStringDeleted(key):
|
|
||||||
updatedEntries.append(.string(key: key, value: ""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return postbox.transaction { transaction -> Signal<Void, SynchronizeLocalizationUpdatesError> in
|
var currentSettings = transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings ?? LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: "en", localization: Localization(version: 0, entries: []), customPluralizationCode: nil), secondaryComponent: nil)
|
||||||
let (code, version, entries) = getLocalization(transaction)
|
|
||||||
|
for difference in parsedDifferences {
|
||||||
if code == updatedCode {
|
let current: (isPrimary: Bool, entries: [LocalizationEntry])
|
||||||
if fromVersion == version {
|
if difference.code == primary.code {
|
||||||
var updatedEntryKeys = Set<String>()
|
if primary.version != difference.fromVersion {
|
||||||
for entry in updatedEntries {
|
|
||||||
updatedEntryKeys.insert(entry.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
var mergedEntries: [LocalizationEntry] = []
|
|
||||||
for entry in entries {
|
|
||||||
if !updatedEntryKeys.contains(entry.key) {
|
|
||||||
mergedEntries.append(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mergedEntries.append(contentsOf: updatedEntries)
|
|
||||||
|
|
||||||
transaction.setPreferencesEntry(key: PreferencesKeys.localizationSettings, value: LocalizationSettings(languageCode: updatedCode, localization: Localization(version: updatedVersion, entries: mergedEntries)))
|
|
||||||
|
|
||||||
return .fail(.done)
|
|
||||||
} else {
|
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|
current = (true, primary.entries)
|
||||||
|
} else if let secondary = secondary, difference.code == secondary.code {
|
||||||
|
if secondary.version != difference.fromVersion {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
current = (false, secondary.entries)
|
||||||
} else {
|
} else {
|
||||||
return .fail(.reset)
|
return .fail(.reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var updatedEntryKeys = Set<String>()
|
||||||
|
for entry in difference.entries {
|
||||||
|
updatedEntryKeys.insert(entry.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mergedEntries: [LocalizationEntry] = []
|
||||||
|
for entry in current.entries {
|
||||||
|
if !updatedEntryKeys.contains(entry.key) {
|
||||||
|
mergedEntries.append(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mergedEntries.append(contentsOf: difference.entries)
|
||||||
|
if current.isPrimary {
|
||||||
|
currentSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent)
|
||||||
|
} else if let currentSecondary = currentSettings.secondaryComponent {
|
||||||
|
currentSettings = LocalizationSettings(primaryComponent: currentSettings.primaryComponent, secondaryComponent: LocalizationComponent(languageCode: currentSecondary.languageCode, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSecondary.customPluralizationCode))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|> mapError { _ -> SynchronizeLocalizationUpdatesError in return .reset
|
|
||||||
}
|
transaction.setPreferencesEntry(key: PreferencesKeys.localizationSettings, value: currentSettings)
|
||||||
|> switchToLatest
|
return .fail(.done)
|
||||||
}
|
}
|
||||||
|
|> mapError { _ -> SynchronizeLocalizationUpdatesError in
|
||||||
|
return .reset
|
||||||
|
}
|
||||||
|
|> switchToLatest
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ((poll
|
return ((poll
|
||||||
|> `catch` { error -> Signal<Void, Void> in
|
|> `catch` { error -> Signal<Void, Void> in
|
||||||
@ -206,8 +228,8 @@ private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: P
|
|||||||
return .fail(Void())
|
return .fail(Void())
|
||||||
case .reset:
|
case .reset:
|
||||||
return postbox.transaction { transaction -> Signal<Void, Void> in
|
return postbox.transaction { transaction -> Signal<Void, Void> in
|
||||||
let (code, _, _) = getLocalization(transaction)
|
let (primary, _) = getLocalization(transaction)
|
||||||
return downoadAndApplyLocalization(postbox: postbox, network: network, languageCode: code)
|
return downloadAndApplyLocalization(postbox: postbox, network: network, languageCode: primary.code)
|
||||||
|> mapError { _ -> Void in
|
|> mapError { _ -> Void in
|
||||||
return Void()
|
return Void()
|
||||||
}
|
}
|
||||||
@ -221,41 +243,61 @@ private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: P
|
|||||||
}
|
}
|
||||||
|
|
||||||
func tryApplyingLanguageDifference(transaction: Transaction, langCode: String, difference: Api.LangPackDifference) -> Bool {
|
func tryApplyingLanguageDifference(transaction: Transaction, langCode: String, difference: Api.LangPackDifference) -> Bool {
|
||||||
let (code, version, entries) = getLocalization(transaction)
|
let (primary, secondary) = getLocalization(transaction)
|
||||||
switch difference {
|
switch difference {
|
||||||
case let .langPackDifference(updatedCode, fromVersion, updatedVersion, strings):
|
case let .langPackDifference(updatedCode, fromVersion, updatedVersion, strings):
|
||||||
if fromVersion == version && updatedCode == code {
|
var current: (isPrimary: Bool, version: Int32, entries: [LocalizationEntry])?
|
||||||
var updatedEntries: [LocalizationEntry] = []
|
if updatedCode == primary.code {
|
||||||
|
current = (true, primary.version, primary.entries)
|
||||||
for string in strings {
|
} else if let secondary = secondary, secondary.code == updatedCode {
|
||||||
switch string {
|
current = (false, secondary.version, secondary.entries)
|
||||||
case let .langPackString(key, value):
|
}
|
||||||
updatedEntries.append(.string(key: key, value: value))
|
guard let (isPrimary, version, entries) = current else {
|
||||||
case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue):
|
|
||||||
updatedEntries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue))
|
|
||||||
case let .langPackStringDeleted(key):
|
|
||||||
updatedEntries.append(.string(key: key, value: ""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var updatedEntryKeys = Set<String>()
|
|
||||||
for entry in updatedEntries {
|
|
||||||
updatedEntryKeys.insert(entry.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
var mergedEntries: [LocalizationEntry] = []
|
|
||||||
for entry in entries {
|
|
||||||
if !updatedEntryKeys.contains(entry.key) {
|
|
||||||
mergedEntries.append(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mergedEntries.append(contentsOf: updatedEntries)
|
|
||||||
|
|
||||||
transaction.setPreferencesEntry(key: PreferencesKeys.localizationSettings, value: LocalizationSettings(languageCode: updatedCode, localization: Localization(version: updatedVersion, entries: mergedEntries)))
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
guard fromVersion == version else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var updatedEntries: [LocalizationEntry] = []
|
||||||
|
|
||||||
|
for string in strings {
|
||||||
|
switch string {
|
||||||
|
case let .langPackString(key, value):
|
||||||
|
updatedEntries.append(.string(key: key, value: value))
|
||||||
|
case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue):
|
||||||
|
updatedEntries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue))
|
||||||
|
case let .langPackStringDeleted(key):
|
||||||
|
updatedEntries.append(.string(key: key, value: ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var updatedEntryKeys = Set<String>()
|
||||||
|
for entry in updatedEntries {
|
||||||
|
updatedEntryKeys.insert(entry.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mergedEntries: [LocalizationEntry] = []
|
||||||
|
for entry in entries {
|
||||||
|
if !updatedEntryKeys.contains(entry.key) {
|
||||||
|
mergedEntries.append(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mergedEntries.append(contentsOf: updatedEntries)
|
||||||
|
|
||||||
|
let currentSettings = transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings ?? LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: "en", localization: Localization(version: 0, entries: []), customPluralizationCode: nil), secondaryComponent: nil)
|
||||||
|
|
||||||
|
var updatedSettings: LocalizationSettings
|
||||||
|
if isPrimary {
|
||||||
|
updatedSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localization: Localization(version: updatedVersion, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent)
|
||||||
|
} else if let currentSecondary = currentSettings.secondaryComponent {
|
||||||
|
updatedSettings = LocalizationSettings(primaryComponent: currentSettings.primaryComponent, secondaryComponent: LocalizationComponent(languageCode: currentSecondary.languageCode, localization: Localization(version: updatedVersion, entries: mergedEntries), customPluralizationCode: currentSecondary.customPluralizationCode))
|
||||||
|
} else {
|
||||||
|
assertionFailure()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.setPreferencesEntry(key: PreferencesKeys.localizationSettings, value: updatedSettings)
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,23 +10,23 @@ import Foundation
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public enum TwoStepVerificationConfiguration {
|
public enum TwoStepVerificationConfiguration {
|
||||||
case notSet(pendingEmailPattern: String)
|
case notSet(pendingEmail: TwoStepVerificationPendingEmail?)
|
||||||
case set(hint: String, hasRecoveryEmail: Bool, pendingEmailPattern: String, hasSecureValues: Bool)
|
case set(hint: String, hasRecoveryEmail: Bool, pendingEmail: TwoStepVerificationPendingEmail?, hasSecureValues: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func twoStepVerificationConfiguration(account: Account) -> Signal<TwoStepVerificationConfiguration, NoError> {
|
public func twoStepVerificationConfiguration(account: Account) -> Signal<TwoStepVerificationConfiguration, NoError> {
|
||||||
return account.network.request(Api.functions.account.getPassword())
|
return account.network.request(Api.functions.account.getPassword())
|
||||||
|> retryRequest
|
|> retryRequest
|
||||||
|> map { result -> TwoStepVerificationConfiguration in
|
|> map { result -> TwoStepVerificationConfiguration in
|
||||||
switch result {
|
switch result {
|
||||||
case let .password(password):
|
case let .password(password):
|
||||||
if password.currentAlgo != nil {
|
if password.currentAlgo != nil {
|
||||||
return .set(hint: password.hint ?? "", hasRecoveryEmail: (password.flags & (1 << 0)) != 0, pendingEmailPattern: password.emailUnconfirmedPattern ?? "", hasSecureValues: (password.flags & (1 << 1)) != 0)
|
return .set(hint: password.hint ?? "", hasRecoveryEmail: (password.flags & (1 << 0)) != 0, pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) }), hasSecureValues: (password.flags & (1 << 1)) != 0)
|
||||||
} else {
|
} else {
|
||||||
return .notSet(pendingEmailPattern: password.emailUnconfirmedPattern ?? "")
|
return .notSet(pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) }))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct TwoStepVerificationSecureSecret {
|
public struct TwoStepVerificationSecureSecret {
|
||||||
@ -97,6 +97,11 @@ public enum UpdateTwoStepVerificationPasswordError {
|
|||||||
public struct TwoStepVerificationPendingEmail {
|
public struct TwoStepVerificationPendingEmail {
|
||||||
public let pattern: String
|
public let pattern: String
|
||||||
public let codeLength: Int32?
|
public let codeLength: Int32?
|
||||||
|
|
||||||
|
public init(pattern: String, codeLength: Int32?) {
|
||||||
|
self.pattern = pattern
|
||||||
|
self.codeLength = codeLength
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum UpdateTwoStepVerificationPasswordResult {
|
public enum UpdateTwoStepVerificationPasswordResult {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user