From ae7c0af98aad35ceda1d6ff6d2dc776abb79058c Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 26 May 2017 13:11:25 +0300 Subject: [PATCH] no message --- TelegramCore.xcodeproj/project.pbxproj | 46 +++ TelegramCore/Account.swift | 82 +++-- TelegramCore/AccountState.swift | 26 +- TelegramCore/AccountViewTracker.swift | 205 +++++++++++ TelegramCore/Api.swift | 323 +++++++++++++++++- .../ApplyMaxReadIndexInteractively.swift | 4 +- TelegramCore/ApplyUpdateMessage.swift | 4 +- TelegramCore/ArchivedStickerPacksInfo.swift | 2 +- .../AutoremoveTimeoutMessageAttribute.swift | 4 +- TelegramCore/BotInfo.swift | 6 +- TelegramCore/CacheStorageSettings.swift | 2 +- TelegramCore/CachedChannelData.swift | 14 +- TelegramCore/CachedChannelParticipants.swift | 12 +- TelegramCore/CachedGroupData.swift | 4 +- TelegramCore/CachedGroupParticipants.swift | 12 +- TelegramCore/CachedUserData.swift | 8 +- TelegramCore/ChannelState.swift | 2 +- TelegramCore/ChatContextResult.swift | 6 +- .../CloudChatRemoveMessagesOperation.swift | 12 +- TelegramCore/CloudFileMediaResource.swift | 42 +-- .../ConsumableContentMessageAttribute.swift | 2 +- TelegramCore/EditedMessageAttribute.swift | 2 +- TelegramCore/EnqueueMessage.swift | 8 +- TelegramCore/ExportedInvitation.swift | 2 +- TelegramCore/FeaturedStickerPack.swift | 2 +- TelegramCore/ForwardSourceInfoAttribute.swift | 2 +- TelegramCore/GlobalNotificationSettings.swift | 4 +- TelegramCore/Holes.swift | 78 +++++ TelegramCore/InlineBotMessageAttribute.swift | 2 +- TelegramCore/InstantPage.swift | 22 +- TelegramCore/Localization.swift | 249 ++++++++++++++ TelegramCore/LocalizationInfo.swift | 26 ++ TelegramCore/LocalizationSettings.swift | 40 +++ TelegramCore/Localizations.swift | 83 +++++ TelegramCore/Log.swift | 34 +- .../ManagedAutoremoveMessageOperations.swift | 1 + .../ManagedConfigurationUpdates.swift | 59 ++-- ...essageContentAsConsumedInteractively.swift | 4 +- TelegramCore/Namespaces.swift | 24 +- TelegramCore/Network.swift | 5 +- ...ingChatContextResultMessageAttribute.swift | 4 +- .../OutgoingContentInfoMessageAttribute.swift | 2 +- .../OutgoingMessageInfoAttribute.swift | 4 +- TelegramCore/PeerAccessRestrictionInfo.swift | 2 +- ...ecretChatIncomingDecryptedOperations.swift | 4 +- .../ReplyMarkupMessageAttribute.swift | 10 +- TelegramCore/ReplyMessageAttribute.swift | 4 +- TelegramCore/ResolvePeerByName.swift | 4 +- TelegramCore/RichText.swift | 12 +- TelegramCore/SecretChatEncryptionConfig.swift | 4 +- TelegramCore/SecretChatFileReference.swift | 10 +- ...SecretChatIncomingDecryptedOperation.swift | 8 +- ...SecretChatIncomingEncryptedOperation.swift | 10 +- TelegramCore/SecretChatKeychain.swift | 8 +- .../SecretChatOutgoingOperation.swift | 46 +-- TelegramCore/SecretChatState.swift | 42 +-- TelegramCore/Serialization.swift | 4 +- TelegramCore/StickerPack.swift | 16 +- TelegramCore/StoreMessage_Telegram.swift | 34 +- TelegramCore/SuggestedLocalizationEntry.swift | 51 +++ .../SynchronizeSavedGifsOperation.swift | 6 +- .../SynchronizeableChatInputState.swift | 6 +- TelegramCore/TelegramChannel.swift | 24 +- TelegramCore/TelegramGroup.swift | 20 +- TelegramCore/TelegramMediaAction.swift | 20 +- TelegramCore/TelegramMediaContact.swift | 8 +- TelegramCore/TelegramMediaFile.swift | 22 +- TelegramCore/TelegramMediaGame.swift | 10 +- TelegramCore/TelegramMediaImage.swift | 2 +- TelegramCore/TelegramMediaMap.swift | 22 +- TelegramCore/TelegramMediaWebpage.swift | 26 +- .../TelegramPeerNotificationSettings.swift | 10 +- TelegramCore/TelegramSecretChat.swift | 14 +- TelegramCore/TelegramUser.swift | 18 +- TelegramCore/TelegramUserPresence.swift | 4 +- .../TextEntitiesMessageAttribute.swift | 8 +- TelegramCore/ViewCountMessageAttribute.swift | 2 +- 77 files changed, 1558 insertions(+), 408 deletions(-) create mode 100644 TelegramCore/Localization.swift create mode 100644 TelegramCore/LocalizationInfo.swift create mode 100644 TelegramCore/LocalizationSettings.swift create mode 100644 TelegramCore/Localizations.swift create mode 100644 TelegramCore/SuggestedLocalizationEntry.swift diff --git a/TelegramCore.xcodeproj/project.pbxproj b/TelegramCore.xcodeproj/project.pbxproj index a66067b939..26d6661645 100644 --- a/TelegramCore.xcodeproj/project.pbxproj +++ b/TelegramCore.xcodeproj/project.pbxproj @@ -289,6 +289,16 @@ D07827CB1E02F5B200071108 /* RichText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827CA1E02F5B200071108 /* RichText.swift */; }; D08774FC1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */; }; D08774FE1E3E3A3500A97350 /* GlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */; }; + D08CAA7D1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */; }; + D08CAA7E1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */; }; + D08CAA801ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */; }; + D08CAA811ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */; }; + D08CAA841ED8164B0000FDA8 /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA831ED8164B0000FDA8 /* Localization.swift */; }; + D08CAA851ED8164B0000FDA8 /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA831ED8164B0000FDA8 /* Localization.swift */; }; + D08CAA871ED81DD40000FDA8 /* LocalizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */; }; + D08CAA881ED81DD40000FDA8 /* LocalizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */; }; + D08CAA8C1ED81EDF0000FDA8 /* Localizations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */; }; + D08CAA8D1ED81EDF0000FDA8 /* Localizations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */; }; D08F4A661E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */; }; D08F4A671E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */; }; D08F4A691E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */; }; @@ -676,6 +686,11 @@ D07827CA1E02F5B200071108 /* RichText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RichText.swift; sourceTree = ""; }; D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedGlobalNotificationSettings.swift; sourceTree = ""; }; D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalNotificationSettings.swift; sourceTree = ""; }; + D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationSettings.swift; sourceTree = ""; }; + D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuggestedLocalizationEntry.swift; sourceTree = ""; }; + D08CAA831ED8164B0000FDA8 /* Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = ""; }; + D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationInfo.swift; sourceTree = ""; }; + D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localizations.swift; sourceTree = ""; }; D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeInstalledStickerPacksOperations.swift; sourceTree = ""; }; D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeInstalledStickerPacksOperations.swift; sourceTree = ""; }; D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerCommands.swift; sourceTree = ""; }; @@ -842,6 +857,7 @@ D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */, D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */, D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */, + D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */, ); name = Settings; sourceTree = ""; @@ -945,6 +961,7 @@ D0FA8B961E1E952D001E855B /* Secret Chats */, D021E0DD1DB539E800C6B04F /* Item Collections */, D01B27A01E394D7B0022A4C0 /* Settings */, + D08CAA821ED816290000FDA8 /* Localization */, ); name = Objects; sourceTree = ""; @@ -1208,6 +1225,24 @@ name = Frameworks; sourceTree = ""; }; + D08CAA821ED816290000FDA8 /* Localization */ = { + isa = PBXGroup; + children = ( + D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */, + D08CAA831ED8164B0000FDA8 /* Localization.swift */, + D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */, + ); + name = Localization; + sourceTree = ""; + }; + D08CAA8A1ED81EA10000FDA8 /* Localization */ = { + isa = PBXGroup; + children = ( + D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */, + ); + name = Localization; + sourceTree = ""; + }; D09D8BF71D4FAB1D0081DBEC = { isa = PBXGroup; children = ( @@ -1247,6 +1282,7 @@ D0C50E2F1E93A83B00F62E39 /* Calls */, D021E0E01DB5400200C6B04F /* Sticker Management */, D05A32DF1E6F096B002760B4 /* Settings */, + D08CAA8A1ED81EA10000FDA8 /* Localization */, D03B0E3A1D631E4400955575 /* Supporting Files */, D09D8C041D4FAB1D0081DBEC /* TelegramCore.h */, D09D8C051D4FAB1D0081DBEC /* Info.plist */, @@ -1592,6 +1628,7 @@ D0E23DD51E8042F500B9B6D2 /* FeaturedStickerPack.swift in Sources */, D0FA8B981E1E955C001E855B /* SecretChatOutgoingOperation.swift in Sources */, D0DF0C911D81A857008AEB01 /* ImageRepresentationsUtils.swift in Sources */, + D08CAA8C1ED81EDF0000FDA8 /* Localizations.swift in Sources */, D0E6521F1E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */, D0F3A8A21E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift in Sources */, D03B0D5A1D631A6900955575 /* Api.swift in Sources */, @@ -1601,6 +1638,7 @@ D0B843B21DA7FF30005F29E1 /* NBAsYouTypeFormatter.m in Sources */, D03B0CDB1D62245F00955575 /* ApiUtils.swift in Sources */, D0B843C91DA7FF30005F29E1 /* NBPhoneNumberDesc.m in Sources */, + D08CAA801ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */, D03B0CE61D6224A700955575 /* ReplyMessageAttribute.swift in Sources */, D0BEAF601E54ACF900BD963D /* AccountManager.swift in Sources */, D0FA0ABD1E76C908005BB9B7 /* TwoStepVerification.swift in Sources */, @@ -1664,6 +1702,7 @@ D0F7AB2F1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */, D0B843971DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift in Sources */, D0448CA21E291B14005A61A7 /* FetchSecretFileResource.swift in Sources */, + D08CAA871ED81DD40000FDA8 /* LocalizationInfo.swift in Sources */, D033FEB61E61F3F900644997 /* BlockedPeers.swift in Sources */, D00C7CCC1E3620C30080C3D5 /* CachedChannelParticipants.swift in Sources */, D09BB6B41DB02C2B00A905C0 /* PendingMessageManager.swift in Sources */, @@ -1683,6 +1722,7 @@ D0B843831DA6EDB8005F29E1 /* CachedGroupData.swift in Sources */, D0E35A121DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */, C239BE9C1E630CA700C2C453 /* UpdatePinnedMessage.swift in Sources */, + D08CAA7D1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */, D0B844531DAC0773005F29E1 /* TelegramUserPresence.swift in Sources */, D08F4A661E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */, D05A32E71E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */, @@ -1742,6 +1782,7 @@ C2366C861E4F403C0097CCFF /* AddressNames.swift in Sources */, D0B843C11DA7FF30005F29E1 /* NBPhoneMetaData.m in Sources */, D0528E601E65B94E00E2FEF5 /* SingleMessageView.swift in Sources */, + D08CAA841ED8164B0000FDA8 /* Localization.swift in Sources */, D0528E5A1E658B3600E2FEF5 /* ManagedLocalInputActivities.swift in Sources */, D0FA8BA41E1FA341001E855B /* SecretChatKeychain.swift in Sources */, D01749601E118FC30057C89A /* AccountIntermediateState.swift in Sources */, @@ -1868,6 +1909,7 @@ D0B844131DAB91CD005F29E1 /* StringFormat.swift in Sources */, D0E35A131DE4C69100BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */, D0B418961D7E0580004562A4 /* TelegramMediaFile.swift in Sources */, + D08CAA881ED81DD40000FDA8 /* LocalizationInfo.swift in Sources */, D001F3EC1E128A1C007A8C60 /* Holes.swift in Sources */, D0B4189B1D7E0580004562A4 /* TelegramMediaWebpage.swift in Sources */, D00C7CE11E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */, @@ -1880,6 +1922,7 @@ D0613FD01E60520700202CDB /* ChannelMembers.swift in Sources */, D001F3E81E128A1C007A8C60 /* ChannelState.swift in Sources */, C2366C8A1E4F40480097CCFF /* SupportPeerId.swift in Sources */, + D08CAA811ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */, D0B844451DAB91FD005F29E1 /* AccountViewTracker.swift in Sources */, D0C48F3D1E8142EF0075317D /* LoadedPeerFromMessage.swift in Sources */, D0F3A8A01E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */, @@ -1917,6 +1960,7 @@ D050F2611E4A5AE700988324 /* PrivacySettings.swift in Sources */, D0B8440F1DAB91CD005F29E1 /* Either.swift in Sources */, D0DC35511DE36908000195EB /* RequestChatContextResults.swift in Sources */, + D08CAA8D1ED81EDF0000FDA8 /* Localizations.swift in Sources */, D0F7B1EC1E045C87007EB8A5 /* SearchPeers.swift in Sources */, D001F3EF1E128A1C007A8C60 /* AccountIntermediateState.swift in Sources */, D0223A991EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */, @@ -1987,6 +2031,7 @@ C2366C871E4F403C0097CCFF /* AddressNames.swift in Sources */, D02ABC7F1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift in Sources */, D0528E611E65B94E00E2FEF5 /* SingleMessageView.swift in Sources */, + D08CAA851ED8164B0000FDA8 /* Localization.swift in Sources */, D0528E5B1E658B3600E2FEF5 /* ManagedLocalInputActivities.swift in Sources */, D0FA8BA51E1FA341001E855B /* SecretChatKeychain.swift in Sources */, D0F7B1E71E045C87007EB8A5 /* JoinChannel.swift in Sources */, @@ -2002,6 +2047,7 @@ D0E305A81E5B5CBE00D7A3A2 /* PeerAdmins.swift in Sources */, D073CE6F1DCBCF17007511FD /* OutgoingMessageInfoAttribute.swift in Sources */, D0B844431DAB91FD005F29E1 /* Account.swift in Sources */, + D08CAA7E1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */, D0448CA01E27F5EB005A61A7 /* Random.swift in Sources */, C251D7441E65E50500283EDE /* StickerSetInstallation.swift in Sources */, ); diff --git a/TelegramCore/Account.swift b/TelegramCore/Account.swift index 862b6f3f28..03f125c33c 100644 --- a/TelegramCore/Account.swift +++ b/TelegramCore/Account.swift @@ -33,10 +33,10 @@ public class AuthorizedAccountState: AccountState { } public init(decoder: Decoder) { - self.pts = decoder.decodeInt32ForKey("pts") - self.qts = decoder.decodeInt32ForKey("qts") - self.date = decoder.decodeInt32ForKey("date") - self.seq = decoder.decodeInt32ForKey("seq") + self.pts = decoder.decodeInt32ForKey("pts", orElse: 0) + self.qts = decoder.decodeInt32ForKey("qts", orElse: 0) + self.date = decoder.decodeInt32ForKey("date", orElse: 0) + self.seq = decoder.decodeInt32ForKey("seq", orElse: 0) } public func encode(_ encoder: Encoder) { @@ -57,8 +57,8 @@ public class AuthorizedAccountState: AccountState { let state: State? public required init(decoder: Decoder) { - self.masterDatacenterId = decoder.decodeInt32ForKey("masterDatacenterId") - self.peerId = PeerId(decoder.decodeInt64ForKey("peerId")) + self.masterDatacenterId = decoder.decodeInt32ForKey("masterDatacenterId", orElse: 0) + self.peerId = PeerId(decoder.decodeInt64ForKey("peerId", orElse: 0)) self.state = decoder.decodeObjectForKey("state", decoder: { return State(decoder: $0) }) as? State } @@ -145,12 +145,16 @@ public class UnauthorizedAccount { postbox.removeKeychainEntryForKey(key) }) - return initializedNetwork(apiId: self.apiId, supplementary: false, datacenterId: Int(masterDatacenterId), keychain: keychain, basePath: self.basePath, testingEnvironment: self.testingEnvironment) + return self.postbox.modify { modifier -> LocalizationSettings? in + return modifier.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings + } |> mapToSignal { settings -> Signal in + return initializedNetwork(apiId: self.apiId, supplementary: false, datacenterId: Int(masterDatacenterId), keychain: keychain, basePath: self.basePath, testingEnvironment: self.testingEnvironment, languageCode: settings?.languageCode) |> map { network in let updated = UnauthorizedAccount(apiId: self.apiId, id: self.id, appGroupPath: self.appGroupPath, basePath: self.basePath, testingEnvironment: self.testingEnvironment, postbox: self.postbox, network: network) updated.shouldBeServiceTaskMaster.set(self.shouldBeServiceTaskMaster.get()) return updated } + } } } } @@ -220,6 +224,8 @@ private var declaredEncodables: Void = { declareEncodable(SynchronizeChatInputStateOperation.self, f: { SynchronizeChatInputStateOperation(decoder: $0) }) declareEncodable(SynchronizeSavedGifsOperation.self, f: { SynchronizeSavedGifsOperation(decoder: $0) }) declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) }) + declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) }) + declareEncodable(SuggestedLocalizationEntry.self, f: { SuggestedLocalizationEntry(decoder: $0) }) return }() @@ -248,7 +254,7 @@ public func accountWithId(apiId: Int32, id: AccountRecordId, supplementary: Bool initializeMessageNamespacesWithHoles.append((peerNamespace, Namespaces.Message.Cloud)) } - let seedConfiguration = SeedConfiguration(initializeChatListWithHoles: [ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 1), timestamp: 1))], initializeMessageNamespacesWithHoles: initializeMessageNamespacesWithHoles, existingMessageTags: allMessageTags) + let seedConfiguration = SeedConfiguration(initializeChatListWithHoles: [ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 1), timestamp: 1))], initializeMessageNamespacesWithHoles: initializeMessageNamespacesWithHoles, existingMessageTags: MessageTags.all, existingGlobalMessageTags: GlobalMessageTags.all) let postbox = openPostbox(basePath: path + "/postbox", globalMessageIdsNamespace: Namespaces.Message.Cloud, seedConfiguration: seedConfiguration) @@ -260,36 +266,40 @@ public func accountWithId(apiId: Int32, id: AccountRecordId, supplementary: Bool return postbox.stateView() |> take(1) |> mapToSignal { view -> Signal in - let accountState = view.state - - let keychain = Keychain(get: { key in - return postbox.keychainEntryForKey(key) - }, set: { (key, data) in - postbox.setKeychainEntryForKey(key, value: data) - }, remove: { key in - postbox.removeKeychainEntryForKey(key) - }) - - if let accountState = accountState { - switch accountState { - case let unauthorizedState as UnauthorizedAccountState: - return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: Int(unauthorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: testingEnvironment) - |> map { network -> AccountResult in - return .unauthorized(UnauthorizedAccount(apiId: apiId, id: id, appGroupPath: appGroupPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) + return postbox.modify { modifier -> LocalizationSettings? in + return modifier.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings + } |> mapToSignal { settings -> Signal in + let accountState = view.state + + let keychain = Keychain(get: { key in + return postbox.keychainEntryForKey(key) + }, set: { (key, data) in + postbox.setKeychainEntryForKey(key, value: data) + }, remove: { key in + postbox.removeKeychainEntryForKey(key) + }) + + if let accountState = accountState { + switch accountState { + case let unauthorizedState as UnauthorizedAccountState: + return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: Int(unauthorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: testingEnvironment, languageCode: settings?.languageCode) + |> map { network -> AccountResult in + return .unauthorized(UnauthorizedAccount(apiId: apiId, id: id, appGroupPath: appGroupPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) + } + case let authorizedState as AuthorizedAccountState: + return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: Int(authorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: testingEnvironment, languageCode: settings?.languageCode) + |> map { network -> AccountResult in + return .authorized(Account(id: id, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, peerId: authorizedState.peerId, auxiliaryMethods: auxiliaryMethods)) } - case let authorizedState as AuthorizedAccountState: - return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: Int(authorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: testingEnvironment) - |> map { network -> AccountResult in - return .authorized(Account(id: id, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, peerId: authorizedState.peerId, auxiliaryMethods: auxiliaryMethods)) - } - case _: - assertionFailure("Unexpected accountState \(accountState)") + case _: + assertionFailure("Unexpected accountState \(accountState)") + } + } + + return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: 2, keychain: keychain, basePath: path, testingEnvironment: testingEnvironment, languageCode: settings?.languageCode) + |> map { network -> AccountResult in + return .unauthorized(UnauthorizedAccount(apiId: apiId, id: id, appGroupPath: appGroupPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) } - } - - return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: 2, keychain: keychain, basePath: path, testingEnvironment: testingEnvironment) - |> map { network -> AccountResult in - return .unauthorized(UnauthorizedAccount(apiId: apiId, id: id, appGroupPath: appGroupPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) } } } diff --git a/TelegramCore/AccountState.swift b/TelegramCore/AccountState.swift index 047742e12d..25d06d1edd 100644 --- a/TelegramCore/AccountState.swift +++ b/TelegramCore/AccountState.swift @@ -20,15 +20,15 @@ public enum SentAuthorizationCodeType: Coding, Equatable { case flashCall(pattern: String) public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("v") as Int32 { + switch decoder.decodeInt32ForKey("v", orElse: 0) { case SentAuthorizationCodeTypeValue.otherSession.rawValue: - self = .otherSession(length: decoder.decodeInt32ForKey("l")) + self = .otherSession(length: decoder.decodeInt32ForKey("l", orElse: 0)) case SentAuthorizationCodeTypeValue.sms.rawValue: - self = .sms(length: decoder.decodeInt32ForKey("l")) + self = .sms(length: decoder.decodeInt32ForKey("l", orElse: 0)) case SentAuthorizationCodeTypeValue.call.rawValue: - self = .call(length: decoder.decodeInt32ForKey("l")) + self = .call(length: decoder.decodeInt32ForKey("l", orElse: 0)) case SentAuthorizationCodeTypeValue.flashCall.rawValue: - self = .flashCall(pattern: decoder.decodeStringForKey("p")) + self = .flashCall(pattern: decoder.decodeStringForKey("p", orElse: "")) default: preconditionFailure() } @@ -99,25 +99,25 @@ public enum UnauthorizedAccountStateContents: Coding, Equatable { case empty case phoneEntry(countryCode: Int32, number: String) case confirmationCodeEntry(number: String, type: SentAuthorizationCodeType, hash: String, timeout: Int32?, nextType: AuthorizationCodeNextType?) - case passwordEntry(hint: String, number:String?, code:String?) + case passwordEntry(hint: String, number: String?, code: String?) case signUp(number: String, codeHash: String, code: String, firstName: String, lastName: String) public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("v") as Int32 { + switch decoder.decodeInt32ForKey("v", orElse: 0) { case UnauthorizedAccountStateContentsValue.empty.rawValue: self = .empty case UnauthorizedAccountStateContentsValue.phoneEntry.rawValue: - self = .phoneEntry(countryCode: decoder.decodeInt32ForKey("cc"), number: decoder.decodeStringForKey("n")) + self = .phoneEntry(countryCode: decoder.decodeInt32ForKey("cc", orElse: 1), number: decoder.decodeStringForKey("n", orElse: "")) case UnauthorizedAccountStateContentsValue.confirmationCodeEntry.rawValue: var nextType: AuthorizationCodeNextType? - if let value = decoder.decodeInt32ForKey("nt") as Int32? { + if let value = decoder.decodeOptionalInt32ForKey("nt") { nextType = AuthorizationCodeNextType(rawValue: value) } - self = .confirmationCodeEntry(number: decoder.decodeStringForKey("num"), type: decoder.decodeObjectForKey("t", decoder: { SentAuthorizationCodeType(decoder: $0) }) as! SentAuthorizationCodeType, hash: decoder.decodeStringForKey("h"), timeout: decoder.decodeInt32ForKey("tm"), nextType: nextType) + self = .confirmationCodeEntry(number: decoder.decodeStringForKey("num", orElse: ""), type: decoder.decodeObjectForKey("t", decoder: { SentAuthorizationCodeType(decoder: $0) }) as! SentAuthorizationCodeType, hash: decoder.decodeStringForKey("h", orElse: ""), timeout: decoder.decodeOptionalInt32ForKey("tm"), nextType: nextType) case UnauthorizedAccountStateContentsValue.passwordEntry.rawValue: - self = .passwordEntry(hint: decoder.decodeStringForKey("h"), number: decoder.decodeStringForKey("n"), code: decoder.decodeStringForKey("c")) + self = .passwordEntry(hint: decoder.decodeStringForKey("h", orElse: ""), number: decoder.decodeOptionalStringForKey("n"), code: decoder.decodeOptionalStringForKey("c")) case UnauthorizedAccountStateContentsValue.signUp.rawValue: - self = .signUp(number: decoder.decodeStringForKey("n"), codeHash: decoder.decodeStringForKey("h"), code: decoder.decodeStringForKey("c"), firstName: decoder.decodeStringForKey("f"), lastName: decoder.decodeStringForKey("l")) + self = .signUp(number: decoder.decodeStringForKey("n", orElse: ""), codeHash: decoder.decodeStringForKey("h", orElse: ""), code: decoder.decodeStringForKey("c", orElse: ""), firstName: decoder.decodeStringForKey("f", orElse: ""), lastName: decoder.decodeStringForKey("l", orElse: "")) default: assertionFailure() self = .empty @@ -231,7 +231,7 @@ public final class UnauthorizedAccountState: AccountState { } public init(decoder: Decoder) { - self.masterDatacenterId = decoder.decodeInt32ForKey("dc") + self.masterDatacenterId = decoder.decodeInt32ForKey("dc", orElse: 0) self.contents = decoder.decodeObjectForKey("c", decoder: { UnauthorizedAccountStateContents(decoder: $0) }) as! UnauthorizedAccountStateContents } diff --git a/TelegramCore/AccountViewTracker.swift b/TelegramCore/AccountViewTracker.swift index db7119a230..9f67b8ac5d 100644 --- a/TelegramCore/AccountViewTracker.swift +++ b/TelegramCore/AccountViewTracker.swift @@ -9,6 +9,28 @@ import Foundation import MtProtoKitDynamic #endif +public enum CallListViewType { + case all + case missed +} + +public enum CallListViewEntry { + case message(Message, [Message]) + case hole(MessageIndex) +} + +public final class CallListView { + public let entries: [CallListViewEntry] + public let earlier: MessageIndex? + public let later: MessageIndex? + + init(entries: [CallListViewEntry], earlier: MessageIndex?, later: MessageIndex?) { + self.entries = entries + self.earlier = earlier + self.later = later + } +} + private func pendingWebpages(entries: [MessageHistoryEntry]) -> Set { var messageIds = Set() for case let .MessageEntry(message, _, _, _) in entries { @@ -160,6 +182,10 @@ public final class AccountViewTracker { private var pendingWebpageMessageIds: [MessageId: Int] = [:] private var webpageDisposables: [MessageId: Disposable] = [:] + private var viewVisibleCallListHoleIds: [Int32: Set] = [:] + private var visibleCallListHoleIds: [MessageIndex: Int] = [:] + private var visibleCallListHoleDisposables: [MessageIndex: Disposable] = [:] + private var updatedViewCountMessageIdsAndTimestamps: [MessageId: Int32] = [:] private var nextUpdatedViewCountDisposableId: Int32 = 0 private var updatedViewCountDisposables = DisposableDict() @@ -238,6 +264,66 @@ public final class AccountViewTracker { } } + private func updateVisibleCallListHoles(viewId: Int32, holeIds: Set) { + self.queue.async { + var addedHoleIds: [MessageIndex] = [] + var removedHoleIds: [MessageIndex] = [] + + let viewHoleIds: Set = self.viewVisibleCallListHoleIds[viewId] ?? Set() + + let viewAddedHoleIds = holeIds.subtracting(viewHoleIds) + let viewRemovedHoleIds = viewHoleIds.subtracting(holeIds) + for holeId in viewAddedHoleIds { + if let count = self.visibleCallListHoleIds[holeId] { + self.visibleCallListHoleIds[holeId] = count + 1 + } else { + self.visibleCallListHoleIds[holeId] = 1 + addedHoleIds.append(holeId) + } + } + for holeId in viewRemovedHoleIds { + if let count = self.visibleCallListHoleIds[holeId] { + if count == 1 { + self.visibleCallListHoleIds.removeValue(forKey: holeId) + removedHoleIds.append(holeId) + } else { + self.visibleCallListHoleIds[holeId] = count - 1 + } + } else { + assertionFailure() + } + } + + if holeIds.isEmpty { + self.viewVisibleCallListHoleIds.removeValue(forKey: viewId) + } else { + self.viewVisibleCallListHoleIds[viewId] = holeIds + } + + for holeId in removedHoleIds { + if let disposable = self.visibleCallListHoleDisposables.removeValue(forKey: holeId) { + disposable.dispose() + } + } + + if let account = self.account { + for holeId in addedHoleIds { + if self.visibleCallListHoleDisposables[holeId] == nil { + self.visibleCallListHoleDisposables[holeId] = fetchCallListHole(network: account.network, postbox: account.postbox, holeIndex: holeId).start(completed: { [weak self] in + if let strongSelf = self { + strongSelf.queue.async { + strongSelf.visibleCallListHoleDisposables.removeValue(forKey: holeId) + } + } + }) + } else { + assertionFailure() + } + } + } + } + } + public func updateViewCountForMessageIds(messageIds: Set) { self.queue.async { var addedMessageIds: [MessageId] = [] @@ -568,4 +654,123 @@ public final class AccountViewTracker { } } } + + public func callListView(type: CallListViewType, index: MessageIndex, count: Int) -> Signal { + if let account = self.account { + let granularity: Int32 = 60 * 60 * 24 + let timezoneOffset: Int32 = { + let nowTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + var now: time_t = time_t(nowTimestamp) + var timeinfoNow: tm = tm() + localtime_r(&now, &timeinfoNow) + return Int32(timeinfoNow.tm_gmtoff) + }() + + let groupingPredicate: (Message, Message) -> Bool = { lhs, rhs in + if lhs.id.peerId != rhs.id.peerId { + return false + } + let lhsTimestamp = ((lhs.timestamp + timezoneOffset) / (granularity)) * (granularity) + let rhsTimestamp = ((rhs.timestamp + timezoneOffset) / (granularity)) * (granularity) + if lhsTimestamp != rhsTimestamp { + return false + } + var lhsMissed = false + var lhsOther = false + inner: for media in lhs.media { + if let action = media as? TelegramMediaAction { + if case let .phoneCall(_, discardReason, _) = action.action { + if lhs.flags.contains(.Incoming), let discardReason = discardReason, case .missed = discardReason { + lhsMissed = true + } else { + lhsOther = true + } + break inner + } + } + } + var rhsMissed = false + var rhsOther = false + inner: for media in rhs.media { + if let action = media as? TelegramMediaAction { + if case let .phoneCall(_, discardReason, _) = action.action { + if rhs.flags.contains(.Incoming), let discardReason = discardReason, case .missed = discardReason { + rhsMissed = true + } else { + rhsOther = true + } + break inner + } + } + } + if lhsMissed != rhsMissed || lhsOther != rhsOther { + return false + } + return true + } + + let key = PostboxViewKey.globalMessageTags(globalTag: type == .all ? GlobalMessageTags.Calls : GlobalMessageTags.MissedCalls, position: index, count: 200, groupingPredicate: groupingPredicate) + let signal = account.postbox.combinedView(keys: [key]) |> map { view -> GlobalMessageTagsView in + let messageView = view.views[key] as! GlobalMessageTagsView + return messageView + } + + let managed = withState(signal, { [weak self] () -> Int32 in + if let strongSelf = self { + return OSAtomicIncrement32(&strongSelf.nextViewId) + } else { + return -1 + } + }, next: { [weak self] next, viewId in + if let strongSelf = self { + var holes = Set() + for entry in next.entries { + if case let .hole(index) = entry { + holes.insert(index) + } + } + strongSelf.updateVisibleCallListHoles(viewId: viewId, holeIds: holes) + } + }, disposed: { [weak self] viewId in + if let strongSelf = self { + strongSelf.updateVisibleCallListHoles(viewId: viewId, holeIds: Set()) + } + }) + + return managed + |> map { view -> CallListView in + var entries: [CallListViewEntry] = [] + if !view.entries.isEmpty { + var currentMessages: [Message] = [] + for entry in view.entries { + switch entry { + case let .hole(index): + if !currentMessages.isEmpty { + entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) + currentMessages.removeAll() + } + //entries.append(.hole(index)) + case let .message(message): + if currentMessages.isEmpty || groupingPredicate(message, currentMessages[currentMessages.count - 1]) { + currentMessages.append(message) + } else { + if !currentMessages.isEmpty { + entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) + currentMessages.removeAll() + } + currentMessages.append(message) + } + } + } + if !currentMessages.isEmpty { + entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) + currentMessages.removeAll() + } + } + return CallListView(entries: entries, earlier: view.earlier, later: view.later) + } + } else { + return .never() + } + } } diff --git a/TelegramCore/Api.swift b/TelegramCore/Api.swift index 8426ac9fd5..fd61750ed4 100644 --- a/TelegramCore/Api.swift +++ b/TelegramCore/Api.swift @@ -82,8 +82,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1343524562] = { return Api.InputChannel.parse_inputChannel($0) } dict[98092748] = { return Api.DcOption.parse_dcOption($0) } dict[-1212732749] = { return Api.account.PasswordSettings.parse_passwordSettings($0) } + dict[292985073] = { return Api.LangPackLanguage.parse_langPackLanguage($0) } dict[-1987579119] = { return Api.help.AppUpdate.parse_appUpdate($0) } dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) } + dict[-209337866] = { return Api.LangPackDifference.parse_langPackDifference($0) } dict[-791039645] = { return Api.channels.ChannelParticipant.parse_channelParticipant($0) } dict[-1299865402] = { return Api.ChannelParticipantRole.parse_channelRoleEmpty($0) } dict[-1776756363] = { return Api.ChannelParticipantRole.parse_channelRoleModerator($0) } @@ -196,6 +198,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-523384512] = { return Api.Update.parse_updateBotShippingQuery($0) } dict[1563376297] = { return Api.Update.parse_updateBotPrecheckoutQuery($0) } dict[-1425052898] = { return Api.Update.parse_updatePhoneCall($0) } + dict[281165899] = { return Api.Update.parse_updateLangPackTooLong($0) } + dict[1442983757] = { return Api.Update.parse_updateLangPack($0) } dict[367766557] = { return Api.ChannelParticipant.parse_channelParticipant($0) } dict[-1557620115] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) } dict[-1861910545] = { return Api.ChannelParticipant.parse_channelParticipantModerator($0) } @@ -340,7 +344,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[182649427] = { return Api.MessageRange.parse_messageRange($0) } dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) } dict[904138920] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultArchive($0) } - dict[-882895228] = { return Api.Config.parse_config($0) } + dict[-163699244] = { return Api.Config.parse_config($0) } dict[-75283823] = { return Api.TopPeerCategoryPeers.parse_topPeerCategoryPeers($0) } dict[-1107729093] = { return Api.Game.parse_game($0) } dict[-1032140601] = { return Api.BotCommand.parse_botCommand($0) } @@ -442,6 +446,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-326966976] = { return Api.phone.PhoneCall.parse_phoneCall($0) } dict[-1132882121] = { return Api.Bool.parse_boolFalse($0) } dict[-1720552011] = { return Api.Bool.parse_boolTrue($0) } + dict[-892239370] = { return Api.LangPackString.parse_langPackString($0) } + dict[1816636575] = { return Api.LangPackString.parse_langPackStringPluralized($0) } dict[-1036396922] = { return Api.InputWebFileLocation.parse_inputWebFileLocation($0) } dict[-947462709] = { return Api.MessageFwdHeader.parse_messageFwdHeader($0) } dict[398898678] = { return Api.help.Support.parse_support($0) } @@ -654,8 +660,12 @@ public struct Api { return _1.serialize(buffer, boxed) case let _1 as Api.account.PasswordSettings: return _1.serialize(buffer, boxed) + case let _1 as Api.LangPackLanguage: + return _1.serialize(buffer, boxed) case let _1 as Api.help.AppUpdate: return _1.serialize(buffer, boxed) + case let _1 as Api.LangPackDifference: + return _1.serialize(buffer, boxed) case let _1 as Api.channels.ChannelParticipant: return _1.serialize(buffer, boxed) case let _1 as Api.ChannelParticipantRole: @@ -914,6 +924,8 @@ public struct Api { return _1.serialize(buffer, boxed) case let _1 as Api.Bool: return _1.serialize(buffer, boxed) + case let _1 as Api.LangPackString: + return _1.serialize(buffer, boxed) case let _1 as Api.InputWebFileLocation: return _1.serialize(buffer, boxed) case let _1 as Api.MessageFwdHeader: @@ -4296,6 +4308,106 @@ public struct Api { } } + public enum LangPackLanguage: CustomStringConvertible { + case langPackLanguage(name: String, nativeName: String, langCode: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) -> Swift.Bool { + switch self { + case .langPackLanguage(let name, let nativeName, let langCode): + if boxed { + buffer.appendInt32(292985073) + } + serializeString(name, buffer: buffer, boxed: false) + serializeString(nativeName, buffer: buffer, boxed: false) + serializeString(langCode, buffer: buffer, boxed: false) + break + } + return true + } + + fileprivate static func parse_langPackLanguage(_ reader: BufferReader) -> LangPackLanguage? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.LangPackLanguage.langPackLanguage(name: _1!, nativeName: _2!, langCode: _3!) + } + else { + return nil + } + } + + public var description: String { + get { + switch self { + case .langPackLanguage(let name, let nativeName, let langCode): + return "(langPackLanguage name: \(name), nativeName: \(nativeName), langCode: \(langCode))" + } + } + } + } + + public enum LangPackDifference: CustomStringConvertible { + case langPackDifference(langCode: String, fromVersion: Int32, version: Int32, strings: [Api.LangPackString]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) -> Swift.Bool { + switch self { + case .langPackDifference(let langCode, let fromVersion, let version, let strings): + if boxed { + buffer.appendInt32(-209337866) + } + serializeString(langCode, buffer: buffer, boxed: false) + serializeInt32(fromVersion, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(strings.count)) + for item in strings { + item.serialize(buffer, true) + } + break + } + return true + } + + fileprivate static func parse_langPackDifference(_ reader: BufferReader) -> LangPackDifference? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: [Api.LangPackString]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.LangPackString.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.LangPackDifference.langPackDifference(langCode: _1!, fromVersion: _2!, version: _3!, strings: _4!) + } + else { + return nil + } + } + + public var description: String { + get { + switch self { + case .langPackDifference(let langCode, let fromVersion, let version, let strings): + return "(langPackDifference langCode: \(langCode), fromVersion: \(fromVersion), version: \(version), strings: \(strings))" + } + } + } + } + public enum ChannelParticipantRole: CustomStringConvertible { case channelRoleEmpty case channelRoleModerator @@ -5207,6 +5319,8 @@ public struct Api { case updateBotShippingQuery(queryId: Int64, userId: Int32, payload: Buffer, shippingAddress: Api.PostAddress) case updateBotPrecheckoutQuery(flags: Int32, queryId: Int64, userId: Int32, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, currency: String, totalAmount: Int64) case updatePhoneCall(phoneCall: Api.PhoneCall) + case updateLangPackTooLong + case updateLangPack(difference: Api.LangPackDifference) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) -> Swift.Bool { switch self { @@ -5712,6 +5826,18 @@ public struct Api { } phoneCall.serialize(buffer, true) break + case .updateLangPackTooLong: + if boxed { + buffer.appendInt32(281165899) + } + + break + case .updateLangPack(let difference): + if boxed { + buffer.appendInt32(1442983757) + } + difference.serialize(buffer, true) + break } return true } @@ -6752,6 +6878,22 @@ public struct Api { return nil } } + fileprivate static func parse_updateLangPackTooLong(_ reader: BufferReader) -> Update? { + return Api.Update.updateLangPackTooLong + } + fileprivate static func parse_updateLangPack(_ reader: BufferReader) -> Update? { + var _1: Api.LangPackDifference? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.LangPackDifference + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateLangPack(difference: _1!) + } + else { + return nil + } + } public var description: String { get { @@ -6876,6 +7018,10 @@ public struct Api { return "(updateBotPrecheckoutQuery flags: \(flags), queryId: \(queryId), userId: \(userId), payload: \(payload), info: \(info), shippingOptionId: \(shippingOptionId), currency: \(currency), totalAmount: \(totalAmount))" case .updatePhoneCall(let phoneCall): return "(updatePhoneCall phoneCall: \(phoneCall))" + case .updateLangPackTooLong: + return "(updateLangPackTooLong)" + case .updateLangPack(let difference): + return "(updateLangPack difference: \(difference))" } } } @@ -10326,13 +10472,13 @@ public struct Api { } public enum Config: CustomStringConvertible { - case config(flags: Int32, date: Int32, expires: Int32, testMode: Api.Bool, thisDc: Int32, dcOptions: [Api.DcOption], chatSizeMax: Int32, megagroupSizeMax: Int32, forwardedCountMax: Int32, onlineUpdatePeriodMs: Int32, offlineBlurTimeoutMs: Int32, offlineIdleTimeoutMs: Int32, onlineCloudTimeoutMs: Int32, notifyCloudDelayMs: Int32, notifyDefaultDelayMs: Int32, chatBigSize: Int32, pushChatPeriodMs: Int32, pushChatLimit: Int32, savedGifsLimit: Int32, editTimeLimit: Int32, ratingEDecay: Int32, stickersRecentLimit: Int32, tmpSessions: Int32?, pinnedDialogsCountMax: Int32, callReceiveTimeoutMs: Int32, callRingTimeoutMs: Int32, callConnectTimeoutMs: Int32, callPacketTimeoutMs: Int32, meUrlPrefix: String, disabledFeatures: [Api.DisabledFeature]) + case config(flags: Int32, date: Int32, expires: Int32, testMode: Api.Bool, thisDc: Int32, dcOptions: [Api.DcOption], chatSizeMax: Int32, megagroupSizeMax: Int32, forwardedCountMax: Int32, onlineUpdatePeriodMs: Int32, offlineBlurTimeoutMs: Int32, offlineIdleTimeoutMs: Int32, onlineCloudTimeoutMs: Int32, notifyCloudDelayMs: Int32, notifyDefaultDelayMs: Int32, chatBigSize: Int32, pushChatPeriodMs: Int32, pushChatLimit: Int32, savedGifsLimit: Int32, editTimeLimit: Int32, ratingEDecay: Int32, stickersRecentLimit: Int32, tmpSessions: Int32?, pinnedDialogsCountMax: Int32, callReceiveTimeoutMs: Int32, callRingTimeoutMs: Int32, callConnectTimeoutMs: Int32, callPacketTimeoutMs: Int32, meUrlPrefix: String, suggestedLangCode: String?, disabledFeatures: [Api.DisabledFeature]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) -> Swift.Bool { switch self { - case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let chatBigSize, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let ratingEDecay, let stickersRecentLimit, let tmpSessions, let pinnedDialogsCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let disabledFeatures): + case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let chatBigSize, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let ratingEDecay, let stickersRecentLimit, let tmpSessions, let pinnedDialogsCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let suggestedLangCode, let disabledFeatures): if boxed { - buffer.appendInt32(-882895228) + buffer.appendInt32(-163699244) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(date, buffer: buffer, boxed: false) @@ -10367,6 +10513,7 @@ public struct Api { serializeInt32(callConnectTimeoutMs, buffer: buffer, boxed: false) serializeInt32(callPacketTimeoutMs, buffer: buffer, boxed: false) serializeString(meUrlPrefix, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {serializeString(suggestedLangCode!, buffer: buffer, boxed: false)} buffer.appendInt32(481674261) buffer.appendInt32(Int32(disabledFeatures.count)) for item in disabledFeatures { @@ -10440,9 +10587,11 @@ public struct Api { _28 = reader.readInt32() var _29: String? _29 = parseString(reader) - var _30: [Api.DisabledFeature]? + var _30: String? + if Int(_1!) & Int(1 << 2) != 0 {_30 = parseString(reader) } + var _31: [Api.DisabledFeature]? if let _ = reader.readInt32() { - _30 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DisabledFeature.self) + _31 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DisabledFeature.self) } let _c1 = _1 != nil let _c2 = _2 != nil @@ -10473,9 +10622,10 @@ public struct Api { let _c27 = _27 != nil let _c28 = _28 != nil let _c29 = _29 != nil - let _c30 = _30 != 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 { - return Api.Config.config(flags: _1!, date: _2!, expires: _3!, testMode: _4!, thisDc: _5!, dcOptions: _6!, chatSizeMax: _7!, megagroupSizeMax: _8!, forwardedCountMax: _9!, onlineUpdatePeriodMs: _10!, offlineBlurTimeoutMs: _11!, offlineIdleTimeoutMs: _12!, onlineCloudTimeoutMs: _13!, notifyCloudDelayMs: _14!, notifyDefaultDelayMs: _15!, chatBigSize: _16!, pushChatPeriodMs: _17!, pushChatLimit: _18!, savedGifsLimit: _19!, editTimeLimit: _20!, ratingEDecay: _21!, stickersRecentLimit: _22!, tmpSessions: _23, pinnedDialogsCountMax: _24!, callReceiveTimeoutMs: _25!, callRingTimeoutMs: _26!, callConnectTimeoutMs: _27!, callPacketTimeoutMs: _28!, meUrlPrefix: _29!, disabledFeatures: _30!) + let _c30 = (Int(_1!) & Int(1 << 2) == 0) || _30 != nil + let _c31 = _31 != 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 { + return Api.Config.config(flags: _1!, date: _2!, expires: _3!, testMode: _4!, thisDc: _5!, dcOptions: _6!, chatSizeMax: _7!, megagroupSizeMax: _8!, forwardedCountMax: _9!, onlineUpdatePeriodMs: _10!, offlineBlurTimeoutMs: _11!, offlineIdleTimeoutMs: _12!, onlineCloudTimeoutMs: _13!, notifyCloudDelayMs: _14!, notifyDefaultDelayMs: _15!, chatBigSize: _16!, pushChatPeriodMs: _17!, pushChatLimit: _18!, savedGifsLimit: _19!, editTimeLimit: _20!, ratingEDecay: _21!, stickersRecentLimit: _22!, tmpSessions: _23, pinnedDialogsCountMax: _24!, callReceiveTimeoutMs: _25!, callRingTimeoutMs: _26!, callConnectTimeoutMs: _27!, callPacketTimeoutMs: _28!, meUrlPrefix: _29!, suggestedLangCode: _30, disabledFeatures: _31!) } else { return nil @@ -10485,8 +10635,8 @@ public struct Api { public var description: String { get { switch self { - case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let chatBigSize, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let ratingEDecay, let stickersRecentLimit, let tmpSessions, let pinnedDialogsCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let disabledFeatures): - return "(config flags: \(flags), date: \(date), expires: \(expires), testMode: \(testMode), thisDc: \(thisDc), dcOptions: \(dcOptions), chatSizeMax: \(chatSizeMax), megagroupSizeMax: \(megagroupSizeMax), forwardedCountMax: \(forwardedCountMax), onlineUpdatePeriodMs: \(onlineUpdatePeriodMs), offlineBlurTimeoutMs: \(offlineBlurTimeoutMs), offlineIdleTimeoutMs: \(offlineIdleTimeoutMs), onlineCloudTimeoutMs: \(onlineCloudTimeoutMs), notifyCloudDelayMs: \(notifyCloudDelayMs), notifyDefaultDelayMs: \(notifyDefaultDelayMs), chatBigSize: \(chatBigSize), pushChatPeriodMs: \(pushChatPeriodMs), pushChatLimit: \(pushChatLimit), savedGifsLimit: \(savedGifsLimit), editTimeLimit: \(editTimeLimit), ratingEDecay: \(ratingEDecay), stickersRecentLimit: \(stickersRecentLimit), tmpSessions: \(tmpSessions), pinnedDialogsCountMax: \(pinnedDialogsCountMax), callReceiveTimeoutMs: \(callReceiveTimeoutMs), callRingTimeoutMs: \(callRingTimeoutMs), callConnectTimeoutMs: \(callConnectTimeoutMs), callPacketTimeoutMs: \(callPacketTimeoutMs), meUrlPrefix: \(meUrlPrefix), disabledFeatures: \(disabledFeatures))" + case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let chatBigSize, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let ratingEDecay, let stickersRecentLimit, let tmpSessions, let pinnedDialogsCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let suggestedLangCode, let disabledFeatures): + return "(config flags: \(flags), date: \(date), expires: \(expires), testMode: \(testMode), thisDc: \(thisDc), dcOptions: \(dcOptions), chatSizeMax: \(chatSizeMax), megagroupSizeMax: \(megagroupSizeMax), forwardedCountMax: \(forwardedCountMax), onlineUpdatePeriodMs: \(onlineUpdatePeriodMs), offlineBlurTimeoutMs: \(offlineBlurTimeoutMs), offlineIdleTimeoutMs: \(offlineIdleTimeoutMs), onlineCloudTimeoutMs: \(onlineCloudTimeoutMs), notifyCloudDelayMs: \(notifyCloudDelayMs), notifyDefaultDelayMs: \(notifyDefaultDelayMs), chatBigSize: \(chatBigSize), pushChatPeriodMs: \(pushChatPeriodMs), pushChatLimit: \(pushChatLimit), savedGifsLimit: \(savedGifsLimit), editTimeLimit: \(editTimeLimit), ratingEDecay: \(ratingEDecay), stickersRecentLimit: \(stickersRecentLimit), tmpSessions: \(tmpSessions), pinnedDialogsCountMax: \(pinnedDialogsCountMax), callReceiveTimeoutMs: \(callReceiveTimeoutMs), callRingTimeoutMs: \(callRingTimeoutMs), callConnectTimeoutMs: \(callConnectTimeoutMs), callPacketTimeoutMs: \(callPacketTimeoutMs), meUrlPrefix: \(meUrlPrefix), suggestedLangCode: \(suggestedLangCode), disabledFeatures: \(disabledFeatures))" } } } @@ -13336,6 +13486,95 @@ public struct Api { } } + public enum LangPackString: CustomStringConvertible { + case langPackString(key: String, value: String) + case langPackStringPluralized(flags: Int32, key: String, zeroValue: String?, oneValue: String?, twoValue: String?, fewValue: String?, manyValue: String?, otherValue: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) -> Swift.Bool { + switch self { + case .langPackString(let key, let value): + if boxed { + buffer.appendInt32(-892239370) + } + serializeString(key, buffer: buffer, boxed: false) + serializeString(value, buffer: buffer, boxed: false) + break + case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue): + if boxed { + buffer.appendInt32(1816636575) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(key, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(zeroValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(oneValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(twoValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(fewValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeString(manyValue!, buffer: buffer, boxed: false)} + serializeString(otherValue, buffer: buffer, boxed: false) + break + } + return true + } + + fileprivate static func parse_langPackString(_ reader: BufferReader) -> LangPackString? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.LangPackString.langPackString(key: _1!, value: _2!) + } + else { + return nil + } + } + fileprivate static func parse_langPackStringPluralized(_ reader: BufferReader) -> LangPackString? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } + var _7: String? + if Int(_1!) & Int(1 << 4) != 0 {_7 = parseString(reader) } + var _8: String? + _8 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.LangPackString.langPackStringPluralized(flags: _1!, key: _2!, zeroValue: _3, oneValue: _4, twoValue: _5, fewValue: _6, manyValue: _7, otherValue: _8!) + } + else { + return nil + } + } + + public var description: String { + get { + switch self { + case .langPackString(let key, let value): + return "(langPackString key: \(key), value: \(value))" + case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue): + return "(langPackStringPluralized flags: \(flags), key: \(key), zeroValue: \(zeroValue), oneValue: \(oneValue), twoValue: \(twoValue), fewValue: \(fewValue), manyValue: \(manyValue), otherValue: \(otherValue))" + } + } + } + } + public enum InputWebFileLocation: CustomStringConvertible { case inputWebFileLocation(url: String, accessHash: Int64) @@ -22217,6 +22456,68 @@ public struct Api { }) } } + public struct langpack { + public static func getLangPack(langCode langCode: String) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.LangPackDifference?) { + let buffer = Buffer() + buffer.appendInt32(-1699363442) + serializeString(langCode, buffer: buffer, boxed: false) + return (FunctionDescription({return "(langpack.getLangPack langCode: \(langCode))"}), buffer, { (buffer: Buffer) -> Api.LangPackDifference? in + let reader = BufferReader(buffer) + var result: Api.LangPackDifference? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.LangPackDifference + } + return result + }) + } + + public static func getStrings(langCode langCode: String, keys: [String]) -> (CustomStringConvertible, Buffer, (Buffer) -> [Api.LangPackString]?) { + let buffer = Buffer() + buffer.appendInt32(773776152) + serializeString(langCode, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(keys.count)) + for item in keys { + serializeString(item, buffer: buffer, boxed: false) + } + return (FunctionDescription({return "(langpack.getStrings langCode: \(langCode), keys: \(keys))"}), buffer, { (buffer: Buffer) -> [Api.LangPackString]? in + let reader = BufferReader(buffer) + var result: [Api.LangPackString]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.LangPackString.self) + } + return result + }) + } + + public static func getDifference(fromVersion fromVersion: Int32) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.LangPackDifference?) { + let buffer = Buffer() + buffer.appendInt32(187583869) + serializeInt32(fromVersion, buffer: buffer, boxed: false) + return (FunctionDescription({return "(langpack.getDifference fromVersion: \(fromVersion))"}), buffer, { (buffer: Buffer) -> Api.LangPackDifference? in + let reader = BufferReader(buffer) + var result: Api.LangPackDifference? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.LangPackDifference + } + return result + }) + } + + public static func getLanguages() -> (CustomStringConvertible, Buffer, (Buffer) -> [Api.LangPackLanguage]?) { + let buffer = Buffer() + buffer.appendInt32(-2146445955) + + return (FunctionDescription({return "(langpack.getLanguages )"}), buffer, { (buffer: Buffer) -> [Api.LangPackLanguage]? in + let reader = BufferReader(buffer) + var result: [Api.LangPackLanguage]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.LangPackLanguage.self) + } + return result + }) + } + } public struct photos { public static func updateProfilePhoto(id id: Api.InputPhoto) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.UserProfilePhoto?) { let buffer = Buffer() diff --git a/TelegramCore/ApplyMaxReadIndexInteractively.swift b/TelegramCore/ApplyMaxReadIndexInteractively.swift index 5975f31646..d82f2aa07b 100644 --- a/TelegramCore/ApplyMaxReadIndexInteractively.swift +++ b/TelegramCore/ApplyMaxReadIndexInteractively.swift @@ -16,7 +16,7 @@ public func applyMaxReadIndexInteractively(postbox: Postbox, network: Network, i if let message = modifier.getMessage(id) { for attribute in message.attributes { if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { - if attribute.countdownBeginTime == nil && !message.containsSecretMedia { + if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && !message.containsSecretMedia { modifier.updateMessage(message.id, update: { currentMessage in var storeForwardInfo: StoreMessageForwardInfo? if let forwardInfo = currentMessage.forwardInfo { @@ -49,7 +49,7 @@ func applyOutgoingReadMaxIndex(modifier: Modifier, index: MessageIndex, beginAt if let message = modifier.getMessage(id), !message.flags.contains(.Incoming) { for attribute in message.attributes { if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { - if attribute.countdownBeginTime == nil && !message.containsSecretMedia { + if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && !message.containsSecretMedia { modifier.updateMessage(message.id, update: { currentMessage in var storeForwardInfo: StoreMessageForwardInfo? if let forwardInfo = currentMessage.forwardInfo { diff --git a/TelegramCore/ApplyUpdateMessage.swift b/TelegramCore/ApplyUpdateMessage.swift index 39c652c234..ee95b5f746 100644 --- a/TelegramCore/ApplyUpdateMessage.swift +++ b/TelegramCore/ApplyUpdateMessage.swift @@ -122,7 +122,9 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes } } - return .update(StoreMessage(id: updatedId, globallyUniqueId: nil, timestamp: updatedTimestamp ?? currentMessage.timestamp, flags: [], tags: tagsForStoreMessage(media: media, textEntities: entitiesAttribute?.entities), globalTags: globalTagsForStoreMessage(media: media), forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)) + let (tags, globalTags) = tagsForStoreMessage(incoming: currentMessage.flags.contains(.Incoming), media: media, textEntities: entitiesAttribute?.entities) + + return .update(StoreMessage(id: updatedId, globallyUniqueId: nil, timestamp: updatedTimestamp ?? currentMessage.timestamp, flags: [], tags: tags, globalTags: globalTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)) }) if let updatedTimestamp = updatedTimestamp { modifier.offsetPendingMessagesTimestamps(lowerBound: message.id, timestamp: updatedTimestamp) diff --git a/TelegramCore/ArchivedStickerPacksInfo.swift b/TelegramCore/ArchivedStickerPacksInfo.swift index 794916eb98..e8ca064897 100644 --- a/TelegramCore/ArchivedStickerPacksInfo.swift +++ b/TelegramCore/ArchivedStickerPacksInfo.swift @@ -33,7 +33,7 @@ public final class ArchivedStickerPacksInfo: OrderedItemListEntryContents { } public init(decoder: Decoder) { - self.count = (decoder.decodeInt32ForKey("c") as Int32) + self.count = decoder.decodeInt32ForKey("c", orElse: 0) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/AutoremoveTimeoutMessageAttribute.swift b/TelegramCore/AutoremoveTimeoutMessageAttribute.swift index fff20501f4..d6ee2c388a 100644 --- a/TelegramCore/AutoremoveTimeoutMessageAttribute.swift +++ b/TelegramCore/AutoremoveTimeoutMessageAttribute.swift @@ -21,8 +21,8 @@ public class AutoremoveTimeoutMessageAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.timeout = decoder.decodeInt32ForKey("t") - self.countdownBeginTime = decoder.decodeInt32ForKey("c") + self.timeout = decoder.decodeInt32ForKey("t", orElse: 0) + self.countdownBeginTime = decoder.decodeOptionalInt32ForKey("c") } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/BotInfo.swift b/TelegramCore/BotInfo.swift index 18d7465e33..e08b22046e 100644 --- a/TelegramCore/BotInfo.swift +++ b/TelegramCore/BotInfo.swift @@ -15,8 +15,8 @@ public struct BotCommand: Coding, Equatable { } public init(decoder: Decoder) { - self.text = decoder.decodeStringForKey("t") - self.description = decoder.decodeStringForKey("d") + self.text = decoder.decodeStringForKey("t", orElse: "") + self.description = decoder.decodeStringForKey("d", orElse: "") } public func encode(_ encoder: Encoder) { @@ -39,7 +39,7 @@ public final class BotInfo: Coding, Equatable { } public init(decoder: Decoder) { - self.description = decoder.decodeStringForKey("d") + self.description = decoder.decodeStringForKey("d", orElse: "") self.commands = decoder.decodeObjectArrayWithDecoderForKey("c") } diff --git a/TelegramCore/CacheStorageSettings.swift b/TelegramCore/CacheStorageSettings.swift index 4ebb824513..c50ed98cc2 100644 --- a/TelegramCore/CacheStorageSettings.swift +++ b/TelegramCore/CacheStorageSettings.swift @@ -19,7 +19,7 @@ public struct CacheStorageSettings: PreferencesEntry, Equatable { } public init(decoder: Decoder) { - self.defaultCacheStorageTimeout = decoder.decodeInt32ForKey("dt") as Int32 + self.defaultCacheStorageTimeout = decoder.decodeInt32ForKey("dt", orElse: 0) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/CachedChannelData.swift b/TelegramCore/CachedChannelData.swift index ba377d7bf4..57fef133fd 100644 --- a/TelegramCore/CachedChannelData.swift +++ b/TelegramCore/CachedChannelData.swift @@ -32,17 +32,17 @@ public struct CachedChannelParticipantsSummary: Coding, Equatable { } public init(decoder: Decoder) { - if let memberCount = decoder.decodeInt32ForKey("p.m") as Int32? { + if let memberCount = decoder.decodeOptionalInt32ForKey("p.m") { self.memberCount = memberCount } else { self.memberCount = 0 } - if let adminCount = decoder.decodeInt32ForKey("p.a") as Int32? { + if let adminCount = decoder.decodeOptionalInt32ForKey("p.a") { self.adminCount = adminCount } else { self.adminCount = 0 } - if let bannedCount = decoder.decodeInt32ForKey("p.b") as Int32? { + if let bannedCount = decoder.decodeOptionalInt32ForKey("p.b") { self.bannedCount = bannedCount } else { self.bannedCount = 0 @@ -163,15 +163,15 @@ public final class CachedChannelData: CachedPeerData { } public init(decoder: Decoder) { - self.flags = CachedChannelFlags(rawValue: decoder.decodeInt32ForKey("f")) - self.about = decoder.decodeStringForKey("a") + self.flags = CachedChannelFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.about = decoder.decodeOptionalStringForKey("a") self.participantsSummary = CachedChannelParticipantsSummary(decoder: decoder) self.exportedInvitation = decoder.decodeObjectForKey("i", decoder: { ExportedInvitation(decoder: $0) }) as? ExportedInvitation self.botInfos = decoder.decodeObjectArrayWithDecoderForKey("b") as [CachedPeerBotInfo] var peerIds = Set() self.topParticipants = decoder.decodeObjectForKey("p", decoder: { CachedChannelParticipants(decoder: $0) }) as? CachedChannelParticipants - self.reportStatus = PeerReportStatus(rawValue: decoder.decodeInt32ForKey("r"))! - if let pinnedMessagePeerId = (decoder.decodeInt64ForKey("pm.p") as Int64?), let pinnedMessageNamespace = (decoder.decodeInt32ForKey("pm.n") as Int32?), let pinnedMessageId = (decoder.decodeInt32ForKey("pm.i") as Int32?) { + self.reportStatus = PeerReportStatus(rawValue: decoder.decodeInt32ForKey("r", orElse: 0))! + if let pinnedMessagePeerId = decoder.decodeOptionalInt64ForKey("pm.p"), let pinnedMessageNamespace = decoder.decodeOptionalInt32ForKey("pm.n"), let pinnedMessageId = decoder.decodeOptionalInt32ForKey("pm.i") { self.pinnedMessageId = MessageId(peerId: PeerId(pinnedMessagePeerId), namespace: pinnedMessageNamespace, id: pinnedMessageId) } else { self.pinnedMessageId = nil diff --git a/TelegramCore/CachedChannelParticipants.swift b/TelegramCore/CachedChannelParticipants.swift index 5af71d9083..0aed2201ba 100644 --- a/TelegramCore/CachedChannelParticipants.swift +++ b/TelegramCore/CachedChannelParticipants.swift @@ -61,18 +61,18 @@ public enum ChannelParticipant: Coding, Equatable { } public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case ChannelParticipantValue.member.rawValue: - self = .member(id: PeerId(decoder.decodeInt64ForKey("i")), invitedAt: decoder.decodeInt32ForKey("t")) + self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) case ChannelParticipantValue.creator.rawValue: - self = .creator(id: PeerId(decoder.decodeInt64ForKey("i"))) + self = .creator(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0))) case ChannelParticipantValue.editor.rawValue: - self = .editor(id: PeerId(decoder.decodeInt64ForKey("i")), invitedBy: PeerId(decoder.decodeInt64ForKey("p")), invitedAt: decoder.decodeInt32ForKey("t")) + self = .editor(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) case ChannelParticipantValue.moderator.rawValue: - self = .moderator(id: PeerId(decoder.decodeInt64ForKey("i")), invitedBy: PeerId(decoder.decodeInt64ForKey("p")), invitedAt: decoder.decodeInt32ForKey("t")) + self = .moderator(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) default: assertionFailure() - self = .member(id: PeerId(decoder.decodeInt64ForKey("i")), invitedAt: decoder.decodeInt32ForKey("t")) + self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) } } diff --git a/TelegramCore/CachedGroupData.swift b/TelegramCore/CachedGroupData.swift index 50f06d805b..32046ac294 100644 --- a/TelegramCore/CachedGroupData.swift +++ b/TelegramCore/CachedGroupData.swift @@ -15,7 +15,7 @@ public final class CachedPeerBotInfo: Coding, Equatable { } public init(decoder: Decoder) { - self.peerId = PeerId(decoder.decodeInt64ForKey("p")) + self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) self.botInfo = decoder.decodeObjectForKey("i", decoder: { return BotInfo(decoder: $0) }) as! BotInfo } @@ -68,7 +68,7 @@ public final class CachedGroupData: CachedPeerData { self.participants = participants self.exportedInvitation = decoder.decodeObjectForKey("i", decoder: { ExportedInvitation(decoder: $0) }) as? ExportedInvitation self.botInfos = decoder.decodeObjectArrayWithDecoderForKey("b") as [CachedPeerBotInfo] - self.reportStatus = PeerReportStatus(rawValue: decoder.decodeInt32ForKey("r"))! + self.reportStatus = PeerReportStatus(rawValue: decoder.decodeInt32ForKey("r", orElse: 0))! var peerIds = Set() if let participants = participants { diff --git a/TelegramCore/CachedGroupParticipants.swift b/TelegramCore/CachedGroupParticipants.swift index ef04a59129..4938ce43b7 100644 --- a/TelegramCore/CachedGroupParticipants.swift +++ b/TelegramCore/CachedGroupParticipants.swift @@ -22,15 +22,15 @@ public enum GroupParticipant: Coding, Equatable { } public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("v") as Int32 { + switch decoder.decodeInt32ForKey("v", orElse: 0) { case 0: - self = .member(id: PeerId(decoder.decodeInt64ForKey("i")), invitedBy: PeerId(decoder.decodeInt64ForKey("b")), invitedAt: decoder.decodeInt32ForKey("t")) + self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) case 1: - self = .creator(id: PeerId(decoder.decodeInt64ForKey("i"))) + self = .creator(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0))) case 2: - self = .admin(id: PeerId(decoder.decodeInt64ForKey("i")), invitedBy: PeerId(decoder.decodeInt64ForKey("b")), invitedAt: decoder.decodeInt32ForKey("t")) + self = .admin(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) default: - self = .member(id: PeerId(decoder.decodeInt64ForKey("i")), invitedBy: PeerId(decoder.decodeInt64ForKey("b")), invitedAt: decoder.decodeInt32ForKey("t")) + self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) } } @@ -98,7 +98,7 @@ public final class CachedGroupParticipants: Coding, Equatable { public init(decoder: Decoder) { self.participants = decoder.decodeObjectArrayWithDecoderForKey("p") - self.version = decoder.decodeInt32ForKey("v") + self.version = decoder.decodeInt32ForKey("v", orElse: 0) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/CachedUserData.swift b/TelegramCore/CachedUserData.swift index f3b6fe2782..29e10041f2 100644 --- a/TelegramCore/CachedUserData.swift +++ b/TelegramCore/CachedUserData.swift @@ -31,11 +31,11 @@ public final class CachedUserData: CachedPeerData { } public init(decoder: Decoder) { - self.about = decoder.decodeStringForKey("a") + self.about = decoder.decodeOptionalStringForKey("a") self.botInfo = decoder.decodeObjectForKey("bi") as? BotInfo - self.reportStatus = PeerReportStatus(rawValue: decoder.decodeInt32ForKey("r"))! - self.isBlocked = decoder.decodeInt32ForKey("b") != 0 - self.commonGroupCount = decoder.decodeInt32ForKey("cg") + self.reportStatus = PeerReportStatus(rawValue: decoder.decodeInt32ForKey("r", orElse: 0))! + self.isBlocked = decoder.decodeInt32ForKey("b", orElse: 0) != 0 + self.commonGroupCount = decoder.decodeInt32ForKey("cg", orElse: 0) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/ChannelState.swift b/TelegramCore/ChannelState.swift index 6eca3fd09e..c7406080db 100644 --- a/TelegramCore/ChannelState.swift +++ b/TelegramCore/ChannelState.swift @@ -13,7 +13,7 @@ final class ChannelState: PeerChatState, Equatable, CustomStringConvertible { } init(decoder: Decoder) { - self.pts = decoder.decodeInt32ForKey("pts") + self.pts = decoder.decodeInt32ForKey("pts", orElse: 0) } func encode(_ encoder: Encoder) { diff --git a/TelegramCore/ChatContextResult.swift b/TelegramCore/ChatContextResult.swift index 47ceffbb86..9d099da185 100644 --- a/TelegramCore/ChatContextResult.swift +++ b/TelegramCore/ChatContextResult.swift @@ -16,11 +16,11 @@ public enum ChatContextResultMessage: Coding, Equatable { case contact(media: TelegramMediaContact, replyMarkup: ReplyMarkupMessageAttribute?) public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("_v") as Int32 { + switch decoder.decodeInt32ForKey("_v", orElse: 0) { case 0: - self = .auto(caption: decoder.decodeStringForKey("c"), replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) + self = .auto(caption: decoder.decodeStringForKey("c", orElse: ""), replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) case 1: - self = .text(text: decoder.decodeStringForKey("t"), entities: decoder.decodeObjectForKey("e") as? TextEntitiesMessageAttribute, disableUrlPreview: decoder.decodeInt32ForKey("du") != 0, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) + self = .text(text: decoder.decodeStringForKey("t", orElse: ""), entities: decoder.decodeObjectForKey("e") as? TextEntitiesMessageAttribute, disableUrlPreview: decoder.decodeInt32ForKey("du", orElse: 0) != 0, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) case 2: self = .mapLocation(media: decoder.decodeObjectForKey("l") as! TelegramMediaMap, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) case 3: diff --git a/TelegramCore/CloudChatRemoveMessagesOperation.swift b/TelegramCore/CloudChatRemoveMessagesOperation.swift index 0840b74ccd..bbc2a25b17 100644 --- a/TelegramCore/CloudChatRemoveMessagesOperation.swift +++ b/TelegramCore/CloudChatRemoveMessagesOperation.swift @@ -32,7 +32,7 @@ final class CloudChatRemoveMessagesOperation: Coding { init(decoder: Decoder) { self.messageIds = MessageId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("i")!) - self.type = CloudChatRemoveMessagesType(rawValue: decoder.decodeInt32ForKey("t"))! + self.type = CloudChatRemoveMessagesType(rawValue: decoder.decodeInt32ForKey("t", orElse: 0))! } func encode(_ encoder: Encoder) { @@ -55,9 +55,9 @@ final class CloudChatRemoveChatOperation: Coding { } init(decoder: Decoder) { - self.peerId = PeerId(decoder.decodeInt64ForKey("p")) - self.reportChatSpam = (decoder.decodeInt32ForKey("r") as Int32) != 0 - if let messageIdPeerId = (decoder.decodeInt64ForKey("m.p") as Int64?), let messageIdNamespace = (decoder.decodeInt32ForKey("m.n") as Int32?), let messageIdId = (decoder.decodeInt32ForKey("m.i") as Int32?) { + self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.reportChatSpam = decoder.decodeInt32ForKey("r", orElse: 0) != 0 + if let messageIdPeerId = decoder.decodeOptionalInt64ForKey("m.p"), let messageIdNamespace = decoder.decodeOptionalInt32ForKey("m.n"), let messageIdId = decoder.decodeOptionalInt32ForKey("m.i") { self.topMessageId = MessageId(peerId: PeerId(messageIdPeerId), namespace: messageIdNamespace, id: messageIdId) } else { self.topMessageId = nil @@ -89,8 +89,8 @@ final class CloudChatClearHistoryOperation: Coding { } init(decoder: Decoder) { - self.peerId = PeerId(decoder.decodeInt64ForKey("p")) - self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p")), namespace: decoder.decodeInt32ForKey("m.n"), id: decoder.decodeInt32ForKey("m.i")) + self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0)) } func encode(_ encoder: Encoder) { diff --git a/TelegramCore/CloudFileMediaResource.swift b/TelegramCore/CloudFileMediaResource.swift index 9cad717aa4..5b459e1ea8 100644 --- a/TelegramCore/CloudFileMediaResource.swift +++ b/TelegramCore/CloudFileMediaResource.swift @@ -64,11 +64,11 @@ public class CloudFileMediaResource: TelegramCloudMediaResource { } public required init(decoder: Decoder) { - self.datacenterId = Int(decoder.decodeInt32ForKey("d") as Int32) - self.volumeId = decoder.decodeInt64ForKey("v") - self.localId = decoder.decodeInt32ForKey("l") - self.secret = decoder.decodeInt64ForKey("s") - if let size = decoder.decodeInt32ForKey("n") as Int32? { + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0) + self.localId = decoder.decodeInt32ForKey("l", orElse: 0) + self.secret = decoder.decodeInt64ForKey("s", orElse: 0) + if let size = decoder.decodeOptionalInt32ForKey("n") { self.size = Int(size) } else { self.size = nil @@ -146,10 +146,10 @@ public class CloudDocumentMediaResource: TelegramCloudMediaResource { } public required init(decoder: Decoder) { - self.datacenterId = Int(decoder.decodeInt32ForKey("d") as Int32) - self.fileId = decoder.decodeInt64ForKey("f") - self.accessHash = decoder.decodeInt64ForKey("a") - if let size = (decoder.decodeInt32ForKey("n") as Int32?) { + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.fileId = decoder.decodeInt64ForKey("f", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) + if let size = decoder.decodeOptionalInt32ForKey("n") { self.size = Int(size) } else { self.size = nil @@ -204,7 +204,7 @@ public class LocalFileMediaResource: TelegramMediaResource { } public required init(decoder: Decoder) { - self.fileId = decoder.decodeInt64ForKey("f") + self.fileId = decoder.decodeInt64ForKey("f", orElse: 0) } public func encode(_ encoder: Encoder) { @@ -258,10 +258,10 @@ public class LocalFileReferenceMediaResource: TelegramMediaResource { } public required init(decoder: Decoder) { - self.localFilePath = decoder.decodeStringForKey("p") - self.randomId = decoder.decodeInt64ForKey("r") - self.isUniquelyReferencedTemporaryFile = (decoder.decodeInt32ForKey("t") as Int32) != 0 - self.size = decoder.decodeInt32ForKey("s") + self.localFilePath = decoder.decodeStringForKey("p", orElse: "") + self.randomId = decoder.decodeInt64ForKey("r", orElse: 0) + self.isUniquelyReferencedTemporaryFile = decoder.decodeInt32ForKey("t", orElse: 0) != 0 + self.size = decoder.decodeOptionalInt32ForKey("s") } public func encode(_ encoder: Encoder) { @@ -318,8 +318,8 @@ public final class HttpReferenceMediaResource: TelegramMediaResource { } public required init(decoder: Decoder) { - self.url = decoder.decodeStringForKey("u") - if let size = (decoder.decodeInt32ForKey("s") as Int32?) { + self.url = decoder.decodeStringForKey("u", orElse: "") + if let size = decoder.decodeOptionalInt32ForKey("s") { self.size = Int(size) } else { self.size = nil @@ -396,15 +396,15 @@ public struct SecretFileMediaResource: TelegramCloudMediaResource { } public init(decoder: Decoder) { - self.fileId = decoder.decodeInt64ForKey("i") - self.accessHash = decoder.decodeInt64ForKey("a") - if let size = decoder.decodeInt32ForKey("s") as Int32? { + self.fileId = decoder.decodeInt64ForKey("i", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) + if let size = decoder.decodeOptionalInt32ForKey("s") { self.size = Int(size) } else { self.size = nil } - self.decryptedSize = decoder.decodeInt32ForKey("ds") - self.datacenterId = Int(decoder.decodeInt32ForKey("d")) + self.decryptedSize = decoder.decodeInt32ForKey("ds", orElse: 0) + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) self.key = decoder.decodeObjectForKey("k", decoder: { SecretFileEncryptionKey(decoder: $0) }) as! SecretFileEncryptionKey } diff --git a/TelegramCore/ConsumableContentMessageAttribute.swift b/TelegramCore/ConsumableContentMessageAttribute.swift index 29e21c6dcd..02d7b13d9c 100644 --- a/TelegramCore/ConsumableContentMessageAttribute.swift +++ b/TelegramCore/ConsumableContentMessageAttribute.swift @@ -13,7 +13,7 @@ public class ConsumableContentMessageAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.consumed = (decoder.decodeInt32ForKey("c") as Int32) != 0 + self.consumed = decoder.decodeInt32ForKey("c", orElse: 0) != 0 } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/EditedMessageAttribute.swift b/TelegramCore/EditedMessageAttribute.swift index 5e3592b113..bcbc65e7c2 100644 --- a/TelegramCore/EditedMessageAttribute.swift +++ b/TelegramCore/EditedMessageAttribute.swift @@ -13,7 +13,7 @@ public class EditedMessageAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.date = decoder.decodeInt32ForKey("d") + self.date = decoder.decodeInt32ForKey("d", orElse: 0) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/EnqueueMessage.swift b/TelegramCore/EnqueueMessage.swift index 4be6f8ceb1..7fb6b595e6 100644 --- a/TelegramCore/EnqueueMessage.swift +++ b/TelegramCore/EnqueueMessage.swift @@ -211,7 +211,9 @@ func enqueueMessages(modifier: Modifier, account: Account, peerId: PeerId, messa authorId = account.peerId } - storeMessages.append(StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, timestamp: timestamp, flags: flags, tags: tagsForStoreMessage(media: mediaList, textEntities: entitiesAttribute?.entities), globalTags: globalTagsForStoreMessage(media: mediaList), forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: mediaList)) + let (tags, globalTags) = tagsForStoreMessage(incoming: false, media: mediaList, textEntities: entitiesAttribute?.entities) + + storeMessages.append(StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, timestamp: timestamp, flags: flags, tags: tags, globalTags: globalTags, forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: mediaList)) case let .forward(source): if let sourceMessage = modifier.getMessage(source), let author = sourceMessage.author ?? sourceMessage.peers[sourceMessage.id.peerId] { if let peer = peer as? TelegramSecretChat { @@ -255,7 +257,9 @@ func enqueueMessages(modifier: Modifier, account: Account, peerId: PeerId, messa } } - storeMessages.append(StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, timestamp: timestamp, flags: flags, tags: tagsForStoreMessage(media: sourceMessage.media, textEntities: entitiesAttribute?.entities), globalTags: globalTagsForStoreMessage(media: sourceMessage.media), forwardInfo: forwardInfo, authorId: account.peerId, text: sourceMessage.text, attributes: attributes, media: sourceMessage.media)) + let (tags, globalTags) = tagsForStoreMessage(incoming: false, media: sourceMessage.media, textEntities: entitiesAttribute?.entities) + + storeMessages.append(StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, timestamp: timestamp, flags: flags, tags: tags, globalTags: globalTags, forwardInfo: forwardInfo, authorId: account.peerId, text: sourceMessage.text, attributes: attributes, media: sourceMessage.media)) } } } diff --git a/TelegramCore/ExportedInvitation.swift b/TelegramCore/ExportedInvitation.swift index 5dc118542e..6234dff1d2 100644 --- a/TelegramCore/ExportedInvitation.swift +++ b/TelegramCore/ExportedInvitation.swift @@ -13,7 +13,7 @@ public struct ExportedInvitation: Coding, Equatable { } public init(decoder: Decoder) { - self.link = decoder.decodeStringForKey("l") + self.link = decoder.decodeStringForKey("l", orElse: "") } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/FeaturedStickerPack.swift b/TelegramCore/FeaturedStickerPack.swift index b06c5f23fd..77953cb167 100644 --- a/TelegramCore/FeaturedStickerPack.swift +++ b/TelegramCore/FeaturedStickerPack.swift @@ -39,7 +39,7 @@ public final class FeaturedStickerPackItem: OrderedItemListEntryContents { public init(decoder: Decoder) { self.info = decoder.decodeObjectForKey("i") as! StickerPackCollectionInfo self.topItems = decoder.decodeObjectArrayForKey("t") - self.unread = (decoder.decodeInt32ForKey("u") as Int32) != 0 + self.unread = decoder.decodeInt32ForKey("u", orElse: 0) != 0 } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/ForwardSourceInfoAttribute.swift b/TelegramCore/ForwardSourceInfoAttribute.swift index a4c6497220..7bedb90c45 100644 --- a/TelegramCore/ForwardSourceInfoAttribute.swift +++ b/TelegramCore/ForwardSourceInfoAttribute.swift @@ -13,7 +13,7 @@ public class ForwardSourceInfoAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p")), namespace: decoder.decodeInt32ForKey("n"), id: decoder.decodeInt32ForKey("i")) + self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: decoder.decodeInt32ForKey("n", orElse: 0), id: decoder.decodeInt32ForKey("i", orElse: 0)) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/GlobalNotificationSettings.swift b/TelegramCore/GlobalNotificationSettings.swift index de64e1fc9e..adcd200b40 100644 --- a/TelegramCore/GlobalNotificationSettings.swift +++ b/TelegramCore/GlobalNotificationSettings.swift @@ -21,8 +21,8 @@ public struct MessageNotificationSettings: Coding, Equatable { } public init(decoder: Decoder) { - self.enabled = (decoder.decodeInt32ForKey("e") as Int32) != 0 - self.displayPreviews = (decoder.decodeInt32ForKey("p") as Int32) != 0 + self.enabled = decoder.decodeInt32ForKey("e", orElse: 0) != 0 + self.displayPreviews = decoder.decodeInt32ForKey("p", orElse: 0) != 0 self.sound = PeerMessageSound.decodeInline(decoder) } diff --git a/TelegramCore/Holes.swift b/TelegramCore/Holes.swift index f8ecc9adde..897964add1 100644 --- a/TelegramCore/Holes.swift +++ b/TelegramCore/Holes.swift @@ -401,3 +401,81 @@ func fetchChatListHole(network: Network, postbox: Postbox, hole: ChatListHole) - } } } + +func fetchCallListHole(network: Network, postbox: Postbox, holeIndex: MessageIndex, limit: Int32 = 100) -> Signal { + let offset: Signal<(Int32, Int32, Api.InputPeer), NoError> + if holeIndex.id.peerId.namespace == Namespaces.Peer.Empty { + offset = single((0, 0, Api.InputPeer.inputPeerEmpty), NoError.self) + } else { + offset = postbox.loadedPeerWithId(holeIndex.id.peerId) + |> take(1) + |> map { peer in + return (holeIndex.timestamp, holeIndex.id.id + 1, apiInputPeer(peer) ?? .inputPeerEmpty) + } + } + return offset + |> mapToSignal { (timestamp, id, peer) -> Signal in + let searchResult = network.request(Api.functions.messages.search(flags: 0, peer: peer, q: "", filter: .inputMessagesFilterPhoneCalls(flags: 0), minDate: 0, maxDate: holeIndex.timestamp, offset: 0, maxId: holeIndex.id.id, limit: limit)) + |> retryRequest + |> mapToSignal { result -> Signal in + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + switch result { + case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + } + return postbox.modify { modifier -> Void in + var storeMessages: [StoreMessage] = [] + var topIndex: MessageIndex? + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + storeMessages.append(storeMessage) + if let index = storeMessage.index, topIndex == nil || index < topIndex! { + topIndex = index + } + } + } + + var updatedIndex: MessageIndex? + if let topIndex = topIndex { + updatedIndex = topIndex.predecessor() + } + + modifier.replaceGlobalMessageTagsHole(globalTags: [.Calls, .MissedCalls], index: holeIndex, with: updatedIndex, messages: storeMessages) + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(modifier: modifier, peers: peers, update: { _, updated -> Peer in + return updated + }) + modifier.updatePeerPresences(peerPresences) + } + } + return searchResult + } +} diff --git a/TelegramCore/InlineBotMessageAttribute.swift b/TelegramCore/InlineBotMessageAttribute.swift index 5e161344c3..45c5067906 100644 --- a/TelegramCore/InlineBotMessageAttribute.swift +++ b/TelegramCore/InlineBotMessageAttribute.swift @@ -17,7 +17,7 @@ public class InlineBotMessageAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.peerId = PeerId(decoder.decodeInt64ForKey("i")) + self.peerId = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/InstantPage.swift b/TelegramCore/InstantPage.swift index 5eb348d3ef..e227168ab1 100644 --- a/TelegramCore/InstantPage.swift +++ b/TelegramCore/InstantPage.swift @@ -55,7 +55,7 @@ public indirect enum InstantPageBlock: Coding, Equatable { case channelBanner(TelegramChannel?) public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case InstantPageBlockType.unsupported.rawValue: self = .unsupported case InstantPageBlockType.title.rawValue: @@ -63,7 +63,7 @@ public indirect enum InstantPageBlock: Coding, Equatable { case InstantPageBlockType.subtitle.rawValue: self = .subtitle(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.authorDate.rawValue: - self = .authorDate(author: decoder.decodeObjectForKey("a", decoder: { RichText(decoder: $0) }) as! RichText, date: decoder.decodeInt32ForKey("d")) + self = .authorDate(author: decoder.decodeObjectForKey("a", decoder: { RichText(decoder: $0) }) as! RichText, date: decoder.decodeInt32ForKey("d", orElse: 0)) case InstantPageBlockType.header.rawValue: self = .header(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.subheader.rawValue: @@ -77,29 +77,29 @@ public indirect enum InstantPageBlock: Coding, Equatable { case InstantPageBlockType.divider.rawValue: self = .divider case InstantPageBlockType.anchor.rawValue: - self = .anchor(decoder.decodeStringForKey("s")) + self = .anchor(decoder.decodeStringForKey("s", orElse: "")) case InstantPageBlockType.list.rawValue: - self = .list(items: decoder.decodeObjectArrayWithDecoderForKey("l"), ordered: decoder.decodeInt32ForKey("o") != 0) + self = .list(items: decoder.decodeObjectArrayWithDecoderForKey("l"), ordered: decoder.decodeOptionalInt32ForKey("o") != 0) case InstantPageBlockType.blockQuote.rawValue: self = .blockQuote(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.pullQuote.rawValue: self = .pullQuote(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.image.rawValue: - self = .image(id: MediaId(namespace: decoder.decodeInt32ForKey("i.n"), id: decoder.decodeInt64ForKey("i.i")), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) + self = .image(id: MediaId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.video.rawValue: - self = .video(id: MediaId(namespace: decoder.decodeInt32ForKey("i.n"), id: decoder.decodeInt64ForKey("i.i")), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText, autoplay: decoder.decodeInt32ForKey("ap") != 0, loop: decoder.decodeInt32ForKey("lo") != 0) + self = .video(id: MediaId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText, autoplay: decoder.decodeInt32ForKey("ap", orElse: 0) != 0, loop: decoder.decodeInt32ForKey("lo", orElse: 0) != 0) case InstantPageBlockType.cover.rawValue: self = .cover(decoder.decodeObjectForKey("c", decoder: { InstantPageBlock(decoder: $0) }) as! InstantPageBlock) case InstantPageBlockType.webEmbed.rawValue: - self = .webEmbed(url: decoder.decodeStringForKey("u"), html: decoder.decodeStringForKey("h"), dimensions: CGSize(width: CGFloat(decoder.decodeInt32ForKey("sw")), height: CGFloat(decoder.decodeInt32ForKey("sh"))), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText, stretchToWidth: decoder.decodeInt32ForKey("st") != 0, allowScrolling: decoder.decodeInt32ForKey("as") != 0) + self = .webEmbed(url: decoder.decodeOptionalStringForKey("u"), html: decoder.decodeOptionalStringForKey("h"), dimensions: CGSize(width: CGFloat(decoder.decodeInt32ForKey("sw", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("sh", orElse: 0))), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText, stretchToWidth: decoder.decodeInt32ForKey("st", orElse: 0) != 0, allowScrolling: decoder.decodeInt32ForKey("as", orElse: 0) != 0) case InstantPageBlockType.postEmbed.rawValue: var avatarId: MediaId? - let avatarIdNamespace: Int32? = decoder.decodeInt32ForKey("av.n") - let avatarIdId: Int64? = decoder.decodeInt64ForKey("av.i") + let avatarIdNamespace: Int32? = decoder.decodeOptionalInt32ForKey("av.n") + let avatarIdId: Int64? = decoder.decodeOptionalInt64ForKey("av.i") if let avatarIdNamespace = avatarIdNamespace, let avatarIdId = avatarIdId { avatarId = MediaId(namespace: avatarIdNamespace, id: avatarIdId) } - self = .postEmbed(url: decoder.decodeStringForKey("u"), webpageId: MediaId(namespace: decoder.decodeInt32ForKey("w.n"), id: decoder.decodeInt64ForKey("w.i")), avatarId: avatarId, author: decoder.decodeStringForKey("a"), date: decoder.decodeInt32ForKey("d"), blocks: decoder.decodeObjectArrayWithDecoderForKey("b"), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) + self = .postEmbed(url: decoder.decodeStringForKey("u", orElse: ""), webpageId: MediaId(namespace: decoder.decodeInt32ForKey("w.n", orElse: 0), id: decoder.decodeInt64ForKey("w.i", orElse: 0)), avatarId: avatarId, author: decoder.decodeStringForKey("a", orElse: ""), date: decoder.decodeInt32ForKey("d", orElse: 0), blocks: decoder.decodeObjectArrayWithDecoderForKey("b"), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.collage.rawValue: self = .collage(items: decoder.decodeObjectArrayWithDecoderForKey("b"), caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.slideshow.rawValue: @@ -420,7 +420,7 @@ public final class InstantPage: Coding, Equatable { public init(decoder: Decoder) { self.blocks = decoder.decodeObjectArrayWithDecoderForKey("b") self.media = MediaDictionary(decoder: decoder).dict - self.isComplete = decoder.decodeInt32ForKey("c") != 0 + self.isComplete = decoder.decodeInt32ForKey("c", orElse: 0) != 0 } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/Localization.swift b/TelegramCore/Localization.swift new file mode 100644 index 0000000000..a9d3d31e32 --- /dev/null +++ b/TelegramCore/Localization.swift @@ -0,0 +1,249 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum LocalizationEntry: Equatable { + case string(key: String, value: String) + case pluralizedString(key: String, zero: String?, one: String?, two: String?, few: String?, many: String?, other: String) + + public static func ==(lhs: LocalizationEntry, rhs: LocalizationEntry) -> Bool { + switch lhs { + case let .string(key, value): + if case .string(key, value) = rhs { + return true + } else { + return false + } + case let .pluralizedString(lhsKey, lhsZero, lhsOne, lhsTwo, lhsFew, lhsMany, lhsOther): + if case let .pluralizedString(rhsKey, rhsZero, rhsOne, rhsTwo, rhsFew, rhsMany, rhsOther) = rhs { + if lhsKey != rhsKey { + return false + } + if lhsZero != rhsZero { + return false + } + if lhsOne != lhsOne { + return false + } + if lhsTwo != lhsTwo { + return false + } + if lhsFew != lhsFew { + return false + } + if lhsMany != lhsMany { + return false + } + if lhsOther != lhsOther { + return false + } + return true + } else { + return false + } + } + } +} + +private struct LocalizationEntryFlags: OptionSet { + var rawValue: Int8 + + init(rawValue: Int8) { + self.rawValue = rawValue + } + + init() { + self.rawValue = 0 + } + + static let pluralized = LocalizationEntryFlags(rawValue: (1 << 0)) + static let hasZero = LocalizationEntryFlags(rawValue: (1 << 1)) + static let hasOne = LocalizationEntryFlags(rawValue: (1 << 2)) + static let hasTwo = LocalizationEntryFlags(rawValue: (1 << 3)) + static let hasFew = LocalizationEntryFlags(rawValue: (1 << 4)) + static let hasMany = LocalizationEntryFlags(rawValue: (1 << 5)) +} + +private func writeString(_ buffer: WriteBuffer, _ string: String) { + if let data = string.data(using: .utf8) { + var length: Int32 = Int32(data.count) + buffer.write(&length, offset: 0, length: 4) + buffer.write(data) + } else { + var length: Int32 = 0 + buffer.write(&length, offset: 0, length: 4) + } +} + +public final class Localization: Coding, Equatable { + public let entries: [LocalizationEntry] + + init(entries: [LocalizationEntry]) { + self.entries = entries + } + + public init(decoder: Decoder) { + let count = decoder.decodeInt32ForKey("c", orElse: 0) + var entries: [LocalizationEntry] = [] + if let data = decoder.decodeBytesForKey("d") { + for _ in 0 ..< count { + var flagsValue: Int8 = 0 + data.read(&flagsValue, offset: 0, length: 1) + let flags = LocalizationEntryFlags(rawValue: flagsValue) + + var length: Int32 = 0 + data.read(&length, offset: 0, length: 4) + + let keyData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let key = String(data: keyData, encoding: .utf8) + data.skip(Int(length)) + + if flags.contains(.pluralized) { + var zero: String? + var one: String? + var two: String? + var few: String? + var many: String? + var other: String? + + if flags.contains(.hasZero) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + zero = value + } + + if flags.contains(.hasZero) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + one = value + } + + if flags.contains(.hasZero) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + two = value + } + + if flags.contains(.hasZero) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + few = value + } + + if flags.contains(.hasZero) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + many = value + } + + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + other = value + + if let key = key, let other = other { + entries.append(.pluralizedString(key: key, zero: zero, one: one, two: two, few: few, many: many, other: other)) + } + } else { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + + if let key = key, let value = value { + entries.append(.string(key: key, value: value)) + } + } + } + } + self.entries = entries + } + + public func encode(_ encoder: Encoder) { + encoder.encodeInt32(Int32(self.entries.count), forKey: "c") + + let buffer = WriteBuffer() + for entry in self.entries { + var flags: LocalizationEntryFlags = [] + switch entry { + case .string: + flags = [] + case let .pluralizedString(_, zero, one, two, few, many, _): + flags.insert(.pluralized) + if zero != nil { + flags.insert(.hasZero) + } + if one != nil { + flags.insert(.hasOne) + } + if two != nil { + flags.insert(.hasTwo) + } + if few != nil { + flags.insert(.hasFew) + } + if many != nil { + flags.insert(.hasMany) + } + } + var flagsValue: Int8 = flags.rawValue + buffer.write(&flagsValue, offset: 0, length: 1) + + switch entry { + case let .string(key, value): + writeString(buffer, key) + writeString(buffer, value) + case let .pluralizedString(key, zero, one, two, few, many, other): + writeString(buffer, key) + if let zero = zero { + writeString(buffer, zero) + } + if let one = one { + writeString(buffer, one) + } + if let two = two { + writeString(buffer, two) + } + if let few = few { + writeString(buffer, few) + } + if let many = many { + writeString(buffer, many) + } + writeString(buffer, other) + } + } + encoder.encodeBytes(buffer, forKey: "d") + } + + public static func ==(lhs: Localization, rhs: Localization) -> Bool { + if lhs === rhs { + return true + } + if lhs.entries == rhs.entries { + return true + } + return false + } +} diff --git a/TelegramCore/LocalizationInfo.swift b/TelegramCore/LocalizationInfo.swift new file mode 100644 index 0000000000..d39ffec7ff --- /dev/null +++ b/TelegramCore/LocalizationInfo.swift @@ -0,0 +1,26 @@ +import Foundation + +public final class LocalizationInfo { + public let languageCode: String + public let title: String + public let localizedTitle: String + + init(languageCode: String, title: String, localizedTitle: String) { + self.languageCode = languageCode + self.title = title + self.localizedTitle = localizedTitle + } +} + +public final class SuggestedLocalizationInfo { + public let languageCode: String + public let extractedEntries: [LocalizationEntry] + + public let availableLocalizations: [LocalizationInfo] + + init(languageCode: String, extractedEntries: [LocalizationEntry], availableLocalizations: [LocalizationInfo]) { + self.languageCode = languageCode + self.extractedEntries = extractedEntries + self.availableLocalizations = availableLocalizations + } +} diff --git a/TelegramCore/LocalizationSettings.swift b/TelegramCore/LocalizationSettings.swift new file mode 100644 index 0000000000..8ec0820420 --- /dev/null +++ b/TelegramCore/LocalizationSettings.swift @@ -0,0 +1,40 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public final class LocalizationSettings: PreferencesEntry, Equatable { + public let languageCode: String + public let localization: Localization + + init(languageCode: String, localization: Localization) { + self.languageCode = languageCode + self.localization = localization + } + + public init(decoder: Decoder) { + self.languageCode = decoder.decodeStringForKey("lc", orElse: "en") + self.localization = decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization + } + + public func encode(_ encoder: Encoder) { + encoder.encodeString(self.languageCode, forKey: "lc") + encoder.encodeObject(self.localization, forKey: "loc") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? LocalizationSettings { + return self == to + } else { + return false + } + } + + public static func ==(lhs: LocalizationSettings, rhs: LocalizationSettings) -> Bool { + return lhs.languageCode == rhs.languageCode && lhs.localization == rhs.localization + } +} diff --git a/TelegramCore/Localizations.swift b/TelegramCore/Localizations.swift new file mode 100644 index 0000000000..70281186e6 --- /dev/null +++ b/TelegramCore/Localizations.swift @@ -0,0 +1,83 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func suggestedLocalizationInfo(network: Network, languageCode: String, extractKeys: [String]) -> Signal { + return combineLatest(network.request(Api.functions.langpack.getLanguages()), network.request(Api.functions.langpack.getStrings(langCode: languageCode, keys: extractKeys))) + |> retryRequest + |> map { languages, strings -> SuggestedLocalizationInfo in + 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)) + } + } + var infos: [LocalizationInfo] = [] + for language in languages { + switch language { + case let .langPackLanguage(name, nativeName, langCode): + infos.append(LocalizationInfo(languageCode: langCode, title: name, localizedTitle: nativeName)) + } + } + return SuggestedLocalizationInfo(languageCode: languageCode, extractedEntries: entries, availableLocalizations: infos) + } +} + +public func availableLocalizations(network: Network) -> Signal<[LocalizationInfo], NoError> { + return network.request(Api.functions.langpack.getLanguages()) + |> retryRequest + |> map { languages -> [LocalizationInfo] in + var infos: [LocalizationInfo] = [] + for language in languages { + switch language { + case let .langPackLanguage(name, nativeName, langCode): + infos.append(LocalizationInfo(languageCode: langCode, title: name, localizedTitle: nativeName)) + } + } + return infos + } +} + +public func downloadLocalization(network: Network, languageCode: String) -> Signal { + return network.request(Api.functions.langpack.getLangPack(langCode: languageCode)) + |> retryRequest + |> map { result -> Localization in + var entries: [LocalizationEntry] = [] + switch result { + case let .langPackDifference(_, _, _, strings): + 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)) + } + } + } + + return Localization(entries: entries) + } +} + +public func downoadAndApplyLocalization(postbox: Postbox, network: Network, languageCode: String) -> Signal { + return downloadLocalization(network: network, languageCode: languageCode) + |> mapToSignal { language -> Signal in + return postbox.modify { modifier -> Void in + modifier.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in + return LocalizationSettings(languageCode: languageCode, localization: language) + }) + + network.context.updateApiEnvironment { current in + return current?.withUpdatedLangPackCode(languageCode) + } + } + } +} diff --git a/TelegramCore/Log.swift b/TelegramCore/Log.swift index 57e7398bdc..4967de2182 100644 --- a/TelegramCore/Log.swift +++ b/TelegramCore/Log.swift @@ -2,8 +2,10 @@ import Foundation import TelegramCorePrivateModule #if os(macOS) import SwiftSignalKitMac + import PostboxMac #else import SwiftSignalKit + import Postbox #endif private let queue = DispatchQueue(label: "org.telegram.Telegram.trace", qos: .utility) @@ -59,13 +61,13 @@ public func registerLoggingFunctions() { private var sharedLogger: Logger? public final class Logger { - private let queue = DispatchQueue(label: "org.telegram.Telegram.log", qos: .utility) + private let queue = Queue(name: "org.telegram.Telegram.log", qos: .utility) private let maxLength: Int = 2 * 1024 * 1024 //private let maxLength: Int = 4 * 1024 private let maxFiles: Int = 20 private let basePath: String - private var file: (Int32, Int)? + private var file: (ManagedFile, Int)? public var logToFile: Bool = true public var logToConsole: Bool = true @@ -133,14 +135,14 @@ public final class Logger { content = String(format: "[%@] %d-%d-%d %02d:%02d:%02d.%03d %@", arguments: [tag, Int(timeinfo.tm_year) + 1900, Int(timeinfo.tm_mon + 1), Int(timeinfo.tm_mday), Int(timeinfo.tm_hour), Int(timeinfo.tm_min), Int(timeinfo.tm_sec), Int(milliseconds), string]) } - var fd: Int32? + var currentFile: ManagedFile? var openNew = false if let (file, length) = self.file { if length >= self.maxLength { - close(file) + self.file = nil openNew = true } else { - fd = file + currentFile = file } } else { openNew = true @@ -172,10 +174,9 @@ public final class Logger { if let (_, url) = maxCreationDate { var value = stat() if stat(url.path, &value) == 0 && Int(value.st_size) < self.maxLength { - let handle = open(url.path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR) - if handle >= 0 { - fd = handle - self.file = (handle, Int(value.st_size)) + if let file = ManagedFile(queue: self.queue, path: url.path, mode: .append) { + self.file = (file, Int(value.st_size)) + currentFile = file } } else { createNew = true @@ -190,23 +191,22 @@ public final class Logger { let path = self.basePath + "/" + fileName - let handle = open(path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR) - if handle >= 0 { - fd = handle - self.file = (handle, 0) + if let file = ManagedFile(queue: self.queue, path: path, mode: .append) { + self.file = (file, 0) + currentFile = file } } } - if let fd = fd { + if let currentFile = currentFile { if let data = content.data(using: .utf8) { data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in - write(fd, bytes, data.count) + currentFile.write(bytes, count: data.count) } var newline: UInt8 = 0x0a - write(fd, &newline, 1) + currentFile.write(&newline, count: 1) if let file = self.file { - self.file = (file.0, file.1 + data.count) + self.file = (file.0, file.1 + data.count + 1) } else { assertionFailure() } diff --git a/TelegramCore/ManagedAutoremoveMessageOperations.swift b/TelegramCore/ManagedAutoremoveMessageOperations.swift index e3ba701150..c9119ce574 100644 --- a/TelegramCore/ManagedAutoremoveMessageOperations.swift +++ b/TelegramCore/ManagedAutoremoveMessageOperations.swift @@ -72,6 +72,7 @@ func managedAutoremoveMessageOperations(postbox: Postbox) -> Signal [Disposable] in return helper.reset() } diff --git a/TelegramCore/ManagedConfigurationUpdates.swift b/TelegramCore/ManagedConfigurationUpdates.swift index 34220ffa5f..a4928a58ce 100644 --- a/TelegramCore/ManagedConfigurationUpdates.swift +++ b/TelegramCore/ManagedConfigurationUpdates.swift @@ -11,29 +11,46 @@ import Foundation func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal { let poll = Signal { subscriber in - return network.request(Api.functions.help.getConfig()).start(next: { result in - switch result { - case let .config(_, _, _, _, _, dcOptions, chatSizeMax, megagroupSizeMax, forwardedCountMax, onlineUpdatePeriodMs, offlineBlurTimeoutMs, offlineIdleTimeoutMs, onlineCloudTimeoutMs, notifyCloudDelayMs, notifyDefaultDelayMs, chatBigSize, pushChatPeriodMs, pushChatLimit, savedGifsLimit, editTimeLimit, ratingEDecay, stickersRecentLimit, tmpSessions, pinnedDialogsCountMax, callReceiveTimeoutMs, callRingTimeoutMs, callConnectTimeoutMs, callPacketTimeoutMs, meUrlPrefix, disabledFeatures): - var addressList: [Int: [MTDatacenterAddress]] = [:] - for option in dcOptions { - switch option { - case let .dcOption(flags, id, ipAddress, port): - let preferForMedia = (flags & (1 << 1)) != 0 - if addressList[Int(id)] == nil { - addressList[Int(id)] = [] + return (network.request(Api.functions.help.getConfig()) |> retryRequest |> mapToSignal { result -> Signal in + return postbox.modify { modifier -> Void in + switch result { + case let .config(_, _, _, _, _, dcOptions, chatSizeMax, megagroupSizeMax, forwardedCountMax, onlineUpdatePeriodMs, offlineBlurTimeoutMs, offlineIdleTimeoutMs, onlineCloudTimeoutMs, notifyCloudDelayMs, notifyDefaultDelayMs, chatBigSize, pushChatPeriodMs, pushChatLimit, savedGifsLimit, editTimeLimit, ratingEDecay, stickersRecentLimit, tmpSessions, pinnedDialogsCountMax, callReceiveTimeoutMs, callRingTimeoutMs, callConnectTimeoutMs, callPacketTimeoutMs, meUrlPrefix, suggestedLangCode, disabledFeatures): + var addressList: [Int: [MTDatacenterAddress]] = [:] + for option in dcOptions { + switch option { + case let .dcOption(flags, id, ipAddress, port): + let preferForMedia = (flags & (1 << 1)) != 0 + if addressList[Int(id)] == nil { + addressList[Int(id)] = [] + } + let restrictToTcp = (flags & (1 << 2)) != 0 + let isCdn = (flags & (1 << 3)) != 0 + addressList[Int(id)]!.append(MTDatacenterAddress(ip: ipAddress, port: UInt16(port), preferForMedia: preferForMedia, restrictToTcp: restrictToTcp, cdn: isCdn)) + } + } + network.context.performBatchUpdates { + for (id, list) in addressList { + network.context.updateAddressSetForDatacenter(withId: id, addressSet: MTDatacenterAddressSet(addressList: list)) + } + } + + modifier.updatePreferencesEntry(key: PreferencesKeys.suggestedLocalization, { entry in + var currentLanguageCode: String? + if let entry = entry as? SuggestedLocalizationEntry { + currentLanguageCode = entry.languageCode + } + if currentLanguageCode != suggestedLangCode { + if let suggestedLangCode = suggestedLangCode { + return SuggestedLocalizationEntry(languageCode: suggestedLangCode, isSeen: false) + } else { + return nil } - let restrictToTcp = (flags & (1 << 2)) != 0 - let isCdn = (flags & (1 << 3)) != 0 - addressList[Int(id)]!.append(MTDatacenterAddress(ip: ipAddress, port: UInt16(port), preferForMedia: preferForMedia, restrictToTcp: restrictToTcp, cdn: isCdn)) - } - } - network.context.performBatchUpdates { - for (id, list) in addressList { - network.context.updateAddressSetForDatacenter(withId: id, addressSet: MTDatacenterAddressSet(addressList: list)) - } - } + } + return entry + }) + } } - }) + }).start() } return (poll |> then(.complete() |> delay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart diff --git a/TelegramCore/MarkMessageContentAsConsumedInteractively.swift b/TelegramCore/MarkMessageContentAsConsumedInteractively.swift index e6ce9f524a..aeb1f98408 100644 --- a/TelegramCore/MarkMessageContentAsConsumedInteractively.swift +++ b/TelegramCore/MarkMessageContentAsConsumedInteractively.swift @@ -29,7 +29,7 @@ public func markMessageContentAsConsumedInteractively(postbox: Postbox, messageI let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) for i in 0 ..< updatedAttributes.count { if let attribute = updatedAttributes[i] as? AutoremoveTimeoutMessageAttribute { - if attribute.countdownBeginTime == nil && message.containsSecretMedia { + if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && message.containsSecretMedia { updatedAttributes[i] = AutoremoveTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: timestamp) updateMessage = true @@ -92,7 +92,7 @@ func markMessageContentAsConsumedRemotely(modifier: Modifier, messageId: Message let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) for i in 0 ..< updatedAttributes.count { if let attribute = updatedAttributes[i] as? AutoremoveTimeoutMessageAttribute { - if attribute.countdownBeginTime == nil && message.containsSecretMedia { + if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && message.containsSecretMedia { updatedAttributes[i] = AutoremoveTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: timestamp) updateMessage = true modifier.addTimestampBasedMessageAttribute(tag: 0, timestamp: timestamp + attribute.timeout, messageId: messageId) diff --git a/TelegramCore/Namespaces.swift b/TelegramCore/Namespaces.swift index d8416c5c63..fd6dfb23f3 100644 --- a/TelegramCore/Namespaces.swift +++ b/TelegramCore/Namespaces.swift @@ -62,9 +62,17 @@ public extension MessageTags { static let Music = MessageTags(rawValue: 1 << 2) static let WebPage = MessageTags(rawValue: 1 << 3) static let VoiceOrInstantVideo = MessageTags(rawValue: 1 << 4) + + static let all: MessageTags = [.PhotoOrVideo, .File, .Music, .WebPage, .VoiceOrInstantVideo] +} + +public extension GlobalMessageTags { + static let Calls = GlobalMessageTags(rawValue: 1 << 0) + static let MissedCalls = GlobalMessageTags(rawValue: 1 << 1) + + static let all: GlobalMessageTags = [.Calls, .MissedCalls] } -let allMessageTags: MessageTags = [.PhotoOrVideo, .File, .Music, .WebPage, .VoiceOrInstantVideo] let peerIdNamespacesWithInitialCloudMessageHoles = [Namespaces.Peer.CloudUser, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel] struct OperationLogTags { @@ -86,6 +94,8 @@ struct OperationLogTags { private enum PreferencesKeyValues: Int32 { case globalNotifications = 0 case cacheStorageSettings = 1 + case localizationSettings = 2 + case suggestedLocalization = 3 } public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey { @@ -106,4 +116,16 @@ public struct PreferencesKeys { key.setInt32(0, value: PreferencesKeyValues.cacheStorageSettings.rawValue) return key }() + + public static let localizationSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.localizationSettings.rawValue) + return key + }() + + public static let suggestedLocalization: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.suggestedLocalization.rawValue) + return key + }() } diff --git a/TelegramCore/Network.swift b/TelegramCore/Network.swift index 0371332d5e..bf019903cb 100644 --- a/TelegramCore/Network.swift +++ b/TelegramCore/Network.swift @@ -293,18 +293,19 @@ func networkUsageStats(basePath: String, reset: ResetNetworkUsageStats) -> Signa }) |> then(Signal.complete() |> delay(5.0, queue: Queue.concurrentDefaultQueue()))) |> restart } -func initializedNetwork(apiId: Int32, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool) -> Signal { +func initializedNetwork(apiId: Int32, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?) -> Signal { return Signal { subscriber in Queue.concurrentDefaultQueue().async { let _ = registeredLoggingFunctions let serialization = Serialization() - let apiEnvironment = MTApiEnvironment() + var apiEnvironment = MTApiEnvironment() apiEnvironment.apiId = apiId apiEnvironment.layer = NSNumber(value: Int(serialization.currentLayer())) apiEnvironment.disableUpdates = supplementary + apiEnvironment = apiEnvironment.withUpdatedLangPackCode(languageCode ?? "en") let context = MTContext(serialization: serialization, apiEnvironment: apiEnvironment)! diff --git a/TelegramCore/OutgoingChatContextResultMessageAttribute.swift b/TelegramCore/OutgoingChatContextResultMessageAttribute.swift index 492de2557d..3e6b3b3ddc 100644 --- a/TelegramCore/OutgoingChatContextResultMessageAttribute.swift +++ b/TelegramCore/OutgoingChatContextResultMessageAttribute.swift @@ -15,8 +15,8 @@ public class OutgoingChatContextResultMessageAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.queryId = decoder.decodeInt64ForKey("q") - self.id = decoder.decodeStringForKey("i") + self.queryId = decoder.decodeInt64ForKey("q", orElse: 0) + self.id = decoder.decodeStringForKey("i", orElse: "") } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/OutgoingContentInfoMessageAttribute.swift b/TelegramCore/OutgoingContentInfoMessageAttribute.swift index 59d571c22f..8c19ec7ba5 100644 --- a/TelegramCore/OutgoingContentInfoMessageAttribute.swift +++ b/TelegramCore/OutgoingContentInfoMessageAttribute.swift @@ -27,7 +27,7 @@ public class OutgoingContentInfoMessageAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.flags = OutgoingContentInfoFlags(rawValue: decoder.decodeInt32ForKey("f")) + self.flags = OutgoingContentInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/OutgoingMessageInfoAttribute.swift b/TelegramCore/OutgoingMessageInfoAttribute.swift index 6738ff2ead..d1f9aca02e 100644 --- a/TelegramCore/OutgoingMessageInfoAttribute.swift +++ b/TelegramCore/OutgoingMessageInfoAttribute.swift @@ -29,8 +29,8 @@ public class OutgoingMessageInfoAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.uniqueId = decoder.decodeInt64ForKey("u") - self.flags = OutgoingMessageInfoFlags(rawValue: decoder.decodeInt32ForKey("f")) + self.uniqueId = decoder.decodeInt64ForKey("u", orElse: 0) + self.flags = OutgoingMessageInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/PeerAccessRestrictionInfo.swift b/TelegramCore/PeerAccessRestrictionInfo.swift index 3d0749a606..65956c45ad 100644 --- a/TelegramCore/PeerAccessRestrictionInfo.swift +++ b/TelegramCore/PeerAccessRestrictionInfo.swift @@ -13,7 +13,7 @@ public final class PeerAccessRestrictionInfo: Coding, Equatable { } public init(decoder: Decoder) { - self.reason = decoder.decodeStringForKey("rsn") + self.reason = decoder.decodeStringForKey("rsn", orElse: "") } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift b/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift index 929b6d78c4..bff83084ad 100644 --- a/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift +++ b/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift @@ -531,8 +531,10 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32 break } } + + let (tags, globalTags) = tagsForStoreMessage(incoming: true, media: parsedMedia, textEntities: entitiesAttribute?.entities) - return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, timestamp: timestamp, flags: [.Incoming], tags: tagsForStoreMessage(media: parsedMedia, textEntities: entitiesAttribute?.entities), globalTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources) + return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources) case let .decryptedMessageService(randomId, action): switch action { case let .decryptedMessageActionDeleteMessages(randomIds): diff --git a/TelegramCore/ReplyMarkupMessageAttribute.swift b/TelegramCore/ReplyMarkupMessageAttribute.swift index 10e7b7babe..a599bd5136 100644 --- a/TelegramCore/ReplyMarkupMessageAttribute.swift +++ b/TelegramCore/ReplyMarkupMessageAttribute.swift @@ -16,11 +16,11 @@ public enum ReplyMarkupButtonAction: Coding, Equatable { case payment public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("v") as Int32 { + switch decoder.decodeInt32ForKey("v", orElse: 0) { case 0: self = .text case 1: - self = .url(decoder.decodeStringForKey("u")) + self = .url(decoder.decodeStringForKey("u", orElse: "")) case 2: self = .callback(decoder.decodeBytesForKey("d") ?? MemoryBuffer()) case 3: @@ -28,7 +28,7 @@ public enum ReplyMarkupButtonAction: Coding, Equatable { case 4: self = .requestMap case 5: - self = .switchInline(samePeer: decoder.decodeInt32ForKey("s") != 0, query: decoder.decodeStringForKey("q")) + self = .switchInline(samePeer: decoder.decodeInt32ForKey("s", orElse: 0) != 0, query: decoder.decodeStringForKey("q", orElse: "")) case 6: self = .openWebApp case 7: @@ -127,7 +127,7 @@ public struct ReplyMarkupButton: Coding, Equatable { } public init(decoder: Decoder) { - self.title = decoder.decodeStringForKey(".t") + self.title = decoder.decodeStringForKey(".t", orElse: "") self.action = ReplyMarkupButtonAction(decoder: decoder) } @@ -190,7 +190,7 @@ public class ReplyMarkupMessageAttribute: MessageAttribute, Equatable { public required init(decoder: Decoder) { self.rows = decoder.decodeObjectArrayWithDecoderForKey("r") - self.flags = ReplyMarkupMessageFlags(rawValue: decoder.decodeInt32ForKey("f")) + self.flags = ReplyMarkupMessageFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/ReplyMessageAttribute.swift b/TelegramCore/ReplyMessageAttribute.swift index 48460b1cae..12c1e579f1 100644 --- a/TelegramCore/ReplyMessageAttribute.swift +++ b/TelegramCore/ReplyMessageAttribute.swift @@ -17,8 +17,8 @@ public class ReplyMessageAttribute: MessageAttribute { } required public init(decoder: Decoder) { - let namespaceAndId: Int64 = decoder.decodeInt64ForKey("i") - self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p")), namespace: Int32(namespaceAndId & 0xffffffff), id: Int32((namespaceAndId >> 32) & 0xffffffff)) + let namespaceAndId: Int64 = decoder.decodeInt64ForKey("i", orElse: 0) + self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: Int32(namespaceAndId & 0xffffffff), id: Int32((namespaceAndId >> 32) & 0xffffffff)) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/ResolvePeerByName.swift b/TelegramCore/ResolvePeerByName.swift index 4c51326989..37acc88c49 100644 --- a/TelegramCore/ResolvePeerByName.swift +++ b/TelegramCore/ResolvePeerByName.swift @@ -30,12 +30,12 @@ final class CachedResolvedByNamePeer: Coding { } init(decoder: Decoder) { - if let peerId = (decoder.decodeInt64ForKey("p") as Int64?) { + if let peerId = decoder.decodeOptionalInt64ForKey("p") { self.peerId = PeerId(peerId) } else { self.peerId = nil } - self.timestamp = decoder.decodeInt32ForKey("t") + self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) } func encode(_ encoder: Encoder) { diff --git a/TelegramCore/RichText.swift b/TelegramCore/RichText.swift index 0a44d8845f..daceffe0b0 100644 --- a/TelegramCore/RichText.swift +++ b/TelegramCore/RichText.swift @@ -31,11 +31,11 @@ public indirect enum RichText: Coding, Equatable { case concat([RichText]) public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case RichTextTypes.empty.rawValue: self = .empty case RichTextTypes.plain.rawValue: - self = .plain(decoder.decodeStringForKey("s")) + self = .plain(decoder.decodeStringForKey("s", orElse: "")) case RichTextTypes.bold.rawValue: self = .bold(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) case RichTextTypes.italic.rawValue: @@ -47,15 +47,15 @@ public indirect enum RichText: Coding, Equatable { case RichTextTypes.fixed.rawValue: self = .fixed(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) case RichTextTypes.url.rawValue: - let webpageIdNamespace: Int32? = decoder.decodeInt32ForKey("w.n") - let webpageIdId: Int64? = decoder.decodeInt64ForKey("w.i") + let webpageIdNamespace: Int32? = decoder.decodeOptionalInt32ForKey("w.n") + let webpageIdId: Int64? = decoder.decodeOptionalInt64ForKey("w.i") var webpageId: MediaId? if let webpageIdNamespace = webpageIdNamespace, let webpageIdId = webpageIdId { webpageId = MediaId(namespace: webpageIdNamespace, id: webpageIdId) } - self = .url(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, url: decoder.decodeStringForKey("u"), webpageId: webpageId) + self = .url(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, url: decoder.decodeStringForKey("u", orElse: ""), webpageId: webpageId) case RichTextTypes.email.rawValue: - self = .email(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, email: decoder.decodeStringForKey("e")) + self = .email(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, email: decoder.decodeStringForKey("e", orElse: "")) case RichTextTypes.concat.rawValue: self = .concat(decoder.decodeObjectArrayWithDecoderForKey("a")) default: diff --git a/TelegramCore/SecretChatEncryptionConfig.swift b/TelegramCore/SecretChatEncryptionConfig.swift index 999520012a..baa24f8f43 100644 --- a/TelegramCore/SecretChatEncryptionConfig.swift +++ b/TelegramCore/SecretChatEncryptionConfig.swift @@ -21,9 +21,9 @@ final class SecretChatEncryptionConfig: Coding { } init(decoder: Decoder) { - self.g = decoder.decodeInt32ForKey("g") + self.g = decoder.decodeInt32ForKey("g", orElse: 0) self.p = decoder.decodeBytesForKey("p")! - self.version = decoder.decodeInt32ForKey("v") + self.version = decoder.decodeInt32ForKey("v", orElse: 0) } func encode(_ encoder: Encoder) { diff --git a/TelegramCore/SecretChatFileReference.swift b/TelegramCore/SecretChatFileReference.swift index cde004186f..2305f9331c 100644 --- a/TelegramCore/SecretChatFileReference.swift +++ b/TelegramCore/SecretChatFileReference.swift @@ -21,11 +21,11 @@ final class SecretChatFileReference: Coding { } init(decoder: Decoder) { - self.id = decoder.decodeInt64ForKey("i") - self.accessHash = decoder.decodeInt64ForKey("a") - self.size = decoder.decodeInt32ForKey("s") - self.datacenterId = decoder.decodeInt32ForKey("d") - self.keyFingerprint = decoder.decodeInt32ForKey("f") + self.id = decoder.decodeInt64ForKey("i", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) + self.size = decoder.decodeInt32ForKey("s", orElse: 0) + self.datacenterId = decoder.decodeInt32ForKey("d", orElse: 0) + self.keyFingerprint = decoder.decodeInt32ForKey("f", orElse: 0) } func encode(_ encoder: Encoder) { diff --git a/TelegramCore/SecretChatIncomingDecryptedOperation.swift b/TelegramCore/SecretChatIncomingDecryptedOperation.swift index 9dd6b5dc4c..41b9f0de8b 100644 --- a/TelegramCore/SecretChatIncomingDecryptedOperation.swift +++ b/TelegramCore/SecretChatIncomingDecryptedOperation.swift @@ -15,8 +15,8 @@ struct SecretChatOperationSequenceInfo: Coding { } init(decoder: Decoder) { - self.topReceivedOperationIndex = decoder.decodeInt32ForKey("r") - self.operationIndex = decoder.decodeInt32ForKey("o") + self.topReceivedOperationIndex = decoder.decodeInt32ForKey("r", orElse: 0) + self.operationIndex = decoder.decodeInt32ForKey("o", orElse: 0) } func encode(_ encoder: Encoder) { @@ -41,8 +41,8 @@ final class SecretChatIncomingDecryptedOperation: Coding { } init(decoder: Decoder) { - self.timestamp = decoder.decodeInt32ForKey("t") - self.layer = decoder.decodeInt32ForKey("l") + self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + self.layer = decoder.decodeInt32ForKey("l", orElse: 0) self.sequenceInfo = decoder.decodeObjectForKey("s", decoder: { SecretChatOperationSequenceInfo(decoder: $0) }) as? SecretChatOperationSequenceInfo self.contents = decoder.decodeBytesForKey("c")! self.file = decoder.decodeObjectForKey("f", decoder: { SecretChatFileReference(decoder: $0) }) as? SecretChatFileReference diff --git a/TelegramCore/SecretChatIncomingEncryptedOperation.swift b/TelegramCore/SecretChatIncomingEncryptedOperation.swift index abd636319e..7e4e6aa5aa 100644 --- a/TelegramCore/SecretChatIncomingEncryptedOperation.swift +++ b/TelegramCore/SecretChatIncomingEncryptedOperation.swift @@ -47,11 +47,11 @@ final class SecretChatIncomingEncryptedOperation: Coding { } init(decoder: Decoder) { - self.peerId = PeerId(decoder.decodeInt64ForKey("p")) - self.globallyUniqueId = decoder.decodeInt64ForKey("u") - self.timestamp = decoder.decodeInt32ForKey("t") - self.type = SecretChatIncomingEncryptedOperationType(decoder.decodeInt32ForKey("k")) - self.keyFingerprint = decoder.decodeInt64ForKey("f") + self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.globallyUniqueId = decoder.decodeInt64ForKey("u", orElse: 0) + self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + self.type = SecretChatIncomingEncryptedOperationType(decoder.decodeInt32ForKey("k", orElse: 0)) + self.keyFingerprint = decoder.decodeInt64ForKey("f", orElse: 0) self.contents = decoder.decodeBytesForKey("c")! self.mediaFileReference = decoder.decodeObjectForKey("m", decoder: { SecretChatFileReference(decoder: $0) }) as? SecretChatFileReference } diff --git a/TelegramCore/SecretChatKeychain.swift b/TelegramCore/SecretChatKeychain.swift index a8bf9406e6..d866ac1aac 100644 --- a/TelegramCore/SecretChatKeychain.swift +++ b/TelegramCore/SecretChatKeychain.swift @@ -10,11 +10,11 @@ enum SecretChatKeyValidity: Coding, Equatable { case sequenceBasedIndexRange(fromCanonicalIndex: Int32) init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case 0: self = .indefinite case 1: - self = .sequenceBasedIndexRange(fromCanonicalIndex: decoder.decodeInt32ForKey("l")) + self = .sequenceBasedIndexRange(fromCanonicalIndex: decoder.decodeInt32ForKey("l", orElse: 0)) default: assertionFailure() self = .sequenceBasedIndexRange(fromCanonicalIndex: Int32.max) @@ -63,10 +63,10 @@ final class SecretChatKey: Coding, Equatable { } init(decoder: Decoder) { - self.fingerprint = decoder.decodeInt64ForKey("f") + self.fingerprint = decoder.decodeInt64ForKey("f", orElse: 0) self.key = decoder.decodeBytesForKey("k")! self.validity = decoder.decodeObjectForKey("v", decoder: { SecretChatKeyValidity(decoder: $0) }) as! SecretChatKeyValidity - self.useCount = decoder.decodeInt32ForKey("u") + self.useCount = decoder.decodeInt32ForKey("u", orElse: 0) } func encode(_ encoder: Encoder) { diff --git a/TelegramCore/SecretChatOutgoingOperation.swift b/TelegramCore/SecretChatOutgoingOperation.swift index 7ab46e8a24..b3429ad7fb 100644 --- a/TelegramCore/SecretChatOutgoingOperation.swift +++ b/TelegramCore/SecretChatOutgoingOperation.swift @@ -17,13 +17,13 @@ enum SecretChatOutgoingFileReference: Coding { case uploadedLarge(id: Int64, partCount: Int32, keyFingerprint: Int32) init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("v") as Int32 { + switch decoder.decodeInt32ForKey("v", orElse: 0) { case SecretChatOutgoingFileValue.remote.rawValue: - self = .remote(id: decoder.decodeInt64ForKey("i"), accessHash: decoder.decodeInt64ForKey("a")) + self = .remote(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("a", orElse: 0)) case SecretChatOutgoingFileValue.uploadedRegular.rawValue: - self = .uploadedRegular(id: decoder.decodeInt64ForKey("i"), partCount: decoder.decodeInt32ForKey("p"), md5Digest: decoder.decodeStringForKey("d"), keyFingerprint: decoder.decodeInt32ForKey("f")) + self = .uploadedRegular(id: decoder.decodeInt64ForKey("i", orElse: 0), partCount: decoder.decodeInt32ForKey("p", orElse: 0), md5Digest: decoder.decodeStringForKey("d", orElse: ""), keyFingerprint: decoder.decodeInt32ForKey("f", orElse: 0)) case SecretChatOutgoingFileValue.uploadedLarge.rawValue: - self = .uploadedLarge(id: decoder.decodeInt64ForKey("i"), partCount: decoder.decodeInt32ForKey("p"), keyFingerprint: decoder.decodeInt32ForKey("f")) + self = .uploadedLarge(id: decoder.decodeInt64ForKey("i", orElse: 0), partCount: decoder.decodeInt32ForKey("p", orElse: 0), keyFingerprint: decoder.decodeInt32ForKey("f", orElse: 0)) default: assertionFailure() self = .remote(id: 0, accessHash: 0) @@ -64,7 +64,7 @@ struct SecretChatOutgoingFile: Coding { init(decoder: Decoder) { self.reference = decoder.decodeObjectForKey("r", decoder: { SecretChatOutgoingFileReference(decoder: $0) }) as! SecretChatOutgoingFileReference - self.size = decoder.decodeInt32ForKey("s") + self.size = decoder.decodeInt32ForKey("s", orElse: 0) self.key = SecretFileEncryptionKey(aesKey: decoder.decodeBytesForKey("k")!.makeData(), aesIv: decoder.decodeBytesForKey("i")!.makeData()) } @@ -116,39 +116,39 @@ enum SecretChatOutgoingOperationContents: Coding { case terminate init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case SecretChatOutgoingOperationValue.initialHandshakeAccept.rawValue: - self = .initialHandshakeAccept(gA: decoder.decodeBytesForKey("g")!, accessHash: decoder.decodeInt64ForKey("h"), b: decoder.decodeBytesForKey("b")!) + self = .initialHandshakeAccept(gA: decoder.decodeBytesForKey("g")!, accessHash: decoder.decodeInt64ForKey("h", orElse: 0), b: decoder.decodeBytesForKey("b")!) case SecretChatOutgoingOperationValue.sendMessage.rawValue: - self = .sendMessage(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l"))!, id: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("i.p")), namespace: decoder.decodeInt32ForKey("i.n"), id: decoder.decodeInt32ForKey("i.i")), file: decoder.decodeObjectForKey("f", decoder: { SecretChatOutgoingFile(decoder: $0) }) as? SecretChatOutgoingFile) + self = .sendMessage(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, id: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("i.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt32ForKey("i.i", orElse: 0)), file: decoder.decodeObjectForKey("f", decoder: { SecretChatOutgoingFile(decoder: $0) }) as? SecretChatOutgoingFile) case SecretChatOutgoingOperationValue.readMessagesContent.rawValue: - self = .readMessagesContent(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u")) + self = .readMessagesContent(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u")) case SecretChatOutgoingOperationValue.deleteMessages.rawValue: - self = .deleteMessages(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u")) + self = .deleteMessages(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u")) case SecretChatOutgoingOperationValue.screenshotMessages.rawValue: - self = .screenshotMessages(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u")) + self = .screenshotMessages(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u")) case SecretChatOutgoingOperationValue.clearHistory.rawValue: - self = .clearHistory(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i")) + self = .clearHistory(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0)) case SecretChatOutgoingOperationValue.resendOperations.rawValue: - self = .resendOperations(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), fromSeqNo: decoder.decodeInt32ForKey("f"), toSeqNo: decoder.decodeInt32ForKey("t")) + self = .resendOperations(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), fromSeqNo: decoder.decodeInt32ForKey("f", orElse: 0), toSeqNo: decoder.decodeInt32ForKey("t", orElse: 0)) case SecretChatOutgoingOperationValue.reportLayerSupport.rawValue: - self = .reportLayerSupport(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), layerSupport: decoder.decodeInt32ForKey("l")) + self = .reportLayerSupport(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), layerSupport: decoder.decodeInt32ForKey("l", orElse: 0)) case SecretChatOutgoingOperationValue.pfsRequestKey.rawValue: - self = .pfsRequestKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), rekeySessionId: decoder.decodeInt64ForKey("s"), a: decoder.decodeBytesForKey("a")!) + self = .pfsRequestKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), rekeySessionId: decoder.decodeInt64ForKey("s", orElse: 0), a: decoder.decodeBytesForKey("a")!) case SecretChatOutgoingOperationValue.pfsAcceptKey.rawValue: - self = .pfsAcceptKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), rekeySessionId: decoder.decodeInt64ForKey("s"), gA: decoder.decodeBytesForKey("g")!, b: decoder.decodeBytesForKey("b")!) + self = .pfsAcceptKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), rekeySessionId: decoder.decodeInt64ForKey("s", orElse: 0), gA: decoder.decodeBytesForKey("g")!, b: decoder.decodeBytesForKey("b")!) case SecretChatOutgoingOperationValue.pfsAbortSession.rawValue: - self = .pfsAbortSession(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), rekeySessionId: decoder.decodeInt64ForKey("s")) + self = .pfsAbortSession(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), rekeySessionId: decoder.decodeInt64ForKey("s", orElse: 0)) case SecretChatOutgoingOperationValue.pfsCommitKey.rawValue: - self = .pfsCommitKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), rekeySessionId: decoder.decodeInt64ForKey("s"), keyFingerprint: decoder.decodeInt64ForKey("f")) + self = .pfsCommitKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), rekeySessionId: decoder.decodeInt64ForKey("s", orElse: 0), keyFingerprint: decoder.decodeInt64ForKey("f", orElse: 0)) case SecretChatOutgoingOperationValue.noop.rawValue: - self = .noop(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i")) + self = .noop(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0)) case SecretChatOutgoingOperationValue.setMessageAutoremoveTimeout.rawValue: - self = .setMessageAutoremoveTimeout(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i"), timeout: decoder.decodeInt32ForKey("t"), messageId: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p")), namespace: decoder.decodeInt32ForKey("m.n"), id: decoder.decodeInt32ForKey("m.i"))) + self = .setMessageAutoremoveTimeout(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), timeout: decoder.decodeInt32ForKey("t", orElse: 0), messageId: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0))) case SecretChatOutgoingOperationValue.terminate.rawValue: self = .terminate default: - self = .noop(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l"))!, actionGloballyUniqueId: 0) + self = .noop(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: 0) assertionFailure() } } @@ -256,8 +256,8 @@ final class SecretChatOutgoingOperation: Coding { init(decoder: Decoder) { self.contents = decoder.decodeObjectForKey("c", decoder: { SecretChatOutgoingOperationContents(decoder: $0) }) as! SecretChatOutgoingOperationContents - self.mutable = (decoder.decodeInt32ForKey("m") as Int32) != 0 - self.delivered = (decoder.decodeInt32ForKey("d") as Int32) != 0 + self.mutable = decoder.decodeInt32ForKey("m", orElse: 0) != 0 + self.delivered = decoder.decodeInt32ForKey("d", orElse: 0) != 0 } func encode(_ encoder: Encoder) { diff --git a/TelegramCore/SecretChatState.swift b/TelegramCore/SecretChatState.swift index 69b2216c9e..a81478d4fe 100644 --- a/TelegramCore/SecretChatState.swift +++ b/TelegramCore/SecretChatState.swift @@ -44,9 +44,9 @@ public struct SecretChatKeySha1Fingerprint: Coding, Equatable { } public init(decoder: Decoder) { - self.k0 = decoder.decodeInt64ForKey("k0") - self.k1 = decoder.decodeInt64ForKey("k1") - self.k2 = decoder.decodeInt32ForKey("k2") + self.k0 = decoder.decodeInt64ForKey("k0", orElse: 0) + self.k1 = decoder.decodeInt64ForKey("k1", orElse: 0) + self.k2 = decoder.decodeInt32ForKey("k2", orElse: 0) } public func encode(_ encoder: Encoder) { @@ -114,10 +114,10 @@ public struct SecretChatKeySha256Fingerprint: Coding, Equatable { } public init(decoder: Decoder) { - self.k0 = decoder.decodeInt64ForKey("k0") - self.k1 = decoder.decodeInt64ForKey("k1") - self.k2 = decoder.decodeInt64ForKey("k2") - self.k3 = decoder.decodeInt64ForKey("k3") + self.k0 = decoder.decodeInt64ForKey("k0", orElse: 0) + self.k1 = decoder.decodeInt64ForKey("k1", orElse: 0) + self.k2 = decoder.decodeInt64ForKey("k2", orElse: 0) + self.k3 = decoder.decodeInt64ForKey("k3", orElse: 0) } public func encode(_ encoder: Encoder) { @@ -198,11 +198,11 @@ enum SecretChatHandshakeState: Coding, Equatable { case requested(g: Int32, p: MemoryBuffer, a: MemoryBuffer) init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case 0: self = .accepting case 1: - self = .requested(g: decoder.decodeInt32ForKey("g"), p: decoder.decodeBytesForKey("p")!, a: decoder.decodeBytesForKey("a")!) + self = .requested(g: decoder.decodeInt32ForKey("g", orElse: 0), p: decoder.decodeBytesForKey("p")!, a: decoder.decodeBytesForKey("a")!) default: self = .accepting assertionFailure() @@ -251,9 +251,9 @@ struct SecretChatLayerNegotiationState: Coding, Equatable { } init(decoder: Decoder) { - self.activeLayer = decoder.decodeInt32ForKey("a") - self.locallyRequestedLayer = decoder.decodeInt32ForKey("lr") - self.remotelyRequestedLayer = decoder.decodeInt32ForKey("rr") + self.activeLayer = decoder.decodeInt32ForKey("a", orElse: 0) + self.locallyRequestedLayer = decoder.decodeOptionalInt32ForKey("lr") + self.remotelyRequestedLayer = decoder.decodeOptionalInt32ForKey("rr") } func encode(_ encoder: Encoder) { @@ -302,7 +302,7 @@ enum SecretChatRekeySessionData: Coding, Equatable { case accepted(key: MemoryBuffer, keyFingerprint: Int64) init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case SecretChatRekeySessionDataValue.requesting.rawValue: self = .requesting case SecretChatRekeySessionDataValue.requested.rawValue: @@ -310,7 +310,7 @@ enum SecretChatRekeySessionData: Coding, Equatable { case SecretChatRekeySessionDataValue.accepting.rawValue: self = .accepting case SecretChatRekeySessionDataValue.accepted.rawValue: - self = .accepted(key: decoder.decodeBytesForKey("k")!, keyFingerprint: decoder.decodeInt64ForKey("f")) + self = .accepted(key: decoder.decodeBytesForKey("k")!, keyFingerprint: decoder.decodeInt64ForKey("f", orElse: 0)) default: preconditionFailure() } @@ -373,7 +373,7 @@ struct SecretChatRekeySessionState: Coding, Equatable { } init(decoder: Decoder) { - self.id = decoder.decodeInt64ForKey("i") + self.id = decoder.decodeInt64ForKey("i", orElse: 0) self.data = decoder.decodeObjectForKey("d", decoder: { SecretChatRekeySessionData(decoder: $0) }) as! SecretChatRekeySessionData } @@ -411,9 +411,9 @@ struct SecretChatSequenceBasedLayerState: Coding, Equatable { init(decoder: Decoder) { self.layerNegotiationState = decoder.decodeObjectForKey("ln", decoder: { SecretChatLayerNegotiationState(decoder: $0) }) as! SecretChatLayerNegotiationState self.rekeyState = decoder.decodeObjectForKey("rs", decoder: { SecretChatRekeySessionState(decoder: $0) }) as? SecretChatRekeySessionState - self.baseIncomingOperationIndex = decoder.decodeInt32ForKey("bi") - self.baseOutgoingOperationIndex = decoder.decodeInt32ForKey("bo") - if let topProcessedCanonicalIncomingOperationIndex = decoder.decodeInt32ForKey("pi") as Int32? { + self.baseIncomingOperationIndex = decoder.decodeInt32ForKey("bi", orElse: 0) + self.baseOutgoingOperationIndex = decoder.decodeInt32ForKey("bo", orElse: 0) + if let topProcessedCanonicalIncomingOperationIndex = decoder.decodeOptionalInt32ForKey("pi") { self.topProcessedCanonicalIncomingOperationIndex = topProcessedCanonicalIncomingOperationIndex } else { self.topProcessedCanonicalIncomingOperationIndex = nil @@ -495,7 +495,7 @@ enum SecretChatEmbeddedState: Coding, Equatable { } init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case SecretChatEmbeddedStateValue.terminated.rawValue: self = .terminated case SecretChatEmbeddedStateValue.handshake.rawValue: @@ -575,11 +575,11 @@ final class SecretChatState: PeerChatState, SecretChatKeyState, Equatable { } init(decoder: Decoder) { - self.role = SecretChatRole(rawValue: decoder.decodeInt32ForKey("r"))! + self.role = SecretChatRole(rawValue: decoder.decodeInt32ForKey("r", orElse: 0))! self.embeddedState = decoder.decodeObjectForKey("s", decoder: { return SecretChatEmbeddedState(decoder: $0) }) as! SecretChatEmbeddedState self.keychain = decoder.decodeObjectForKey("k", decoder: { return SecretChatKeychain(decoder: $0) }) as! SecretChatKeychain self.keyFingerprint = decoder.decodeObjectForKey("f", decoder: { return SecretChatKeyFingerprint(decoder: $0) }) as? SecretChatKeyFingerprint - self.messageAutoremoveTimeout = decoder.decodeInt32ForKey("a") + self.messageAutoremoveTimeout = decoder.decodeOptionalInt32ForKey("a") } func encode(_ encoder: Encoder) { diff --git a/TelegramCore/Serialization.swift b/TelegramCore/Serialization.swift index d968057ef2..d8c011b4fc 100644 --- a/TelegramCore/Serialization.swift +++ b/TelegramCore/Serialization.swift @@ -20,7 +20,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 66 + return 67 } public func parseMessage(_ data: Data!) -> Any! { @@ -57,7 +57,7 @@ public class Serialization: NSObject, MTSerialization { if let config = parse(Buffer(data: response)) { switch config { //config flags:# date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int phonecalls_enabled:flags.1?true disabled_features:Vector = Config; - case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): var addressList = [MTDatacenterAddress]() for option in dcOptions { switch option { diff --git a/TelegramCore/StickerPack.swift b/TelegramCore/StickerPack.swift index 9b60f99042..8106483f37 100644 --- a/TelegramCore/StickerPack.swift +++ b/TelegramCore/StickerPack.swift @@ -55,13 +55,13 @@ public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable { } public init(decoder: Decoder) { - self.id = ItemCollectionId(namespace: decoder.decodeInt32ForKey("i.n"), id: decoder.decodeInt64ForKey("i.i")) - self.accessHash = decoder.decodeInt64ForKey("a") - self.title = decoder.decodeStringForKey("t") - self.shortName = decoder.decodeStringForKey("s") - self.hash = decoder.decodeInt32ForKey("h") - self.flags = StickerPackCollectionInfoFlags(rawValue: decoder.decodeInt32ForKey("f")) - self.count = decoder.decodeInt32ForKey("n") + self.id = ItemCollectionId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)) + self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) + self.title = decoder.decodeStringForKey("t", orElse: "") + self.shortName = decoder.decodeStringForKey("s", orElse: "") + self.hash = decoder.decodeInt32ForKey("h", orElse: 0) + self.flags = StickerPackCollectionInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.count = decoder.decodeInt32ForKey("n", orElse: 0) } public func encode(_ encoder: Encoder) { @@ -116,7 +116,7 @@ public final class StickerPackItem: ItemCollectionItem, Equatable { } public init(decoder: Decoder) { - self.index = ItemCollectionItemIndex(index: decoder.decodeInt32ForKey("i.n"), id: decoder.decodeInt64ForKey("i.i")) + self.index = ItemCollectionItemIndex(index: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)) self.file = decoder.decodeObjectForKey("f") as! TelegramMediaFile self.indexKeys = decoder.decodeBytesArrayForKey("s") } diff --git a/TelegramCore/StoreMessage_Telegram.swift b/TelegramCore/StoreMessage_Telegram.swift index d0913b7dfb..8ffbdf1964 100644 --- a/TelegramCore/StoreMessage_Telegram.swift +++ b/TelegramCore/StoreMessage_Telegram.swift @@ -5,13 +5,14 @@ import Foundation import Postbox #endif -public func tagsForStoreMessage(media: [Media], textEntities: [MessageTextEntity]?) -> MessageTags { +public func tagsForStoreMessage(incoming: Bool, media: [Media], textEntities: [MessageTextEntity]?) -> (MessageTags, GlobalMessageTags) { var tags = MessageTags() + var globalTags = GlobalMessageTags() for attachment in media { if let _ = attachment as? TelegramMediaImage { tags.insert(.PhotoOrVideo) } else if let file = attachment as? TelegramMediaFile { - var refinedTag: MessageTags? + var refinedTag: MessageTags? = .File inner: for attribute in file.attributes { switch attribute { case let .Video(_, _, flags): @@ -28,17 +29,28 @@ public func tagsForStoreMessage(media: [Media], textEntities: [MessageTextEntity refinedTag = .Music } break inner + case .Sticker: + refinedTag = nil + break inner default: break } } if let refinedTag = refinedTag { tags.insert(refinedTag) - } else { - tags.insert(.File) } } else if let webpage = attachment as? TelegramMediaWebpage, case .Loaded = webpage.content { tags.insert(.WebPage) + } else if let action = attachment as? TelegramMediaAction { + switch action.action { + case let .phoneCall(_, discardReason, _): + globalTags.insert(.Calls) + if incoming, let discardReason = discardReason, case .missed = discardReason { + globalTags.insert(.MissedCalls) + } + default: + break + } } } if let textEntities = textEntities, !textEntities.isEmpty && !tags.contains(.WebPage) { @@ -51,11 +63,7 @@ public func tagsForStoreMessage(media: [Media], textEntities: [MessageTextEntity } } } - return tags -} - -public func globalTagsForStoreMessage(media: [Media]) -> GlobalMessageTags { - return [] + return (tags, globalTags) } extension Api.Message { @@ -425,7 +433,9 @@ extension StoreMessage { storeFlags.insert(.Personal) } - self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), globallyUniqueId: nil, timestamp: date, flags: storeFlags, tags: tagsForStoreMessage(media: medias, textEntities: entitiesAttribute?.entities), globalTags: globalTagsForStoreMessage(media: medias), forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: medias) + let (tags, globalTags) = tagsForStoreMessage(incoming: storeFlags.contains(.Incoming), media: medias, textEntities: entitiesAttribute?.entities) + + self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), globallyUniqueId: nil, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: medias) case .messageEmpty: return nil case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action): @@ -474,7 +484,9 @@ extension StoreMessage { media.append(action) } - self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), globallyUniqueId: nil, timestamp: date, flags: storeFlags, tags: [], globalTags: globalTagsForStoreMessage(media: media), forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media) + let (tags, globalTags) = tagsForStoreMessage(incoming: storeFlags.contains(.Incoming), media: media, textEntities: nil) + + self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), globallyUniqueId: nil, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media) } } } diff --git a/TelegramCore/SuggestedLocalizationEntry.swift b/TelegramCore/SuggestedLocalizationEntry.swift new file mode 100644 index 0000000000..8e240ae892 --- /dev/null +++ b/TelegramCore/SuggestedLocalizationEntry.swift @@ -0,0 +1,51 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public final class SuggestedLocalizationEntry: PreferencesEntry { + public let languageCode: String + public let isSeen: Bool + + init(languageCode: String, isSeen: Bool) { + self.languageCode = languageCode + self.isSeen = isSeen + } + + public init(decoder: Decoder) { + self.languageCode = decoder.decodeStringForKey("lc", orElse: "en") + self.isSeen = decoder.decodeInt32ForKey("s", orElse: 0) != 0 + } + + public func encode(_ encoder: Encoder) { + encoder.encodeString(self.languageCode, forKey: "lc") + encoder.encodeInt32(self.isSeen ? 1 : 0, forKey: "s") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? SuggestedLocalizationEntry { + return self == to + } else { + return false + } + } + + public static func ==(lhs: SuggestedLocalizationEntry, rhs: SuggestedLocalizationEntry) -> Bool { + return lhs.languageCode == rhs.languageCode && lhs.isSeen == rhs.isSeen + } +} + +public func markSuggestedLocalizationAsSeenInteractively(postbox: Postbox, languageCode: String) -> Signal { + return postbox.modify { modifier -> Void in + modifier.updatePreferencesEntry(key: PreferencesKeys.suggestedLocalization, { current in + if let current = current as? SuggestedLocalizationEntry, current.languageCode == languageCode, !current.isSeen { + return SuggestedLocalizationEntry(languageCode: languageCode, isSeen: true) + } + return current + }) + } +} diff --git a/TelegramCore/SynchronizeSavedGifsOperation.swift b/TelegramCore/SynchronizeSavedGifsOperation.swift index 8b7ff454a2..e0702b43f0 100644 --- a/TelegramCore/SynchronizeSavedGifsOperation.swift +++ b/TelegramCore/SynchronizeSavedGifsOperation.swift @@ -19,11 +19,11 @@ enum SynchronizeSavedGifsOperationContent: Coding { case sync init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case SynchronizeSavedGifsOperationContentType.add.rawValue: - self = .add(id: decoder.decodeInt64ForKey("i"), accessHash: decoder.decodeInt64ForKey("h")) + self = .add(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) case SynchronizeSavedGifsOperationContentType.remove.rawValue: - self = .remove(id: decoder.decodeInt64ForKey("i"), accessHash: decoder.decodeInt64ForKey("h")) + self = .remove(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) case SynchronizeSavedGifsOperationContentType.sync.rawValue: self = .sync default: diff --git a/TelegramCore/SynchronizeableChatInputState.swift b/TelegramCore/SynchronizeableChatInputState.swift index ca72e8ee0d..d4158133c9 100644 --- a/TelegramCore/SynchronizeableChatInputState.swift +++ b/TelegramCore/SynchronizeableChatInputState.swift @@ -17,9 +17,9 @@ public struct SynchronizeableChatInputState: Coding, Equatable { } public init(decoder: Decoder) { - self.text = decoder.decodeStringForKey("t") - self.timestamp = decoder.decodeInt32ForKey("s") - if let messageIdPeerId = (decoder.decodeInt64ForKey("m.p") as Int64?), let messageIdNamespace = (decoder.decodeInt32ForKey("m.n") as Int32?), let messageIdId = (decoder.decodeInt32ForKey("m.i") as Int32?) { + self.text = decoder.decodeStringForKey("t", orElse: "") + self.timestamp = decoder.decodeInt32ForKey("s", orElse: 0) + if let messageIdPeerId = decoder.decodeOptionalInt64ForKey("m.p"), let messageIdNamespace = decoder.decodeOptionalInt32ForKey("m.n"), let messageIdId = decoder.decodeOptionalInt32ForKey("m.i") { self.replyToMessageId = MessageId(peerId: PeerId(messageIdPeerId), namespace: messageIdNamespace, id: messageIdId) } else { self.replyToMessageId = nil diff --git a/TelegramCore/TelegramChannel.swift b/TelegramCore/TelegramChannel.swift index 1167e63677..b2e9fc34d5 100644 --- a/TelegramCore/TelegramChannel.swift +++ b/TelegramCore/TelegramChannel.swift @@ -149,11 +149,11 @@ public enum TelegramChannelInfo: Equatable { } fileprivate static func decode(decoder: Decoder) -> TelegramChannelInfo { - let type: Int32 = decoder.decodeInt32ForKey("i.t") + let type: Int32 = decoder.decodeInt32ForKey("i.t", orElse: 0) if type == 0 { - return .broadcast(TelegramChannelBroadcastInfo(flags: TelegramChannelBroadcastFlags(rawValue: decoder.decodeInt32ForKey("i.f")))) + return .broadcast(TelegramChannelBroadcastInfo(flags: TelegramChannelBroadcastFlags(rawValue: decoder.decodeInt32ForKey("i.f", orElse: 0)))) } else { - return .group(TelegramChannelGroupInfo(flags: TelegramChannelGroupFlags(rawValue: decoder.decodeInt32ForKey("i.f")))) + return .group(TelegramChannelGroupInfo(flags: TelegramChannelGroupFlags(rawValue: decoder.decodeInt32ForKey("i.f", orElse: 0)))) } } } @@ -209,17 +209,17 @@ public final class TelegramChannel: Peer { } public init(decoder: Decoder) { - self.id = PeerId(decoder.decodeInt64ForKey("i")) - self.accessHash = decoder.decodeInt64ForKey("ah") - self.title = decoder.decodeStringForKey("t") - self.username = decoder.decodeStringForKey("un") + self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) + self.accessHash = decoder.decodeOptionalInt64ForKey("ah") + self.title = decoder.decodeStringForKey("t", orElse: "") + self.username = decoder.decodeOptionalStringForKey("un") self.photo = decoder.decodeObjectArrayForKey("ph") - self.creationDate = decoder.decodeInt32ForKey("d") - self.version = decoder.decodeInt32ForKey("v") - self.participationStatus = TelegramChannelParticipationStatus(rawValue: decoder.decodeInt32ForKey("ps")) - self.role = TelegramChannelRole(rawValue: decoder.decodeInt32ForKey("ro")) + self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0) + self.version = decoder.decodeInt32ForKey("v", orElse: 0) + self.participationStatus = TelegramChannelParticipationStatus(rawValue: decoder.decodeInt32ForKey("ps", orElse: 0)) + self.role = TelegramChannelRole(rawValue: decoder.decodeInt32ForKey("ro", orElse: 0)) self.info = TelegramChannelInfo.decode(decoder: decoder) - self.flags = TelegramChannelFlags(rawValue: decoder.decodeInt32ForKey("fl")) + self.flags = TelegramChannelFlags(rawValue: decoder.decodeInt32ForKey("fl", orElse: 0)) self.restrictionInfo = decoder.decodeObjectForKey("ri") as? PeerAccessRestrictionInfo } diff --git a/TelegramCore/TelegramGroup.swift b/TelegramCore/TelegramGroup.swift index 84e61e9f47..f102201ef8 100644 --- a/TelegramCore/TelegramGroup.swift +++ b/TelegramCore/TelegramGroup.swift @@ -74,22 +74,22 @@ public final class TelegramGroup: Peer { } public init(decoder: Decoder) { - self.id = PeerId(decoder.decodeInt64ForKey("i")) - self.title = decoder.decodeStringForKey("t") + self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) + self.title = decoder.decodeStringForKey("t", orElse: "") self.photo = decoder.decodeObjectArrayForKey("ph") - self.participantCount = Int(decoder.decodeInt32ForKey("pc")) - self.role = TelegramGroupRole(rawValue: decoder.decodeInt32ForKey("r"))! - self.membership = TelegramGroupMembership(rawValue: decoder.decodeInt32ForKey("m"))! - self.flags = TelegramGroupFlags(rawValue: decoder.decodeInt32ForKey("f")) - let migrationPeerId: Int64? = decoder.decodeInt64ForKey("mr.i") - let migrationAccessHash: Int64? = decoder.decodeInt64ForKey("mr.a") + self.participantCount = Int(decoder.decodeInt32ForKey("pc", orElse: 0)) + self.role = TelegramGroupRole(rawValue: decoder.decodeInt32ForKey("r", orElse: 0))! + self.membership = TelegramGroupMembership(rawValue: decoder.decodeInt32ForKey("m", orElse: 0))! + self.flags = TelegramGroupFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + let migrationPeerId: Int64? = decoder.decodeOptionalInt64ForKey("mr.i") + let migrationAccessHash: Int64? = decoder.decodeOptionalInt64ForKey("mr.a") if let migrationPeerId = migrationPeerId, let migrationAccessHash = migrationAccessHash { self.migrationReference = TelegramGroupToChannelMigrationReference(peerId: PeerId(migrationPeerId), accessHash: migrationAccessHash) } else { self.migrationReference = nil } - self.creationDate = decoder.decodeInt32ForKey("d") - self.version = Int(decoder.decodeInt32ForKey("v")) + self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0) + self.version = Int(decoder.decodeInt32ForKey("v", orElse: 0)) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/TelegramMediaAction.swift b/TelegramCore/TelegramMediaAction.swift index 8fb863079b..a0734c7456 100644 --- a/TelegramCore/TelegramMediaAction.swift +++ b/TelegramCore/TelegramMediaAction.swift @@ -30,10 +30,10 @@ public enum TelegramMediaActionType: Coding, Equatable { case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?) public init(decoder: Decoder) { - let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue") + let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) switch rawValue { case 1: - self = .groupCreated(title: decoder.decodeStringForKey("title")) + self = .groupCreated(title: decoder.decodeStringForKey("title", orElse: "")) case 2: self = .addedMembers(peerIds: PeerId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("peerIds")!)) case 3: @@ -41,29 +41,29 @@ public enum TelegramMediaActionType: Coding, Equatable { case 4: self = .photoUpdated(image: decoder.decodeObjectForKey("image") as? TelegramMediaImage) case 5: - self = .titleUpdated(title: decoder.decodeStringForKey("title")) + self = .titleUpdated(title: decoder.decodeStringForKey("title", orElse: "")) case 6: self = .pinnedMessageUpdated case 7: - self = .joinedByLink(inviter: PeerId(decoder.decodeInt64ForKey("inviter"))) + self = .joinedByLink(inviter: PeerId(decoder.decodeInt64ForKey("inviter", orElse: 0))) case 8: - self = .channelMigratedFromGroup(title: decoder.decodeStringForKey("title"), groupId: PeerId(decoder.decodeInt64ForKey("groupId"))) + self = .channelMigratedFromGroup(title: decoder.decodeStringForKey("title", orElse: ""), groupId: PeerId(decoder.decodeInt64ForKey("groupId", orElse: 0))) case 9: - self = .groupMigratedToChannel(channelId: PeerId(decoder.decodeInt64ForKey("channelId"))) + self = .groupMigratedToChannel(channelId: PeerId(decoder.decodeInt64ForKey("channelId", orElse: 0))) case 10: self = .historyCleared case 11: self = .historyScreenshot case 12: - self = .messageAutoremoveTimeoutUpdated(decoder.decodeInt32ForKey("t")) + self = .messageAutoremoveTimeoutUpdated(decoder.decodeInt32ForKey("t", orElse: 0)) case 13: - self = .gameScore(gameId: decoder.decodeInt64ForKey("i"), score: decoder.decodeInt32ForKey("s")) + self = .gameScore(gameId: decoder.decodeInt64ForKey("i", orElse: 0), score: decoder.decodeInt32ForKey("s", orElse: 0)) case 14: var discardReason: PhoneCallDiscardReason? - if let value = (decoder.decodeInt32ForKey("dr") as Int32?) { + if let value = decoder.decodeOptionalInt32ForKey("dr") { discardReason = PhoneCallDiscardReason(rawValue: value) } - self = .phoneCall(callId: decoder.decodeInt64ForKey("i"), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d")) + self = .phoneCall(callId: decoder.decodeInt64ForKey("i", orElse: 0), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d", orElse: 0)) default: self = .unknown } diff --git a/TelegramCore/TelegramMediaContact.swift b/TelegramCore/TelegramMediaContact.swift index 17810a3c8f..8e67220e0c 100644 --- a/TelegramCore/TelegramMediaContact.swift +++ b/TelegramCore/TelegramMediaContact.swift @@ -26,10 +26,10 @@ public final class TelegramMediaContact: Media { } public init(decoder: Decoder) { - self.firstName = decoder.decodeStringForKey("n.f") - self.lastName = decoder.decodeStringForKey("n.l") - self.phoneNumber = decoder.decodeStringForKey("pn") - if let peerIdValue: Int64 = decoder.decodeInt64ForKey("p") { + self.firstName = decoder.decodeStringForKey("n.f", orElse: "") + self.lastName = decoder.decodeStringForKey("n.l", orElse: "") + self.phoneNumber = decoder.decodeStringForKey("pn", orElse: "") + if let peerIdValue = decoder.decodeOptionalInt64ForKey("p") { self.peerId = PeerId(peerIdValue) self.peerIds = [PeerId(peerIdValue)] } else { diff --git a/TelegramCore/TelegramMediaFile.swift b/TelegramCore/TelegramMediaFile.swift index 85aa870ef3..3f4a8cf8c0 100644 --- a/TelegramCore/TelegramMediaFile.swift +++ b/TelegramCore/TelegramMediaFile.swift @@ -18,11 +18,11 @@ public enum StickerPackReference: Coding { case name(String) public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("r") as Int32 { + switch decoder.decodeInt32ForKey("r", orElse: 0) { case 0: - self = .id(id: decoder.decodeInt64ForKey("i"), accessHash: decoder.decodeInt64ForKey("h")) + self = .id(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) case 1: - self = .name(decoder.decodeStringForKey("n")) + self = .name(decoder.decodeStringForKey("n", orElse: "")) default: self = .name("") assertionFailure() @@ -66,25 +66,25 @@ public enum TelegramMediaFileAttribute: Coding { case HasLinkedStickers public init(decoder: Decoder) { - let type: Int32 = decoder.decodeInt32ForKey("t") + let type: Int32 = decoder.decodeInt32ForKey("t", orElse: 0) switch type { case typeFileName: - self = .FileName(fileName: decoder.decodeStringForKey("fn")) + self = .FileName(fileName: decoder.decodeStringForKey("fn", orElse: "")) case typeSticker: - self = .Sticker(displayText: decoder.decodeStringForKey("dt"), packReference: decoder.decodeObjectForKey("pr", decoder: { StickerPackReference(decoder: $0) }) as? StickerPackReference) + self = .Sticker(displayText: decoder.decodeStringForKey("dt", orElse: ""), packReference: decoder.decodeObjectForKey("pr", decoder: { StickerPackReference(decoder: $0) }) as? StickerPackReference) case typeImageSize: - self = .ImageSize(size: CGSize(width: CGFloat(decoder.decodeInt32ForKey("w")), height: CGFloat(decoder.decodeInt32ForKey("h")))) + self = .ImageSize(size: CGSize(width: CGFloat(decoder.decodeInt32ForKey("w", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("h", orElse: 0)))) case typeAnimated: self = .Animated case typeVideo: - self = .Video(duration: Int(decoder.decodeInt32ForKey("du")), size: CGSize(width: CGFloat(decoder.decodeInt32ForKey("w")), height: CGFloat(decoder.decodeInt32ForKey("h"))), flags: TelegramMediaVideoFlags(rawValue: decoder.decodeInt32ForKey("f"))) + self = .Video(duration: Int(decoder.decodeInt32ForKey("du", orElse: 0)), size: CGSize(width: CGFloat(decoder.decodeInt32ForKey("w", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("h", orElse: 0))), flags: TelegramMediaVideoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0))) case typeAudio: let waveformBuffer = decoder.decodeBytesForKeyNoCopy("wf") var waveform: MemoryBuffer? if let waveformBuffer = waveformBuffer { waveform = MemoryBuffer(copyOf: waveformBuffer) } - self = .Audio(isVoice: decoder.decodeInt32ForKey("iv") != 0, duration: Int(decoder.decodeInt32ForKey("du")), title: decoder.decodeStringForKey("ti"), performer: decoder.decodeStringForKey("pe"), waveform: waveform) + self = .Audio(isVoice: decoder.decodeInt32ForKey("iv", orElse: 0) != 0, duration: Int(decoder.decodeInt32ForKey("du", orElse: 0)), title: decoder.decodeOptionalStringForKey("ti"), performer: decoder.decodeOptionalStringForKey("pe"), waveform: waveform) case typeHasLinkedStickers: self = .HasLinkedStickers default: @@ -162,8 +162,8 @@ public final class TelegramMediaFile: Media, Equatable { self.fileId = MediaId(decoder.decodeBytesForKeyNoCopy("i")!) self.resource = decoder.decodeObjectForKey("r") as! TelegramMediaResource self.previewRepresentations = decoder.decodeObjectArrayForKey("pr") - self.mimeType = decoder.decodeStringForKey("mt") - if let size = (decoder.decodeInt32ForKey("s") as Int32?) { + self.mimeType = decoder.decodeStringForKey("mt", orElse: "") + if let size = decoder.decodeOptionalInt32ForKey("s") { self.size = Int(size) } else { self.size = nil diff --git a/TelegramCore/TelegramMediaGame.swift b/TelegramCore/TelegramMediaGame.swift index 3e2cb05409..d8f17ce5da 100644 --- a/TelegramCore/TelegramMediaGame.swift +++ b/TelegramCore/TelegramMediaGame.swift @@ -30,11 +30,11 @@ public final class TelegramMediaGame: Media { } public init(decoder: Decoder) { - self.gameId = decoder.decodeInt64ForKey("i") - self.accessHash = decoder.decodeInt64ForKey("h") - self.name = decoder.decodeStringForKey("n") - self.title = decoder.decodeStringForKey("t") - self.description = decoder.decodeStringForKey("d") + self.gameId = decoder.decodeInt64ForKey("i", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("h", orElse: 0) + self.name = decoder.decodeStringForKey("n", orElse: "") + self.title = decoder.decodeStringForKey("t", orElse: "") + self.description = decoder.decodeStringForKey("d", orElse: "") self.image = decoder.decodeObjectForKey("p") as? TelegramMediaImage self.file = decoder.decodeObjectForKey("f") as? TelegramMediaFile } diff --git a/TelegramCore/TelegramMediaImage.swift b/TelegramCore/TelegramMediaImage.swift index 31bd5eab2a..3c210824f2 100644 --- a/TelegramCore/TelegramMediaImage.swift +++ b/TelegramCore/TelegramMediaImage.swift @@ -90,7 +90,7 @@ public final class TelegramMediaImageRepresentation: Coding, Equatable, CustomSt } public init(decoder: Decoder) { - self.dimensions = CGSize(width: CGFloat(decoder.decodeInt32ForKey("dx")), height: CGFloat(decoder.decodeInt32ForKey("dy"))) + self.dimensions = CGSize(width: CGFloat(decoder.decodeInt32ForKey("dx", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("dy", orElse: 0))) self.resource = decoder.decodeObjectForKey("r") as! TelegramMediaResource } diff --git a/TelegramCore/TelegramMediaMap.swift b/TelegramCore/TelegramMediaMap.swift index 6cc89ff781..80e0c80b3b 100644 --- a/TelegramCore/TelegramMediaMap.swift +++ b/TelegramCore/TelegramMediaMap.swift @@ -21,11 +21,11 @@ public final class NamedGeoPlace: Coding { } public init(decoder: Decoder) { - self.country = decoder.decodeStringForKey("gp_co") - self.state = decoder.decodeStringForKey("gp_sta") - self.city = decoder.decodeStringForKey("gp_ci") - self.district = decoder.decodeStringForKey("gp_dis") - self.street = decoder.decodeStringForKey("gp_str") + self.country = decoder.decodeOptionalStringForKey("gp_co") + self.state = decoder.decodeOptionalStringForKey("gp_sta") + self.city = decoder.decodeOptionalStringForKey("gp_ci") + self.district = decoder.decodeOptionalStringForKey("gp_dis") + self.street = decoder.decodeOptionalStringForKey("gp_str") } public func encode(_ encoder: Encoder) { @@ -65,10 +65,10 @@ public final class MapVenue: Coding { } public init(decoder: Decoder) { - self.title = decoder.decodeStringForKey("ti") - self.address = decoder.decodeStringForKey("ad") - self.provider = decoder.decodeStringForKey("pr") - self.id = decoder.decodeStringForKey("id") + self.title = decoder.decodeStringForKey("ti", orElse: "") + self.address = decoder.decodeOptionalStringForKey("ad") + self.provider = decoder.decodeOptionalStringForKey("pr") + self.id = decoder.decodeOptionalStringForKey("id") } public func encode(_ encoder: Encoder) { @@ -103,8 +103,8 @@ public final class TelegramMediaMap: Media { } public init(decoder: Decoder) { - self.latitude = decoder.decodeDoubleForKey("la") - self.longitude = decoder.decodeDoubleForKey("lo") + self.latitude = decoder.decodeDoubleForKey("la", orElse: 0.0) + self.longitude = decoder.decodeDoubleForKey("lo", orElse: 0.0) self.geoPlace = decoder.decodeObjectForKey("gp", decoder: { NamedGeoPlace(decoder: $0) }) as? NamedGeoPlace self.venue = decoder.decodeObjectForKey("ve", decoder: { MapVenue(decoder: $0) }) as? MapVenue } diff --git a/TelegramCore/TelegramMediaWebpage.swift b/TelegramCore/TelegramMediaWebpage.swift index 682e0394c5..2111abd566 100644 --- a/TelegramCore/TelegramMediaWebpage.swift +++ b/TelegramCore/TelegramMediaWebpage.swift @@ -40,25 +40,25 @@ public final class TelegramMediaWebpageLoadedContent: Coding, Equatable { } public init(decoder: Decoder) { - self.url = decoder.decodeStringForKey("u") - self.displayUrl = decoder.decodeStringForKey("d") - self.type = decoder.decodeStringForKey("ty") - self.websiteName = decoder.decodeStringForKey("ws") - self.title = decoder.decodeStringForKey("ti") - self.text = decoder.decodeStringForKey("tx") - self.embedUrl = decoder.decodeStringForKey("eu") - self.embedType = decoder.decodeStringForKey("et") - if let embedSizeWidth: Int32 = decoder.decodeInt32ForKey("esw"), let embedSizeHeight: Int32 = decoder.decodeInt32ForKey("esh") { + self.url = decoder.decodeStringForKey("u", orElse: "") + self.displayUrl = decoder.decodeStringForKey("d", orElse: "") + self.type = decoder.decodeOptionalStringForKey("ty") + self.websiteName = decoder.decodeOptionalStringForKey("ws") + self.title = decoder.decodeOptionalStringForKey("ti") + self.text = decoder.decodeOptionalStringForKey("tx") + self.embedUrl = decoder.decodeOptionalStringForKey("eu") + self.embedType = decoder.decodeOptionalStringForKey("et") + if let embedSizeWidth = decoder.decodeOptionalInt32ForKey("esw"), let embedSizeHeight = decoder.decodeOptionalInt32ForKey("esh") { self.embedSize = CGSize(width: CGFloat(embedSizeWidth), height: CGFloat(embedSizeHeight)) } else { self.embedSize = nil } - if let duration: Int32 = decoder.decodeInt32ForKey("du") { + if let duration = decoder.decodeOptionalInt32ForKey("du") { self.duration = Int(duration) } else { self.duration = nil } - self.author = decoder.decodeStringForKey("au") + self.author = decoder.decodeOptionalStringForKey("au") if let image = decoder.decodeObjectForKey("im") as? TelegramMediaImage { self.image = image @@ -207,8 +207,8 @@ public final class TelegramMediaWebpage: Media, Equatable { public init(decoder: Decoder) { self.webpageId = MediaId(decoder.decodeBytesForKeyNoCopy("i")!) - if decoder.decodeInt32ForKey("ct") == 0 { - self.content = .Pending(decoder.decodeInt32ForKey("pendingDate")) + if decoder.decodeInt32ForKey("ct", orElse: 0) == 0 { + self.content = .Pending(decoder.decodeInt32ForKey("pendingDate", orElse: 0)) } else { self.content = .Loaded(TelegramMediaWebpageLoadedContent(decoder: decoder)) } diff --git a/TelegramCore/TelegramPeerNotificationSettings.swift b/TelegramCore/TelegramPeerNotificationSettings.swift index 487b130a73..fbce403022 100644 --- a/TelegramCore/TelegramPeerNotificationSettings.swift +++ b/TelegramCore/TelegramPeerNotificationSettings.swift @@ -10,11 +10,11 @@ public enum PeerMuteState: Equatable { case muted(until: Int32) fileprivate static func decodeInline(_ decoder: Decoder) -> PeerMuteState { - switch decoder.decodeInt32ForKey("m.v") as Int32 { + switch decoder.decodeInt32ForKey("m.v", orElse: 0) { case 0: return .unmuted case 1: - return .muted(until: decoder.decodeInt32ForKey("m.u")) + return .muted(until: decoder.decodeInt32ForKey("m.u", orElse: 0)) default: return .unmuted } @@ -62,13 +62,13 @@ public enum PeerMessageSound: Equatable { case bundledClassic(id: Int32) static func decodeInline(_ decoder: Decoder) -> PeerMessageSound { - switch decoder.decodeInt32ForKey("s.v") as Int32 { + switch decoder.decodeInt32ForKey("s.v", orElse: 0) { case PeerMessageSoundValue.none.rawValue: return .none case PeerMessageSoundValue.bundledModern.rawValue: - return .bundledModern(id: decoder.decodeInt32ForKey("s.i")) + return .bundledModern(id: decoder.decodeInt32ForKey("s.i", orElse: 0)) case PeerMessageSoundValue.bundledClassic.rawValue: - return .bundledClassic(id: decoder.decodeInt32ForKey("s.i")) + return .bundledClassic(id: decoder.decodeInt32ForKey("s.i", orElse: 0)) default: assertionFailure() return .bundledModern(id: 0) diff --git a/TelegramCore/TelegramSecretChat.swift b/TelegramCore/TelegramSecretChat.swift index 7419978953..2abed5fd3d 100644 --- a/TelegramCore/TelegramSecretChat.swift +++ b/TelegramCore/TelegramSecretChat.swift @@ -34,15 +34,15 @@ public final class TelegramSecretChat: Peer { } public init(decoder: Decoder) { - self.id = PeerId(decoder.decodeInt64ForKey("i")) - self.regularPeerId = PeerId(decoder.decodeInt64ForKey("r")) + self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) + self.regularPeerId = PeerId(decoder.decodeInt64ForKey("r", orElse: 0)) self.notificationSettingsPeerId = self.regularPeerId - self.accessHash = decoder.decodeInt64ForKey("h") - self.creationDate = decoder.decodeInt32ForKey("d") - self.role = SecretChatRole(rawValue: decoder.decodeInt32ForKey("o"))! - self.embeddedState = SecretChatEmbeddedPeerState(rawValue: decoder.decodeInt32ForKey("s"))! + self.accessHash = decoder.decodeInt64ForKey("h", orElse: 0) + self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0) + self.role = SecretChatRole(rawValue: decoder.decodeInt32ForKey("o", orElse: 0))! + self.embeddedState = SecretChatEmbeddedPeerState(rawValue: decoder.decodeInt32ForKey("s", orElse: 0))! self.associatedPeerIds = [self.regularPeerId] - self.messageAutoremoveTimeout = decoder.decodeInt32ForKey("at") + self.messageAutoremoveTimeout = decoder.decodeOptionalInt32ForKey("at") } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/TelegramUser.swift b/TelegramCore/TelegramUser.swift index f26c931eab..d97ab17f51 100644 --- a/TelegramCore/TelegramUser.swift +++ b/TelegramCore/TelegramUser.swift @@ -45,8 +45,8 @@ public struct BotUserInfo: Coding, Equatable { } public init(decoder: Decoder) { - self.flags = BotUserInfoFlags(rawValue: decoder.decodeInt32ForKey("f")) - self.inlinePlaceholder = decoder.decodeStringForKey("ip") + self.flags = BotUserInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.inlinePlaceholder = decoder.decodeOptionalStringForKey("ip") } public func encode(_ encoder: Encoder) { @@ -108,20 +108,20 @@ public final class TelegramUser: Peer { } public init(decoder: Decoder) { - self.id = PeerId(decoder.decodeInt64ForKey("i")) + self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) - let accessHash: Int64 = decoder.decodeInt64ForKey("ah") + let accessHash: Int64 = decoder.decodeInt64ForKey("ah", orElse: 0) if accessHash != 0 { self.accessHash = accessHash } else { self.accessHash = nil } - self.firstName = decoder.decodeStringForKey("fn") - self.lastName = decoder.decodeStringForKey("ln") + self.firstName = decoder.decodeOptionalStringForKey("fn") + self.lastName = decoder.decodeOptionalStringForKey("ln") - self.username = decoder.decodeStringForKey("un") - self.phone = decoder.decodeStringForKey("p") + self.username = decoder.decodeOptionalStringForKey("un") + self.phone = decoder.decodeOptionalStringForKey("p") self.photo = decoder.decodeObjectArrayForKey("ph") @@ -131,7 +131,7 @@ public final class TelegramUser: Peer { self.botInfo = nil } - self.flags = UserInfoFlags(rawValue: decoder.decodeInt32ForKey("fl")) + self.flags = UserInfoFlags(rawValue: decoder.decodeInt32ForKey("fl", orElse: 0)) } public func encode(_ encoder: Encoder) { diff --git a/TelegramCore/TelegramUserPresence.swift b/TelegramCore/TelegramUserPresence.swift index 4cd0f98d43..5817bd0744 100644 --- a/TelegramCore/TelegramUserPresence.swift +++ b/TelegramCore/TelegramUserPresence.swift @@ -90,11 +90,11 @@ public enum UserPresenceStatus: Comparable, Coding { } public init(decoder: Decoder) { - switch decoder.decodeInt32ForKey("v") as Int32 { + switch decoder.decodeInt32ForKey("v", orElse: 0) { case 0: self = .none case 1: - self = .present(until: decoder.decodeInt32ForKey("t")) + self = .present(until: decoder.decodeInt32ForKey("t", orElse: 0)) case 2: self = .recently case 3: diff --git a/TelegramCore/TextEntitiesMessageAttribute.swift b/TelegramCore/TextEntitiesMessageAttribute.swift index d72148973f..4525f3437c 100644 --- a/TelegramCore/TextEntitiesMessageAttribute.swift +++ b/TelegramCore/TextEntitiesMessageAttribute.swift @@ -107,8 +107,8 @@ public struct MessageTextEntity: Coding, Equatable { } public init(decoder: Decoder) { - self.range = Int(decoder.decodeInt32ForKey("start")) ..< Int(decoder.decodeInt32ForKey("end")) - let type: Int32 = decoder.decodeInt32ForKey("_rawValue") + self.range = Int(decoder.decodeInt32ForKey("start", orElse: 0)) ..< Int(decoder.decodeInt32ForKey("end", orElse: 0)) + let type: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) switch type { case 1: self.type = .Mention @@ -129,9 +129,9 @@ public struct MessageTextEntity: Coding, Equatable { case 9: self.type = .Pre case 10: - self.type = .TextUrl(url: decoder.decodeStringForKey("url")) + self.type = .TextUrl(url: decoder.decodeStringForKey("url", orElse: "")) case 11: - self.type = .TextMention(peerId: PeerId(decoder.decodeInt64ForKey("peerId"))) + self.type = .TextMention(peerId: PeerId(decoder.decodeInt64ForKey("peerId", orElse: 0))) default: self.type = .Unknown } diff --git a/TelegramCore/ViewCountMessageAttribute.swift b/TelegramCore/ViewCountMessageAttribute.swift index 7f52235eeb..7f4f56e4a1 100644 --- a/TelegramCore/ViewCountMessageAttribute.swift +++ b/TelegramCore/ViewCountMessageAttribute.swift @@ -15,7 +15,7 @@ public class ViewCountMessageAttribute: MessageAttribute { } required public init(decoder: Decoder) { - self.count = Int(decoder.decodeInt32ForKey("c")) + self.count = Int(decoder.decodeInt32ForKey("c", orElse: 0)) } public func encode(_ encoder: Encoder) {