Postbox refactor waves 427-437: combinedView → engine.data migrations

Squashed batch of 14 consumer-side migrations from Postbox
combinedView/subscribe patterns to TelegramEngine.data.subscribe /
.get, plus two engine-data-item additions.

- Wave 427: DataAndStorageSettingsController preferences subscribe
- Wave 428: SaveIncomingMediaController inner preferences subscribe
- Wave 429: SaveIncomingMediaController top-level preferences subscribe
- Wave 430 (reverted + retried as 430-retry):
    initial TabBarChatListFilterController globalNotifications attempt
    landed and was reverted; replaced by ChatControllerContentData
    messageAndTopic collapse via additive Messages.MessageCount
    handleThreads/namespace parameter
- Wave 431: ChatControllerContentData savedMessagesPeer collapse via
    new Peer.MainPeer(id:) engine data item
- Wave 432 (+ followup): 6 messageHistoryThreadInfo sites to
    Messages.ThreadInfo
- Wave 433: ChatListController cachedPeerData → engine.data.get
- Wave 434: 8 orderedItemList sites to Collections.Featured*Packs
- Wave 435: StorageUsageExceptionsScreen preferences combinedView
- Wave 436: FeaturedStickersScreen 2 itemCollectionInfos sites
- Wave 437: extends Messages.PeerUnreadCount with handleThreads
    parameter + migrates AccountContext unreadCount site
This commit is contained in:
isaac 2026-05-20 00:18:15 +08:00
parent c64653ed37
commit b8ee5493d9
12 changed files with 133 additions and 222 deletions

View file

@ -1401,12 +1401,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
let _ = (combineLatest(queue: .mainQueue(),
self.context.account.postbox.combinedView(keys: [.cachedPeerData(peerId: peer.id)])
|> take(1),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.CachedData(id: peer.id)),
forumSourcePeer
)
|> deliverOnMainQueue).start(next: { [weak self] combinedView, forumSourcePeer in
guard let self, let cachedDataView = combinedView.views[.cachedPeerData(peerId: peer.id)] as? CachedPeerDataView else {
|> deliverOnMainQueue).start(next: { [weak self] cachedPeerData, forumSourcePeer in
guard let self else {
return
}
guard let navigationController = self.navigationController as? NavigationController else {
@ -1432,7 +1431,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} else if case let .channel(channel) = peer, channel.flags.contains(.displayForumAsTabs) {
openAsInlineForum = false
} else {
if let cachedData = cachedDataView.cachedPeerData as? CachedChannelData, case let .known(viewForumAsMessages) = cachedData.viewForumAsMessages, viewForumAsMessages {
if let cachedData = cachedPeerData as? CachedChannelData, case let .known(viewForumAsMessages) = cachedData.viewForumAsMessages, viewForumAsMessages {
openAsInlineForum = false
}
}

View file

@ -389,23 +389,16 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
self.disposable = (combineLatest(queue: .mainQueue(),
mappedFeatured,
self.additionalPacks.get(),
context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])]),
context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCollections.InstalledPackIds(namespace: Namespaces.ItemCollection.CloudStickerPacks)),
context.sharedContext.presentationData
)
|> map { featuredEntries, additionalPacks, view, presentationData -> FeaturedTransition in
|> map { featuredEntries, additionalPacks, installedPackIds, presentationData -> FeaturedTransition in
var presentationData = presentationData
if let forceTheme {
presentationData = presentationData.withUpdated(theme: forceTheme)
}
var installedPacks = Set<ItemCollectionId>()
if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView {
if let packsEntries = stickerPacksView.entriesByNamespace[Namespaces.ItemCollection.CloudStickerPacks] {
for entry in packsEntries {
installedPacks.insert(entry.id)
}
}
}
let installedPacks = Set(installedPackIds)
let entries = featuredScreenEntries(featuredEntries: featuredEntries.0, installedPacks: installedPacks, theme: presentationData.theme, strings: presentationData.strings, fixedUnread: featuredEntries.1, additionalPacks: additionalPacks)
let previous = previousEntries.swap(entries)
@ -1370,17 +1363,9 @@ private final class FeaturedPaneSearchContentNode: ASDisplayNode {
)
}
let installedPackIds = context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])])
|> map { view -> Set<ItemCollectionId> in
var installedPacks = Set<ItemCollectionId>()
if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView {
if let packsEntries = stickerPacksView.entriesByNamespace[Namespaces.ItemCollection.CloudStickerPacks] {
for entry in packsEntries {
installedPacks.insert(entry.id)
}
}
}
return installedPacks
let installedPackIds = context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCollections.InstalledPackIds(namespace: Namespaces.ItemCollection.CloudStickerPacks))
|> map { installedPackIds -> Set<ItemCollectionId> in
return Set(installedPackIds)
}
|> distinctUntilChanged
let packs = combineLatest(rawPacks, installedPackIds)

