Fixed unread counter category for private channels

Added support for "contact joined" service messages
Updated password recovery API
Updated Localization APIs
Added limited contact presence polling after getDifference
This commit is contained in:
Peter 2018-11-11 17:46:21 +04:00
parent bf8ec5775f
commit 0b96d69daa
23 changed files with 369 additions and 173 deletions

View File

@ -366,6 +366,8 @@
D05A32E51E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */; }; D05A32E51E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */; };
D05A32E71E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */; }; D05A32E71E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */; };
D05A32E81E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */; }; D05A32E81E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */; };
D05D8B372192F8AF0064586F /* LocalizationListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B362192F8AF0064586F /* LocalizationListState.swift */; };
D05D8B382192F8AF0064586F /* LocalizationListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B362192F8AF0064586F /* LocalizationListState.swift */; };
D0613FCA1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.swift */; }; D0613FCA1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.swift */; };
D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.swift */; }; D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.swift */; };
D0613FCF1E60520700202CDB /* ChannelMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FCE1E60520700202CDB /* ChannelMembers.swift */; }; D0613FCF1E60520700202CDB /* ChannelMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FCE1E60520700202CDB /* ChannelMembers.swift */; };
@ -957,6 +959,7 @@
D05A32E01E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatedAccountPrivacySettings.swift; sourceTree = "<group>"; }; D05A32E01E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatedAccountPrivacySettings.swift; sourceTree = "<group>"; };
D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentAccountSessions.swift; sourceTree = "<group>"; }; D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentAccountSessions.swift; sourceTree = "<group>"; };
D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentAccountSession.swift; sourceTree = "<group>"; }; D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentAccountSession.swift; sourceTree = "<group>"; };
D05D8B362192F8AF0064586F /* LocalizationListState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationListState.swift; sourceTree = "<group>"; };
D0613FC91E60440600202CDB /* InvitationLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvitationLinks.swift; sourceTree = "<group>"; }; D0613FC91E60440600202CDB /* InvitationLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvitationLinks.swift; sourceTree = "<group>"; };
D0613FCE1E60520700202CDB /* ChannelMembers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelMembers.swift; sourceTree = "<group>"; }; D0613FCE1E60520700202CDB /* ChannelMembers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelMembers.swift; sourceTree = "<group>"; };
D0613FD61E606B3B00202CDB /* ConvertGroupToSupergroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertGroupToSupergroup.swift; sourceTree = "<group>"; }; D0613FD61E606B3B00202CDB /* ConvertGroupToSupergroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertGroupToSupergroup.swift; sourceTree = "<group>"; };
@ -1680,6 +1683,7 @@
D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */, D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */,
D08CAA831ED8164B0000FDA8 /* Localization.swift */, D08CAA831ED8164B0000FDA8 /* Localization.swift */,
D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */, D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */,
D05D8B362192F8AF0064586F /* LocalizationListState.swift */,
); );
name = Localization; name = Localization;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2179,6 +2183,7 @@
D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */, D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */,
D00C7CEB1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */, D00C7CEB1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */,
D09BB6B61DB0428000A905C0 /* PendingMessageUploadedContent.swift in Sources */, D09BB6B61DB0428000A905C0 /* PendingMessageUploadedContent.swift in Sources */,
D05D8B372192F8AF0064586F /* LocalizationListState.swift in Sources */,
D0F3CC7D1DDE289E008148FA /* ResolvePeerByName.swift in Sources */, D0F3CC7D1DDE289E008148FA /* ResolvePeerByName.swift in Sources */,
D0B843B71DA7FF30005F29E1 /* NBMetadataCoreMapper.m in Sources */, D0B843B71DA7FF30005F29E1 /* NBMetadataCoreMapper.m in Sources */,
D0AB0B921D65E9FA002C78E7 /* ManagedServiceViews.swift in Sources */, D0AB0B921D65E9FA002C78E7 /* ManagedServiceViews.swift in Sources */,
@ -2716,6 +2721,7 @@
D07047BB1F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift in Sources */, D07047BB1F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift in Sources */,
D0380DBB204EF306000414AB /* MessageMediaPreuploadManager.swift in Sources */, D0380DBB204EF306000414AB /* MessageMediaPreuploadManager.swift in Sources */,
D050F2621E4A5AE700988324 /* GlobalNotificationSettings.swift in Sources */, D050F2621E4A5AE700988324 /* GlobalNotificationSettings.swift in Sources */,
D05D8B382192F8AF0064586F /* LocalizationListState.swift in Sources */,
D0DFD5E01FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */, D0DFD5E01FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */,
D0B418991D7E0580004562A4 /* TelegramMediaMap.swift in Sources */, D0B418991D7E0580004562A4 /* TelegramMediaMap.swift in Sources */,
D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */, D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */,

View File

