mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-15 18:59:54 +00:00
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:
parent
bf8ec5775f
commit
0b96d69daa
@ -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 = "<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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1680,6 +1683,7 @@
|
||||
D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */,
|
||||
D08CAA831ED8164B0000FDA8 /* Localization.swift */,
|
||||
D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */,
|
||||
D05D8B362192F8AF0064586F /* LocalizationListState.swift */,
|
||||
);
|
||||
name = Localization;
|
||||
sourceTree = "<group>";
|
||||
@ -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 */,
|
||||
|
||||
@ -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]
|
||||
}
|
||||
|
||||
@ -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<Void, NoError> {
|
||||
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<AccountRecordId>()
|
||||
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())
|
||||
}
|
||||
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -110,6 +110,11 @@ public final class AccountStateManager {
|
||||
return self.appliedIncomingReadMessagesPipe.signal()
|
||||
}
|
||||
|
||||
private let significantStateUpdateCompletedPipe = ValuePipe<Void>()
|
||||
var significantStateUpdateCompleted: Signal<Void, NoError> {
|
||||
return self.significantStateUpdateCompletedPipe.signal()
|
||||
}
|
||||
|
||||
private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:]
|
||||
|
||||
private let delayNotificatonsUntil = Atomic<Int32?>(value: nil)
|
||||
@ -424,6 +429,7 @@ public final class AccountStateManager {
|
||||
strongSelf.insertProcessEvents(events)
|
||||
}
|
||||
strongSelf.currentIsUpdatingValue = false
|
||||
strongSelf.significantStateUpdateCompletedPipe.putNext(Void())
|
||||
}
|
||||
} else {
|
||||
if !events.isEmpty {
|
||||
|
||||
@ -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) }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
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<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)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
|
||||
@ -15,8 +15,8 @@ public enum ConfirmTwoStepRecoveryEmailError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func confirmTwoStepRecoveryEmail(network: Network, email: String, code: String) -> Signal<Never, ConfirmTwoStepRecoveryEmailError> {
|
||||
return network.request(Api.functions.account.confirmPasswordEmail(email: email, code: code), automaticFloodWait: false)
|
||||
public func confirmTwoStepRecoveryEmail(network: Network, code: String) -> Signal<Never, ConfirmTwoStepRecoveryEmailError> {
|
||||
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<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
|
||||
}
|
||||
|
||||
@ -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)]) {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
102
TelegramCore/LocalizationListState.swift
Normal file
102
TelegramCore/LocalizationListState.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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<Void, DownloadAndApplyLocalizationError> 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
|
||||
|
||||
@ -60,7 +60,7 @@ func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<V
|
||||
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)
|
||||
var invalidateLocalization = false
|
||||
|
||||
@ -174,7 +174,7 @@ private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: P
|
||||
return postbox.transaction { transaction -> Signal<Void, SynchronizeLocalizationUpdatesError> 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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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! {
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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, _, _):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user