View file

@ -932,13 +932,9 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
}
})
let preferencesKey: EngineRawPostboxViewKey = .preferences(keys: Set([ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings]))
let preferences = context.account.postbox.combinedView(keys: [preferencesKey])
|> map { views -> MediaAutoSaveSettings in
guard let view = views.views[preferencesKey] as? EngineRawPreferencesView else {
return .default
}
return view.values[ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings]?.get(MediaAutoSaveSettings.self) ?? MediaAutoSaveSettings.default
let preferences = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.ApplicationSpecificPreference(key: ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings))
|> map { entry -> MediaAutoSaveSettings in
return entry?.get(MediaAutoSaveSettings.self) ?? MediaAutoSaveSettings.default
}
let autosaveExceptionPeers: Signal<[EnginePeer.Id: EnginePeer?], NoError> = preferences

View file

@ -514,13 +514,9 @@ public func saveIncomingMediaController(context: AccountContext, scope: SaveInco
controller.peerSelected = { [weak controller] peer, _ in
let peerId = peer.id
let preferencesKey: EngineRawPostboxViewKey = .preferences(keys: Set([ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings]))
let preferences = context.account.postbox.combinedView(keys: [preferencesKey])
|> map { views -> MediaAutoSaveSettings in
guard let view = views.views[preferencesKey] as? EngineRawPreferencesView else {
return .default
}
return view.values[ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings]?.get(MediaAutoSaveSettings.self) ?? MediaAutoSaveSettings.default
let preferences = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.ApplicationSpecificPreference(key: ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings))
|> map { entry -> MediaAutoSaveSettings in
return entry?.get(MediaAutoSaveSettings.self) ?? MediaAutoSaveSettings.default
}
let _ = (preferences
@ -621,13 +617,9 @@ public func saveIncomingMediaController(context: AccountContext, scope: SaveInco
}
)
let preferencesKey: EngineRawPostboxViewKey = .preferences(keys: Set([ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings]))
let preferences = context.account.postbox.combinedView(keys: [preferencesKey])
|> map { views -> MediaAutoSaveSettings in
guard let view = views.views[preferencesKey] as? EngineRawPreferencesView else {
return .default
}
return view.values[ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings]?.get(MediaAutoSaveSettings.self) ?? MediaAutoSaveSettings.default
let preferences = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.ApplicationSpecificPreference(key: ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings))
|> map { entry -> MediaAutoSaveSettings in
return entry?.get(MediaAutoSaveSettings.self) ?? MediaAutoSaveSettings.default
}
let peer: Signal<(EnginePeer?, EnginePeer.Presence?), NoError>

View file

@ -230,17 +230,9 @@ public func storageUsageExceptionsScreen(
return cacheSettings
})
let viewKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.accountSpecificCacheStorageSettings]))
let accountSpecificSettings: Signal<AccountSpecificCacheStorageSettings, NoError> = context.account.postbox.combinedView(keys: [viewKey])
|> map { views -> AccountSpecificCacheStorageSettings in
let cacheSettings: AccountSpecificCacheStorageSettings
if let view = views.views[viewKey] as? PreferencesView, let value = view.values[PreferencesKeys.accountSpecificCacheStorageSettings]?.get(AccountSpecificCacheStorageSettings.self) {
cacheSettings = value
} else {
cacheSettings = AccountSpecificCacheStorageSettings.defaultSettings
}
return cacheSettings
let accountSpecificSettings: Signal<AccountSpecificCacheStorageSettings, NoError> = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.ApplicationSpecificPreference(key: PreferencesKeys.accountSpecificCacheStorageSettings))
|> map { entry -> AccountSpecificCacheStorageSettings in
return entry?.get(AccountSpecificCacheStorageSettings.self) ?? AccountSpecificCacheStorageSettings.defaultSettings
}
|> distinctUntilChanged

View file

