mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-29 11:25:38 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/TelegramCore
This commit is contained in:
commit
f59b9e432e
@ -331,6 +331,10 @@
|
|||||||
D0528E661E65C82400E2FEF5 /* UpdateContactName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */; };
|
D0528E661E65C82400E2FEF5 /* UpdateContactName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */; };
|
||||||
D0528E6A1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */; };
|
D0528E6A1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */; };
|
||||||
D0528E6B1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */; };
|
D0528E6B1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */; };
|
||||||
|
D0529D2421A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0529D2321A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift */; };
|
||||||
|
D0529D2521A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0529D2321A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift */; };
|
||||||
|
D0529D2721A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0529D2621A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift */; };
|
||||||
|
D0529D2821A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0529D2621A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift */; };
|
||||||
D053B3FB1F1651FA00E2D58A /* MonotonicTime.h in Headers */ = {isa = PBXBuildFile; fileRef = D053B3F91F1651FA00E2D58A /* MonotonicTime.h */; };
|
D053B3FB1F1651FA00E2D58A /* MonotonicTime.h in Headers */ = {isa = PBXBuildFile; fileRef = D053B3F91F1651FA00E2D58A /* MonotonicTime.h */; };
|
||||||
D053B3FC1F1651FA00E2D58A /* MonotonicTime.m in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FA1F1651FA00E2D58A /* MonotonicTime.m */; };
|
D053B3FC1F1651FA00E2D58A /* MonotonicTime.m in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FA1F1651FA00E2D58A /* MonotonicTime.m */; };
|
||||||
D053B3FE1F16534400E2D58A /* MonotonicTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FD1F16534400E2D58A /* MonotonicTime.swift */; };
|
D053B3FE1F16534400E2D58A /* MonotonicTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FD1F16534400E2D58A /* MonotonicTime.swift */; };
|
||||||
@ -942,6 +946,8 @@
|
|||||||
D0528E5F1E65B94E00E2FEF5 /* SingleMessageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleMessageView.swift; sourceTree = "<group>"; };
|
D0528E5F1E65B94E00E2FEF5 /* SingleMessageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleMessageView.swift; sourceTree = "<group>"; };
|
||||||
D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateContactName.swift; sourceTree = "<group>"; };
|
D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateContactName.swift; sourceTree = "<group>"; };
|
||||||
D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebpagePreview.swift; sourceTree = "<group>"; };
|
D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebpagePreview.swift; sourceTree = "<group>"; };
|
||||||
|
D0529D2321A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SynchronizeRecentlyUsedMediaOperations.swift; sourceTree = "<group>"; };
|
||||||
|
D0529D2621A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeRecentlyUsedMediaOperations.swift; sourceTree = "<group>"; };
|
||||||
D053B3F91F1651FA00E2D58A /* MonotonicTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MonotonicTime.h; sourceTree = "<group>"; };
|
D053B3F91F1651FA00E2D58A /* MonotonicTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MonotonicTime.h; sourceTree = "<group>"; };
|
||||||
D053B3FA1F1651FA00E2D58A /* MonotonicTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MonotonicTime.m; sourceTree = "<group>"; };
|
D053B3FA1F1651FA00E2D58A /* MonotonicTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MonotonicTime.m; sourceTree = "<group>"; };
|
||||||
D053B3FD1F16534400E2D58A /* MonotonicTime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MonotonicTime.swift; sourceTree = "<group>"; };
|
D053B3FD1F16534400E2D58A /* MonotonicTime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MonotonicTime.swift; sourceTree = "<group>"; };
|
||||||
@ -1490,6 +1496,8 @@
|
|||||||
D00422D221677F4500719B67 /* ManagedAccountPresence.swift */,
|
D00422D221677F4500719B67 /* ManagedAccountPresence.swift */,
|
||||||
D0A8998E217A37A000759EE6 /* NotificationAutolockReportManager.swift */,
|
D0A8998E217A37A000759EE6 /* NotificationAutolockReportManager.swift */,
|
||||||
09028385218E5DBB0067EFBD /* ManagedVoipConfigurationUpdates.swift */,
|
09028385218E5DBB0067EFBD /* ManagedVoipConfigurationUpdates.swift */,
|
||||||
|
D0529D2321A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift */,
|
||||||
|
D0529D2621A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift */,
|
||||||
);
|
);
|
||||||
name = State;
|
name = State;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2397,6 +2405,7 @@
|
|||||||
D058E0D11E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */,
|
D058E0D11E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */,
|
||||||
D0BC38751E40A7F70044D6FE /* RemovePeerChat.swift in Sources */,
|
D0BC38751E40A7F70044D6FE /* RemovePeerChat.swift in Sources */,
|
||||||
D09F9DC820767D2C00DB4DE1 /* Api3.swift in Sources */,
|
D09F9DC820767D2C00DB4DE1 /* Api3.swift in Sources */,
|
||||||
|
D0529D2721A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift in Sources */,
|
||||||
D0AB0B961D662F0B002C78E7 /* ManagedChatListHoles.swift in Sources */,
|
D0AB0B961D662F0B002C78E7 /* ManagedChatListHoles.swift in Sources */,
|
||||||
D05A32E41E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */,
|
D05A32E41E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */,
|
||||||
D01A21A61F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift in Sources */,
|
D01A21A61F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift in Sources */,
|
||||||
@ -2431,6 +2440,7 @@
|
|||||||
D0B85AC51F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */,
|
D0B85AC51F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */,
|
||||||
D0B843C31DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */,
|
D0B843C31DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */,
|
||||||
C2366C861E4F403C0097CCFF /* AddressNames.swift in Sources */,
|
C2366C861E4F403C0097CCFF /* AddressNames.swift in Sources */,
|
||||||
|
D0529D2421A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift in Sources */,
|
||||||
D0FA08BB2046B37900DD23FC /* ContentPrivacySettings.swift in Sources */,
|
D0FA08BB2046B37900DD23FC /* ContentPrivacySettings.swift in Sources */,
|
||||||
D0F8C39D20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */,
|
D0F8C39D20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */,
|
||||||
D0B843C11DA7FF30005F29E1 /* NBPhoneMetaData.m in Sources */,
|
D0B843C11DA7FF30005F29E1 /* NBPhoneMetaData.m in Sources */,
|
||||||
@ -2673,6 +2683,7 @@
|
|||||||
D001F3E91E128A1C007A8C60 /* SecretChatState.swift in Sources */,
|
D001F3E91E128A1C007A8C60 /* SecretChatState.swift in Sources */,
|
||||||
D08F4A6A1E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */,
|
D08F4A6A1E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */,
|
||||||
D0B8444B1DAB91FD005F29E1 /* ManagedSynchronizePeerReadStates.swift in Sources */,
|
D0B8444B1DAB91FD005F29E1 /* ManagedSynchronizePeerReadStates.swift in Sources */,
|
||||||
|
D0529D2521A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift in Sources */,
|
||||||
D06ECFC920B810D300C576C2 /* TermsOfService.swift in Sources */,
|
D06ECFC920B810D300C576C2 /* TermsOfService.swift in Sources */,
|
||||||
9F06831121A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */,
|
9F06831121A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */,
|
||||||
D0F8C39E20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */,
|
D0F8C39E20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */,
|
||||||
@ -2781,6 +2792,7 @@
|
|||||||
D0448CA61E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */,
|
D0448CA61E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */,
|
||||||
D001F3F11E128A1C007A8C60 /* SynchronizePeerReadState.swift in Sources */,
|
D001F3F11E128A1C007A8C60 /* SynchronizePeerReadState.swift in Sources */,
|
||||||
D054648F20738626002ECC1E /* SecureIdDriversLicenseValue.swift in Sources */,
|
D054648F20738626002ECC1E /* SecureIdDriversLicenseValue.swift in Sources */,
|
||||||
|
D0529D2821A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift in Sources */,
|
||||||
D050F2641E4A5AEB00988324 /* ManagedSynchronizePinnedChatsOperations.swift in Sources */,
|
D050F2641E4A5AEB00988324 /* ManagedSynchronizePinnedChatsOperations.swift in Sources */,
|
||||||
D0575AF21E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift in Sources */,
|
D0575AF21E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift in Sources */,
|
||||||
D0528E661E65C82400E2FEF5 /* UpdateContactName.swift in Sources */,
|
D0528E661E65C82400E2FEF5 /* UpdateContactName.swift in Sources */,
|
||||||
|
|||||||
@ -1064,7 +1064,7 @@ public class Account {
|
|||||||
self.managedOperationsDisposable.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager, namespace: .stickers).start())
|
self.managedOperationsDisposable.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager, namespace: .stickers).start())
|
||||||
self.managedOperationsDisposable.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager, namespace: .masks).start())
|
self.managedOperationsDisposable.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager, namespace: .masks).start())
|
||||||
self.managedOperationsDisposable.add(managedSynchronizeMarkFeaturedStickerPacksAsSeenOperations(postbox: self.postbox, network: self.network).start())
|
self.managedOperationsDisposable.add(managedSynchronizeMarkFeaturedStickerPacksAsSeenOperations(postbox: self.postbox, network: self.network).start())
|
||||||
self.managedOperationsDisposable.add(managedRecentStickers(postbox: self.postbox, network: self.network).start())
|
self.managedOperationsDisposable.add(managedSynchronizeRecentlyUsedMediaOperations(postbox: self.postbox, network: self.network, category: .stickers, revalidationContext: self.mediaReferenceRevalidationContext).start())
|
||||||
self.managedOperationsDisposable.add(managedSynchronizeSavedGifsOperations(postbox: self.postbox, network: self.network, revalidationContext: self.mediaReferenceRevalidationContext).start())
|
self.managedOperationsDisposable.add(managedSynchronizeSavedGifsOperations(postbox: self.postbox, network: self.network, revalidationContext: self.mediaReferenceRevalidationContext).start())
|
||||||
self.managedOperationsDisposable.add(managedSynchronizeSavedStickersOperations(postbox: self.postbox, network: self.network, revalidationContext: self.mediaReferenceRevalidationContext).start())
|
self.managedOperationsDisposable.add(managedSynchronizeSavedStickersOperations(postbox: self.postbox, network: self.network, revalidationContext: self.mediaReferenceRevalidationContext).start())
|
||||||
self.managedOperationsDisposable.add(managedRecentlyUsedInlineBots(postbox: self.postbox, network: self.network, accountPeerId: peerId).start())
|
self.managedOperationsDisposable.add(managedRecentlyUsedInlineBots(postbox: self.postbox, network: self.network, accountPeerId: peerId).start())
|
||||||
|
|||||||
@ -87,6 +87,7 @@ private var declaredEncodables: Void = {
|
|||||||
declareEncodable(SynchronizeChatInputStateOperation.self, f: { SynchronizeChatInputStateOperation(decoder: $0) })
|
declareEncodable(SynchronizeChatInputStateOperation.self, f: { SynchronizeChatInputStateOperation(decoder: $0) })
|
||||||
declareEncodable(SynchronizeSavedGifsOperation.self, f: { SynchronizeSavedGifsOperation(decoder: $0) })
|
declareEncodable(SynchronizeSavedGifsOperation.self, f: { SynchronizeSavedGifsOperation(decoder: $0) })
|
||||||
declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) })
|
declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) })
|
||||||
|
declareEncodable(SynchronizeRecentlyUsedMediaOperation.self, f: { SynchronizeRecentlyUsedMediaOperation(decoder: $0) })
|
||||||
declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) })
|
declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) })
|
||||||
declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) })
|
declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) })
|
||||||
declareEncodable(LocalizationListState.self, f: { LocalizationListState(decoder: $0) })
|
declareEncodable(LocalizationListState.self, f: { LocalizationListState(decoder: $0) })
|
||||||
|
|||||||
@ -203,7 +203,7 @@ public func authorizeWithCode(account: UnauthorizedAccount, code: String, termsO
|
|||||||
return .fail(.limitExceeded)
|
return .fail(.limitExceeded)
|
||||||
} else if errorDescription == "PHONE_CODE_INVALID" {
|
} else if errorDescription == "PHONE_CODE_INVALID" {
|
||||||
return .fail(.invalidCode)
|
return .fail(.invalidCode)
|
||||||
} else if errorDescription == "CODE_HASH_EXPIRED" {
|
} else if errorDescription == "CODE_HASH_EXPIRED" || errorDescription == "PHONE_CODE_EXPIRED" {
|
||||||
return .fail(.codeExpired)
|
return .fail(.codeExpired)
|
||||||
} else if errorDescription == "PHONE_NUMBER_UNOCCUPIED" {
|
} else if errorDescription == "PHONE_NUMBER_UNOCCUPIED" {
|
||||||
return .single(.signUp)
|
return .single(.signUp)
|
||||||
|
|||||||
@ -71,7 +71,7 @@ private final class ContactSyncManagerImpl {
|
|||||||
let timestamp = CFAbsoluteTimeGetCurrent()
|
let timestamp = CFAbsoluteTimeGetCurrent()
|
||||||
let shouldUpdate: Bool
|
let shouldUpdate: Bool
|
||||||
if let lastContactPresencesRequestTimestamp = strongSelf.lastContactPresencesRequestTimestamp {
|
if let lastContactPresencesRequestTimestamp = strongSelf.lastContactPresencesRequestTimestamp {
|
||||||
if timestamp > lastContactPresencesRequestTimestamp + 30.0 * 60.0 {
|
if timestamp > lastContactPresencesRequestTimestamp + 2.0 * 60.0 {
|
||||||
shouldUpdate = true
|
shouldUpdate = true
|
||||||
} else {
|
} else {
|
||||||
shouldUpdate = false
|
shouldUpdate = false
|
||||||
|
|||||||
@ -1018,8 +1018,12 @@ extension InstantPageBlock {
|
|||||||
self = .blockQuote(text: RichText(apiText: text), caption: RichText(apiText: caption))
|
self = .blockQuote(text: RichText(apiText: text), caption: RichText(apiText: caption))
|
||||||
case let .pageBlockPullquote(text, caption):
|
case let .pageBlockPullquote(text, caption):
|
||||||
self = .pullQuote(text: RichText(apiText: text), caption: RichText(apiText: caption))
|
self = .pullQuote(text: RichText(apiText: text), caption: RichText(apiText: caption))
|
||||||
case let .pageBlockPhoto(_, photoId, caption, url, webpageId):
|
case let .pageBlockPhoto(flags, photoId, caption, url, webpageId):
|
||||||
self = .image(id: MediaId(namespace: Namespaces.Media.CloudImage, id: photoId), caption: InstantPageCaption(apiCaption: caption), url: url, webpageId: webpageId != nil ? MediaId(namespace: Namespaces.Media.CloudWebpage, id: webpageId!) : nil)
|
var webpageMediaId: MediaId?
|
||||||
|
if (flags & (1 << 0)) != 0, let webpageId = webpageId, webpageId != 0 {
|
||||||
|
webpageMediaId = MediaId(namespace: Namespaces.Media.CloudWebpage, id: webpageId)
|
||||||
|
}
|
||||||
|
self = .image(id: MediaId(namespace: Namespaces.Media.CloudImage, id: photoId), caption: InstantPageCaption(apiCaption: caption), url: url, webpageId: webpageMediaId)
|
||||||
case let .pageBlockVideo(flags, videoId, caption):
|
case let .pageBlockVideo(flags, videoId, caption):
|
||||||
self = .video(id: MediaId(namespace: Namespaces.Media.CloudFile, id: videoId), caption: InstantPageCaption(apiCaption: caption), autoplay: (flags & (1 << 0)) != 0, loop: (flags & (1 << 1)) != 0)
|
self = .video(id: MediaId(namespace: Namespaces.Media.CloudFile, id: videoId), caption: InstantPageCaption(apiCaption: caption), autoplay: (flags & (1 << 0)) != 0, loop: (flags & (1 << 1)) != 0)
|
||||||
case let .pageBlockCover(cover):
|
case let .pageBlockCover(cover):
|
||||||
|
|||||||
@ -1195,7 +1195,7 @@ private func sendMessage(postbox: Postbox, network: Network, messageId: MessageI
|
|||||||
}
|
}
|
||||||
|
|
||||||
for file in sentStickers {
|
for file in sentStickers {
|
||||||
transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 20)
|
addRecentlyUsedSticker(transaction: transaction, fileReference: .standalone(media: file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
183
TelegramCore/ManagedSynchronizeRecentlyUsedMediaOperations.swift
Normal file
183
TelegramCore/ManagedSynchronizeRecentlyUsedMediaOperations.swift
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
import Foundation
|
||||||
|
#if os(macOS)
|
||||||
|
import PostboxMac
|
||||||
|
import SwiftSignalKitMac
|
||||||
|
import MtProtoKitMac
|
||||||
|
#else
|
||||||
|
import Postbox
|
||||||
|
import SwiftSignalKit
|
||||||
|
import MtProtoKitDynamic
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private final class ManagedSynchronizeRecentlyUsedMediaOperationsHelper {
|
||||||
|
var operationDisposables: [Int32: Disposable] = [:]
|
||||||
|
|
||||||
|
func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) {
|
||||||
|
var disposeOperations: [Disposable] = []
|
||||||
|
var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = []
|
||||||
|
|
||||||
|
var hasRunningOperationForPeerId = Set<PeerId>()
|
||||||
|
var validMergedIndices = Set<Int32>()
|
||||||
|
for entry in entries {
|
||||||
|
if !hasRunningOperationForPeerId.contains(entry.peerId) {
|
||||||
|
hasRunningOperationForPeerId.insert(entry.peerId)
|
||||||
|
validMergedIndices.insert(entry.mergedIndex)
|
||||||
|
|
||||||
|
if self.operationDisposables[entry.mergedIndex] == nil {
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
beginOperations.append((entry, disposable))
|
||||||
|
self.operationDisposables[entry.mergedIndex] = disposable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var removeMergedIndices: [Int32] = []
|
||||||
|
for (mergedIndex, disposable) in self.operationDisposables {
|
||||||
|
if !validMergedIndices.contains(mergedIndex) {
|
||||||
|
removeMergedIndices.append(mergedIndex)
|
||||||
|
disposeOperations.append(disposable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for mergedIndex in removeMergedIndices {
|
||||||
|
self.operationDisposables.removeValue(forKey: mergedIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (disposeOperations, beginOperations)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reset() -> [Disposable] {
|
||||||
|
let disposables = Array(self.operationDisposables.values)
|
||||||
|
self.operationDisposables.removeAll()
|
||||||
|
return disposables
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal<Void, NoError>) -> Signal<Void, NoError> {
|
||||||
|
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||||
|
var result: PeerMergedOperationLogEntry?
|
||||||
|
transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in
|
||||||
|
if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeRecentlyUsedMediaOperation {
|
||||||
|
result = entry.mergedEntry!
|
||||||
|
return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none)
|
||||||
|
} else {
|
||||||
|
return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return f(transaction, result)
|
||||||
|
} |> switchToLatest
|
||||||
|
}
|
||||||
|
|
||||||
|
func managedSynchronizeRecentlyUsedMediaOperations(postbox: Postbox, network: Network, category: RecentlyUsedMediaCategory, revalidationContext: MediaReferenceRevalidationContext) -> Signal<Void, NoError> {
|
||||||
|
return Signal { _ in
|
||||||
|
let tag: PeerOperationLogTag
|
||||||
|
switch category {
|
||||||
|
case .stickers:
|
||||||
|
tag = OperationLogTags.SynchronizeRecentlyUsedStickers
|
||||||
|
}
|
||||||
|
|
||||||
|
let helper = Atomic<ManagedSynchronizeRecentlyUsedMediaOperationsHelper>(value: ManagedSynchronizeRecentlyUsedMediaOperationsHelper())
|
||||||
|
|
||||||
|
let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in
|
||||||
|
let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in
|
||||||
|
return helper.update(view.entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
for disposable in disposeOperations {
|
||||||
|
disposable.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entry, disposable) in beginOperations {
|
||||||
|
let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal<Void, NoError> in
|
||||||
|
if let entry = entry {
|
||||||
|
if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation {
|
||||||
|
return synchronizeRecentlyUsedMedia(transaction: transaction, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation)
|
||||||
|
} else {
|
||||||
|
assertionFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .complete()
|
||||||
|
})
|
||||||
|
|> then(postbox.transaction { transaction -> Void in
|
||||||
|
let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex)
|
||||||
|
})
|
||||||
|
|
||||||
|
disposable.set(signal.start())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return ActionDisposable {
|
||||||
|
let disposables = helper.with { helper -> [Disposable] in
|
||||||
|
return helper.reset()
|
||||||
|
}
|
||||||
|
for disposable in disposables {
|
||||||
|
disposable.dispose()
|
||||||
|
}
|
||||||
|
disposable.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum SaveRecentlyUsedMediaError {
|
||||||
|
case generic
|
||||||
|
case invalidReference
|
||||||
|
}
|
||||||
|
|
||||||
|
private func synchronizeRecentlyUsedMedia(transaction: Transaction, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeRecentlyUsedMediaOperation) -> Signal<Void, NoError> {
|
||||||
|
switch operation.content {
|
||||||
|
case let .add(id, accessHash, fileReference):
|
||||||
|
guard let fileReference = fileReference else {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
let addSticker: (Data) -> Signal<Api.Bool, SaveRecentlyUsedMediaError> = { fileReference in
|
||||||
|
return network.request(Api.functions.messages.saveRecentSticker(flags: 0, id: .inputDocument(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference)), unsave: .boolFalse))
|
||||||
|
|> mapError { error -> SaveRecentlyUsedMediaError in
|
||||||
|
if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") {
|
||||||
|
return .invalidReference
|
||||||
|
}
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let initialSignal: Signal<Api.Bool, SaveRecentlyUsedMediaError>
|
||||||
|
if let reference = (fileReference.media.resource as? CloudDocumentMediaResource)?.fileReference {
|
||||||
|
initialSignal = addSticker(reference)
|
||||||
|
} else {
|
||||||
|
initialSignal = .fail(.invalidReference)
|
||||||
|
}
|
||||||
|
|
||||||
|
return initialSignal
|
||||||
|
|> `catch` { error -> Signal<Api.Bool, SaveRecentlyUsedMediaError> in
|
||||||
|
switch error {
|
||||||
|
case .generic:
|
||||||
|
return .fail(.generic)
|
||||||
|
case .invalidReference:
|
||||||
|
return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false), resource: fileReference.media.resource)
|
||||||
|
|> mapError { _ -> SaveRecentlyUsedMediaError in
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
|> mapToSignal { reference -> Signal<Api.Bool, SaveRecentlyUsedMediaError> in
|
||||||
|
return addSticker(reference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
case let .remove(id, accessHash):
|
||||||
|
return network.request(Api.functions.messages.saveRecentSticker(flags: 0, id: .inputDocument(id: id, accessHash: accessHash, fileReference: Buffer()), unsave: .boolTrue))
|
||||||
|
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||||
|
return .single(.boolFalse)
|
||||||
|
}
|
||||||
|
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
case .sync:
|
||||||
|
return managedRecentStickers(postbox: postbox, network: network)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -125,6 +125,7 @@ public struct OperationLogTags {
|
|||||||
static let SynchronizeSavedStickers = PeerOperationLogTag(value: 14)
|
static let SynchronizeSavedStickers = PeerOperationLogTag(value: 14)
|
||||||
static let SynchronizeGroupedPeers = PeerOperationLogTag(value: 15)
|
static let SynchronizeGroupedPeers = PeerOperationLogTag(value: 15)
|
||||||
static let SynchronizeMarkAllUnseenPersonalMessages = PeerOperationLogTag(value: 16)
|
static let SynchronizeMarkAllUnseenPersonalMessages = PeerOperationLogTag(value: 16)
|
||||||
|
static let SynchronizeRecentlyUsedStickers = PeerOperationLogTag(value: 17)
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension PeerSummaryCounterTags {
|
public extension PeerSummaryCounterTags {
|
||||||
|
|||||||
@ -27,6 +27,7 @@ func manageStickerPacks(network: Network, postbox: Postbox) -> Signal<Void, NoEr
|
|||||||
addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: .masks, content: .sync)
|
addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: .masks, content: .sync)
|
||||||
addSynchronizeSavedGifsOperation(transaction: transaction, operation: .sync)
|
addSynchronizeSavedGifsOperation(transaction: transaction, operation: .sync)
|
||||||
addSynchronizeSavedStickersOperation(transaction: transaction, operation: .sync)
|
addSynchronizeSavedStickersOperation(transaction: transaction, operation: .sync)
|
||||||
|
addSynchronizeRecentlyUsedMediaOperation(transaction: transaction, category: .stickers, operation: .sync)
|
||||||
} |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
} |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
105
TelegramCore/SynchronizeRecentlyUsedMediaOperations.swift
Normal file
105
TelegramCore/SynchronizeRecentlyUsedMediaOperations.swift
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import Foundation
|
||||||
|
#if os(macOS)
|
||||||
|
import PostboxMac
|
||||||
|
import SwiftSignalKitMac
|
||||||
|
#else
|
||||||
|
import Postbox
|
||||||
|
import SwiftSignalKit
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private enum SynchronizeRecentlyUsedMediaOperationContentType: Int32 {
|
||||||
|
case add
|
||||||
|
case remove
|
||||||
|
case sync
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SynchronizeRecentlyUsedMediaOperationContent: PostboxCoding {
|
||||||
|
case add(id: Int64, accessHash: Int64, fileReference: FileMediaReference?)
|
||||||
|
case remove(id: Int64, accessHash: Int64)
|
||||||
|
case sync
|
||||||
|
|
||||||
|
init(decoder: PostboxDecoder) {
|
||||||
|
switch decoder.decodeInt32ForKey("r", orElse: 0) {
|
||||||
|
case SynchronizeRecentlyUsedMediaOperationContentType.add.rawValue:
|
||||||
|
self = .add(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0), fileReference: decoder.decodeAnyObjectForKey("fr", decoder: { FileMediaReference(decoder: $0) }) as? FileMediaReference)
|
||||||
|
case SynchronizeRecentlyUsedMediaOperationContentType.remove.rawValue:
|
||||||
|
self = .remove(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0))
|
||||||
|
case SynchronizeRecentlyUsedMediaOperationContentType.sync.rawValue:
|
||||||
|
self = .sync
|
||||||
|
default:
|
||||||
|
assertionFailure()
|
||||||
|
self = .sync
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encode(_ encoder: PostboxEncoder) {
|
||||||
|
switch self {
|
||||||
|
case let .add(id, accessHash, fileReference):
|
||||||
|
encoder.encodeInt32(SynchronizeRecentlyUsedMediaOperationContentType.add.rawValue, forKey: "r")
|
||||||
|
encoder.encodeInt64(id, forKey: "i")
|
||||||
|
encoder.encodeInt64(accessHash, forKey: "h")
|
||||||
|
if let fileReference = fileReference {
|
||||||
|
encoder.encodeObjectWithEncoder(fileReference, encoder: fileReference.encode, forKey: "fr")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "fr")
|
||||||
|
}
|
||||||
|
case let .remove(id, accessHash):
|
||||||
|
encoder.encodeInt32(SynchronizeRecentlyUsedMediaOperationContentType.remove.rawValue, forKey: "r")
|
||||||
|
encoder.encodeInt64(id, forKey: "i")
|
||||||
|
encoder.encodeInt64(accessHash, forKey: "h")
|
||||||
|
case .sync:
|
||||||
|
encoder.encodeInt32(SynchronizeRecentlyUsedMediaOperationContentType.sync.rawValue, forKey: "r")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class SynchronizeRecentlyUsedMediaOperation: PostboxCoding {
|
||||||
|
let content: SynchronizeRecentlyUsedMediaOperationContent
|
||||||
|
|
||||||
|
init(content: SynchronizeRecentlyUsedMediaOperationContent) {
|
||||||
|
self.content = content
|
||||||
|
}
|
||||||
|
|
||||||
|
init(decoder: PostboxDecoder) {
|
||||||
|
self.content = decoder.decodeObjectForKey("c", decoder: { SynchronizeRecentlyUsedMediaOperationContent(decoder: $0) }) as! SynchronizeRecentlyUsedMediaOperationContent
|
||||||
|
}
|
||||||
|
|
||||||
|
func encode(_ encoder: PostboxEncoder) {
|
||||||
|
encoder.encodeObject(self.content, forKey: "c")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RecentlyUsedMediaCategory {
|
||||||
|
case stickers
|
||||||
|
}
|
||||||
|
|
||||||
|
func addSynchronizeRecentlyUsedMediaOperation(transaction: Transaction, category: RecentlyUsedMediaCategory, operation: SynchronizeRecentlyUsedMediaOperationContent) {
|
||||||
|
let tag: PeerOperationLogTag
|
||||||
|
switch category {
|
||||||
|
case .stickers:
|
||||||
|
tag = OperationLogTags.SynchronizeRecentlyUsedStickers
|
||||||
|
}
|
||||||
|
let peerId = PeerId(namespace: 0, id: 0)
|
||||||
|
|
||||||
|
var topOperation: (SynchronizeRecentlyUsedMediaOperation, Int32)?
|
||||||
|
transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in
|
||||||
|
if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation {
|
||||||
|
topOperation = (operation, entry.tagLocalIndex)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
if let (topOperation, topLocalIndex) = topOperation, case .sync = topOperation.content {
|
||||||
|
let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeRecentlyUsedMediaOperation(content: operation))
|
||||||
|
transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeRecentlyUsedMediaOperation(content: .sync))
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRecentlyUsedSticker(transaction: Transaction, fileReference: FileMediaReference) {
|
||||||
|
if let resource = fileReference.media.resource as? CloudDocumentMediaResource {
|
||||||
|
transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(fileReference.media.fileId).rawValue, contents: RecentMediaItem(fileReference.media)), removeTailIfCountExceeds: 20)
|
||||||
|
addSynchronizeRecentlyUsedMediaOperation(transaction: transaction, category: .stickers, operation: .add(id: resource.fileId, accessHash: resource.accessHash, fileReference: fileReference))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user