diff --git a/TelegramCore.xcodeproj/project.pbxproj b/TelegramCore.xcodeproj/project.pbxproj index 340c5748cb..16d18e9bd3 100644 --- a/TelegramCore.xcodeproj/project.pbxproj +++ b/TelegramCore.xcodeproj/project.pbxproj @@ -366,6 +366,8 @@ D05A32E51E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */; }; D05A32E71E6F0B5C002760B4 /* 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 */; }; D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.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 = ""; }; D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentAccountSessions.swift; sourceTree = ""; }; D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentAccountSession.swift; sourceTree = ""; }; + D05D8B362192F8AF0064586F /* LocalizationListState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationListState.swift; sourceTree = ""; }; D0613FC91E60440600202CDB /* InvitationLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvitationLinks.swift; sourceTree = ""; }; D0613FCE1E60520700202CDB /* ChannelMembers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelMembers.swift; sourceTree = ""; }; D0613FD61E606B3B00202CDB /* ConvertGroupToSupergroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertGroupToSupergroup.swift; sourceTree = ""; }; @@ -1680,6 +1683,7 @@ D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */, D08CAA831ED8164B0000FDA8 /* Localization.swift */, D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */, + D05D8B362192F8AF0064586F /* LocalizationListState.swift */, ); name = Localization; sourceTree = ""; @@ -2179,6 +2183,7 @@ D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */, D00C7CEB1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */, D09BB6B61DB0428000A905C0 /* PendingMessageUploadedContent.swift in Sources */, + D05D8B372192F8AF0064586F /* LocalizationListState.swift in Sources */, D0F3CC7D1DDE289E008148FA /* ResolvePeerByName.swift in Sources */, D0B843B71DA7FF30005F29E1 /* NBMetadataCoreMapper.m in Sources */, D0AB0B921D65E9FA002C78E7 /* ManagedServiceViews.swift in Sources */, @@ -2716,6 +2721,7 @@ D07047BB1F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift in Sources */, D0380DBB204EF306000414AB /* MessageMediaPreuploadManager.swift in Sources */, D050F2621E4A5AE700988324 /* GlobalNotificationSettings.swift in Sources */, + D05D8B382192F8AF0064586F /* LocalizationListState.swift in Sources */, D0DFD5E01FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */, D0B418991D7E0580004562A4 /* TelegramMediaMap.swift in Sources */, D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */, diff --git a/TelegramCore/Account.swift b/TelegramCore/Account.swift index 2c23b62baf..640b6ba5ee 100644 --- a/TelegramCore/Account.swift +++ b/TelegramCore/Account.swift @@ -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 - if let peer = peer as? TelegramChannel, let addressName = peer.addressName, !addressName.isEmpty { + if let peer = peer as? TelegramChannel { switch peer.info { case .group: - return [.publicGroups] + if let addressName = peer.addressName, !addressName.isEmpty { + return [.publicGroups] + } else { + return [.regularChatsAndPrivateGroups] + } case .broadcast: return [.channels] } diff --git a/TelegramCore/AccountManager.swift b/TelegramCore/AccountManager.swift index 195c2338a1..cf612dfc33 100644 --- a/TelegramCore/AccountManager.swift +++ b/TelegramCore/AccountManager.swift @@ -89,6 +89,7 @@ private var declaredEncodables: Void = { declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) }) declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) }) declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) }) + declareEncodable(LocalizationListState.self, f: { LocalizationListState(decoder: $0) }) declareEncodable(ProxySettings.self, f: { ProxySettings(decoder: $0) }) declareEncodable(NetworkSettings.self, f: { NetworkSettings(decoder: $0) }) declareEncodable(RemoteStorageConfiguration.self, f: { RemoteStorageConfiguration(decoder: $0) }) @@ -207,20 +208,20 @@ public func currentAccount(allocateIfNotExists: Bool, networkArguments: NetworkI initialKind = .authorized } let updatedKind = postbox.stateView() - |> map { view -> Bool in - let kind: AccountKind - if view.state is AuthorizedAccountState { - kind = .authorized - } else { - kind = .unauthorized - } - if kind != initialKind { - return true - } else { - return false - } + |> map { view -> Bool in + let kind: AccountKind + if view.state is AuthorizedAccountState { + kind = .authorized + } else { + kind = .unauthorized } - |> distinctUntilChanged + if kind != initialKind { + return true + } else { + return false + } + } + |> distinctUntilChanged return Signal { subscriber in subscriber.putNext(accountResult) @@ -242,28 +243,27 @@ public func currentAccount(allocateIfNotExists: Bool, networkArguments: NetworkI public func logoutFromAccount(id: AccountRecordId, accountManager: AccountManager) -> Signal { Logger.shared.log("AccountManager", "logoutFromAccount \(id)") return accountManager.transaction { transaction -> Void in - let currentId = transaction.getCurrentId() - if let currentId = currentId { - transaction.updateRecord(currentId, { current in - if let current = current { - var found = false - for attribute in current.attributes { - if attribute is LoggedOutAccountAttribute { - found = true - break - } + transaction.updateRecord(id, { current in + if let current = current { + var found = false + for attribute in current.attributes { + if attribute is LoggedOutAccountAttribute { + found = true + break } - if found { - return current - } else { - return AccountRecord(id: current.id, attributes: current.attributes + [LoggedOutAccountAttribute()], temporarySessionId: nil) - } - } else { - return nil } - }) - let id = transaction.createRecord([]) - transaction.setCurrentId(id) + if found { + return current + } 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 beginList: [(AccountRecordId, MetaDisposable)] = [] let _ = loggedOutAccounts.modify { disposables in - let validIds = Set(view.records.filter { - for attribute in $0.attributes { + var validIds = Set() + outer: for record in view.records { + for attribute in record.attributes { if attribute is LoggedOutAccountAttribute { - return true + validIds.insert(record.id) + continue outer } } - return false - }.map { $0.id }) + } var disposables = disposables @@ -320,7 +321,7 @@ public func managedCleanupAccounts(networkArguments: NetworkInitializationArgume disposable.dispose() } 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()) } diff --git a/TelegramCore/AccountStateManagementUtils.swift b/TelegramCore/AccountStateManagementUtils.swift index fe2b76886c..3e29365911 100644 --- a/TelegramCore/AccountStateManagementUtils.swift +++ b/TelegramCore/AccountStateManagementUtils.swift @@ -101,13 +101,6 @@ private func locallyGeneratedMessageTimestampsFromUpdateGroups(_ groups: [Update 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: break } @@ -306,13 +299,6 @@ private func locallyGeneratedMessageTimestampsFromDifference(_ difference: Api.u 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: break } @@ -920,25 +906,6 @@ private func finalStateWithUpdatesAndServerTime(account: Account, state: Account } else { 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): updatedState.readInbox(MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: maxId)) case let .updateReadChannelOutbox(channelId, maxId): diff --git a/TelegramCore/AccountStateManager.swift b/TelegramCore/AccountStateManager.swift index 41fda4b343..0550337937 100644 --- a/TelegramCore/AccountStateManager.swift +++ b/TelegramCore/AccountStateManager.swift @@ -110,6 +110,11 @@ public final class AccountStateManager { return self.appliedIncomingReadMessagesPipe.signal() } + private let significantStateUpdateCompletedPipe = ValuePipe() + var significantStateUpdateCompleted: Signal { + return self.significantStateUpdateCompletedPipe.signal() + } + private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:] private let delayNotificatonsUntil = Atomic(value: nil) @@ -424,6 +429,7 @@ public final class AccountStateManager { strongSelf.insertProcessEvents(events) } strongSelf.currentIsUpdatingValue = false + strongSelf.significantStateUpdateCompletedPipe.putNext(Void()) } } else { if !events.isEmpty { diff --git a/TelegramCore/Api0.swift b/TelegramCore/Api0.swift index 604e3dd038..d419375d9f 100644 --- a/TelegramCore/Api0.swift +++ b/TelegramCore/Api0.swift @@ -89,7 +89,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1343524562] = { return Api.InputChannel.parse_inputChannel($0) } dict[414687501] = { return Api.DcOption.parse_dcOption($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[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($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[-1489818765] = { return Api.Update.parse_updateUserName($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[314359194] = { return Api.Update.parse_updateNewEncryptedMessage($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[455635795] = { return Api.MessageAction.parse_messageActionSecureValuesSentMe($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[462375633] = { return Api.PhoneCall.parse_phoneCallWaiting($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[-1353671392] = { return Api.PeerNotifySettings.parse_peerNotifySettings($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[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) } dict[-715532088] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) } diff --git a/TelegramCore/Api1.swift b/TelegramCore/Api1.swift index 33cac029fd..c4a83c5ba9 100644 --- a/TelegramCore/Api1.swift +++ b/TelegramCore/Api1.swift @@ -2362,13 +2362,13 @@ extension Api { } 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) { 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 { - buffer.appendInt32(106019213) + buffer.appendInt32(-288727837) } serializeInt32(flags, buffer: buffer, boxed: false) serializeString(name, buffer: buffer, boxed: false) @@ -2378,14 +2378,15 @@ extension Api { serializeString(pluralCode, buffer: buffer, boxed: false) serializeInt32(stringsCount, buffer: buffer, boxed: false) serializeInt32(translatedCount, buffer: buffer, boxed: false) + serializeString(translationsUrl, buffer: buffer, boxed: false) break } } func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount): - return ("langPackLanguage", [("flags", flags), ("name", name), ("nativeName", nativeName), ("langCode", langCode), ("baseLangCode", baseLangCode), ("pluralCode", pluralCode), ("stringsCount", stringsCount), ("translatedCount", 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), ("translationsUrl", translationsUrl)]) } } @@ -2406,6 +2407,8 @@ extension Api { _7 = reader.readInt32() var _8: Int32? _8 = reader.readInt32() + var _9: String? + _9 = parseString(reader) let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -2414,8 +2417,9 @@ extension Api { let _c6 = _6 != nil let _c7 = _7 != nil let _c8 = _8 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { - return Api.LangPackLanguage.langPackLanguage(flags: _1!, name: _2!, nativeName: _3!, langCode: _4!, baseLangCode: _5, pluralCode: _6!, stringsCount: _7!, translatedCount: _8!) + let _c9 = _9 != nil + 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 { return nil @@ -3337,7 +3341,6 @@ extension Api { case updateUserStatus(userId: Int32, status: Api.UserStatus) case updateUserName(userId: Int32, firstName: String, lastName: String, username: String) 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 updateNewEncryptedMessage(message: Api.EncryptedMessage, qts: Int32) case updateEncryptedChatTyping(chatId: Int32) @@ -3473,13 +3476,6 @@ extension Api { photo.serialize(buffer, true) previous.serialize(buffer, true) 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): if boxed { buffer.appendInt32(-1657903163) @@ -3988,8 +3984,6 @@ extension Api { return ("updateUserName", [("userId", userId), ("firstName", firstName), ("lastName", lastName), ("username", username)]) case .updateUserPhoto(let userId, let date, let photo, let 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): return ("updateContactLink", [("userId", userId), ("myLink", myLink), ("foreignLink", foreignLink)]) case .updateNewEncryptedMessage(let message, let qts): @@ -4271,20 +4265,6 @@ extension Api { 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? { var _1: Int32? _1 = reader.readInt32() @@ -15158,6 +15138,7 @@ extension Api { case messageActionBotAllowed(domain: String) case messageActionSecureValuesSentMe(values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted) case messageActionSecureValuesSent(types: [Api.SecureValueType]) + case messageActionContactSignUp(flags: Int32) func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -15323,6 +15304,12 @@ extension Api { item.serialize(buffer, true) } 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)]) case .messageActionSecureValuesSent(let types): return ("messageActionSecureValuesSent", [("types", types)]) + case .messageActionContactSignUp(let flags): + return ("messageActionContactSignUp", [("flags", flags)]) } } @@ -15637,6 +15626,17 @@ extension Api { 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 { @@ -16258,13 +16258,13 @@ extension Api { } 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) { 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 { - buffer.appendInt32(-242812612) + buffer.appendInt32(-1282352120) } serializeInt32(flags, 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 << 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 << 3) != 0 {serializeString(author!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeInt32(publishedDate!, buffer: buffer, boxed: false)} break } } func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .pageRelatedArticle(let flags, let url, let webpageId, let title, let description, let photoId): - return ("pageRelatedArticle", [("flags", flags), ("url", url), ("webpageId", webpageId), ("title", title), ("description", description), ("photoId", 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), ("author", author), ("publishedDate", publishedDate)]) } } @@ -16296,14 +16298,20 @@ extension Api { if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } var _6: Int64? 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 _c2 = _2 != nil let _c3 = _3 != nil let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.PageRelatedArticle.pageRelatedArticle(flags: _1!, url: _2!, webpageId: _3!, title: _4, description: _5, photoId: _6) + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + 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 { return nil diff --git a/TelegramCore/Api3.swift b/TelegramCore/Api3.swift index 0572fd3d2f..8f13cded86 100644 --- a/TelegramCore/Api3.swift +++ b/TelegramCore/Api3.swift @@ -4939,12 +4939,53 @@ extension Api { }) } - static func confirmPasswordEmail(email: String, code: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func confirmPasswordEmail(code: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-558870880) - serializeString(email, buffer: buffer, boxed: false) + buffer.appendInt32(-1881204448) 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) { + 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) { + 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) { + 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) var result: Api.Bool? if let signature = reader.readInt32() { diff --git a/TelegramCore/ConfirmTwoStepRecoveryEmail.swift b/TelegramCore/ConfirmTwoStepRecoveryEmail.swift index c3e9ca2b65..3231aeb640 100644 --- a/TelegramCore/ConfirmTwoStepRecoveryEmail.swift +++ b/TelegramCore/ConfirmTwoStepRecoveryEmail.swift @@ -15,8 +15,8 @@ public enum ConfirmTwoStepRecoveryEmailError { case generic } -public func confirmTwoStepRecoveryEmail(network: Network, email: String, code: String) -> Signal { - return network.request(Api.functions.account.confirmPasswordEmail(email: email, code: code), automaticFloodWait: false) +public func confirmTwoStepRecoveryEmail(network: Network, code: String) -> Signal { + return network.request(Api.functions.account.confirmPasswordEmail(code: code), automaticFloodWait: false) |> mapError { error -> ConfirmTwoStepRecoveryEmailError in if error.errorDescription == "EMAIL_INVALID" { return .invalidEmail @@ -31,3 +31,19 @@ public func confirmTwoStepRecoveryEmail(network: Network, email: String, code: S } |> ignoreValues } + +public enum ResendTwoStepRecoveryEmailError { + case flood + case generic +} + +public func resendTwoStepRecoveryEmail(network: Network) -> Signal { + return network.request(Api.functions.account.resendPasswordEmail(), automaticFloodWait: false) + |> mapError { error -> ResendTwoStepRecoveryEmailError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .flood + } + return .generic + } + |> ignoreValues +} diff --git a/TelegramCore/ContactSyncManager.swift b/TelegramCore/ContactSyncManager.swift index 2907b9fdd0..486c2cd825 100644 --- a/TelegramCore/ContactSyncManager.swift +++ b/TelegramCore/ContactSyncManager.swift @@ -35,9 +35,11 @@ private final class ContactSyncManagerImpl { private var nextId: Int32 = 0 private var operations: [ContactSyncOperation] = [] + private var lastContactPresencesRequestTimestamp: Double? private var reimportAttempts: [TelegramDeviceContactImportIdentifier: Double] = [:] private let importableContactsDisposable = MetaDisposable() + private let significantStateUpdateCompletedDisposable = MetaDisposable() init(queue: Queue, postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager) { self.queue = queue @@ -61,6 +63,36 @@ private final class ContactSyncManagerImpl { strongSelf.addOperation(.updatePresences) 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)]) { diff --git a/TelegramCore/InstantPage.swift b/TelegramCore/InstantPage.swift index 5c8bcfa3e2..52782caa6f 100644 --- a/TelegramCore/InstantPage.swift +++ b/TelegramCore/InstantPage.swift @@ -950,7 +950,7 @@ extension InstantPageTableRow { extension InstantPageRelatedArticle { convenience init(apiRelatedArticle: Api.PageRelatedArticle) { 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? if let photoId = photoId { posterPhotoId = MediaId(namespace: Namespaces.Media.CloudImage, id: photoId) diff --git a/TelegramCore/LimitsConfiguration.swift b/TelegramCore/LimitsConfiguration.swift index 121cf7b03b..5b7254c33c 100644 --- a/TelegramCore/LimitsConfiguration.swift +++ b/TelegramCore/LimitsConfiguration.swift @@ -5,20 +5,21 @@ import Foundation import Postbox #endif -public final class LimitsConfiguration: PreferencesEntry { - public let maxGroupMemberCount: Int32 - public let maxSupergroupMemberCount: Int32 - public let maxMessageForwardBatchSize: Int32 - public let maxSavedGifCount: Int32 - public let maxRecentStickerCount: Int32 - public let maxMessageEditingInterval: Int32 - public let maxMediaCaptionLength: Int32 +public struct LimitsConfiguration: Equatable, PreferencesEntry { + public var maxGroupMemberCount: Int32 + public var maxSupergroupMemberCount: Int32 + public var maxMessageForwardBatchSize: Int32 + public var maxSavedGifCount: Int32 + public var maxRecentStickerCount: Int32 + public var maxMessageEditingInterval: Int32 + public var maxMediaCaptionLength: Int32 + public var canRemoveIncomingMessagesInPrivateChats: Bool 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.maxSupergroupMemberCount = maxSupergroupMemberCount self.maxMessageForwardBatchSize = maxMessageForwardBatchSize @@ -26,6 +27,7 @@ public final class LimitsConfiguration: PreferencesEntry { self.maxRecentStickerCount = maxRecentStickerCount self.maxMessageEditingInterval = maxMessageEditingInterval self.maxMediaCaptionLength = maxMediaCaptionLength + self.canRemoveIncomingMessagesInPrivateChats = canRemoveIncomingMessagesInPrivateChats } public init(decoder: PostboxDecoder) { @@ -36,6 +38,7 @@ public final class LimitsConfiguration: PreferencesEntry { self.maxRecentStickerCount = decoder.decodeInt32ForKey("maxRecentStickerCount", orElse: 20) self.maxMessageEditingInterval = decoder.decodeInt32ForKey("maxMessageEditingInterval", orElse: 2 * 24 * 60 * 60) self.maxMediaCaptionLength = decoder.decodeInt32ForKey("maxMediaCaptionLength", orElse: 1000) + self.canRemoveIncomingMessagesInPrivateChats = decoder.decodeInt32ForKey("canRemoveIncomingMessagesInPrivateChats", orElse: 0) != 0 } public func encode(_ encoder: PostboxEncoder) { @@ -46,34 +49,14 @@ public final class LimitsConfiguration: PreferencesEntry { encoder.encodeInt32(self.maxRecentStickerCount, forKey: "maxRecentStickerCount") encoder.encodeInt32(self.maxMessageEditingInterval, forKey: "maxMessageEditingInterval") encoder.encodeInt32(self.maxMediaCaptionLength, forKey: "maxMediaCaptionLength") + encoder.encodeInt32(self.canRemoveIncomingMessagesInPrivateChats ? 1 : 0, forKey: "canRemoveIncomingMessagesInPrivateChats") } public func isEqual(to: PreferencesEntry) -> Bool { guard let to = to as? LimitsConfiguration else { return false } - if self.maxGroupMemberCount != to.maxGroupMemberCount { - 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 + return self == to } } diff --git a/TelegramCore/LocalizationInfo.swift b/TelegramCore/LocalizationInfo.swift index 6621a442b2..7f40c85ea0 100644 --- a/TelegramCore/LocalizationInfo.swift +++ b/TelegramCore/LocalizationInfo.swift @@ -5,7 +5,7 @@ import Foundation import Postbox #endif -public final class LocalizationInfo: PostboxCoding { +public struct LocalizationInfo: PostboxCoding, Equatable { public let languageCode: String public let baseLanguageCode: String? public let customPluralizationCode: String? @@ -14,8 +14,9 @@ public final class LocalizationInfo: PostboxCoding { public let isOfficial: Bool public let totalStringCount: 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.baseLanguageCode = baseLanguageCode self.customPluralizationCode = customPluralizationCode @@ -24,6 +25,7 @@ public final class LocalizationInfo: PostboxCoding { self.isOfficial = isOfficial self.totalStringCount = totalStringCount self.translatedStringCount = translatedStringCount + self.platformUrl = platformUrl } public init(decoder: PostboxDecoder) { @@ -35,6 +37,7 @@ public final class LocalizationInfo: PostboxCoding { self.isOfficial = decoder.decodeInt32ForKey("of", orElse: 0) != 0 self.totalStringCount = decoder.decodeInt32ForKey("tsc", orElse: 0) self.translatedStringCount = decoder.decodeInt32ForKey("lsc", orElse: 0) + self.platformUrl = decoder.decodeStringForKey("platformUrl", orElse: "") } 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.totalStringCount, forKey: "tsc") encoder.encodeInt32(self.translatedStringCount, forKey: "lsc") + encoder.encodeString(self.platformUrl, forKey: "platformUrl") } } extension LocalizationInfo { - convenience init(apiLanguage: Api.LangPackLanguage) { + init(apiLanguage: Api.LangPackLanguage) { switch apiLanguage { 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) } } } diff --git a/TelegramCore/LocalizationListState.swift b/TelegramCore/LocalizationListState.swift new file mode 100644 index 0000000000..bfbb48c39f --- /dev/null +++ b/TelegramCore/LocalizationListState.swift @@ -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 { + 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() + 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() + 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 { + return network.request(Api.functions.langpack.getLanguages(langPack: "")) + |> retryRequest + |> mapToSignal { languages -> Signal 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 + } +} diff --git a/TelegramCore/LocalizationSettings.swift b/TelegramCore/LocalizationSettings.swift index 67454db9c9..4328477ffd 100644 --- a/TelegramCore/LocalizationSettings.swift +++ b/TelegramCore/LocalizationSettings.swift @@ -7,23 +7,27 @@ import Foundation public final class LocalizationComponent: Equatable, PostboxCoding { public let languageCode: String + public let localizedName: String public let localization: Localization 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.localizedName = localizedName self.localization = localization self.customPluralizationCode = customPluralizationCode } public init(decoder: PostboxDecoder) { self.languageCode = decoder.decodeStringForKey("lc", orElse: "") + self.localizedName = decoder.decodeStringForKey("localizedName", orElse: "") self.localization = decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization self.customPluralizationCode = decoder.decodeOptionalStringForKey("cpl") } public func encode(_ encoder: PostboxEncoder) { encoder.encodeString(self.languageCode, forKey: "lc") + encoder.encodeString(self.localizedName, forKey: "localizedName") encoder.encodeObject(self.localization, forKey: "loc") if let customPluralizationCode = self.customPluralizationCode { encoder.encodeString(customPluralizationCode, forKey: "cpl") @@ -36,6 +40,9 @@ public final class LocalizationComponent: Equatable, PostboxCoding { if lhs.languageCode != rhs.languageCode { return false } + if lhs.localizedName != rhs.localizedName { + return false + } if lhs.localization != rhs.localization { return false } @@ -57,7 +64,7 @@ public final class LocalizationSettings: PreferencesEntry, Equatable { public init(decoder: PostboxDecoder) { if let languageCode = decoder.decodeOptionalStringForKey("lc") { - self.primaryComponent = LocalizationComponent(languageCode: languageCode, localization: decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization, customPluralizationCode: nil) + self.primaryComponent = LocalizationComponent(languageCode: languageCode, localizedName: "", localization: decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization, customPluralizationCode: nil) self.secondaryComponent = nil } else { self.primaryComponent = decoder.decodeObjectForKey("primaryComponent", decoder: { LocalizationComponent(decoder: $0) }) as! LocalizationComponent diff --git a/TelegramCore/Localizations.swift b/TelegramCore/Localizations.swift index 9c502b140d..47ef42b7e9 100644 --- a/TelegramCore/Localizations.swift +++ b/TelegramCore/Localizations.swift @@ -139,11 +139,23 @@ public func downloadAndApplyLocalization(postbox: Postbox, network: Network, lan } var secondaryComponent: LocalizationComponent? 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 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 diff --git a/TelegramCore/ManagedConfigurationUpdates.swift b/TelegramCore/ManagedConfigurationUpdates.swift index 3872452fc9..f858532d47 100644 --- a/TelegramCore/ManagedConfigurationUpdates.swift +++ b/TelegramCore/ManagedConfigurationUpdates.swift @@ -60,7 +60,7 @@ func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal Signal in 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 { let current: (isPrimary: Bool, entries: [LocalizationEntry]) @@ -205,9 +205,9 @@ private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: P } mergedEntries.append(contentsOf: difference.entries) if current.isPrimary { - currentSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent) + 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 { - 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) - 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 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 { - 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 { assertionFailure() return false diff --git a/TelegramCore/Namespaces.swift b/TelegramCore/Namespaces.swift index 4469de5c48..8efb7ecfdb 100644 --- a/TelegramCore/Namespaces.swift +++ b/TelegramCore/Namespaces.swift @@ -146,6 +146,7 @@ private enum PreferencesKeyValues: Int32 { case remoteStorageConfiguration = 10 case voipConfiguration = 11 case appChangelogState = 12 + case localizationListState = 13 } public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey { @@ -226,6 +227,12 @@ public struct PreferencesKeys { key.setInt32(0, value: PreferencesKeyValues.appChangelogState.rawValue) 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 { diff --git a/TelegramCore/Serialization.swift b/TelegramCore/Serialization.swift index f11dded846..9f0fa9fe29 100644 --- a/TelegramCore/Serialization.swift +++ b/TelegramCore/Serialization.swift @@ -202,7 +202,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 88 + return 90 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/TelegramCore/StoreMessage_Telegram.swift b/TelegramCore/StoreMessage_Telegram.swift index 855db016ee..246c71f608 100644 --- a/TelegramCore/StoreMessage_Telegram.swift +++ b/TelegramCore/StoreMessage_Telegram.swift @@ -209,7 +209,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { } 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 case let .messageActionChannelMigrateFrom(_, chatId): result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)) diff --git a/TelegramCore/TelegramMediaAction.swift b/TelegramCore/TelegramMediaAction.swift index 2d3142c99b..c27e6b5093 100644 --- a/TelegramCore/TelegramMediaAction.swift +++ b/TelegramCore/TelegramMediaAction.swift @@ -282,6 +282,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe return nil case let .messageActionSecureValuesSent(types): return TelegramMediaAction(action: .botSentSecureValues(types: types.map(SentSecureValueType.init))) + case .messageActionContactSignUp: + return TelegramMediaAction(action: .peerJoined) } } diff --git a/TelegramCore/UpdatesApiUtils.swift b/TelegramCore/UpdatesApiUtils.swift index ead41ef055..3385f67292 100644 --- a/TelegramCore/UpdatesApiUtils.swift +++ b/TelegramCore/UpdatesApiUtils.swift @@ -281,8 +281,6 @@ extension Api.Update { case let .chatParticipantsForbidden(_, 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, _, _, _): return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)] case let .updateNewChannelMessage(message, _, _):