@ -185,10 +185,14 @@ let telegramPostboxSeedConfiguration: SeedConfiguration = {
} }
return SeedConfiguration(initializeChatListWithHole: (topLevel: ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 1), timestamp: Int32.max - 1)), groups: 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, messageTagsWithSummary: MessageTags.unseenPersonalMessage, existingGlobalMessageTags: GlobalMessageTags.all, peerNamespacesRequiringMessageTextIndex: [Namespaces.Peer.SecretChat], peerSummaryCounterTags: { peer in return SeedConfiguration(initializeChatListWithHole: (topLevel: ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 1), timestamp: Int32.max - 1)), groups: 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, messageTagsWithSummary: MessageTags.unseenPersonalMessage, existingGlobalMessageTags: GlobalMessageTags.all, peerNamespacesRequiringMessageTextIndex: [Namespaces.Peer.SecretChat], peerSummaryCounterTags: { peer in
if let peer = peer as? TelegramChannel, let addressName = peer.addressName, !addressName.isEmpty { if let peer = peer as? TelegramChannel {
switch peer.info { switch peer.info {
case .group: case .group:
return [.publicGroups] if let addressName = peer.addressName, !addressName.isEmpty {
return [.publicGroups]
} else {
return [.regularChatsAndPrivateGroups]
}
case .broadcast: case .broadcast:
return [.channels] return [.channels]
} }

View File

@ -89,6 +89,7 @@ private var declaredEncodables: Void = {
declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) }) declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) })
declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) }) declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) })
declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) }) declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) })
declareEncodable(LocalizationListState.self, f: { LocalizationListState(decoder: $0) })
declareEncodable(ProxySettings.self, f: { ProxySettings(decoder: $0) }) declareEncodable(ProxySettings.self, f: { ProxySettings(decoder: $0) })
declareEncodable(NetworkSettings.self, f: { NetworkSettings(decoder: $0) }) declareEncodable(NetworkSettings.self, f: { NetworkSettings(decoder: $0) })
declareEncodable(RemoteStorageConfiguration.self, f: { RemoteStorageConfiguration(decoder: $0) }) declareEncodable(RemoteStorageConfiguration.self, f: { RemoteStorageConfiguration(decoder: $0) })
@ -207,20 +208,20 @@ public func currentAccount(allocateIfNotExists: Bool, networkArguments: NetworkI
initialKind = .authorized initialKind = .authorized
} }
let updatedKind = postbox.stateView() let updatedKind = postbox.stateView()
|> map { view -> Bool in |> map { view -> Bool in
let kind: AccountKind let kind: AccountKind
if view.state is AuthorizedAccountState { if view.state is AuthorizedAccountState {
kind = .authorized kind = .authorized
} else { } else {
kind = .unauthorized kind = .unauthorized
}
if kind != initialKind {
return true
} else {
return false
}
} }
|> distinctUntilChanged if kind != initialKind {
return true
} else {
return false
}
}
|> distinctUntilChanged
return Signal { subscriber in return Signal { subscriber in
subscriber.putNext(accountResult) subscriber.putNext(accountResult)
@ -242,28 +243,27 @@ public func currentAccount(allocateIfNotExists: Bool, networkArguments: NetworkI
public func logoutFromAccount(id: AccountRecordId, accountManager: AccountManager) -> Signal<Void, NoError> { public func logoutFromAccount(id: AccountRecordId, accountManager: AccountManager) -> Signal<Void, NoError> {
Logger.shared.log("AccountManager", "logoutFromAccount \(id)") Logger.shared.log("AccountManager", "logoutFromAccount \(id)")
return accountManager.transaction { transaction -> Void in return accountManager.transaction { transaction -> Void in
let currentId = transaction.getCurrentId() transaction.updateRecord(id, { current in
if let currentId = currentId { if let current = current {
transaction.updateRecord(currentId, { current in var found = false
if let current = current { for attribute in current.attributes {
var found = false if attribute is LoggedOutAccountAttribute {
for attribute in current.attributes { found = true
if attribute is LoggedOutAccountAttribute { break
found = true
break
}
} }
if found {
return current
} else {
return AccountRecord(id: current.id, attributes: current.attributes + [LoggedOutAccountAttribute()], temporarySessionId: nil)
}
} else {
return nil
} }
}) if found {
let id = transaction.createRecord([]) return current
transaction.setCurrentId(id) } else {
return AccountRecord(id: current.id, attributes: current.attributes + [LoggedOutAccountAttribute()], temporarySessionId: nil)
}
} else {
return nil
}
})
if transaction.getCurrentId() == id {
let updatedId = transaction.createRecord([])
transaction.setCurrentId(updatedId)
} }
} }
} }
@ -285,14 +285,15 @@ public func managedCleanupAccounts(networkArguments: NetworkInitializationArgume
var disposeList: [(AccountRecordId, MetaDisposable)] = [] var disposeList: [(AccountRecordId, MetaDisposable)] = []
var beginList: [(AccountRecordId, MetaDisposable)] = [] var beginList: [(AccountRecordId, MetaDisposable)] = []
let _ = loggedOutAccounts.modify { disposables in let _ = loggedOutAccounts.modify { disposables in
let validIds = Set(view.records.filter { var validIds = Set<AccountRecordId>()
for attribute in $0.attributes { outer: for record in view.records {
for attribute in record.attributes {
if attribute is LoggedOutAccountAttribute { if attribute is LoggedOutAccountAttribute {
return true validIds.insert(record.id)
continue outer
} }
} }
return false }
}.map { $0.id })
var disposables = disposables var disposables = disposables
@ -320,7 +321,7 @@ public func managedCleanupAccounts(networkArguments: NetworkInitializationArgume
disposable.dispose() disposable.dispose()
} }
for (id, disposable) in beginList { for (id, disposable) in beginList {
Logger.shared.log("managedCleanupAccounts", "cleanup \(id)") Logger.shared.log("managedCleanupAccounts", "cleanup \(id), current is \(String(describing: view.currentRecord?.id))")
disposable.set(cleanupAccount(networkArguments: networkArguments, accountManager: accountManager, id: id, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods).start()) disposable.set(cleanupAccount(networkArguments: networkArguments, accountManager: accountManager, id: id, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods).start())
} }

View File

@ -101,13 +101,6 @@ private func locallyGeneratedMessageTimestampsFromUpdateGroups(_ groups: [Update
messageTimestamps[peerId]!.append((Namespaces.Message.Local, date)) messageTimestamps[peerId]!.append((Namespaces.Message.Local, date))
} }
} }
case let .updateContactRegistered(userId, date):
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
if messageTimestamps[peerId] == nil {
messageTimestamps[peerId] = [(Namespaces.Message.Local, date)]
} else {
messageTimestamps[peerId]!.append((Namespaces.Message.Local, date))
}
default: default:
break break
} }
@ -306,13 +299,6 @@ private func locallyGeneratedMessageTimestampsFromDifference(_ difference: Api.u
messageTimestamps[peerId]!.append((Namespaces.Message.Local, date)) messageTimestamps[peerId]!.append((Namespaces.Message.Local, date))
} }
} }
case let .updateContactRegistered(userId, date):
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
if messageTimestamps[peerId] == nil {
messageTimestamps[peerId] = [(Namespaces.Message.Local, date)]
} else {
messageTimestamps[peerId]!.append((Namespaces.Message.Local, date))
}
default: default:
break break
} }
@ -920,25 +906,6 @@ private func finalStateWithUpdatesAndServerTime(account: Account, state: Account
} else { } else {
updatedState.addDisplayAlert(text) updatedState.addDisplayAlert(text)
} }
case let .updateContactRegistered(userId, date):
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
var alreadyStored = false
if let storedMessages = updatedState.storedMessagesByPeerIdAndTimestamp[peerId] {
for index in storedMessages {
if index.timestamp == date {
alreadyStored = true
break
}
}
}
if alreadyStored {
Logger.shared.log("State", "skipping joined message at \(date) for \(peerId): already stored")
} else {
let message = StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: nil, groupingKey: nil, timestamp: date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: peerId, text: "", attributes: [], media: [TelegramMediaAction(action: .peerJoined)])
updatedState.addMessages([message], location: .UpperHistoryBlock)
}
case let .updateReadChannelInbox(channelId, maxId): case let .updateReadChannelInbox(channelId, maxId):
updatedState.readInbox(MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: maxId)) updatedState.readInbox(MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: maxId))
case let .updateReadChannelOutbox(channelId, maxId): case let .updateReadChannelOutbox(channelId, maxId):

View File