@ -206,16 +206,18 @@ public extension TelegramEngine.EngineData.Item {
public typealias Result = Int
fileprivate let id: EnginePeer.Id
fileprivate let handleThreads: Bool
public var mapKey: EnginePeer.Id {
return self.id
}
var key: PostboxViewKey {
return .unreadCounts(items: [.peer(id: self.id, handleThreads: true)])
return .unreadCounts(items: [.peer(id: self.id, handleThreads: self.handleThreads)])
}
public init(id: EnginePeer.Id) {
public init(id: EnginePeer.Id, handleThreads: Bool = true) {
self.id = id
self.handleThreads = handleThreads
}
func extract(view: PostboxView) -> Result {
@ -223,7 +225,7 @@ public extension TelegramEngine.EngineData.Item {
preconditionFailure()
}
return Int(view.count(for: .peer(id: self.id, handleThreads: true)) ?? 0)
return Int(view.count(for: .peer(id: self.id, handleThreads: self.handleThreads)) ?? 0)
}
}
@ -337,25 +339,28 @@ public extension TelegramEngine.EngineData.Item {
public var peerId: EnginePeer.Id
public var tag: MessageTags
public var threadId: Int64?
public var namespace: Int32
}
public typealias Result = Int?
fileprivate var peerId: EnginePeer.Id
fileprivate var tag: MessageTags
fileprivate var threadId: Int64?
fileprivate var namespace: Int32
public var mapKey: ItemKey {
return ItemKey(peerId: self.peerId, tag: self.tag, threadId: self.threadId)
return ItemKey(peerId: self.peerId, tag: self.tag, threadId: self.threadId, namespace: self.namespace)
}
public init(peerId: EnginePeer.Id, threadId: Int64?, tag: MessageTags) {
public init(peerId: EnginePeer.Id, threadId: Int64?, tag: MessageTags, namespace: Int32 = Namespaces.Message.Cloud) {
self.peerId = peerId
self.threadId = threadId
self.tag = tag
self.namespace = namespace
}
var key: PostboxViewKey {
return .historyTagSummaryView(tag: self.tag, peerId: self.peerId, threadId: self.threadId, namespace: Namespaces.Message.Cloud, customTag: nil)
return .historyTagSummaryView(tag: self.tag, peerId: self.peerId, threadId: self.threadId, namespace: self.namespace, customTag: nil)
}
func extract(view: PostboxView) -> Result {

View file

@ -184,6 +184,36 @@ public extension TelegramEngine.EngineData.Item {
}
}
public struct MainPeer: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Optional<EnginePeer>
fileprivate var id: EnginePeer.Id
public var mapKey: EnginePeer.Id {
return self.id
}
public init(id: EnginePeer.Id) {
self.id = id
}
var key: PostboxViewKey {
return .peer(peerId: self.id, components: [])
}
func extract(view: PostboxView) -> Result {
guard let view = view as? PeerView else {
preconditionFailure()
}
guard let peer = view.peers[self.id] else {
return nil
}
if let secretChat = peer as? TelegramSecretChat {
return view.peers[secretChat.regularPeerId].flatMap(EnginePeer.init)
}
return EnginePeer(peer)
}
}
public struct RenderedPeer: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Optional<EngineRenderedPeer>

View file

@ -835,14 +835,9 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
return
}
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks)
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
return
}
for featuredEmojiPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Collections.FeaturedEmojiPacks())
|> deliverOnMainQueue).start(next: { featuredEmojiPacks in
for featuredEmojiPack in featuredEmojiPacks {
if featuredEmojiPack.info.id == collectionId {
if let strongSelf = self {
strongSelf.scheduledContentAnimationHint = EmojiPagerContentComponent.ContentAnimation(type: .groupInstalled(id: collectionId, scrollToGroup: scrollToGroup))
@ -877,15 +872,10 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
])])
interaction.presentController(actionSheet, nil)
} else if groupId == AnyHashable("featuredTop") {
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks)
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
return
}
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Collections.FeaturedEmojiPacks())
|> deliverOnMainQueue).start(next: { featuredEmojiPacks in
var emojiPackIds: [Int64] = []
for featuredEmojiPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
for featuredEmojiPack in featuredEmojiPacks {
emojiPackIds.append(featuredEmojiPack.info.id.id)
}
let _ = ApplicationSpecificNotice.setDismissedTrendingEmojiPacks(accountManager: context.sharedContext.accountManager, values: emojiPackIds).start()
@ -1355,14 +1345,9 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
return
}
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
return
}
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Collections.FeaturedStickerPacks())
|> deliverOnMainQueue).start(next: { featuredStickerPacks in
for featuredStickerPack in featuredStickerPacks {
if featuredStickerPack.info.id == collectionId {
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: featuredStickerPack.info.id.id, accessHash: featuredStickerPack.info.accessHash), forceActualized: false)
|> mapToSignal { result -> Signal<Void, NoError> in
@ -1411,15 +1396,10 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
])])
interaction.presentController(actionSheet, nil)
} else if groupId == AnyHashable("featuredTop") {
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
return
}
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Collections.FeaturedStickerPacks())
|> deliverOnMainQueue).start(next: { featuredStickerPacks in
var stickerPackIds: [Int64] = []
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
for featuredStickerPack in featuredStickerPacks {
stickerPackIds.append(featuredStickerPack.info.id.id)
}
let _ = ApplicationSpecificNotice.setDismissedTrendingStickerPacks(accountManager: context.sharedContext.accountManager, values: stickerPackIds).start()

View file

@ -2037,14 +2037,7 @@ func peerInfoScreenData(
let threadData: Signal<MessageHistoryThreadData?, NoError>
if case let .replyThread(message) = chatLocation {
let threadId = message.threadId
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
threadData = context.account.postbox.combinedView(keys: [viewKey])
|> map { views -> MessageHistoryThreadData? in
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
return nil
}
return view.info?.data.get(MessageHistoryThreadData.self)
}
threadData = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: peerId, threadId: threadId))
} else {
threadData = .single(nil)
}

