[WIP] Topics

This commit is contained in:
Ali 2022-10-11 18:38:58 +04:00
parent 9a08911483
commit db4b73ae6b
92 changed files with 1900 additions and 909 deletions

View File

@ -49,7 +49,7 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
}
if !isMuted && hasUnread {
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: index.messageIndex.id.peerId), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: .combinedLocation)
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: index.messageIndex.id.peerId, threadId: nil), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: .combinedLocation)
|> take(1)
|> map { view -> [INMessage] in
var messages: [INMessage] = []

View File

@ -8114,3 +8114,5 @@ Sorry for the inconvenience.";
"ChatList.StartAction" = "Start";
"ChatList.CloseAction" = "Close";
"Channel.EditAdmin.PermissionCreateTopics" = "Create Topics";

View File

@ -159,7 +159,7 @@ private func getCommonTimeline(friends: [Friend]?, in context: TimelineProviderC
if let readState = transaction.getCombinedPeerReadState(peer.id), readState.count > 0 {
var isMuted = false
if let notificationSettings = transaction.getPeerNotificationSettings(peer.id) as? TelegramPeerNotificationSettings {
if let notificationSettings = transaction.getPeerNotificationSettings(id: peer.id) as? TelegramPeerNotificationSettings {
isMuted = notificationSettings.isRemovedFromTotalUnreadCount(default: false)
}
badge = WidgetDataPeer.Badge(

View File

@ -397,7 +397,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
isMuted = true
}
items.append(.action(ContextMenuActionItem(text: isMuted ? strings.ChatList_Context_Unmute : strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId, threadId: nil)
|> deliverOnMainQueue).start(completed: {
f(.default)
})

View File

@ -492,7 +492,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return
}
chatTitleView.titleContent = .peer(peerView: peerView, customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false)
chatTitleView.titleContent = .peer(peerView: peerView, customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: nil)
strongSelf.infoReady.set(.single(true))
if let channel = peerView.peers[peerView.peerId] as? TelegramChannel, !channel.flags.contains(.isForum) {
@ -2468,112 +2468,122 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
public static func openMoreMenu(context: AccountContext, peerId: EnginePeer.Id, sourceController: ViewController, isViewingAsTopics: Bool, sourceView: UIView, gesture: ContextGesture?) {
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: "View as Topics", icon: { theme in
if !isViewingAsTopics {
return nil
}
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, a in
a(.default)
guard let sourceController = sourceController, let navigationController = sourceController.navigationController as? NavigationController else {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).start(next: { peer in
guard case let .channel(channel) = peer else {
return
}
let chatController = context.sharedContext.makeChatListController(context: context, location: .forum(peerId: peerId), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false)
navigationController.replaceController(sourceController, with: chatController, animated: false)
})))
items.append(.action(ContextMenuActionItem(text: "View as Messages", icon: { theme in
if isViewingAsTopics {
return nil
}
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, a in
a(.default)
guard let sourceController = sourceController, let navigationController = sourceController.navigationController as? NavigationController else {
return
}
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peerId), subject: nil, botStart: nil, mode: .standard(previewing: false))
navigationController.replaceController(sourceController, with: chatController, animated: false)
})))
items.append(.separator)
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Group Info", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/CreateGroupActionIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, f in
f(.default)
var items: [ContextMenuItem] = []
let _ = (context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
)
|> deliverOnMainQueue).start(next: { peer in
guard let sourceController = sourceController, let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) else {
return
items.append(.action(ContextMenuActionItem(text: "View as Topics", icon: { theme in
if !isViewingAsTopics {
return nil
}
(sourceController.navigationController as? NavigationController)?.pushViewController(controller)
})
})))
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add Member", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, f in
f(.default)
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).start(next: { peer in
guard let sourceController = sourceController, let peer = peer else {
return
}
let selectAddMemberDisposable = MetaDisposable()
let addMemberDisposable = MetaDisposable()
context.sharedContext.openAddPeerMembers(context: context, updatedPresentationData: nil, parentController: sourceController, groupPeer: peer._asPeer(), selectAddMemberDisposable: selectAddMemberDisposable, addMemberDisposable: addMemberDisposable)
})
})))
items.append(.separator)
if let sourceController = sourceController as? ChatController {
items.append(.action(ContextMenuActionItem(text: strings.Conversation_Search, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] action in
action.dismissWithResult(.default)
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, a in
a(.default)
sourceController?.beginMessageSearch("")
guard let sourceController = sourceController, let navigationController = sourceController.navigationController as? NavigationController else {
return
}
let chatController = context.sharedContext.makeChatListController(context: context, location: .forum(peerId: peerId), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false)
navigationController.replaceController(sourceController, with: chatController, animated: false)
})))
} else {
items.append(.action(ContextMenuActionItem(text: "View as Messages", icon: { theme in
if isViewingAsTopics {
return nil
}
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, a in
a(.default)
guard let sourceController = sourceController, let navigationController = sourceController.navigationController as? NavigationController else {
return
}
let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peerId), subject: nil, botStart: nil, mode: .standard(previewing: false))
navigationController.replaceController(sourceController, with: chatController, animated: false)
})))
items.append(.separator)
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "New Topic", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
}, action: { action in
action.dismissWithResult(.default)
items.append(.action(ContextMenuActionItem(text: "Group Info", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/CreateGroupActionIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, f in
f(.default)
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
controller.navigationPresentation = .modal
controller.completion = { title, fileId in
let availableColors: [Int32] = [0x6FB9F0, 0xFFD67E, 0xCB86DB, 0x8EEE98, 0xFF93B2, 0xFB6F5F]
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: availableColors.randomElement()!, iconFileId: fileId)
|> deliverOnMainQueue).start(next: { topicId in
if let navigationController = (sourceController.navigationController as? NavigationController) {
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, navigationController: navigationController, activateInput: .text).start()
}
})
}
sourceController.push(controller)
let _ = (context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
)
|> deliverOnMainQueue).start(next: { peer in
guard let sourceController = sourceController, let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) else {
return
}
(sourceController.navigationController as? NavigationController)?.pushViewController(controller)
})
})))
}
if channel.hasPermission(.inviteMembers) {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add Member", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, f in
f(.default)
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).start(next: { peer in
guard let sourceController = sourceController, let peer = peer else {
return
}
let selectAddMemberDisposable = MetaDisposable()
let addMemberDisposable = MetaDisposable()
context.sharedContext.openAddPeerMembers(context: context, updatedPresentationData: nil, parentController: sourceController, groupPeer: peer._asPeer(), selectAddMemberDisposable: selectAddMemberDisposable, addMemberDisposable: addMemberDisposable)
})
})))
}
if let sourceController = sourceController as? ChatController {
items.append(.separator)
items.append(.action(ContextMenuActionItem(text: strings.Conversation_Search, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] action in
action.dismissWithResult(.default)
sourceController?.beginMessageSearch("")
})))
} else if channel.hasPermission(.pinMessages) {
items.append(.separator)
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "New Topic", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
}, action: { action in
action.dismissWithResult(.default)
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
controller.navigationPresentation = .modal
controller.completion = { title, fileId in
let availableColors: [Int32] = [0x6FB9F0, 0xFFD67E, 0xCB86DB, 0x8EEE98, 0xFF93B2, 0xFB6F5F]
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: availableColors.randomElement()!, iconFileId: fileId)
|> deliverOnMainQueue).start(next: { topicId in
if let navigationController = (sourceController.navigationController as? NavigationController) {
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, navigationController: navigationController, activateInput: .text).start()
}
})
}
sourceController.push(controller)
})))
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: sourceController, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
sourceController.presentInGlobalOverlay(contextController)
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: sourceController, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
sourceController.presentInGlobalOverlay(contextController)
})
}
private var initializedFilters = false

View File

@ -183,7 +183,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
let timestamp1: Int32 = 100000
let peers: [EnginePeer.Id: EnginePeer] = [:]
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture, _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture, _ in
gesture?.cancel()
}, present: { _ in })

View File

@ -1741,6 +1741,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
}, setPeerIdWithRevealedOptions: { _, _ in
}, setItemPinned: { _, _ in
}, setPeerMuted: { _, _ in
}, setPeerThreadMuted: { _, _, _ in
}, deletePeer: { _, _ in
}, deletePeerThread: { _, _ in
}, updatePeerGrouping: { _, _ in
@ -2952,7 +2953,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
var peers: [EnginePeer.Id: EnginePeer] = [:]
peers[peer1.id] = peer1
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture, _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture, _ in
gesture?.cancel()
}, present: { _ in })

View File

@ -2688,6 +2688,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
switch option.key {
case RevealOptionKey.delete.rawValue:
item.interaction.deletePeerThread(peerId, threadId)
case RevealOptionKey.mute.rawValue:
item.interaction.setPeerThreadMuted(peerId, threadId, true)
close = false
case RevealOptionKey.unmute.rawValue:
item.interaction.setPeerThreadMuted(peerId, threadId, false)
close = false
default:
break
}

View File

@ -67,6 +67,7 @@ public final class ChatListNodeInteraction {
let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void
let setItemPinned: (EngineChatList.PinnedItem.Id, Bool) -> Void
let setPeerMuted: (EnginePeer.Id, Bool) -> Void
let setPeerThreadMuted: (EnginePeer.Id, Int64?, Bool) -> Void
let deletePeer: (EnginePeer.Id, Bool) -> Void
let deletePeerThread: (EnginePeer.Id, Int64) -> Void
let updatePeerGrouping: (EnginePeer.Id, Bool) -> Void
@ -98,6 +99,7 @@ public final class ChatListNodeInteraction {
setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void,
setItemPinned: @escaping (EngineChatList.PinnedItem.Id, Bool) -> Void,
setPeerMuted: @escaping (EnginePeer.Id, Bool) -> Void,
setPeerThreadMuted: @escaping (EnginePeer.Id, Int64?, Bool) -> Void,
deletePeer: @escaping (EnginePeer.Id, Bool) -> Void,
deletePeerThread: @escaping (EnginePeer.Id, Int64) -> Void,
updatePeerGrouping: @escaping (EnginePeer.Id, Bool) -> Void,
@ -119,6 +121,7 @@ public final class ChatListNodeInteraction {
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
self.setItemPinned = setItemPinned
self.setPeerMuted = setPeerMuted
self.setPeerThreadMuted = setPeerThreadMuted
self.deletePeer = deletePeer
self.deletePeerThread = deletePeerThread
self.updatePeerGrouping = updatePeerGrouping
@ -946,7 +949,7 @@ public final class ChatListNode: ListView {
return
}
strongSelf.setCurrentRemovingPeerId(peerId)
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId, threadId: nil)
|> deliverOnMainQueue).start(completed: {
self?.updateState { state in
var state = state
@ -955,6 +958,17 @@ public final class ChatListNode: ListView {
}
self?.setCurrentRemovingPeerId(nil)
})
}, setPeerThreadMuted: { [weak self] peerId, threadId, _ in
//self?.setCurrentRemovingPeerId(peerId)
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId, threadId: threadId)
|> deliverOnMainQueue).start(completed: {
self?.updateState { state in
var state = state
state.peerIdWithRevealedOptions = nil
return state
}
//self?.setCurrentRemovingPeerId(nil)
})
}, deletePeer: { [weak self] peerId, joined in
self?.deletePeerChat?(peerId, joined)
}, deletePeerThread: { [weak self] peerId, threadId in
@ -1799,8 +1813,11 @@ public final class ChatListNode: ListView {
if let combinedReadState = combinedReadState {
hasUnread = combinedReadState.count > 0
}
if case let .chatList(index) = index {
preloadItems.append(ChatHistoryPreloadItem(index: index, isMuted: isMuted, hasUnread: hasUnread))
switch index {
case let .chatList(index):
preloadItems.append(ChatHistoryPreloadItem(index: index, threadId: nil, isMuted: isMuted, hasUnread: hasUnread))
case .forum:
break
}
}
default:

View File

@ -166,7 +166,27 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
}
}
case let .forum(peerId):
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(id: peerId)
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(
id: peerId,
summaryComponents: ChatListEntrySummaryComponents(
components: [
ChatListEntryMessageTagSummaryKey(
tag: .unseenPersonalMessage,
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
): ChatListEntrySummaryComponents.Component(
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
),
ChatListEntryMessageTagSummaryKey(
tag: .unseenReaction,
actionType: PendingMessageActionType.readReaction
): ChatListEntrySummaryComponents.Component(
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
)
]
)
)
var isFirst = false
return account.postbox.combinedView(keys: [viewKey])
|> map { views -> ChatListNodeViewUpdate in
@ -182,18 +202,41 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
guard let data = item.info.get(MessageHistoryThreadData.self) else {
continue
}
var hasUnseenMentions = false
var isMuted = false
if case .muted = data.notificationSettings.muteState {
isMuted = true
}
if let info = item.tagSummaryInfo[ChatListEntryMessageTagSummaryKey(
tag: .unseenPersonalMessage,
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
)] {
hasUnseenMentions = (info.tagSummaryCount ?? 0) > (info.actionsSummaryCount ?? 0)
}
var hasUnseenReactions = false
if let info = item.tagSummaryInfo[ChatListEntryMessageTagSummaryKey(
tag: .unseenReaction,
actionType: PendingMessageActionType.readReaction
)] {
hasUnseenReactions = (info.tagSummaryCount ?? 0) != 0// > (info.actionsSummaryCount ?? 0)
}
items.append(EngineChatList.Item(
id: .forum(item.id),
index: .forum(timestamp: item.index.timestamp, threadId: item.id, namespace: item.index.id.namespace, id: item.index.id.id),
messages: item.topMessage.flatMap { [EngineMessage($0)] } ?? [],
readCounters: EnginePeerReadCounters(state: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, .idBased(maxIncomingReadId: 1, maxOutgoingReadId: 1, maxKnownId: 1, count: data.incomingUnreadCount, markedUnread: false))])),
isMuted: false,
isMuted: isMuted,
draft: nil,
threadInfo: data.info,
renderedPeer: EngineRenderedPeer(peer: EnginePeer(peer)),
presence: nil,
hasUnseenMentions: false,
hasUnseenReactions: false,
hasUnseenMentions: hasUnseenMentions,
hasUnseenReactions: hasUnseenReactions,
forumTopicTitle: nil,
hasFailed: false,
isContact: false

View File

@ -18,6 +18,17 @@ public extension ChatLocation {
return nil
}
}
var threadId: Int64? {
switch self {
case .peer:
return nil
case let .replyThread(replyThreadMessage):
return Int64(replyThreadMessage.messageId.id)
case .feed:
return nil
}
}
}
public enum ChatPresentationInputQueryKind: Int32 {

View File

@ -76,6 +76,7 @@ public final class HashtagSearchController: TelegramBaseController {
}, setPeerIdWithRevealedOptions: { _, _ in
}, setItemPinned: { _, _ in
}, setPeerMuted: { _, _ in
}, setPeerThreadMuted: { _, _, _ in
}, deletePeer: { _, _ in
}, deletePeerThread: { _, _ in
}, updatePeerGrouping: { _, _ in

View File

@ -416,7 +416,7 @@ private struct ChannelAdminControllerState: Equatable {
}
}
private func stringForRight(strings: PresentationStrings, right: TelegramChatAdminRightsFlags, isGroup: Bool, isChannel: Bool, defaultBannedRights: TelegramChatBannedRights?) -> String {
private func stringForRight(strings: PresentationStrings, right: TelegramChatAdminRightsFlags, isGroup: Bool, isChannel: Bool, isForum: Bool, defaultBannedRights: TelegramChatBannedRights?) -> String {
if right.contains(.canChangeInfo) {
return isGroup ? strings.Group_EditAdmin_PermissionChangeInfo : strings.Channel_EditAdmin_PermissionChangeInfo
} else if right.contains(.canPostMessages) {
@ -438,7 +438,11 @@ private func stringForRight(strings: PresentationStrings, right: TelegramChatAdm
return strings.Channel_EditAdmin_PermissionInviteSubscribers
}
} else if right.contains(.canPinMessages) {
return strings.Channel_EditAdmin_PermissionPinMessages
if isForum {
return strings.Channel_EditAdmin_PermissionCreateTopics
} else {
return strings.Channel_EditAdmin_PermissionPinMessages
}
} else if right.contains(.canAddAdmins) {
return strings.Channel_EditAdmin_PermissionAddAdmins
} else if right.contains(.canBeAnonymous) {
@ -612,7 +616,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
var index = 0
for right in rightsOrder {
if accountUserRightsFlags.contains(right) {
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), right == .canBeAnonymous))
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, isForum: channel.flags.contains(.isForum), defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), right == .canBeAnonymous))
index += 1
}
}
@ -651,7 +655,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
var index = 0
for right in rightsOrder {
if accountUserRightsFlags.contains(right) {
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && admin.id != accountPeerId && !rightEnabledByDefault(channelPeer: channel, right: right)))
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, isForum: channel.flags.contains(.isForum), defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && admin.id != accountPeerId && !rightEnabledByDefault(channelPeer: channel, right: right)))
index += 1
}
}
@ -683,7 +687,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
} else if let initialParticipant = initialParticipant, case let .member(_, _, maybeAdminInfo, _, _) = initialParticipant, let adminInfo = maybeAdminInfo {
var index = 0
for right in rightsOrder {
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, adminInfo.rights.rights, adminInfo.rights.rights.contains(right), false))
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, isForum: channel.flags.contains(.isForum), defaultBannedRights: channel.defaultBannedRights), right, adminInfo.rights.rights, adminInfo.rights.rights.contains(right), false))
index += 1
}
}
@ -782,7 +786,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
var index = 0
for right in rightsOrder {
if accountUserRightsFlags.contains(right) {
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: group.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && accountIsCreator))
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, isForum: false, defaultBannedRights: group.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && accountIsCreator))
index += 1
}
}

View File

@ -293,7 +293,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
var index = 0
for (right, _) in allGroupPermissionList {
let defaultEnabled = !defaultBannedRights.flags.contains(right) && channel.hasPermission(.banMembers)
entries.append(.rightItem(presentationData.theme, index, stringForGroupPermission(strings: presentationData.strings, right: right), right, defaultEnabled && !currentRightsFlags.contains(right), defaultEnabled && !state.updating))
entries.append(.rightItem(presentationData.theme, index, stringForGroupPermission(strings: presentationData.strings, right: right, isForum: channel.flags.contains(.isForum)), right, defaultEnabled && !currentRightsFlags.contains(right), defaultEnabled && !state.updating))
index += 1
}
@ -339,7 +339,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
var index = 0
for (right, _) in allGroupPermissionList {
let defaultEnabled = !defaultBannedRightsFlags.contains(right)
entries.append(.rightItem(presentationData.theme, index, stringForGroupPermission(strings: presentationData.strings, right: right), right, defaultEnabled && !currentRightsFlags.contains(right), defaultEnabled && !state.updating))
entries.append(.rightItem(presentationData.theme, index, stringForGroupPermission(strings: presentationData.strings, right: right, isForum: false), right, defaultEnabled && !currentRightsFlags.contains(right), defaultEnabled && !state.updating))
index += 1
}

View File

@ -336,7 +336,7 @@ private struct ChannelPermissionsControllerState: Equatable {
var modifiedSlowmodeTimeout: Int32?
}
func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatBannedRightsFlags) -> String {
func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatBannedRightsFlags, isForum: Bool) -> String {
if right.contains(.banSendMessages) {
return strings.Channel_BanUser_PermissionSendMessages
} else if right.contains(.banSendMedia) {
@ -352,7 +352,11 @@ func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatB
} else if right.contains(.banAddMembers) {
return strings.Channel_BanUser_PermissionAddMembers
} else if right.contains(.banPinMessages) {
return strings.Channel_EditAdmin_PermissionPinMessages
if isForum {
return strings.Channel_EditAdmin_PermissionCreateTopics
} else {
return strings.Channel_EditAdmin_PermissionPinMessages
}
} else {
return ""
}
@ -442,7 +446,7 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
if !channel.hasPermission(correspondingAdminRight) {
enabled = false
}
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights), !effectiveRightsFlags.contains(rights), rights, enabled))
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights, isForum: channel.flags.contains(.isForum)), !effectiveRightsFlags.contains(rights), rights, enabled))
rightIndex += 1
}
@ -479,7 +483,7 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
entries.append(.permissionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_SectionTitle))
var rightIndex: Int = 0
for (rights, _) in allGroupPermissionList {
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights), !effectiveRightsFlags.contains(rights), rights, true))
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights, isForum: false), !effectiveRightsFlags.contains(rights), rights, true))
rightIndex += 1
}

View File