@ -110,6 +110,11 @@ public final class AccountStateManager {
return self.appliedIncomingReadMessagesPipe.signal() return self.appliedIncomingReadMessagesPipe.signal()
} }
private let significantStateUpdateCompletedPipe = ValuePipe<Void>()
var significantStateUpdateCompleted: Signal<Void, NoError> {
return self.significantStateUpdateCompletedPipe.signal()
}
private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:] private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:]
private let delayNotificatonsUntil = Atomic<Int32?>(value: nil) private let delayNotificatonsUntil = Atomic<Int32?>(value: nil)
@ -424,6 +429,7 @@ public final class AccountStateManager {
strongSelf.insertProcessEvents(events) strongSelf.insertProcessEvents(events)
} }
strongSelf.currentIsUpdatingValue = false strongSelf.currentIsUpdatingValue = false
strongSelf.significantStateUpdateCompletedPipe.putNext(Void())
} }
} else { } else {
if !events.isEmpty { if !events.isEmpty {

View File

@ -89,7 +89,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1343524562] = { return Api.InputChannel.parse_inputChannel($0) } dict[-1343524562] = { return Api.InputChannel.parse_inputChannel($0) }
dict[414687501] = { return Api.DcOption.parse_dcOption($0) } dict[414687501] = { return Api.DcOption.parse_dcOption($0) }
dict[-1705233435] = { return Api.account.PasswordSettings.parse_passwordSettings($0) } dict[-1705233435] = { return Api.account.PasswordSettings.parse_passwordSettings($0) }
dict[106019213] = { return Api.LangPackLanguage.parse_langPackLanguage($0) } dict[-288727837] = { return Api.LangPackLanguage.parse_langPackLanguage($0) }
dict[-1987579119] = { return Api.help.AppUpdate.parse_appUpdate($0) } dict[-1987579119] = { return Api.help.AppUpdate.parse_appUpdate($0) }
dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) } dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) }
dict[-209337866] = { return Api.LangPackDifference.parse_langPackDifference($0) } dict[-209337866] = { return Api.LangPackDifference.parse_langPackDifference($0) }
@ -154,7 +154,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[469489699] = { return Api.Update.parse_updateUserStatus($0) } dict[469489699] = { return Api.Update.parse_updateUserStatus($0) }
dict[-1489818765] = { return Api.Update.parse_updateUserName($0) } dict[-1489818765] = { return Api.Update.parse_updateUserName($0) }
dict[-1791935732] = { return Api.Update.parse_updateUserPhoto($0) } dict[-1791935732] = { return Api.Update.parse_updateUserPhoto($0) }
dict[628472761] = { return Api.Update.parse_updateContactRegistered($0) }
dict[-1657903163] = { return Api.Update.parse_updateContactLink($0) } dict[-1657903163] = { return Api.Update.parse_updateContactLink($0) }
dict[314359194] = { return Api.Update.parse_updateNewEncryptedMessage($0) } dict[314359194] = { return Api.Update.parse_updateNewEncryptedMessage($0) }
dict[386986326] = { return Api.Update.parse_updateEncryptedChatTyping($0) } dict[386986326] = { return Api.Update.parse_updateEncryptedChatTyping($0) }
@ -631,6 +630,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1410748418] = { return Api.MessageAction.parse_messageActionBotAllowed($0) } dict[-1410748418] = { return Api.MessageAction.parse_messageActionBotAllowed($0) }
dict[455635795] = { return Api.MessageAction.parse_messageActionSecureValuesSentMe($0) } dict[455635795] = { return Api.MessageAction.parse_messageActionSecureValuesSentMe($0) }
dict[-648257196] = { return Api.MessageAction.parse_messageActionSecureValuesSent($0) } dict[-648257196] = { return Api.MessageAction.parse_messageActionSecureValuesSent($0) }
dict[1894744724] = { return Api.MessageAction.parse_messageActionContactSignUp($0) }
dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) } dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) }
dict[462375633] = { return Api.PhoneCall.parse_phoneCallWaiting($0) } dict[462375633] = { return Api.PhoneCall.parse_phoneCallWaiting($0) }
dict[-2089411356] = { return Api.PhoneCall.parse_phoneCallRequested($0) } dict[-2089411356] = { return Api.PhoneCall.parse_phoneCallRequested($0) }
@ -651,7 +651,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1889961234] = { return Api.PeerNotifySettings.parse_peerNotifySettingsEmpty($0) } dict[1889961234] = { return Api.PeerNotifySettings.parse_peerNotifySettingsEmpty($0) }
dict[-1353671392] = { return Api.PeerNotifySettings.parse_peerNotifySettings($0) } dict[-1353671392] = { return Api.PeerNotifySettings.parse_peerNotifySettings($0) }
dict[-1995686519] = { return Api.InputBotInlineMessageID.parse_inputBotInlineMessageID($0) } dict[-1995686519] = { return Api.InputBotInlineMessageID.parse_inputBotInlineMessageID($0) }
dict[-242812612] = { return Api.PageRelatedArticle.parse_pageRelatedArticle($0) } dict[-1282352120] = { return Api.PageRelatedArticle.parse_pageRelatedArticle($0) }
dict[313694676] = { return Api.StickerPack.parse_stickerPack($0) } dict[313694676] = { return Api.StickerPack.parse_stickerPack($0) }
dict[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) } dict[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) }
dict[-715532088] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) } dict[-715532088] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) }

View File