View file

@ -944,14 +944,9 @@ public class StickerPickerScreen: ViewController {
return
}
let context = controller.context
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks)
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
return
}
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Collections.FeaturedEmojiPacks())
|> deliverOnMainQueue).start(next: { featuredEmojiPacks in
for featuredStickerPack in featuredEmojiPacks {
if featuredStickerPack.info.id == collectionId {
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: featuredStickerPack.info.id.id, accessHash: featuredStickerPack.info.accessHash), forceActualized: false)
|> mapToSignal { result -> Signal<Void, NoError> in
@ -1310,14 +1305,12 @@ public class StickerPickerScreen: ViewController {
}
let presentationData = controller.context.sharedContext.currentPresentationData.with { $0 }
if groupId == AnyHashable("featuredTop") {
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
let _ = (controller.context.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] views in
guard let self, let controller = self.controller, let view = views.views[viewKey] as? OrderedItemListView else {
let _ = (controller.context.engine.data.get(TelegramEngine.EngineData.Item.Collections.FeaturedStickerPacks())
|> deliverOnMainQueue).start(next: { [weak self] featuredStickerPacks in
guard let self, let controller = self.controller else {
return
}
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
for featuredStickerPack in featuredStickerPacks {
if featuredStickerPack.topItems.contains(where: { $0.file.fileId == file.fileId }) {
controller.pushController(FeaturedStickersScreen(
context: controller.context,
@ -1368,14 +1361,9 @@ public class StickerPickerScreen: ViewController {
return
}
let context = controller.context
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
return
}
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Collections.FeaturedStickerPacks())
|> deliverOnMainQueue).start(next: { featuredStickerPacks in
for featuredStickerPack in featuredStickerPacks {
if featuredStickerPack.info.id == collectionId {
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: featuredStickerPack.info.id.id, accessHash: featuredStickerPack.info.accessHash), forceActualized: false)
|> mapToSignal { result -> Signal<Void, NoError> in
@ -1424,15 +1412,10 @@ public class StickerPickerScreen: ViewController {
])])
context.sharedContext.mainWindow?.presentInGlobalOverlay(actionSheet)
} else if groupId == AnyHashable("featuredTop") {
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
return
}
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Collections.FeaturedStickerPacks())
|> deliverOnMainQueue).start(next: { featuredStickerPacks in
var stickerPackIds: [Int64] = []
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
for featuredStickerPack in featuredStickerPacks {
stickerPackIds.append(featuredStickerPack.info.id.id)
}
let _ = ApplicationSpecificNotice.setDismissedTrendingStickerPacks(accountManager: context.sharedContext.accountManager, values: stickerPackIds).start()

View file

@ -560,11 +560,10 @@ public final class AccountContextImpl: AccountContext {
return .single(nil)
case let .replyThread(data):
if data.isForumPost, let peerId = location.peerId {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.peerId, threadId: data.threadId)
return self.account.postbox.combinedView(keys: [viewKey])
|> map { views -> MessageId? in
if let threadInfo = views.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.data.get(MessageHistoryThreadData.self) {
return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: data.maxOutgoingReadId)
return self.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: data.peerId, threadId: data.threadId))
|> map { threadData -> MessageId? in
if let threadData {
return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: threadData.maxOutgoingReadId)
} else {
return nil
}
@ -583,26 +582,13 @@ public final class AccountContextImpl: AccountContext {
public func chatLocationUnreadCount(for location: ChatLocation, contextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<Int, NoError> {
switch location {
case let .peer(peerId):
let unreadCountsKey: PostboxViewKey = .unreadCounts(items: [.peer(id: peerId, handleThreads: false), .total(nil)])
return self.account.postbox.combinedView(keys: [unreadCountsKey])
|> map { views in
var unreadCount: Int32 = 0
if let view = views.views[unreadCountsKey] as? UnreadMessageCountsView {
if let count = view.count(for: .peer(id: peerId, handleThreads: false)) {
unreadCount = count
}
}
return Int(unreadCount)
}
return self.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.PeerUnreadCount(id: peerId, handleThreads: false))
case let .replyThread(data):
if data.isForumPost {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.peerId, threadId: data.threadId)
return self.account.postbox.combinedView(keys: [viewKey])
|> map { views -> Int in
if let threadInfo = views.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.data.get(MessageHistoryThreadData.self) {
return Int(data.incomingUnreadCount)
return self.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: data.peerId, threadId: data.threadId))
|> map { threadData -> Int in
if let threadData {
return Int(threadData.incomingUnreadCount)
} else {
return 0
}

View file

@ -652,16 +652,9 @@ extension ChatControllerImpl {
let threadInfo: Signal<EngineMessageHistoryThread.Info?, NoError>
if let threadId = chatLocation.threadId {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
threadInfo = context.account.postbox.combinedView(keys: [viewKey])
|> map { views -> EngineMessageHistoryThread.Info? in
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
return nil
}
guard let data = view.info?.data.get(MessageHistoryThreadData.self) else {
return nil
}
return data.info
threadInfo = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: peerId, threadId: threadId))
|> map { threadData -> EngineMessageHistoryThread.Info? in
return threadData?.info
}
|> distinctUntilChanged
} else {
@ -1244,26 +1237,24 @@ extension ChatControllerImpl {
guard let replyThreadId = replyThreadId else {
return .single((message, nil, 0))
}
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: replyThreadId)
let countViewKey: PostboxViewKey = .historyTagSummaryView(tag: MessageTags(), peerId: peerId, threadId: replyThreadId, namespace: Namespaces.Message.Cloud, customTag: nil)
let localCountViewKey: PostboxViewKey = .historyTagSummaryView(tag: MessageTags(), peerId: peerId, threadId: replyThreadId, namespace: Namespaces.Message.Local, customTag: nil)
return context.account.postbox.combinedView(keys: [viewKey, countViewKey, localCountViewKey])
|> map { views -> (message: Message?, threadData: MessageHistoryThreadData?, messageCount: Int) in
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
return (message, nil, 0)
}
return context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: peerId, threadId: replyThreadId),
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: replyThreadId, tag: MessageTags()),
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: replyThreadId, tag: MessageTags(), namespace: Namespaces.Message.Local)
)
|> map { threadData, cloudCount, localCount -> (message: Message?, threadData: MessageHistoryThreadData?, messageCount: Int) in
var messageCount = 0
if let summaryView = views.views[countViewKey] as? MessageHistoryTagSummaryView, let count = summaryView.count {
if let count = cloudCount {
if replyThreadId == 1 {
messageCount += Int(count)
messageCount += count
} else {
messageCount += max(Int(count) - 1, 0)
messageCount += max(count - 1, 0)
}
}
if let summaryView = views.views[localCountViewKey] as? MessageHistoryTagSummaryView, let count = summaryView.count {
messageCount += Int(count)
if let count = localCount {
messageCount += count
}
return (message, view.info?.data.get(MessageHistoryThreadData.self), messageCount)
return (message, threadData, messageCount)
}
}
@ -1277,29 +1268,16 @@ extension ChatControllerImpl {
let savedMessagesPeer: Signal<(peer: EnginePeer?, messageCount: Int, presence: EnginePeer.Presence?, isMonoforumFeeRemoved: Bool)?, NoError>
if let savedMessagesPeerId {
let threadPeerId = savedMessagesPeerId
let basicPeerKey: PostboxViewKey = .peer(peerId: threadPeerId, components: [])
let countViewKey: PostboxViewKey = .historyTagSummaryView(tag: MessageTags(), peerId: peerId, threadId: savedMessagesPeerId.toInt64(), namespace: Namespaces.Message.Cloud, customTag: nil)
let threadInfoKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: savedMessagesPeerId.toInt64())
savedMessagesPeer = context.account.postbox.combinedView(keys: [basicPeerKey, countViewKey, threadInfoKey])
|> map { views -> (peer: EnginePeer?, messageCount: Int, presence: EnginePeer.Presence?, isMonoforumFeeRemoved: Bool)? in
var peer: EnginePeer?
var presence: EnginePeer.Presence?
if let peerView = views.views[basicPeerKey] as? PeerView {
peer = peerViewMainPeer(peerView).flatMap(EnginePeer.init)
presence = peerView.peerPresences[threadPeerId].flatMap(EnginePeer.Presence.init)
}
var messageCount = 0
if let summaryView = views.views[countViewKey] as? MessageHistoryTagSummaryView, let count = summaryView.count {
messageCount += Int(count)
}
var isMonoforumFeeRemoved = false
if let threadInfoView = views.views[threadInfoKey] as? MessageHistoryThreadInfoView, let threadInfo = threadInfoView.info?.data.get(MessageHistoryThreadData.self) {
isMonoforumFeeRemoved = threadInfo.isMessageFeeRemoved
}
savedMessagesPeer = context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Peer.MainPeer(id: threadPeerId),
TelegramEngine.EngineData.Item.Peer.Presence(id: threadPeerId),
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: savedMessagesPeerId.toInt64(), tag: MessageTags()),
TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: peerId, threadId: savedMessagesPeerId.toInt64())
)
|> map { peer, presence, count, threadInfo -> (peer: EnginePeer?, messageCount: Int, presence: EnginePeer.Presence?, isMonoforumFeeRemoved: Bool)? in
let messageCount = count.flatMap(Int.init) ?? 0
let isMonoforumFeeRemoved = threadInfo?.isMessageFeeRemoved ?? false
return (peer, messageCount, presence, isMonoforumFeeRemoved)
}
|> distinctUntilChanged(isEqual: { lhs, rhs in
@ -2134,13 +2112,9 @@ extension ChatControllerImpl {
let threadData: Signal<ChatPresentationInterfaceState.ThreadData?, NoError>
let forumTopicData: Signal<ChatPresentationInterfaceState.ThreadData?, NoError>
if let threadId = chatLocation.threadId {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
threadData = context.account.postbox.combinedView(keys: [viewKey])
|> map { views -> ChatPresentationInterfaceState.ThreadData? in
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
return nil
}
guard let data = view.info?.data.get(MessageHistoryThreadData.self) else {
threadData = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: peerId, threadId: threadId))
|> map { threadData -> ChatPresentationInterfaceState.ThreadData? in
guard let data = threadData else {
return nil
}
return ChatPresentationInterfaceState.ThreadData(title: data.info.title, icon: data.info.icon, iconColor: data.info.iconColor, isOwnedByMe: data.isOwnedByMe, isClosed: data.isClosed)
@ -2151,13 +2125,9 @@ extension ChatControllerImpl {
forumTopicData = isForum
|> mapToSignal { isForum -> Signal<ChatPresentationInterfaceState.ThreadData?, NoError> in
if isForum {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: 1)
return context.account.postbox.combinedView(keys: [viewKey])
|> map { views -> ChatPresentationInterfaceState.ThreadData? in
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
return nil
}
guard let data = view.info?.data.get(MessageHistoryThreadData.self) else {
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: peerId, threadId: 1))
|> map { threadData -> ChatPresentationInterfaceState.ThreadData? in
guard let data = threadData else {
return nil
}
return ChatPresentationInterfaceState.ThreadData(title: data.info.title, icon: data.info.icon, iconColor: data.info.iconColor, isOwnedByMe: data.isOwnedByMe, isClosed: data.isClosed)