diff --git a/TelegramCore/Account.swift b/TelegramCore/Account.swift index 9a32b874b5..74d767d245 100644 --- a/TelegramCore/Account.swift +++ b/TelegramCore/Account.swift @@ -101,7 +101,7 @@ public func ==(lhs: AuthorizedAccountState.State, rhs: AuthorizedAccountState.St public class UnauthorizedAccount { public let networkArguments: NetworkInitializationArguments public let id: AccountRecordId - public let appGroupPath: String + public let rootPath: String public let basePath: String public let testingEnvironment: Bool public let postbox: Postbox @@ -113,10 +113,10 @@ public class UnauthorizedAccount { public let shouldBeServiceTaskMaster = Promise() - init(networkArguments: NetworkInitializationArguments, id: AccountRecordId, appGroupPath: String, basePath: String, testingEnvironment: Bool, postbox: Postbox, network: Network, shouldKeepAutoConnection: Bool = true) { + init(networkArguments: NetworkInitializationArguments, id: AccountRecordId, rootPath: String, basePath: String, testingEnvironment: Bool, postbox: Postbox, network: Network, shouldKeepAutoConnection: Bool = true) { self.networkArguments = networkArguments self.id = id - self.appGroupPath = appGroupPath + self.rootPath = rootPath self.basePath = basePath self.testingEnvironment = testingEnvironment self.postbox = postbox @@ -150,7 +150,7 @@ public class UnauthorizedAccount { } |> mapToSignal { (localizationSettings, proxySettings) -> Signal in return initializedNetwork(arguments: self.networkArguments, supplementary: false, datacenterId: Int(masterDatacenterId), keychain: keychain, basePath: self.basePath, testingEnvironment: self.testingEnvironment, languageCode: localizationSettings?.languageCode, proxySettings: proxySettings) |> map { network in - let updated = UnauthorizedAccount(networkArguments: self.networkArguments, id: self.id, appGroupPath: self.appGroupPath, basePath: self.basePath, testingEnvironment: self.testingEnvironment, postbox: self.postbox, network: network) + let updated = UnauthorizedAccount(networkArguments: self.networkArguments, id: self.id, rootPath: self.rootPath, basePath: self.basePath, testingEnvironment: self.testingEnvironment, postbox: self.postbox, network: network) updated.shouldBeServiceTaskMaster.set(self.shouldBeServiceTaskMaster.get()) return updated } @@ -273,10 +273,10 @@ public enum AccountResult { case authorized(Account) } -public func accountWithId(networkArguments: NetworkInitializationArguments, id: AccountRecordId, supplementary: Bool, appGroupPath: String, testingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal { +public func accountWithId(networkArguments: NetworkInitializationArguments, id: AccountRecordId, supplementary: Bool, rootPath: String, testingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal { let _ = declaredEncodables - let path = "\(appGroupPath)/\(accountRecordIdPathName(id))" + let path = "\(rootPath)/\(accountRecordIdPathName(id))" var initializeMessageNamespacesWithHoles: [(PeerId.Namespace, MessageId.Namespace)] = [] for peerNamespace in peerIdNamespacesWithInitialCloudMessageHoles { @@ -313,7 +313,7 @@ public func accountWithId(networkArguments: NetworkInitializationArguments, id: case let unauthorizedState as UnauthorizedAccountState: return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: Int(unauthorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: testingEnvironment, languageCode: localizationSettings?.languageCode, proxySettings: proxySettings) |> map { network -> AccountResult in - return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, appGroupPath: appGroupPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) + return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) } case let authorizedState as AuthorizedAccountState: return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: Int(authorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: testingEnvironment, languageCode: localizationSettings?.languageCode, proxySettings: proxySettings) @@ -327,7 +327,7 @@ public func accountWithId(networkArguments: NetworkInitializationArguments, id: return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: 2, keychain: keychain, basePath: path, testingEnvironment: testingEnvironment, languageCode: localizationSettings?.languageCode, proxySettings: proxySettings) |> map { network -> AccountResult in - return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, appGroupPath: appGroupPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) + return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) } } } diff --git a/TelegramCore/AccountManager.swift b/TelegramCore/AccountManager.swift index 32ca01bbbb..cec1a5f19e 100644 --- a/TelegramCore/AccountManager.swift +++ b/TelegramCore/AccountManager.swift @@ -14,7 +14,34 @@ private enum AccountKind { case unauthorized } -public func currentAccount(networkArguments: NetworkInitializationArguments, supplementary: Bool, manager: AccountManager, appGroupPath: String, testingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal { +public func rootPathForBasePath(_ appGroupPath: String) -> String { + return appGroupPath + "/telegram-data" +} + +public func performAppGroupUpgrades(appGroupPath: String, rootPath: String) { + let _ = try? FileManager.default.createDirectory(at: URL(fileURLWithPath: rootPath), withIntermediateDirectories: true, attributes: nil) + + do { + var resourceValues = URLResourceValues() + resourceValues.isExcludedFromBackup = true + var mutableUrl = URL(fileURLWithPath: rootPath) + try mutableUrl.setResourceValues(resourceValues) + } catch let e { + print("\(e)") + } + + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: appGroupPath), includingPropertiesForKeys: [], options: []) { + for url in files { + if url.lastPathComponent == "accounts-metadata" || + url.lastPathComponent.hasSuffix("logs") || + url.lastPathComponent.hasPrefix("account-") { + let _ = try? FileManager.default.moveItem(at: url, to: URL(fileURLWithPath: rootPath + "/" + url.lastPathComponent)) + } + } + } +} + +public func currentAccount(networkArguments: NetworkInitializationArguments, supplementary: Bool, manager: AccountManager, rootPath: String, testingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal { return manager.allocatedCurrentAccountId() |> distinctUntilChanged(isEqual: { lhs, rhs in return lhs == rhs @@ -23,7 +50,7 @@ public func currentAccount(networkArguments: NetworkInitializationArguments, sup if let id = id { let reload = ValuePromise(true, ignoreRepeated: false) return reload.get() |> mapToSignal { _ -> Signal in - return accountWithId(networkArguments: networkArguments, id: id, supplementary: supplementary, appGroupPath: appGroupPath, testingEnvironment: testingEnvironment, auxiliaryMethods: auxiliaryMethods) + return accountWithId(networkArguments: networkArguments, id: id, supplementary: supplementary, rootPath: rootPath, testingEnvironment: testingEnvironment, auxiliaryMethods: auxiliaryMethods) |> mapToSignal { accountResult -> Signal in let postbox: Postbox let initialKind: AccountKind @@ -98,7 +125,7 @@ public func logoutFromAccount(id: AccountRecordId, accountManager: AccountManage } } -public func managedCleanupAccounts(networkArguments: NetworkInitializationArguments, accountManager: AccountManager, appGroupPath: String, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal { +public func managedCleanupAccounts(networkArguments: NetworkInitializationArguments, accountManager: AccountManager, rootPath: String, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal { return Signal { subscriber in let loggedOutAccounts = Atomic<[AccountRecordId: MetaDisposable]>(value: [:]) let disposable = accountManager.accountRecords().start(next: { view in @@ -114,7 +141,6 @@ public func managedCleanupAccounts(networkArguments: NetworkInitializationArgume return false }.map { $0.id }) - var disposables = disposables for id in disposables.keys { @@ -141,7 +167,22 @@ public func managedCleanupAccounts(networkArguments: NetworkInitializationArgume disposable.dispose() } for (id, disposable) in beginList { - disposable.set(cleanupAccount(networkArguments: networkArguments, accountManager: accountManager, id: id, appGroupPath: appGroupPath, auxiliaryMethods: auxiliaryMethods).start()) + disposable.set(cleanupAccount(networkArguments: networkArguments, accountManager: accountManager, id: id, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods).start()) + } + + var validPaths = Set() + for record in view.records { + validPaths.insert("\(accountRecordIdPathName(record.id))") + } + + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: rootPath), includingPropertiesForKeys: [], options: []) { + for url in files { + if url.lastPathComponent.hasPrefix("account-") { + if !validPaths.contains(url.lastPathComponent) { + try? FileManager.default.removeItem(at: url) + } + } + } } }) @@ -151,9 +192,8 @@ public func managedCleanupAccounts(networkArguments: NetworkInitializationArgume } } - -private func cleanupAccount(networkArguments: NetworkInitializationArguments, accountManager: AccountManager, id: AccountRecordId, appGroupPath: String, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal { - return accountWithId(networkArguments: networkArguments, id: id, supplementary: true, appGroupPath: appGroupPath, testingEnvironment: false, auxiliaryMethods: auxiliaryMethods) +private func cleanupAccount(networkArguments: NetworkInitializationArguments, accountManager: AccountManager, id: AccountRecordId, rootPath: String, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal { + return accountWithId(networkArguments: networkArguments, id: id, supplementary: true, rootPath: rootPath, testingEnvironment: false, auxiliaryMethods: auxiliaryMethods) |> mapToSignal { account -> Signal in switch account { case .upgrading: diff --git a/TelegramCore/ApplyMaxReadIndexInteractively.swift b/TelegramCore/ApplyMaxReadIndexInteractively.swift index 6cd904a238..c2d396781f 100644 --- a/TelegramCore/ApplyMaxReadIndexInteractively.swift +++ b/TelegramCore/ApplyMaxReadIndexInteractively.swift @@ -7,40 +7,44 @@ import Foundation import SwiftSignalKit #endif -public func applyMaxReadIndexInteractively(postbox: Postbox, network: Network, stateManager: AccountStateManager, index: MessageIndex) -> Signal { +public func applyMaxReadIndexInteractively(postbox: Postbox, stateManager: AccountStateManager, index: MessageIndex) -> Signal { return postbox.modify { modifier -> Void in - let messageIds = modifier.applyInteractiveReadMaxIndex(index) - if index.id.peerId.namespace == Namespaces.Peer.SecretChat { - let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - for id in messageIds { - if let message = modifier.getMessage(id) { - for attribute in message.attributes { - if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { - if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && !message.containsSecretMedia { - modifier.updateMessage(message.id, update: { currentMessage in - var storeForwardInfo: StoreMessageForwardInfo? - if let forwardInfo = currentMessage.forwardInfo { - storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + applyMaxReadIndexInteractively(modifier: modifier, stateManager: stateManager, index: index) + } +} + +func applyMaxReadIndexInteractively(modifier: Modifier, stateManager: AccountStateManager, index: MessageIndex) { + let messageIds = modifier.applyInteractiveReadMaxIndex(index) + if index.id.peerId.namespace == Namespaces.Peer.SecretChat { + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + for id in messageIds { + if let message = modifier.getMessage(id) { + for attribute in message.attributes { + if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { + if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && !message.containsSecretMedia { + modifier.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + let updatedAttributes = currentMessage.attributes.map({ currentAttribute -> MessageAttribute in + if let currentAttribute = currentAttribute as? AutoremoveTimeoutMessageAttribute { + return AutoremoveTimeoutMessageAttribute(timeout: currentAttribute.timeout, countdownBeginTime: timestamp) + } else { + return currentAttribute } - let updatedAttributes = currentMessage.attributes.map({ currentAttribute -> MessageAttribute in - if let currentAttribute = currentAttribute as? AutoremoveTimeoutMessageAttribute { - return AutoremoveTimeoutMessageAttribute(timeout: currentAttribute.timeout, countdownBeginTime: timestamp) - } else { - return currentAttribute - } - }) - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)) }) - modifier.addTimestampBasedMessageAttribute(tag: 0, timestamp: timestamp + attribute.timeout, messageId: id) - } - break + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)) + }) + modifier.addTimestampBasedMessageAttribute(tag: 0, timestamp: timestamp + attribute.timeout, messageId: id) } + break } } } - } else if index.id.peerId.namespace == Namespaces.Peer.CloudUser || index.id.peerId.namespace == Namespaces.Peer.CloudGroup || index.id.peerId.namespace == Namespaces.Peer.CloudChannel { - stateManager.notifyAppliedIncomingReadMessages([index.id]) } + } else if index.id.peerId.namespace == Namespaces.Peer.CloudUser || index.id.peerId.namespace == Namespaces.Peer.CloudGroup || index.id.peerId.namespace == Namespaces.Peer.CloudChannel { + stateManager.notifyAppliedIncomingReadMessages([index.id]) } } diff --git a/TelegramCore/CachedStickerPack.swift b/TelegramCore/CachedStickerPack.swift index bc87be1726..045c56a426 100644 --- a/TelegramCore/CachedStickerPack.swift +++ b/TelegramCore/CachedStickerPack.swift @@ -44,39 +44,45 @@ final class CachedStickerPack: PostboxCoding { private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 100, highWaterItemCount: 200) -public func cachedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference) -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem], Bool)?, NoError> { - return postbox.modify { modifier -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem], Bool)?, NoError> in +public enum CachedStickerPackResult { + case none + case fetching + case result(StickerPackCollectionInfo, [ItemCollectionItem], Bool) +} + +public func cachedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference) -> Signal { + return postbox.modify { modifier -> Signal in let namespace = Namespaces.ItemCollection.CloudStickerPacks if case let .id(id, _) = reference, let currentInfo = modifier.getItemCollectionInfo(collectionId: ItemCollectionId(namespace: namespace, id: id)) as? StickerPackCollectionInfo { let items = modifier.getItemCollectionItems(collectionId: ItemCollectionId(namespace: namespace, id: id)) - return .single((currentInfo, items, true)) + return .single(.result(currentInfo, items, true)) } else { - let current: Signal<(StickerPackCollectionInfo, [ItemCollectionItem], Bool)?, NoError> + let current: Signal var loadRemote = false if case let .id(id, _) = reference, let cached = modifier.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { - current = .single((info, cached.items, false)) + current = .single(.result(info, cached.items, false)) if cached.hash != info.hash { loadRemote = true } } else { - current = .single(nil) + current = .single(.fetching) loadRemote = true } var signal = current if loadRemote { let appliedRemote = remoteStickerPack(network: network, reference: reference) - |> mapToSignal { result -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem], Bool)?, NoError> in - return postbox.modify { modifier -> (StickerPackCollectionInfo, [ItemCollectionItem], Bool)? in + |> mapToSignal { result -> Signal in + return postbox.modify { modifier -> CachedStickerPackResult in if let result = result { modifier.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(result.0.id)), entry: CachedStickerPack(info: result.0, items: result.1.map { $0 as! StickerPackItem }, hash: result.0.hash), collectionSpec: collectionSpec) let currentInfo = modifier.getItemCollectionInfo(collectionId: result.0.id) as? StickerPackCollectionInfo - return (result.0, result.1, currentInfo != nil) + return .result(result.0, result.1, currentInfo != nil) } else { - return nil + return .none } } } diff --git a/TelegramCore/CollectCacheUsageStats.swift b/TelegramCore/CollectCacheUsageStats.swift index ea32dcb119..0580ad2645 100644 --- a/TelegramCore/CollectCacheUsageStats.swift +++ b/TelegramCore/CollectCacheUsageStats.swift @@ -165,6 +165,9 @@ public func collectCacheUsageStats(account: Account) -> Signal Disposable { +public func installInteractiveReadMessagesAction(postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId) -> Disposable { return postbox.installStoreMessageAction(peerId: peerId, { messages, modifier in var consumeMessageIds: [MessageId] = [] + var readMessageIndexByNamespace: [MessageId.Namespace: MessageIndex] = [:] + for message in messages { if case let .Id(id) = message.id { var hasUnconsumedMention = false @@ -29,6 +31,14 @@ public func installInteractiveReadMessagesAction(postbox: Postbox, peerId: PeerI if hasUnconsumedMention && !hasUnconsumedContent { consumeMessageIds.append(id) } + + if message.flags.contains(.Incoming) { + let index = MessageIndex(id: id, timestamp: message.timestamp) + let current = readMessageIndexByNamespace[id.namespace] + if current == nil || current! < index { + readMessageIndexByNamespace[id.namespace] = index + } + } } } @@ -46,5 +56,9 @@ public func installInteractiveReadMessagesAction(postbox: Postbox, peerId: PeerI modifier.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: id, action: ConsumePersonalMessageAction()) } + + for (_, index) in readMessageIndexByNamespace { + applyMaxReadIndexInteractively(modifier: modifier, stateManager: stateManager, index: index) + } }) } diff --git a/TelegramCore/LoadedStickerPack.swift b/TelegramCore/LoadedStickerPack.swift index 5315529899..1dd7756b32 100644 --- a/TelegramCore/LoadedStickerPack.swift +++ b/TelegramCore/LoadedStickerPack.swift @@ -89,58 +89,13 @@ func remoteStickerPack(network: Network, reference: StickerPackReference) -> Sig public func loadedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference) -> Signal { return cachedStickerPack(postbox: postbox, network: network, reference: reference) |> map { result -> LoadedStickerPack in - if let result = result { - return .result(info: result.0, items: result.1, installed: result.2) - } else { - return .fetching + switch result { + case .none: + return .none + case .fetching: + return .fetching + case let .result(info, items, installed): + return .result(info: info, items: items, installed: installed) } } } - -private func loadedStickerPack1(account: Account, reference: StickerPackReference) -> Signal { - return account.postbox.modify { modifier -> Signal in - switch reference { - case let .id(id, _): - if let info = modifier.getItemCollectionInfo(collectionId: ItemCollectionId(namespace: Namespaces.ItemCollection.CloudStickerPacks, id: id)) as? StickerPackCollectionInfo { - let items = modifier.getItemCollectionItems(collectionId: info.id) - return account.postbox.combinedView(keys: [PostboxViewKey.itemCollectionInfo(id: info.id)]) - |> map { view in - if let view = view.views[PostboxViewKey.itemCollectionInfo(id: info.id)] as? ItemCollectionInfoView, let info = view.info as? StickerPackCollectionInfo { - return .result(info: info, items: items, installed: true) - } else { - return .result(info: info, items: items, installed: false) - } - } - } else if let info = modifier.getItemCollectionInfo(collectionId: ItemCollectionId(namespace: Namespaces.ItemCollection.CloudMaskPacks, id: id)) as? StickerPackCollectionInfo { - let items = modifier.getItemCollectionItems(collectionId: info.id) - return account.postbox.combinedView(keys: [PostboxViewKey.itemCollectionInfo(id: info.id)]) - |> map { view in - if let view = view.views[PostboxViewKey.itemCollectionInfo(id: info.id)] as? ItemCollectionInfoView, let info = view.info as? StickerPackCollectionInfo { - return .result(info: info, items: items, installed: true) - } else { - return .result(info: info, items: items, installed: false) - } - } - } - default: - break - } - - let signal = remoteStickerPack(network: account.network, reference: reference) |> mapToSignal { result -> Signal in - if let result = result { - return account.postbox.combinedView(keys: [PostboxViewKey.itemCollectionInfo(id: result.0.id)]) - |> map { view in - if let view = view.views[PostboxViewKey.itemCollectionInfo(id: result.0.id)] as? ItemCollectionInfoView, let info = view.info as? StickerPackCollectionInfo { - return .result(info: info, items: result.1, installed: true) - } else { - return .result(info: result.0, items: result.1, installed: false) - } - } - } else { - return .single(.none) - } - } - - return .single(.fetching) |> then(signal) - } |> switchToLatest -} diff --git a/TelegramCore/PeerSpecificStickerPack.swift b/TelegramCore/PeerSpecificStickerPack.swift index 7645a04118..776b940091 100644 --- a/TelegramCore/PeerSpecificStickerPack.swift +++ b/TelegramCore/PeerSpecificStickerPack.swift @@ -27,8 +27,8 @@ public func peerSpecificStickerPack(postbox: Postbox, network: Network, peerId: if let info = info.info { return cachedStickerPack(postbox: postbox, network: network, reference: .id(id: info.id.id, accessHash: info.accessHash)) |> map { result -> (StickerPackCollectionInfo, [ItemCollectionItem])? in - if let result = result { - return (result.0, result.1) + if case let .result(info, items, _) = result { + return (info, items) } else { return nil } diff --git a/TelegramCore/PeerUtils.swift b/TelegramCore/PeerUtils.swift index 741c03172f..5f9546a4f1 100644 --- a/TelegramCore/PeerUtils.swift +++ b/TelegramCore/PeerUtils.swift @@ -6,6 +6,24 @@ import Foundation #endif public extension Peer { + public func displayTitle(or defaultTitle: String) -> String { + switch self { + case let user as TelegramUser: + let name = user.name + if name.isEmpty { + return defaultTitle + } else { + return name + } + case let group as TelegramGroup: + return group.title + case let channel as TelegramChannel: + return channel.title + default: + return "" + } + } + public var displayTitle: String { switch self { case let user as TelegramUser: diff --git a/TelegramCore/PendingMessageManager.swift b/TelegramCore/PendingMessageManager.swift index a262384bba..316cb442ee 100644 --- a/TelegramCore/PendingMessageManager.swift +++ b/TelegramCore/PendingMessageManager.swift @@ -675,23 +675,30 @@ public final class PendingMessageManager { if updatedState != state { modifier.setPeerChatState(message.id.peerId, state: updatedState) } - modifier.updateMessage(message.id, update: { currentMessage in - var flags = StoreMessageFlags(message.flags) - if !flags.contains(.Failed) { - flags.insert(.Sending) - } - var storeForwardInfo: StoreMessageForwardInfo? - if let forwardInfo = currentMessage.forwardInfo { - storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) - } - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) - }) + } else if case .historyScreenshot = media.action { + sentAsAction = true + let updatedState = addSecretChatOutgoingOperation(modifier: modifier, peerId: message.id.peerId, operation: .screenshotMessages(layer: layer, actionGloballyUniqueId: message.globallyUniqueId!, globallyUniqueIds: []), state: state) + if updatedState != state { + modifier.setPeerChatState(message.id.peerId, state: updatedState) + } } break } } - if !sentAsAction { + if sentAsAction { + modifier.updateMessage(message.id, update: { currentMessage in + var flags = StoreMessageFlags(message.flags) + if !flags.contains(.Failed) { + flags.insert(.Sending) + } + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } else { let updatedState = addSecretChatOutgoingOperation(modifier: modifier, peerId: message.id.peerId, operation: .sendMessage(layer: layer, id: message.id, file: secretFile), state: state) if updatedState != state { modifier.setPeerChatState(message.id.peerId, state: updatedState) diff --git a/TelegramCore/PendingMessageUploadedContent.swift b/TelegramCore/PendingMessageUploadedContent.swift index 96d9bc1e37..4d5aa4fe0c 100644 --- a/TelegramCore/PendingMessageUploadedContent.swift +++ b/TelegramCore/PendingMessageUploadedContent.swift @@ -396,7 +396,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili } else if let resource = file.resource as? LocalFileReferenceMediaResource, let size = resource.size { hintSize = Int(size) } - if file.resource.headerSize != 0 { + if file.resource.headerSize != 0 && !file.isAnimated { hintFileIsLarge = true } let upload = messageMediaPreuploadManager.upload(network: network, postbox: postbox, source: .resource(file.resource), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(file.attributes)), hintFileSize: hintSize, hintFileIsLarge: hintFileIsLarge) diff --git a/TelegramCore/SearchMessages.swift b/TelegramCore/SearchMessages.swift index fb81066497..572871ab9f 100644 --- a/TelegramCore/SearchMessages.swift +++ b/TelegramCore/SearchMessages.swift @@ -97,7 +97,7 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q remoteSearchResult = account.network.request(Api.functions.messages.searchGlobal(q: query, offsetDate: 0, offsetPeer: Api.InputPeer.inputPeerEmpty, offsetId: 0, limit: 64), automaticFloodWait: false) |> mapError { _ in } |> map(Optional.init) } - + let processedSearchResult = remoteSearchResult |> mapToSignal { result -> Signal<[Message], NoError> in guard let result = result else { diff --git a/TelegramCore/SetSecretChatMessageAutoremoveTimeoutInteractively.swift b/TelegramCore/SetSecretChatMessageAutoremoveTimeoutInteractively.swift index 0eb048a459..b9100e32bb 100644 --- a/TelegramCore/SetSecretChatMessageAutoremoveTimeoutInteractively.swift +++ b/TelegramCore/SetSecretChatMessageAutoremoveTimeoutInteractively.swift @@ -10,16 +10,26 @@ import Foundation public func setSecretChatMessageAutoremoveTimeoutInteractively(account: Account, peerId: PeerId, timeout: Int32?) -> Signal { return account.postbox.modify { modifier -> Void in if let peer = modifier.getPeer(peerId) as? TelegramSecretChat, let state = modifier.getPeerChatState(peerId) as? SecretChatState { - let updatedPeer = peer.withUpdatedMessageAutoremoveTimeout(timeout) - let updatedState = state.withUpdatedMessageAutoremoveTimeout(timeout) - if !updatedPeer.isEqual(peer) { - updatePeers(modifier: modifier, peers: [updatedPeer], update: { $1 }) + if state.messageAutoremoveTimeout != timeout { + let updatedPeer = peer.withUpdatedMessageAutoremoveTimeout(timeout) + let updatedState = state.withUpdatedMessageAutoremoveTimeout(timeout) + if !updatedPeer.isEqual(peer) { + updatePeers(modifier: modifier, peers: [updatedPeer], update: { $1 }) + } + if updatedState != state { + modifier.setPeerChatState(peerId, state: updatedState) + } + + let _ = enqueueMessages(modifier: modifier, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], media: TelegramMediaAction(action: TelegramMediaActionType.messageAutoremoveTimeoutUpdated(timeout == nil ? 0 : timeout!)), replyToMessageId: nil, localGroupingKey: nil))]) } - if updatedState != state { - modifier.setPeerChatState(peerId, state: updatedState) - } - - enqueueMessages(modifier: modifier, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], media: TelegramMediaAction(action: TelegramMediaActionType.messageAutoremoveTimeoutUpdated(timeout == nil ? 0 : timeout!)), replyToMessageId: nil, localGroupingKey: nil))]) + } + } +} + +public func addSecretChatMessageScreenshot(account: Account, peerId: PeerId) -> Signal { + return account.postbox.modify { modifier -> Void in + if let peer = modifier.getPeer(peerId) as? TelegramSecretChat, let state = modifier.getPeerChatState(peerId) as? SecretChatState { + let _ = enqueueMessages(modifier: modifier, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], media: TelegramMediaAction(action: TelegramMediaActionType.historyScreenshot), replyToMessageId: nil, localGroupingKey: nil))]) } } } diff --git a/third-party/libphonenumber-iOS/NBPhoneNumberUtil.m b/third-party/libphonenumber-iOS/NBPhoneNumberUtil.m index f1ec6e5280..282ca96cd1 100755 --- a/third-party/libphonenumber-iOS/NBPhoneNumberUtil.m +++ b/third-party/libphonenumber-iOS/NBPhoneNumberUtil.m @@ -451,7 +451,8 @@ static NSArray *GEO_MOBILE_COUNTRIES; - (NSDictionary *)DIGIT_MAPPINGS { - if (!DIGIT_MAPPINGS) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ DIGIT_MAPPINGS = [NSDictionary dictionaryWithObjectsAndKeys: @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9", // Fullwidth digit 0 to 9 @@ -460,7 +461,7 @@ static NSArray *GEO_MOBILE_COUNTRIES; @"0", @"\u0660", @"1", @"\u0661", @"2", @"\u0662", @"3", @"\u0663", @"4", @"\u0664", @"5", @"\u0665", @"6", @"\u0666", @"7", @"\u0667", @"8", @"\u0668", @"9", @"\u0669", // Eastern-Arabic digit 0 to 9 @"0", @"\u06F0", @"1", @"\u06F1", @"2", @"\u06F2", @"3", @"\u06F3", @"4", @"\u06F4", @"5", @"\u06F5", @"6", @"\u06F6", @"7", @"\u06F7", @"8", @"\u06F8", @"9", @"\u06F9", nil]; - } + }); return DIGIT_MAPPINGS; }