@ -2362,13 +2362,13 @@ extension Api {
} }
enum LangPackLanguage: TypeConstructorDescription { enum LangPackLanguage: TypeConstructorDescription {
case langPackLanguage(flags: Int32, name: String, nativeName: String, langCode: String, baseLangCode: String?, pluralCode: String, stringsCount: Int32, translatedCount: Int32) case langPackLanguage(flags: Int32, name: String, nativeName: String, langCode: String, baseLangCode: String?, pluralCode: String, stringsCount: Int32, translatedCount: Int32, translationsUrl: String)
func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount): case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount, let translationsUrl):
if boxed { if boxed {
buffer.appendInt32(106019213) buffer.appendInt32(-288727837)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(name, buffer: buffer, boxed: false) serializeString(name, buffer: buffer, boxed: false)
@ -2378,14 +2378,15 @@ extension Api {
serializeString(pluralCode, buffer: buffer, boxed: false) serializeString(pluralCode, buffer: buffer, boxed: false)
serializeInt32(stringsCount, buffer: buffer, boxed: false) serializeInt32(stringsCount, buffer: buffer, boxed: false)
serializeInt32(translatedCount, buffer: buffer, boxed: false) serializeInt32(translatedCount, buffer: buffer, boxed: false)
serializeString(translationsUrl, buffer: buffer, boxed: false)
break break
} }
} }
func descriptionFields() -> (String, [(String, Any)]) { func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount): case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount, let translationsUrl):
return ("langPackLanguage", [("flags", flags), ("name", name), ("nativeName", nativeName), ("langCode", langCode), ("baseLangCode", baseLangCode), ("pluralCode", pluralCode), ("stringsCount", stringsCount), ("translatedCount", translatedCount)]) return ("langPackLanguage", [("flags", flags), ("name", name), ("nativeName", nativeName), ("langCode", langCode), ("baseLangCode", baseLangCode), ("pluralCode", pluralCode), ("stringsCount", stringsCount), ("translatedCount", translatedCount), ("translationsUrl", translationsUrl)])
} }
} }
@ -2406,6 +2407,8 @@ extension Api {
_7 = reader.readInt32() _7 = reader.readInt32()
var _8: Int32? var _8: Int32?
_8 = reader.readInt32() _8 = reader.readInt32()
var _9: String?
_9 = parseString(reader)
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -2414,8 +2417,9 @@ extension Api {
let _c6 = _6 != nil let _c6 = _6 != nil
let _c7 = _7 != nil let _c7 = _7 != nil
let _c8 = _8 != nil let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { let _c9 = _9 != nil
return Api.LangPackLanguage.langPackLanguage(flags: _1!, name: _2!, nativeName: _3!, langCode: _4!, baseLangCode: _5, pluralCode: _6!, stringsCount: _7!, translatedCount: _8!) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.LangPackLanguage.langPackLanguage(flags: _1!, name: _2!, nativeName: _3!, langCode: _4!, baseLangCode: _5, pluralCode: _6!, stringsCount: _7!, translatedCount: _8!, translationsUrl: _9!)
} }
else { else {
return nil return nil
@ -3337,7 +3341,6 @@ extension Api {
case updateUserStatus(userId: Int32, status: Api.UserStatus) case updateUserStatus(userId: Int32, status: Api.UserStatus)
case updateUserName(userId: Int32, firstName: String, lastName: String, username: String) case updateUserName(userId: Int32, firstName: String, lastName: String, username: String)
case updateUserPhoto(userId: Int32, date: Int32, photo: Api.UserProfilePhoto, previous: Api.Bool) case updateUserPhoto(userId: Int32, date: Int32, photo: Api.UserProfilePhoto, previous: Api.Bool)
case updateContactRegistered(userId: Int32, date: Int32)
case updateContactLink(userId: Int32, myLink: Api.ContactLink, foreignLink: Api.ContactLink) case updateContactLink(userId: Int32, myLink: Api.ContactLink, foreignLink: Api.ContactLink)
case updateNewEncryptedMessage(message: Api.EncryptedMessage, qts: Int32) case updateNewEncryptedMessage(message: Api.EncryptedMessage, qts: Int32)
case updateEncryptedChatTyping(chatId: Int32) case updateEncryptedChatTyping(chatId: Int32)
@ -3473,13 +3476,6 @@ extension Api {
photo.serialize(buffer, true) photo.serialize(buffer, true)
previous.serialize(buffer, true) previous.serialize(buffer, true)
break break
case .updateContactRegistered(let userId, let date):
if boxed {
buffer.appendInt32(628472761)
}
serializeInt32(userId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
break
case .updateContactLink(let userId, let myLink, let foreignLink): case .updateContactLink(let userId, let myLink, let foreignLink):
if boxed { if boxed {
buffer.appendInt32(-1657903163) buffer.appendInt32(-1657903163)
@ -3988,8 +3984,6 @@ extension Api {
return ("updateUserName", [("userId", userId), ("firstName", firstName), ("lastName", lastName), ("username", username)]) return ("updateUserName", [("userId", userId), ("firstName", firstName), ("lastName", lastName), ("username", username)])
case .updateUserPhoto(let userId, let date, let photo, let previous): case .updateUserPhoto(let userId, let date, let photo, let previous):
return ("updateUserPhoto", [("userId", userId), ("date", date), ("photo", photo), ("previous", previous)]) return ("updateUserPhoto", [("userId", userId), ("date", date), ("photo", photo), ("previous", previous)])
case .updateContactRegistered(let userId, let date):
return ("updateContactRegistered", [("userId", userId), ("date", date)])
case .updateContactLink(let userId, let myLink, let foreignLink): case .updateContactLink(let userId, let myLink, let foreignLink):
return ("updateContactLink", [("userId", userId), ("myLink", myLink), ("foreignLink", foreignLink)]) return ("updateContactLink", [("userId", userId), ("myLink", myLink), ("foreignLink", foreignLink)])
case .updateNewEncryptedMessage(let message, let qts): case .updateNewEncryptedMessage(let message, let qts):
@ -4271,20 +4265,6 @@ extension Api {
return nil return nil
} }
} }
static func parse_updateContactRegistered(_ reader: BufferReader) -> Update? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.Update.updateContactRegistered(userId: _1!, date: _2!)
}
else {
return nil
}
}
static func parse_updateContactLink(_ reader: BufferReader) -> Update? { static func parse_updateContactLink(_ reader: BufferReader) -> Update? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()
@ -15158,6 +15138,7 @@ extension Api {
case messageActionBotAllowed(domain: String) case messageActionBotAllowed(domain: String)
case messageActionSecureValuesSentMe(values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted) case messageActionSecureValuesSentMe(values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted)
case messageActionSecureValuesSent(types: [Api.SecureValueType]) case messageActionSecureValuesSent(types: [Api.SecureValueType])
case messageActionContactSignUp(flags: Int32)
func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -15323,6 +15304,12 @@ extension Api {
item.serialize(buffer, true) item.serialize(buffer, true)
} }
break break
case .messageActionContactSignUp(let flags):
if boxed {
buffer.appendInt32(1894744724)
}
serializeInt32(flags, buffer: buffer, boxed: false)
break
} }
} }
@ -15372,6 +15359,8 @@ extension Api {
return ("messageActionSecureValuesSentMe", [("values", values), ("credentials", credentials)]) return ("messageActionSecureValuesSentMe", [("values", values), ("credentials", credentials)])
case .messageActionSecureValuesSent(let types): case .messageActionSecureValuesSent(let types):
return ("messageActionSecureValuesSent", [("types", types)]) return ("messageActionSecureValuesSent", [("types", types)])
case .messageActionContactSignUp(let flags):
return ("messageActionContactSignUp", [("flags", flags)])
} }
} }
@ -15637,6 +15626,17 @@ extension Api {
return nil return nil
} }
} }
static func parse_messageActionContactSignUp(_ reader: BufferReader) -> MessageAction? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.MessageAction.messageActionContactSignUp(flags: _1!)
}
else {
return nil
}
}
} }
enum PhoneCall: TypeConstructorDescription { enum PhoneCall: TypeConstructorDescription {
@ -16258,13 +16258,13 @@ extension Api {
} }
enum PageRelatedArticle: TypeConstructorDescription { enum PageRelatedArticle: TypeConstructorDescription {
case pageRelatedArticle(flags: Int32, url: String, webpageId: Int64, title: String?, description: String?, photoId: Int64?) case pageRelatedArticle(flags: Int32, url: String, webpageId: Int64, title: String?, description: String?, photoId: Int64?, author: String?, publishedDate: Int32?)
func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .pageRelatedArticle(let flags, let url, let webpageId, let title, let description, let photoId): case .pageRelatedArticle(let flags, let url, let webpageId, let title, let description, let photoId, let author, let publishedDate):
if boxed { if boxed {
buffer.appendInt32(-242812612) buffer.appendInt32(-1282352120)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(url, buffer: buffer, boxed: false) serializeString(url, buffer: buffer, boxed: false)
@ -16272,14 +16272,16 @@ extension Api {
if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeInt64(photoId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {serializeInt64(photoId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {serializeString(author!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(publishedDate!, buffer: buffer, boxed: false)}
break break
} }
} }
func descriptionFields() -> (String, [(String, Any)]) { func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .pageRelatedArticle(let flags, let url, let webpageId, let title, let description, let photoId): case .pageRelatedArticle(let flags, let url, let webpageId, let title, let description, let photoId, let author, let publishedDate):
return ("pageRelatedArticle", [("flags", flags), ("url", url), ("webpageId", webpageId), ("title", title), ("description", description), ("photoId", photoId)]) return ("pageRelatedArticle", [("flags", flags), ("url", url), ("webpageId", webpageId), ("title", title), ("description", description), ("photoId", photoId), ("author", author), ("publishedDate", publishedDate)])
} }
} }
@ -16296,14 +16298,20 @@ extension Api {
if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) }
var _6: Int64? var _6: Int64?
if Int(_1!) & Int(1 << 2) != 0 {_6 = reader.readInt64() } if Int(_1!) & Int(1 << 2) != 0 {_6 = reader.readInt64() }
var _7: String?
if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) }
var _8: Int32?
if Int(_1!) & Int(1 << 4) != 0 {_8 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil
return Api.PageRelatedArticle.pageRelatedArticle(flags: _1!, url: _2!, webpageId: _3!, title: _4, description: _5, photoId: _6) let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.PageRelatedArticle.pageRelatedArticle(flags: _1!, url: _2!, webpageId: _3!, title: _4, description: _5, photoId: _6, author: _7, publishedDate: _8)
} }
else { else {
return nil return nil

View File

@ -4939,12 +4939,53 @@ extension Api {
}) })
} }
static func confirmPasswordEmail(email: String, code: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { static func confirmPasswordEmail(code: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(-558870880) buffer.appendInt32(-1881204448)
serializeString(email, buffer: buffer, boxed: false)
serializeString(code, buffer: buffer, boxed: false) serializeString(code, buffer: buffer, boxed: false)
return (FunctionDescription(name: "account.confirmPasswordEmail", parameters: [("email", email), ("code", code)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in return (FunctionDescription(name: "account.confirmPasswordEmail", parameters: [("code", code)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
static func resendPasswordEmail() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(2055154197)
return (FunctionDescription(name: "account.resendPasswordEmail", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
static func getContactSignUpNotification() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-1626880216)
return (FunctionDescription(name: "account.getContactSignUpNotification", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
static func setContactSignUpNotification(silent: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-806076575)
silent.serialize(buffer, true)
return (FunctionDescription(name: "account.setContactSignUpNotification", parameters: [("silent", silent)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.Bool? var result: Api.Bool?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {

View File

@ -15,8 +15,8 @@ public enum ConfirmTwoStepRecoveryEmailError {
case generic case generic
} }
public func confirmTwoStepRecoveryEmail(network: Network, email: String, code: String) -> Signal<Never, ConfirmTwoStepRecoveryEmailError> { public func confirmTwoStepRecoveryEmail(network: Network, code: String) -> Signal<Never, ConfirmTwoStepRecoveryEmailError> {
return network.request(Api.functions.account.confirmPasswordEmail(email: email, code: code), automaticFloodWait: false) return network.request(Api.functions.account.confirmPasswordEmail(code: code), automaticFloodWait: false)
|> mapError { error -> ConfirmTwoStepRecoveryEmailError in |> mapError { error -> ConfirmTwoStepRecoveryEmailError in
if error.errorDescription == "EMAIL_INVALID" { if error.errorDescription == "EMAIL_INVALID" {
return .invalidEmail return .invalidEmail
@ -31,3 +31,19 @@ public func confirmTwoStepRecoveryEmail(network: Network, email: String, code: S
} }
|> ignoreValues |> ignoreValues
} }
public enum ResendTwoStepRecoveryEmailError {
case flood
case generic
}
public func resendTwoStepRecoveryEmail(network: Network) -> Signal<Never, ResendTwoStepRecoveryEmailError> {
return network.request(Api.functions.account.resendPasswordEmail(), automaticFloodWait: false)
|> mapError { error -> ResendTwoStepRecoveryEmailError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .flood
}
return .generic
}
|> ignoreValues
}

View File

@ -35,9 +35,11 @@ private final class ContactSyncManagerImpl {
private var nextId: Int32 = 0 private var nextId: Int32 = 0
private var operations: [ContactSyncOperation] = [] private var operations: [ContactSyncOperation] = []
private var lastContactPresencesRequestTimestamp: Double?
private var reimportAttempts: [TelegramDeviceContactImportIdentifier: Double] = [:] private var reimportAttempts: [TelegramDeviceContactImportIdentifier: Double] = [:]
private let importableContactsDisposable = MetaDisposable() private let importableContactsDisposable = MetaDisposable()
private let significantStateUpdateCompletedDisposable = MetaDisposable()
init(queue: Queue, postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager) { init(queue: Queue, postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager) {
self.queue = queue self.queue = queue
@ -61,6 +63,36 @@ private final class ContactSyncManagerImpl {
strongSelf.addOperation(.updatePresences) strongSelf.addOperation(.updatePresences)
strongSelf.addOperation(.sync(importableContacts: importableContacts)) strongSelf.addOperation(.sync(importableContacts: importableContacts))
})) }))
self.significantStateUpdateCompletedDisposable.set((self.stateManager.significantStateUpdateCompleted
|> deliverOn(self.queue)).start(next: { [weak self] in
guard let strongSelf = self else {
return
}
let timestamp = CFAbsoluteTimeGetCurrent()
let shouldUpdate: Bool
if let lastContactPresencesRequestTimestamp = strongSelf.lastContactPresencesRequestTimestamp {
if timestamp > lastContactPresencesRequestTimestamp + 30.0 * 60.0 {
shouldUpdate = true
} else {
shouldUpdate = false
}
} else {
shouldUpdate = true
}
if shouldUpdate {
strongSelf.lastContactPresencesRequestTimestamp = timestamp
var found = false
for operation in strongSelf.operations {
if case .updatePresences = operation.content {
found = true
break
}
}
if !found {
strongSelf.addOperation(.updatePresences)
}
}
}))
} }
func addIsContactUpdates(_ updates: [(PeerId, Bool)]) { func addIsContactUpdates(_ updates: [(PeerId, Bool)]) {

View File

@ -950,7 +950,7 @@ extension InstantPageTableRow {
extension InstantPageRelatedArticle { extension InstantPageRelatedArticle {
convenience init(apiRelatedArticle: Api.PageRelatedArticle) { convenience init(apiRelatedArticle: Api.PageRelatedArticle) {
switch apiRelatedArticle { switch apiRelatedArticle {
case let .pageRelatedArticle(flags, url, webpageId, title, description, photoId): case let .pageRelatedArticle(flags, url, webpageId, title, description, photoId, author, publishedDate):
var posterPhotoId: MediaId? var posterPhotoId: MediaId?
if let photoId = photoId { if let photoId = photoId {
posterPhotoId = MediaId(namespace: Namespaces.Media.CloudImage, id: photoId) posterPhotoId = MediaId(namespace: Namespaces.Media.CloudImage, id: photoId)

View File

@ -5,20 +5,21 @@ import Foundation
import Postbox import Postbox
#endif #endif
public final class LimitsConfiguration: PreferencesEntry { public struct LimitsConfiguration: Equatable, PreferencesEntry {
public let maxGroupMemberCount: Int32 public var maxGroupMemberCount: Int32
public let maxSupergroupMemberCount: Int32 public var maxSupergroupMemberCount: Int32
public let maxMessageForwardBatchSize: Int32 public var maxMessageForwardBatchSize: Int32
public let maxSavedGifCount: Int32 public var maxSavedGifCount: Int32
public let maxRecentStickerCount: Int32 public var maxRecentStickerCount: Int32
public let maxMessageEditingInterval: Int32 public var maxMessageEditingInterval: Int32
public let maxMediaCaptionLength: Int32 public var maxMediaCaptionLength: Int32
public var canRemoveIncomingMessagesInPrivateChats: Bool
public static var defaultValue: LimitsConfiguration { public static var defaultValue: LimitsConfiguration {
return LimitsConfiguration(maxGroupMemberCount: 200, maxSupergroupMemberCount: 5000, maxMessageForwardBatchSize: 50, maxSavedGifCount: 200, maxRecentStickerCount: 20, maxMessageEditingInterval: 2 * 24 * 60 * 60, maxMediaCaptionLength: 1000) return LimitsConfiguration(maxGroupMemberCount: 200, maxSupergroupMemberCount: 5000, maxMessageForwardBatchSize: 50, maxSavedGifCount: 200, maxRecentStickerCount: 20, maxMessageEditingInterval: 2 * 24 * 60 * 60, maxMediaCaptionLength: 1000, canRemoveIncomingMessagesInPrivateChats: false)
} }
init(maxGroupMemberCount: Int32, maxSupergroupMemberCount: Int32, maxMessageForwardBatchSize: Int32, maxSavedGifCount: Int32, maxRecentStickerCount: Int32, maxMessageEditingInterval: Int32, maxMediaCaptionLength: Int32) { init(maxGroupMemberCount: Int32, maxSupergroupMemberCount: Int32, maxMessageForwardBatchSize: Int32, maxSavedGifCount: Int32, maxRecentStickerCount: Int32, maxMessageEditingInterval: Int32, maxMediaCaptionLength: Int32, canRemoveIncomingMessagesInPrivateChats: Bool) {
self.maxGroupMemberCount = maxGroupMemberCount self.maxGroupMemberCount = maxGroupMemberCount
self.maxSupergroupMemberCount = maxSupergroupMemberCount self.maxSupergroupMemberCount = maxSupergroupMemberCount
self.maxMessageForwardBatchSize = maxMessageForwardBatchSize self.maxMessageForwardBatchSize = maxMessageForwardBatchSize
@ -26,6 +27,7 @@ public final class LimitsConfiguration: PreferencesEntry {
self.maxRecentStickerCount = maxRecentStickerCount self.maxRecentStickerCount = maxRecentStickerCount
self.maxMessageEditingInterval = maxMessageEditingInterval self.maxMessageEditingInterval = maxMessageEditingInterval
self.maxMediaCaptionLength = maxMediaCaptionLength self.maxMediaCaptionLength = maxMediaCaptionLength
self.canRemoveIncomingMessagesInPrivateChats = canRemoveIncomingMessagesInPrivateChats
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -36,6 +38,7 @@ public final class LimitsConfiguration: PreferencesEntry {
self.maxRecentStickerCount = decoder.decodeInt32ForKey("maxRecentStickerCount", orElse: 20) self.maxRecentStickerCount = decoder.decodeInt32ForKey("maxRecentStickerCount", orElse: 20)
self.maxMessageEditingInterval = decoder.decodeInt32ForKey("maxMessageEditingInterval", orElse: 2 * 24 * 60 * 60) self.maxMessageEditingInterval = decoder.decodeInt32ForKey("maxMessageEditingInterval", orElse: 2 * 24 * 60 * 60)
self.maxMediaCaptionLength = decoder.decodeInt32ForKey("maxMediaCaptionLength", orElse: 1000) self.maxMediaCaptionLength = decoder.decodeInt32ForKey("maxMediaCaptionLength", orElse: 1000)
self.canRemoveIncomingMessagesInPrivateChats = decoder.decodeInt32ForKey("canRemoveIncomingMessagesInPrivateChats", orElse: 0) != 0
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
@ -46,34 +49,14 @@ public final class LimitsConfiguration: PreferencesEntry {
encoder.encodeInt32(self.maxRecentStickerCount, forKey: "maxRecentStickerCount") encoder.encodeInt32(self.maxRecentStickerCount, forKey: "maxRecentStickerCount")
encoder.encodeInt32(self.maxMessageEditingInterval, forKey: "maxMessageEditingInterval") encoder.encodeInt32(self.maxMessageEditingInterval, forKey: "maxMessageEditingInterval")
encoder.encodeInt32(self.maxMediaCaptionLength, forKey: "maxMediaCaptionLength") encoder.encodeInt32(self.maxMediaCaptionLength, forKey: "maxMediaCaptionLength")
encoder.encodeInt32(self.canRemoveIncomingMessagesInPrivateChats ? 1 : 0, forKey: "canRemoveIncomingMessagesInPrivateChats")
} }
public func isEqual(to: PreferencesEntry) -> Bool { public func isEqual(to: PreferencesEntry) -> Bool {
guard let to = to as? LimitsConfiguration else { guard let to = to as? LimitsConfiguration else {
return false return false
} }
if self.maxGroupMemberCount != to.maxGroupMemberCount { return self == to
return false
}
if self.maxSupergroupMemberCount != to.maxSupergroupMemberCount {
return false
}
if self.maxMessageForwardBatchSize != to.maxMessageForwardBatchSize {
return false
}
if self.maxSavedGifCount != to.maxSavedGifCount {
return false
}
if self.maxRecentStickerCount != to.maxRecentStickerCount {
return false
}
if self.maxMessageEditingInterval != to.maxMessageEditingInterval {
return false
}
if self.maxMediaCaptionLength != to.maxMediaCaptionLength {
return false
}
return true
} }
} }

View File

@ -5,7 +5,7 @@ import Foundation
import Postbox import Postbox
#endif #endif
public final class LocalizationInfo: PostboxCoding { public struct LocalizationInfo: PostboxCoding, Equatable {
public let languageCode: String public let languageCode: String
public let baseLanguageCode: String? public let baseLanguageCode: String?
public let customPluralizationCode: String? public let customPluralizationCode: String?
@ -14,8 +14,9 @@ public final class LocalizationInfo: PostboxCoding {
public let isOfficial: Bool public let isOfficial: Bool
public let totalStringCount: Int32 public let totalStringCount: Int32
public let translatedStringCount: Int32 public let translatedStringCount: Int32
public let platformUrl: String
public init(languageCode: String, baseLanguageCode: String?, customPluralizationCode: String?, title: String, localizedTitle: String, isOfficial: Bool, totalStringCount: Int32, translatedStringCount: Int32) { public init(languageCode: String, baseLanguageCode: String?, customPluralizationCode: String?, title: String, localizedTitle: String, isOfficial: Bool, totalStringCount: Int32, translatedStringCount: Int32, platformUrl: String) {
self.languageCode = languageCode self.languageCode = languageCode
self.baseLanguageCode = baseLanguageCode self.baseLanguageCode = baseLanguageCode
self.customPluralizationCode = customPluralizationCode self.customPluralizationCode = customPluralizationCode
@ -24,6 +25,7 @@ public final class LocalizationInfo: PostboxCoding {
self.isOfficial = isOfficial self.isOfficial = isOfficial
self.totalStringCount = totalStringCount self.totalStringCount = totalStringCount
self.translatedStringCount = translatedStringCount self.translatedStringCount = translatedStringCount
self.platformUrl = platformUrl
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -35,6 +37,7 @@ public final class LocalizationInfo: PostboxCoding {
self.isOfficial = decoder.decodeInt32ForKey("of", orElse: 0) != 0 self.isOfficial = decoder.decodeInt32ForKey("of", orElse: 0) != 0
self.totalStringCount = decoder.decodeInt32ForKey("tsc", orElse: 0) self.totalStringCount = decoder.decodeInt32ForKey("tsc", orElse: 0)
self.translatedStringCount = decoder.decodeInt32ForKey("lsc", orElse: 0) self.translatedStringCount = decoder.decodeInt32ForKey("lsc", orElse: 0)
self.platformUrl = decoder.decodeStringForKey("platformUrl", orElse: "")
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
@ -54,14 +57,15 @@ public final class LocalizationInfo: PostboxCoding {
encoder.encodeInt32(self.isOfficial ? 1 : 0, forKey: "of") encoder.encodeInt32(self.isOfficial ? 1 : 0, forKey: "of")
encoder.encodeInt32(self.totalStringCount, forKey: "tsc") encoder.encodeInt32(self.totalStringCount, forKey: "tsc")
encoder.encodeInt32(self.translatedStringCount, forKey: "lsc") encoder.encodeInt32(self.translatedStringCount, forKey: "lsc")
encoder.encodeString(self.platformUrl, forKey: "platformUrl")
} }
} }
extension LocalizationInfo { extension LocalizationInfo {
convenience init(apiLanguage: Api.LangPackLanguage) { init(apiLanguage: Api.LangPackLanguage) {
switch apiLanguage { switch apiLanguage {
case let .langPackLanguage(language): case let .langPackLanguage(language):
self.init(languageCode: language.langCode, baseLanguageCode: language.baseLangCode, customPluralizationCode: language.pluralCode, title: language.name, localizedTitle: language.nativeName, isOfficial: (language.flags & (1 << 0)) != 0, totalStringCount: language.stringsCount, translatedStringCount: language.translatedCount) self.init(languageCode: language.langCode, baseLanguageCode: language.baseLangCode, customPluralizationCode: language.pluralCode, title: language.name, localizedTitle: language.nativeName, isOfficial: (language.flags & (1 << 0)) != 0, totalStringCount: language.stringsCount, translatedStringCount: language.translatedCount, platformUrl: language.translationsUrl)
} }
} }
} }

View File

@ -0,0 +1,102 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
#else
import Postbox
import SwiftSignalKit
#endif
public struct LocalizationListState: PreferencesEntry, Equatable {
public var availableOfficialLocalizations: [LocalizationInfo]
public var availableSavedLocalizations: [LocalizationInfo]
public static var defaultSettings: LocalizationListState {
return LocalizationListState(availableOfficialLocalizations: [], availableSavedLocalizations: [])
}
public init(availableOfficialLocalizations: [LocalizationInfo], availableSavedLocalizations: [LocalizationInfo]) {
self.availableOfficialLocalizations = availableOfficialLocalizations
self.availableSavedLocalizations = availableSavedLocalizations
}
public init(decoder: PostboxDecoder) {
self.availableOfficialLocalizations = decoder.decodeObjectArrayWithDecoderForKey("availableOfficialLocalizations")
self.availableSavedLocalizations = decoder.decodeObjectArrayWithDecoderForKey("availableSavedLocalizations")
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeObjectArray(self.availableOfficialLocalizations, forKey: "availableOfficialLocalizations")
encoder.encodeObjectArray(self.availableSavedLocalizations, forKey: "availableSavedLocalizations")
}
public func isEqual(to: PreferencesEntry) -> Bool {
guard let to = to as? LocalizationListState else {
return false
}
return self == to
}
}
public func removeSavedLocalization(transaction: Transaction, languageCode: String) {
updateLocalizationListStateInteractively(transaction: transaction, { state in
var state = state
state.availableSavedLocalizations = state.availableSavedLocalizations.filter({ $0.languageCode != languageCode })
return state
})
}
func updateLocalizationListStateInteractively(postbox: Postbox, _ f: @escaping (LocalizationListState) -> LocalizationListState) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
updateLocalizationListStateInteractively(transaction: transaction, f)
}
}
func updateLocalizationListStateInteractively(transaction: Transaction, _ f: @escaping (LocalizationListState) -> LocalizationListState) {
transaction.updatePreferencesEntry(key: PreferencesKeys.localizationListState, { current in
let previous = (current as? LocalizationListState) ?? LocalizationListState.defaultSettings
var updated = f(previous)
var removeOfficialIndices: [Int] = []
var officialSet = Set<String>()
for i in 0 ..< updated.availableOfficialLocalizations.count {
if officialSet.contains(updated.availableOfficialLocalizations[i].languageCode) {
removeOfficialIndices.append(i)
} else {
officialSet.insert(updated.availableOfficialLocalizations[i].languageCode)
}
}
for i in removeOfficialIndices.reversed() {
updated.availableOfficialLocalizations.remove(at: i)
}
var removeSavedIndices: [Int] = []
var savedSet = Set<String>()
for i in 0 ..< updated.availableSavedLocalizations.count {
if savedSet.contains(updated.availableSavedLocalizations[i].languageCode) {
removeSavedIndices.append(i)
} else {
savedSet.insert(updated.availableSavedLocalizations[i].languageCode)
}
}
for i in removeSavedIndices.reversed() {
updated.availableSavedLocalizations.remove(at: i)
}
return updated
})
}
public func synchronizedLocalizationListState(postbox: Postbox, network: Network) -> Signal<Never, NoError> {
return network.request(Api.functions.langpack.getLanguages(langPack: ""))
|> retryRequest
|> mapToSignal { languages -> Signal<Never, NoError> in
let infos: [LocalizationInfo] = languages.map(LocalizationInfo.init(apiLanguage:))
return postbox.transaction { transaction -> Void in
updateLocalizationListStateInteractively(transaction: transaction, { current in
var current = current
current.availableOfficialLocalizations = infos
return current
})
}
|> ignoreValues
}
}

View File

@ -7,23 +7,27 @@ import Foundation
public final class LocalizationComponent: Equatable, PostboxCoding { public final class LocalizationComponent: Equatable, PostboxCoding {
public let languageCode: String public let languageCode: String
public let localizedName: String
public let localization: Localization public let localization: Localization
public let customPluralizationCode: String? public let customPluralizationCode: String?
public init(languageCode: String, localization: Localization, customPluralizationCode: String?) { public init(languageCode: String, localizedName: String, localization: Localization, customPluralizationCode: String?) {
self.languageCode = languageCode self.languageCode = languageCode
self.localizedName = localizedName
self.localization = localization self.localization = localization
self.customPluralizationCode = customPluralizationCode self.customPluralizationCode = customPluralizationCode
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
self.languageCode = decoder.decodeStringForKey("lc", orElse: "") self.languageCode = decoder.decodeStringForKey("lc", orElse: "")
self.localizedName = decoder.decodeStringForKey("localizedName", orElse: "")
self.localization = decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization self.localization = decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization
self.customPluralizationCode = decoder.decodeOptionalStringForKey("cpl") self.customPluralizationCode = decoder.decodeOptionalStringForKey("cpl")
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
encoder.encodeString(self.languageCode, forKey: "lc") encoder.encodeString(self.languageCode, forKey: "lc")
encoder.encodeString(self.localizedName, forKey: "localizedName")
encoder.encodeObject(self.localization, forKey: "loc") encoder.encodeObject(self.localization, forKey: "loc")
if let customPluralizationCode = self.customPluralizationCode { if let customPluralizationCode = self.customPluralizationCode {
encoder.encodeString(customPluralizationCode, forKey: "cpl") encoder.encodeString(customPluralizationCode, forKey: "cpl")
@ -36,6 +40,9 @@ public final class LocalizationComponent: Equatable, PostboxCoding {
if lhs.languageCode != rhs.languageCode { if lhs.languageCode != rhs.languageCode {
return false return false
} }
if lhs.localizedName != rhs.localizedName {
return false
}
if lhs.localization != rhs.localization { if lhs.localization != rhs.localization {
return false return false
} }
@ -57,7 +64,7 @@ public final class LocalizationSettings: PreferencesEntry, Equatable {
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
if let languageCode = decoder.decodeOptionalStringForKey("lc") { if let languageCode = decoder.decodeOptionalStringForKey("lc") {
self.primaryComponent = LocalizationComponent(languageCode: languageCode, localization: decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization, customPluralizationCode: nil) self.primaryComponent = LocalizationComponent(languageCode: languageCode, localizedName: "", localization: decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization, customPluralizationCode: nil)
self.secondaryComponent = nil self.secondaryComponent = nil
} else { } else {
self.primaryComponent = decoder.decodeObjectForKey("primaryComponent", decoder: { LocalizationComponent(decoder: $0) }) as! LocalizationComponent self.primaryComponent = decoder.decodeObjectForKey("primaryComponent", decoder: { LocalizationComponent(decoder: $0) }) as! LocalizationComponent

View File

@ -139,11 +139,23 @@ public func downloadAndApplyLocalization(postbox: Postbox, network: Network, lan
} }
var secondaryComponent: LocalizationComponent? var secondaryComponent: LocalizationComponent?
if let secondaryCode = preview.baseLanguageCode, components.count > 1 { if let secondaryCode = preview.baseLanguageCode, components.count > 1 {
secondaryComponent = LocalizationComponent(languageCode: secondaryCode, localization: components[1], customPluralizationCode: nil) secondaryComponent = LocalizationComponent(languageCode: secondaryCode, localizedName: "", localization: components[1], customPluralizationCode: nil)
} }
return postbox.transaction { transaction -> Signal<Void, DownloadAndApplyLocalizationError> in return postbox.transaction { transaction -> Signal<Void, DownloadAndApplyLocalizationError> in
transaction.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in transaction.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in
return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: preview.languageCode, localization: primaryLocalization, customPluralizationCode: preview.customPluralizationCode), secondaryComponent: secondaryComponent) return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: preview.languageCode, localizedName: preview.localizedTitle, localization: primaryLocalization, customPluralizationCode: preview.customPluralizationCode), secondaryComponent: secondaryComponent)
})
updateLocalizationListStateInteractively(transaction: transaction, { state in
var state = state
for i in 0 ..< state.availableSavedLocalizations.count {
if state.availableSavedLocalizations[i].languageCode == preview.languageCode {
state.availableSavedLocalizations.remove(at: i)
break
}
}
state.availableSavedLocalizations.insert(preview, at: 0)
return state
}) })
network.context.updateApiEnvironment { current in network.context.updateApiEnvironment { current in

View File

@ -60,7 +60,7 @@ func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<V
return entry return entry
}) })
updateLimitsConfiguration(transaction: transaction, configuration: LimitsConfiguration(maxGroupMemberCount: config.chatSizeMax, maxSupergroupMemberCount: config.megagroupSizeMax, maxMessageForwardBatchSize: config.forwardedCountMax, maxSavedGifCount: config.savedGifsLimit, maxRecentStickerCount: config.stickersRecentLimit, maxMessageEditingInterval: config.editTimeLimit, maxMediaCaptionLength: config.captionLengthMax)) updateLimitsConfiguration(transaction: transaction, configuration: LimitsConfiguration(maxGroupMemberCount: config.chatSizeMax, maxSupergroupMemberCount: config.megagroupSizeMax, maxMessageForwardBatchSize: config.forwardedCountMax, maxSavedGifCount: config.savedGifsLimit, maxRecentStickerCount: config.stickersRecentLimit, maxMessageEditingInterval: config.editTimeLimit, maxMediaCaptionLength: config.captionLengthMax, canRemoveIncomingMessagesInPrivateChats: (config.flags & (1 << 6)) != 0))
let (primary, secondary) = getLocalization(transaction) let (primary, secondary) = getLocalization(transaction)
var invalidateLocalization = false var invalidateLocalization = false

View File

@ -174,7 +174,7 @@ private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: P
return postbox.transaction { transaction -> Signal<Void, SynchronizeLocalizationUpdatesError> in return postbox.transaction { transaction -> Signal<Void, SynchronizeLocalizationUpdatesError> in
let (primary, secondary) = getLocalization(transaction) let (primary, secondary) = getLocalization(transaction)
var currentSettings = transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings ?? LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: "en", localization: Localization(version: 0, entries: []), customPluralizationCode: nil), secondaryComponent: nil) var currentSettings = transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings ?? LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: "en", localizedName: "English", localization: Localization(version: 0, entries: []), customPluralizationCode: nil), secondaryComponent: nil)
for difference in parsedDifferences { for difference in parsedDifferences {
let current: (isPrimary: Bool, entries: [LocalizationEntry]) let current: (isPrimary: Bool, entries: [LocalizationEntry])
@ -205,9 +205,9 @@ private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: P
} }
mergedEntries.append(contentsOf: difference.entries) mergedEntries.append(contentsOf: difference.entries)
if current.isPrimary { if current.isPrimary {
currentSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent) currentSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localizedName: currentSettings.primaryComponent.localizedName, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent)
} else if let currentSecondary = currentSettings.secondaryComponent { } else if let currentSecondary = currentSettings.secondaryComponent {
currentSettings = LocalizationSettings(primaryComponent: currentSettings.primaryComponent, secondaryComponent: LocalizationComponent(languageCode: currentSecondary.languageCode, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSecondary.customPluralizationCode)) currentSettings = LocalizationSettings(primaryComponent: currentSettings.primaryComponent, secondaryComponent: LocalizationComponent(languageCode: currentSecondary.languageCode, localizedName: currentSecondary.localizedName, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSecondary.customPluralizationCode))
} }
} }
@ -284,13 +284,13 @@ func tryApplyingLanguageDifference(transaction: Transaction, langCode: String, d
} }
mergedEntries.append(contentsOf: updatedEntries) mergedEntries.append(contentsOf: updatedEntries)
let currentSettings = transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings ?? LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: "en", localization: Localization(version: 0, entries: []), customPluralizationCode: nil), secondaryComponent: nil) let currentSettings = transaction.getPreferencesEntry(key: PreferencesKeys.localizationSettings) as? LocalizationSettings ?? LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: "en", localizedName: "English", localization: Localization(version: 0, entries: []), customPluralizationCode: nil), secondaryComponent: nil)
var updatedSettings: LocalizationSettings var updatedSettings: LocalizationSettings
if isPrimary { if isPrimary {
updatedSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localization: Localization(version: updatedVersion, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent) updatedSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localizedName: currentSettings.primaryComponent.localizedName, localization: Localization(version: updatedVersion, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent)
} else if let currentSecondary = currentSettings.secondaryComponent { } else if let currentSecondary = currentSettings.secondaryComponent {
updatedSettings = LocalizationSettings(primaryComponent: currentSettings.primaryComponent, secondaryComponent: LocalizationComponent(languageCode: currentSecondary.languageCode, localization: Localization(version: updatedVersion, entries: mergedEntries), customPluralizationCode: currentSecondary.customPluralizationCode)) updatedSettings = LocalizationSettings(primaryComponent: currentSettings.primaryComponent, secondaryComponent: LocalizationComponent(languageCode: currentSecondary.languageCode, localizedName: currentSecondary.localizedName, localization: Localization(version: updatedVersion, entries: mergedEntries), customPluralizationCode: currentSecondary.customPluralizationCode))
} else { } else {
assertionFailure() assertionFailure()
return false return false

View File

@ -146,6 +146,7 @@ private enum PreferencesKeyValues: Int32 {
case remoteStorageConfiguration = 10 case remoteStorageConfiguration = 10
case voipConfiguration = 11 case voipConfiguration = 11
case appChangelogState = 12 case appChangelogState = 12
case localizationListState = 13
} }
public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey { public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey {
@ -226,6 +227,12 @@ public struct PreferencesKeys {
key.setInt32(0, value: PreferencesKeyValues.appChangelogState.rawValue) key.setInt32(0, value: PreferencesKeyValues.appChangelogState.rawValue)
return key return key
}() }()
public static let localizationListState: ValueBoxKey = {
let key = ValueBoxKey(length: 4)
key.setInt32(0, value: PreferencesKeyValues.localizationListState.rawValue)
return key
}()
} }
private enum SharedDataKeyValues: Int32 { private enum SharedDataKeyValues: Int32 {

View File

@ -202,7 +202,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization { public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt { public func currentLayer() -> UInt {
return 88 return 90
} }
public func parseMessage(_ data: Data!) -> Any! { public func parseMessage(_ data: Data!) -> Any! {

View File

@ -209,7 +209,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
} }
switch action { switch action {
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe: case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp:
break break
case let .messageActionChannelMigrateFrom(_, chatId): case let .messageActionChannelMigrateFrom(_, chatId):
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)) result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))

View File

@ -282,6 +282,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return nil return nil
case let .messageActionSecureValuesSent(types): case let .messageActionSecureValuesSent(types):
return TelegramMediaAction(action: .botSentSecureValues(types: types.map(SentSecureValueType.init))) return TelegramMediaAction(action: .botSentSecureValues(types: types.map(SentSecureValueType.init)))
case .messageActionContactSignUp:
return TelegramMediaAction(action: .peerJoined)
} }
} }

View File

@ -281,8 +281,6 @@ extension Api.Update {
case let .chatParticipantsForbidden(_, chatId, _): case let .chatParticipantsForbidden(_, chatId, _):
return [PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)] return [PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)]
} }
case let .updateContactRegistered(userId, _):
return [PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)]
case let .updateDeleteChannelMessages(channelId, _, _, _): case let .updateDeleteChannelMessages(channelId, _, _, _):
return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)] return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)]
case let .updateNewChannelMessage(message, _, _): case let .updateNewChannelMessage(message, _, _):