@ -260,7 +260,7 @@ final class ChatListTable: Table {
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(messageIndex.id.peerId))
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: filterPredicate.messageTagSummary)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: filterPredicate.messageTagSummary)
if filterPredicate.pinnedPeerIds.contains(peer.id) {
passFilter = true
@ -895,7 +895,7 @@ final class ChatListTable: Table {
}
var tagSummary: MessageHistoryTagNamespaceSummary?
if let summaryTag = summaryTag {
tagSummary = summaryTable.get(MessageHistoryTagsSummaryKey(tag: summaryTag, peerId: peerIndex.messageIndex.id.peerId, namespace: namespace))
tagSummary = summaryTable.get(MessageHistoryTagsSummaryKey(tag: summaryTag, peerId: peerIndex.messageIndex.id.peerId, threadId: nil, namespace: namespace))
}
var topMessageAttributes: [MessageAttribute] = []
if let topMessage = topMessage {

View File

@ -10,7 +10,7 @@ public struct ChatListEntryMessageTagSummaryKey: Hashable {
}
}
public struct ChatListEntryMessageTagSummaryComponent {
public struct ChatListEntryMessageTagSummaryComponent: Equatable {
public let namespace: MessageId.Namespace
public init(namespace: MessageId.Namespace) {
@ -18,7 +18,7 @@ public struct ChatListEntryMessageTagSummaryComponent {
}
}
public struct ChatListEntryPendingMessageActionsSummaryComponent {
public struct ChatListEntryPendingMessageActionsSummaryComponent: Equatable {
public let namespace: MessageId.Namespace
public init(namespace: MessageId.Namespace) {
@ -26,8 +26,8 @@ public struct ChatListEntryPendingMessageActionsSummaryComponent {
}
}
public struct ChatListEntrySummaryComponents {
public struct Component {
public struct ChatListEntrySummaryComponents: Equatable {
public struct Component: Equatable {
public let tagSummary: ChatListEntryMessageTagSummaryComponent?
public let actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent?

View File

@ -63,7 +63,7 @@ private func mappedChatListFilterPredicate(postbox: PostboxImpl, currentTransact
let notificationsPeerId = peer.notificationSettingsPeerId ?? peer.id
let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId)
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId))
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: predicate.messageTagSummary)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: predicate.messageTagSummary)
if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) {
return true
@ -402,7 +402,7 @@ private final class ChatListViewSpaceState {
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId))
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: filterPredicate.messageTagSummary)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: filterPredicate.messageTagSummary)
if !filterPredicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: postbox.readStateTable.getCombinedState(peer.id)?.isUnread ?? false, isContact: postbox.contactsTable.isContact(peerId: notificationsPeerId), messageTagSummaryResult: messageTagSummaryResult) {
continue inner
@ -498,7 +498,7 @@ private final class ChatListViewSpaceState {
if !transaction.currentUpdatedPeerNotificationSettings.isEmpty, case let .group(groupId, pinned, maybeFilterPredicate) = self.space, let filterPredicate = maybeFilterPredicate {
var removeEntryIndices: [MutableChatListEntryIndex] = []
let _ = self.orderedEntries.mutableScan { entry in
let _ = self.orderedEntries.mutableScan { entry -> MutableChatListEntry? in
let entryPeer: Peer
let entryNotificationsPeerId: PeerId
switch entry {
@ -532,7 +532,7 @@ private final class ChatListViewSpaceState {
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: entryPeer, peerSettings: settingsChange.1)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, calculation: filterPredicate.messageTagSummary)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, threadId: nil, calculation: filterPredicate.messageTagSummary)
let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId), messageTagSummaryResult: messageTagSummaryResult)
if !isIncluded {
@ -570,7 +570,7 @@ private final class ChatListViewSpaceState {
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: settingsChange.1)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, calculation: filterPredicate.messageTagSummary)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, threadId: nil, calculation: filterPredicate.messageTagSummary)
let isIncluded = filterPredicate.includes(peer: mainPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: peerId), messageTagSummaryResult: messageTagSummaryResult)
if isIncluded && self.orderedEntries.indicesForPeerId(mainPeer.id) == nil {
@ -730,7 +730,7 @@ private final class ChatListViewSpaceState {
if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty, case let .group(groupId, pinned, maybeFilterPredicate) = self.space, let filterPredicate = maybeFilterPredicate, let filterMessageTagSummary = filterPredicate.messageTagSummary {
var removeEntryIndices: [MutableChatListEntryIndex] = []
let _ = self.orderedEntries.mutableScan { entry in
let _ = self.orderedEntries.mutableScan { entry -> MutableChatListEntry? in
let entryPeer: Peer
let entryNotificationsPeerId: PeerId
switch entry {
@ -752,7 +752,7 @@ private final class ChatListViewSpaceState {
return nil
}
let updatedMessageSummary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: filterMessageTagSummary.addCount.tag, peerId: entryPeer.id, namespace: filterMessageTagSummary.addCount.namespace)]
let updatedMessageSummary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: filterMessageTagSummary.addCount.tag, peerId: entryPeer.id, threadId: nil, namespace: filterMessageTagSummary.addCount.namespace)]
let updatedActionsSummary = transaction.currentUpdatedMessageActionsSummaries[PendingMessageActionsSummaryKey(type: filterMessageTagSummary.subtractCount.type, peerId: entryPeer.id, namespace: filterMessageTagSummary.subtractCount.namespace)]
if updatedMessageSummary != nil || updatedActionsSummary != nil {
@ -768,7 +768,7 @@ private final class ChatListViewSpaceState {
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: entryPeer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(entryPeer.id))
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, calculation: filterPredicate.messageTagSummary)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, threadId: nil, calculation: filterPredicate.messageTagSummary)
let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId), messageTagSummaryResult: messageTagSummaryResult)
if !isIncluded {
@ -813,7 +813,7 @@ private final class ChatListViewSpaceState {
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(mainPeer.id))
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, calculation: filterPredicate.messageTagSummary)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, threadId: nil, calculation: filterPredicate.messageTagSummary)
let isIncluded = filterPredicate.includes(peer: mainPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: peerId), messageTagSummaryResult: messageTagSummaryResult)
if isIncluded && self.orderedEntries.indicesForPeerId(mainPeer.id) == nil {
@ -852,7 +852,7 @@ private final class ChatListViewSpaceState {
for (key, component) in self.summaryComponents.components {
var updatedTagSummaryCount: Int32?
if let tagSummary = component.tagSummary {
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: index.messageIndex.id.peerId, namespace: tagSummary.namespace)
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: index.messageIndex.id.peerId, threadId: nil, namespace: tagSummary.namespace)
if let summary = transaction.currentUpdatedMessageTagSummaries[key] {
updatedTagSummaryCount = summary.count
}
@ -1428,7 +1428,7 @@ struct ChatListViewState {
var actionsSummaryCount: Int32?
if let tagSummary = component.tagSummary {
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: index.messageIndex.id.peerId, namespace: tagSummary.namespace)
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: index.messageIndex.id.peerId, threadId: nil, namespace: tagSummary.namespace)
if let summary = postbox.messageHistoryTagsSummaryTable.get(key) {
tagSummaryCount = summary.count
}

View File

@ -2,12 +2,36 @@ import Foundation
import SwiftSignalKit
public enum ChatLocationInput {
case peer(peerId: PeerId)
case peer(peerId: PeerId, threadId: Int64?)
case thread(peerId: PeerId, threadId: Int64, data: Signal<MessageHistoryViewExternalInput, NoError>)
case feed(id: Int32, data: Signal<MessageHistoryViewExternalInput, NoError>)
}
public extension ChatLocationInput {
var peerId: PeerId? {
switch self {
case let .peer(peerId, _):
return peerId
case let .thread(peerId, _, _):
return peerId
case .feed:
return nil
}
}
var threadId: Int64? {
switch self {
case let .peer(_, threadId):
return threadId
case let .thread(_, threadId, _):
return threadId
case .feed:
return nil
}
}
}
public enum ResolvedChatLocationInput {
case peer(PeerId)
case peer(peerId: PeerId, threadId: Int64?)
case external(MessageHistoryViewExternalInput)
}

View File

@ -3,7 +3,15 @@ import Foundation
struct MessageHistoryIndexHoleOperationKey: Hashable {
let peerId: PeerId
let namespace: MessageId.Namespace
let threadId: Int64?
let space: MessageHistoryHoleSpace
init(peerId: PeerId, namespace: MessageId.Namespace, threadId: Int64?, space: MessageHistoryHoleSpace) {
self.peerId = peerId
self.namespace = namespace
self.threadId = threadId
self.space = space
}
}
enum MessageHistoryIndexHoleOperation {
@ -25,8 +33,8 @@ public enum MessageHistoryHoleSpace: Equatable, Hashable, CustomStringConvertibl
}
}
private func addOperation(_ operation: MessageHistoryIndexHoleOperation, peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, to operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
let key = MessageHistoryIndexHoleOperationKey(peerId: peerId, namespace: namespace, space: space)
func addMessageHistoryHoleOperation(_ operation: MessageHistoryIndexHoleOperation, peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, to operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
let key = MessageHistoryIndexHoleOperationKey(peerId: peerId, namespace: namespace, threadId: threadId, space: space)
if operations[key] == nil {
operations[key] = []
}
@ -365,7 +373,7 @@ final class MessageHistoryHoleIndexTable: Table {
self.valueBox.set(self.table, key: self.key(id: MessageId(peerId: peerId, namespace: namespace, id: closedRange.upperBound), space: space), value: MemoryBuffer(memory: &lowerBound, capacity: 4, length: 4, freeWhenDone: false))
}
addOperation(.insert(clippedRange), peerId: peerId, namespace: namespace, space: space, to: &operations)
addMessageHistoryHoleOperation(.insert(clippedRange), peerId: peerId, threadId: nil, namespace: namespace, space: space, to: &operations)
}
func remove(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
@ -431,7 +439,7 @@ final class MessageHistoryHoleIndexTable: Table {
}
if !removeKeys.isEmpty {
addOperation(.remove(range), peerId: peerId, namespace: namespace, space: space, to: &operations)
addMessageHistoryHoleOperation(.remove(range), peerId: peerId, threadId: nil, namespace: namespace, space: space, to: &operations)
}
}

View File

@ -81,6 +81,7 @@ final class MessageHistoryTable: Table {
let failedTable: MessageHistoryFailedTable
let tagsTable: MessageHistoryTagsTable
let threadsTable: MessageHistoryThreadsTable
let threadTagsTable: MessageHistoryThreadTagsTable
let globalTagsTable: GlobalMessageHistoryTagsTable
let localTagsTable: LocalMessageHistoryTagsTable
let timeBasedAttributesTable: TimestampBasedMessageAttributesTable
@ -90,7 +91,7 @@ final class MessageHistoryTable: Table {
let summaryTable: MessageHistoryTagsSummaryTable
let pendingActionsTable: PendingMessageActionsTable
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, threadsTable: MessageHistoryThreadsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, timeBasedAttributesTable: TimestampBasedMessageAttributesTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, threadsTable: MessageHistoryThreadsTable, threadTagsTable: MessageHistoryThreadTagsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, timeBasedAttributesTable: TimestampBasedMessageAttributesTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) {
self.seedConfiguration = seedConfiguration
self.messageHistoryIndexTable = messageHistoryIndexTable
self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable
@ -101,6 +102,7 @@ final class MessageHistoryTable: Table {
self.failedTable = failedTable
self.tagsTable = tagsTable
self.threadsTable = threadsTable
self.threadTagsTable = threadTagsTable
self.globalTagsTable = globalTagsTable
self.localTagsTable = localTagsTable
self.timeBasedAttributesTable = timeBasedAttributesTable
@ -278,6 +280,9 @@ final class MessageHistoryTable: Table {
if (currentTags & 1) != 0 {
let tag = MessageTags(rawValue: 1 << UInt32(i))
self.tagsTable.add(tags: tag, index: message.index, isNewlyAdded: true, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
if let threadId = message.threadId {
self.threadTagsTable.add(tags: tag, threadId: threadId, index: message.index, isNewlyAdded: true, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
}
}
}
}
@ -434,13 +439,34 @@ final class MessageHistoryTable: Table {
return globallyUniqueIdToMessageId
}
func removeMessages(_ messageIds: [MessageId], operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
func removeMessages(_ messageIds: [MessageId], operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
for (peerId, messageIds) in self.messageIdsByPeerId(messageIds) {
var operations: [MessageHistoryIndexOperation] = []
for id in messageIds {
self.messageHistoryIndexTable.removeMessage(id, operations: &operations)
}
if let forEachMedia = forEachMedia {
for operation in operations {
if case let .Remove(index) = operation {
if let message = self.getMessage(index) {
for media in self.renderMessageMedia(referencedMedia: message.referencedMedia, embeddedMediaData: message.embeddedMediaData) {
forEachMedia(media)
}
}
}
}
}
self.processIndexOperations(peerId, operations: operations, processedOperationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: &timestampBasedMessageAttributesOperations)
}
}
func removeMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
var operations: [MessageHistoryIndexOperation] = []
self.messageHistoryIndexTable.removeMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, operations: &operations)
if let forEachMedia = forEachMedia {
for operation in operations {
if case let .Remove(index) = operation {
if let message = self.getMessage(index) {
@ -450,27 +476,12 @@ final class MessageHistoryTable: Table {
}
}
}
self.processIndexOperations(peerId, operations: operations, processedOperationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: &timestampBasedMessageAttributesOperations)
}
}
func removeMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
var operations: [MessageHistoryIndexOperation] = []
self.messageHistoryIndexTable.removeMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, operations: &operations)
for operation in operations {
if case let .Remove(index) = operation {
if let message = self.getMessage(index) {
for media in self.renderMessageMedia(referencedMedia: message.referencedMedia, embeddedMediaData: message.embeddedMediaData) {
forEachMedia(media)
}
}
}
}
self.processIndexOperations(peerId, operations: operations, processedOperationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: &timestampBasedMessageAttributesOperations)
}
func clearHistoryInRange(peerId: PeerId, threadId: Int64?, minTimestamp: Int32, maxTimestamp: Int32, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
func clearHistoryInRange(peerId: PeerId, threadId: Int64?, minTimestamp: Int32, maxTimestamp: Int32, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
var indices = self.allMessageIndices(peerId: peerId).filter { namespaces.contains($0.id.namespace) }
if let threadId = threadId {
indices = indices.filter { index in
@ -491,7 +502,7 @@ final class MessageHistoryTable: Table {
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: &timestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
func clearHistory(peerId: PeerId, threadId: Int64?, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
func clearHistory(peerId: PeerId, threadId: Int64?, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
var indices = self.allMessageIndices(peerId: peerId).filter { namespaces.contains($0.id.namespace) }
if let threadId = threadId {
indices = indices.filter { index in
@ -509,12 +520,12 @@ final class MessageHistoryTable: Table {
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: &timestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
func removeAllMessagesWithAuthor(peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
func removeAllMessagesWithAuthor(peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
let indices = self.allIndicesWithAuthor(peerId: peerId, authorId: authorId, namespace: namespace)
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: &timestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
func removeAllMessagesWithGlobalTag(tag: GlobalMessageTags, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
func removeAllMessagesWithGlobalTag(tag: GlobalMessageTags, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
var indices: [MessageIndex] = []
for entry in self.allIndicesWithGlobalTag(tag: tag) {
switch entry {
@ -527,7 +538,7 @@ final class MessageHistoryTable: Table {
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: &timestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
func removeAllMessagesWithForwardAuthor(peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
func removeAllMessagesWithForwardAuthor(peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
let indices = self.allIndicesWithForwardAuthor(peerId: peerId, forwardAuthorId: forwardAuthorId, namespace: namespace)
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: &timestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
@ -1335,6 +1346,9 @@ final class MessageHistoryTable: Table {
for tag in message.tags {
self.tagsTable.remove(tags: tag, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
if let threadId = message.threadId {
self.threadTagsTable.remove(tags: tag, threadId: threadId, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
}
}
if let threadId = message.threadId {
self.threadsTable.remove(threadId: threadId, index: index)
@ -1539,10 +1553,17 @@ final class MessageHistoryTable: Table {
if previousMessage.tags != message.tags || index != updatedIndex {
if !previousMessage.tags.isEmpty {
self.tagsTable.remove(tags: previousMessage.tags, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
if let threadId = previousMessage.threadId {
self.threadTagsTable.remove(tags: previousMessage.tags, threadId: threadId, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
}
}
if !message.tags.isEmpty {
//let isNewlyAdded = previousMessage.tags.isEmpty
self.tagsTable.add(tags: message.tags, index: message.index, isNewlyAdded: false, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
if let threadId = message.threadId {
self.threadTagsTable.add(tags: message.tags, threadId: threadId, index: message.index, isNewlyAdded: false, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
}
}
}
if previousMessage.threadId != message.threadId || index != message.index {
@ -2977,54 +2998,85 @@ final class MessageHistoryTable: Table {
precondition(fromIndex.id.namespace == toIndex.id.namespace)
var result: [IntermediateMessage] = []
if let threadId = threadId {
var indices: [MessageIndex] = []
var startIndex = fromIndex
var localIncludeFrom = includeFrom
while true {
let sliceIndices: [MessageIndex]
if let tag = tag {
let indices: [MessageIndex]
if fromIndex < toIndex {
sliceIndices = self.threadsTable.laterIndices(threadId: threadId, peerId: peerId, namespace: namespace, index: startIndex, includeFrom: localIncludeFrom, count: limit)
indices = self.threadTagsTable.laterIndices(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace, index: fromIndex, includeFrom: includeFrom, count: limit)
} else {
sliceIndices = self.threadsTable.earlierIndices(threadId: threadId, peerId: peerId, namespace: namespace, index: startIndex, includeFrom: localIncludeFrom, count: limit)
indices = self.threadTagsTable.earlierIndices(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace, index: fromIndex, includeFrom: includeFrom, count: limit)
}
if sliceIndices.isEmpty {
break
}
startIndex = sliceIndices[sliceIndices.count - 1]
localIncludeFrom = false
for index in sliceIndices {
for index in indices {
if let ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange {
if ignoreMessagesInTimestampRange.contains(index.timestamp) {
continue
}
}
if let tag = tag {
if self.tagsTable.entryExists(tag: tag, index: index) {
indices.append(index)
if fromIndex < toIndex {
if index < fromIndex || index > toIndex {
continue
}
} else {
indices.append(index)
if index < toIndex || index > fromIndex {
continue
}
}
if let message = self.getMessage(index) {
result.append(message)
} else {
assertionFailure()
}
}
if indices.count >= limit {
break
}
}
for index in indices {
if fromIndex < toIndex {
if index < fromIndex || index > toIndex {
continue
} else {
var indices: [MessageIndex] = []
var startIndex = fromIndex
var localIncludeFrom = includeFrom
while true {
let sliceIndices: [MessageIndex]
if fromIndex < toIndex {
sliceIndices = self.threadsTable.laterIndices(threadId: threadId, peerId: peerId, namespace: namespace, index: startIndex, includeFrom: localIncludeFrom, count: limit)
} else {
sliceIndices = self.threadsTable.earlierIndices(threadId: threadId, peerId: peerId, namespace: namespace, index: startIndex, includeFrom: localIncludeFrom, count: limit)
}
} else {
if index < toIndex || index > fromIndex {
continue
if sliceIndices.isEmpty {
break
}
startIndex = sliceIndices[sliceIndices.count - 1]
localIncludeFrom = false
for index in sliceIndices {
if let ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange {
if ignoreMessagesInTimestampRange.contains(index.timestamp) {
continue
}
}
if let tag = tag {
if self.tagsTable.entryExists(tag: tag, index: index) {
indices.append(index)
}
} else {
indices.append(index)
}
}
if indices.count >= limit {
break
}
}
if let message = self.getMessage(index) {
result.append(message)
} else {
assertionFailure()
for index in indices {
if fromIndex < toIndex {
if index < fromIndex || index > toIndex {
continue
}
} else {
if index < toIndex || index > fromIndex {
continue
}
}
if let message = self.getMessage(index) {
result.append(message)
} else {
assertionFailure()
}
}
}
} else if let tag = tag {

View File

@ -3,22 +3,24 @@ import Foundation
final class MutableMessageHistoryTagSummaryView: MutablePostboxView {
private let tag: MessageTags
private let peerId: PeerId
private let threadId: Int64?
private let namespace: MessageId.Namespace
fileprivate var count: Int32?
init(postbox: PostboxImpl, tag: MessageTags, peerId: PeerId, namespace: MessageId.Namespace) {
init(postbox: PostboxImpl, tag: MessageTags, peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace) {
self.tag = tag
self.peerId = peerId
self.threadId = threadId
self.namespace = namespace
self.count = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: tag, peerId: peerId, namespace: namespace))?.count
self.count = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: tag, peerId: peerId, threadId: threadId, namespace: namespace))?.count
}
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
var hasChanges = false
if let summary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: self.tag, peerId: self.peerId, namespace: self.namespace)] {
if let summary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: self.tag, peerId: self.peerId, threadId: self.threadId, namespace: self.namespace)] {
self.count = summary.count
hasChanges = true
}

View File

@ -43,6 +43,7 @@ public struct MessageHistoryTagNamespaceSummary: Equatable, CustomStringConverti
struct MessageHistoryTagsSummaryKey: Equatable, Hashable {
let tag: MessageTags
let peerId: PeerId
let threadId: Int64?
let namespace: MessageId.Namespace
}
@ -80,7 +81,8 @@ class MessageHistoryTagsSummaryTable: Table {
private var cachedSummaries: [MessageHistoryTagsSummaryKey: CachedEntry] = [:]
private var updatedKeys = Set<MessageHistoryTagsSummaryKey>()
private let sharedKey = ValueBoxKey(length: 4 + 8 + 4)
private let sharedSimpleKey = ValueBoxKey(length: 4 + 8 + 4)
private let sharedThreadKey = ValueBoxKey(length: 4 + 8 + 4 + 8)
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, invalidateTable: InvalidatedMessageHistoryTagsSummaryTable) {
self.invalidateTable = invalidateTable
@ -88,17 +90,25 @@ class MessageHistoryTagsSummaryTable: Table {
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(key: MessageHistoryTagsSummaryKey, sharedKey: ValueBoxKey = ValueBoxKey(length: 4 + 8 + 4)) -> ValueBoxKey {
sharedKey.setUInt32(0, value: key.tag.rawValue)
sharedKey.setInt64(4, value: key.peerId.toInt64())
sharedKey.setInt32(4 + 8, value: key.namespace)
return sharedKey
private func keyShared(key: MessageHistoryTagsSummaryKey) -> ValueBoxKey {
if let threadId = key.threadId {
self.sharedThreadKey.setUInt32(0, value: key.tag.rawValue)
self.sharedThreadKey.setInt64(4, value: key.peerId.toInt64())
self.sharedThreadKey.setInt32(4 + 8, value: key.namespace)
self.sharedThreadKey.setInt64(4 + 8 + 4, value: threadId)
return self.sharedSimpleKey
} else {
self.sharedSimpleKey.setUInt32(0, value: key.tag.rawValue)
self.sharedSimpleKey.setInt64(4, value: key.peerId.toInt64())
self.sharedSimpleKey.setInt32(4 + 8, value: key.namespace)
return self.sharedSimpleKey
}
}
func get(_ key: MessageHistoryTagsSummaryKey) -> MessageHistoryTagNamespaceSummary? {
if let cached = self.cachedSummaries[key] {
return cached.summary
} else if let value = self.valueBox.get(self.table, key: self.key(key: key, sharedKey: self.sharedKey)) {
} else if let value = self.valueBox.get(self.table, key: self.keyShared(key: key)) {
let entry = readSummary(value)
self.cachedSummaries[key] = CachedEntry(summary: entry)
return entry
@ -164,10 +174,10 @@ class MessageHistoryTagsSummaryTable: Table {
if let summary = cached.summary {
buffer.reset()
writeSummary(summary, to: buffer)
self.valueBox.set(self.table, key: self.key(key: key, sharedKey: self.sharedKey), value: buffer)
self.valueBox.set(self.table, key: self.keyShared(key: key), value: buffer)
} else {
assertionFailure()
self.valueBox.remove(self.table, key: self.key(key: key, sharedKey: self.sharedKey), secure: false)
self.valueBox.remove(self.table, key: self.keyShared(key: key), secure: false)
}
} else {
assertionFailure()

View File

@ -46,7 +46,7 @@ class MessageHistoryTagsTable: Table {
for tag in tags {
self.valueBox.set(self.table, key: self.key(tag: tag, index: index, key: self.sharedKey), value: MemoryBuffer())
if self.summaryTags.contains(tag) {
self.summaryTable.addMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, namespace: index.id.namespace), id: index.id.id, isNewlyAdded: isNewlyAdded, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
self.summaryTable.addMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, threadId: nil, namespace: index.id.namespace), id: index.id.id, isNewlyAdded: isNewlyAdded, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
}
}
}
@ -56,7 +56,7 @@ class MessageHistoryTagsTable: Table {
self.valueBox.remove(self.table, key: self.key(tag: tag, index: index, key: self.sharedKey), secure: false)
if self.summaryTags.contains(tag) {
self.summaryTable.removeMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, namespace: index.id.namespace), id: index.id.id, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
self.summaryTable.removeMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, threadId: nil, namespace: index.id.namespace), id: index.id.id, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
}
}
}

View File

@ -329,7 +329,7 @@ final class MessageHistoryThreadHoleIndexTable: Table {
self.valueBox.set(self.table, key: self.key(threadId: threadId, id: MessageId(peerId: peerId, namespace: namespace, id: closedRange.upperBound), space: space), value: MemoryBuffer(memory: &lowerBound, capacity: 4, length: 4, freeWhenDone: false))
}
//addOperation(.insert(clippedRange), peerId: peerId, namespace: namespace, space: space, to: &operations)
addMessageHistoryHoleOperation(.insert(clippedRange), peerId: peerId, threadId: threadId, namespace: namespace, space: space, to: &operations)
}
func remove(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
@ -337,7 +337,7 @@ final class MessageHistoryThreadHoleIndexTable: Table {
self.removeInternal(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &operations)
/*switch space {
switch space {
case .everywhere:
if let namespaceHoleTags = self.seedConfiguration.messageHoles[peerId.namespace]?[namespace] {
for tag in namespaceHoleTags {
@ -346,7 +346,7 @@ final class MessageHistoryThreadHoleIndexTable: Table {
}
case .tag:
break
}*/
}
}
private func removeInternal(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
@ -393,9 +393,9 @@ final class MessageHistoryThreadHoleIndexTable: Table {
self.valueBox.set(self.table, key: self.key(threadId: threadId, id: MessageId(peerId: peerId, namespace: namespace, id: closedRange.upperBound), space: space), value: MemoryBuffer(memory: &lowerBound, capacity: 4, length: 4, freeWhenDone: false))
}
/*if !removeKeys.isEmpty {
addOperation(.remove(range), peerId: peerId, namespace: namespace, space: space, to: &operations)
}*/
if !removeKeys.isEmpty {
addMessageHistoryHoleOperation(.remove(range), peerId: peerId, threadId: threadId, namespace: namespace, space: space, to: &operations)
}
}
func debugList(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace) -> [ClosedRange<MessageId.Id>] {

View File

@ -5,27 +5,32 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
let id: Int64
let index: MessageIndex
var info: CodableEntry
var tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo]
var topMessage: Message?
init(
id: Int64,
index: MessageIndex,
info: CodableEntry,
tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo],
topMessage: Message?
) {
self.id = id
self.index = index
self.info = info
self.tagSummaryInfo = tagSummaryInfo
self.topMessage = topMessage
}
}
fileprivate let peerId: PeerId
fileprivate let summaryComponents: ChatListEntrySummaryComponents
fileprivate var peer: Peer?
fileprivate var items: [Item] = []
init(postbox: PostboxImpl, peerId: PeerId) {
init(postbox: PostboxImpl, peerId: PeerId, summaryComponents: ChatListEntrySummaryComponents) {
self.peerId = peerId
self.summaryComponents = summaryComponents
self.reload(postbox: postbox)
}
@ -36,10 +41,34 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
self.peer = postbox.peerTable.get(self.peerId)
for item in postbox.messageHistoryThreadIndexTable.getAll(peerId: self.peerId) {
var tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo] = [:]
for (key, component) in self.summaryComponents.components {
var tagSummaryCount: Int32?
var actionsSummaryCount: Int32?
if let tagSummary = component.tagSummary {
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: self.peerId, threadId: item.threadId, namespace: tagSummary.namespace)
if let summary = postbox.messageHistoryTagsSummaryTable.get(key) {
tagSummaryCount = summary.count
}
}
if let actionsSummary = component.actionsSummary {
let key = PendingMessageActionsSummaryKey(type: key.actionType, peerId: self.peerId, namespace: actionsSummary.namespace)
actionsSummaryCount = postbox.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(key.peerId, key.namespace, key.type))
}
tagSummaryInfo[key] = ChatListMessageTagSummaryInfo(
tagSummaryCount: tagSummaryCount,
actionsSummaryCount: actionsSummaryCount
)
}
self.items.append(Item(
id: item.threadId,
index: item.index,
info: item.info,
tagSummaryInfo: tagSummaryInfo,
topMessage: postbox.getMessage(item.index.id)
))
}
@ -48,7 +77,7 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
var updated = false
if transaction.updatedMessageThreadPeerIds.contains(self.peerId) {
if transaction.updatedMessageThreadPeerIds.contains(self.peerId) || transaction.currentUpdatedMessageTagSummaries.contains(where: { $0.key.peerId == self.peerId }) || transaction.currentUpdatedMessageActionsSummaries.contains(where: { $0.key.peerId == self.peerId }) {
self.reload(postbox: postbox)
updated = true
}
@ -70,17 +99,20 @@ public final class EngineMessageHistoryThread {
public let id: Int64
public let index: MessageIndex
public let info: CodableEntry
public let tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo]
public let topMessage: Message?
public init(
id: Int64,
index: MessageIndex,
info: CodableEntry,
tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo],
topMessage: Message?
) {
self.id = id
self.index = index
self.info = info
self.tagSummaryInfo = tagSummaryInfo
self.topMessage = topMessage
}
@ -94,6 +126,9 @@ public final class EngineMessageHistoryThread {
if lhs.info != rhs.info {
return false
}
if lhs.tagSummaryInfo != rhs.tagSummaryInfo {
return false
}
if let lhsMessage = lhs.topMessage, let rhsMessage = rhs.topMessage {
if lhsMessage.index != rhsMessage.index {
return false
@ -123,6 +158,7 @@ public final class MessageHistoryThreadIndexView: PostboxView {
id: item.id,
index: item.index,
info: item.info,
tagSummaryInfo: item.tagSummaryInfo,
topMessage: item.topMessage
))
}

View File

@ -1,9 +1,5 @@
import Foundation
private func extractKey(_ key: ValueBoxKey) -> MessageIndex {
return MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(0)), namespace: key.getInt32(8 + 8), id: key.getInt32(8 + 8 + 4 + 4)), timestamp: key.getInt32(8 + 8 + 4))
}
class MessageHistoryThreadsTable: Table {
struct ItemId: Hashable {
var peerId: PeerId
@ -31,6 +27,10 @@ class MessageHistoryThreadsTable: Table {
return key
}
private func extractKey(_ key: ValueBoxKey) -> MessageIndex {
return MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(0)), namespace: key.getInt32(8 + 8), id: key.getInt32(8 + 8 + 4 + 4)), timestamp: key.getInt32(8 + 8 + 4))
}
private func lowerBound(threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey {
let key = ValueBoxKey(length: 8 + 8 + 4)
key.setInt64(0, value: peerId.toInt64())
@ -146,3 +146,199 @@ class MessageHistoryThreadsTable: Table {
self.updatedIds.removeAll()
}
}
class MessageHistoryThreadTagsTable: Table {
static func tableSpec(_ id: Int32) -> ValueBoxTable {
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true)
}
private let summaryTable: MessageHistoryTagsSummaryTable
private let summaryTags: MessageTags
private let sharedKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4 + 4)
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, summaryTable: MessageHistoryTagsSummaryTable) {
self.summaryTable = summaryTable
self.summaryTags = seedConfiguration.messageTagsWithSummary
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(tag: MessageTags, threadId: Int64, index: MessageIndex, key: ValueBoxKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4 + 4)) -> ValueBoxKey {
key.setInt64(0, value: index.id.peerId.toInt64())
key.setInt64(8, value: threadId)
key.setUInt32(8 + 8, value: tag.rawValue)
key.setInt32(8 + 8 + 4, value: index.id.namespace)
key.setInt32(8 + 8 + 4 + 4, value: index.timestamp)
key.setInt32(8 + 8 + 4 + 4 + 4, value: index.id.id)
return key
}
private func extractKey(_ key: ValueBoxKey) -> MessageIndex {
return MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(0)), namespace: key.getInt32(8 + 8 + 4), id: key.getInt32(8 + 8 + 4 + 4 + 4)), timestamp: key.getInt32(8 + 8 + 4 + 4))
}
private func lowerBound(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey {
let key = ValueBoxKey(length: 8 + 8 + 4 + 4)
key.setInt64(0, value: peerId.toInt64())
key.setInt64(8, value: threadId)
key.setUInt32(8 + 8, value: tag.rawValue)
key.setInt32(8 + 8 + 4, value: namespace)
return key
}
private func upperBound(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey {
return self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace).successor
}
func add(tags: MessageTags, threadId: Int64, index: MessageIndex, isNewlyAdded: Bool, updatedSummaries: inout[MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation]) {
for tag in tags {
self.valueBox.set(self.table, key: self.key(tag: tag, threadId: threadId, index: index, key: self.sharedKey), value: MemoryBuffer())
if self.summaryTags.contains(tag) {
self.summaryTable.addMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, threadId: threadId, namespace: index.id.namespace), id: index.id.id, isNewlyAdded: isNewlyAdded, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
}
}
}
func remove(tags: MessageTags, threadId: Int64, index: MessageIndex, updatedSummaries: inout[MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation]) {
for tag in tags {
self.valueBox.remove(self.table, key: self.key(tag: tag, threadId: threadId, index: index, key: self.sharedKey), secure: false)
if self.summaryTags.contains(tag) {
self.summaryTable.removeMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, threadId: threadId, namespace: index.id.namespace), id: index.id.id, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
}
}
}
func entryExists(tag: MessageTags, threadId: Int64, index: MessageIndex) -> Bool {
return self.valueBox.exists(self.table, key: self.key(tag: tag, threadId: threadId, index: index, key: self.sharedKey))
}
func entryLocation(at index: MessageIndex, threadId: Int64, tag: MessageTags) -> MessageHistoryEntryLocation? {
if let _ = self.valueBox.get(self.table, key: self.key(tag: tag, threadId: threadId, index: index)) {
var greaterCount = 0
self.valueBox.range(self.table, start: self.key(tag: tag, threadId: threadId, index: index), end: self.upperBound(tag: tag, threadId: threadId, peerId: index.id.peerId, namespace: index.id.namespace), keys: { _ in
greaterCount += 1
return true
}, limit: 0)
var lowerCount = 0
self.valueBox.range(self.table, start: self.key(tag: tag, threadId: threadId, index: index), end: self.lowerBound(tag: tag, threadId: threadId, peerId: index.id.peerId, namespace: index.id.namespace), keys: { _ in
lowerCount += 1
return true
}, limit: 0)
return MessageHistoryEntryLocation(index: lowerCount, count: greaterCount + lowerCount + 1)
}
return nil
}
func earlierIndices(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, index: MessageIndex?, includeFrom: Bool, minIndex: MessageIndex? = nil, count: Int) -> [MessageIndex] {
var indices: [MessageIndex] = []
let key: ValueBoxKey
if let index = index {
if includeFrom {
key = self.key(tag: tag, threadId: threadId, index: index).successor
} else {
key = self.key(tag: tag, threadId: threadId, index: index)
}
} else {
key = self.upperBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace)
}
let endKey: ValueBoxKey
if let minIndex = minIndex {
endKey = self.key(tag: tag, threadId: threadId, index: minIndex)
} else {
endKey = self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace)
}
self.valueBox.range(self.table, start: key, end: endKey, keys: { key in
indices.append(self.extractKey(key))
return true
}, limit: count)
return indices
}
func laterIndices(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, index: MessageIndex?, includeFrom: Bool, count: Int) -> [MessageIndex] {
var indices: [MessageIndex] = []
let key: ValueBoxKey
if let index = index {
if includeFrom {
key = self.key(tag: tag, threadId: threadId, index: index).predecessor
} else {
key = self.key(tag: tag, threadId: threadId, index: index)
}
} else {
key = self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace)
}
self.valueBox.range(self.table, start: key, end: self.upperBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), keys: { key in
indices.append(self.extractKey(key))
return true
}, limit: count)
return indices
}
func getMessageCountInRange(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, lowerBound: MessageIndex, upperBound: MessageIndex) -> Int {
precondition(lowerBound.id.namespace == namespace)
precondition(upperBound.id.namespace == namespace)
var lowerBoundKey = self.key(tag: tag, threadId: threadId, index: lowerBound)
if lowerBound.timestamp > 1 {
lowerBoundKey = lowerBoundKey.predecessor
}
var upperBoundKey = self.key(tag: tag, threadId: threadId, index: upperBound)
if upperBound.timestamp < Int32.max - 1 {
upperBoundKey = upperBoundKey.successor
}
return Int(self.valueBox.count(self.table, start: lowerBoundKey, end: upperBoundKey))
}
func latestIndex(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> MessageIndex? {
var result: MessageIndex?
self.valueBox.range(self.table, start: self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), end: self.upperBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), keys: { key in
result = extractKey(key)
return true
}, limit: 1)
return result
}
func findRandomIndex(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, tag: MessageTags, ignoreIds: ([MessageId], Set<MessageId>), isMessage: (MessageIndex) -> Bool) -> MessageIndex? {
var indices: [MessageIndex] = []
self.valueBox.range(self.table, start: self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), end: self.upperBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), keys: { key in
indices.append(extractKey(key))
return true
}, limit: 0)
var checkedIndices = Set<Int>()
while checkedIndices.count < indices.count {
let i = Int(arc4random_uniform(UInt32(indices.count)))
if checkedIndices.contains(i) {
continue
}
checkedIndices.insert(i)
let index = indices[i]
if isMessage(index) && !ignoreIds.1.contains(index.id) {
return index
}
}
checkedIndices.removeAll()
let lastId = ignoreIds.0.last
while checkedIndices.count < indices.count {
let i = Int(arc4random_uniform(UInt32(indices.count)))
if checkedIndices.contains(i) {
continue
}
checkedIndices.insert(i)
let index = indices[i]
if isMessage(index) && lastId != index.id {
return index
}
}
return nil
}
func debugGetAllIndices() -> [MessageIndex] {
var indices: [MessageIndex] = []
self.valueBox.scan(self.table, values: { key, value in
indices.append(extractKey(key))
return true
})
return indices
}
}

View File

@ -285,7 +285,7 @@ public final class MessageHistoryViewExternalInput: Equatable {
}
public enum MessageHistoryViewInput: Equatable {
case single(PeerId)
case single(peerId: PeerId, threadId: Int64?)
case associated(PeerId, MessageId?)
case external(MessageHistoryViewExternalInput)
}
@ -362,7 +362,7 @@ final class MutableMessageHistoryView {
switch peerIds {
case let .associated(peerId, _):
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
case let .single(peerId):
case let .single(peerId, _):
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
case let .external(input):
switch input.content {
@ -420,7 +420,7 @@ final class MutableMessageHistoryView {
func updatePeerIds(transaction: PostboxTransaction) {
switch self.peerIds {
case let .single(peerId):
case let .single(peerId, _):
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId] {
if updatedData.associatedHistoryMessageId != nil {
self.peerIds = .associated(peerId, updatedData.associatedHistoryMessageId)
@ -445,7 +445,7 @@ final class MutableMessageHistoryView {
switch peerIds {
case let .associated(peerId, _):
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
case let .single(peerId):
case let .single(peerId, _):
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
case let .external(input):
switch input.content {
@ -458,7 +458,7 @@ final class MutableMessageHistoryView {
}
switch self.peerIds {
case let .single(peerId):
case let .single(peerId, _):
holePeerIdsSet.insert(peerId)
if let value = transaction.currentOperationsByPeerId[peerId] {
operations.append(value)
@ -497,7 +497,10 @@ final class MutableMessageHistoryView {
let externalThreadId: Int64?
let isExternal: Bool
switch self.peerIds {
case .single, .associated:
case let .single(_, threadId):
externalThreadId = threadId
isExternal = false
case .associated:
externalThreadId = nil
isExternal = false
case let .external(input):
@ -527,7 +530,7 @@ final class MutableMessageHistoryView {
}
}
if matchesSpace {
if holePeerIdsSet.contains(key.peerId) {
if holePeerIdsSet.contains(key.peerId) && key.threadId == externalThreadId {
for operation in holeOperations {
switch operation {
case let .insert(range):
@ -865,9 +868,11 @@ final class MutableMessageHistoryView {
if !transaction.currentPeerHoleOperations.isEmpty {
var holePeerIdsSet: [PeerId] = []
var threadId: Int64?
switch self.peerIds {
case let .single(peerId):
case let .single(peerId, threadIdValue):
holePeerIdsSet.append(peerId)
threadId = threadIdValue
case let .associated(peerId, associatedId):
holePeerIdsSet.append(peerId)
if let associatedId = associatedId {
@ -878,7 +883,7 @@ final class MutableMessageHistoryView {
}
let space: MessageHistoryHoleSpace = self.tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
for key in transaction.currentPeerHoleOperations.keys {
if holePeerIdsSet.contains(key.peerId) && key.space == space {
if holePeerIdsSet.contains(key.peerId) && threadId == key.threadId && key.space == space {
hasChanges = true
}
}
@ -1108,7 +1113,7 @@ public final class MessageHistoryView {
}
}
}
if let maxNamespaceIndex = maxNamespaceIndex , maxIndex == nil || maxIndex! < maxNamespaceIndex {
if let maxNamespaceIndex = maxNamespaceIndex, maxIndex == nil || maxIndex! < maxNamespaceIndex {
maxIndex = maxNamespaceIndex
}
}
@ -1177,4 +1182,83 @@ public final class MessageHistoryView {
self.entries = entries
}
public init(base: MessageHistoryView, fixed combinedReadStates: MessageHistoryViewReadState?, transient transientReadStates: MessageHistoryViewReadState?) {
self.tagMask = base.tagMask
self.namespaces = base.namespaces
self.anchorIndex = base.anchorIndex
self.earlierId = base.earlierId
self.laterId = base.laterId
self.holeEarlier = base.holeEarlier
self.holeLater = base.holeLater
self.entries = base.entries
self.fixedReadStates = combinedReadStates
self.transientReadStates = transientReadStates
self.topTaggedMessages = base.topTaggedMessages
self.additionalData = base.additionalData
self.isLoading = base.isLoading
self.isAddedToChatList = base.isAddedToChatList
if let combinedReadStates = combinedReadStates {
switch combinedReadStates {
case let .peer(states):
var hasUnread = false
for (_, readState) in states {
if readState.count > 0 {
hasUnread = true
break
}
}
var maxIndex: MessageIndex?
if hasUnread {
var peerIds = Set<PeerId>()
for entry in entries {
peerIds.insert(entry.index.id.peerId)
}
for peerId in peerIds {
if let combinedReadState = states[peerId] {
for (namespace, state) in combinedReadState.states {
var maxNamespaceIndex: MessageIndex?
var index = entries.count - 1
for entry in entries.reversed() {
if entry.index.id.peerId == peerId && entry.index.id.namespace == namespace && state.isIncomingMessageIndexRead(entry.index) {
maxNamespaceIndex = entry.index
break
}
index -= 1
}
if maxNamespaceIndex == nil && index == -1 && entries.count != 0 {
index = 0
for entry in entries {
if entry.index.id.peerId == peerId && entry.index.id.namespace == namespace {
maxNamespaceIndex = entry.index.peerLocalPredecessor()
break
}
index += 1
}
}
if let _ = maxNamespaceIndex , index + 1 < entries.count {
for i in index + 1 ..< entries.count {
if entries[i].message.flags.intersection(.IsIncomingMask).isEmpty {
maxNamespaceIndex = entries[i].message.index
} else {
break
}
}
}
if let maxNamespaceIndex = maxNamespaceIndex, maxIndex == nil || maxIndex! < maxNamespaceIndex {
maxIndex = maxNamespaceIndex
}
}
}
}
}
self.maxReadIndex = maxIndex
}
} else {
self.maxReadIndex = nil
}
}
}

View File

@ -11,7 +11,7 @@ public enum MessageHistoryInput: Equatable, Hashable {
}
}
case automatic(Automatic?)
case automatic(threadId: Int64?, info: Automatic?)
case external(MessageHistoryViewExternalInput, MessageTags?)
public func hash(into hasher: inout Hasher) {
@ -27,8 +27,8 @@ public enum MessageHistoryInput: Equatable, Hashable {
private extension MessageHistoryInput {
func fetch(postbox: PostboxImpl, peerId: PeerId, namespace: MessageId.Namespace, from fromIndex: MessageIndex, includeFrom: Bool, to toIndex: MessageIndex, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, limit: Int) -> [IntermediateMessage] {
switch self {
case let .automatic(automatic):
var items = postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: automatic?.tag, threadId: nil, from: fromIndex, includeFrom: includeFrom, to: toIndex, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, limit: limit)
case let .automatic(threadId, automatic):
var items = postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: automatic?.tag, threadId: threadId, from: fromIndex, includeFrom: includeFrom, to: toIndex, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, limit: limit)
if let automatic = automatic, automatic.appendMessagesFromTheSameGroup {
enum Direction {
case lowToHigh
@ -171,11 +171,19 @@ private extension MessageHistoryInput {
func getMessageCountInRange(postbox: PostboxImpl, peerId: PeerId, namespace: MessageId.Namespace, lowerBound: MessageIndex, upperBound: MessageIndex) -> Int {
switch self {
case let .automatic(automatic):
case let .automatic(threadId, automatic):
if let automatic = automatic {
return postbox.messageHistoryTagsTable.getMessageCountInRange(tag: automatic.tag, peerId: peerId, namespace: namespace, lowerBound: lowerBound, upperBound: upperBound)
if let threadId = threadId {
return postbox.messageHistoryThreadTagsTable.getMessageCountInRange(tag: automatic.tag, threadId: threadId, peerId: peerId, namespace: namespace, lowerBound: lowerBound, upperBound: upperBound)
} else {
return postbox.messageHistoryTagsTable.getMessageCountInRange(tag: automatic.tag, peerId: peerId, namespace: namespace, lowerBound: lowerBound, upperBound: upperBound)
}
} else {
return postbox.messageHistoryTable.getMessageCountInRange(peerId: peerId, namespace: namespace, tag: nil, lowerBound: lowerBound, upperBound: upperBound)
if let threadId = threadId {
return postbox.messageHistoryThreadsTable.getMessageCountInRange(threadId: threadId, peerId: peerId, namespace: namespace, lowerBound: lowerBound, upperBound: upperBound)
} else {
return postbox.messageHistoryTable.getMessageCountInRange(peerId: peerId, namespace: namespace, tag: nil, lowerBound: lowerBound, upperBound: upperBound)
}
}
case .external:
return 0
@ -492,8 +500,9 @@ private func sampleHoleRanges(input: MessageHistoryInput, orderedEntriesBySpace:
var tag: MessageTags?
var threadId: Int64?
switch input {
case let .automatic(automatic):
case let .automatic(threadIdValue, automatic):
tag = automatic?.tag
threadId = threadIdValue
case let .external(value, _):
switch value.content {
case let .thread(_, id, _):
@ -1016,9 +1025,9 @@ final class HistoryViewLoadedState {
let input: MessageHistoryInput
switch locations {
case let .single(peerId):
case let .single(peerId, threadId):
peerIds.append(peerId)
input = .automatic(tag.flatMap { tag in
input = .automatic(threadId: threadId, info: tag.flatMap { tag in
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup)
})
case let .associated(peerId, associatedId):
@ -1026,7 +1035,7 @@ final class HistoryViewLoadedState {
if let associatedId = associatedId {
peerIds.append(associatedId.peerId)
}
input = .automatic(tag.flatMap { tag in
input = .automatic(threadId: nil, info: tag.flatMap { tag in
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup)
})
case let .external(external):
@ -1482,9 +1491,11 @@ final class HistoryViewLoadedState {
private func fetchHoles(postbox: PostboxImpl, locations: MessageHistoryViewInput, tag: MessageTags?, namespaces: MessageIdNamespaces) -> [PeerIdAndNamespace: IndexSet] {
var peerIds: [PeerId] = []
var threadId: Int64?
switch locations {
case let .single(peerId):
case let .single(peerId, threadIdValue):
peerIds.append(peerId)
threadId = threadIdValue
case let .associated(peerId, associatedId):
peerIds.append(peerId)
if let associatedId = associatedId {
@ -1508,15 +1519,30 @@ private func fetchHoles(postbox: PostboxImpl, locations: MessageHistoryViewInput
var holesBySpace: [PeerIdAndNamespace: IndexSet] = [:]
let holeSpace = tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
for peerId in peerIds {
for namespace in postbox.messageHistoryHoleIndexTable.existingNamespaces(peerId: peerId, holeSpace: holeSpace) {
if namespaces.contains(namespace) {
let indices = postbox.messageHistoryHoleIndexTable.closest(peerId: peerId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
if !indices.isEmpty {
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
assert(canContainHoles(peerIdAndNamespace, input: .automatic(tag.flatMap { tag in
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: false)
}), seedConfiguration: postbox.seedConfiguration))
holesBySpace[peerIdAndNamespace] = indices
if let threadId = threadId {
for namespace in postbox.messageHistoryThreadHoleIndexTable.existingNamespaces(peerId: peerId, threadId: threadId, holeSpace: holeSpace) {
if namespaces.contains(namespace) {
let indices = postbox.messageHistoryThreadHoleIndexTable.closest(peerId: peerId, threadId: threadId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
if !indices.isEmpty {
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
assert(canContainHoles(peerIdAndNamespace, input: .automatic(threadId: threadId, info: tag.flatMap { tag in
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: false)
}), seedConfiguration: postbox.seedConfiguration))
holesBySpace[peerIdAndNamespace] = indices
}
}
}
} else {
for namespace in postbox.messageHistoryHoleIndexTable.existingNamespaces(peerId: peerId, holeSpace: holeSpace) {
if namespaces.contains(namespace) {
let indices = postbox.messageHistoryHoleIndexTable.closest(peerId: peerId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
if !indices.isEmpty {
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
assert(canContainHoles(peerIdAndNamespace, input: .automatic(threadId: nil, info: tag.flatMap { tag in
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: false)
}), seedConfiguration: postbox.seedConfiguration))
holesBySpace[peerIdAndNamespace] = indices
}
}
}
}
@ -1612,8 +1638,12 @@ enum HistoryViewState {
case .unread:
let anchorPeerId: PeerId
switch locations {
case let .single(peerId):
case let .single(peerId, threadId):
anchorPeerId = peerId
if threadId != nil {
self = .loaded(HistoryViewLoadedState(anchor: .upperBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
return
}
case let .associated(peerId, _):
anchorPeerId = peerId
case .external:
@ -1661,6 +1691,8 @@ enum HistoryViewState {
case let .message(messageId):
var threadId: Int64?
switch locations {
case let .single(_, threadIdValue):
threadId = threadIdValue
case let .external(input):
switch input.content {
case let .thread(_, id, _):

View File

@ -25,7 +25,7 @@ public struct MessageOfInterestHole: Hashable, Equatable, CustomStringConvertibl
}
public enum MessageOfInterestViewLocation: Hashable {
case peer(PeerId)
case peer(peerId: PeerId, threadId: Int64?)
}
final class MutableMessageOfInterestHolesView: MutablePostboxView {
@ -45,9 +45,9 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
let mainPeerId: PeerId
let peerIds: MessageHistoryViewInput
switch self.location {
case let .peer(id):
case let .peer(id, threadId):
mainPeerId = id
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
peerIds = postbox.peerIdsForLocation(.peer(peerId: id, threadId: threadId), ignoreRelatedChats: false)
}
self.peerIds = peerIds
var anchor: HistoryViewInputAnchor = .upperBound
@ -107,12 +107,14 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
var peerId: PeerId
var threadId: Int64?
switch self.location {
case let .peer(id):
peerId = id
case let .peer(id, threadIdValue):
peerId = id
threadId = threadIdValue
}
var anchor: HistoryViewInputAnchor = self.anchor
if transaction.alteredInitialPeerCombinedReadStates[peerId] != nil {
if threadId == nil, transaction.alteredInitialPeerCombinedReadStates[peerId] != nil {
let updatedAnchor: HistoryViewInputAnchor = .upperBound
if let combinedState = postbox.readStateTable.getCombinedState(peerId), let state = combinedState.states.first, state.1.count != 0 {
switch state.1 {
@ -129,8 +131,8 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
self.anchor = anchor
let peerIds: MessageHistoryViewInput
switch self.location {
case let .peer(id):
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
case let .peer(id, threadId):
peerIds = postbox.peerIdsForLocation(.peer(peerId: id, threadId: threadId), ignoreRelatedChats: false)
}
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, ignoreMessagesInTimestampRange: nil, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
return self.updateFromView()
@ -138,9 +140,11 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
var reloadView = false
if !transaction.currentPeerHoleOperations.isEmpty {
var allPeerIds: [PeerId]
var threadId: Int64?
switch peerIds {
case let .single(peerId):
case let .single(peerId, threadIdValue):
allPeerIds = [peerId]
threadId = threadIdValue
case let .associated(peerId, attachedMessageId):
allPeerIds = [peerId]
if let attachedMessageId = attachedMessageId {
@ -151,7 +155,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
break
}
for (key, _) in transaction.currentPeerHoleOperations {
if allPeerIds.contains(key.peerId) {
if allPeerIds.contains(key.peerId) && key.threadId == threadId {
reloadView = true
break
}
@ -160,8 +164,8 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
if reloadView {
let peerIds: MessageHistoryViewInput
switch self.location {
case let .peer(id):
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
case let .peer(id, threadId):
peerIds = postbox.peerIdsForLocation(.peer(peerId: id, threadId: threadId), ignoreRelatedChats: false)
}
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, ignoreMessagesInTimestampRange: nil, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
}

View File

@ -67,14 +67,14 @@ public final class Transaction {
}
}
public func addHole(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
public func addHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
assert(!self.disposed)
self.postbox?.addHole(peerId: peerId, namespace: namespace, space: space, range: range)
self.postbox?.addHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range)
}
public func removeHole(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
public func removeHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
assert(!self.disposed)
self.postbox?.removeHole(peerId: peerId, namespace: namespace, space: space, range: range)
self.postbox?.removeHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range)
}
public func getHole(containing id: MessageId) -> [MessageHistoryHoleSpace: ClosedRange<MessageId.Id>] {
@ -87,16 +87,6 @@ public final class Transaction {
return self.postbox?.messageHistoryHoleIndexTable.closest(peerId: peerId, namespace: namespace, space: .everywhere, range: 1 ... (Int32.max - 1)) ?? IndexSet()
}
public func addThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
assert(!self.disposed)
self.postbox?.addThreadIndexHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range)
}
public func removeThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
assert(!self.disposed)
self.postbox?.removeThreadIndexHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range)
}
public func getThreadIndexHoles(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace) -> IndexSet {
assert(!self.disposed)
return self.postbox!.messageHistoryThreadHoleIndexTable.closest(peerId: peerId, threadId: threadId, namespace: namespace, space: .everywhere, range: 1 ... (Int32.max - 1))
@ -137,12 +127,12 @@ public final class Transaction {
self.postbox?.replaceChatListHole(groupId: groupId, index: index, hole: hole)
}
public func deleteMessages(_ messageIds: [MessageId], forEachMedia: (Media) -> Void) {
public func deleteMessages(_ messageIds: [MessageId], forEachMedia: ((Media) -> Void)?) {
assert(!self.disposed)
self.postbox?.deleteMessages(messageIds, forEachMedia: forEachMedia)
}
public func deleteMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, forEachMedia: (Media) -> Void) {
public func deleteMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, forEachMedia: ((Media) -> Void)?) {
assert(!self.disposed)
self.postbox?.deleteMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, forEachMedia: forEachMedia)
}
@ -151,12 +141,12 @@ public final class Transaction {
self.postbox?.withAllMessages(peerId: peerId, namespace: namespace, f)
}
public func clearHistory(_ peerId: PeerId, threadId: Int64?, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: (Media) -> Void) {
public func clearHistory(_ peerId: PeerId, threadId: Int64?, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: ((Media) -> Void)?) {
assert(!self.disposed)
self.postbox?.clearHistory(peerId, threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, forEachMedia: forEachMedia)
}
public func removeAllMessagesWithAuthor(_ peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, forEachMedia: (Media) -> Void) {
public func removeAllMessagesWithAuthor(_ peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, forEachMedia: ((Media) -> Void)?) {
assert(!self.disposed)
self.postbox?.removeAllMessagesWithAuthor(peerId, authorId: authorId, namespace: namespace, forEachMedia: forEachMedia)
}
@ -166,7 +156,7 @@ public final class Transaction {
self.postbox?.removeAllMessagesWithGlobalTag(tag: tag)
}
public func removeAllMessagesWithForwardAuthor(_ peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace, forEachMedia: (Media) -> Void) {
public func removeAllMessagesWithForwardAuthor(_ peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace, forEachMedia: ((Media) -> Void)?) {
assert(!self.disposed)
self.postbox?.removeAllMessagesWithForwardAuthor(peerId, forwardAuthorId: forwardAuthorId, namespace: namespace, forEachMedia: forEachMedia)
}
@ -188,7 +178,7 @@ public final class Transaction {
}
}
public func deleteMessagesWithGlobalIds(_ ids: [Int32], forEachMedia: (Media) -> Void) {
public func deleteMessagesWithGlobalIds(_ ids: [Int32], forEachMedia: ((Media) -> Void)?) {
assert(!self.disposed)
if let postbox = self.postbox {
let messageIds = postbox.messageIdsForGlobalIds(ids)
@ -229,7 +219,7 @@ public final class Transaction {
public func applyInteractiveReadMaxIndex(_ messageIndex: MessageIndex) -> [MessageId] {
assert(!self.disposed)
if let postbox = self.postbox {
return postbox.applyInteractiveReadMaxIndex(messageIndex)
return postbox.applyInteractiveReadMaxIndex(messageIndex: messageIndex)
} else {
return []
}
@ -328,7 +318,7 @@ public final class Transaction {
return self.postbox?.readStateTable.getCombinedState(id)
}
public func getPeerNotificationSettings(_ id: PeerId) -> PeerNotificationSettings? {
public func getPeerNotificationSettings(id: PeerId) -> PeerNotificationSettings? {
assert(!self.disposed)
return self.postbox?.peerNotificationSettingsTable.getEffective(id)
}
@ -894,7 +884,7 @@ public final class Transaction {
let notificationsPeerId = peer.notificationSettingsPeerId ?? peerId
let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId)
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId))
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: predicate.messageTagSummary)
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: predicate.messageTagSummary)
if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) {
includedPeerIds[peer.id] = true
@ -1002,14 +992,14 @@ public final class Transaction {
return self.postbox?.getPendingMessageAction(type: type, id: id)
}
public func getMessageTagSummary(peerId: PeerId, tagMask: MessageTags, namespace: MessageId.Namespace) -> MessageHistoryTagNamespaceSummary? {
public func getMessageTagSummary(peerId: PeerId, threadId: Int64?, tagMask: MessageTags, namespace: MessageId.Namespace) -> MessageHistoryTagNamespaceSummary? {
assert(!self.disposed)
return self.postbox?.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, namespace: namespace))
return self.postbox?.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, threadId: threadId, namespace: namespace))
}
public func replaceMessageTagSummary(peerId: PeerId, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
public func replaceMessageTagSummary(peerId: PeerId, threadId: Int64?, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
assert(!self.disposed)
self.postbox?.replaceMessageTagSummary(peerId: peerId, tagMask: tagMask, namespace: namespace, count: count, maxId: maxId)
self.postbox?.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: tagMask, namespace: namespace, count: count, maxId: maxId)
}
public func getPendingMessageActionsSummary(peerId: PeerId, type: PendingMessageActionType, namespace: MessageId.Namespace) -> Int32? {
@ -1017,12 +1007,16 @@ public final class Transaction {
return self.postbox?.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(peerId, namespace, type))
}
public func getMessageIndicesWithTag(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags) -> [MessageIndex] {
public func getMessageIndicesWithTag(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, tag: MessageTags) -> [MessageIndex] {
assert(!self.disposed)
guard let postbox = self.postbox else {
return []
}
return postbox.messageHistoryTagsTable.earlierIndices(tag: tag, peerId: peerId, namespace: namespace, index: nil, includeFrom: false, count: 1000)
if let threadId = threadId {
return postbox.messageHistoryThreadTagsTable.earlierIndices(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace, index: nil, includeFrom: false, count: 1000)
} else {
return postbox.messageHistoryTagsTable.earlierIndices(tag: tag, peerId: peerId, namespace: namespace, index: nil, includeFrom: false, count: 1000)
}
}
public func getMessagesWithThreadId(peerId: PeerId, namespace: MessageId.Namespace, threadId: Int64, from: MessageIndex, includeFrom: Bool, to: MessageIndex, limit: Int) -> [Message] {
@ -1447,6 +1441,7 @@ final class PostboxImpl {
let messageHistoryFailedTable: MessageHistoryFailedTable
let messageHistoryTagsTable: MessageHistoryTagsTable
let messageHistoryThreadsTable: MessageHistoryThreadsTable
let messageHistoryThreadTagsTable: MessageHistoryThreadTagsTable
let messageHistoryThreadHoleIndexTable: MessageHistoryThreadHoleIndexTable
let messageHistoryThreadReverseIndexTable: MessageHistoryThreadReverseIndexTable
let messageHistoryThreadIndexTable: MessageHistoryThreadIndexTable
@ -1524,6 +1519,7 @@ final class PostboxImpl {
self.pendingMessageActionsTable = PendingMessageActionsTable(valueBox: self.valueBox, table: PendingMessageActionsTable.tableSpec(46), useCaches: useCaches, metadataTable: self.pendingMessageActionsMetadataTable)
self.messageHistoryTagsTable = MessageHistoryTagsTable(valueBox: self.valueBox, table: MessageHistoryTagsTable.tableSpec(12), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
self.messageHistoryThreadsTable = MessageHistoryThreadsTable(valueBox: self.valueBox, table: MessageHistoryThreadsTable.tableSpec(62), useCaches: useCaches)
self.messageHistoryThreadTagsTable = MessageHistoryThreadTagsTable(valueBox: self.valueBox, table: MessageHistoryThreadTagsTable.tableSpec(71), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.messageHistoryThreadReverseIndexTable = MessageHistoryThreadReverseIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadReverseIndexTable.tableSpec(69), useCaches: useCaches)
self.messageHistoryThreadIndexTable = MessageHistoryThreadIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadIndexTable.tableSpec(70), reverseIndexTable: self.messageHistoryThreadReverseIndexTable, useCaches: useCaches)
@ -1538,7 +1534,7 @@ final class PostboxImpl {
self.timestampBasedMessageAttributesTable = TimestampBasedMessageAttributesTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(34), useCaches: useCaches, indexTable: self.timestampBasedMessageAttributesIndexTable)
self.textIndexTable = MessageHistoryTextIndexTable(valueBox: self.valueBox, table: MessageHistoryTextIndexTable.tableSpec(41))
self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55), useCaches: useCaches)
self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), useCaches: useCaches, seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, threadsTable: self.messageHistoryThreadsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, timeBasedAttributesTable: self.timestampBasedMessageAttributesTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable)
self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), useCaches: useCaches, seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, threadsTable: self.messageHistoryThreadsTable, threadTagsTable: self.messageHistoryThreadTagsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, timeBasedAttributesTable: self.timestampBasedMessageAttributesTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable)
self.peerChatStateTable = PeerChatStateTable(valueBox: self.valueBox, table: PeerChatStateTable.tableSpec(13), useCaches: useCaches)
self.peerNameTokenIndexTable = ReverseIndexReferenceTable<PeerIdReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<PeerIdReverseIndexReference>.tableSpec(26), useCaches: useCaches)
self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), useCaches: useCaches, peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable)
@ -1582,6 +1578,7 @@ final class PostboxImpl {
tables.append(self.messageHistoryFailedTable)
tables.append(self.messageHistoryTagsTable)
tables.append(self.messageHistoryThreadsTable)
tables.append(self.messageHistoryThreadTagsTable)
tables.append(self.messageHistoryThreadHoleIndexTable)
tables.append(self.messageHistoryThreadReverseIndexTable)
tables.append(self.messageHistoryThreadIndexTable)
@ -1818,20 +1815,20 @@ final class PostboxImpl {
}
}
fileprivate func addHole(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
self.messageHistoryHoleIndexTable.add(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
fileprivate func addHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
if let threadId = threadId {
self.messageHistoryThreadHoleIndexTable.add(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
} else {
self.messageHistoryHoleIndexTable.add(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
}
}
fileprivate func removeHole(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
self.messageHistoryHoleIndexTable.remove(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
}
fileprivate func addThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
self.messageHistoryThreadHoleIndexTable.add(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
}
fileprivate func removeThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
self.messageHistoryThreadHoleIndexTable.remove(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
fileprivate func removeHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
if let threadId = threadId {
self.messageHistoryThreadHoleIndexTable.remove(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
} else {
self.messageHistoryHoleIndexTable.remove(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
}
}
fileprivate func recalculateChatListGroupStats(groupId: PeerGroupId) {
@ -1844,11 +1841,11 @@ final class PostboxImpl {
self.chatListTable.replaceHole(groupId: groupId, index: index, hole: hole, operations: &self.currentChatListOperations)
}
fileprivate func deleteMessages(_ messageIds: [MessageId], forEachMedia: (Media) -> Void) {
fileprivate func deleteMessages(_ messageIds: [MessageId], forEachMedia: ((Media) -> Void)?) {
self.messageHistoryTable.removeMessages(messageIds, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: &currentUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
fileprivate func deleteMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, forEachMedia: (Media) -> Void) {
fileprivate func deleteMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, forEachMedia: ((Media) -> Void)?) {
self.messageHistoryTable.removeMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: &currentUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
@ -1864,7 +1861,7 @@ final class PostboxImpl {
}
}
fileprivate func clearHistory(_ peerId: PeerId, threadId: Int64?, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: (Media) -> Void) {
fileprivate func clearHistory(_ peerId: PeerId, threadId: Int64?, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: ((Media) -> Void)?) {
if let minTimestamp = minTimestamp, let maxTimestamp = maxTimestamp {
self.messageHistoryTable.clearHistoryInRange(peerId: peerId, threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: &currentUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
} else {
@ -1875,7 +1872,7 @@ final class PostboxImpl {
}
}
fileprivate func removeAllMessagesWithAuthor(_ peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, forEachMedia: (Media) -> Void) {
fileprivate func removeAllMessagesWithAuthor(_ peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, forEachMedia: ((Media) -> Void)?) {
self.messageHistoryTable.removeAllMessagesWithAuthor(peerId: peerId, authorId: authorId, namespace: namespace, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: &currentUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
@ -1883,7 +1880,7 @@ final class PostboxImpl {
self.messageHistoryTable.removeAllMessagesWithGlobalTag(tag: tag, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: &currentUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: { _ in })
}
fileprivate func removeAllMessagesWithForwardAuthor(_ peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace, forEachMedia: (Media) -> Void) {
fileprivate func removeAllMessagesWithForwardAuthor(_ peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace, forEachMedia: ((Media) -> Void)?) {
self.messageHistoryTable.removeAllMessagesWithForwardAuthor(peerId: peerId, forwardAuthorId: forwardAuthorId, namespace: namespace, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: &currentUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
}
@ -1907,17 +1904,17 @@ final class PostboxImpl {
self.messageHistoryTable.applyOutgoingReadMaxId(messageId, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations)
}
fileprivate func applyInteractiveReadMaxIndex(_ messageIndex: MessageIndex) -> [MessageId] {
let peerIds = self.peerIdsForLocation(.peer(messageIndex.id.peerId), ignoreRelatedChats: false)
fileprivate func applyInteractiveReadMaxIndex(messageIndex: MessageIndex) -> [MessageId] {
let peerIds = self.peerIdsForLocation(.peer(peerId: messageIndex.id.peerId, threadId: nil), ignoreRelatedChats: false)
switch peerIds {
case let .associated(_, messageId):
if let messageId = messageId, let readState = self.readStateTable.getCombinedState(messageId.peerId), readState.count != 0 {
if let topMessage = self.messageHistoryTable.topMessage(peerId: messageId.peerId) {
let _ = self.messageHistoryTable.applyInteractiveMaxReadIndex(postbox: self, messageIndex: topMessage.index, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations)
}
case let .associated(_, messageId):
if let messageId = messageId, let readState = self.readStateTable.getCombinedState(messageId.peerId), readState.count != 0 {
if let topMessage = self.messageHistoryTable.topMessage(peerId: messageId.peerId) {
let _ = self.messageHistoryTable.applyInteractiveMaxReadIndex(postbox: self, messageIndex: topMessage.index, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations)
}
default:
break
}
default:
break
}
let initialCombinedStates = self.readStateTable.getCombinedState(messageIndex.id.peerId)
var resultIds = self.messageHistoryTable.applyInteractiveMaxReadIndex(postbox: self, messageIndex: messageIndex, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations)
@ -2487,8 +2484,8 @@ final class PostboxImpl {
return self.pendingMessageActionsTable.getAction(id: id, type: type)
}
fileprivate func replaceMessageTagSummary(peerId: PeerId, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
let key = MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, namespace: namespace)
fileprivate func replaceMessageTagSummary(peerId: PeerId, threadId: Int64?, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
let key = MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, threadId: threadId, namespace: namespace)
self.messageHistoryTagsSummaryTable.replace(key: key, count: count, maxId: maxId, updatedSummaries: &self.currentUpdatedMessageTagSummaries)
}
@ -2611,8 +2608,8 @@ final class PostboxImpl {
func resolvedChatLocationInput(chatLocation: ChatLocationInput) -> Signal<(ResolvedChatLocationInput, Bool), NoError> {
switch chatLocation {
case let .peer(peerId):
return .single((.peer(peerId), false))
case let .peer(peerId, threadId):
return .single((.peer(peerId: peerId, threadId: threadId), false))
case .thread(_, _, let data), .feed(_, let data):
return Signal { subscriber in
var isHoleFill = false
@ -2629,9 +2626,9 @@ final class PostboxImpl {
func peerIdsForLocation(_ chatLocation: ResolvedChatLocationInput, ignoreRelatedChats: Bool) -> MessageHistoryViewInput {
var peerIds: MessageHistoryViewInput
switch chatLocation {
case let .peer(peerId):
peerIds = .single(peerId)
if !ignoreRelatedChats, let associatedMessageId = self.cachedPeerDataTable.get(peerId)?.associatedHistoryMessageId, associatedMessageId.peerId != peerId {
case let .peer(peerId, threadId):
peerIds = .single(peerId: peerId, threadId: threadId)
if !ignoreRelatedChats, threadId == nil, let associatedMessageId = self.cachedPeerDataTable.get(peerId)?.associatedHistoryMessageId, associatedMessageId.peerId != peerId {
peerIds = .associated(peerId, associatedMessageId)
}
case let .external(input):
@ -2640,7 +2637,7 @@ final class PostboxImpl {
return peerIds
}
public func aroundMessageOfInterestHistoryViewForChatLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, count: Int, clipHoles: Bool = true, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundMessageOfInterestHistoryViewForChatLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, count: Int, clipHoles: Bool = true, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, customUnreadMessageId: MessageId?, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
return self.resolvedChatLocationInput(chatLocation: chatLocation)
|> mapToSignal { chatLocationData in
let (chatLocation, isHoleFill) = chatLocationData
@ -2650,8 +2647,10 @@ final class PostboxImpl {
var anchor: HistoryViewInputAnchor = .upperBound
switch peerIds {
case let .single(peerId):
if self.chatListTable.getPeerChatListIndex(peerId: peerId) != nil {
case let .single(peerId, threadId):
if let customUnreadMessageId = customUnreadMessageId {
anchor = .message(customUnreadMessageId)
} else if threadId == nil, self.chatListTable.getPeerChatListIndex(peerId: peerId) != nil {
if let combinedState = self.readStateTable.getCombinedState(peerId), let state = combinedState.states.first, state.1.count != 0 {
switch state.1 {
case let .idBased(maxIncomingReadId, _, _, _, _):
@ -2770,8 +2769,10 @@ final class PostboxImpl {
var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] = [:]
var mainPeerIdForTopTaggedMessages: PeerId?
switch peerIds {
case let .single(id):
mainPeerIdForTopTaggedMessages = id
case let .single(id, threadId):
if threadId == nil {
mainPeerIdForTopTaggedMessages = id
}
case let .associated(id, _):
mainPeerIdForTopTaggedMessages = id
case .external:
@ -2844,8 +2845,8 @@ final class PostboxImpl {
var readStates: MessageHistoryViewReadState?
var transientReadStates: MessageHistoryViewReadState?
switch peerIds {
case let .single(peerId):
if let readState = self.readStateTable.getCombinedState(peerId) {
case let .single(peerId, threadId):
if threadId == nil, let readState = self.readStateTable.getCombinedState(peerId) {
transientReadStates = .peer([peerId: readState])
}
case let .associated(peerId, _):
@ -2876,8 +2877,8 @@ final class PostboxImpl {
let initialData: InitialMessageHistoryData
switch peerIds {
case let .single(peerId):
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: nil)
case let .single(peerId, threadId):
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: threadId)
case let .associated(peerId, _):
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: nil)
case let .external(input):
@ -3671,7 +3672,7 @@ final class PostboxImpl {
fileprivate func addHolesEverywhere(peerNamespaces: [PeerId.Namespace], holeNamespace: MessageId.Namespace) {
for peerId in self.chatListIndexTable.getAllPeerIds() {
if peerNamespaces.contains(peerId.namespace) && self.messageHistoryMetadataTable.isInitialized(peerId) {
self.addHole(peerId: peerId, namespace: holeNamespace, space: .everywhere, range: 1 ... Int32.max - 1)
self.addHole(peerId: peerId, threadId: nil, namespace: holeNamespace, space: .everywhere, range: 1 ... Int32.max - 1)
}
}
}
@ -3818,6 +3819,7 @@ public class Postbox {
appendMessagesFromTheSameGroup: Bool,
namespaces: MessageIdNamespaces,
orderStatistics: MessageHistoryViewOrderStatistics,
customUnreadMessageId: MessageId?,
additionalData: [AdditionalMessageHistoryViewData]
) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
return Signal { subscriber in
@ -3834,6 +3836,7 @@ public class Postbox {
appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup,
namespaces: namespaces,
orderStatistics: orderStatistics,
customUnreadMessageId: customUnreadMessageId,
additionalData: additionalData
).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion))
}

View File

@ -45,11 +45,11 @@ func resolveChatListMessageTagSummaryResultCalculation(addSummary: MessageHistor
return count > 0
}
func resolveChatListMessageTagSummaryResultCalculation(postbox: PostboxImpl, peerId: PeerId, calculation: ChatListMessageTagSummaryResultCalculation?) -> Bool? {
func resolveChatListMessageTagSummaryResultCalculation(postbox: PostboxImpl, peerId: PeerId, threadId: Int64?, calculation: ChatListMessageTagSummaryResultCalculation?) -> Bool? {
guard let calculation = calculation else {
return nil
}
let addSummary = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: calculation.addCount.tag, peerId: peerId, namespace: calculation.addCount.namespace))
let addSummary = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: calculation.addCount.tag, peerId: peerId, threadId: threadId, namespace: calculation.addCount.namespace))
let subtractSummary = postbox.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(peerId, calculation.subtractCount.namespace, calculation.subtractCount.type))
let count = (addSummary?.count ?? 0) - subtractSummary
return count > 0

View File

@ -269,9 +269,9 @@ final class ViewTracker {
var updateType: ViewUpdateType = .Generic
switch mutableView.peerIds {
case let .single(peerId):
case let .single(peerId, threadId):
for key in transaction.currentPeerHoleOperations.keys {
if key.peerId == peerId {
if key.peerId == peerId && key.threadId == threadId {
updateType = .FillHole
break
}

View File

@ -12,7 +12,7 @@ public enum PostboxViewKey: Hashable {
case pendingMessageActions(type: PendingMessageActionType)
case invalidatedMessageHistoryTagSummaries(tagMask: MessageTags, namespace: MessageId.Namespace)
case pendingMessageActionsSummary(type: PendingMessageActionType, peerId: PeerId, namespace: MessageId.Namespace)
case historyTagSummaryView(tag: MessageTags, peerId: PeerId, namespace: MessageId.Namespace)
case historyTagSummaryView(tag: MessageTags, peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace)
case cachedPeerData(peerId: PeerId)
case unreadCounts(items: [UnreadMessageCountsItem])
case combinedReadState(peerId: PeerId)
@ -38,7 +38,7 @@ public enum PostboxViewKey: Hashable {
case isContact(id: PeerId)
case chatListIndex(id: PeerId)
case peerTimeoutAttributes
case messageHistoryThreadIndex(id: PeerId)
case messageHistoryThreadIndex(id: PeerId, summaryComponents: ChatListEntrySummaryComponents)
case messageHistoryThreadInfo(peerId: PeerId, threadId: Int64)
public func hash(into hasher: inout Hasher) {
@ -68,9 +68,10 @@ public enum PostboxViewKey: Hashable {
hasher.combine(type)
hasher.combine(peerId)
hasher.combine(namespace)
case let .historyTagSummaryView(tag, peerId, namespace):
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
hasher.combine(tag)
hasher.combine(peerId)
hasher.combine(threadId)
hasher.combine(namespace)
case let .cachedPeerData(peerId):
hasher.combine(peerId)
@ -126,7 +127,7 @@ public enum PostboxViewKey: Hashable {
hasher.combine(id)
case .peerTimeoutAttributes:
hasher.combine(17)
case let .messageHistoryThreadIndex(id):
case let .messageHistoryThreadIndex(id, _):
hasher.combine(id)
case let .messageHistoryThreadInfo(peerId, threadId):
hasher.combine(peerId)
@ -202,8 +203,8 @@ public enum PostboxViewKey: Hashable {
} else {
return false
}
case let .historyTagSummaryView(tag, peerId, namespace):
if case .historyTagSummaryView(tag, peerId, namespace) = rhs {
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
if case .historyTagSummaryView(tag, peerId, threadId, namespace) = rhs {
return true
} else {
return false
@ -358,8 +359,8 @@ public enum PostboxViewKey: Hashable {
} else {
return false
}
case let .messageHistoryThreadIndex(id):
if case .messageHistoryThreadIndex(id) = rhs {
case let .messageHistoryThreadIndex(id, summaryComponents):
if case .messageHistoryThreadIndex(id, summaryComponents) = rhs {
return true
} else {
return false
@ -398,8 +399,8 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
return MutableInvalidatedMessageHistoryTagSummariesView(postbox: postbox, tagMask: tagMask, namespace: namespace)
case let .pendingMessageActionsSummary(type, peerId, namespace):
return MutablePendingMessageActionsSummaryView(postbox: postbox, type: type, peerId: peerId, namespace: namespace)
case let .historyTagSummaryView(tag, peerId, namespace):
return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, namespace: namespace)
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, threadId: threadId, namespace: namespace)
case let .cachedPeerData(peerId):
return MutableCachedPeerDataView(postbox: postbox, peerId: peerId)
case let .unreadCounts(items):
@ -450,8 +451,8 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
return MutableChatListIndexView(postbox: postbox, id: id)
case .peerTimeoutAttributes:
return MutablePeerTimeoutAttributesView(postbox: postbox)
case let .messageHistoryThreadIndex(id):
return MutableMessageHistoryThreadIndexView(postbox: postbox, peerId: id)
case let .messageHistoryThreadIndex(id, summaryComponents):
return MutableMessageHistoryThreadIndexView(postbox: postbox, peerId: id, summaryComponents: summaryComponents)
case let .messageHistoryThreadInfo(peerId, threadId):
return MutableMessageHistoryThreadInfoView(postbox: postbox, peerId: peerId, threadId: threadId)
}

View File

@ -781,16 +781,16 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
let presentationData = context.sharedContext.currentPresentationData.modify {$0}
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: nil, sound: sound) |> deliverOnMainQueue
}
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, muteInterval: muteInterval) |> deliverOnMainQueue
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: nil, muteInterval: muteInterval) |> deliverOnMainQueue
}
let updatePeerDisplayPreviews:(PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
peerId, displayPreviews in
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, displayPreviews: displayPreviews) |> deliverOnMainQueue
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: nil, displayPreviews: displayPreviews) |> deliverOnMainQueue
}
self.backgroundColor = presentationData.theme.list.blocksBackgroundColor
@ -814,7 +814,7 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
let mode = stateValue.with { $0.mode }
dismissInputImpl?()
presentControllerImpl?(notificationPeerExceptionController(context: context, peer: peer._asPeer(), mode: mode, updatePeerSound: { peerId, sound in
presentControllerImpl?(notificationPeerExceptionController(context: context, peer: peer._asPeer(), threadId: nil, mode: mode, updatePeerSound: { peerId, sound in
_ = updatePeerSound(peer.id, sound).start(next: { _ in
updateNotificationsDisposable.set(nil)
_ = combineLatest(updatePeerSound(peer.id, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in

View File

@ -365,7 +365,7 @@ private struct NotificationExceptionPeerState : Equatable {
}
}
public func notificationPeerExceptionController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: Peer, mode: NotificationExceptionMode, edit: Bool = false, updatePeerSound: @escaping(PeerId, PeerMessageSound) -> Void, updatePeerNotificationInterval: @escaping(PeerId, Int32?) -> Void, updatePeerDisplayPreviews: @escaping(PeerId, PeerNotificationDisplayPreviews) -> Void, removePeerFromExceptions: @escaping () -> Void, modifiedPeer: @escaping () -> Void) -> ViewController {
public func notificationPeerExceptionController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: Peer, threadId: Int64?, mode: NotificationExceptionMode, edit: Bool = false, updatePeerSound: @escaping(PeerId, PeerMessageSound) -> Void, updatePeerNotificationInterval: @escaping(PeerId, Int32?) -> Void, updatePeerDisplayPreviews: @escaping(PeerId, PeerNotificationDisplayPreviews) -> Void, removePeerFromExceptions: @escaping () -> Void, modifiedPeer: @escaping () -> Void) -> ViewController {
let initialState = NotificationExceptionPeerState(canRemove: false)
let statePromise = Promise(initialState)
let stateValue = Atomic(value: initialState)
@ -420,10 +420,13 @@ public func notificationPeerExceptionController(context: AccountContext, updated
statePromise.set(context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peer.id),
EngineDataOptional(threadId.flatMap { TelegramEngine.EngineData.Item.Peer.ThreadNotificationSettings(id: peer.id, threadId: $0) }),
TelegramEngine.EngineData.Item.NotificationSettings.Global()
)
|> map { notificationSettings, globalNotificationSettings -> NotificationExceptionPeerState in
var state = NotificationExceptionPeerState(canRemove: mode.peerIds.contains(peer.id), notifications: notificationSettings._asNotificationSettings())
|> map { peerNotificationSettings, threadNotificationSettings, globalNotificationSettings -> NotificationExceptionPeerState in
let effectiveSettings = threadNotificationSettings ?? peerNotificationSettings
var state = NotificationExceptionPeerState(canRemove: mode.peerIds.contains(peer.id), notifications: effectiveSettings._asNotificationSettings())
let globalSettings = globalNotificationSettings
switch mode {
case .channels:

View File

@ -438,16 +438,16 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
}
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: nil, sound: sound) |> deliverOnMainQueue
}
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, muteInterval: muteInterval) |> deliverOnMainQueue
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: nil, muteInterval: muteInterval) |> deliverOnMainQueue
}
let updatePeerDisplayPreviews:(PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
peerId, displayPreviews in
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, displayPreviews: displayPreviews) |> deliverOnMainQueue
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: nil, displayPreviews: displayPreviews) |> deliverOnMainQueue
}
var peerIds: Set<PeerId> = Set(mode.peerIds)
@ -502,7 +502,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
}
let mode = stateValue.with { $0.mode }
pushControllerImpl?(notificationPeerExceptionController(context: context, peer: peer._asPeer(), mode: mode, updatePeerSound: { peerId, sound in
pushControllerImpl?(notificationPeerExceptionController(context: context, peer: peer._asPeer(), threadId: nil, mode: mode, updatePeerSound: { peerId, sound in
_ = updatePeerSound(peer.id, sound).start(next: { _ in
updateNotificationsDisposable.set(nil)
_ = combineLatest(updatePeerSound(peer.id, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in

View File

@ -219,7 +219,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
var items: [ChatListItem] = []
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
}, activateChatPreview: { _, _, gesture, _ in
gesture?.cancel()
}, present: { _ in })

View File

@ -839,7 +839,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
var items: [ChatListItem] = []
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
}, activateChatPreview: { _, _, gesture, _ in
gesture?.cancel()
}, present: { _ in

View File

@ -363,7 +363,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
var items: [ChatListItem] = []
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
}, activateChatPreview: { _, _, gesture, _ in
gesture?.cancel()
}, present: { _ in

View File

@ -447,7 +447,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
contextActionImpl?(messageId, node, gesture)
})
let messageView = context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .upperBound, anchorIndex: .upperBound, count: 100, fixedCombinedReadStates: nil)
let messageView = context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 100, fixedCombinedReadStates: nil)
|> map { messageHistoryView, _, _ -> MessageHistoryView? in
return messageHistoryView
}

View File

@ -222,7 +222,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-207944868] = { return Api.FileHash.parse_fileHash($0) }
dict[-11252123] = { return Api.Folder.parse_folder($0) }
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
dict[413771876] = { return Api.ForumTopic.parse_forumTopic($0) }
dict[1495324380] = { return Api.ForumTopic.parse_forumTopic($0) }
dict[-1107729093] = { return Api.Game.parse_game($0) }
dict[-1297942941] = { return Api.GeoPoint.parse_geoPoint($0) }
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) }
@ -315,6 +315,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) }
dict[-1311015810] = { return Api.InputNotifyPeer.parse_inputNotifyBroadcasts($0) }
dict[1251338318] = { return Api.InputNotifyPeer.parse_inputNotifyChats($0) }
dict[1548122514] = { return Api.InputNotifyPeer.parse_inputNotifyForumTopic($0) }
dict[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) }
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) }

View File

@ -4985,16 +4985,18 @@ public extension Api.functions.messages {
}
}
public extension Api.functions.messages {
static func getSearchCounters(peer: Api.InputPeer, filters: [Api.MessagesFilter]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.messages.SearchCounter]>) {
static func getSearchCounters(flags: Int32, peer: Api.InputPeer, topMsgId: Int32?, filters: [Api.MessagesFilter]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.messages.SearchCounter]>) {
let buffer = Buffer()
buffer.appendInt32(1932455680)
buffer.appendInt32(11435201)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(topMsgId!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(filters.count))
for item in filters {
item.serialize(buffer, true)
}
return (FunctionDescription(name: "messages.getSearchCounters", parameters: [("peer", String(describing: peer)), ("filters", String(describing: filters))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.messages.SearchCounter]? in
return (FunctionDescription(name: "messages.getSearchCounters", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("topMsgId", String(describing: topMsgId)), ("filters", String(describing: filters))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.messages.SearchCounter]? in
let reader = BufferReader(buffer)
var result: [Api.messages.SearchCounter]?
if let _ = reader.readInt32() {
@ -5470,11 +5472,13 @@ public extension Api.functions.messages {
}
}
public extension Api.functions.messages {
static func readReactions(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AffectedHistory>) {
static func readReactions(flags: Int32, peer: Api.InputPeer, topMsgId: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AffectedHistory>) {
let buffer = Buffer()
buffer.appendInt32(-2099097129)
buffer.appendInt32(1420459918)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
return (FunctionDescription(name: "messages.readReactions", parameters: [("peer", String(describing: peer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedHistory? in
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(topMsgId!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "messages.readReactions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("topMsgId", String(describing: topMsgId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedHistory? in
let reader = BufferReader(buffer)
var result: Api.messages.AffectedHistory?
if let signature = reader.readInt32() {

View File

@ -1094,13 +1094,13 @@ public extension Api {
}
public extension Api {
enum ForumTopic: TypeConstructorDescription {
case forumTopic(flags: Int32, id: Int32, date: Int32, title: String, iconColor: Int32, iconEmojiId: Int64?, topMessage: Int32, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, unreadMentionsCount: Int32, unreadReactionsCount: Int32, fromId: Api.Peer)
case forumTopic(flags: Int32, id: Int32, date: Int32, title: String, iconColor: Int32, iconEmojiId: Int64?, topMessage: Int32, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, unreadMentionsCount: Int32, unreadReactionsCount: Int32, fromId: Api.Peer, notifySettings: Api.PeerNotifySettings)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .forumTopic(let flags, let id, let date, let title, let iconColor, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let unreadReactionsCount, let fromId):
case .forumTopic(let flags, let id, let date, let title, let iconColor, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let unreadReactionsCount, let fromId, let notifySettings):
if boxed {
buffer.appendInt32(413771876)
buffer.appendInt32(1495324380)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false)
@ -1115,14 +1115,15 @@ public extension Api {
serializeInt32(unreadMentionsCount, buffer: buffer, boxed: false)
serializeInt32(unreadReactionsCount, buffer: buffer, boxed: false)
fromId.serialize(buffer, true)
notifySettings.serialize(buffer, true)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .forumTopic(let flags, let id, let date, let title, let iconColor, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let unreadReactionsCount, let fromId):
return ("forumTopic", [("flags", String(describing: flags)), ("id", String(describing: id)), ("date", String(describing: date)), ("title", String(describing: title)), ("iconColor", String(describing: iconColor)), ("iconEmojiId", String(describing: iconEmojiId)), ("topMessage", String(describing: topMessage)), ("readInboxMaxId", String(describing: readInboxMaxId)), ("readOutboxMaxId", String(describing: readOutboxMaxId)), ("unreadCount", String(describing: unreadCount)), ("unreadMentionsCount", String(describing: unreadMentionsCount)), ("unreadReactionsCount", String(describing: unreadReactionsCount)), ("fromId", String(describing: fromId))])
case .forumTopic(let flags, let id, let date, let title, let iconColor, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let unreadReactionsCount, let fromId, let notifySettings):
return ("forumTopic", [("flags", String(describing: flags)), ("id", String(describing: id)), ("date", String(describing: date)), ("title", String(describing: title)), ("iconColor", String(describing: iconColor)), ("iconEmojiId", String(describing: iconEmojiId)), ("topMessage", String(describing: topMessage)), ("readInboxMaxId", String(describing: readInboxMaxId)), ("readOutboxMaxId", String(describing: readOutboxMaxId)), ("unreadCount", String(describing: unreadCount)), ("unreadMentionsCount", String(describing: unreadMentionsCount)), ("unreadReactionsCount", String(describing: unreadReactionsCount)), ("fromId", String(describing: fromId)), ("notifySettings", String(describing: notifySettings))])
}
}
@ -1155,6 +1156,10 @@ public extension Api {
if let signature = reader.readInt32() {
_13 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _14: Api.PeerNotifySettings?
if let signature = reader.readInt32() {
_14 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
@ -1168,8 +1173,9 @@ public extension Api {
let _c11 = _11 != nil
let _c12 = _12 != nil
let _c13 = _13 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 {
return Api.ForumTopic.forumTopic(flags: _1!, id: _2!, date: _3!, title: _4!, iconColor: _5!, iconEmojiId: _6, topMessage: _7!, readInboxMaxId: _8!, readOutboxMaxId: _9!, unreadCount: _10!, unreadMentionsCount: _11!, unreadReactionsCount: _12!, fromId: _13!)
let _c14 = _14 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 {
return Api.ForumTopic.forumTopic(flags: _1!, id: _2!, date: _3!, title: _4!, iconColor: _5!, iconEmojiId: _6, topMessage: _7!, readInboxMaxId: _8!, readOutboxMaxId: _9!, unreadCount: _10!, unreadMentionsCount: _11!, unreadReactionsCount: _12!, fromId: _13!, notifySettings: _14!)
}
else {
return nil

View File

@ -860,6 +860,7 @@ public extension Api {
indirect enum InputNotifyPeer: TypeConstructorDescription {
case inputNotifyBroadcasts
case inputNotifyChats
case inputNotifyForumTopic(peer: Api.InputPeer, topMsgId: Int32)
case inputNotifyPeer(peer: Api.InputPeer)
case inputNotifyUsers
@ -876,6 +877,13 @@ public extension Api {
buffer.appendInt32(1251338318)
}
break
case .inputNotifyForumTopic(let peer, let topMsgId):
if boxed {
buffer.appendInt32(1548122514)
}
peer.serialize(buffer, true)
serializeInt32(topMsgId, buffer: buffer, boxed: false)
break
case .inputNotifyPeer(let peer):
if boxed {
@ -898,6 +906,8 @@ public extension Api {
return ("inputNotifyBroadcasts", [])
case .inputNotifyChats:
return ("inputNotifyChats", [])
case .inputNotifyForumTopic(let peer, let topMsgId):
return ("inputNotifyForumTopic", [("peer", String(describing: peer)), ("topMsgId", String(describing: topMsgId))])
case .inputNotifyPeer(let peer):
return ("inputNotifyPeer", [("peer", String(describing: peer))])
case .inputNotifyUsers:
@ -911,6 +921,22 @@ public extension Api {
public static func parse_inputNotifyChats(_ reader: BufferReader) -> InputNotifyPeer? {
return Api.InputNotifyPeer.inputNotifyChats
}
public static func parse_inputNotifyForumTopic(_ reader: BufferReader) -> InputNotifyPeer? {
var _1: Api.InputPeer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
}
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputNotifyPeer.inputNotifyForumTopic(peer: _1!, topMsgId: _2!)
}
else {
return nil
}
}
public static func parse_inputNotifyPeer(_ reader: BufferReader) -> InputNotifyPeer? {
var _1: Api.InputPeer?
if let signature = reader.readInt32() {

View File

@ -117,7 +117,7 @@ enum AccountStateMutationOperation {
case UpdateAudioTranscription(messageId: MessageId, id: Int64, isPending: Bool, text: String)
case UpdateConfig
case UpdateExtendedMedia(MessageId, Api.MessageExtendedMedia)
case ResetForumTopic(topicId: MessageId, data: MessageHistoryThreadData, pts: Int32)
case ResetForumTopic(topicId: MessageId, data: StoreMessageHistoryThreadData, pts: Int32)
}
struct HoleFromPreviousState {

View File

@ -62,8 +62,14 @@ public struct MessageHistoryThreadData: Codable, Equatable {
public var maxIncomingReadId: Int32
public var maxKnownMessageId: Int32
public var maxOutgoingReadId: Int32
public var unreadMentionCount: Int32
public var unreadReactionCount: Int32
public var notificationSettings: TelegramPeerNotificationSettings
}
struct StoreMessageHistoryThreadData {
var data: MessageHistoryThreadData
var topMessageId: Int32
var unreadMentionCount: Int32
var unreadReactionCount: Int32
}
public enum CreateForumChannelTopicError {
@ -247,7 +253,7 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
let _ = transaction.addMessages(messages.compactMap { message -> StoreMessage? in
let _ = InternalAccountState.addMessages(transaction: transaction, messages: messages.compactMap { message -> StoreMessage? in
return StoreMessage(apiMessage: message)
}, location: .Random)
@ -261,7 +267,7 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
for topic in topics {
switch topic {
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId):
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings):
let data = MessageHistoryThreadData(
creationDate: date,
author: fromId.peerId,
@ -274,13 +280,15 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
maxIncomingReadId: readInboxMaxId,
maxKnownMessageId: topMessage,
maxOutgoingReadId: readOutboxMaxId,
unreadMentionCount: unreadMentionsCount,
unreadReactionCount: unreadReactionsCount
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
)
guard let info = CodableEntry(data) else {
continue
}
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: info)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: Int64(id), tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: Int64(id), tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
}
}
}
@ -316,25 +324,6 @@ public final class ForumChannelTopics {
let _ = _internal_loadMessageHistoryThreads(account: self.account, peerId: peerId).start()
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(id: self.peerId)
self.statePromise.set(self.account.postbox.combinedView(keys: [viewKey])
|> map { views -> State in
guard let view = views.views[viewKey] as? MessageHistoryThreadIndexView else {
preconditionFailure()
}
return State(items: view.items.compactMap { item -> ForumChannelTopics.Item? in
guard let data = item.info.get(MessageHistoryThreadData.self) else {
return nil
}
return ForumChannelTopics.Item(
id: item.id,
info: data.info,
index: item.index,
topMessage: item.topMessage.flatMap(EngineMessage.init)
)
})
})
self.updateDisposable.set(account.viewTracker.polledChannel(peerId: peerId).start())
}

View File

@ -65,5 +65,5 @@ public func unarchiveAutomaticallyArchivedPeer(account: Account, peerId: PeerId)
}
|> deliverOnMainQueue).start()
let _ = _internal_updatePeerMuteSetting(account: account, peerId: peerId, muteInterval: nil).start()
let _ = _internal_updatePeerMuteSetting(account: account, peerId: peerId, threadId: nil, muteInterval: nil).start()
}

View File

@ -75,7 +75,7 @@ private func activeChannelsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set<Peer
switch chat {
case .channel:
if let channel = parseTelegramGroupOrChannel(chat: chat) as? TelegramChannel {
if channel.participationStatus == .member {
if channel.participationStatus == .member, case .personal = channel.accessHash {
peerIds.insert(channel.id)
}
}
@ -469,13 +469,13 @@ private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set<Pe
hasValidInclusion = false
}
if hasValidInclusion {
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) {
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) {
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
}
} else {
if let peer = transaction.getPeer(peerId) {
if let channel = peer as? TelegramChannel, channel.participationStatus != .member {
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) {
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) {
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
Logger.shared.log("State", "Peer \(peerId) (\(peer.debugDisplayTitle) has no stored inclusion, using synthesized one")
}
@ -1694,21 +1694,25 @@ func resolveForumThreads(postbox: Postbox, network: Network, state: AccountMutab
for topic in topics {
switch topic {
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId):
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings):
state.operations.append(.ResetForumTopic(
topicId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id),
data: MessageHistoryThreadData(
creationDate: date,
author: fromId.peerId,
info: EngineMessageHistoryThread.Info(
title: title,
icon: iconEmojiId == 0 ? nil : iconEmojiId,
iconColor: iconColor
data: StoreMessageHistoryThreadData(
data: MessageHistoryThreadData(
creationDate: date,
author: fromId.peerId,
info: EngineMessageHistoryThread.Info(
title: title,
icon: iconEmojiId == 0 ? nil : iconEmojiId,
iconColor: iconColor
),
incomingUnreadCount: unreadCount,
maxIncomingReadId: readInboxMaxId,
maxKnownMessageId: topMessage,
maxOutgoingReadId: readOutboxMaxId,
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
),
incomingUnreadCount: unreadCount,
maxIncomingReadId: readInboxMaxId,
maxKnownMessageId: topMessage,
maxOutgoingReadId: readOutboxMaxId,
topMessageId: topMessage,
unreadMentionCount: unreadMentionsCount,
unreadReactionCount: unreadReactionsCount
),
@ -1786,7 +1790,7 @@ func resolveForumThreads(postbox: Postbox, network: Network, ids: [MessageId]) -
for topic in topics {
switch topic {
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId):
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings):
let data = MessageHistoryThreadData(
creationDate: date,
author: fromId.peerId,
@ -1799,12 +1803,14 @@ func resolveForumThreads(postbox: Postbox, network: Network, ids: [MessageId]) -
maxIncomingReadId: readInboxMaxId,
maxKnownMessageId: topMessage,
maxOutgoingReadId: readOutboxMaxId,
unreadMentionCount: unreadMentionsCount,
unreadReactionCount: unreadReactionsCount
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
)
if let entry = CodableEntry(data) {
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: entry)
}
transaction.replaceMessageTagSummary(peerId: peerId, threadId: Int64(id), tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: Int64(id), tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
}
}
}
@ -1900,19 +1906,23 @@ func resolveForumThreads(postbox: Postbox, network: Network, fetchedChatList: Fe
for topic in topics {
switch topic {
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId):
fetchedChatList.threadInfos[MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)] = MessageHistoryThreadData(
creationDate: date,
author: fromId.peerId,
info: EngineMessageHistoryThread.Info(
title: title,
icon: iconEmojiId == 0 ? nil : iconEmojiId,
iconColor: iconColor
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings):
fetchedChatList.threadInfos[MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)] = StoreMessageHistoryThreadData(
data: MessageHistoryThreadData(
creationDate: date,
author: fromId.peerId,
info: EngineMessageHistoryThread.Info(
title: title,
icon: iconEmojiId == 0 ? nil : iconEmojiId,
iconColor: iconColor
),
incomingUnreadCount: unreadCount,
maxIncomingReadId: readInboxMaxId,
maxKnownMessageId: topMessage,
maxOutgoingReadId: readOutboxMaxId,
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
),
incomingUnreadCount: unreadCount,
maxIncomingReadId: readInboxMaxId,
maxKnownMessageId: topMessage,
maxOutgoingReadId: readOutboxMaxId,
topMessageId: topMessage,
unreadMentionCount: unreadMentionsCount,
unreadReactionCount: unreadReactionsCount
)
@ -2209,7 +2219,7 @@ func pollChannelOnce(postbox: Postbox, network: Network, peerId: PeerId, stateMa
hasValidInclusion = false
}
if hasValidInclusion {
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) as? TelegramPeerNotificationSettings {
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
}
}
@ -2263,7 +2273,7 @@ public func standalonePollChannelOnce(postbox: Postbox, network: Network, peerId
hasValidInclusion = false
}
if hasValidInclusion {
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) as? TelegramPeerNotificationSettings {
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
}
}
@ -3099,7 +3109,7 @@ func replayFinalState(
case .groupCreated, .channelMigratedFromGroup:
let holesAtHistoryStart = transaction.getHole(containing: MessageId(peerId: chatPeerId, namespace: Namespaces.Message.Cloud, id: id.id - 1))
for (space, _) in holesAtHistoryStart {
transaction.removeHole(peerId: chatPeerId, namespace: Namespaces.Message.Cloud, space: space, range: 1 ... id.id)
transaction.removeHole(peerId: chatPeerId, threadId: nil, namespace: Namespaces.Message.Cloud, space: space, range: 1 ... id.id)
}
default:
break
@ -3422,11 +3432,11 @@ func replayFinalState(
case let .UpdatePeerChatUnreadMark(peerId, namespace, value):
transaction.applyMarkUnread(peerId: peerId, namespace: namespace, value: value, interactive: false)
case let .ResetMessageTagSummary(peerId, tag, namespace, count, range):
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: tag, namespace: namespace, count: count, maxId: range.maxId)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: tag, namespace: namespace, count: count, maxId: range.maxId)
if count == 0 {
transaction.removeHole(peerId: peerId, namespace: namespace, space: .tag(tag), range: 1 ... (Int32.max - 1))
transaction.removeHole(peerId: peerId, threadId: nil, namespace: namespace, space: .tag(tag), range: 1 ... (Int32.max - 1))
if tag == .unseenPersonalMessage {
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, namespace: namespace, tag: tag).map({ $0.id })
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, threadId: nil, namespace: namespace, tag: tag).map({ $0.id })
Logger.shared.log("State", "will call markUnseenPersonalMessage for \(ids.count) messages")
for id in ids {
markUnseenPersonalMessage(transaction: transaction, id: id, addSynchronizeAction: false)
@ -3942,11 +3952,13 @@ func replayFinalState(
case let .ResetForumTopic(topicId, data, pts):
if finalState.state.resetForumTopicLists[topicId.peerId] == nil {
let _ = pts
if let entry = CodableEntry(data) {
if let entry = CodableEntry(data.data) {
transaction.setMessageHistoryThreadInfo(peerId: topicId.peerId, threadId: Int64(topicId.id), info: entry)
} else {
assertionFailure()
}
transaction.replaceMessageTagSummary(peerId: topicId.peerId, threadId: Int64(topicId.id), tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: data.unreadMentionCount, maxId: data.topMessageId)
transaction.replaceMessageTagSummary(peerId: topicId.peerId, threadId: Int64(topicId.id), tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: data.unreadReactionCount, maxId: data.topMessageId)
}
}
}
@ -3959,9 +3971,9 @@ func replayFinalState(
upperId = Int32.max
}
if upperId >= messageId.id {
transaction.addHole(peerId: messageId.peerId, namespace: messageId.namespace, space: .everywhere, range: messageId.id ... upperId)
transaction.addHole(peerId: messageId.peerId, threadId: nil, namespace: messageId.namespace, space: .everywhere, range: messageId.id ... upperId)
transaction.addHole(peerId: messageId.peerId, namespace: messageId.namespace, space: .tag(.pinned), range: 1 ... upperId)
transaction.addHole(peerId: messageId.peerId, threadId: nil, namespace: messageId.namespace, space: .tag(.pinned), range: 1 ... upperId)
Logger.shared.log("State", "adding hole for peer \(messageId.peerId), \(messageId.id) ... \(upperId)")
} else {
@ -4269,7 +4281,7 @@ func replayFinalState(
let currentInclusion = transaction.getPeerChatListInclusion(peerId)
if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive {
if let peer = transaction.getPeer(peerId) as? TelegramSecretChat {
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: transaction.getGlobalNotificationSettings(), peer: peer, peerSettings: transaction.getPeerNotificationSettings(peer.regularPeerId))
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: transaction.getGlobalNotificationSettings(), peer: peer, peerSettings: transaction.getPeerNotificationSettings(id: peer.regularPeerId))
if !isRemovedFromTotalUnreadCount {
transaction.updatePeerChatListInclusion(peerId, inclusion: currentInclusion.withGroupId(groupId: .root))

View File

@ -1358,7 +1358,7 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
notificationPeerId = author.id
}
if let notificationSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings {
if let notificationSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings {
var defaultSound: PeerMessageSound = defaultCloudPeerNotificationSound
var defaultNotify: Bool = true
if let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) {

View File

@ -181,7 +181,7 @@ private func fetchPoll(account: Account, messageId: MessageId) -> Signal<Void, N
private func wrappedHistoryViewAdditionalData(chatLocation: ChatLocationInput, additionalData: [AdditionalMessageHistoryViewData]) -> [AdditionalMessageHistoryViewData] {
var result = additionalData
switch chatLocation {
case let .peer(peerId):
case let .peer(peerId, _):
if peerId.namespace == Namespaces.Peer.CloudChannel {
if result.firstIndex(where: { if case .peerChatState = $0 { return true } else { return false } }) == nil {
result.append(.peerChatState(peerId))
@ -1220,13 +1220,13 @@ public final class AccountViewTracker {
}
}
public func updateMarkAllMentionsSeen(peerId: PeerId) {
public func updateMarkAllMentionsSeen(peerId: PeerId, threadId: Int64?) {
self.queue.async {
guard let account = self.account else {
return
}
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id }))
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id }))
for id in ids {
transaction.updateMessage(id, update: { currentMessage in
@ -1244,13 +1244,13 @@ public final class AccountViewTracker {
})
}
if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), summary.count > 0 {
if let summary = transaction.getMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), summary.count > 0 {
var maxId: Int32 = summary.range.maxId
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
maxId = index.id.id
}
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId)
addSynchronizeMarkAllUnseenPersonalMessagesOperation(transaction: transaction, peerId: peerId, maxId: summary.range.maxId)
}
@ -1303,13 +1303,13 @@ public final class AccountViewTracker {
}
}
public func updateMarkAllReactionsSeen(peerId: PeerId) {
public func updateMarkAllReactionsSeen(peerId: PeerId, threadId: Int64?) {
self.queue.async {
guard let account = self.account else {
return
}
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id }))
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id }))
for id in ids {
transaction.updateMessage(id, update: { currentMessage in
@ -1327,13 +1327,13 @@ public final class AccountViewTracker {
})
}
if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud) {
if let summary = transaction.getMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud) {
var maxId: Int32 = summary.range.maxId
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
maxId = index.id.id
}
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId)
addSynchronizeMarkAllUnseenReactionsOperation(transaction: transaction, peerId: peerId, maxId: summary.range.maxId)
}
@ -1513,6 +1513,35 @@ public final class AccountViewTracker {
}
func wrappedMessageHistorySignal(chatLocation: ChatLocationInput, signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>, addHoleIfNeeded: Bool) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
var signal = signal
if let postbox = self.account?.postbox, let peerId = chatLocation.peerId, let threadId = chatLocation.threadId {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
let fixedReadStates = Atomic<MessageHistoryViewReadState?>(value: nil)
signal = combineLatest(signal, postbox.combinedView(keys: [viewKey]))
|> map { view, additionalViews -> (MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?) in
var view = view
if let threadInfo = additionalViews.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.get(MessageHistoryThreadData.self) {
let readState = CombinedPeerReadState(states: [(Namespaces.Message.Cloud, .idBased(maxIncomingReadId: data.maxIncomingReadId, maxOutgoingReadId: data.maxOutgoingReadId, maxKnownId: data.maxKnownMessageId, count: data.incomingUnreadCount, markedUnread: false))])
let fixed = fixedReadStates.modify { current in
if let current = current {
return current
} else {
return view.0.fixedReadStates ?? .peer([peerId: readState])
}
}
view.0 = MessageHistoryView(
base: view.0,
fixed: fixed,
transient: .peer([peerId: readState])
)
}
return view
}
}
let history = withState(signal, { [weak self] () -> Int32 in
if let strongSelf = self {
return OSAtomicIncrement32(&strongSelf.nextViewId)
@ -1526,7 +1555,7 @@ public final class AccountViewTracker {
strongSelf.updatePendingWebpages(viewId: viewId, messageIds: messageIds, localWebpages: localWebpages)
let (pollMessageIds, pollMessageDict) = pollMessages(entries: next.0.entries)
strongSelf.updatePolls(viewId: viewId, messageIds: pollMessageIds, messages: pollMessageDict)
if case let .peer(peerId) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
if case let .peer(peerId, _) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0)
} else if case let .thread(peerId, _, _) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0, location: chatLocation)
@ -1539,7 +1568,7 @@ public final class AccountViewTracker {
strongSelf.updatePendingWebpages(viewId: viewId, messageIds: [], localWebpages: [:])
strongSelf.updatePolls(viewId: viewId, messageIds: [], messages: [:])
switch chatLocation {
case let .peer(peerId):
case let .peer(peerId, _):
if peerId.namespace == Namespaces.Peer.CloudChannel {
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: nil)
}
@ -1556,7 +1585,7 @@ public final class AccountViewTracker {
let peerId: PeerId?
switch chatLocation {
case let .peer(peerIdValue):
case let .peer(peerIdValue, _):
peerId = peerIdValue
case let .thread(peerIdValue, _, _):
peerId = peerIdValue
@ -1583,7 +1612,7 @@ public final class AccountViewTracker {
let isAutomaticallyTracked = self.account!.postbox.transaction { transaction -> Bool in
if transaction.getPeerChatListIndex(peerId) == nil {
if addHole {
transaction.addHole(peerId: peerId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: 1 ... (Int32.max - 1))
transaction.addHole(peerId: peerId, threadId: nil, namespace: Namespaces.Message.Cloud, space: .everywhere, range: 1 ... (Int32.max - 1))
}
return false
} else {
@ -1670,7 +1699,40 @@ public final class AccountViewTracker {
public func aroundMessageOfInterestHistoryViewForLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>? = nil, count: Int, tagMask: MessageTags? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account {
let signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
let signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>
if let peerId = chatLocation.peerId, let threadId = chatLocation.threadId, tagMask == nil {
return account.postbox.transaction { transaction -> MessageHistoryThreadData? in
return transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self)
}
|> mapToSignal { threadInfo -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in
if let threadInfo = threadInfo {
let anchor: HistoryViewInputAnchor
if threadInfo.incomingUnreadCount > 0 && tagMask == nil {
let customUnreadMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: threadInfo.maxIncomingReadId)
anchor = .message(customUnreadMessageId)
} else {
anchor = .upperBound
}
return account.postbox.aroundMessageHistoryViewForLocation(
chatLocation,
anchor: anchor,
ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange,
count: count,
fixedCombinedReadStates: nil,
topTaggedMessageIdNamespaces: [],
tagMask: tagMask,
appendMessagesFromTheSameGroup: false,
namespaces: .not(Namespaces.Message.allScheduled),
orderStatistics: orderStatistics
)
}
return account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, customUnreadMessageId: nil, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
}
} else {
signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, customUnreadMessageId: nil, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
}
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal, addHoleIfNeeded: true)
} else {
return .never()
@ -1961,13 +2023,13 @@ public final class AccountViewTracker {
}
}
public func unseenPersonalMessagesAndReactionCount(peerId: PeerId) -> Signal<(mentionCount: Int32, reactionCount: Int32), NoError> {
public func unseenPersonalMessagesAndReactionCount(peerId: PeerId, threadId: Int64?) -> Signal<(mentionCount: Int32, reactionCount: Int32), NoError> {
if let account = self.account {
let pendingMentionsKey: PostboxViewKey = .pendingMessageActionsSummary(type: .consumeUnseenPersonalMessage, peerId: peerId, namespace: Namespaces.Message.Cloud)
let summaryMentionsKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenPersonalMessage, peerId: peerId, namespace: Namespaces.Message.Cloud)
let summaryMentionsKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenPersonalMessage, peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud)
let pendingReactionsKey: PostboxViewKey = .pendingMessageActionsSummary(type: .readReaction, peerId: peerId, namespace: Namespaces.Message.Cloud)
let summaryReactionsKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenReaction, peerId: peerId, namespace: Namespaces.Message.Cloud)
let summaryReactionsKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenReaction, peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud)
return account.postbox.combinedView(keys: [pendingMentionsKey, summaryMentionsKey, pendingReactionsKey, summaryReactionsKey])
|> map { views -> (mentionCount: Int32, reactionCount: Int32) in

View File

@ -5,12 +5,14 @@ import SwiftSignalKit
public struct HistoryPreloadIndex: Hashable, Comparable, CustomStringConvertible {
public let index: ChatListIndex?
public let threadId: Int64?
public let hasUnread: Bool
public let isMuted: Bool
public let isPriority: Bool
public init(index: ChatListIndex?, hasUnread: Bool, isMuted: Bool, isPriority: Bool) {
public init(index: ChatListIndex?, threadId: Int64?, hasUnread: Bool, isMuted: Bool, isPriority: Bool) {
self.index = index
self.threadId = threadId
self.hasUnread = hasUnread
self.isMuted = isMuted
self.isPriority = isPriority
@ -38,6 +40,15 @@ public struct HistoryPreloadIndex: Hashable, Comparable, CustomStringConvertible
return false
}
}
if lhs.index == rhs.index {
if let lhsThreadId = lhs.threadId, let rhsThreadId = rhs.threadId {
if lhsThreadId != rhsThreadId {
return lhsThreadId < rhsThreadId
}
}
}
if let lhsIndex = lhs.index, let rhsIndex = rhs.index {
return lhsIndex > rhsIndex
} else if lhs.index != nil {
@ -117,6 +128,7 @@ private final class HistoryPreloadEntry: Comparable {
private final class HistoryPreloadViewContext {
var index: ChatListIndex?
var threadId: Int64?
var hasUnread: Bool?
var isMuted: Bool?
var isPriority: Bool
@ -125,7 +137,7 @@ private final class HistoryPreloadViewContext {
var media: [HolesViewMedia] = []
var preloadIndex: HistoryPreloadIndex {
return HistoryPreloadIndex(index: self.index, hasUnread: self.hasUnread ?? false, isMuted: self.isMuted ?? true, isPriority: self.isPriority)
return HistoryPreloadIndex(index: self.index, threadId: self.threadId, hasUnread: self.hasUnread ?? false, isMuted: self.isMuted ?? true, isPriority: self.isPriority)
}
var currentHole: HistoryPreloadHole? {
@ -136,8 +148,9 @@ private final class HistoryPreloadViewContext {
}
}
init(index: ChatListIndex?, hasUnread: Bool?, isMuted: Bool?, isPriority: Bool) {
init(index: ChatListIndex?, threadId: Int64?, hasUnread: Bool?, isMuted: Bool?, isPriority: Bool) {
self.index = index
self.threadId = threadId
self.hasUnread = hasUnread
self.isMuted = isMuted
self.isPriority = isPriority
@ -149,7 +162,7 @@ private final class HistoryPreloadViewContext {
}
private enum ChatHistoryPreloadEntity: Hashable {
case peer(PeerId)
case peer(peerId: PeerId, threadId: Int64?)
}
private struct ChatHistoryPreloadIndex {
@ -236,11 +249,13 @@ private final class AdditionalPreloadPeerIdsContext {
public struct ChatHistoryPreloadItem : Equatable {
public let index: ChatListIndex
public let threadId: Int64?
public let isMuted: Bool
public let hasUnread: Bool
public init(index: ChatListIndex, isMuted: Bool, hasUnread: Bool) {
public init(index: ChatListIndex, threadId: Int64?, isMuted: Bool, hasUnread: Bool) {
self.index = index
self.threadId = threadId
self.isMuted = isMuted
self.hasUnread = hasUnread
}
@ -365,7 +380,7 @@ final class ChatHistoryPreloadManager {
var indices: [(ChatHistoryPreloadIndex, Bool, Bool)] = []
for item in loadItems {
indices.append((ChatHistoryPreloadIndex(index: item.index, entity: .peer(item.index.messageIndex.id.peerId)), item.hasUnread, item.isMuted))
indices.append((ChatHistoryPreloadIndex(index: item.index, entity: .peer(peerId: item.index.messageIndex.id.peerId, threadId: item.threadId)), item.hasUnread, item.isMuted))
}
strongSelf.update(indices: indices, additionalPeerIds: additionalPeerIds)
@ -376,7 +391,7 @@ final class ChatHistoryPreloadManager {
self.queue.async {
var validEntityIds = Set(indices.map { $0.0.entity })
for peerId in additionalPeerIds {
validEntityIds.insert(.peer(peerId))
validEntityIds.insert(.peer(peerId: peerId, threadId: nil))
}
var removedEntityIds: [ChatHistoryPreloadEntity] = []
@ -400,7 +415,7 @@ final class ChatHistoryPreloadManager {
}
for peerId in additionalPeerIds {
if !existingPeerIds.contains(peerId) {
combinedIndices.append((ChatHistoryPreloadIndex(index: ChatListIndex.absoluteLowerBound, entity: .peer(peerId)), false, true, true))
combinedIndices.append((ChatHistoryPreloadIndex(index: ChatListIndex.absoluteLowerBound, entity: .peer(peerId: peerId, threadId: nil)), false, true, true))
}
}
@ -418,12 +433,17 @@ final class ChatHistoryPreloadManager {
}
}
} else {
let view = HistoryPreloadViewContext(index: index.index, hasUnread: hasUnread, isMuted: isMuted, isPriority: isPriority)
var threadId: Int64?
switch index.entity {
case let .peer(_, threadIdValue):
threadId = threadIdValue
}
let view = HistoryPreloadViewContext(index: index.index, threadId: threadId, hasUnread: hasUnread, isMuted: isMuted, isPriority: isPriority)
self.views[index.entity] = view
let key: PostboxViewKey
switch index.entity {
case let .peer(peerId):
key = .messageOfInterestHole(location: .peer(peerId), namespace: Namespaces.Message.Cloud, count: 70)
case let .peer(peerId, threadId):
key = .messageOfInterestHole(location: .peer(peerId: peerId, threadId: threadId), namespace: Namespaces.Message.Cloud, count: 70)
}
view.disposable.set((self.postbox.combinedView(keys: [key])
|> deliverOn(self.queue)).start(next: { [weak self] next in
@ -453,8 +473,8 @@ final class ChatHistoryPreloadManager {
let holeIsUpdated = previousHole != updatedHole
switch index.entity {
case let .peer(peerId):
Logger.shared.log("HistoryPreload", "view \(peerId) hole \(String(describing: updatedHole)) isUpdated: \(holeIsUpdated)")
case let .peer(peerId, threadId):
Logger.shared.log("HistoryPreload", "view \(peerId) (threadId: \(String(describing: threadId)) hole \(String(describing: updatedHole)) isUpdated: \(holeIsUpdated)")
}
if previousHole != updatedHole {

View File

@ -203,7 +203,7 @@ struct FetchedChatList {
var pinnedItemIds: [PeerId]?
var folderSummaries: [PeerGroupId: PeerGroupUnreadCountersSummary]
var peerGroupIds: [PeerId: PeerGroupId]
var threadInfos: [MessageId: MessageHistoryThreadData]
var threadInfos: [MessageId: StoreMessageHistoryThreadData]
}
func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLocation, upperBound: MessageIndex, hash: Int64, limit: Int32) -> Signal<FetchedChatList?, NoError> {

View File

@ -1,3 +1,16 @@
import Foundation
import Postbox
enum InternalAccountState {
static func addMessages(transaction: Transaction, messages: [StoreMessage], location: AddMessagesLocation) -> [Int64 : MessageId] {
return transaction.addMessages(messages, location: location)
}
static func deleteMessages(transaction: Transaction, ids: [MessageId], forEachMedia: ((Media) -> Void)?) {
transaction.deleteMessages(ids, forEachMedia: forEachMedia)
}
static func invalidateChannelState(peerId: PeerId) {
}
}

View File

@ -156,7 +156,7 @@ final class HistoryViewStateValidationContexts {
}
}
if let location = location, case let .thread(peerId, threadId, _) = location {
if let location = location, let peerId = location.peerId, let threadId = location.threadId {
var rangesToInvalidate: [[MessageId]] = []
let addToRange: (MessageId, inout [[MessageId]]) -> Void = { id, ranges in
if ranges.isEmpty {
@ -219,7 +219,7 @@ final class HistoryViewStateValidationContexts {
context.batchReferences[messageId] = batch
}
disposable.set((validateReplyThreadMessagesBatch(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, peerId: peerId, threadMessageId: makeThreadIdMessageId(peerId: peerId, threadId: threadId).id, messageIds: messages)
disposable.set((validateReplyThreadMessagesBatch(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, peerId: peerId, threadMessageId: makeThreadIdMessageId(peerId: peerId, threadId: threadId).id, tag: view.tagMask, messageIds: messages)
|> deliverOn(self.queue)).start(completed: { [weak self, weak batch] in
if let strongSelf = self, let context = strongSelf.contexts[id], let batch = batch {
var completedMessageIds: [MessageId] = []
@ -355,7 +355,7 @@ final class HistoryViewStateValidationContexts {
}
} else if view.namespaces.contains(Namespaces.Message.ScheduledCloud) {
if let _ = self.contexts[id] {
} else if let location = location, case let .peer(peerId) = location {
} else if let location = location, case let .peer(peerId, _) = location {
let timestamp = self.network.context.globalTime()
if let previousTimestamp = self.previousPeerValidationTimestamps[peerId], timestamp < previousTimestamp + 60 {
} else {
@ -543,7 +543,7 @@ private func validateChannelMessagesBatch(postbox: Postbox, network: Network, ac
} |> switchToLatest
}
private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, threadMessageId: Int32, messageIds: [MessageId]) -> Signal<Void, NoError> {
private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, threadMessageId: Int32, tag: MessageTags?, messageIds: [MessageId]) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Signal<Void, NoError> in
var previousMessages: [Message] = []
var previous: [MessageId: Message] = [:]
@ -556,10 +556,22 @@ private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network
var signal: Signal<ValidatedMessages, MTRpcError>
let hash = hashForMessages(previousMessages, withChannelIds: false)
Logger.shared.log("HistoryValidation", "validate reply thread batch for \(peerId): \(previousMessages.map({ $0.id }))")
Logger.shared.log("HistoryValidation", "validate reply thread batch (tag: \(String(describing: tag?.rawValue)) for \(peerId): \(previousMessages.map({ $0.id }))")
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
let requestSignal: Signal<Api.messages.Messages, MTRpcError>
requestSignal = network.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: threadMessageId, offsetId: messageIds[messageIds.count - 1].id, offsetDate: 0, addOffset: -1, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
if let tag = tag {
if let filter = messageFilterForTagMask(tag) {
var flags: Int32 = 0
flags |= (1 << 1)
requestSignal = network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: threadMessageId, filter: filter, minDate: 0, maxDate: 0, offsetId: messageIds[messageIds.count - 1].id + 1, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
} else {
return .complete()
}
} else {
requestSignal = network.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: threadMessageId, offsetId: messageIds[messageIds.count - 1].id, offsetDate: 0, addOffset: -1, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
}
signal = requestSignal
|> map { result -> ValidatedMessages in

View File

@ -406,7 +406,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
minMaxRange = 1 ... Int32.max - 1
}
request = source.request(Api.functions.messages.getUnreadMentions(flags: 0, peer: inputPeer, topMsgId: nil, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId {
flags |= (1 << 1)
topMsgId = threadId.id
}
request = source.request(Api.functions.messages.getUnreadMentions(flags: flags, peer: inputPeer, topMsgId: topMsgId, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
} else if tag == .unseenReaction {
let offsetId: Int32
let addOffset: Int32
@ -454,7 +461,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
minMaxRange = 1 ... Int32.max - 1
}
request = source.request(Api.functions.messages.getUnreadReactions(flags: 0, peer: inputPeer, topMsgId: nil, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId {
flags |= (1 << 0)
topMsgId = threadId.id
}
request = source.request(Api.functions.messages.getUnreadReactions(flags: flags, peer: inputPeer, topMsgId: topMsgId, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
} else if tag == .liveLocation {
let selectedLimit = count
@ -511,7 +525,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
minMaxRange = 1 ... (Int32.max - 1)
}
request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, topMsgId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId {
flags |= (1 << 1)
topMsgId = threadId.id
}
request = source.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
} else {
assertionFailure()
minMaxRange = 1 ... 1
@ -669,13 +690,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
switch peerInput {
case let .direct(peerId, threadId):
if let threadId = threadId {
for range in strictFilledIndices.rangeView {
transaction.removeThreadIndexHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: Int32(range.lowerBound) ... Int32(range.upperBound))
}
} else {
transaction.removeHole(peerId: peerId, namespace: namespace, space: space, range: filledRange)
}
transaction.removeHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: filledRange)
case .threadFromChannel:
break
}
@ -736,9 +751,11 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId
})
for (threadMessageId, data) in fetchedChats.threadInfos {
if let entry = CodableEntry(data) {
if let entry = CodableEntry(data.data) {
transaction.setMessageHistoryThreadInfo(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id), info: entry)
}
transaction.replaceMessageTagSummary(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id), tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: data.unreadMentionCount, maxId: data.topMessageId)
transaction.replaceMessageTagSummary(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id), tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: data.unreadReactionCount, maxId: data.topMessageId)
}
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: fetchedChats.peerPresences)
@ -778,10 +795,10 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId
}
for (peerId, summary) in fetchedChats.mentionTagSummaries {
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
}
for (peerId, summary) in fetchedChats.reactionTagSummaries {
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
}
for (groupId, summary) in fetchedChats.folderSummaries {

View File

@ -377,7 +377,7 @@ private func synchronizeUnseenPersonalMentionsTag(postbox: Postbox, network: Net
}
return postbox.transaction { transaction -> Void in
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadMentionsCount, maxId: apiTopMessage)
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, threadId: nil, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadMentionsCount, maxId: apiTopMessage)
}
} else {
return .complete()
@ -419,7 +419,7 @@ private func synchronizeUnseenReactionsTag(postbox: Postbox, network: Network, e
}
return postbox.transaction { transaction -> Void in
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadReactionsCount, maxId: apiTopMessage)
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, threadId: nil, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadReactionsCount, maxId: apiTopMessage)
}
} else {
return .complete()

View File

@ -24,13 +24,11 @@ private final class ManagedMessageHistoryHolesState {
for entry in entries {
switch entry.hole {
case let .peer(hole):
if hole.threadId == nil {
if self.holeDisposables[entry] == nil {
let disposable = MetaDisposable()
self.holeDisposables[entry] = disposable
added[entry] = disposable
}
case .peer:
if self.holeDisposables[entry] == nil {
let disposable = MetaDisposable()
self.holeDisposables[entry] = disposable
added[entry] = disposable
}
}
}
@ -55,7 +53,7 @@ func managedMessageHistoryHoles(accountPeerId: PeerId, network: Network, postbox
for (entry, disposable) in added {
switch entry.hole {
case let .peer(hole):
disposable.set(fetchMessageHistoryHole(accountPeerId: accountPeerId, source: .network(network), postbox: postbox, peerInput: .direct(peerId: hole.peerId, threadId: nil), namespace: hole.namespace, direction: entry.direction, space: entry.space, count: entry.count).start())
disposable.set(fetchMessageHistoryHole(accountPeerId: accountPeerId, source: .network(network), postbox: postbox, peerInput: .direct(peerId: hole.peerId, threadId: hole.threadId), namespace: hole.namespace, direction: entry.direction, space: entry.space, count: entry.count).start())
}
}
})

View File

@ -72,7 +72,7 @@ func managedPendingPeerNotificationSettings(postbox: Postbox, network: Network)
}
for (peerId, settings, disposable) in beginOperations {
let signal = pushPeerNotificationSettings(postbox: postbox, network: network, peerId: peerId, settings: settings)
let signal = pushPeerNotificationSettings(postbox: postbox, network: network, peerId: peerId, threadId: nil, settings: settings)
disposable.set(signal.start())
}
})
@ -89,62 +89,109 @@ func managedPendingPeerNotificationSettings(postbox: Postbox, network: Network)
}
}
private func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: PeerId, settings: PeerNotificationSettings) -> Signal<Void, NoError> {
func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: PeerId, threadId: Int64?, settings: PeerNotificationSettings) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Signal<Void, NoError> in
if let peer = transaction.getPeer(peerId) {
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
}
if let notificationPeer = transaction.getPeer(notificationPeerId), let inputPeer = apiInputPeer(notificationPeer), let settings = settings as? TelegramPeerNotificationSettings {
let showPreviews: Api.Bool?
switch settings.displayPreviews {
if let threadId = threadId {
if let data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
let settings = data.notificationSettings
let showPreviews: Api.Bool?
switch settings.displayPreviews {
case .default:
showPreviews = nil
case .show:
showPreviews = .boolTrue
case .hide:
showPreviews = .boolFalse
}
let muteUntil: Int32?
switch settings.muteState {
}
let muteUntil: Int32?
switch settings.muteState {
case let .muted(until):
muteUntil = until
case .unmuted:
muteUntil = 0
case .default:
muteUntil = nil
}
let sound: Api.NotificationSound? = settings.messageSound.apiSound
var flags: Int32 = 0
if showPreviews != nil {
flags |= (1 << 0)
}
if muteUntil != nil {
flags |= (1 << 2)
}
if sound != nil {
flags |= (1 << 3)
}
let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound)
return network.request(Api.functions.account.updateNotifySettings(peer: .inputNotifyPeer(peer: inputPeer), settings: inputSettings))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> mapToSignal { result -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in
transaction.updateCurrentPeerNotificationSettings([notificationPeerId: settings])
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil)
}
let sound: Api.NotificationSound? = settings.messageSound.apiSound
var flags: Int32 = 0
if showPreviews != nil {
flags |= (1 << 0)
}
if muteUntil != nil {
flags |= (1 << 2)
}
if sound != nil {
flags |= (1 << 3)
}
let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound)
return network.request(Api.functions.account.updateNotifySettings(peer: .inputNotifyForumTopic(peer: inputPeer, topMsgId: Int32(clamping: threadId)), settings: inputSettings))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> mapToSignal { result -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in
}
}
} else {
return .complete()
}
} else {
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil)
if let notificationPeer = transaction.getPeer(notificationPeerId), let inputPeer = apiInputPeer(notificationPeer), let settings = settings as? TelegramPeerNotificationSettings {
let showPreviews: Api.Bool?
switch settings.displayPreviews {
case .default:
showPreviews = nil
case .show:
showPreviews = .boolTrue
case .hide:
showPreviews = .boolFalse
}
let muteUntil: Int32?
switch settings.muteState {
case let .muted(until):
muteUntil = until
case .unmuted:
muteUntil = 0
case .default:
muteUntil = nil
}
let sound: Api.NotificationSound? = settings.messageSound.apiSound
var flags: Int32 = 0
if showPreviews != nil {
flags |= (1 << 0)
}
if muteUntil != nil {
flags |= (1 << 2)
}
if sound != nil {
flags |= (1 << 3)
}
let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound)
return network.request(Api.functions.account.updateNotifySettings(peer: .inputNotifyPeer(peer: inputPeer), settings: inputSettings))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> mapToSignal { result -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in
transaction.updateCurrentPeerNotificationSettings([notificationPeerId: settings])
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil)
}
}
}
} else {
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil)
}
return .complete()
}
return .complete()
}
} else {
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {

View File

@ -284,7 +284,7 @@ private func synchronizeMarkAllUnseenReactions(transaction: Transaction, postbox
return .complete()
}
let signal = network.request(Api.functions.messages.readReactions(peer: inputPeer))
let signal = network.request(Api.functions.messages.readReactions(flags: 0, peer: inputPeer, topMsgId: nil))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.AffectedHistory?, Bool> in
return .fail(true)
@ -308,90 +308,6 @@ private func synchronizeMarkAllUnseenReactions(transaction: Transaction, postbox
|> `catch` { _ -> Signal<Void, NoError> in
return .complete()
}
/*let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel)
let limit: Int32 = 100
let oneOperation: (Int32) -> Signal<Int32?, MTRpcError> = { maxId in
return network.request(Api.functions.messages.getUnreadReactions(peer: inputPeer, offsetId: maxId, addOffset: maxId == 0 ? 0 : -1, limit: limit, maxId: maxId == 0 ? 0 : (maxId + 1), minId: 1))
|> mapToSignal { result -> Signal<[MessageId], MTRpcError> in
switch result {
case let .messages(messages, _, _):
return .single(messages.compactMap({ $0.id() }))
case let .channelMessages(_, _, _, _, messages, _, _):
return .single(messages.compactMap({ $0.id() }))
case .messagesNotModified:
return .single([])
case let .messagesSlice(_, _, _, _, messages, _, _):
return .single(messages.compactMap({ $0.id() }))
}
}
|> mapToSignal { ids -> Signal<Int32?, MTRpcError> in
let filteredIds = ids.filter { $0.id <= operation.maxId }
if filteredIds.isEmpty {
return .single(ids.min()?.id)
}
if peerId.namespace == Namespaces.Peer.CloudChannel {
guard let inputChannel = inputChannel else {
return .single(nil)
}
return network.request(Api.functions.channels.readMessageContents(channel: inputChannel, id: filteredIds.map { $0.id }))
|> map { result -> Int32? in
if ids.count < limit {
return nil
} else {
return ids.min()?.id
}
}
} else {
return network.request(Api.functions.messages.readMessageContents(id: filteredIds.map { $0.id }))
|> map { result -> Int32? in
switch result {
case let .affectedMessages(pts, ptsCount):
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
}
if ids.count < limit {
return nil
} else {
return ids.min()?.id
}
}
}
}
}
let currentMaxId = Atomic<Int32>(value: 0)
let loopOperations: Signal<Void, GetUnseenIdsError> = (
(
deferred {
return oneOperation(currentMaxId.with { $0 })
}
|> `catch` { error -> Signal<Int32?, GetUnseenIdsError> in
return .fail(.error(error))
}
)
|> mapToSignal { resultId -> Signal<Void, GetUnseenIdsError> in
if let resultId = resultId {
let previous = currentMaxId.swap(resultId)
if previous == resultId {
return .fail(.done)
} else {
return .complete()
}
} else {
return .fail(.done)
}
}
|> `catch` { error -> Signal<Void, GetUnseenIdsError> in
switch error {
case .done, .error:
return .fail(error)
}
}
|> restart
)
return loopOperations
|> `catch` { _ -> Signal<Void, NoError> in
return .complete()
}*/
}
func markUnseenReactionMessage(transaction: Transaction, id: MessageId, addSynchronizeAction: Bool) {

View File

@ -68,11 +68,7 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
if channel.flags.contains(.isForum) {
return []
}
if channel.username != nil {
return .group
} else {
return .group
}
return .group
}
} else {
assertionFailure()

View File

@ -73,11 +73,41 @@ public func getCloudLegacySound(id: Int64) -> (id: Int32, category: CloudSoundBu
return nil
}
public enum PeerMuteState: Equatable {
public enum PeerMuteState: Codable, Equatable {
case `default`
case unmuted
case muted(until: Int32)
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
switch try container.decode(Int32.self, forKey: "m.v") {
case 0:
self = .default
case 1:
self = .muted(until: try container.decode(Int32.self, forKey: "m.u"))
case 2:
self = .unmuted
default:
assertionFailure()
self = .default
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
switch self {
case .default:
try container.encode(0 as Int32, forKey: "m.v")
case let .muted(until):
try container.encode(1 as Int32, forKey: "m.v")
try container.encode(until, forKey: "m.u")
case .unmuted:
try container.encode(2 as Int32, forKey: "m.v")
}
}
fileprivate static func decodeInline(_ decoder: PostboxDecoder) -> PeerMuteState {
switch decoder.decodeInt32ForKey("m.v", orElse: 0) {
case 0:
@ -104,15 +134,15 @@ public enum PeerMuteState: Equatable {
}
}
private enum PeerMessageSoundValue: Int32 {
case none
case bundledModern
case bundledClassic
case `default`
case cloud
private enum PeerMessageSoundValue: Int32, Codable {
case none = 0
case bundledModern = 1
case bundledClassic = 2
case `default` = 3
case cloud = 4
}
public enum PeerMessageSound: Equatable {
public enum PeerMessageSound: Equatable, Codable {
public enum Id: Hashable {
case none
case `default`
@ -142,6 +172,30 @@ public enum PeerMessageSound: Equatable {
}
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
switch try container.decode(Int32.self, forKey: "s.v") {
case PeerMessageSoundValue.none.rawValue:
self = .none
case PeerMessageSoundValue.bundledModern.rawValue:
self = .cloud(fileId: getCloudSoundOrDefault(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0, isModern: true))
case PeerMessageSoundValue.bundledClassic.rawValue:
self = .cloud(fileId: getCloudSoundOrDefault(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0, isModern: false))
case PeerMessageSoundValue.default.rawValue:
self = .default
case PeerMessageSoundValue.cloud.rawValue:
do {
self = .cloud(fileId: try container.decode(Int64.self, forKey: "s.cloud.fileId"))
} catch {
self = .default
}
default:
assertionFailure()
self = defaultCloudPeerNotificationSound
}
}
static func decodeInline(_ container: KeyedDecodingContainer<StringCodingKey>) throws -> PeerMessageSound {
switch try container.decode(Int32.self, forKey: "s.v") {
case PeerMessageSoundValue.none.rawValue:
@ -181,6 +235,26 @@ public enum PeerMessageSound: Equatable {
return defaultCloudPeerNotificationSound
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
switch self {
case .none:
try container.encode(PeerMessageSoundValue.none.rawValue, forKey: "s.v")
case let .bundledModern(id):
try container.encode(PeerMessageSoundValue.bundledModern.rawValue, forKey: "s.v")
try container.encode(id, forKey: "s.i")
case let .bundledClassic(id):
try container.encode(PeerMessageSoundValue.bundledClassic.rawValue, forKey: "s.v")
try container.encode(id, forKey: "s.i")
case let .cloud(fileId):
try container.encode(PeerMessageSoundValue.cloud.rawValue, forKey: "s.v")
try container.encode(fileId, forKey: "s.cloud.fileId")
case .default:
try container.encode(PeerMessageSoundValue.default.rawValue, forKey: "s.v")
}
}
func encodeInline(_ container: inout KeyedEncodingContainer<StringCodingKey>) throws {
switch self {
@ -254,11 +328,40 @@ public enum PeerMessageSound: Equatable {
}
}
public enum PeerNotificationDisplayPreviews {
public enum PeerNotificationDisplayPreviews: Equatable, Codable {
case `default`
case show
case hide
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
switch try container.decode(Int32.self, forKey: "p.v") {
case 0:
self = .default
case 1:
self = .show
case 2:
self = .hide
default:
assertionFailure()
self = .default
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
switch self {
case .default:
try container.encode(0 as Int32, forKey: "p.v")
case .show:
try container.encode(1 as Int32, forKey: "p.v")
case .hide:
try container.encode(2 as Int32, forKey: "p.v")
}
}
static func decodeInline(_ decoder: PostboxDecoder) -> PeerNotificationDisplayPreviews {
switch decoder.decodeInt32ForKey("p.v", orElse: 0) {
case 0:
@ -285,7 +388,7 @@ public enum PeerNotificationDisplayPreviews {
}
}
public final class TelegramPeerNotificationSettings: PeerNotificationSettings, Equatable {
public final class TelegramPeerNotificationSettings: PeerNotificationSettings, Codable, Equatable {
public let muteState: PeerMuteState
public let messageSound: PeerMessageSound
public let displayPreviews: PeerNotificationDisplayPreviews
@ -325,6 +428,22 @@ public final class TelegramPeerNotificationSettings: PeerNotificationSettings, E
self.displayPreviews = PeerNotificationDisplayPreviews.decodeInline(decoder)
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
self.muteState = try container.decode(PeerMuteState.self, forKey: "muteState")
self.messageSound = try container.decode(PeerMessageSound.self, forKey: "messageSound")
self.displayPreviews = try container.decode(PeerNotificationDisplayPreviews.self, forKey: "displayPreviews")
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
try container.encode(self.muteState, forKey: "muteState")
try container.encode(self.messageSound, forKey: "messageSound")
try container.encode(self.displayPreviews, forKey: "displayPreviews")
}
public func encode(_ encoder: PostboxEncoder) {
self.muteState.encodeInline(encoder)
self.messageSound.encodeInline(encoder)

View File

@ -275,23 +275,26 @@ public extension TelegramEngine.EngineData.Item {
public struct ItemKey: Hashable {
public var peerId: EnginePeer.Id
public var tag: MessageTags
public var threadId: Int64?
}
public typealias Result = Int?
fileprivate var peerId: EnginePeer.Id
fileprivate var tag: MessageTags
fileprivate var threadId: Int64?
public var mapKey: ItemKey {
return ItemKey(peerId: self.peerId, tag: self.tag)
return ItemKey(peerId: self.peerId, tag: self.tag, threadId: self.threadId)
}
public init(peerId: EnginePeer.Id, tag: MessageTags) {
public init(peerId: EnginePeer.Id, threadId: Int64?, tag: MessageTags) {
self.peerId = peerId
self.threadId = threadId
self.tag = tag
}
var key: PostboxViewKey {
return .historyTagSummaryView(tag: tag, peerId: peerId, namespace: Namespaces.Message.Cloud)
return .historyTagSummaryView(tag: self.tag, peerId: self.peerId, threadId: self.threadId, namespace: Namespaces.Message.Cloud)
}
func extract(view: PostboxView) -> Result {

View File

@ -258,6 +258,32 @@ public extension TelegramEngine.EngineData.Item {
return EnginePeer.NotificationSettings(notificationSettings)
}
}
public struct ThreadNotificationSettings: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = EnginePeer.NotificationSettings
fileprivate var id: EnginePeer.Id
fileprivate var threadId: Int64
public init(id: EnginePeer.Id, threadId: Int64) {
self.id = id
self.threadId = threadId
}
var key: PostboxViewKey {
return .messageHistoryThreadInfo(peerId: self.id, threadId: self.threadId)
}
func extract(view: PostboxView) -> Result {
guard let view = view as? MessageHistoryThreadInfoView else {
preconditionFailure()
}
guard let data = view.info?.get(MessageHistoryThreadData.self) else {
return EnginePeer.NotificationSettings(TelegramPeerNotificationSettings.defaultSettings)
}
return EnginePeer.NotificationSettings(data.notificationSettings)
}
}
public struct ParticipantCount: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Optional<Int>

View File

@ -115,14 +115,14 @@ public final class EngineDataOptional<Item: TelegramEngineDataItem>: TelegramEng
}
func _extract(views: [PostboxViewKey: PostboxView]) -> Any {
var result: [Item.Result] = []
var result: Item.Result?
if let item = self.item {
let itemResult = (item as! AnyPostboxViewDataItem)._extract(views: views)
result.append(itemResult as! Item.Result)
result = (itemResult as! Item.Result)
}
return result
return result as Any
}
}

View File

@ -133,7 +133,7 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, viewT
}
if !hasUnread && peerId.namespace == Namespaces.Peer.SecretChat {
let unseenSummary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud)
let unseenSummary = transaction.getMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud)
let actionSummary = transaction.getPendingMessageActionsSummary(peerId: peerId, type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud)
if (unseenSummary?.count ?? 0) - (actionSummary ?? 0) > 0 {
hasUnread = true
@ -147,7 +147,7 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, viewT
} else {
transaction.applyMarkUnread(peerId: peerId, namespace: principalNamespace, value: false, interactive: true)
}
viewTracker.updateMarkAllMentionsSeen(peerId: peerId)
viewTracker.updateMarkAllMentionsSeen(peerId: peerId, threadId: nil)
}
} else {
if setToValue == nil || setToValue! {
@ -156,22 +156,22 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, viewT
}
}
public func clearPeerUnseenPersonalMessagesInteractively(account: Account, peerId: PeerId) -> Signal<Never, NoError> {
public func clearPeerUnseenPersonalMessagesInteractively(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Void in
if peerId.namespace == Namespaces.Peer.SecretChat {
return
}
account.viewTracker.updateMarkAllMentionsSeen(peerId: peerId)
account.viewTracker.updateMarkAllMentionsSeen(peerId: peerId, threadId: threadId)
}
|> ignoreValues
}
public func clearPeerUnseenReactionsInteractively(account: Account, peerId: PeerId) -> Signal<Never, NoError> {
public func clearPeerUnseenReactionsInteractively(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Void in
if peerId.namespace == Namespaces.Peer.SecretChat {
return
}
account.viewTracker.updateMarkAllReactionsSeen(peerId: peerId)
account.viewTracker.updateMarkAllReactionsSeen(peerId: peerId, threadId: threadId)
}
|> ignoreValues
}

View File

@ -9,14 +9,14 @@ public enum EarliestUnseenPersonalMentionMessageResult: Equatable {
case result(MessageId?)
}
func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenPersonalMessage, additionalData: [.peerChatState(peerId)])
func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: threadId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenPersonalMessage, additionalData: [.peerChatState(peerId)])
|> mapToSignal { view -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
if view.0.isLoading {
return .single(.loading)
}
if case .FillHole = view.1 {
return _internal_earliestUnseenPersonalMentionMessage(account: account, peerId: peerId)
return _internal_earliestUnseenPersonalMentionMessage(account: account, peerId: peerId, threadId: threadId)
}
if let message = view.0.entries.first?.message {
if peerId.namespace == Namespaces.Peer.CloudChannel {
@ -53,10 +53,10 @@ func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: Pe
} else {
return account.postbox.transaction { transaction -> EarliestUnseenPersonalMentionMessageResult in
if let topId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) {
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: topId.id)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: topId.id)
transaction.removeHole(peerId: peerId, namespace: Namespaces.Message.Cloud, space: .tag(.unseenPersonalMessage), range: 1 ... (Int32.max - 1))
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id })
transaction.removeHole(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, space: .tag(.unseenPersonalMessage), range: 1 ... (Int32.max - 1))
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id })
for id in ids {
markUnseenPersonalMessage(transaction: transaction, id: id, addSynchronizeAction: false)
}
@ -76,14 +76,14 @@ func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: Pe
})
}
func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenReaction, additionalData: [.peerChatState(peerId)])
func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: threadId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenReaction, additionalData: [.peerChatState(peerId)])
|> mapToSignal { view -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
if view.0.isLoading {
return .single(.loading)
}
if case .FillHole = view.1 {
return _internal_earliestUnseenPersonalReactionMessage(account: account, peerId: peerId)
return _internal_earliestUnseenPersonalReactionMessage(account: account, peerId: peerId, threadId: threadId)
}
if let message = view.0.entries.first?.message {
if peerId.namespace == Namespaces.Peer.CloudChannel {
@ -120,10 +120,10 @@ func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: P
} else {
return account.postbox.transaction { transaction -> EarliestUnseenPersonalMentionMessageResult in
if let topId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) {
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: 0, maxId: topId.id)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: 0, maxId: topId.id)
transaction.removeHole(peerId: peerId, namespace: Namespaces.Message.Cloud, space: .tag(.unseenReaction), range: 1 ... (Int32.max - 1))
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id })
transaction.removeHole(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, space: .tag(.unseenReaction), range: 1 ... (Int32.max - 1))
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id })
for id in ids {
markUnseenReactionMessage(transaction: transaction, id: id, addSynchronizeAction: false)
}

View File

@ -4,7 +4,7 @@ import SwiftSignalKit
import TelegramApi
func _internal_topPeerActiveLiveLocationMessages(viewTracker: AccountViewTracker, accountPeerId: PeerId, peerId: PeerId) -> Signal<(Peer?, [Message]), NoError> {
return viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .upperBound, anchorIndex: .upperBound, count: 50, fixedCombinedReadStates: nil, tagMask: .liveLocation, orderStatistics: [], additionalData: [.peer(accountPeerId)])
return viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 50, fixedCombinedReadStates: nil, tagMask: .liveLocation, orderStatistics: [], additionalData: [.peer(accountPeerId)])
|> map { (view, _, _) -> (Peer?, [Message]) in
var accountPeer: Peer?
for entry in view.additionalData {

View File

@ -325,10 +325,6 @@ private class ReplyThreadHistoryContextImpl {
return
}
guard let _ = self.stateValue else {
return
}
let fromIdExclusive: Int32?
let toIndex = messageIndex
if let maxReadIncomingMessageId = self.maxReadIncomingMessageIdValue {
@ -345,6 +341,7 @@ private class ReplyThreadHistoryContextImpl {
if messageIndex.id.id >= data.maxIncomingReadId {
if let count = transaction.getThreadMessageCount(peerId: messageId.peerId, threadId: Int64(messageId.id), namespace: messageId.namespace, fromIdExclusive: data.maxIncomingReadId, toIndex: messageIndex) {
data.incomingUnreadCount = max(0, data.incomingUnreadCount - Int32(count))
data.maxIncomingReadId = messageIndex.id.id
}
data.maxKnownMessageId = max(data.maxKnownMessageId, messageIndex.id.id)
@ -937,7 +934,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
return account.postbox.transaction { transaction -> Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError> in
if let initialFilledHoles = initialFilledHoles {
for range in initialFilledHoles.strictRemovedIndices.rangeView {
transaction.removeThreadIndexHole(peerId: discussionMessage.messageId.peerId, threadId: makeMessageThreadId(discussionMessage.messageId), namespace: Namespaces.Message.Cloud, space: .everywhere, range: Int32(range.lowerBound) ... Int32(range.upperBound))
transaction.removeHole(peerId: discussionMessage.messageId.peerId, threadId: makeMessageThreadId(discussionMessage.messageId), namespace: Namespaces.Message.Cloud, space: .everywhere, range: Int32(range.lowerBound) ... Int32(range.upperBound))
}
}

View File

@ -189,12 +189,7 @@ public final class SparseMessageList {
let count: Int
count = 200
let location: ChatLocationInput
if let threadId = self.threadId {
location = .thread(peerId: self.peerId, threadId: threadId, data: .single(MessageHistoryViewExternalInput(content: .thread(peerId: self.peerId, id: threadId, holes: [:]), maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil)))
} else {
location = .peer(peerId: self.peerId)
}
let location: ChatLocationInput = .peer(peerId: self.peerId, threadId: self.threadId)
self.topItemsDisposable.set((self.account.postbox.aroundMessageHistoryViewForLocation(location, anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: count, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: self.messageTag, appendMessagesFromTheSameGroup: false, namespaces: .not(Set(Namespaces.Message.allScheduled)), orderStatistics: [])
|> deliverOn(self.queue)).start(next: { [weak self] view, updateType, _ in

View File

@ -154,32 +154,32 @@ public extension TelegramEngine {
return PollResultsContext(account: self.account, messageId: messageId, poll: poll)
}
public func earliestUnseenPersonalMentionMessage(peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
public func earliestUnseenPersonalMentionMessage(peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
let account = self.account
return _internal_earliestUnseenPersonalMentionMessage(account: self.account, peerId: peerId)
return _internal_earliestUnseenPersonalMentionMessage(account: self.account, peerId: peerId, threadId: threadId)
|> mapToSignal { result -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
switch result {
case .loading:
return .single(result)
case let .result(messageId):
if messageId == nil {
let _ = clearPeerUnseenPersonalMessagesInteractively(account: account, peerId: peerId).start()
let _ = clearPeerUnseenPersonalMessagesInteractively(account: account, peerId: peerId, threadId: threadId).start()
}
return .single(result)
}
}
}
public func earliestUnseenPersonalReactionMessage(peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
public func earliestUnseenPersonalReactionMessage(peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
let account = self.account
return _internal_earliestUnseenPersonalReactionMessage(account: self.account, peerId: peerId)
return _internal_earliestUnseenPersonalReactionMessage(account: self.account, peerId: peerId, threadId: threadId)
|> mapToSignal { result -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
switch result {
case .loading:
return .single(result)
case let .result(messageId):
if messageId == nil {
let _ = clearPeerUnseenReactionsInteractively(account: account, peerId: peerId).start()
let _ = clearPeerUnseenReactionsInteractively(account: account, peerId: peerId, threadId: threadId).start()
}
return .single(result)
}
@ -297,7 +297,7 @@ public extension TelegramEngine {
return SparseMessageScrollingContext(account: self.account, peerId: peerId)
}
public func refreshMessageTagStats(peerId: EnginePeer.Id, tags: [EngineMessage.Tags]) -> Signal<Never, NoError> {
public func refreshMessageTagStats(peerId: EnginePeer.Id, threadId: Int64?, tags: [EngineMessage.Tags]) -> Signal<Never, NoError> {
let account = self.account
return self.account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
@ -312,7 +312,15 @@ public extension TelegramEngine {
signals.append(.single((nil, nil)))
continue
}
signals.append(self.account.network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, topMsgId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1, maxId: 0, minId: 0, hash: 0))
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = threadId {
flags |= (1 << 1)
topMsgId = Int32(clamping: threadId)
}
signals.append(self.account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1, maxId: 0, minId: 0, hash: 0))
|> map { result -> (count: Int32?, topId: Int32?) in
switch result {
case let .messagesSlice(_, count, _, _, messages, _, _):
@ -335,7 +343,7 @@ public extension TelegramEngine {
for i in 0 ..< tags.count {
let (count, maxId) = counts[i]
if let count = count {
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: tags[i], namespace: Namespaces.Message.Cloud, count: count, maxId: maxId ?? 1)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: tags[i], namespace: Namespaces.Message.Cloud, count: count, maxId: maxId ?? 1)
}
}
}

View File

@ -170,7 +170,7 @@ func _internal_requestUnpinAllMessages(account: Account, peerId: PeerId) -> Sign
}, delayIncrement: 0.0, maxDelay: 0.0, maxRetries: 100, onQueue: .concurrentDefaultQueue())
|> mapToSignal { _ -> Signal<Never, InternalError> in
let signal: Signal<Never, InternalError> = account.postbox.transaction { transaction -> Void in
for index in transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .pinned) {
for index in transaction.getMessageIndicesWithTag(peerId: peerId, threadId: nil, namespace: Namespaces.Message.Cloud, tag: .pinned) {
transaction.updateMessage(index.id, update: { currentMessage in
var storeForwardInfo: StoreMessageForwardInfo?
if let forwardInfo = currentMessage.forwardInfo {

View File

@ -1,17 +1,41 @@
import Foundation
import Postbox
import SwiftSignalKit
import TelegramApi
func _internal_togglePeerMuted(account: Account, peerId: PeerId) -> Signal<Void, NoError> {
func _internal_togglePeerMuted(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<Void, NoError> {
return account.postbox.transaction { transaction -> Void in
if let peer = transaction.getPeer(peerId) {
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
guard let peer = transaction.getPeer(peerId) else {
return
}
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
}
if let threadId = threadId {
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
var updatedSettings: TelegramPeerNotificationSettings
switch data.notificationSettings.muteState {
case .default:
updatedSettings = data.notificationSettings.withUpdatedMuteState(.muted(until: Int32.max))
case .unmuted:
updatedSettings = data.notificationSettings.withUpdatedMuteState(.muted(until: Int32.max))
case .muted:
updatedSettings = data.notificationSettings.withUpdatedMuteState(.unmuted)
}
data.notificationSettings = updatedSettings
if let entry = CodableEntry(data) {
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
//TODO:loc
let _ = pushPeerNotificationSettings(postbox: account.postbox, network: account.network, peerId: peerId, threadId: threadId, settings: TelegramPeerNotificationSettings.defaultSettings).start()
}
}
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
} else {
let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings
let previousSettings: TelegramPeerNotificationSettings
if let currentSettings = currentSettings {
previousSettings = currentSettings
@ -38,97 +62,159 @@ func _internal_togglePeerMuted(account: Account, peerId: PeerId) -> Signal<Void,
}
}
func _internal_updatePeerMuteSetting(account: Account, peerId: PeerId, muteInterval: Int32?) -> Signal<Void, NoError> {
func _internal_updatePeerMuteSetting(account: Account, peerId: PeerId, threadId: Int64?, muteInterval: Int32?) -> Signal<Void, NoError> {
return account.postbox.transaction { transaction -> Void in
updatePeerMuteSetting(transaction: transaction, peerId: peerId, muteInterval: muteInterval)
_internal_updatePeerMuteSetting(account: account, transaction: transaction, peerId: peerId, threadId: threadId, muteInterval: muteInterval)
}
}
func updatePeerMuteSetting(transaction: Transaction, peerId: PeerId, muteInterval: Int32?) {
func _internal_updatePeerMuteSetting(account: Account, transaction: Transaction, peerId: PeerId, threadId: Int64?, muteInterval: Int32?) {
if let peer = transaction.getPeer(peerId) {
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
}
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
let previousSettings: TelegramPeerNotificationSettings
if let currentSettings = currentSettings {
previousSettings = currentSettings
} else {
previousSettings = TelegramPeerNotificationSettings.defaultSettings
}
let muteState: PeerMuteState
if let muteInterval = muteInterval {
if muteInterval == 0 {
muteState = .unmuted
} else {
let absoluteUntil: Int32
if muteInterval == Int32.max {
absoluteUntil = Int32.max
if let threadId = threadId {
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
let muteState: PeerMuteState
if let muteInterval = muteInterval {
if muteInterval == 0 {
muteState = .unmuted
} else {
let absoluteUntil: Int32
if muteInterval == Int32.max {
absoluteUntil = Int32.max
} else {
absoluteUntil = Int32(Date().timeIntervalSince1970) + muteInterval
}
muteState = .muted(until: absoluteUntil)
}
} else {
absoluteUntil = Int32(Date().timeIntervalSince1970) + muteInterval
muteState = .default
}
muteState = .muted(until: absoluteUntil)
data.notificationSettings = previousSettings.withUpdatedMuteState(muteState)
if let entry = CodableEntry(data) {
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
}
//TODO:loc
let _ = pushPeerNotificationSettings(postbox: account.postbox, network: account.network, peerId: peerId, threadId: threadId, settings: TelegramPeerNotificationSettings.defaultSettings).start()
}
} else {
muteState = .default
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
}
let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings
let previousSettings: TelegramPeerNotificationSettings
if let currentSettings = currentSettings {
previousSettings = currentSettings
} else {
previousSettings = TelegramPeerNotificationSettings.defaultSettings
}
let muteState: PeerMuteState
if let muteInterval = muteInterval {
if muteInterval == 0 {
muteState = .unmuted
} else {
let absoluteUntil: Int32
if muteInterval == Int32.max {
absoluteUntil = Int32.max
} else {
absoluteUntil = Int32(Date().timeIntervalSince1970) + muteInterval
}
muteState = .muted(until: absoluteUntil)
}
} else {
muteState = .default
}
let updatedSettings = previousSettings.withUpdatedMuteState(muteState)
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings)
}
let updatedSettings = previousSettings.withUpdatedMuteState(muteState)
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings)
}
}
func _internal_updatePeerDisplayPreviewsSetting(account: Account, peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
func _internal_updatePeerDisplayPreviewsSetting(account: Account, peerId: PeerId, threadId: Int64?, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
return account.postbox.transaction { transaction -> Void in
updatePeerDisplayPreviewsSetting(transaction: transaction, peerId: peerId, displayPreviews: displayPreviews)
_internal_updatePeerDisplayPreviewsSetting(account: account, transaction: transaction, peerId: peerId, threadId: threadId, displayPreviews: displayPreviews)
}
}
func updatePeerDisplayPreviewsSetting(transaction: Transaction, peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) {
func _internal_updatePeerDisplayPreviewsSetting(account: Account, transaction: Transaction, peerId: PeerId, threadId: Int64?, displayPreviews: PeerNotificationDisplayPreviews) {
if let peer = transaction.getPeer(peerId) {
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
}
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
let previousSettings: TelegramPeerNotificationSettings
if let currentSettings = currentSettings {
previousSettings = currentSettings
if let threadId = threadId {
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
data.notificationSettings = previousSettings.withUpdatedDisplayPreviews(displayPreviews)
if let entry = CodableEntry(data) {
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
}
//TODO:loc
let _ = pushPeerNotificationSettings(postbox: account.postbox, network: account.network, peerId: peerId, threadId: threadId, settings: TelegramPeerNotificationSettings.defaultSettings).start()
}
} else {
previousSettings = TelegramPeerNotificationSettings.defaultSettings
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
}
let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings
let previousSettings: TelegramPeerNotificationSettings
if let currentSettings = currentSettings {
previousSettings = currentSettings
} else {
previousSettings = TelegramPeerNotificationSettings.defaultSettings
}
let updatedSettings = previousSettings.withUpdatedDisplayPreviews(displayPreviews)
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings)
}
let updatedSettings = previousSettings.withUpdatedDisplayPreviews(displayPreviews)
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings)
}
}
func _internal_updatePeerNotificationSoundInteractive(account: Account, peerId: PeerId, sound: PeerMessageSound) -> Signal<Void, NoError> {
func _internal_updatePeerNotificationSoundInteractive(account: Account, peerId: PeerId, threadId: Int64?, sound: PeerMessageSound) -> Signal<Void, NoError> {
return account.postbox.transaction { transaction -> Void in
updatePeerNotificationSoundInteractive(transaction: transaction, peerId: peerId, sound: sound)
_internal_updatePeerNotificationSoundInteractive(account: account, transaction: transaction, peerId: peerId, threadId: threadId, sound: sound)
}
}
func updatePeerNotificationSoundInteractive(transaction: Transaction, peerId: PeerId, sound: PeerMessageSound) {
func _internal_updatePeerNotificationSoundInteractive(account: Account, transaction: Transaction, peerId: PeerId, threadId: Int64?, sound: PeerMessageSound) {
if let peer = transaction.getPeer(peerId) {
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
}
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
let previousSettings: TelegramPeerNotificationSettings
if let currentSettings = currentSettings {
previousSettings = currentSettings
if let threadId = threadId {
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
data.notificationSettings = previousSettings.withUpdatedMessageSound(sound)
if let entry = CodableEntry(data) {
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
}
//TODO:loc
let _ = pushPeerNotificationSettings(postbox: account.postbox, network: account.network, peerId: peerId, threadId: threadId, settings: TelegramPeerNotificationSettings.defaultSettings).start()
}
} else {
previousSettings = TelegramPeerNotificationSettings.defaultSettings
var notificationPeerId = peerId
if let associatedPeerId = peer.associatedPeerId {
notificationPeerId = associatedPeerId
}
let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings
let previousSettings: TelegramPeerNotificationSettings
if let currentSettings = currentSettings {
previousSettings = currentSettings
} else {
previousSettings = TelegramPeerNotificationSettings.defaultSettings
}
let updatedSettings = previousSettings.withUpdatedMessageSound(sound)
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings)
}
let updatedSettings = previousSettings.withUpdatedMessageSound(sound)
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings)
}
}

View File

@ -710,8 +710,8 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox,
transaction.resetIncomingReadStates([peerId: [Namespaces.Message.Cloud: .idBased(maxIncomingReadId: readInboxMaxId, maxOutgoingReadId: readOutboxMaxId, maxKnownId: topMessage, count: unreadCount, markedUnread: false)]])
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
if let pts = pts {
if transaction.getPeerChatState(peerId) == nil {

View File

@ -73,7 +73,7 @@ func _internal_joinChannel(account: Account, peerId: PeerId, hash: String?) -> S
}
if let channel = transaction.getPeer(peerId) as? TelegramChannel, case .broadcast = channel.info {
let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings ?? TelegramPeerNotificationSettings.defaultSettings
let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) as? TelegramPeerNotificationSettings ?? TelegramPeerNotificationSettings.defaultSettings
transaction.updateCurrentPeerNotificationSettings([peerId: notificationSettings.withUpdatedMuteState(.muted(until: Int32.max))])
}

View File

@ -183,28 +183,28 @@ public extension TelegramEngine {
return _internal_reportRepliesMessage(account: self.account, messageId: messageId, deleteMessage: deleteMessage, deleteHistory: deleteHistory, reportSpam: reportSpam)
}
public func togglePeerMuted(peerId: PeerId) -> Signal<Void, NoError> {
return _internal_togglePeerMuted(account: self.account, peerId: peerId)
public func togglePeerMuted(peerId: PeerId, threadId: Int64?) -> Signal<Void, NoError> {
return _internal_togglePeerMuted(account: self.account, peerId: peerId, threadId: threadId)
}
public func updatePeerMuteSetting(peerId: PeerId, muteInterval: Int32?) -> Signal<Void, NoError> {
return _internal_updatePeerMuteSetting(account: self.account, peerId: peerId, muteInterval: muteInterval)
public func updatePeerMuteSetting(peerId: PeerId, threadId: Int64?, muteInterval: Int32?) -> Signal<Void, NoError> {
return _internal_updatePeerMuteSetting(account: self.account, peerId: peerId, threadId: threadId, muteInterval: muteInterval)
}
public func updatePeerDisplayPreviewsSetting(peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
return _internal_updatePeerDisplayPreviewsSetting(account: self.account, peerId: peerId, displayPreviews: displayPreviews)
public func updatePeerDisplayPreviewsSetting(peerId: PeerId, threadId: Int64?, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
return _internal_updatePeerDisplayPreviewsSetting(account: self.account, peerId: peerId, threadId: threadId, displayPreviews: displayPreviews)
}
public func updatePeerNotificationSoundInteractive(peerId: PeerId, sound: PeerMessageSound) -> Signal<Void, NoError> {
return _internal_updatePeerNotificationSoundInteractive(account: self.account, peerId: peerId, sound: sound)
public func updatePeerNotificationSoundInteractive(peerId: PeerId, threadId: Int64?, sound: PeerMessageSound) -> Signal<Void, NoError> {
return _internal_updatePeerNotificationSoundInteractive(account: self.account, peerId: peerId, threadId: threadId, sound: sound)
}
public func removeCustomNotificationSettings(peerIds: [PeerId]) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
for peerId in peerIds {
TelegramCore.updatePeerNotificationSoundInteractive(transaction: transaction, peerId: peerId, sound: .default)
TelegramCore.updatePeerMuteSetting(transaction: transaction, peerId: peerId, muteInterval: nil)
TelegramCore.updatePeerDisplayPreviewsSetting(transaction: transaction, peerId: peerId, displayPreviews: .default)
_internal_updatePeerNotificationSoundInteractive(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, sound: .default)
_internal_updatePeerMuteSetting(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, muteInterval: nil)
_internal_updatePeerDisplayPreviewsSetting(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, displayPreviews: .default)
}
}
|> ignoreValues

View File

@ -71,7 +71,8 @@ public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?,
}
case Namespaces.Peer.CloudChannel:
if let channel = updated as? TelegramChannel {
switch channel.participationStatus {
if case .personal = channel.accessHash {
switch channel.participationStatus {
case .member:
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: channel.creationDate, forceRootGroupIfNotExists: true)
case .left:
@ -80,6 +81,7 @@ public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?,
transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded)
default:
transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded)
}
}
} else {
assertionFailure()

View File

@ -31,7 +31,7 @@ public enum ChatTitleContent {
case replies
}
case peer(peerView: PeerView, customTitle: String?, onlineMemberCount: Int32?, isScheduledMessages: Bool)
case peer(peerView: PeerView, customTitle: String?, onlineMemberCount: Int32?, isScheduledMessages: Bool, isMuted: Bool?)
case replyThread(type: ReplyThreadType, count: Int)
case custom(String, String?, Bool)
}
@ -123,7 +123,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
var titleCredibilityIcon: ChatTitleCredibilityIcon = .none
var isEnabled = true
switch titleContent {
case let .peer(peerView, customTitle, _, isScheduledMessages):
case let .peer(peerView, customTitle, _, isScheduledMessages, isMuted):
if peerView.peerId.isReplies {
let typeText: String = self.strings.DialogList_Replies
segments = [.text(0, NSAttributedString(string: typeText, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))]
@ -166,10 +166,16 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
titleLeftIcon = .lock
}
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
if titleCredibilityIcon != .verified {
titleRightIcon = .mute
if let isMuted {
if isMuted {
titleRightIcon = .mute
}
} else {
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
if titleCredibilityIcon != .verified {
titleRightIcon = .mute
}
}
}
}
@ -313,7 +319,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
var inputActivitiesAllowed = true
if let titleContent = self.titleContent {
switch titleContent {
case let .peer(peerView, _, _, isScheduledMessages):
case let .peer(peerView, _, _, isScheduledMessages, _):
if let peer = peerViewMainPeer(peerView) {
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies {
inputActivitiesAllowed = false
@ -414,7 +420,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
} else {
if let titleContent = self.titleContent {
switch titleContent {
case let .peer(peerView, _, onlineMemberCount, isScheduledMessages):
case let .peer(peerView, _, onlineMemberCount, isScheduledMessages, _):
if let peer = peerViewMainPeer(peerView) {
let servicePeer = isServicePeer(peer)
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies {

View File

@ -342,10 +342,14 @@ public final class AccountContextImpl: AccountContext {
public func chatLocationInput(for location: ChatLocation, contextHolder: Atomic<ChatLocationContextHolder?>) -> ChatLocationInput {
switch location {
case let .peer(peerId):
return .peer(peerId: peerId)
return .peer(peerId: peerId, threadId: nil)
case let .replyThread(data):
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return .thread(peerId: data.messageId.peerId, threadId: makeMessageThreadId(data.messageId), data: context.state)
if data.isForumPost {
return .peer(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
} else {
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return .thread(peerId: data.messageId.peerId, threadId: makeMessageThreadId(data.messageId), data: context.state)
}
case let .feed(id):
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
return .feed(id: id, data: context.state)
@ -357,8 +361,20 @@ public final class AccountContextImpl: AccountContext {
case .peer:
return .single(nil)
case let .replyThread(data):
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return context.maxReadOutgoingMessageId
if data.isForumPost, let peerId = location.peerId {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
return self.account.postbox.combinedView(keys: [viewKey])
|> map { views -> MessageId? in
if let threadInfo = views.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.get(MessageHistoryThreadData.self) {
return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: data.maxOutgoingReadId)
} else {
return nil
}
}
} else {
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return context.maxReadOutgoingMessageId
}
case let .feed(id):
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
return context.maxReadOutgoingMessageId
@ -372,18 +388,30 @@ public final class AccountContextImpl: AccountContext {
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(peerId)) {
unreadCount = count
}
}
return Int(unreadCount)
}
case let .replyThread(data):
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return context.unreadCount
if data.isForumPost {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
return self.account.postbox.combinedView(keys: [viewKey])
|> map { views -> Int in
if let threadInfo = views.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.get(MessageHistoryThreadData.self) {
return Int(data.incomingUnreadCount)
} else {
return 0
}
}
} else {
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return context.unreadCount
}
case let .feed(id):
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
return context.unreadCount

View File

@ -252,7 +252,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
break
case .muteNotifications, .unmuteNotifications:
if let context = self.context, let presentationInterfaceState = self.presentationInterfaceState, let peer = presentationInterfaceState.renderedPeer?.peer {
self.actionDisposable.set(context.engine.peers.togglePeerMuted(peerId: peer.id).start())
self.actionDisposable.set(context.engine.peers.togglePeerMuted(peerId: peer.id, threadId: nil).start())
}
case .hidePinnedMessages, .unpinMessages:
self.interfaceInteraction?.unpinAllMessages()

View File

@ -4384,7 +4384,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if case .pinnedMessages = presentationInterfaceState.subject {
strongSelf.chatTitleView?.titleContent = .custom(presentationInterfaceState.strings.Chat_TitlePinnedMessages(Int32(displayedCount ?? 1)), nil, false)
} else {
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages)
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil)
let imageOverride: AvatarNodeImageOverride?
if strongSelf.context.account.peerId == peer.id {
imageOverride = .savedMessagesIcon
@ -4741,18 +4741,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let peerView = context.account.viewTracker.peerView(peerId)
let messageAndTopic = messagePromise.get()
|> mapToSignal { message -> Signal<(message: Message?, threadInfo: EngineMessageHistoryThread.Info?), NoError> in
|> mapToSignal { message -> Signal<(message: Message?, threadData: MessageHistoryThreadData?), NoError> in
guard let message = message else {
return .single((nil, nil))
}
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: Int64(message.id.id))
return context.account.postbox.combinedView(keys: [viewKey])
|> map { views -> (message: Message?, threadInfo: EngineMessageHistoryThread.Info?) in
|> map { views -> (message: Message?, threadData: MessageHistoryThreadData?) in
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
return (message, nil)
}
return (message, view.info?.get(MessageHistoryThreadData.self)?.info)
return (message, view.info?.get(MessageHistoryThreadData.self))
}
}
@ -4809,8 +4809,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
if let threadInfo = messageAndTopic.threadInfo {
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: threadInfo.title, onlineMemberCount: onlineMemberCount, isScheduledMessages: false)
var peerIsMuted = false
if let threadData = messageAndTopic.threadData {
if case let .muted(until) = threadData.notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
peerIsMuted = true
}
} else if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
peerIsMuted = true
}
}
if let threadInfo = messageAndTopic.threadData?.info {
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: threadInfo.title, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: peerIsMuted)
let avatarContent: EmojiStatusComponent.Content
if let fileId = threadInfo.icon {
@ -4829,12 +4840,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if strongSelf.isNodeLoaded {
strongSelf.chatDisplayNode.peerView = peerView
}
var peerIsMuted = false
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
peerIsMuted = true
}
}
var peerDiscussionId: PeerId?
var peerGeoLocation: PeerGeoLocation?
var currentSendAsPeerId: PeerId?
@ -6813,8 +6819,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
self.chatDisplayNode.navigateButtons.mentionsPressed = { [weak self] in
if let strongSelf = self, strongSelf.isNodeLoaded, case let .peer(peerId) = strongSelf.chatLocation {
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalMentionMessage(peerId: peerId)
if let strongSelf = self, strongSelf.isNodeLoaded, let peerId = strongSelf.chatLocation.peerId {
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalMentionMessage(peerId: peerId, threadId: strongSelf.chatLocation.threadId)
strongSelf.navigationActionDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
if let strongSelf = self {
switch result {
@ -6850,10 +6856,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
action: { _, f in
f(.dismissWithoutContent)
guard let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation else {
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId else {
return
}
let _ = clearPeerUnseenPersonalMessagesInteractively(account: strongSelf.context.account, peerId: peerId).start()
let _ = clearPeerUnseenPersonalMessagesInteractively(account: strongSelf.context.account, peerId: peerId, threadId: strongSelf.chatLocation.threadId).start()
}
)))
let items = ContextController.Items(content: .list(menuItems))
@ -6870,8 +6876,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
self.chatDisplayNode.navigateButtons.reactionsPressed = { [weak self] in
if let strongSelf = self, strongSelf.isNodeLoaded, case let .peer(peerId) = strongSelf.chatLocation {
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalReactionMessage(peerId: peerId)
if let strongSelf = self, strongSelf.isNodeLoaded, let peerId = strongSelf.chatLocation.peerId {
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalReactionMessage(peerId: peerId, threadId: strongSelf.chatLocation.threadId)
strongSelf.navigationActionDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
if let strongSelf = self {
switch result {
@ -7017,10 +7023,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
action: { _, f in
f(.dismissWithoutContent)
guard let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation else {
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId else {
return
}
let _ = clearPeerUnseenReactionsInteractively(account: strongSelf.context.account, peerId: peerId).start()
let _ = clearPeerUnseenReactionsInteractively(account: strongSelf.context.account, peerId: peerId, threadId: strongSelf.chatLocation.threadId).start()
}
)))
let items = ContextController.Items(content: .list(menuItems))
@ -7851,7 +7857,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self?.navigationButtonAction(.openChatInfo(expandAvatar: false))
}, togglePeerNotifications: { [weak self] in
if let strongSelf = self, let peerId = strongSelf.chatLocation.peerId {
let _ = strongSelf.context.engine.peers.togglePeerMuted(peerId: peerId).start()
let _ = strongSelf.context.engine.peers.togglePeerMuted(peerId: peerId, threadId: strongSelf.chatLocation.threadId).start()
}
}, sendContextResult: { [weak self] results, result, node, rect in
guard let strongSelf = self else {
@ -9360,7 +9366,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
})
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesAndReactionCount(peerId: peerId) |> deliverOnMainQueue).start(next: { [weak self] mentionCount, reactionCount in
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesAndReactionCount(peerId: peerId, threadId: nil) |> deliverOnMainQueue).start(next: { [weak self] mentionCount, reactionCount in
if let strongSelf = self {
if case let .standard(previewing) = strongSelf.presentationInterfaceState.mode, previewing {
strongSelf.chatDisplayNode.navigateButtons.mentionCount = 0
strongSelf.chatDisplayNode.navigateButtons.reactionsCount = 0
} else {
strongSelf.chatDisplayNode.navigateButtons.mentionCount = mentionCount
strongSelf.chatDisplayNode.navigateButtons.reactionsCount = reactionCount
}
}
})
} else if let peerId = self.chatLocation.peerId, let threadId = self.chatLocation.threadId {
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesAndReactionCount(peerId: peerId, threadId: threadId) |> deliverOnMainQueue).start(next: { [weak self] mentionCount, reactionCount in
if let strongSelf = self {
if case let .standard(previewing) = strongSelf.presentationInterfaceState.mode, previewing {
strongSelf.chatDisplayNode.navigateButtons.mentionCount = 0

View File

@ -86,6 +86,14 @@ func chatHistoryEntriesForView(
continue
}
if case let .replyThread(replyThreadMessage) = location, replyThreadMessage.isForumPost {
for media in message.media {
if let action = media as? TelegramMediaAction, case .topicCreated = action.action {
continue loop
}
}
}
if let maybeJoinMessage = joinMessage {
if message.timestamp > maybeJoinMessage.timestamp, (!view.holeEarlier || count > 0) {
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))

View File

@ -127,7 +127,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
return true
}
init(context: AccountContext, peerId: PeerId, tagMask: MessageTags, interfaceInteraction: ChatControllerInteraction) {
init(context: AccountContext, peerId: PeerId, threadId: Int64?, tagMask: MessageTags, interfaceInteraction: ChatControllerInteraction) {
self.context = context
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -174,7 +174,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
if let strongSelf = self {
let signal: Signal<([ChatHistorySearchEntry], [MessageId: Message])?, NoError>
if let query = query, !query.isEmpty {
let foundRemoteMessages: Signal<[Message], NoError> = context.engine.messages.searchMessages(location: .peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: nil, minDate: nil, maxDate: nil), query: query, state: nil)
let foundRemoteMessages: Signal<[Message], NoError> = context.engine.messages.searchMessages(location: .peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: threadId.flatMap { makeThreadIdMessageId(peerId: peerId, threadId: $0) }, minDate: nil, maxDate: nil), query: query, state: nil)
|> map { $0.0.messages }
|> delay(0.2, queue: Queue.concurrentDefaultQueue())

View File

@ -229,6 +229,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
}, setPeerIdWithRevealedOptions: { _, _ in
}, setItemPinned: { _, _ in
}, setPeerMuted: { _, _ in
}, setPeerThreadMuted: { _, _, _ in
}, deletePeer: { _, _ in
}, deletePeerThread: { _, _ in
}, updatePeerGrouping: { _, _ in

View File

@ -147,7 +147,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
}
self.statusPromise.set(context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: tagMask)
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: chatLocation.threadId, tag: tagMask)
)
|> map { count -> PeerInfoStatusData? in
let count: Int = count ?? 0

View File

@ -2031,7 +2031,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
}
return context.engine.data.subscribe(EngineDataMap(
summaries.map { TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: $0) }
summaries.map { TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: chatLocation.threadId, tag: $0) }
))
|> map { summaries -> (ContentType, [MessageTags: Int32]) in
var result: [MessageTags: Int32] = [:]

View File

@ -187,7 +187,7 @@ final class PeerInfoScreenData {
let invitations: PeerExportedInvitationsState?
let requests: PeerInvitationImportersState?
let requestsContext: PeerInvitationImportersContext?
let threadInfo: EngineMessageHistoryThread.Info?
let threadData: MessageHistoryThreadData?
init(
peer: Peer?,
@ -206,7 +206,7 @@ final class PeerInfoScreenData {
invitations: PeerExportedInvitationsState?,
requests: PeerInvitationImportersState?,
requestsContext: PeerInvitationImportersContext?,
threadInfo: EngineMessageHistoryThread.Info?
threadData: MessageHistoryThreadData?
) {
self.peer = peer
self.chatPeer = chatPeer
@ -224,7 +224,7 @@ final class PeerInfoScreenData {
self.invitations = invitations
self.requests = requests
self.requestsContext = requestsContext
self.threadInfo = threadInfo
self.threadData = threadData
}
}
@ -477,7 +477,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
invitations: nil,
requests: nil,
requestsContext: nil,
threadInfo: nil
threadData: nil
)
}
}
@ -504,7 +504,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
invitations: nil,
requests: nil,
requestsContext: nil,
threadInfo: nil
threadData: nil
))
case let .user(userPeerId, secretChatId, kind):
let groupsInCommon: GroupsInCommonContext?
@ -635,7 +635,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
invitations: nil,
requests: nil,
requestsContext: nil,
threadInfo: nil
threadData: nil
)
}
case .channel:
@ -711,7 +711,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
invitations: invitations,
requests: requests,
requestsContext: currentRequestsContext,
threadInfo: nil
threadData: nil
)
}
case let .group(groupId):
@ -815,19 +815,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
let requestsContextPromise = Promise<PeerInvitationImportersContext?>(nil)
let requestsStatePromise = Promise<PeerInvitationImportersState?>(nil)
let threadInfo: Signal<EngineMessageHistoryThread.Info?, NoError>
let threadData: Signal<MessageHistoryThreadData?, NoError>
if case let .replyThread(message) = chatLocation {
let threadId = Int64(message.messageId.id)
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
threadInfo = context.account.postbox.combinedView(keys: [viewKey])
|> map { views -> EngineMessageHistoryThread.Info? in
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?.get(MessageHistoryThreadData.self)?.info
return view.info?.get(MessageHistoryThreadData.self)
}
} else {
threadInfo = .single(nil)
threadData = .single(nil)
}
return combineLatest(queue: .mainQueue(),
@ -840,9 +840,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
invitationsStatePromise.get(),
requestsContextPromise.get(),
requestsStatePromise.get(),
threadInfo
threadData
)
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadInfo -> PeerInfoScreenData in
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadData -> PeerInfoScreenData in
var discussionPeer: Peer?
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
discussionPeer = peer
@ -882,13 +882,20 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
requestsStatePromise.set(requestsContext.state |> map(Optional.init))
}
}
var notificationSettings: TelegramPeerNotificationSettings?
if let threadData = threadData {
notificationSettings = threadData.notificationSettings
} else {
notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings
}
return PeerInfoScreenData(
peer: peerView.peers[groupId],
chatPeer: peerView.peers[groupId],
cachedData: peerView.cachedData,
status: status,
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
notificationSettings: notificationSettings,
globalNotificationSettings: globalNotificationSettings,
isContact: peerView.peerIsContact,
availablePanes: availablePanes ?? [],
@ -900,20 +907,29 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
invitations: invitations,
requests: requests,
requestsContext: currentRequestsContext,
threadInfo: threadInfo
threadData: threadData
)
}
}
}
}
func canEditPeerInfo(context: AccountContext, peer: Peer?) -> Bool {
func canEditPeerInfo(context: AccountContext, peer: Peer?, threadData: MessageHistoryThreadData?) -> Bool {
if context.account.peerId == peer?.id {
return true
}
if let channel = peer as? TelegramChannel {
if channel.hasPermission(.changeInfo) {
return true
if let threadData = threadData {
if channel.hasPermission(.pinMessages) {
return true
}
if threadData.author == context.account.peerId {
return true
}
} else {
if channel.hasPermission(.changeInfo) {
return true
}
}
} else if let group = peer as? TelegramGroup {
switch group.role {

View File

@ -634,7 +634,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
transition.updateAlpha(node: self, alpha: 1.0 - fraction)
}
func update(peer: Peer?, item: PeerInfoAvatarListItem?, updatingAvatar: PeerInfoUpdatingAvatar?, uploadProgress: CGFloat?, theme: PresentationTheme, avatarSize: CGFloat, isEditing: Bool) {
func update(peer: Peer?, threadData: MessageHistoryThreadData?, item: PeerInfoAvatarListItem?, updatingAvatar: PeerInfoUpdatingAvatar?, uploadProgress: CGFloat?, theme: PresentationTheme, avatarSize: CGFloat, isEditing: Bool) {
guard let peer = peer else {
return
}
@ -644,7 +644,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .linear)
if canEditPeerInfo(context: self.context, peer: peer) {
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
var overlayHidden = true
if let updatingAvatar = updatingAvatar {
overlayHidden = false
@ -730,12 +730,12 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode {
}
var removedPhotoResourceIds = Set<String>()
func update(peer: Peer?, item: PeerInfoAvatarListItem?, updatingAvatar: PeerInfoUpdatingAvatar?, uploadProgress: CGFloat?, theme: PresentationTheme, avatarSize: CGFloat, isEditing: Bool) {
func update(peer: Peer?, threadData: MessageHistoryThreadData?, item: PeerInfoAvatarListItem?, updatingAvatar: PeerInfoUpdatingAvatar?, uploadProgress: CGFloat?, theme: PresentationTheme, avatarSize: CGFloat, isEditing: Bool) {
guard let peer = peer else {
return
}
let canEdit = canEditPeerInfo(context: self.context, peer: peer)
let canEdit = canEditPeerInfo(context: self.context, peer: peer, threadData: threadData)
let previousItem = self.item
var item = item
@ -1906,14 +1906,14 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
self.itemNodes[key]?.layer.addShakeAnimation()
}
func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, peer: Peer?, cachedData: CachedPeerData?, isContact: Bool, isSettings: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat {
func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, peer: Peer?, threadData: MessageHistoryThreadData?, cachedData: CachedPeerData?, isContact: Bool, isSettings: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat {
let avatarSize: CGFloat = isModalOverlay ? 200.0 : 100.0
let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 13.0), size: CGSize(width: avatarSize, height: avatarSize))
transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize()))
var contentHeight: CGFloat = statusBarHeight + 10.0 + avatarSize + 20.0
if canEditPeerInfo(context: self.context, peer: peer) {
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
if self.avatarButtonNode.supernode == nil {
self.addSubnode(self.avatarButtonNode)
}
@ -1936,12 +1936,12 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
}
} else if let _ = peer as? TelegramGroup {
fieldKeys.append(.title)
if canEditPeerInfo(context: self.context, peer: peer) {
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
fieldKeys.append(.description)
}
} else if let _ = peer as? TelegramChannel {
fieldKeys.append(.title)
if canEditPeerInfo(context: self.context, peer: peer) {
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
fieldKeys.append(.description)
}
}
@ -1995,10 +1995,10 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
} else {
placeholder = presentationData.strings.GroupInfo_GroupNamePlaceholder
}
isEnabled = canEditPeerInfo(context: self.context, peer: peer)
isEnabled = canEditPeerInfo(context: self.context, peer: peer, threadData: threadData)
case .description:
placeholder = presentationData.strings.Channel_Edit_AboutItem
isEnabled = canEditPeerInfo(context: self.context, peer: peer)
isEnabled = canEditPeerInfo(context: self.context, peer: peer, threadData: threadData)
}
let itemHeight = itemNode.update(width: width, safeInset: safeInset, isSettings: isSettings, hasPrevious: hasPrevious, hasNext: key != fieldKeys.last, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText)
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)))
@ -2029,6 +2029,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
private var presentationData: PresentationData?
private var state: PeerInfoState?
private var peer: Peer?
private var threadData: MessageHistoryThreadData?
private var avatarSize: CGFloat?
private let isOpenedFromChat: Bool
@ -2225,7 +2226,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
guard let strongSelf = self, let state = strongSelf.state, let peer = strongSelf.peer, let presentationData = strongSelf.presentationData, let avatarSize = strongSelf.avatarSize else {
return
}
strongSelf.editingContentNode.avatarNode.update(peer: peer, item: strongSelf.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
strongSelf.editingContentNode.avatarNode.update(peer: peer, threadData: strongSelf.threadData, item: strongSelf.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
}
self.avatarListNode.animateOverlaysFadeIn = { [weak self] in
@ -2344,9 +2345,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
private var currentCredibilityIcon: CredibilityIcon?
private var currentPanelStatusData: PeerInfoStatusData?
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadInfo: EngineMessageHistoryThread.Info?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
self.state = state
self.peer = peer
self.threadData = threadData
self.avatarListNode.listContainerNode.peer = peer
let previousPanelStatusData = self.currentPanelStatusData
@ -2503,7 +2505,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.buttonsContainerNode.alpha = self.regularContentNode.alpha
self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0
let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, isModalOverlay: isModalOverlay, peer: state.isEditing ? peer : nil, cachedData: cachedData, isContact: isContact, isSettings: isSettings, presentationData: presentationData, transition: transition)
let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, isModalOverlay: isModalOverlay, peer: state.isEditing ? peer : nil, threadData: threadData, cachedData: cachedData, isContact: isContact, isSettings: isSettings, presentationData: presentationData, transition: transition)
transition.updateFrame(node: self.editingContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -contentOffset), size: CGSize(width: width, height: editingContentHeight)))
let avatarOverlayFarme = self.editingContentNode.convert(self.editingContentNode.avatarNode.frame, to: self)
@ -2567,7 +2569,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadInfo)
let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadData?.info)
var isPremium = false
var isVerified = false
@ -2591,8 +2593,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
title = presentationData.strings.Conversation_SavedMessages
} else if peer.id == self.context.account.peerId && !self.isSettings {
title = presentationData.strings.DialogList_Replies
} else if let threadInfo = threadInfo {
title = threadInfo.title
} else if let threadData = threadData {
title = threadData.info.title
} else {
title = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
}
@ -2619,7 +2621,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
smallSubtitleString = NSAttributedString(string: subtitle, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))
subtitleString = NSAttributedString(string: subtitle, font: Font.regular(17.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
} else if let _ = threadInfo {
} else if let _ = threadData {
let subtitleColor: UIColor = presentationData.theme.list.itemSecondaryTextColor
//TODO:localize
@ -2909,9 +2911,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
})
}
self.avatarListNode.update(size: CGSize(), avatarSize: avatarSize, isExpanded: self.isAvatarExpanded, peer: peer, threadInfo: threadInfo, theme: presentationData.theme, transition: transition)
self.editingContentNode.avatarNode.update(peer: peer, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
self.avatarOverlayNode.update(peer: peer, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
self.avatarListNode.update(size: CGSize(), avatarSize: avatarSize, isExpanded: self.isAvatarExpanded, peer: peer, threadInfo: threadData?.info, theme: presentationData.theme, transition: transition)
self.editingContentNode.avatarNode.update(peer: peer, threadData: threadData, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
self.avatarOverlayNode.update(peer: peer, threadData: threadData, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
if additive {
transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale)
transition.updateSublayerTransformScaleAdditive(node: self.avatarOverlayNode, scale: avatarScale)

View File

@ -1078,7 +1078,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
let ItemMembers = 6
let ItemMemberRequests = 7
if let _ = data.threadInfo {
if let _ = data.threadData {
let mainUsername: String
if let addressName = channel.addressName {
mainUsername = addressName
@ -1599,7 +1599,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
}
}
if cachedData.flags.contains(.canSetStickerSet) && canEditPeerInfo(context: context, peer: channel) {
if cachedData.flags.contains(.canSetStickerSet) && canEditPeerInfo(context: context, peer: channel, threadData: data.threadData) {
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemStickerPack, label: .text(cachedData.stickerPack?.title ?? presentationData.strings.GroupInfo_SharedMediaNone), text: presentationData.strings.Stickers_GroupStickers, icon: UIImage(bundleImageName: "Settings/Menu/Stickers"), action: {
interaction.editingOpenStickerPackSetup()
}))
@ -2817,7 +2817,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
case .edit:
if case let .replyThread(message) = strongSelf.chatLocation {
let threadId = Int64(message.messageId.id)
if let threadInfo = strongSelf.data?.threadInfo {
if let threadInfo = strongSelf.data?.threadData?.info {
let controller = ForumCreateTopicScreen(context: strongSelf.context, peerId: strongSelf.peerId, mode: .edit(topic: threadInfo))
controller.navigationPresentation = .modal
let context = strongSelf.context
@ -2990,7 +2990,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
} else {
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
}
} else if let group = data.peer as? TelegramGroup, canEditPeerInfo(context: strongSelf.context, peer: group) {
} else if let group = data.peer as? TelegramGroup, canEditPeerInfo(context: strongSelf.context, peer: group, threadData: data.threadData) {
let title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? ""
let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? ""
@ -3049,7 +3049,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
}))
}
} else if let channel = data.peer as? TelegramChannel, canEditPeerInfo(context: strongSelf.context, peer: channel) {
} else if let channel = data.peer as? TelegramChannel, canEditPeerInfo(context: strongSelf.context, peer: channel, threadData: data.threadData) {
let title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? ""
let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? ""
@ -3383,7 +3383,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
})
self.refreshMessageTagStatsDisposable = context.engine.messages.refreshMessageTagStats(peerId: peerId, tags: [.video, .photo, .gif, .music, .voiceOrInstantVideo, .webPage, .file]).start()
self.refreshMessageTagStatsDisposable = context.engine.messages.refreshMessageTagStats(peerId: peerId, threadId: chatLocation.threadId, tags: [.video, .photo, .gif, .music, .voiceOrInstantVideo, .webPage, .file]).start()
}
deinit {
@ -3557,7 +3557,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
self.view.endEditing(true)
return self.context.sharedContext.openChatMessage(OpenChatMessageParams(context: self.context, chatLocation: nil, chatLocationContextHolder: nil, message: galleryMessage, standalone: false, reverseMessageGalleryOrder: true, navigationController: navigationController, dismissInput: { [weak self] in
return self.context.sharedContext.openChatMessage(OpenChatMessageParams(context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, message: galleryMessage, standalone: false, reverseMessageGalleryOrder: true, navigationController: navigationController, dismissInput: { [weak self] in
self?.view.endEditing(true)
}, present: { [weak self] c, a in
self?.controller?.present(c, in: .window(.root), with: a, blockInteraction: true)
@ -3919,7 +3919,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
self.requestCall(isVideo: false, gesture: gesture)
case .mute:
if let notificationSettings = self.data?.notificationSettings, case .muted = notificationSettings.muteState {
let _ = self.context.engine.peers.updatePeerMuteSetting(peerId: self.peerId, muteInterval: nil).start()
let _ = self.context.engine.peers.updatePeerMuteSetting(peerId: self.peerId, threadId: self.chatLocation.threadId, muteInterval: nil).start()
let iconColor: UIColor = .white
self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
@ -3968,7 +3968,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: value).start()
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: value).start()
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_mute_for", scale: 0.066, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipMutedFor(mutedForTimeIntervalString(strings: strongSelf.presentationData.strings, value: value)).string), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
@ -4006,7 +4006,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: .default).start()
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, sound: .default).start()
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundEnabled), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
@ -4019,7 +4019,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: .none).start()
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, sound: .none).start()
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundDisabled), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
})))
@ -4033,19 +4033,20 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self, let peer = strongSelf.data?.peer else {
return
}
let threadId = strongSelf.chatLocation.threadId
let context = strongSelf.context
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: sound) |> deliverOnMainQueue
}
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, muteInterval: muteInterval) |> deliverOnMainQueue
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: muteInterval) |> deliverOnMainQueue
}
let updatePeerDisplayPreviews:(PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
let updatePeerDisplayPreviews: (PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
peerId, displayPreviews in
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, displayPreviews: displayPreviews) |> deliverOnMainQueue
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: threadId, displayPreviews: displayPreviews) |> deliverOnMainQueue
}
let mode: NotificationExceptionMode
@ -4063,7 +4064,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
mode = .groups([:])
}
let exceptionController = notificationPeerExceptionController(context: context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, peer: peer, mode: mode, edit: true, updatePeerSound: { peerId, sound in
let exceptionController = notificationPeerExceptionController(context: context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, peer: peer, threadId: threadId, mode: mode, edit: true, updatePeerSound: { peerId, sound in
let _ = (updatePeerSound(peer.id, sound)
|> deliverOnMainQueue).start(next: { _ in
@ -4107,7 +4108,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
return
}
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: Int32.max).start()
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: Int32.max).start()
let iconColor: UIColor = .white
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
@ -4151,8 +4152,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
return .single(items)
}
let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: false, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: data.threadInfo))
let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: true, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: strongSelf.data?.threadInfo))
let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: false, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: data.threadData?.info))
let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: true, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: strongSelf.data?.threadData?.info))
let filteredButtons = allHeaderButtons.subtracting(headerButtons)
@ -4820,9 +4821,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
return
}
if value <= 0 {
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: nil).start()
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: nil).start()
} else {
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: value).start()
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: value).start()
let timeString = stringForPreciseRelativeTimestamp(strings: strongSelf.presentationData.strings, relativeTimestamp: Int32(Date().timeIntervalSince1970) + value, relativeTo: Int32(Date().timeIntervalSince1970), dateTimeFormat: strongSelf.presentationData.dateTimeFormat)
@ -5269,7 +5270,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: sound).start()
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, sound: sound).start()
})
soundController.navigationPresentation = .modal
strongSelf.controller?.push(soundController)
@ -5277,7 +5278,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: value).start()
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: value).start()
})
strongSelf.view.endEditing(true)
strongSelf.controller?.present(muteSettingsController, in: .window(.root))
@ -5298,7 +5299,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: sound).start()
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, sound: sound).start()
})
strongSelf.controller?.push(soundController)
})
@ -5310,7 +5311,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self, let peer = peer else {
return
}
let _ = strongSelf.context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peer.id, displayPreviews: value ? .show : .hide).start()
let _ = strongSelf.context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peer.id, threadId: strongSelf.chatLocation.threadId, displayPreviews: value ? .show : .hide).start()
})
}
@ -6526,7 +6527,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
private func openAvatarForEditing(fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
guard let peer = self.data?.peer, canEditPeerInfo(context: self.context, peer: peer) else {
guard let peer = self.data?.peer, canEditPeerInfo(context: self.context, peer: peer, threadData: self.data?.threadData) else {
return
}
@ -7308,7 +7309,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
}
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, threadId: self.chatLocation.threadId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in
self?.deactivateSearch()
})
}
@ -7364,8 +7365,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
let peerId = self.peerId
let _ = (self.context.engine.data.get(EngineDataMap([
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: .photo),
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: .video)
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: self.chatLocation.threadId, tag: .photo),
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: self.chatLocation.threadId, tag: .video)
]))
|> deliverOnMainQueue).start(next: { [weak self] messageCounts in
guard let strongSelf = self else {
@ -7417,17 +7418,19 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
items.append(.action(generateAction(false)))
var ignoreNextActions = false
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowCalendar, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.contextMenu.primaryColor)
}, action: { _, a in
if ignoreNextActions {
return
}
ignoreNextActions = true
a(.default)
self?.openMediaCalendar()
})))
if strongSelf.chatLocation.threadId == nil {
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowCalendar, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.contextMenu.primaryColor)
}, action: { _, a in
if ignoreNextActions {
return
}
ignoreNextActions = true
a(.default)
self?.openMediaCalendar()
})))
}
if photoCount != 0 && videoCount != 0 {
items.append(.separator)
@ -7665,7 +7668,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
let headerInset = sectionInset
var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadInfo: self.data?.threadInfo, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
if !self.isSettings && !self.state.isEditing {
headerHeight += 71.0
}
@ -8025,7 +8028,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
let headerInset = sectionInset
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadInfo: self.data?.threadInfo, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
}
let paneAreaExpansionDistance: CGFloat = 32.0
@ -9042,7 +9045,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
}
let headerInset = sectionInset
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadInfo: self.screenNode.data?.threadInfo, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, transition: transition, additive: false)
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, transition: transition, additive: false)
}
let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height

View File

@ -880,7 +880,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
animationTimer.start()
self.statusPromise.set(context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: tagMaskForType(self.contentType))
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: chatLocation.threadId, tag: tagMaskForType(self.contentType))
)
|> map { count -> PeerInfoStatusData? in
let count: Int = count ?? 0
@ -925,7 +925,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
return
}
self.isRequestingView = true
self.listDisposable.set((self.context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: self.peerId), index: .upperBound, anchorIndex: .upperBound, count: self.numberOfItemsToRequest, fixedCombinedReadStates: nil, tagMask: tagMaskForType(self.contentType))
self.listDisposable.set((self.context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: self.peerId, threadId: self.chatLocation.threadId), index: .upperBound, anchorIndex: .upperBound, count: self.numberOfItemsToRequest, fixedCombinedReadStates: nil, tagMask: tagMaskForType(self.contentType))
|> deliverOnMainQueue).start(next: { [weak self] (view, updateType, _) in
guard let strongSelf = self else {
return

View File

@ -213,7 +213,7 @@ private final class PrefetchManagerInnerImpl {
context = PrefetchMediaContext()
self.contexts[id] = context
let priority: FetchManagerPriority = .backgroundPrefetch(locationOrder: HistoryPreloadIndex(index: nil, hasUnread: false, isMuted: false, isPriority: true), localOrder: MessageIndex(id: MessageId(peerId: PeerId(0), namespace: 0, id: order), timestamp: 0))
let priority: FetchManagerPriority = .backgroundPrefetch(locationOrder: HistoryPreloadIndex(index: nil, threadId: nil, hasUnread: false, isMuted: false, isPriority: true), localOrder: MessageIndex(id: MessageId(peerId: PeerId(0), namespace: 0, id: order), timestamp: 0))
if case .full = automaticDownload {
let fetchSignal = freeMediaFileInteractiveFetched(fetchManager: self.fetchManager, fileReference: .standalone(media: media), priority: priority)

View File

@ -91,7 +91,7 @@ final class WatchChatMessagesHandler: WatchRequestHandler {
|> take(1)
|> mapToSignal({ context -> Signal<(MessageHistoryView, Bool, PresentationData), NoError> in
if let context = context {
return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .upperBound, anchorIndex: .upperBound, count: limit, fixedCombinedReadStates: nil)
return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: limit, fixedCombinedReadStates: nil)
|> map { messageHistoryView, _, _ -> (MessageHistoryView, Bool, PresentationData) in
return (messageHistoryView, peerId == context.account.peerId, context.sharedContext.currentPresentationData.with { $0 })
}
@ -833,7 +833,7 @@ final class WatchPeerSettingsHandler: WatchRequestHandler {
var signal: Signal<Void, NoError>?
if let args = subscription as? TGBridgePeerUpdateNotificationSettingsSubscription, let peerId = makePeerIdFromBridgeIdentifier(args.peerId) {
signal = context.engine.peers.togglePeerMuted(peerId: peerId)
signal = context.engine.peers.togglePeerMuted(peerId: peerId, threadId: nil)
} else if let args = subscription as? TGBridgePeerUpdateBlockStatusSubscription, let peerId = makePeerIdFromBridgeIdentifier(args.peerId) {
signal = context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peerId, isBlocked: args.blocked)
}