no message

This commit is contained in:
Peter
2017-05-26 13:11:25 +03:00
parent f93eebb273
commit ae7c0af98a
77 changed files with 1558 additions and 408 deletions

View File

@@ -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 = "<group>"; };
D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedGlobalNotificationSettings.swift; sourceTree = "<group>"; };
D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalNotificationSettings.swift; sourceTree = "<group>"; };
D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationSettings.swift; sourceTree = "<group>"; };
D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuggestedLocalizationEntry.swift; sourceTree = "<group>"; };
D08CAA831ED8164B0000FDA8 /* Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = "<group>"; };
D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationInfo.swift; sourceTree = "<group>"; };
D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localizations.swift; sourceTree = "<group>"; };
D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeInstalledStickerPacksOperations.swift; sourceTree = "<group>"; };
D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeInstalledStickerPacksOperations.swift; sourceTree = "<group>"; };
D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerCommands.swift; sourceTree = "<group>"; };
@@ -842,6 +857,7 @@
D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */,
D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */,
D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */,
D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */,
);
name = Settings;
sourceTree = "<group>";
@@ -945,6 +961,7 @@
D0FA8B961E1E952D001E855B /* Secret Chats */,
D021E0DD1DB539E800C6B04F /* Item Collections */,
D01B27A01E394D7B0022A4C0 /* Settings */,
D08CAA821ED816290000FDA8 /* Localization */,
);
name = Objects;
sourceTree = "<group>";
@@ -1208,6 +1225,24 @@
name = Frameworks;
sourceTree = "<group>";
};
D08CAA821ED816290000FDA8 /* Localization */ = {
isa = PBXGroup;
children = (
D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */,
D08CAA831ED8164B0000FDA8 /* Localization.swift */,
D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */,
);
name = Localization;
sourceTree = "<group>";
};
D08CAA8A1ED81EA10000FDA8 /* Localization */ = {
isa = PBXGroup;
children = (
D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */,
);
name = Localization;
sourceTree = "<group>";
};
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 */,
);

View File

@@ -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<UnauthorizedAccount, NoError> 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<AccountResult, NoError> 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<AccountResult, NoError> 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))
}
}
}

View File

@@ -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
}

View File

@@ -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<MessageId> {
var messageIds = Set<MessageId>()
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<MessageIndex>] = [:]
private var visibleCallListHoleIds: [MessageIndex: Int] = [:]
private var visibleCallListHoleDisposables: [MessageIndex: Disposable] = [:]
private var updatedViewCountMessageIdsAndTimestamps: [MessageId: Int32] = [:]
private var nextUpdatedViewCountDisposableId: Int32 = 0
private var updatedViewCountDisposables = DisposableDict<Int32>()
@@ -238,6 +264,66 @@ public final class AccountViewTracker {
}
}
private func updateVisibleCallListHoles(viewId: Int32, holeIds: Set<MessageIndex>) {
self.queue.async {
var addedHoleIds: [MessageIndex] = []
var removedHoleIds: [MessageIndex] = []
let viewHoleIds: Set<MessageIndex> = 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<MessageId>) {
self.queue.async {
var addedMessageIds: [MessageId] = []
@@ -568,4 +654,123 @@ public final class AccountViewTracker {
}
}
}
public func callListView(type: CallListViewType, index: MessageIndex, count: Int) -> Signal<CallListView, NoError> {
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<MessageIndex>()
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()
}
}
}

View File

@@ -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()

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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")
}

View File

@@ -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) {

View File

@@ -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<PeerId>()
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

View File

@@ -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))
}
}

View File

@@ -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<PeerId>()
if let participants = participants {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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:

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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))
}
}
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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)
}

View File

@@ -401,3 +401,81 @@ func fetchChatListHole(network: Network, postbox: Postbox, hole: ChatListHole) -
}
}
}
func fetchCallListHole(network: Network, postbox: Postbox, holeIndex: MessageIndex, limit: Int32 = 100) -> Signal<Void, NoError> {
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<Void, NoError> 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<Void, NoError> 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
}
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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<SuggestedLocalizationInfo, NoError> {
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<Localization, NoError> {
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<Void, NoError> {
return downloadLocalization(network: network, languageCode: languageCode)
|> mapToSignal { language -> Signal<Void, NoError> 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)
}
}
}
}

View File

@@ -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<UInt8>) -> 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()
}

View File

@@ -72,6 +72,7 @@ func managedAutoremoveMessageOperations(postbox: Postbox) -> Signal<Void, NoErro
})
return ActionDisposable {
disposable.dispose()
let disposables = helper.with { helper -> [Disposable] in
return helper.reset()
}

View File

@@ -11,29 +11,46 @@ import Foundation
func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
let poll = Signal<Void, NoError> { 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<Void, NoError> 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

View File

@@ -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)

View File

@@ -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
}()
}

View File

@@ -293,18 +293,19 @@ func networkUsageStats(basePath: String, reset: ResetNetworkUsageStats) -> Signa
}) |> then(Signal<NetworkUsageStats, NoError>.complete() |> delay(5.0, queue: Queue.concurrentDefaultQueue()))) |> restart
}
func initializedNetwork(apiId: Int32, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool) -> Signal<Network, NoError> {
func initializedNetwork(apiId: Int32, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?) -> Signal<Network, NoError> {
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)!

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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):

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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:

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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<DcOption> 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<DisabledFeature> = Config;
case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
var addressList = [MTDatacenterAddress]()
for option in dcOptions {
switch option {

View File

@@ -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")
}

View File

@@ -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)
}
}
}

View File

@@ -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<Void, NoError> {
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
})
}
}

View File

@@ -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:

View File

@@ -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

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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))
}

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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:

View File

@@ -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
}

View File

@@ -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) {