mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-06 17:00:13 +00:00
[WIP] Topics
This commit is contained in:
parent
9a08911483
commit
db4b73ae6b
@ -49,7 +49,7 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !isMuted && hasUnread {
|
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)
|
|> take(1)
|
||||||
|> map { view -> [INMessage] in
|
|> map { view -> [INMessage] in
|
||||||
var messages: [INMessage] = []
|
var messages: [INMessage] = []
|
||||||
|
|||||||
@ -8114,3 +8114,5 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"ChatList.StartAction" = "Start";
|
"ChatList.StartAction" = "Start";
|
||||||
"ChatList.CloseAction" = "Close";
|
"ChatList.CloseAction" = "Close";
|
||||||
|
|
||||||
|
"Channel.EditAdmin.PermissionCreateTopics" = "Create Topics";
|
||||||
|
|||||||
@ -159,7 +159,7 @@ private func getCommonTimeline(friends: [Friend]?, in context: TimelineProviderC
|
|||||||
|
|
||||||
if let readState = transaction.getCombinedPeerReadState(peer.id), readState.count > 0 {
|
if let readState = transaction.getCombinedPeerReadState(peer.id), readState.count > 0 {
|
||||||
var isMuted = false
|
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)
|
isMuted = notificationSettings.isRemovedFromTotalUnreadCount(default: false)
|
||||||
}
|
}
|
||||||
badge = WidgetDataPeer.Badge(
|
badge = WidgetDataPeer.Badge(
|
||||||
|
|||||||
@ -397,7 +397,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
|||||||
isMuted = true
|
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
|
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: {
|
|> deliverOnMainQueue).start(completed: {
|
||||||
f(.default)
|
f(.default)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -492,7 +492,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
return
|
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))
|
strongSelf.infoReady.set(.single(true))
|
||||||
|
|
||||||
if let channel = peerView.peers[peerView.peerId] as? TelegramChannel, !channel.flags.contains(.isForum) {
|
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?) {
|
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
|
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||||
|
|> deliverOnMainQueue).start(next: { peer in
|
||||||
var items: [ContextMenuItem] = []
|
guard case let .channel(channel) = peer else {
|
||||||
|
|
||||||
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 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let chatController = context.sharedContext.makeChatListController(context: context, location: .forum(peerId: peerId), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false)
|
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
||||||
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 chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peerId), subject: nil, botStart: nil, mode: .standard(previewing: false))
|
var items: [ContextMenuItem] = []
|
||||||
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)
|
|
||||||
|
|
||||||
let _ = (context.engine.data.get(
|
items.append(.action(ContextMenuActionItem(text: "View as Topics", icon: { theme in
|
||||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
if !isViewingAsTopics {
|
||||||
)
|
return nil
|
||||||
|> 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)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||||
})
|
}, action: { [weak sourceController] _, a in
|
||||||
})))
|
a(.default)
|
||||||
|
|
||||||
//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)
|
|
||||||
|
|
||||||
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
|
//TODO:localize
|
||||||
items.append(.action(ContextMenuActionItem(text: "New Topic", icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: "Group Info", icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/CreateGroupActionIcon"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { action in
|
}, action: { [weak sourceController] _, f in
|
||||||
action.dismissWithResult(.default)
|
f(.default)
|
||||||
|
|
||||||
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
|
let _ = (context.engine.data.get(
|
||||||
controller.navigationPresentation = .modal
|
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
||||||
controller.completion = { title, fileId in
|
)
|
||||||
let availableColors: [Int32] = [0x6FB9F0, 0xFFD67E, 0xCB86DB, 0x8EEE98, 0xFF93B2, 0xFB6F5F]
|
|> 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 {
|
||||||
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: availableColors.randomElement()!, iconFileId: fileId)
|
return
|
||||||
|> deliverOnMainQueue).start(next: { topicId in
|
}
|
||||||
if let navigationController = (sourceController.navigationController as? NavigationController) {
|
(sourceController.navigationController as? NavigationController)?.pushViewController(controller)
|
||||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, navigationController: navigationController, activateInput: .text).start()
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sourceController.push(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 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)
|
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)
|
sourceController.presentInGlobalOverlay(contextController)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private var initializedFilters = false
|
private var initializedFilters = false
|
||||||
|
|||||||
@ -183,7 +183,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
|||||||
let timestamp1: Int32 = 100000
|
let timestamp1: Int32 = 100000
|
||||||
let peers: [EnginePeer.Id: EnginePeer] = [:]
|
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
|
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()
|
gesture?.cancel()
|
||||||
}, present: { _ in })
|
}, present: { _ in })
|
||||||
|
|
||||||
|
|||||||
@ -1741,6 +1741,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
}, setPeerIdWithRevealedOptions: { _, _ in
|
}, setPeerIdWithRevealedOptions: { _, _ in
|
||||||
}, setItemPinned: { _, _ in
|
}, setItemPinned: { _, _ in
|
||||||
}, setPeerMuted: { _, _ in
|
}, setPeerMuted: { _, _ in
|
||||||
|
}, setPeerThreadMuted: { _, _, _ in
|
||||||
}, deletePeer: { _, _ in
|
}, deletePeer: { _, _ in
|
||||||
}, deletePeerThread: { _, _ in
|
}, deletePeerThread: { _, _ in
|
||||||
}, updatePeerGrouping: { _, _ in
|
}, updatePeerGrouping: { _, _ in
|
||||||
@ -2952,7 +2953,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
|||||||
var peers: [EnginePeer.Id: EnginePeer] = [:]
|
var peers: [EnginePeer.Id: EnginePeer] = [:]
|
||||||
peers[peer1.id] = peer1
|
peers[peer1.id] = peer1
|
||||||
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
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()
|
gesture?.cancel()
|
||||||
}, present: { _ in })
|
}, present: { _ in })
|
||||||
|
|
||||||
|
|||||||
@ -2688,6 +2688,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
switch option.key {
|
switch option.key {
|
||||||
case RevealOptionKey.delete.rawValue:
|
case RevealOptionKey.delete.rawValue:
|
||||||
item.interaction.deletePeerThread(peerId, threadId)
|
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:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,6 +67,7 @@ public final class ChatListNodeInteraction {
|
|||||||
let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void
|
let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void
|
||||||
let setItemPinned: (EngineChatList.PinnedItem.Id, Bool) -> Void
|
let setItemPinned: (EngineChatList.PinnedItem.Id, Bool) -> Void
|
||||||
let setPeerMuted: (EnginePeer.Id, Bool) -> Void
|
let setPeerMuted: (EnginePeer.Id, Bool) -> Void
|
||||||
|
let setPeerThreadMuted: (EnginePeer.Id, Int64?, Bool) -> Void
|
||||||
let deletePeer: (EnginePeer.Id, Bool) -> Void
|
let deletePeer: (EnginePeer.Id, Bool) -> Void
|
||||||
let deletePeerThread: (EnginePeer.Id, Int64) -> Void
|
let deletePeerThread: (EnginePeer.Id, Int64) -> Void
|
||||||
let updatePeerGrouping: (EnginePeer.Id, Bool) -> Void
|
let updatePeerGrouping: (EnginePeer.Id, Bool) -> Void
|
||||||
@ -98,6 +99,7 @@ public final class ChatListNodeInteraction {
|
|||||||
setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void,
|
setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void,
|
||||||
setItemPinned: @escaping (EngineChatList.PinnedItem.Id, Bool) -> Void,
|
setItemPinned: @escaping (EngineChatList.PinnedItem.Id, Bool) -> Void,
|
||||||
setPeerMuted: @escaping (EnginePeer.Id, Bool) -> Void,
|
setPeerMuted: @escaping (EnginePeer.Id, Bool) -> Void,
|
||||||
|
setPeerThreadMuted: @escaping (EnginePeer.Id, Int64?, Bool) -> Void,
|
||||||
deletePeer: @escaping (EnginePeer.Id, Bool) -> Void,
|
deletePeer: @escaping (EnginePeer.Id, Bool) -> Void,
|
||||||
deletePeerThread: @escaping (EnginePeer.Id, Int64) -> Void,
|
deletePeerThread: @escaping (EnginePeer.Id, Int64) -> Void,
|
||||||
updatePeerGrouping: @escaping (EnginePeer.Id, Bool) -> Void,
|
updatePeerGrouping: @escaping (EnginePeer.Id, Bool) -> Void,
|
||||||
@ -119,6 +121,7 @@ public final class ChatListNodeInteraction {
|
|||||||
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
||||||
self.setItemPinned = setItemPinned
|
self.setItemPinned = setItemPinned
|
||||||
self.setPeerMuted = setPeerMuted
|
self.setPeerMuted = setPeerMuted
|
||||||
|
self.setPeerThreadMuted = setPeerThreadMuted
|
||||||
self.deletePeer = deletePeer
|
self.deletePeer = deletePeer
|
||||||
self.deletePeerThread = deletePeerThread
|
self.deletePeerThread = deletePeerThread
|
||||||
self.updatePeerGrouping = updatePeerGrouping
|
self.updatePeerGrouping = updatePeerGrouping
|
||||||
@ -946,7 +949,7 @@ public final class ChatListNode: ListView {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.setCurrentRemovingPeerId(peerId)
|
strongSelf.setCurrentRemovingPeerId(peerId)
|
||||||
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
|
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId, threadId: nil)
|
||||||
|> deliverOnMainQueue).start(completed: {
|
|> deliverOnMainQueue).start(completed: {
|
||||||
self?.updateState { state in
|
self?.updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
@ -955,6 +958,17 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
self?.setCurrentRemovingPeerId(nil)
|
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
|
}, deletePeer: { [weak self] peerId, joined in
|
||||||
self?.deletePeerChat?(peerId, joined)
|
self?.deletePeerChat?(peerId, joined)
|
||||||
}, deletePeerThread: { [weak self] peerId, threadId in
|
}, deletePeerThread: { [weak self] peerId, threadId in
|
||||||
@ -1799,8 +1813,11 @@ public final class ChatListNode: ListView {
|
|||||||
if let combinedReadState = combinedReadState {
|
if let combinedReadState = combinedReadState {
|
||||||
hasUnread = combinedReadState.count > 0
|
hasUnread = combinedReadState.count > 0
|
||||||
}
|
}
|
||||||
if case let .chatList(index) = index {
|
switch index {
|
||||||
preloadItems.append(ChatHistoryPreloadItem(index: index, isMuted: isMuted, hasUnread: hasUnread))
|
case let .chatList(index):
|
||||||
|
preloadItems.append(ChatHistoryPreloadItem(index: index, threadId: nil, isMuted: isMuted, hasUnread: hasUnread))
|
||||||
|
case .forum:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -166,7 +166,27 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .forum(peerId):
|
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
|
var isFirst = false
|
||||||
return account.postbox.combinedView(keys: [viewKey])
|
return account.postbox.combinedView(keys: [viewKey])
|
||||||
|> map { views -> ChatListNodeViewUpdate in
|
|> map { views -> ChatListNodeViewUpdate in
|
||||||
@ -182,18 +202,41 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
|||||||
guard let data = item.info.get(MessageHistoryThreadData.self) else {
|
guard let data = item.info.get(MessageHistoryThreadData.self) else {
|
||||||
continue
|
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(
|
items.append(EngineChatList.Item(
|
||||||
id: .forum(item.id),
|
id: .forum(item.id),
|
||||||
index: .forum(timestamp: item.index.timestamp, threadId: item.id, namespace: item.index.id.namespace, id: item.index.id.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)] } ?? [],
|
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))])),
|
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,
|
draft: nil,
|
||||||
threadInfo: data.info,
|
threadInfo: data.info,
|
||||||
renderedPeer: EngineRenderedPeer(peer: EnginePeer(peer)),
|
renderedPeer: EngineRenderedPeer(peer: EnginePeer(peer)),
|
||||||
presence: nil,
|
presence: nil,
|
||||||
hasUnseenMentions: false,
|
hasUnseenMentions: hasUnseenMentions,
|
||||||
hasUnseenReactions: false,
|
hasUnseenReactions: hasUnseenReactions,
|
||||||
forumTopicTitle: nil,
|
forumTopicTitle: nil,
|
||||||
hasFailed: false,
|
hasFailed: false,
|
||||||
isContact: false
|
isContact: false
|
||||||
|
|||||||
@ -18,6 +18,17 @@ public extension ChatLocation {
|
|||||||
return nil
|
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 {
|
public enum ChatPresentationInputQueryKind: Int32 {
|
||||||
|
|||||||
@ -76,6 +76,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
|||||||
}, setPeerIdWithRevealedOptions: { _, _ in
|
}, setPeerIdWithRevealedOptions: { _, _ in
|
||||||
}, setItemPinned: { _, _ in
|
}, setItemPinned: { _, _ in
|
||||||
}, setPeerMuted: { _, _ in
|
}, setPeerMuted: { _, _ in
|
||||||
|
}, setPeerThreadMuted: { _, _, _ in
|
||||||
}, deletePeer: { _, _ in
|
}, deletePeer: { _, _ in
|
||||||
}, deletePeerThread: { _, _ in
|
}, deletePeerThread: { _, _ in
|
||||||
}, updatePeerGrouping: { _, _ in
|
}, updatePeerGrouping: { _, _ in
|
||||||
|
|||||||
@ -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) {
|
if right.contains(.canChangeInfo) {
|
||||||
return isGroup ? strings.Group_EditAdmin_PermissionChangeInfo : strings.Channel_EditAdmin_PermissionChangeInfo
|
return isGroup ? strings.Group_EditAdmin_PermissionChangeInfo : strings.Channel_EditAdmin_PermissionChangeInfo
|
||||||
} else if right.contains(.canPostMessages) {
|
} else if right.contains(.canPostMessages) {
|
||||||
@ -438,7 +438,11 @@ private func stringForRight(strings: PresentationStrings, right: TelegramChatAdm
|
|||||||
return strings.Channel_EditAdmin_PermissionInviteSubscribers
|
return strings.Channel_EditAdmin_PermissionInviteSubscribers
|
||||||
}
|
}
|
||||||
} else if right.contains(.canPinMessages) {
|
} 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) {
|
} else if right.contains(.canAddAdmins) {
|
||||||
return strings.Channel_EditAdmin_PermissionAddAdmins
|
return strings.Channel_EditAdmin_PermissionAddAdmins
|
||||||
} else if right.contains(.canBeAnonymous) {
|
} else if right.contains(.canBeAnonymous) {
|
||||||
@ -612,7 +616,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
|||||||
var index = 0
|
var index = 0
|
||||||
for right in rightsOrder {
|
for right in rightsOrder {
|
||||||
if accountUserRightsFlags.contains(right) {
|
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
|
index += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -651,7 +655,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
|||||||
var index = 0
|
var index = 0
|
||||||
for right in rightsOrder {
|
for right in rightsOrder {
|
||||||
if accountUserRightsFlags.contains(right) {
|
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
|
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 {
|
} else if let initialParticipant = initialParticipant, case let .member(_, _, maybeAdminInfo, _, _) = initialParticipant, let adminInfo = maybeAdminInfo {
|
||||||
var index = 0
|
var index = 0
|
||||||
for right in rightsOrder {
|
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
|
index += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -782,7 +786,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
|||||||
var index = 0
|
var index = 0
|
||||||
for right in rightsOrder {
|
for right in rightsOrder {
|
||||||
if accountUserRightsFlags.contains(right) {
|
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
|
index += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -293,7 +293,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
|
|||||||
var index = 0
|
var index = 0
|
||||||
for (right, _) in allGroupPermissionList {
|
for (right, _) in allGroupPermissionList {
|
||||||
let defaultEnabled = !defaultBannedRights.flags.contains(right) && channel.hasPermission(.banMembers)
|
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
|
index += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +339,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
|
|||||||
var index = 0
|
var index = 0
|
||||||
for (right, _) in allGroupPermissionList {
|
for (right, _) in allGroupPermissionList {
|
||||||
let defaultEnabled = !defaultBannedRightsFlags.contains(right)
|
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
|
index += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -336,7 +336,7 @@ private struct ChannelPermissionsControllerState: Equatable {
|
|||||||
var modifiedSlowmodeTimeout: Int32?
|
var modifiedSlowmodeTimeout: Int32?
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatBannedRightsFlags) -> String {
|
func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatBannedRightsFlags, isForum: Bool) -> String {
|
||||||
if right.contains(.banSendMessages) {
|
if right.contains(.banSendMessages) {
|
||||||
return strings.Channel_BanUser_PermissionSendMessages
|
return strings.Channel_BanUser_PermissionSendMessages
|
||||||
} else if right.contains(.banSendMedia) {
|
} else if right.contains(.banSendMedia) {
|
||||||
@ -352,7 +352,11 @@ func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatB
|
|||||||
} else if right.contains(.banAddMembers) {
|
} else if right.contains(.banAddMembers) {
|
||||||
return strings.Channel_BanUser_PermissionAddMembers
|
return strings.Channel_BanUser_PermissionAddMembers
|
||||||
} else if right.contains(.banPinMessages) {
|
} else if right.contains(.banPinMessages) {
|
||||||
return strings.Channel_EditAdmin_PermissionPinMessages
|
if isForum {
|
||||||
|
return strings.Channel_EditAdmin_PermissionCreateTopics
|
||||||
|
} else {
|
||||||
|
return strings.Channel_EditAdmin_PermissionPinMessages
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -442,7 +446,7 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
|
|||||||
if !channel.hasPermission(correspondingAdminRight) {
|
if !channel.hasPermission(correspondingAdminRight) {
|
||||||
enabled = false
|
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
|
rightIndex += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +483,7 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
|
|||||||
entries.append(.permissionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_SectionTitle))
|
entries.append(.permissionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_SectionTitle))
|
||||||
var rightIndex: Int = 0
|
var rightIndex: Int = 0
|
||||||
for (rights, _) in allGroupPermissionList {
|
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
|
rightIndex += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -260,7 +260,7 @@ final class ChatListTable: Table {
|
|||||||
|
|
||||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(messageIndex.id.peerId))
|
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) {
|
if filterPredicate.pinnedPeerIds.contains(peer.id) {
|
||||||
passFilter = true
|
passFilter = true
|
||||||
@ -895,7 +895,7 @@ final class ChatListTable: Table {
|
|||||||
}
|
}
|
||||||
var tagSummary: MessageHistoryTagNamespaceSummary?
|
var tagSummary: MessageHistoryTagNamespaceSummary?
|
||||||
if let summaryTag = summaryTag {
|
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] = []
|
var topMessageAttributes: [MessageAttribute] = []
|
||||||
if let topMessage = topMessage {
|
if let topMessage = topMessage {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ public struct ChatListEntryMessageTagSummaryKey: Hashable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ChatListEntryMessageTagSummaryComponent {
|
public struct ChatListEntryMessageTagSummaryComponent: Equatable {
|
||||||
public let namespace: MessageId.Namespace
|
public let namespace: MessageId.Namespace
|
||||||
|
|
||||||
public init(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 let namespace: MessageId.Namespace
|
||||||
|
|
||||||
public init(namespace: MessageId.Namespace) {
|
public init(namespace: MessageId.Namespace) {
|
||||||
@ -26,8 +26,8 @@ public struct ChatListEntryPendingMessageActionsSummaryComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ChatListEntrySummaryComponents {
|
public struct ChatListEntrySummaryComponents: Equatable {
|
||||||
public struct Component {
|
public struct Component: Equatable {
|
||||||
public let tagSummary: ChatListEntryMessageTagSummaryComponent?
|
public let tagSummary: ChatListEntryMessageTagSummaryComponent?
|
||||||
public let actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent?
|
public let actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent?
|
||||||
|
|
||||||
|
|||||||
@ -63,7 +63,7 @@ private func mappedChatListFilterPredicate(postbox: PostboxImpl, currentTransact
|
|||||||
let notificationsPeerId = peer.notificationSettingsPeerId ?? peer.id
|
let notificationsPeerId = peer.notificationSettingsPeerId ?? peer.id
|
||||||
let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId)
|
let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId)
|
||||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(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) {
|
if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) {
|
||||||
return true
|
return true
|
||||||
@ -402,7 +402,7 @@ private final class ChatListViewSpaceState {
|
|||||||
|
|
||||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId))
|
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) {
|
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
|
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 {
|
if !transaction.currentUpdatedPeerNotificationSettings.isEmpty, case let .group(groupId, pinned, maybeFilterPredicate) = self.space, let filterPredicate = maybeFilterPredicate {
|
||||||
var removeEntryIndices: [MutableChatListEntryIndex] = []
|
var removeEntryIndices: [MutableChatListEntryIndex] = []
|
||||||
let _ = self.orderedEntries.mutableScan { entry in
|
let _ = self.orderedEntries.mutableScan { entry -> MutableChatListEntry? in
|
||||||
let entryPeer: Peer
|
let entryPeer: Peer
|
||||||
let entryNotificationsPeerId: PeerId
|
let entryNotificationsPeerId: PeerId
|
||||||
switch entry {
|
switch entry {
|
||||||
@ -532,7 +532,7 @@ private final class ChatListViewSpaceState {
|
|||||||
|
|
||||||
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: entryPeer, peerSettings: settingsChange.1)
|
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)
|
let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId), messageTagSummaryResult: messageTagSummaryResult)
|
||||||
if !isIncluded {
|
if !isIncluded {
|
||||||
@ -570,7 +570,7 @@ private final class ChatListViewSpaceState {
|
|||||||
|
|
||||||
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: settingsChange.1)
|
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)
|
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 {
|
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 {
|
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] = []
|
var removeEntryIndices: [MutableChatListEntryIndex] = []
|
||||||
let _ = self.orderedEntries.mutableScan { entry in
|
let _ = self.orderedEntries.mutableScan { entry -> MutableChatListEntry? in
|
||||||
let entryPeer: Peer
|
let entryPeer: Peer
|
||||||
let entryNotificationsPeerId: PeerId
|
let entryNotificationsPeerId: PeerId
|
||||||
switch entry {
|
switch entry {
|
||||||
@ -752,7 +752,7 @@ private final class ChatListViewSpaceState {
|
|||||||
return nil
|
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)]
|
let updatedActionsSummary = transaction.currentUpdatedMessageActionsSummaries[PendingMessageActionsSummaryKey(type: filterMessageTagSummary.subtractCount.type, peerId: entryPeer.id, namespace: filterMessageTagSummary.subtractCount.namespace)]
|
||||||
|
|
||||||
if updatedMessageSummary != nil || updatedActionsSummary != nil {
|
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 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)
|
let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId), messageTagSummaryResult: messageTagSummaryResult)
|
||||||
if !isIncluded {
|
if !isIncluded {
|
||||||
@ -813,7 +813,7 @@ private final class ChatListViewSpaceState {
|
|||||||
|
|
||||||
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(mainPeer.id))
|
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)
|
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 {
|
if isIncluded && self.orderedEntries.indicesForPeerId(mainPeer.id) == nil {
|
||||||
@ -852,7 +852,7 @@ private final class ChatListViewSpaceState {
|
|||||||
for (key, component) in self.summaryComponents.components {
|
for (key, component) in self.summaryComponents.components {
|
||||||
var updatedTagSummaryCount: Int32?
|
var updatedTagSummaryCount: Int32?
|
||||||
if let tagSummary = component.tagSummary {
|
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] {
|
if let summary = transaction.currentUpdatedMessageTagSummaries[key] {
|
||||||
updatedTagSummaryCount = summary.count
|
updatedTagSummaryCount = summary.count
|
||||||
}
|
}
|
||||||
@ -1428,7 +1428,7 @@ struct ChatListViewState {
|
|||||||
var actionsSummaryCount: Int32?
|
var actionsSummaryCount: Int32?
|
||||||
|
|
||||||
if let tagSummary = component.tagSummary {
|
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) {
|
if let summary = postbox.messageHistoryTagsSummaryTable.get(key) {
|
||||||
tagSummaryCount = summary.count
|
tagSummaryCount = summary.count
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,12 +2,36 @@ import Foundation
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
|
||||||
public enum ChatLocationInput {
|
public enum ChatLocationInput {
|
||||||
case peer(peerId: PeerId)
|
case peer(peerId: PeerId, threadId: Int64?)
|
||||||
case thread(peerId: PeerId, threadId: Int64, data: Signal<MessageHistoryViewExternalInput, NoError>)
|
case thread(peerId: PeerId, threadId: Int64, data: Signal<MessageHistoryViewExternalInput, NoError>)
|
||||||
case feed(id: Int32, 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 {
|
public enum ResolvedChatLocationInput {
|
||||||
case peer(PeerId)
|
case peer(peerId: PeerId, threadId: Int64?)
|
||||||
case external(MessageHistoryViewExternalInput)
|
case external(MessageHistoryViewExternalInput)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,15 @@ import Foundation
|
|||||||
struct MessageHistoryIndexHoleOperationKey: Hashable {
|
struct MessageHistoryIndexHoleOperationKey: Hashable {
|
||||||
let peerId: PeerId
|
let peerId: PeerId
|
||||||
let namespace: MessageId.Namespace
|
let namespace: MessageId.Namespace
|
||||||
|
let threadId: Int64?
|
||||||
let space: MessageHistoryHoleSpace
|
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 {
|
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]]) {
|
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, space: space)
|
let key = MessageHistoryIndexHoleOperationKey(peerId: peerId, namespace: namespace, threadId: threadId, space: space)
|
||||||
if operations[key] == nil {
|
if operations[key] == nil {
|
||||||
operations[key] = []
|
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))
|
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]]) {
|
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 {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -81,6 +81,7 @@ final class MessageHistoryTable: Table {
|
|||||||
let failedTable: MessageHistoryFailedTable
|
let failedTable: MessageHistoryFailedTable
|
||||||
let tagsTable: MessageHistoryTagsTable
|
let tagsTable: MessageHistoryTagsTable
|
||||||
let threadsTable: MessageHistoryThreadsTable
|
let threadsTable: MessageHistoryThreadsTable
|
||||||
|
let threadTagsTable: MessageHistoryThreadTagsTable
|
||||||
let globalTagsTable: GlobalMessageHistoryTagsTable
|
let globalTagsTable: GlobalMessageHistoryTagsTable
|
||||||
let localTagsTable: LocalMessageHistoryTagsTable
|
let localTagsTable: LocalMessageHistoryTagsTable
|
||||||
let timeBasedAttributesTable: TimestampBasedMessageAttributesTable
|
let timeBasedAttributesTable: TimestampBasedMessageAttributesTable
|
||||||
@ -90,7 +91,7 @@ final class MessageHistoryTable: Table {
|
|||||||
let summaryTable: MessageHistoryTagsSummaryTable
|
let summaryTable: MessageHistoryTagsSummaryTable
|
||||||
let pendingActionsTable: PendingMessageActionsTable
|
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.seedConfiguration = seedConfiguration
|
||||||
self.messageHistoryIndexTable = messageHistoryIndexTable
|
self.messageHistoryIndexTable = messageHistoryIndexTable
|
||||||
self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable
|
self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable
|
||||||
@ -101,6 +102,7 @@ final class MessageHistoryTable: Table {
|
|||||||
self.failedTable = failedTable
|
self.failedTable = failedTable
|
||||||
self.tagsTable = tagsTable
|
self.tagsTable = tagsTable
|
||||||
self.threadsTable = threadsTable
|
self.threadsTable = threadsTable
|
||||||
|
self.threadTagsTable = threadTagsTable
|
||||||
self.globalTagsTable = globalTagsTable
|
self.globalTagsTable = globalTagsTable
|
||||||
self.localTagsTable = localTagsTable
|
self.localTagsTable = localTagsTable
|
||||||
self.timeBasedAttributesTable = timeBasedAttributesTable
|
self.timeBasedAttributesTable = timeBasedAttributesTable
|
||||||
@ -278,6 +280,9 @@ final class MessageHistoryTable: Table {
|
|||||||
if (currentTags & 1) != 0 {
|
if (currentTags & 1) != 0 {
|
||||||
let tag = MessageTags(rawValue: 1 << UInt32(i))
|
let tag = MessageTags(rawValue: 1 << UInt32(i))
|
||||||
self.tagsTable.add(tags: tag, index: message.index, isNewlyAdded: true, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
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
|
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) {
|
for (peerId, messageIds) in self.messageIdsByPeerId(messageIds) {
|
||||||
var operations: [MessageHistoryIndexOperation] = []
|
var operations: [MessageHistoryIndexOperation] = []
|
||||||
|
|
||||||
for id in messageIds {
|
for id in messageIds {
|
||||||
self.messageHistoryIndexTable.removeMessage(id, operations: &operations)
|
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: ×tampBasedMessageAttributesOperations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
for operation in operations {
|
||||||
if case let .Remove(index) = operation {
|
if case let .Remove(index) = operation {
|
||||||
if let message = self.getMessage(index) {
|
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: ×tampBasedMessageAttributesOperations)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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: ×tampBasedMessageAttributesOperations)
|
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: ×tampBasedMessageAttributesOperations)
|
||||||
}
|
}
|
||||||
|
|
||||||
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) }
|
var indices = self.allMessageIndices(peerId: peerId).filter { namespaces.contains($0.id.namespace) }
|
||||||
if let threadId = threadId {
|
if let threadId = threadId {
|
||||||
indices = indices.filter { index in
|
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: ×tampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
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: ×tampBasedMessageAttributesOperations, 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) }
|
var indices = self.allMessageIndices(peerId: peerId).filter { namespaces.contains($0.id.namespace) }
|
||||||
if let threadId = threadId {
|
if let threadId = threadId {
|
||||||
indices = indices.filter { index in
|
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: ×tampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
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: ×tampBasedMessageAttributesOperations, 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)
|
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: ×tampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
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: ×tampBasedMessageAttributesOperations, 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] = []
|
var indices: [MessageIndex] = []
|
||||||
for entry in self.allIndicesWithGlobalTag(tag: tag) {
|
for entry in self.allIndicesWithGlobalTag(tag: tag) {
|
||||||
switch entry {
|
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: ×tampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
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: ×tampBasedMessageAttributesOperations, 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)
|
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: ×tampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
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: ×tampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
||||||
}
|
}
|
||||||
@ -1335,6 +1346,9 @@ final class MessageHistoryTable: Table {
|
|||||||
|
|
||||||
for tag in message.tags {
|
for tag in message.tags {
|
||||||
self.tagsTable.remove(tags: tag, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
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 {
|
if let threadId = message.threadId {
|
||||||
self.threadsTable.remove(threadId: threadId, index: index)
|
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 != message.tags || index != updatedIndex {
|
||||||
if !previousMessage.tags.isEmpty {
|
if !previousMessage.tags.isEmpty {
|
||||||
self.tagsTable.remove(tags: previousMessage.tags, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
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 {
|
if !message.tags.isEmpty {
|
||||||
//let isNewlyAdded = previousMessage.tags.isEmpty
|
//let isNewlyAdded = previousMessage.tags.isEmpty
|
||||||
self.tagsTable.add(tags: message.tags, index: message.index, isNewlyAdded: false, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
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 {
|
if previousMessage.threadId != message.threadId || index != message.index {
|
||||||
@ -2977,54 +2998,85 @@ final class MessageHistoryTable: Table {
|
|||||||
precondition(fromIndex.id.namespace == toIndex.id.namespace)
|
precondition(fromIndex.id.namespace == toIndex.id.namespace)
|
||||||
var result: [IntermediateMessage] = []
|
var result: [IntermediateMessage] = []
|
||||||
if let threadId = threadId {
|
if let threadId = threadId {
|
||||||
var indices: [MessageIndex] = []
|
if let tag = tag {
|
||||||
var startIndex = fromIndex
|
let indices: [MessageIndex]
|
||||||
var localIncludeFrom = includeFrom
|
|
||||||
while true {
|
|
||||||
let sliceIndices: [MessageIndex]
|
|
||||||
if fromIndex < toIndex {
|
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 {
|
} 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 {
|
for index in indices {
|
||||||
break
|
|
||||||
}
|
|
||||||
startIndex = sliceIndices[sliceIndices.count - 1]
|
|
||||||
localIncludeFrom = false
|
|
||||||
|
|
||||||
for index in sliceIndices {
|
|
||||||
if let ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange {
|
if let ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange {
|
||||||
if ignoreMessagesInTimestampRange.contains(index.timestamp) {
|
if ignoreMessagesInTimestampRange.contains(index.timestamp) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let tag = tag {
|
if fromIndex < toIndex {
|
||||||
if self.tagsTable.entryExists(tag: tag, index: index) {
|
if index < fromIndex || index > toIndex {
|
||||||
indices.append(index)
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
break
|
var indices: [MessageIndex] = []
|
||||||
}
|
var startIndex = fromIndex
|
||||||
}
|
var localIncludeFrom = includeFrom
|
||||||
for index in indices {
|
while true {
|
||||||
if fromIndex < toIndex {
|
let sliceIndices: [MessageIndex]
|
||||||
if index < fromIndex || index > toIndex {
|
if fromIndex < toIndex {
|
||||||
continue
|
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 sliceIndices.isEmpty {
|
||||||
if index < toIndex || index > fromIndex {
|
break
|
||||||
continue
|
}
|
||||||
|
|
||||||
|
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) {
|
for index in indices {
|
||||||
result.append(message)
|
if fromIndex < toIndex {
|
||||||
} else {
|
if index < fromIndex || index > toIndex {
|
||||||
assertionFailure()
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if index < toIndex || index > fromIndex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let message = self.getMessage(index) {
|
||||||
|
result.append(message)
|
||||||
|
} else {
|
||||||
|
assertionFailure()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let tag = tag {
|
} else if let tag = tag {
|
||||||
|
|||||||
@ -3,22 +3,24 @@ import Foundation
|
|||||||
final class MutableMessageHistoryTagSummaryView: MutablePostboxView {
|
final class MutableMessageHistoryTagSummaryView: MutablePostboxView {
|
||||||
private let tag: MessageTags
|
private let tag: MessageTags
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
|
private let threadId: Int64?
|
||||||
private let namespace: MessageId.Namespace
|
private let namespace: MessageId.Namespace
|
||||||
|
|
||||||
fileprivate var count: Int32?
|
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.tag = tag
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.threadId = threadId
|
||||||
self.namespace = namespace
|
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 {
|
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
||||||
var hasChanges = false
|
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
|
self.count = summary.count
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,7 @@ public struct MessageHistoryTagNamespaceSummary: Equatable, CustomStringConverti
|
|||||||
struct MessageHistoryTagsSummaryKey: Equatable, Hashable {
|
struct MessageHistoryTagsSummaryKey: Equatable, Hashable {
|
||||||
let tag: MessageTags
|
let tag: MessageTags
|
||||||
let peerId: PeerId
|
let peerId: PeerId
|
||||||
|
let threadId: Int64?
|
||||||
let namespace: MessageId.Namespace
|
let namespace: MessageId.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +81,8 @@ class MessageHistoryTagsSummaryTable: Table {
|
|||||||
private var cachedSummaries: [MessageHistoryTagsSummaryKey: CachedEntry] = [:]
|
private var cachedSummaries: [MessageHistoryTagsSummaryKey: CachedEntry] = [:]
|
||||||
private var updatedKeys = Set<MessageHistoryTagsSummaryKey>()
|
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) {
|
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, invalidateTable: InvalidatedMessageHistoryTagsSummaryTable) {
|
||||||
self.invalidateTable = invalidateTable
|
self.invalidateTable = invalidateTable
|
||||||
@ -88,17 +90,25 @@ class MessageHistoryTagsSummaryTable: Table {
|
|||||||
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
|
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func key(key: MessageHistoryTagsSummaryKey, sharedKey: ValueBoxKey = ValueBoxKey(length: 4 + 8 + 4)) -> ValueBoxKey {
|
private func keyShared(key: MessageHistoryTagsSummaryKey) -> ValueBoxKey {
|
||||||
sharedKey.setUInt32(0, value: key.tag.rawValue)
|
if let threadId = key.threadId {
|
||||||
sharedKey.setInt64(4, value: key.peerId.toInt64())
|
self.sharedThreadKey.setUInt32(0, value: key.tag.rawValue)
|
||||||
sharedKey.setInt32(4 + 8, value: key.namespace)
|
self.sharedThreadKey.setInt64(4, value: key.peerId.toInt64())
|
||||||
return sharedKey
|
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? {
|
func get(_ key: MessageHistoryTagsSummaryKey) -> MessageHistoryTagNamespaceSummary? {
|
||||||
if let cached = self.cachedSummaries[key] {
|
if let cached = self.cachedSummaries[key] {
|
||||||
return cached.summary
|
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)
|
let entry = readSummary(value)
|
||||||
self.cachedSummaries[key] = CachedEntry(summary: entry)
|
self.cachedSummaries[key] = CachedEntry(summary: entry)
|
||||||
return entry
|
return entry
|
||||||
@ -164,10 +174,10 @@ class MessageHistoryTagsSummaryTable: Table {
|
|||||||
if let summary = cached.summary {
|
if let summary = cached.summary {
|
||||||
buffer.reset()
|
buffer.reset()
|
||||||
writeSummary(summary, to: buffer)
|
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 {
|
} else {
|
||||||
assertionFailure()
|
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 {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class MessageHistoryTagsTable: Table {
|
|||||||
for tag in tags {
|
for tag in tags {
|
||||||
self.valueBox.set(self.table, key: self.key(tag: tag, index: index, key: self.sharedKey), value: MemoryBuffer())
|
self.valueBox.set(self.table, key: self.key(tag: tag, index: index, key: self.sharedKey), value: MemoryBuffer())
|
||||||
if self.summaryTags.contains(tag) {
|
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)
|
self.valueBox.remove(self.table, key: self.key(tag: tag, index: index, key: self.sharedKey), secure: false)
|
||||||
|
|
||||||
if self.summaryTags.contains(tag) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
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]]) {
|
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)
|
self.removeInternal(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &operations)
|
||||||
|
|
||||||
/*switch space {
|
switch space {
|
||||||
case .everywhere:
|
case .everywhere:
|
||||||
if let namespaceHoleTags = self.seedConfiguration.messageHoles[peerId.namespace]?[namespace] {
|
if let namespaceHoleTags = self.seedConfiguration.messageHoles[peerId.namespace]?[namespace] {
|
||||||
for tag in namespaceHoleTags {
|
for tag in namespaceHoleTags {
|
||||||
@ -346,7 +346,7 @@ final class MessageHistoryThreadHoleIndexTable: Table {
|
|||||||
}
|
}
|
||||||
case .tag:
|
case .tag:
|
||||||
break
|
break
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func removeInternal(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
|
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))
|
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 {
|
if !removeKeys.isEmpty {
|
||||||
addOperation(.remove(range), peerId: peerId, namespace: namespace, space: space, to: &operations)
|
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>] {
|
func debugList(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace) -> [ClosedRange<MessageId.Id>] {
|
||||||
|
|||||||
@ -5,27 +5,32 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
|
|||||||
let id: Int64
|
let id: Int64
|
||||||
let index: MessageIndex
|
let index: MessageIndex
|
||||||
var info: CodableEntry
|
var info: CodableEntry
|
||||||
|
var tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo]
|
||||||
var topMessage: Message?
|
var topMessage: Message?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
id: Int64,
|
id: Int64,
|
||||||
index: MessageIndex,
|
index: MessageIndex,
|
||||||
info: CodableEntry,
|
info: CodableEntry,
|
||||||
|
tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo],
|
||||||
topMessage: Message?
|
topMessage: Message?
|
||||||
) {
|
) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.index = index
|
self.index = index
|
||||||
self.info = info
|
self.info = info
|
||||||
|
self.tagSummaryInfo = tagSummaryInfo
|
||||||
self.topMessage = topMessage
|
self.topMessage = topMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate let peerId: PeerId
|
fileprivate let peerId: PeerId
|
||||||
|
fileprivate let summaryComponents: ChatListEntrySummaryComponents
|
||||||
fileprivate var peer: Peer?
|
fileprivate var peer: Peer?
|
||||||
fileprivate var items: [Item] = []
|
fileprivate var items: [Item] = []
|
||||||
|
|
||||||
init(postbox: PostboxImpl, peerId: PeerId) {
|
init(postbox: PostboxImpl, peerId: PeerId, summaryComponents: ChatListEntrySummaryComponents) {
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.summaryComponents = summaryComponents
|
||||||
|
|
||||||
self.reload(postbox: postbox)
|
self.reload(postbox: postbox)
|
||||||
}
|
}
|
||||||
@ -36,10 +41,34 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
|
|||||||
self.peer = postbox.peerTable.get(self.peerId)
|
self.peer = postbox.peerTable.get(self.peerId)
|
||||||
|
|
||||||
for item in postbox.messageHistoryThreadIndexTable.getAll(peerId: 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(
|
self.items.append(Item(
|
||||||
id: item.threadId,
|
id: item.threadId,
|
||||||
index: item.index,
|
index: item.index,
|
||||||
info: item.info,
|
info: item.info,
|
||||||
|
tagSummaryInfo: tagSummaryInfo,
|
||||||
topMessage: postbox.getMessage(item.index.id)
|
topMessage: postbox.getMessage(item.index.id)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -48,7 +77,7 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
|
|||||||
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
||||||
var updated = false
|
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)
|
self.reload(postbox: postbox)
|
||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
@ -70,17 +99,20 @@ public final class EngineMessageHistoryThread {
|
|||||||
public let id: Int64
|
public let id: Int64
|
||||||
public let index: MessageIndex
|
public let index: MessageIndex
|
||||||
public let info: CodableEntry
|
public let info: CodableEntry
|
||||||
|
public let tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo]
|
||||||
public let topMessage: Message?
|
public let topMessage: Message?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
id: Int64,
|
id: Int64,
|
||||||
index: MessageIndex,
|
index: MessageIndex,
|
||||||
info: CodableEntry,
|
info: CodableEntry,
|
||||||
|
tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo],
|
||||||
topMessage: Message?
|
topMessage: Message?
|
||||||
) {
|
) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.index = index
|
self.index = index
|
||||||
self.info = info
|
self.info = info
|
||||||
|
self.tagSummaryInfo = tagSummaryInfo
|
||||||
self.topMessage = topMessage
|
self.topMessage = topMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +126,9 @@ public final class EngineMessageHistoryThread {
|
|||||||
if lhs.info != rhs.info {
|
if lhs.info != rhs.info {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.tagSummaryInfo != rhs.tagSummaryInfo {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if let lhsMessage = lhs.topMessage, let rhsMessage = rhs.topMessage {
|
if let lhsMessage = lhs.topMessage, let rhsMessage = rhs.topMessage {
|
||||||
if lhsMessage.index != rhsMessage.index {
|
if lhsMessage.index != rhsMessage.index {
|
||||||
return false
|
return false
|
||||||
@ -123,6 +158,7 @@ public final class MessageHistoryThreadIndexView: PostboxView {
|
|||||||
id: item.id,
|
id: item.id,
|
||||||
index: item.index,
|
index: item.index,
|
||||||
info: item.info,
|
info: item.info,
|
||||||
|
tagSummaryInfo: item.tagSummaryInfo,
|
||||||
topMessage: item.topMessage
|
topMessage: item.topMessage
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import Foundation
|
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 {
|
class MessageHistoryThreadsTable: Table {
|
||||||
struct ItemId: Hashable {
|
struct ItemId: Hashable {
|
||||||
var peerId: PeerId
|
var peerId: PeerId
|
||||||
@ -31,6 +27,10 @@ class MessageHistoryThreadsTable: Table {
|
|||||||
return key
|
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 {
|
private func lowerBound(threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey {
|
||||||
let key = ValueBoxKey(length: 8 + 8 + 4)
|
let key = ValueBoxKey(length: 8 + 8 + 4)
|
||||||
key.setInt64(0, value: peerId.toInt64())
|
key.setInt64(0, value: peerId.toInt64())
|
||||||
@ -146,3 +146,199 @@ class MessageHistoryThreadsTable: Table {
|
|||||||
self.updatedIds.removeAll()
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -285,7 +285,7 @@ public final class MessageHistoryViewExternalInput: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum MessageHistoryViewInput: Equatable {
|
public enum MessageHistoryViewInput: Equatable {
|
||||||
case single(PeerId)
|
case single(peerId: PeerId, threadId: Int64?)
|
||||||
case associated(PeerId, MessageId?)
|
case associated(PeerId, MessageId?)
|
||||||
case external(MessageHistoryViewExternalInput)
|
case external(MessageHistoryViewExternalInput)
|
||||||
}
|
}
|
||||||
@ -362,7 +362,7 @@ final class MutableMessageHistoryView {
|
|||||||
switch peerIds {
|
switch peerIds {
|
||||||
case let .associated(peerId, _):
|
case let .associated(peerId, _):
|
||||||
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
||||||
case let .single(peerId):
|
case let .single(peerId, _):
|
||||||
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
||||||
case let .external(input):
|
case let .external(input):
|
||||||
switch input.content {
|
switch input.content {
|
||||||
@ -420,7 +420,7 @@ final class MutableMessageHistoryView {
|
|||||||
|
|
||||||
func updatePeerIds(transaction: PostboxTransaction) {
|
func updatePeerIds(transaction: PostboxTransaction) {
|
||||||
switch self.peerIds {
|
switch self.peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId, _):
|
||||||
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId] {
|
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId] {
|
||||||
if updatedData.associatedHistoryMessageId != nil {
|
if updatedData.associatedHistoryMessageId != nil {
|
||||||
self.peerIds = .associated(peerId, updatedData.associatedHistoryMessageId)
|
self.peerIds = .associated(peerId, updatedData.associatedHistoryMessageId)
|
||||||
@ -445,7 +445,7 @@ final class MutableMessageHistoryView {
|
|||||||
switch peerIds {
|
switch peerIds {
|
||||||
case let .associated(peerId, _):
|
case let .associated(peerId, _):
|
||||||
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
||||||
case let .single(peerId):
|
case let .single(peerId, _):
|
||||||
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
||||||
case let .external(input):
|
case let .external(input):
|
||||||
switch input.content {
|
switch input.content {
|
||||||
@ -458,7 +458,7 @@ final class MutableMessageHistoryView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch self.peerIds {
|
switch self.peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId, _):
|
||||||
holePeerIdsSet.insert(peerId)
|
holePeerIdsSet.insert(peerId)
|
||||||
if let value = transaction.currentOperationsByPeerId[peerId] {
|
if let value = transaction.currentOperationsByPeerId[peerId] {
|
||||||
operations.append(value)
|
operations.append(value)
|
||||||
@ -497,7 +497,10 @@ final class MutableMessageHistoryView {
|
|||||||
let externalThreadId: Int64?
|
let externalThreadId: Int64?
|
||||||
let isExternal: Bool
|
let isExternal: Bool
|
||||||
switch self.peerIds {
|
switch self.peerIds {
|
||||||
case .single, .associated:
|
case let .single(_, threadId):
|
||||||
|
externalThreadId = threadId
|
||||||
|
isExternal = false
|
||||||
|
case .associated:
|
||||||
externalThreadId = nil
|
externalThreadId = nil
|
||||||
isExternal = false
|
isExternal = false
|
||||||
case let .external(input):
|
case let .external(input):
|
||||||
@ -527,7 +530,7 @@ final class MutableMessageHistoryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matchesSpace {
|
if matchesSpace {
|
||||||
if holePeerIdsSet.contains(key.peerId) {
|
if holePeerIdsSet.contains(key.peerId) && key.threadId == externalThreadId {
|
||||||
for operation in holeOperations {
|
for operation in holeOperations {
|
||||||
switch operation {
|
switch operation {
|
||||||
case let .insert(range):
|
case let .insert(range):
|
||||||
@ -865,9 +868,11 @@ final class MutableMessageHistoryView {
|
|||||||
|
|
||||||
if !transaction.currentPeerHoleOperations.isEmpty {
|
if !transaction.currentPeerHoleOperations.isEmpty {
|
||||||
var holePeerIdsSet: [PeerId] = []
|
var holePeerIdsSet: [PeerId] = []
|
||||||
|
var threadId: Int64?
|
||||||
switch self.peerIds {
|
switch self.peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadIdValue):
|
||||||
holePeerIdsSet.append(peerId)
|
holePeerIdsSet.append(peerId)
|
||||||
|
threadId = threadIdValue
|
||||||
case let .associated(peerId, associatedId):
|
case let .associated(peerId, associatedId):
|
||||||
holePeerIdsSet.append(peerId)
|
holePeerIdsSet.append(peerId)
|
||||||
if let associatedId = associatedId {
|
if let associatedId = associatedId {
|
||||||
@ -878,7 +883,7 @@ final class MutableMessageHistoryView {
|
|||||||
}
|
}
|
||||||
let space: MessageHistoryHoleSpace = self.tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
|
let space: MessageHistoryHoleSpace = self.tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
|
||||||
for key in transaction.currentPeerHoleOperations.keys {
|
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
|
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
|
maxIndex = maxNamespaceIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1177,4 +1182,83 @@ public final class MessageHistoryView {
|
|||||||
|
|
||||||
self.entries = entries
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public enum MessageHistoryInput: Equatable, Hashable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case automatic(Automatic?)
|
case automatic(threadId: Int64?, info: Automatic?)
|
||||||
case external(MessageHistoryViewExternalInput, MessageTags?)
|
case external(MessageHistoryViewExternalInput, MessageTags?)
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
@ -27,8 +27,8 @@ public enum MessageHistoryInput: Equatable, Hashable {
|
|||||||
private extension MessageHistoryInput {
|
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] {
|
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 {
|
switch self {
|
||||||
case let .automatic(automatic):
|
case let .automatic(threadId, 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)
|
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 {
|
if let automatic = automatic, automatic.appendMessagesFromTheSameGroup {
|
||||||
enum Direction {
|
enum Direction {
|
||||||
case lowToHigh
|
case lowToHigh
|
||||||
@ -171,11 +171,19 @@ private extension MessageHistoryInput {
|
|||||||
|
|
||||||
func getMessageCountInRange(postbox: PostboxImpl, peerId: PeerId, namespace: MessageId.Namespace, lowerBound: MessageIndex, upperBound: MessageIndex) -> Int {
|
func getMessageCountInRange(postbox: PostboxImpl, peerId: PeerId, namespace: MessageId.Namespace, lowerBound: MessageIndex, upperBound: MessageIndex) -> Int {
|
||||||
switch self {
|
switch self {
|
||||||
case let .automatic(automatic):
|
case let .automatic(threadId, automatic):
|
||||||
if let automatic = 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 {
|
} 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:
|
case .external:
|
||||||
return 0
|
return 0
|
||||||
@ -492,8 +500,9 @@ private func sampleHoleRanges(input: MessageHistoryInput, orderedEntriesBySpace:
|
|||||||
var tag: MessageTags?
|
var tag: MessageTags?
|
||||||
var threadId: Int64?
|
var threadId: Int64?
|
||||||
switch input {
|
switch input {
|
||||||
case let .automatic(automatic):
|
case let .automatic(threadIdValue, automatic):
|
||||||
tag = automatic?.tag
|
tag = automatic?.tag
|
||||||
|
threadId = threadIdValue
|
||||||
case let .external(value, _):
|
case let .external(value, _):
|
||||||
switch value.content {
|
switch value.content {
|
||||||
case let .thread(_, id, _):
|
case let .thread(_, id, _):
|
||||||
@ -1016,9 +1025,9 @@ final class HistoryViewLoadedState {
|
|||||||
|
|
||||||
let input: MessageHistoryInput
|
let input: MessageHistoryInput
|
||||||
switch locations {
|
switch locations {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadId):
|
||||||
peerIds.append(peerId)
|
peerIds.append(peerId)
|
||||||
input = .automatic(tag.flatMap { tag in
|
input = .automatic(threadId: threadId, info: tag.flatMap { tag in
|
||||||
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup)
|
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup)
|
||||||
})
|
})
|
||||||
case let .associated(peerId, associatedId):
|
case let .associated(peerId, associatedId):
|
||||||
@ -1026,7 +1035,7 @@ final class HistoryViewLoadedState {
|
|||||||
if let associatedId = associatedId {
|
if let associatedId = associatedId {
|
||||||
peerIds.append(associatedId.peerId)
|
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)
|
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup)
|
||||||
})
|
})
|
||||||
case let .external(external):
|
case let .external(external):
|
||||||
@ -1482,9 +1491,11 @@ final class HistoryViewLoadedState {
|
|||||||
|
|
||||||
private func fetchHoles(postbox: PostboxImpl, locations: MessageHistoryViewInput, tag: MessageTags?, namespaces: MessageIdNamespaces) -> [PeerIdAndNamespace: IndexSet] {
|
private func fetchHoles(postbox: PostboxImpl, locations: MessageHistoryViewInput, tag: MessageTags?, namespaces: MessageIdNamespaces) -> [PeerIdAndNamespace: IndexSet] {
|
||||||
var peerIds: [PeerId] = []
|
var peerIds: [PeerId] = []
|
||||||
|
var threadId: Int64?
|
||||||
switch locations {
|
switch locations {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadIdValue):
|
||||||
peerIds.append(peerId)
|
peerIds.append(peerId)
|
||||||
|
threadId = threadIdValue
|
||||||
case let .associated(peerId, associatedId):
|
case let .associated(peerId, associatedId):
|
||||||
peerIds.append(peerId)
|
peerIds.append(peerId)
|
||||||
if let associatedId = associatedId {
|
if let associatedId = associatedId {
|
||||||
@ -1508,15 +1519,30 @@ private func fetchHoles(postbox: PostboxImpl, locations: MessageHistoryViewInput
|
|||||||
var holesBySpace: [PeerIdAndNamespace: IndexSet] = [:]
|
var holesBySpace: [PeerIdAndNamespace: IndexSet] = [:]
|
||||||
let holeSpace = tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
|
let holeSpace = tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
|
||||||
for peerId in peerIds {
|
for peerId in peerIds {
|
||||||
for namespace in postbox.messageHistoryHoleIndexTable.existingNamespaces(peerId: peerId, holeSpace: holeSpace) {
|
if let threadId = threadId {
|
||||||
if namespaces.contains(namespace) {
|
for namespace in postbox.messageHistoryThreadHoleIndexTable.existingNamespaces(peerId: peerId, threadId: threadId, holeSpace: holeSpace) {
|
||||||
let indices = postbox.messageHistoryHoleIndexTable.closest(peerId: peerId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
|
if namespaces.contains(namespace) {
|
||||||
if !indices.isEmpty {
|
let indices = postbox.messageHistoryThreadHoleIndexTable.closest(peerId: peerId, threadId: threadId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
|
||||||
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
|
if !indices.isEmpty {
|
||||||
assert(canContainHoles(peerIdAndNamespace, input: .automatic(tag.flatMap { tag in
|
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
|
||||||
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: false)
|
assert(canContainHoles(peerIdAndNamespace, input: .automatic(threadId: threadId, info: tag.flatMap { tag in
|
||||||
}), seedConfiguration: postbox.seedConfiguration))
|
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: false)
|
||||||
holesBySpace[peerIdAndNamespace] = indices
|
}), 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:
|
case .unread:
|
||||||
let anchorPeerId: PeerId
|
let anchorPeerId: PeerId
|
||||||
switch locations {
|
switch locations {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadId):
|
||||||
anchorPeerId = peerId
|
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, _):
|
case let .associated(peerId, _):
|
||||||
anchorPeerId = peerId
|
anchorPeerId = peerId
|
||||||
case .external:
|
case .external:
|
||||||
@ -1661,6 +1691,8 @@ enum HistoryViewState {
|
|||||||
case let .message(messageId):
|
case let .message(messageId):
|
||||||
var threadId: Int64?
|
var threadId: Int64?
|
||||||
switch locations {
|
switch locations {
|
||||||
|
case let .single(_, threadIdValue):
|
||||||
|
threadId = threadIdValue
|
||||||
case let .external(input):
|
case let .external(input):
|
||||||
switch input.content {
|
switch input.content {
|
||||||
case let .thread(_, id, _):
|
case let .thread(_, id, _):
|
||||||
|
|||||||
@ -25,7 +25,7 @@ public struct MessageOfInterestHole: Hashable, Equatable, CustomStringConvertibl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum MessageOfInterestViewLocation: Hashable {
|
public enum MessageOfInterestViewLocation: Hashable {
|
||||||
case peer(PeerId)
|
case peer(peerId: PeerId, threadId: Int64?)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
||||||
@ -45,9 +45,9 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|||||||
let mainPeerId: PeerId
|
let mainPeerId: PeerId
|
||||||
let peerIds: MessageHistoryViewInput
|
let peerIds: MessageHistoryViewInput
|
||||||
switch self.location {
|
switch self.location {
|
||||||
case let .peer(id):
|
case let .peer(id, threadId):
|
||||||
mainPeerId = id
|
mainPeerId = id
|
||||||
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
|
peerIds = postbox.peerIdsForLocation(.peer(peerId: id, threadId: threadId), ignoreRelatedChats: false)
|
||||||
}
|
}
|
||||||
self.peerIds = peerIds
|
self.peerIds = peerIds
|
||||||
var anchor: HistoryViewInputAnchor = .upperBound
|
var anchor: HistoryViewInputAnchor = .upperBound
|
||||||
@ -107,12 +107,14 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|||||||
|
|
||||||
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
||||||
var peerId: PeerId
|
var peerId: PeerId
|
||||||
|
var threadId: Int64?
|
||||||
switch self.location {
|
switch self.location {
|
||||||
case let .peer(id):
|
case let .peer(id, threadIdValue):
|
||||||
peerId = id
|
peerId = id
|
||||||
|
threadId = threadIdValue
|
||||||
}
|
}
|
||||||
var anchor: HistoryViewInputAnchor = self.anchor
|
var anchor: HistoryViewInputAnchor = self.anchor
|
||||||
if transaction.alteredInitialPeerCombinedReadStates[peerId] != nil {
|
if threadId == nil, transaction.alteredInitialPeerCombinedReadStates[peerId] != nil {
|
||||||
let updatedAnchor: HistoryViewInputAnchor = .upperBound
|
let updatedAnchor: HistoryViewInputAnchor = .upperBound
|
||||||
if let combinedState = postbox.readStateTable.getCombinedState(peerId), let state = combinedState.states.first, state.1.count != 0 {
|
if let combinedState = postbox.readStateTable.getCombinedState(peerId), let state = combinedState.states.first, state.1.count != 0 {
|
||||||
switch state.1 {
|
switch state.1 {
|
||||||
@ -129,8 +131,8 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|||||||
self.anchor = anchor
|
self.anchor = anchor
|
||||||
let peerIds: MessageHistoryViewInput
|
let peerIds: MessageHistoryViewInput
|
||||||
switch self.location {
|
switch self.location {
|
||||||
case let .peer(id):
|
case let .peer(id, threadId):
|
||||||
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
|
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})
|
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()
|
return self.updateFromView()
|
||||||
@ -138,9 +140,11 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|||||||
var reloadView = false
|
var reloadView = false
|
||||||
if !transaction.currentPeerHoleOperations.isEmpty {
|
if !transaction.currentPeerHoleOperations.isEmpty {
|
||||||
var allPeerIds: [PeerId]
|
var allPeerIds: [PeerId]
|
||||||
|
var threadId: Int64?
|
||||||
switch peerIds {
|
switch peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadIdValue):
|
||||||
allPeerIds = [peerId]
|
allPeerIds = [peerId]
|
||||||
|
threadId = threadIdValue
|
||||||
case let .associated(peerId, attachedMessageId):
|
case let .associated(peerId, attachedMessageId):
|
||||||
allPeerIds = [peerId]
|
allPeerIds = [peerId]
|
||||||
if let attachedMessageId = attachedMessageId {
|
if let attachedMessageId = attachedMessageId {
|
||||||
@ -151,7 +155,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
for (key, _) in transaction.currentPeerHoleOperations {
|
for (key, _) in transaction.currentPeerHoleOperations {
|
||||||
if allPeerIds.contains(key.peerId) {
|
if allPeerIds.contains(key.peerId) && key.threadId == threadId {
|
||||||
reloadView = true
|
reloadView = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -160,8 +164,8 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|||||||
if reloadView {
|
if reloadView {
|
||||||
let peerIds: MessageHistoryViewInput
|
let peerIds: MessageHistoryViewInput
|
||||||
switch self.location {
|
switch self.location {
|
||||||
case let .peer(id):
|
case let .peer(id, threadId):
|
||||||
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
|
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})
|
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})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
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)
|
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>] {
|
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()
|
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 {
|
public func getThreadIndexHoles(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace) -> IndexSet {
|
||||||
assert(!self.disposed)
|
assert(!self.disposed)
|
||||||
return self.postbox!.messageHistoryThreadHoleIndexTable.closest(peerId: peerId, threadId: threadId, namespace: namespace, space: .everywhere, range: 1 ... (Int32.max - 1))
|
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)
|
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)
|
assert(!self.disposed)
|
||||||
self.postbox?.deleteMessages(messageIds, forEachMedia: forEachMedia)
|
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)
|
assert(!self.disposed)
|
||||||
self.postbox?.deleteMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, forEachMedia: forEachMedia)
|
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)
|
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)
|
assert(!self.disposed)
|
||||||
self.postbox?.clearHistory(peerId, threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, forEachMedia: forEachMedia)
|
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)
|
assert(!self.disposed)
|
||||||
self.postbox?.removeAllMessagesWithAuthor(peerId, authorId: authorId, namespace: namespace, forEachMedia: forEachMedia)
|
self.postbox?.removeAllMessagesWithAuthor(peerId, authorId: authorId, namespace: namespace, forEachMedia: forEachMedia)
|
||||||
}
|
}
|
||||||
@ -166,7 +156,7 @@ public final class Transaction {
|
|||||||
self.postbox?.removeAllMessagesWithGlobalTag(tag: tag)
|
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)
|
assert(!self.disposed)
|
||||||
self.postbox?.removeAllMessagesWithForwardAuthor(peerId, forwardAuthorId: forwardAuthorId, namespace: namespace, forEachMedia: forEachMedia)
|
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)
|
assert(!self.disposed)
|
||||||
if let postbox = self.postbox {
|
if let postbox = self.postbox {
|
||||||
let messageIds = postbox.messageIdsForGlobalIds(ids)
|
let messageIds = postbox.messageIdsForGlobalIds(ids)
|
||||||
@ -229,7 +219,7 @@ public final class Transaction {
|
|||||||
public func applyInteractiveReadMaxIndex(_ messageIndex: MessageIndex) -> [MessageId] {
|
public func applyInteractiveReadMaxIndex(_ messageIndex: MessageIndex) -> [MessageId] {
|
||||||
assert(!self.disposed)
|
assert(!self.disposed)
|
||||||
if let postbox = self.postbox {
|
if let postbox = self.postbox {
|
||||||
return postbox.applyInteractiveReadMaxIndex(messageIndex)
|
return postbox.applyInteractiveReadMaxIndex(messageIndex: messageIndex)
|
||||||
} else {
|
} else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@ -328,7 +318,7 @@ public final class Transaction {
|
|||||||
return self.postbox?.readStateTable.getCombinedState(id)
|
return self.postbox?.readStateTable.getCombinedState(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getPeerNotificationSettings(_ id: PeerId) -> PeerNotificationSettings? {
|
public func getPeerNotificationSettings(id: PeerId) -> PeerNotificationSettings? {
|
||||||
assert(!self.disposed)
|
assert(!self.disposed)
|
||||||
return self.postbox?.peerNotificationSettingsTable.getEffective(id)
|
return self.postbox?.peerNotificationSettingsTable.getEffective(id)
|
||||||
}
|
}
|
||||||
@ -894,7 +884,7 @@ public final class Transaction {
|
|||||||
let notificationsPeerId = peer.notificationSettingsPeerId ?? peerId
|
let notificationsPeerId = peer.notificationSettingsPeerId ?? peerId
|
||||||
let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId)
|
let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId)
|
||||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(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) {
|
if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) {
|
||||||
includedPeerIds[peer.id] = true
|
includedPeerIds[peer.id] = true
|
||||||
@ -1002,14 +992,14 @@ public final class Transaction {
|
|||||||
return self.postbox?.getPendingMessageAction(type: type, id: id)
|
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)
|
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)
|
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? {
|
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))
|
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)
|
assert(!self.disposed)
|
||||||
guard let postbox = self.postbox else {
|
guard let postbox = self.postbox else {
|
||||||
return []
|
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] {
|
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 messageHistoryFailedTable: MessageHistoryFailedTable
|
||||||
let messageHistoryTagsTable: MessageHistoryTagsTable
|
let messageHistoryTagsTable: MessageHistoryTagsTable
|
||||||
let messageHistoryThreadsTable: MessageHistoryThreadsTable
|
let messageHistoryThreadsTable: MessageHistoryThreadsTable
|
||||||
|
let messageHistoryThreadTagsTable: MessageHistoryThreadTagsTable
|
||||||
let messageHistoryThreadHoleIndexTable: MessageHistoryThreadHoleIndexTable
|
let messageHistoryThreadHoleIndexTable: MessageHistoryThreadHoleIndexTable
|
||||||
let messageHistoryThreadReverseIndexTable: MessageHistoryThreadReverseIndexTable
|
let messageHistoryThreadReverseIndexTable: MessageHistoryThreadReverseIndexTable
|
||||||
let messageHistoryThreadIndexTable: MessageHistoryThreadIndexTable
|
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.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.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.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.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.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)
|
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.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.textIndexTable = MessageHistoryTextIndexTable(valueBox: self.valueBox, table: MessageHistoryTextIndexTable.tableSpec(41))
|
||||||
self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55), useCaches: useCaches)
|
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.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.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)
|
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.messageHistoryFailedTable)
|
||||||
tables.append(self.messageHistoryTagsTable)
|
tables.append(self.messageHistoryTagsTable)
|
||||||
tables.append(self.messageHistoryThreadsTable)
|
tables.append(self.messageHistoryThreadsTable)
|
||||||
|
tables.append(self.messageHistoryThreadTagsTable)
|
||||||
tables.append(self.messageHistoryThreadHoleIndexTable)
|
tables.append(self.messageHistoryThreadHoleIndexTable)
|
||||||
tables.append(self.messageHistoryThreadReverseIndexTable)
|
tables.append(self.messageHistoryThreadReverseIndexTable)
|
||||||
tables.append(self.messageHistoryThreadIndexTable)
|
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>) {
|
fileprivate func addHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||||
self.messageHistoryHoleIndexTable.add(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
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>) {
|
fileprivate func removeHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||||
self.messageHistoryHoleIndexTable.remove(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
if let threadId = threadId {
|
||||||
}
|
self.messageHistoryThreadHoleIndexTable.remove(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
||||||
|
} else {
|
||||||
fileprivate func addThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
self.messageHistoryHoleIndexTable.remove(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
||||||
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 recalculateChatListGroupStats(groupId: PeerGroupId) {
|
fileprivate func recalculateChatListGroupStats(groupId: PeerGroupId) {
|
||||||
@ -1844,11 +1841,11 @@ final class PostboxImpl {
|
|||||||
self.chatListTable.replaceHole(groupId: groupId, index: index, hole: hole, operations: &self.currentChatListOperations)
|
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: ¤tUnsentOperations, 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)
|
self.messageHistoryTable.removeMessages(messageIds, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, 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: ¤tUnsentOperations, 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)
|
self.messageHistoryTable.removeMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, 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 {
|
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: ¤tUnsentOperations, 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)
|
self.messageHistoryTable.clearHistoryInRange(peerId: peerId, threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, 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 {
|
} 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: ¤tUnsentOperations, 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)
|
self.messageHistoryTable.removeAllMessagesWithAuthor(peerId: peerId, authorId: authorId, namespace: namespace, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, 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: ¤tUnsentOperations, 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 })
|
self.messageHistoryTable.removeAllMessagesWithGlobalTag(tag: tag, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, 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: ¤tUnsentOperations, 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)
|
self.messageHistoryTable.removeAllMessagesWithForwardAuthor(peerId: peerId, forwardAuthorId: forwardAuthorId, namespace: namespace, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, 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)
|
self.messageHistoryTable.applyOutgoingReadMaxId(messageId, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func applyInteractiveReadMaxIndex(_ messageIndex: MessageIndex) -> [MessageId] {
|
fileprivate func applyInteractiveReadMaxIndex(messageIndex: MessageIndex) -> [MessageId] {
|
||||||
let peerIds = self.peerIdsForLocation(.peer(messageIndex.id.peerId), ignoreRelatedChats: false)
|
let peerIds = self.peerIdsForLocation(.peer(peerId: messageIndex.id.peerId, threadId: nil), ignoreRelatedChats: false)
|
||||||
switch peerIds {
|
switch peerIds {
|
||||||
case let .associated(_, messageId):
|
case let .associated(_, messageId):
|
||||||
if let messageId = messageId, let readState = self.readStateTable.getCombinedState(messageId.peerId), readState.count != 0 {
|
if let messageId = messageId, let readState = self.readStateTable.getCombinedState(messageId.peerId), readState.count != 0 {
|
||||||
if let topMessage = self.messageHistoryTable.topMessage(peerId: messageId.peerId) {
|
if let topMessage = self.messageHistoryTable.topMessage(peerId: messageId.peerId) {
|
||||||
let _ = self.messageHistoryTable.applyInteractiveMaxReadIndex(postbox: self, messageIndex: topMessage.index, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations)
|
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)
|
let initialCombinedStates = self.readStateTable.getCombinedState(messageIndex.id.peerId)
|
||||||
var resultIds = self.messageHistoryTable.applyInteractiveMaxReadIndex(postbox: self, messageIndex: messageIndex, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations)
|
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)
|
return self.pendingMessageActionsTable.getAction(id: id, type: type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func replaceMessageTagSummary(peerId: PeerId, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
|
fileprivate func replaceMessageTagSummary(peerId: PeerId, threadId: Int64?, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
|
||||||
let key = MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, namespace: namespace)
|
let key = MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, threadId: threadId, namespace: namespace)
|
||||||
self.messageHistoryTagsSummaryTable.replace(key: key, count: count, maxId: maxId, updatedSummaries: &self.currentUpdatedMessageTagSummaries)
|
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> {
|
func resolvedChatLocationInput(chatLocation: ChatLocationInput) -> Signal<(ResolvedChatLocationInput, Bool), NoError> {
|
||||||
switch chatLocation {
|
switch chatLocation {
|
||||||
case let .peer(peerId):
|
case let .peer(peerId, threadId):
|
||||||
return .single((.peer(peerId), false))
|
return .single((.peer(peerId: peerId, threadId: threadId), false))
|
||||||
case .thread(_, _, let data), .feed(_, let data):
|
case .thread(_, _, let data), .feed(_, let data):
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
var isHoleFill = false
|
var isHoleFill = false
|
||||||
@ -2629,9 +2626,9 @@ final class PostboxImpl {
|
|||||||
func peerIdsForLocation(_ chatLocation: ResolvedChatLocationInput, ignoreRelatedChats: Bool) -> MessageHistoryViewInput {
|
func peerIdsForLocation(_ chatLocation: ResolvedChatLocationInput, ignoreRelatedChats: Bool) -> MessageHistoryViewInput {
|
||||||
var peerIds: MessageHistoryViewInput
|
var peerIds: MessageHistoryViewInput
|
||||||
switch chatLocation {
|
switch chatLocation {
|
||||||
case let .peer(peerId):
|
case let .peer(peerId, threadId):
|
||||||
peerIds = .single(peerId)
|
peerIds = .single(peerId: peerId, threadId: threadId)
|
||||||
if !ignoreRelatedChats, let associatedMessageId = self.cachedPeerDataTable.get(peerId)?.associatedHistoryMessageId, associatedMessageId.peerId != peerId {
|
if !ignoreRelatedChats, threadId == nil, let associatedMessageId = self.cachedPeerDataTable.get(peerId)?.associatedHistoryMessageId, associatedMessageId.peerId != peerId {
|
||||||
peerIds = .associated(peerId, associatedMessageId)
|
peerIds = .associated(peerId, associatedMessageId)
|
||||||
}
|
}
|
||||||
case let .external(input):
|
case let .external(input):
|
||||||
@ -2640,7 +2637,7 @@ final class PostboxImpl {
|
|||||||
return peerIds
|
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)
|
return self.resolvedChatLocationInput(chatLocation: chatLocation)
|
||||||
|> mapToSignal { chatLocationData in
|
|> mapToSignal { chatLocationData in
|
||||||
let (chatLocation, isHoleFill) = chatLocationData
|
let (chatLocation, isHoleFill) = chatLocationData
|
||||||
@ -2650,8 +2647,10 @@ final class PostboxImpl {
|
|||||||
|
|
||||||
var anchor: HistoryViewInputAnchor = .upperBound
|
var anchor: HistoryViewInputAnchor = .upperBound
|
||||||
switch peerIds {
|
switch peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadId):
|
||||||
if self.chatListTable.getPeerChatListIndex(peerId: peerId) != nil {
|
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 {
|
if let combinedState = self.readStateTable.getCombinedState(peerId), let state = combinedState.states.first, state.1.count != 0 {
|
||||||
switch state.1 {
|
switch state.1 {
|
||||||
case let .idBased(maxIncomingReadId, _, _, _, _):
|
case let .idBased(maxIncomingReadId, _, _, _, _):
|
||||||
@ -2770,8 +2769,10 @@ final class PostboxImpl {
|
|||||||
var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] = [:]
|
var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] = [:]
|
||||||
var mainPeerIdForTopTaggedMessages: PeerId?
|
var mainPeerIdForTopTaggedMessages: PeerId?
|
||||||
switch peerIds {
|
switch peerIds {
|
||||||
case let .single(id):
|
case let .single(id, threadId):
|
||||||
mainPeerIdForTopTaggedMessages = id
|
if threadId == nil {
|
||||||
|
mainPeerIdForTopTaggedMessages = id
|
||||||
|
}
|
||||||
case let .associated(id, _):
|
case let .associated(id, _):
|
||||||
mainPeerIdForTopTaggedMessages = id
|
mainPeerIdForTopTaggedMessages = id
|
||||||
case .external:
|
case .external:
|
||||||
@ -2844,8 +2845,8 @@ final class PostboxImpl {
|
|||||||
var readStates: MessageHistoryViewReadState?
|
var readStates: MessageHistoryViewReadState?
|
||||||
var transientReadStates: MessageHistoryViewReadState?
|
var transientReadStates: MessageHistoryViewReadState?
|
||||||
switch peerIds {
|
switch peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadId):
|
||||||
if let readState = self.readStateTable.getCombinedState(peerId) {
|
if threadId == nil, let readState = self.readStateTable.getCombinedState(peerId) {
|
||||||
transientReadStates = .peer([peerId: readState])
|
transientReadStates = .peer([peerId: readState])
|
||||||
}
|
}
|
||||||
case let .associated(peerId, _):
|
case let .associated(peerId, _):
|
||||||
@ -2876,8 +2877,8 @@ final class PostboxImpl {
|
|||||||
|
|
||||||
let initialData: InitialMessageHistoryData
|
let initialData: InitialMessageHistoryData
|
||||||
switch peerIds {
|
switch peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadId):
|
||||||
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: nil)
|
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: threadId)
|
||||||
case let .associated(peerId, _):
|
case let .associated(peerId, _):
|
||||||
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: nil)
|
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: nil)
|
||||||
case let .external(input):
|
case let .external(input):
|
||||||
@ -3671,7 +3672,7 @@ final class PostboxImpl {
|
|||||||
fileprivate func addHolesEverywhere(peerNamespaces: [PeerId.Namespace], holeNamespace: MessageId.Namespace) {
|
fileprivate func addHolesEverywhere(peerNamespaces: [PeerId.Namespace], holeNamespace: MessageId.Namespace) {
|
||||||
for peerId in self.chatListIndexTable.getAllPeerIds() {
|
for peerId in self.chatListIndexTable.getAllPeerIds() {
|
||||||
if peerNamespaces.contains(peerId.namespace) && self.messageHistoryMetadataTable.isInitialized(peerId) {
|
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,
|
appendMessagesFromTheSameGroup: Bool,
|
||||||
namespaces: MessageIdNamespaces,
|
namespaces: MessageIdNamespaces,
|
||||||
orderStatistics: MessageHistoryViewOrderStatistics,
|
orderStatistics: MessageHistoryViewOrderStatistics,
|
||||||
|
customUnreadMessageId: MessageId?,
|
||||||
additionalData: [AdditionalMessageHistoryViewData]
|
additionalData: [AdditionalMessageHistoryViewData]
|
||||||
) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
@ -3834,6 +3836,7 @@ public class Postbox {
|
|||||||
appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup,
|
appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup,
|
||||||
namespaces: namespaces,
|
namespaces: namespaces,
|
||||||
orderStatistics: orderStatistics,
|
orderStatistics: orderStatistics,
|
||||||
|
customUnreadMessageId: customUnreadMessageId,
|
||||||
additionalData: additionalData
|
additionalData: additionalData
|
||||||
).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion))
|
).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,11 +45,11 @@ func resolveChatListMessageTagSummaryResultCalculation(addSummary: MessageHistor
|
|||||||
return count > 0
|
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 {
|
guard let calculation = calculation else {
|
||||||
return nil
|
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 subtractSummary = postbox.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(peerId, calculation.subtractCount.namespace, calculation.subtractCount.type))
|
||||||
let count = (addSummary?.count ?? 0) - subtractSummary
|
let count = (addSummary?.count ?? 0) - subtractSummary
|
||||||
return count > 0
|
return count > 0
|
||||||
|
|||||||
@ -269,9 +269,9 @@ final class ViewTracker {
|
|||||||
|
|
||||||
var updateType: ViewUpdateType = .Generic
|
var updateType: ViewUpdateType = .Generic
|
||||||
switch mutableView.peerIds {
|
switch mutableView.peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId, threadId):
|
||||||
for key in transaction.currentPeerHoleOperations.keys {
|
for key in transaction.currentPeerHoleOperations.keys {
|
||||||
if key.peerId == peerId {
|
if key.peerId == peerId && key.threadId == threadId {
|
||||||
updateType = .FillHole
|
updateType = .FillHole
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ public enum PostboxViewKey: Hashable {
|
|||||||
case pendingMessageActions(type: PendingMessageActionType)
|
case pendingMessageActions(type: PendingMessageActionType)
|
||||||
case invalidatedMessageHistoryTagSummaries(tagMask: MessageTags, namespace: MessageId.Namespace)
|
case invalidatedMessageHistoryTagSummaries(tagMask: MessageTags, namespace: MessageId.Namespace)
|
||||||
case pendingMessageActionsSummary(type: PendingMessageActionType, peerId: PeerId, 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 cachedPeerData(peerId: PeerId)
|
||||||
case unreadCounts(items: [UnreadMessageCountsItem])
|
case unreadCounts(items: [UnreadMessageCountsItem])
|
||||||
case combinedReadState(peerId: PeerId)
|
case combinedReadState(peerId: PeerId)
|
||||||
@ -38,7 +38,7 @@ public enum PostboxViewKey: Hashable {
|
|||||||
case isContact(id: PeerId)
|
case isContact(id: PeerId)
|
||||||
case chatListIndex(id: PeerId)
|
case chatListIndex(id: PeerId)
|
||||||
case peerTimeoutAttributes
|
case peerTimeoutAttributes
|
||||||
case messageHistoryThreadIndex(id: PeerId)
|
case messageHistoryThreadIndex(id: PeerId, summaryComponents: ChatListEntrySummaryComponents)
|
||||||
case messageHistoryThreadInfo(peerId: PeerId, threadId: Int64)
|
case messageHistoryThreadInfo(peerId: PeerId, threadId: Int64)
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
@ -68,9 +68,10 @@ public enum PostboxViewKey: Hashable {
|
|||||||
hasher.combine(type)
|
hasher.combine(type)
|
||||||
hasher.combine(peerId)
|
hasher.combine(peerId)
|
||||||
hasher.combine(namespace)
|
hasher.combine(namespace)
|
||||||
case let .historyTagSummaryView(tag, peerId, namespace):
|
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
|
||||||
hasher.combine(tag)
|
hasher.combine(tag)
|
||||||
hasher.combine(peerId)
|
hasher.combine(peerId)
|
||||||
|
hasher.combine(threadId)
|
||||||
hasher.combine(namespace)
|
hasher.combine(namespace)
|
||||||
case let .cachedPeerData(peerId):
|
case let .cachedPeerData(peerId):
|
||||||
hasher.combine(peerId)
|
hasher.combine(peerId)
|
||||||
@ -126,7 +127,7 @@ public enum PostboxViewKey: Hashable {
|
|||||||
hasher.combine(id)
|
hasher.combine(id)
|
||||||
case .peerTimeoutAttributes:
|
case .peerTimeoutAttributes:
|
||||||
hasher.combine(17)
|
hasher.combine(17)
|
||||||
case let .messageHistoryThreadIndex(id):
|
case let .messageHistoryThreadIndex(id, _):
|
||||||
hasher.combine(id)
|
hasher.combine(id)
|
||||||
case let .messageHistoryThreadInfo(peerId, threadId):
|
case let .messageHistoryThreadInfo(peerId, threadId):
|
||||||
hasher.combine(peerId)
|
hasher.combine(peerId)
|
||||||
@ -202,8 +203,8 @@ public enum PostboxViewKey: Hashable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .historyTagSummaryView(tag, peerId, namespace):
|
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
|
||||||
if case .historyTagSummaryView(tag, peerId, namespace) = rhs {
|
if case .historyTagSummaryView(tag, peerId, threadId, namespace) = rhs {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -358,8 +359,8 @@ public enum PostboxViewKey: Hashable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .messageHistoryThreadIndex(id):
|
case let .messageHistoryThreadIndex(id, summaryComponents):
|
||||||
if case .messageHistoryThreadIndex(id) = rhs {
|
if case .messageHistoryThreadIndex(id, summaryComponents) = rhs {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -398,8 +399,8 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
|
|||||||
return MutableInvalidatedMessageHistoryTagSummariesView(postbox: postbox, tagMask: tagMask, namespace: namespace)
|
return MutableInvalidatedMessageHistoryTagSummariesView(postbox: postbox, tagMask: tagMask, namespace: namespace)
|
||||||
case let .pendingMessageActionsSummary(type, peerId, namespace):
|
case let .pendingMessageActionsSummary(type, peerId, namespace):
|
||||||
return MutablePendingMessageActionsSummaryView(postbox: postbox, type: type, peerId: peerId, namespace: namespace)
|
return MutablePendingMessageActionsSummaryView(postbox: postbox, type: type, peerId: peerId, namespace: namespace)
|
||||||
case let .historyTagSummaryView(tag, peerId, namespace):
|
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
|
||||||
return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, namespace: namespace)
|
return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, threadId: threadId, namespace: namespace)
|
||||||
case let .cachedPeerData(peerId):
|
case let .cachedPeerData(peerId):
|
||||||
return MutableCachedPeerDataView(postbox: postbox, peerId: peerId)
|
return MutableCachedPeerDataView(postbox: postbox, peerId: peerId)
|
||||||
case let .unreadCounts(items):
|
case let .unreadCounts(items):
|
||||||
@ -450,8 +451,8 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
|
|||||||
return MutableChatListIndexView(postbox: postbox, id: id)
|
return MutableChatListIndexView(postbox: postbox, id: id)
|
||||||
case .peerTimeoutAttributes:
|
case .peerTimeoutAttributes:
|
||||||
return MutablePeerTimeoutAttributesView(postbox: postbox)
|
return MutablePeerTimeoutAttributesView(postbox: postbox)
|
||||||
case let .messageHistoryThreadIndex(id):
|
case let .messageHistoryThreadIndex(id, summaryComponents):
|
||||||
return MutableMessageHistoryThreadIndexView(postbox: postbox, peerId: id)
|
return MutableMessageHistoryThreadIndexView(postbox: postbox, peerId: id, summaryComponents: summaryComponents)
|
||||||
case let .messageHistoryThreadInfo(peerId, threadId):
|
case let .messageHistoryThreadInfo(peerId, threadId):
|
||||||
return MutableMessageHistoryThreadInfoView(postbox: postbox, peerId: peerId, threadId: threadId)
|
return MutableMessageHistoryThreadInfoView(postbox: postbox, peerId: peerId, threadId: threadId)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -781,16 +781,16 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
|
|||||||
let presentationData = context.sharedContext.currentPresentationData.modify {$0}
|
let presentationData = context.sharedContext.currentPresentationData.modify {$0}
|
||||||
|
|
||||||
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
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
|
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> = {
|
let updatePeerDisplayPreviews:(PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
|
||||||
peerId, displayPreviews in
|
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
|
self.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
||||||
@ -814,7 +814,7 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
|
|||||||
let mode = stateValue.with { $0.mode }
|
let mode = stateValue.with { $0.mode }
|
||||||
|
|
||||||
dismissInputImpl?()
|
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
|
_ = updatePeerSound(peer.id, sound).start(next: { _ in
|
||||||
updateNotificationsDisposable.set(nil)
|
updateNotificationsDisposable.set(nil)
|
||||||
_ = combineLatest(updatePeerSound(peer.id, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in
|
_ = combineLatest(updatePeerSound(peer.id, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in
|
||||||
|
|||||||
@ -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 initialState = NotificationExceptionPeerState(canRemove: false)
|
||||||
let statePromise = Promise(initialState)
|
let statePromise = Promise(initialState)
|
||||||
let stateValue = Atomic(value: initialState)
|
let stateValue = Atomic(value: initialState)
|
||||||
@ -420,10 +420,13 @@ public func notificationPeerExceptionController(context: AccountContext, updated
|
|||||||
|
|
||||||
statePromise.set(context.engine.data.get(
|
statePromise.set(context.engine.data.get(
|
||||||
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peer.id),
|
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()
|
TelegramEngine.EngineData.Item.NotificationSettings.Global()
|
||||||
)
|
)
|
||||||
|> map { notificationSettings, globalNotificationSettings -> NotificationExceptionPeerState in
|
|> map { peerNotificationSettings, threadNotificationSettings, globalNotificationSettings -> NotificationExceptionPeerState in
|
||||||
var state = NotificationExceptionPeerState(canRemove: mode.peerIds.contains(peer.id), notifications: notificationSettings._asNotificationSettings())
|
let effectiveSettings = threadNotificationSettings ?? peerNotificationSettings
|
||||||
|
|
||||||
|
var state = NotificationExceptionPeerState(canRemove: mode.peerIds.contains(peer.id), notifications: effectiveSettings._asNotificationSettings())
|
||||||
let globalSettings = globalNotificationSettings
|
let globalSettings = globalNotificationSettings
|
||||||
switch mode {
|
switch mode {
|
||||||
case .channels:
|
case .channels:
|
||||||
|
|||||||
@ -438,16 +438,16 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
|
|||||||
}
|
}
|
||||||
|
|
||||||
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
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
|
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> = {
|
let updatePeerDisplayPreviews:(PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
|
||||||
peerId, displayPreviews in
|
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)
|
var peerIds: Set<PeerId> = Set(mode.peerIds)
|
||||||
@ -502,7 +502,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mode = stateValue.with { $0.mode }
|
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
|
_ = updatePeerSound(peer.id, sound).start(next: { _ in
|
||||||
updateNotificationsDisposable.set(nil)
|
updateNotificationsDisposable.set(nil)
|
||||||
_ = combineLatest(updatePeerSound(peer.id, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in
|
_ = combineLatest(updatePeerSound(peer.id, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in
|
||||||
|
|||||||
@ -219,7 +219,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
var items: [ChatListItem] = []
|
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
|
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
|
}, activateChatPreview: { _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in })
|
}, present: { _ in })
|
||||||
|
|||||||
@ -839,7 +839,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
var items: [ChatListItem] = []
|
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
|
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
|
}, activateChatPreview: { _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in
|
}, present: { _ in
|
||||||
|
|||||||
@ -363,7 +363,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
var items: [ChatListItem] = []
|
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
|
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
|
}, activateChatPreview: { _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in
|
}, present: { _ in
|
||||||
|
|||||||
@ -447,7 +447,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
contextActionImpl?(messageId, node, gesture)
|
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
|
|> map { messageHistoryView, _, _ -> MessageHistoryView? in
|
||||||
return messageHistoryView
|
return messageHistoryView
|
||||||
}
|
}
|
||||||
|
|||||||
@ -222,7 +222,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-207944868] = { return Api.FileHash.parse_fileHash($0) }
|
dict[-207944868] = { return Api.FileHash.parse_fileHash($0) }
|
||||||
dict[-11252123] = { return Api.Folder.parse_folder($0) }
|
dict[-11252123] = { return Api.Folder.parse_folder($0) }
|
||||||
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($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[-1107729093] = { return Api.Game.parse_game($0) }
|
||||||
dict[-1297942941] = { return Api.GeoPoint.parse_geoPoint($0) }
|
dict[-1297942941] = { return Api.GeoPoint.parse_geoPoint($0) }
|
||||||
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($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[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) }
|
||||||
dict[-1311015810] = { return Api.InputNotifyPeer.parse_inputNotifyBroadcasts($0) }
|
dict[-1311015810] = { return Api.InputNotifyPeer.parse_inputNotifyBroadcasts($0) }
|
||||||
dict[1251338318] = { return Api.InputNotifyPeer.parse_inputNotifyChats($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[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) }
|
||||||
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
|
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
|
||||||
dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) }
|
dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) }
|
||||||
|
|||||||
@ -4985,16 +4985,18 @@ public extension Api.functions.messages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(1932455680)
|
buffer.appendInt32(11435201)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
peer.serialize(buffer, true)
|
peer.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(topMsgId!, buffer: buffer, boxed: false)}
|
||||||
buffer.appendInt32(481674261)
|
buffer.appendInt32(481674261)
|
||||||
buffer.appendInt32(Int32(filters.count))
|
buffer.appendInt32(Int32(filters.count))
|
||||||
for item in filters {
|
for item in filters {
|
||||||
item.serialize(buffer, true)
|
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)
|
let reader = BufferReader(buffer)
|
||||||
var result: [Api.messages.SearchCounter]?
|
var result: [Api.messages.SearchCounter]?
|
||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
@ -5470,11 +5472,13 @@ public extension Api.functions.messages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(-2099097129)
|
buffer.appendInt32(1420459918)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
peer.serialize(buffer, true)
|
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)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.messages.AffectedHistory?
|
var result: Api.messages.AffectedHistory?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
|
|||||||
@ -1094,13 +1094,13 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum ForumTopic: TypeConstructorDescription {
|
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) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
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 {
|
if boxed {
|
||||||
buffer.appendInt32(413771876)
|
buffer.appendInt32(1495324380)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt32(id, buffer: buffer, boxed: false)
|
serializeInt32(id, buffer: buffer, boxed: false)
|
||||||
@ -1115,14 +1115,15 @@ public extension Api {
|
|||||||
serializeInt32(unreadMentionsCount, buffer: buffer, boxed: false)
|
serializeInt32(unreadMentionsCount, buffer: buffer, boxed: false)
|
||||||
serializeInt32(unreadReactionsCount, buffer: buffer, boxed: false)
|
serializeInt32(unreadReactionsCount, buffer: buffer, boxed: false)
|
||||||
fromId.serialize(buffer, true)
|
fromId.serialize(buffer, true)
|
||||||
|
notifySettings.serialize(buffer, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
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):
|
||||||
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))])
|
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() {
|
if let signature = reader.readInt32() {
|
||||||
_13 = Api.parse(reader, signature: signature) as? Api.Peer
|
_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 _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -1168,8 +1173,9 @@ public extension Api {
|
|||||||
let _c11 = _11 != nil
|
let _c11 = _11 != nil
|
||||||
let _c12 = _12 != nil
|
let _c12 = _12 != nil
|
||||||
let _c13 = _13 != nil
|
let _c13 = _13 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 {
|
let _c14 = _14 != nil
|
||||||
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!)
|
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 {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -860,6 +860,7 @@ public extension Api {
|
|||||||
indirect enum InputNotifyPeer: TypeConstructorDescription {
|
indirect enum InputNotifyPeer: TypeConstructorDescription {
|
||||||
case inputNotifyBroadcasts
|
case inputNotifyBroadcasts
|
||||||
case inputNotifyChats
|
case inputNotifyChats
|
||||||
|
case inputNotifyForumTopic(peer: Api.InputPeer, topMsgId: Int32)
|
||||||
case inputNotifyPeer(peer: Api.InputPeer)
|
case inputNotifyPeer(peer: Api.InputPeer)
|
||||||
case inputNotifyUsers
|
case inputNotifyUsers
|
||||||
|
|
||||||
@ -876,6 +877,13 @@ public extension Api {
|
|||||||
buffer.appendInt32(1251338318)
|
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
|
break
|
||||||
case .inputNotifyPeer(let peer):
|
case .inputNotifyPeer(let peer):
|
||||||
if boxed {
|
if boxed {
|
||||||
@ -898,6 +906,8 @@ public extension Api {
|
|||||||
return ("inputNotifyBroadcasts", [])
|
return ("inputNotifyBroadcasts", [])
|
||||||
case .inputNotifyChats:
|
case .inputNotifyChats:
|
||||||
return ("inputNotifyChats", [])
|
return ("inputNotifyChats", [])
|
||||||
|
case .inputNotifyForumTopic(let peer, let topMsgId):
|
||||||
|
return ("inputNotifyForumTopic", [("peer", String(describing: peer)), ("topMsgId", String(describing: topMsgId))])
|
||||||
case .inputNotifyPeer(let peer):
|
case .inputNotifyPeer(let peer):
|
||||||
return ("inputNotifyPeer", [("peer", String(describing: peer))])
|
return ("inputNotifyPeer", [("peer", String(describing: peer))])
|
||||||
case .inputNotifyUsers:
|
case .inputNotifyUsers:
|
||||||
@ -911,6 +921,22 @@ public extension Api {
|
|||||||
public static func parse_inputNotifyChats(_ reader: BufferReader) -> InputNotifyPeer? {
|
public static func parse_inputNotifyChats(_ reader: BufferReader) -> InputNotifyPeer? {
|
||||||
return Api.InputNotifyPeer.inputNotifyChats
|
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? {
|
public static func parse_inputNotifyPeer(_ reader: BufferReader) -> InputNotifyPeer? {
|
||||||
var _1: Api.InputPeer?
|
var _1: Api.InputPeer?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
|
|||||||
@ -117,7 +117,7 @@ enum AccountStateMutationOperation {
|
|||||||
case UpdateAudioTranscription(messageId: MessageId, id: Int64, isPending: Bool, text: String)
|
case UpdateAudioTranscription(messageId: MessageId, id: Int64, isPending: Bool, text: String)
|
||||||
case UpdateConfig
|
case UpdateConfig
|
||||||
case UpdateExtendedMedia(MessageId, Api.MessageExtendedMedia)
|
case UpdateExtendedMedia(MessageId, Api.MessageExtendedMedia)
|
||||||
case ResetForumTopic(topicId: MessageId, data: MessageHistoryThreadData, pts: Int32)
|
case ResetForumTopic(topicId: MessageId, data: StoreMessageHistoryThreadData, pts: Int32)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HoleFromPreviousState {
|
struct HoleFromPreviousState {
|
||||||
|
|||||||
@ -62,8 +62,14 @@ public struct MessageHistoryThreadData: Codable, Equatable {
|
|||||||
public var maxIncomingReadId: Int32
|
public var maxIncomingReadId: Int32
|
||||||
public var maxKnownMessageId: Int32
|
public var maxKnownMessageId: Int32
|
||||||
public var maxOutgoingReadId: Int32
|
public var maxOutgoingReadId: Int32
|
||||||
public var unreadMentionCount: Int32
|
public var notificationSettings: TelegramPeerNotificationSettings
|
||||||
public var unreadReactionCount: Int32
|
}
|
||||||
|
|
||||||
|
struct StoreMessageHistoryThreadData {
|
||||||
|
var data: MessageHistoryThreadData
|
||||||
|
var topMessageId: Int32
|
||||||
|
var unreadMentionCount: Int32
|
||||||
|
var unreadReactionCount: Int32
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CreateForumChannelTopicError {
|
public enum CreateForumChannelTopicError {
|
||||||
@ -247,7 +253,7 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
|
|||||||
|
|
||||||
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
|
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)
|
return StoreMessage(apiMessage: message)
|
||||||
}, location: .Random)
|
}, location: .Random)
|
||||||
|
|
||||||
@ -261,7 +267,7 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
|
|||||||
|
|
||||||
for topic in topics {
|
for topic in topics {
|
||||||
switch topic {
|
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(
|
let data = MessageHistoryThreadData(
|
||||||
creationDate: date,
|
creationDate: date,
|
||||||
author: fromId.peerId,
|
author: fromId.peerId,
|
||||||
@ -274,13 +280,15 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
|
|||||||
maxIncomingReadId: readInboxMaxId,
|
maxIncomingReadId: readInboxMaxId,
|
||||||
maxKnownMessageId: topMessage,
|
maxKnownMessageId: topMessage,
|
||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
unreadMentionCount: unreadMentionsCount,
|
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
||||||
unreadReactionCount: unreadReactionsCount
|
|
||||||
)
|
)
|
||||||
guard let info = CodableEntry(data) else {
|
guard let info = CodableEntry(data) else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: info)
|
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 _ = _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())
|
self.updateDisposable.set(account.viewTracker.polledChannel(peerId: peerId).start())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -65,5 +65,5 @@ public func unarchiveAutomaticallyArchivedPeer(account: Account, peerId: PeerId)
|
|||||||
}
|
}
|
||||||
|> deliverOnMainQueue).start()
|
|> deliverOnMainQueue).start()
|
||||||
|
|
||||||
let _ = _internal_updatePeerMuteSetting(account: account, peerId: peerId, muteInterval: nil).start()
|
let _ = _internal_updatePeerMuteSetting(account: account, peerId: peerId, threadId: nil, muteInterval: nil).start()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,7 +75,7 @@ private func activeChannelsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set<Peer
|
|||||||
switch chat {
|
switch chat {
|
||||||
case .channel:
|
case .channel:
|
||||||
if let channel = parseTelegramGroupOrChannel(chat: chat) as? TelegramChannel {
|
if let channel = parseTelegramGroupOrChannel(chat: chat) as? TelegramChannel {
|
||||||
if channel.participationStatus == .member {
|
if channel.participationStatus == .member, case .personal = channel.accessHash {
|
||||||
peerIds.insert(channel.id)
|
peerIds.insert(channel.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -469,13 +469,13 @@ private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set<Pe
|
|||||||
hasValidInclusion = false
|
hasValidInclusion = false
|
||||||
}
|
}
|
||||||
if hasValidInclusion {
|
if hasValidInclusion {
|
||||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) {
|
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) {
|
||||||
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let peer = transaction.getPeer(peerId) {
|
if let peer = transaction.getPeer(peerId) {
|
||||||
if let channel = peer as? TelegramChannel, channel.participationStatus != .member {
|
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)
|
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
||||||
Logger.shared.log("State", "Peer \(peerId) (\(peer.debugDisplayTitle) has no stored inclusion, using synthesized one")
|
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 {
|
for topic in topics {
|
||||||
switch topic {
|
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(
|
state.operations.append(.ResetForumTopic(
|
||||||
topicId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id),
|
topicId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id),
|
||||||
data: MessageHistoryThreadData(
|
data: StoreMessageHistoryThreadData(
|
||||||
creationDate: date,
|
data: MessageHistoryThreadData(
|
||||||
author: fromId.peerId,
|
creationDate: date,
|
||||||
info: EngineMessageHistoryThread.Info(
|
author: fromId.peerId,
|
||||||
title: title,
|
info: EngineMessageHistoryThread.Info(
|
||||||
icon: iconEmojiId == 0 ? nil : iconEmojiId,
|
title: title,
|
||||||
iconColor: iconColor
|
icon: iconEmojiId == 0 ? nil : iconEmojiId,
|
||||||
|
iconColor: iconColor
|
||||||
|
),
|
||||||
|
incomingUnreadCount: unreadCount,
|
||||||
|
maxIncomingReadId: readInboxMaxId,
|
||||||
|
maxKnownMessageId: topMessage,
|
||||||
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
|
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
||||||
),
|
),
|
||||||
incomingUnreadCount: unreadCount,
|
topMessageId: topMessage,
|
||||||
maxIncomingReadId: readInboxMaxId,
|
|
||||||
maxKnownMessageId: topMessage,
|
|
||||||
maxOutgoingReadId: readOutboxMaxId,
|
|
||||||
unreadMentionCount: unreadMentionsCount,
|
unreadMentionCount: unreadMentionsCount,
|
||||||
unreadReactionCount: unreadReactionsCount
|
unreadReactionCount: unreadReactionsCount
|
||||||
),
|
),
|
||||||
@ -1786,7 +1790,7 @@ func resolveForumThreads(postbox: Postbox, network: Network, ids: [MessageId]) -
|
|||||||
|
|
||||||
for topic in topics {
|
for topic in topics {
|
||||||
switch topic {
|
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(
|
let data = MessageHistoryThreadData(
|
||||||
creationDate: date,
|
creationDate: date,
|
||||||
author: fromId.peerId,
|
author: fromId.peerId,
|
||||||
@ -1799,12 +1803,14 @@ func resolveForumThreads(postbox: Postbox, network: Network, ids: [MessageId]) -
|
|||||||
maxIncomingReadId: readInboxMaxId,
|
maxIncomingReadId: readInboxMaxId,
|
||||||
maxKnownMessageId: topMessage,
|
maxKnownMessageId: topMessage,
|
||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
unreadMentionCount: unreadMentionsCount,
|
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
||||||
unreadReactionCount: unreadReactionsCount
|
|
||||||
)
|
)
|
||||||
if let entry = CodableEntry(data) {
|
if let entry = CodableEntry(data) {
|
||||||
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: entry)
|
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 {
|
for topic in topics {
|
||||||
switch topic {
|
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):
|
||||||
fetchedChatList.threadInfos[MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)] = MessageHistoryThreadData(
|
fetchedChatList.threadInfos[MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)] = StoreMessageHistoryThreadData(
|
||||||
creationDate: date,
|
data: MessageHistoryThreadData(
|
||||||
author: fromId.peerId,
|
creationDate: date,
|
||||||
info: EngineMessageHistoryThread.Info(
|
author: fromId.peerId,
|
||||||
title: title,
|
info: EngineMessageHistoryThread.Info(
|
||||||
icon: iconEmojiId == 0 ? nil : iconEmojiId,
|
title: title,
|
||||||
iconColor: iconColor
|
icon: iconEmojiId == 0 ? nil : iconEmojiId,
|
||||||
|
iconColor: iconColor
|
||||||
|
),
|
||||||
|
incomingUnreadCount: unreadCount,
|
||||||
|
maxIncomingReadId: readInboxMaxId,
|
||||||
|
maxKnownMessageId: topMessage,
|
||||||
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
|
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
||||||
),
|
),
|
||||||
incomingUnreadCount: unreadCount,
|
topMessageId: topMessage,
|
||||||
maxIncomingReadId: readInboxMaxId,
|
|
||||||
maxKnownMessageId: topMessage,
|
|
||||||
maxOutgoingReadId: readOutboxMaxId,
|
|
||||||
unreadMentionCount: unreadMentionsCount,
|
unreadMentionCount: unreadMentionsCount,
|
||||||
unreadReactionCount: unreadReactionsCount
|
unreadReactionCount: unreadReactionsCount
|
||||||
)
|
)
|
||||||
@ -2209,7 +2219,7 @@ func pollChannelOnce(postbox: Postbox, network: Network, peerId: PeerId, stateMa
|
|||||||
hasValidInclusion = false
|
hasValidInclusion = false
|
||||||
}
|
}
|
||||||
if hasValidInclusion {
|
if hasValidInclusion {
|
||||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) as? TelegramPeerNotificationSettings {
|
||||||
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2263,7 +2273,7 @@ public func standalonePollChannelOnce(postbox: Postbox, network: Network, peerId
|
|||||||
hasValidInclusion = false
|
hasValidInclusion = false
|
||||||
}
|
}
|
||||||
if hasValidInclusion {
|
if hasValidInclusion {
|
||||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) as? TelegramPeerNotificationSettings {
|
||||||
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3099,7 +3109,7 @@ func replayFinalState(
|
|||||||
case .groupCreated, .channelMigratedFromGroup:
|
case .groupCreated, .channelMigratedFromGroup:
|
||||||
let holesAtHistoryStart = transaction.getHole(containing: MessageId(peerId: chatPeerId, namespace: Namespaces.Message.Cloud, id: id.id - 1))
|
let holesAtHistoryStart = transaction.getHole(containing: MessageId(peerId: chatPeerId, namespace: Namespaces.Message.Cloud, id: id.id - 1))
|
||||||
for (space, _) in holesAtHistoryStart {
|
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:
|
default:
|
||||||
break
|
break
|
||||||
@ -3422,11 +3432,11 @@ func replayFinalState(
|
|||||||
case let .UpdatePeerChatUnreadMark(peerId, namespace, value):
|
case let .UpdatePeerChatUnreadMark(peerId, namespace, value):
|
||||||
transaction.applyMarkUnread(peerId: peerId, namespace: namespace, value: value, interactive: false)
|
transaction.applyMarkUnread(peerId: peerId, namespace: namespace, value: value, interactive: false)
|
||||||
case let .ResetMessageTagSummary(peerId, tag, namespace, count, range):
|
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 {
|
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 {
|
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")
|
Logger.shared.log("State", "will call markUnseenPersonalMessage for \(ids.count) messages")
|
||||||
for id in ids {
|
for id in ids {
|
||||||
markUnseenPersonalMessage(transaction: transaction, id: id, addSynchronizeAction: false)
|
markUnseenPersonalMessage(transaction: transaction, id: id, addSynchronizeAction: false)
|
||||||
@ -3942,11 +3952,13 @@ func replayFinalState(
|
|||||||
case let .ResetForumTopic(topicId, data, pts):
|
case let .ResetForumTopic(topicId, data, pts):
|
||||||
if finalState.state.resetForumTopicLists[topicId.peerId] == nil {
|
if finalState.state.resetForumTopicLists[topicId.peerId] == nil {
|
||||||
let _ = pts
|
let _ = pts
|
||||||
if let entry = CodableEntry(data) {
|
if let entry = CodableEntry(data.data) {
|
||||||
transaction.setMessageHistoryThreadInfo(peerId: topicId.peerId, threadId: Int64(topicId.id), info: entry)
|
transaction.setMessageHistoryThreadInfo(peerId: topicId.peerId, threadId: Int64(topicId.id), info: entry)
|
||||||
} else {
|
} else {
|
||||||
assertionFailure()
|
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
|
upperId = Int32.max
|
||||||
}
|
}
|
||||||
if upperId >= messageId.id {
|
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)")
|
Logger.shared.log("State", "adding hole for peer \(messageId.peerId), \(messageId.id) ... \(upperId)")
|
||||||
} else {
|
} else {
|
||||||
@ -4269,7 +4281,7 @@ func replayFinalState(
|
|||||||
let currentInclusion = transaction.getPeerChatListInclusion(peerId)
|
let currentInclusion = transaction.getPeerChatListInclusion(peerId)
|
||||||
if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive {
|
if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive {
|
||||||
if let peer = transaction.getPeer(peerId) as? TelegramSecretChat {
|
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 {
|
if !isRemovedFromTotalUnreadCount {
|
||||||
transaction.updatePeerChatListInclusion(peerId, inclusion: currentInclusion.withGroupId(groupId: .root))
|
transaction.updatePeerChatListInclusion(peerId, inclusion: currentInclusion.withGroupId(groupId: .root))
|
||||||
|
|||||||
@ -1358,7 +1358,7 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
|
|||||||
notificationPeerId = author.id
|
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 defaultSound: PeerMessageSound = defaultCloudPeerNotificationSound
|
||||||
var defaultNotify: Bool = true
|
var defaultNotify: Bool = true
|
||||||
if let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) {
|
if let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) {
|
||||||
|
|||||||
@ -181,7 +181,7 @@ private func fetchPoll(account: Account, messageId: MessageId) -> Signal<Void, N
|
|||||||
private func wrappedHistoryViewAdditionalData(chatLocation: ChatLocationInput, additionalData: [AdditionalMessageHistoryViewData]) -> [AdditionalMessageHistoryViewData] {
|
private func wrappedHistoryViewAdditionalData(chatLocation: ChatLocationInput, additionalData: [AdditionalMessageHistoryViewData]) -> [AdditionalMessageHistoryViewData] {
|
||||||
var result = additionalData
|
var result = additionalData
|
||||||
switch chatLocation {
|
switch chatLocation {
|
||||||
case let .peer(peerId):
|
case let .peer(peerId, _):
|
||||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
if result.firstIndex(where: { if case .peerChatState = $0 { return true } else { return false } }) == nil {
|
if result.firstIndex(where: { if case .peerChatState = $0 { return true } else { return false } }) == nil {
|
||||||
result.append(.peerChatState(peerId))
|
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 {
|
self.queue.async {
|
||||||
guard let account = self.account else {
|
guard let account = self.account else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
|
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 {
|
for id in ids {
|
||||||
transaction.updateMessage(id, update: { currentMessage in
|
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
|
var maxId: Int32 = summary.range.maxId
|
||||||
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||||
maxId = index.id.id
|
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)
|
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 {
|
self.queue.async {
|
||||||
guard let account = self.account else {
|
guard let account = self.account else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
|
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 {
|
for id in ids {
|
||||||
transaction.updateMessage(id, update: { currentMessage in
|
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
|
var maxId: Int32 = summary.range.maxId
|
||||||
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||||
maxId = index.id.id
|
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)
|
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> {
|
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
|
let history = withState(signal, { [weak self] () -> Int32 in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
return OSAtomicIncrement32(&strongSelf.nextViewId)
|
return OSAtomicIncrement32(&strongSelf.nextViewId)
|
||||||
@ -1526,7 +1555,7 @@ public final class AccountViewTracker {
|
|||||||
strongSelf.updatePendingWebpages(viewId: viewId, messageIds: messageIds, localWebpages: localWebpages)
|
strongSelf.updatePendingWebpages(viewId: viewId, messageIds: messageIds, localWebpages: localWebpages)
|
||||||
let (pollMessageIds, pollMessageDict) = pollMessages(entries: next.0.entries)
|
let (pollMessageIds, pollMessageDict) = pollMessages(entries: next.0.entries)
|
||||||
strongSelf.updatePolls(viewId: viewId, messageIds: pollMessageIds, messages: pollMessageDict)
|
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)
|
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0)
|
||||||
} else if case let .thread(peerId, _, _) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
|
} else if case let .thread(peerId, _, _) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0, location: chatLocation)
|
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.updatePendingWebpages(viewId: viewId, messageIds: [], localWebpages: [:])
|
||||||
strongSelf.updatePolls(viewId: viewId, messageIds: [], messages: [:])
|
strongSelf.updatePolls(viewId: viewId, messageIds: [], messages: [:])
|
||||||
switch chatLocation {
|
switch chatLocation {
|
||||||
case let .peer(peerId):
|
case let .peer(peerId, _):
|
||||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: nil)
|
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: nil)
|
||||||
}
|
}
|
||||||
@ -1556,7 +1585,7 @@ public final class AccountViewTracker {
|
|||||||
|
|
||||||
let peerId: PeerId?
|
let peerId: PeerId?
|
||||||
switch chatLocation {
|
switch chatLocation {
|
||||||
case let .peer(peerIdValue):
|
case let .peer(peerIdValue, _):
|
||||||
peerId = peerIdValue
|
peerId = peerIdValue
|
||||||
case let .thread(peerIdValue, _, _):
|
case let .thread(peerIdValue, _, _):
|
||||||
peerId = peerIdValue
|
peerId = peerIdValue
|
||||||
@ -1583,7 +1612,7 @@ public final class AccountViewTracker {
|
|||||||
let isAutomaticallyTracked = self.account!.postbox.transaction { transaction -> Bool in
|
let isAutomaticallyTracked = self.account!.postbox.transaction { transaction -> Bool in
|
||||||
if transaction.getPeerChatListIndex(peerId) == nil {
|
if transaction.getPeerChatListIndex(peerId) == nil {
|
||||||
if addHole {
|
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
|
return false
|
||||||
} else {
|
} 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> {
|
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 {
|
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)
|
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal, addHoleIfNeeded: true)
|
||||||
} else {
|
} else {
|
||||||
return .never()
|
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 {
|
if let account = self.account {
|
||||||
let pendingMentionsKey: PostboxViewKey = .pendingMessageActionsSummary(type: .consumeUnseenPersonalMessage, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
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 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])
|
return account.postbox.combinedView(keys: [pendingMentionsKey, summaryMentionsKey, pendingReactionsKey, summaryReactionsKey])
|
||||||
|> map { views -> (mentionCount: Int32, reactionCount: Int32) in
|
|> map { views -> (mentionCount: Int32, reactionCount: Int32) in
|
||||||
|
|||||||
@ -5,12 +5,14 @@ import SwiftSignalKit
|
|||||||
|
|
||||||
public struct HistoryPreloadIndex: Hashable, Comparable, CustomStringConvertible {
|
public struct HistoryPreloadIndex: Hashable, Comparable, CustomStringConvertible {
|
||||||
public let index: ChatListIndex?
|
public let index: ChatListIndex?
|
||||||
|
public let threadId: Int64?
|
||||||
public let hasUnread: Bool
|
public let hasUnread: Bool
|
||||||
public let isMuted: Bool
|
public let isMuted: Bool
|
||||||
public let isPriority: 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.index = index
|
||||||
|
self.threadId = threadId
|
||||||
self.hasUnread = hasUnread
|
self.hasUnread = hasUnread
|
||||||
self.isMuted = isMuted
|
self.isMuted = isMuted
|
||||||
self.isPriority = isPriority
|
self.isPriority = isPriority
|
||||||
@ -38,6 +40,15 @@ public struct HistoryPreloadIndex: Hashable, Comparable, CustomStringConvertible
|
|||||||
return false
|
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 {
|
if let lhsIndex = lhs.index, let rhsIndex = rhs.index {
|
||||||
return lhsIndex > rhsIndex
|
return lhsIndex > rhsIndex
|
||||||
} else if lhs.index != nil {
|
} else if lhs.index != nil {
|
||||||
@ -117,6 +128,7 @@ private final class HistoryPreloadEntry: Comparable {
|
|||||||
|
|
||||||
private final class HistoryPreloadViewContext {
|
private final class HistoryPreloadViewContext {
|
||||||
var index: ChatListIndex?
|
var index: ChatListIndex?
|
||||||
|
var threadId: Int64?
|
||||||
var hasUnread: Bool?
|
var hasUnread: Bool?
|
||||||
var isMuted: Bool?
|
var isMuted: Bool?
|
||||||
var isPriority: Bool
|
var isPriority: Bool
|
||||||
@ -125,7 +137,7 @@ private final class HistoryPreloadViewContext {
|
|||||||
var media: [HolesViewMedia] = []
|
var media: [HolesViewMedia] = []
|
||||||
|
|
||||||
var preloadIndex: HistoryPreloadIndex {
|
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? {
|
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.index = index
|
||||||
|
self.threadId = threadId
|
||||||
self.hasUnread = hasUnread
|
self.hasUnread = hasUnread
|
||||||
self.isMuted = isMuted
|
self.isMuted = isMuted
|
||||||
self.isPriority = isPriority
|
self.isPriority = isPriority
|
||||||
@ -149,7 +162,7 @@ private final class HistoryPreloadViewContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private enum ChatHistoryPreloadEntity: Hashable {
|
private enum ChatHistoryPreloadEntity: Hashable {
|
||||||
case peer(PeerId)
|
case peer(peerId: PeerId, threadId: Int64?)
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct ChatHistoryPreloadIndex {
|
private struct ChatHistoryPreloadIndex {
|
||||||
@ -236,11 +249,13 @@ private final class AdditionalPreloadPeerIdsContext {
|
|||||||
|
|
||||||
public struct ChatHistoryPreloadItem : Equatable {
|
public struct ChatHistoryPreloadItem : Equatable {
|
||||||
public let index: ChatListIndex
|
public let index: ChatListIndex
|
||||||
|
public let threadId: Int64?
|
||||||
public let isMuted: Bool
|
public let isMuted: Bool
|
||||||
public let hasUnread: 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.index = index
|
||||||
|
self.threadId = threadId
|
||||||
self.isMuted = isMuted
|
self.isMuted = isMuted
|
||||||
self.hasUnread = hasUnread
|
self.hasUnread = hasUnread
|
||||||
}
|
}
|
||||||
@ -365,7 +380,7 @@ final class ChatHistoryPreloadManager {
|
|||||||
|
|
||||||
var indices: [(ChatHistoryPreloadIndex, Bool, Bool)] = []
|
var indices: [(ChatHistoryPreloadIndex, Bool, Bool)] = []
|
||||||
for item in loadItems {
|
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)
|
strongSelf.update(indices: indices, additionalPeerIds: additionalPeerIds)
|
||||||
@ -376,7 +391,7 @@ final class ChatHistoryPreloadManager {
|
|||||||
self.queue.async {
|
self.queue.async {
|
||||||
var validEntityIds = Set(indices.map { $0.0.entity })
|
var validEntityIds = Set(indices.map { $0.0.entity })
|
||||||
for peerId in additionalPeerIds {
|
for peerId in additionalPeerIds {
|
||||||
validEntityIds.insert(.peer(peerId))
|
validEntityIds.insert(.peer(peerId: peerId, threadId: nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
var removedEntityIds: [ChatHistoryPreloadEntity] = []
|
var removedEntityIds: [ChatHistoryPreloadEntity] = []
|
||||||
@ -400,7 +415,7 @@ final class ChatHistoryPreloadManager {
|
|||||||
}
|
}
|
||||||
for peerId in additionalPeerIds {
|
for peerId in additionalPeerIds {
|
||||||
if !existingPeerIds.contains(peerId) {
|
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 {
|
} 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
|
self.views[index.entity] = view
|
||||||
let key: PostboxViewKey
|
let key: PostboxViewKey
|
||||||
switch index.entity {
|
switch index.entity {
|
||||||
case let .peer(peerId):
|
case let .peer(peerId, threadId):
|
||||||
key = .messageOfInterestHole(location: .peer(peerId), namespace: Namespaces.Message.Cloud, count: 70)
|
key = .messageOfInterestHole(location: .peer(peerId: peerId, threadId: threadId), namespace: Namespaces.Message.Cloud, count: 70)
|
||||||
}
|
}
|
||||||
view.disposable.set((self.postbox.combinedView(keys: [key])
|
view.disposable.set((self.postbox.combinedView(keys: [key])
|
||||||
|> deliverOn(self.queue)).start(next: { [weak self] next in
|
|> deliverOn(self.queue)).start(next: { [weak self] next in
|
||||||
@ -453,8 +473,8 @@ final class ChatHistoryPreloadManager {
|
|||||||
let holeIsUpdated = previousHole != updatedHole
|
let holeIsUpdated = previousHole != updatedHole
|
||||||
|
|
||||||
switch index.entity {
|
switch index.entity {
|
||||||
case let .peer(peerId):
|
case let .peer(peerId, threadId):
|
||||||
Logger.shared.log("HistoryPreload", "view \(peerId) hole \(String(describing: updatedHole)) isUpdated: \(holeIsUpdated)")
|
Logger.shared.log("HistoryPreload", "view \(peerId) (threadId: \(String(describing: threadId)) hole \(String(describing: updatedHole)) isUpdated: \(holeIsUpdated)")
|
||||||
}
|
}
|
||||||
|
|
||||||
if previousHole != updatedHole {
|
if previousHole != updatedHole {
|
||||||
|
|||||||
@ -203,7 +203,7 @@ struct FetchedChatList {
|
|||||||
var pinnedItemIds: [PeerId]?
|
var pinnedItemIds: [PeerId]?
|
||||||
var folderSummaries: [PeerGroupId: PeerGroupUnreadCountersSummary]
|
var folderSummaries: [PeerGroupId: PeerGroupUnreadCountersSummary]
|
||||||
var peerGroupIds: [PeerId: PeerGroupId]
|
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> {
|
func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLocation, upperBound: MessageIndex, hash: Int64, limit: Int32) -> Signal<FetchedChatList?, NoError> {
|
||||||
|
|||||||
@ -1,3 +1,16 @@
|
|||||||
import Foundation
|
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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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]] = []
|
var rangesToInvalidate: [[MessageId]] = []
|
||||||
let addToRange: (MessageId, inout [[MessageId]]) -> Void = { id, ranges in
|
let addToRange: (MessageId, inout [[MessageId]]) -> Void = { id, ranges in
|
||||||
if ranges.isEmpty {
|
if ranges.isEmpty {
|
||||||
@ -219,7 +219,7 @@ final class HistoryViewStateValidationContexts {
|
|||||||
context.batchReferences[messageId] = batch
|
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
|
|> deliverOn(self.queue)).start(completed: { [weak self, weak batch] in
|
||||||
if let strongSelf = self, let context = strongSelf.contexts[id], let batch = batch {
|
if let strongSelf = self, let context = strongSelf.contexts[id], let batch = batch {
|
||||||
var completedMessageIds: [MessageId] = []
|
var completedMessageIds: [MessageId] = []
|
||||||
@ -355,7 +355,7 @@ final class HistoryViewStateValidationContexts {
|
|||||||
}
|
}
|
||||||
} else if view.namespaces.contains(Namespaces.Message.ScheduledCloud) {
|
} else if view.namespaces.contains(Namespaces.Message.ScheduledCloud) {
|
||||||
if let _ = self.contexts[id] {
|
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()
|
let timestamp = self.network.context.globalTime()
|
||||||
if let previousTimestamp = self.previousPeerValidationTimestamps[peerId], timestamp < previousTimestamp + 60 {
|
if let previousTimestamp = self.previousPeerValidationTimestamps[peerId], timestamp < previousTimestamp + 60 {
|
||||||
} else {
|
} else {
|
||||||
@ -543,7 +543,7 @@ private func validateChannelMessagesBatch(postbox: Postbox, network: Network, ac
|
|||||||
} |> switchToLatest
|
} |> 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
|
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||||
var previousMessages: [Message] = []
|
var previousMessages: [Message] = []
|
||||||
var previous: [MessageId: Message] = [:]
|
var previous: [MessageId: Message] = [:]
|
||||||
@ -556,10 +556,22 @@ private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network
|
|||||||
|
|
||||||
var signal: Signal<ValidatedMessages, MTRpcError>
|
var signal: Signal<ValidatedMessages, MTRpcError>
|
||||||
let hash = hashForMessages(previousMessages, withChannelIds: false)
|
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) {
|
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||||
let requestSignal: Signal<Api.messages.Messages, MTRpcError>
|
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
|
signal = requestSignal
|
||||||
|> map { result -> ValidatedMessages in
|
|> map { result -> ValidatedMessages in
|
||||||
|
|||||||
@ -406,7 +406,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||||||
minMaxRange = 1 ... Int32.max - 1
|
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 {
|
} else if tag == .unseenReaction {
|
||||||
let offsetId: Int32
|
let offsetId: Int32
|
||||||
let addOffset: Int32
|
let addOffset: Int32
|
||||||
@ -454,7 +461,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||||||
minMaxRange = 1 ... Int32.max - 1
|
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 {
|
} else if tag == .liveLocation {
|
||||||
let selectedLimit = count
|
let selectedLimit = count
|
||||||
|
|
||||||
@ -511,7 +525,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||||||
minMaxRange = 1 ... (Int32.max - 1)
|
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 {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
minMaxRange = 1 ... 1
|
minMaxRange = 1 ... 1
|
||||||
@ -669,13 +690,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||||||
|
|
||||||
switch peerInput {
|
switch peerInput {
|
||||||
case let .direct(peerId, threadId):
|
case let .direct(peerId, threadId):
|
||||||
if let threadId = threadId {
|
transaction.removeHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: filledRange)
|
||||||
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)
|
|
||||||
}
|
|
||||||
case .threadFromChannel:
|
case .threadFromChannel:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -736,9 +751,11 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId
|
|||||||
})
|
})
|
||||||
|
|
||||||
for (threadMessageId, data) in fetchedChats.threadInfos {
|
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.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)
|
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 {
|
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 {
|
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 {
|
for (groupId, summary) in fetchedChats.folderSummaries {
|
||||||
|
|||||||
@ -377,7 +377,7 @@ private func synchronizeUnseenPersonalMentionsTag(postbox: Postbox, network: Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
return postbox.transaction { transaction -> Void in
|
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 {
|
} else {
|
||||||
return .complete()
|
return .complete()
|
||||||
@ -419,7 +419,7 @@ private func synchronizeUnseenReactionsTag(postbox: Postbox, network: Network, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
return postbox.transaction { transaction -> Void in
|
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 {
|
} else {
|
||||||
return .complete()
|
return .complete()
|
||||||
|
|||||||
@ -24,13 +24,11 @@ private final class ManagedMessageHistoryHolesState {
|
|||||||
|
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
switch entry.hole {
|
switch entry.hole {
|
||||||
case let .peer(hole):
|
case .peer:
|
||||||
if hole.threadId == nil {
|
if self.holeDisposables[entry] == nil {
|
||||||
if self.holeDisposables[entry] == nil {
|
let disposable = MetaDisposable()
|
||||||
let disposable = MetaDisposable()
|
self.holeDisposables[entry] = disposable
|
||||||
self.holeDisposables[entry] = disposable
|
added[entry] = disposable
|
||||||
added[entry] = disposable
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,7 +53,7 @@ func managedMessageHistoryHoles(accountPeerId: PeerId, network: Network, postbox
|
|||||||
for (entry, disposable) in added {
|
for (entry, disposable) in added {
|
||||||
switch entry.hole {
|
switch entry.hole {
|
||||||
case let .peer(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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -72,7 +72,7 @@ func managedPendingPeerNotificationSettings(postbox: Postbox, network: Network)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (peerId, settings, disposable) in beginOperations {
|
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())
|
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
|
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
|
var notificationPeerId = peerId
|
||||||
if let associatedPeerId = peer.associatedPeerId {
|
if let associatedPeerId = peer.associatedPeerId {
|
||||||
notificationPeerId = associatedPeerId
|
notificationPeerId = associatedPeerId
|
||||||
}
|
}
|
||||||
|
|
||||||
if let notificationPeer = transaction.getPeer(notificationPeerId), let inputPeer = apiInputPeer(notificationPeer), let settings = settings as? TelegramPeerNotificationSettings {
|
if let threadId = threadId {
|
||||||
let showPreviews: Api.Bool?
|
if let data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||||
switch settings.displayPreviews {
|
let settings = data.notificationSettings
|
||||||
|
|
||||||
|
let showPreviews: Api.Bool?
|
||||||
|
switch settings.displayPreviews {
|
||||||
case .default:
|
case .default:
|
||||||
showPreviews = nil
|
showPreviews = nil
|
||||||
case .show:
|
case .show:
|
||||||
showPreviews = .boolTrue
|
showPreviews = .boolTrue
|
||||||
case .hide:
|
case .hide:
|
||||||
showPreviews = .boolFalse
|
showPreviews = .boolFalse
|
||||||
}
|
}
|
||||||
let muteUntil: Int32?
|
let muteUntil: Int32?
|
||||||
switch settings.muteState {
|
switch settings.muteState {
|
||||||
case let .muted(until):
|
case let .muted(until):
|
||||||
muteUntil = until
|
muteUntil = until
|
||||||
case .unmuted:
|
case .unmuted:
|
||||||
muteUntil = 0
|
muteUntil = 0
|
||||||
case .default:
|
case .default:
|
||||||
muteUntil = nil
|
muteUntil = nil
|
||||||
}
|
}
|
||||||
let sound: Api.NotificationSound? = settings.messageSound.apiSound
|
let sound: Api.NotificationSound? = settings.messageSound.apiSound
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
if showPreviews != nil {
|
if showPreviews != nil {
|
||||||
flags |= (1 << 0)
|
flags |= (1 << 0)
|
||||||
}
|
}
|
||||||
if muteUntil != nil {
|
if muteUntil != nil {
|
||||||
flags |= (1 << 2)
|
flags |= (1 << 2)
|
||||||
}
|
}
|
||||||
if sound != nil {
|
if sound != nil {
|
||||||
flags |= (1 << 3)
|
flags |= (1 << 3)
|
||||||
}
|
}
|
||||||
let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound)
|
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))
|
return network.request(Api.functions.account.updateNotifySettings(peer: .inputNotifyForumTopic(peer: inputPeer, topMsgId: Int32(clamping: threadId)), settings: inputSettings))
|
||||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||||
return .single(.boolFalse)
|
return .single(.boolFalse)
|
||||||
}
|
}
|
||||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||||
return postbox.transaction { transaction -> Void 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 {
|
||||||
|
return .complete()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
|
if let notificationPeer = transaction.getPeer(notificationPeerId), let inputPeer = apiInputPeer(notificationPeer), let settings = settings as? TelegramPeerNotificationSettings {
|
||||||
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil)
|
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 {
|
} else {
|
||||||
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
|
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
|
||||||
|
|||||||
@ -284,7 +284,7 @@ private func synchronizeMarkAllUnseenReactions(transaction: Transaction, postbox
|
|||||||
return .complete()
|
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)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<Api.messages.AffectedHistory?, Bool> in
|
|> `catch` { _ -> Signal<Api.messages.AffectedHistory?, Bool> in
|
||||||
return .fail(true)
|
return .fail(true)
|
||||||
@ -308,90 +308,6 @@ private func synchronizeMarkAllUnseenReactions(transaction: Transaction, postbox
|
|||||||
|> `catch` { _ -> Signal<Void, NoError> in
|
|> `catch` { _ -> Signal<Void, NoError> in
|
||||||
return .complete()
|
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) {
|
func markUnseenReactionMessage(transaction: Transaction, id: MessageId, addSynchronizeAction: Bool) {
|
||||||
|
|||||||
@ -68,11 +68,7 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
|
|||||||
if channel.flags.contains(.isForum) {
|
if channel.flags.contains(.isForum) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
if channel.username != nil {
|
return .group
|
||||||
return .group
|
|
||||||
} else {
|
|
||||||
return .group
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
|
|||||||
@ -73,11 +73,41 @@ public func getCloudLegacySound(id: Int64) -> (id: Int32, category: CloudSoundBu
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PeerMuteState: Equatable {
|
public enum PeerMuteState: Codable, Equatable {
|
||||||
case `default`
|
case `default`
|
||||||
case unmuted
|
case unmuted
|
||||||
case muted(until: Int32)
|
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 {
|
fileprivate static func decodeInline(_ decoder: PostboxDecoder) -> PeerMuteState {
|
||||||
switch decoder.decodeInt32ForKey("m.v", orElse: 0) {
|
switch decoder.decodeInt32ForKey("m.v", orElse: 0) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -104,15 +134,15 @@ public enum PeerMuteState: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum PeerMessageSoundValue: Int32 {
|
private enum PeerMessageSoundValue: Int32, Codable {
|
||||||
case none
|
case none = 0
|
||||||
case bundledModern
|
case bundledModern = 1
|
||||||
case bundledClassic
|
case bundledClassic = 2
|
||||||
case `default`
|
case `default` = 3
|
||||||
case cloud
|
case cloud = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PeerMessageSound: Equatable {
|
public enum PeerMessageSound: Equatable, Codable {
|
||||||
public enum Id: Hashable {
|
public enum Id: Hashable {
|
||||||
case none
|
case none
|
||||||
case `default`
|
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 {
|
static func decodeInline(_ container: KeyedDecodingContainer<StringCodingKey>) throws -> PeerMessageSound {
|
||||||
switch try container.decode(Int32.self, forKey: "s.v") {
|
switch try container.decode(Int32.self, forKey: "s.v") {
|
||||||
case PeerMessageSoundValue.none.rawValue:
|
case PeerMessageSoundValue.none.rawValue:
|
||||||
@ -181,6 +235,26 @@ public enum PeerMessageSound: Equatable {
|
|||||||
return defaultCloudPeerNotificationSound
|
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 {
|
func encodeInline(_ container: inout KeyedEncodingContainer<StringCodingKey>) throws {
|
||||||
switch self {
|
switch self {
|
||||||
@ -254,11 +328,40 @@ public enum PeerMessageSound: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PeerNotificationDisplayPreviews {
|
public enum PeerNotificationDisplayPreviews: Equatable, Codable {
|
||||||
case `default`
|
case `default`
|
||||||
case show
|
case show
|
||||||
case hide
|
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 {
|
static func decodeInline(_ decoder: PostboxDecoder) -> PeerNotificationDisplayPreviews {
|
||||||
switch decoder.decodeInt32ForKey("p.v", orElse: 0) {
|
switch decoder.decodeInt32ForKey("p.v", orElse: 0) {
|
||||||
case 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 muteState: PeerMuteState
|
||||||
public let messageSound: PeerMessageSound
|
public let messageSound: PeerMessageSound
|
||||||
public let displayPreviews: PeerNotificationDisplayPreviews
|
public let displayPreviews: PeerNotificationDisplayPreviews
|
||||||
@ -325,6 +428,22 @@ public final class TelegramPeerNotificationSettings: PeerNotificationSettings, E
|
|||||||
self.displayPreviews = PeerNotificationDisplayPreviews.decodeInline(decoder)
|
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) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
self.muteState.encodeInline(encoder)
|
self.muteState.encodeInline(encoder)
|
||||||
self.messageSound.encodeInline(encoder)
|
self.messageSound.encodeInline(encoder)
|
||||||
|
|||||||
@ -275,23 +275,26 @@ public extension TelegramEngine.EngineData.Item {
|
|||||||
public struct ItemKey: Hashable {
|
public struct ItemKey: Hashable {
|
||||||
public var peerId: EnginePeer.Id
|
public var peerId: EnginePeer.Id
|
||||||
public var tag: MessageTags
|
public var tag: MessageTags
|
||||||
|
public var threadId: Int64?
|
||||||
}
|
}
|
||||||
|
|
||||||
public typealias Result = Int?
|
public typealias Result = Int?
|
||||||
|
|
||||||
fileprivate var peerId: EnginePeer.Id
|
fileprivate var peerId: EnginePeer.Id
|
||||||
fileprivate var tag: MessageTags
|
fileprivate var tag: MessageTags
|
||||||
|
fileprivate var threadId: Int64?
|
||||||
public var mapKey: ItemKey {
|
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.peerId = peerId
|
||||||
|
self.threadId = threadId
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
}
|
}
|
||||||
|
|
||||||
var key: PostboxViewKey {
|
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 {
|
func extract(view: PostboxView) -> Result {
|
||||||
|
|||||||
@ -258,6 +258,32 @@ public extension TelegramEngine.EngineData.Item {
|
|||||||
return EnginePeer.NotificationSettings(notificationSettings)
|
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 struct ParticipantCount: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||||
public typealias Result = Optional<Int>
|
public typealias Result = Optional<Int>
|
||||||
|
|||||||
@ -115,14 +115,14 @@ public final class EngineDataOptional<Item: TelegramEngineDataItem>: TelegramEng
|
|||||||
}
|
}
|
||||||
|
|
||||||
func _extract(views: [PostboxViewKey: PostboxView]) -> Any {
|
func _extract(views: [PostboxViewKey: PostboxView]) -> Any {
|
||||||
var result: [Item.Result] = []
|
var result: Item.Result?
|
||||||
|
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
let itemResult = (item as! AnyPostboxViewDataItem)._extract(views: views)
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -133,7 +133,7 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, viewT
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !hasUnread && peerId.namespace == Namespaces.Peer.SecretChat {
|
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)
|
let actionSummary = transaction.getPendingMessageActionsSummary(peerId: peerId, type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud)
|
||||||
if (unseenSummary?.count ?? 0) - (actionSummary ?? 0) > 0 {
|
if (unseenSummary?.count ?? 0) - (actionSummary ?? 0) > 0 {
|
||||||
hasUnread = true
|
hasUnread = true
|
||||||
@ -147,7 +147,7 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, viewT
|
|||||||
} else {
|
} else {
|
||||||
transaction.applyMarkUnread(peerId: peerId, namespace: principalNamespace, value: false, interactive: true)
|
transaction.applyMarkUnread(peerId: peerId, namespace: principalNamespace, value: false, interactive: true)
|
||||||
}
|
}
|
||||||
viewTracker.updateMarkAllMentionsSeen(peerId: peerId)
|
viewTracker.updateMarkAllMentionsSeen(peerId: peerId, threadId: nil)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if setToValue == nil || setToValue! {
|
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
|
return account.postbox.transaction { transaction -> Void in
|
||||||
if peerId.namespace == Namespaces.Peer.SecretChat {
|
if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
account.viewTracker.updateMarkAllMentionsSeen(peerId: peerId)
|
account.viewTracker.updateMarkAllMentionsSeen(peerId: peerId, threadId: threadId)
|
||||||
}
|
}
|
||||||
|> ignoreValues
|
|> 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
|
return account.postbox.transaction { transaction -> Void in
|
||||||
if peerId.namespace == Namespaces.Peer.SecretChat {
|
if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
account.viewTracker.updateMarkAllReactionsSeen(peerId: peerId)
|
account.viewTracker.updateMarkAllReactionsSeen(peerId: peerId, threadId: threadId)
|
||||||
}
|
}
|
||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,14 +9,14 @@ public enum EarliestUnseenPersonalMentionMessageResult: Equatable {
|
|||||||
case result(MessageId?)
|
case result(MessageId?)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||||
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenPersonalMessage, additionalData: [.peerChatState(peerId)])
|
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
|
|> mapToSignal { view -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
|
||||||
if view.0.isLoading {
|
if view.0.isLoading {
|
||||||
return .single(.loading)
|
return .single(.loading)
|
||||||
}
|
}
|
||||||
if case .FillHole = view.1 {
|
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 let message = view.0.entries.first?.message {
|
||||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
@ -53,10 +53,10 @@ func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: Pe
|
|||||||
} else {
|
} else {
|
||||||
return account.postbox.transaction { transaction -> EarliestUnseenPersonalMentionMessageResult in
|
return account.postbox.transaction { transaction -> EarliestUnseenPersonalMentionMessageResult in
|
||||||
if let topId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
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))
|
transaction.removeHole(peerId: peerId, threadId: threadId, 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 })
|
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id })
|
||||||
for id in ids {
|
for id in ids {
|
||||||
markUnseenPersonalMessage(transaction: transaction, id: id, addSynchronizeAction: false)
|
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> {
|
func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||||
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenReaction, additionalData: [.peerChatState(peerId)])
|
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
|
|> mapToSignal { view -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
|
||||||
if view.0.isLoading {
|
if view.0.isLoading {
|
||||||
return .single(.loading)
|
return .single(.loading)
|
||||||
}
|
}
|
||||||
if case .FillHole = view.1 {
|
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 let message = view.0.entries.first?.message {
|
||||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
@ -120,10 +120,10 @@ func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: P
|
|||||||
} else {
|
} else {
|
||||||
return account.postbox.transaction { transaction -> EarliestUnseenPersonalMentionMessageResult in
|
return account.postbox.transaction { transaction -> EarliestUnseenPersonalMentionMessageResult in
|
||||||
if let topId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
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))
|
transaction.removeHole(peerId: peerId, threadId: threadId, 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 })
|
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id })
|
||||||
for id in ids {
|
for id in ids {
|
||||||
markUnseenReactionMessage(transaction: transaction, id: id, addSynchronizeAction: false)
|
markUnseenReactionMessage(transaction: transaction, id: id, addSynchronizeAction: false)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import SwiftSignalKit
|
|||||||
import TelegramApi
|
import TelegramApi
|
||||||
|
|
||||||
func _internal_topPeerActiveLiveLocationMessages(viewTracker: AccountViewTracker, accountPeerId: PeerId, peerId: PeerId) -> Signal<(Peer?, [Message]), NoError> {
|
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
|
|> map { (view, _, _) -> (Peer?, [Message]) in
|
||||||
var accountPeer: Peer?
|
var accountPeer: Peer?
|
||||||
for entry in view.additionalData {
|
for entry in view.additionalData {
|
||||||
|
|||||||
@ -325,10 +325,6 @@ private class ReplyThreadHistoryContextImpl {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let _ = self.stateValue else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let fromIdExclusive: Int32?
|
let fromIdExclusive: Int32?
|
||||||
let toIndex = messageIndex
|
let toIndex = messageIndex
|
||||||
if let maxReadIncomingMessageId = self.maxReadIncomingMessageIdValue {
|
if let maxReadIncomingMessageId = self.maxReadIncomingMessageIdValue {
|
||||||
@ -345,6 +341,7 @@ private class ReplyThreadHistoryContextImpl {
|
|||||||
if messageIndex.id.id >= data.maxIncomingReadId {
|
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) {
|
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.incomingUnreadCount = max(0, data.incomingUnreadCount - Int32(count))
|
||||||
|
data.maxIncomingReadId = messageIndex.id.id
|
||||||
}
|
}
|
||||||
|
|
||||||
data.maxKnownMessageId = max(data.maxKnownMessageId, 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
|
return account.postbox.transaction { transaction -> Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError> in
|
||||||
if let initialFilledHoles = initialFilledHoles {
|
if let initialFilledHoles = initialFilledHoles {
|
||||||
for range in initialFilledHoles.strictRemovedIndices.rangeView {
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -189,12 +189,7 @@ public final class SparseMessageList {
|
|||||||
let count: Int
|
let count: Int
|
||||||
count = 200
|
count = 200
|
||||||
|
|
||||||
let location: ChatLocationInput
|
let location: ChatLocationInput = .peer(peerId: self.peerId, threadId: self.threadId)
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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: [])
|
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
|
|> deliverOn(self.queue)).start(next: { [weak self] view, updateType, _ in
|
||||||
|
|||||||
@ -154,32 +154,32 @@ public extension TelegramEngine {
|
|||||||
return PollResultsContext(account: self.account, messageId: messageId, poll: poll)
|
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
|
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
|
|> mapToSignal { result -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
|
||||||
switch result {
|
switch result {
|
||||||
case .loading:
|
case .loading:
|
||||||
return .single(result)
|
return .single(result)
|
||||||
case let .result(messageId):
|
case let .result(messageId):
|
||||||
if messageId == nil {
|
if messageId == nil {
|
||||||
let _ = clearPeerUnseenPersonalMessagesInteractively(account: account, peerId: peerId).start()
|
let _ = clearPeerUnseenPersonalMessagesInteractively(account: account, peerId: peerId, threadId: threadId).start()
|
||||||
}
|
}
|
||||||
return .single(result)
|
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
|
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
|
|> mapToSignal { result -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
|
||||||
switch result {
|
switch result {
|
||||||
case .loading:
|
case .loading:
|
||||||
return .single(result)
|
return .single(result)
|
||||||
case let .result(messageId):
|
case let .result(messageId):
|
||||||
if messageId == nil {
|
if messageId == nil {
|
||||||
let _ = clearPeerUnseenReactionsInteractively(account: account, peerId: peerId).start()
|
let _ = clearPeerUnseenReactionsInteractively(account: account, peerId: peerId, threadId: threadId).start()
|
||||||
}
|
}
|
||||||
return .single(result)
|
return .single(result)
|
||||||
}
|
}
|
||||||
@ -297,7 +297,7 @@ public extension TelegramEngine {
|
|||||||
return SparseMessageScrollingContext(account: self.account, peerId: peerId)
|
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
|
let account = self.account
|
||||||
return self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
return self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||||
@ -312,7 +312,15 @@ public extension TelegramEngine {
|
|||||||
signals.append(.single((nil, nil)))
|
signals.append(.single((nil, nil)))
|
||||||
continue
|
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
|
|> map { result -> (count: Int32?, topId: Int32?) in
|
||||||
switch result {
|
switch result {
|
||||||
case let .messagesSlice(_, count, _, _, messages, _, _):
|
case let .messagesSlice(_, count, _, _, messages, _, _):
|
||||||
@ -335,7 +343,7 @@ public extension TelegramEngine {
|
|||||||
for i in 0 ..< tags.count {
|
for i in 0 ..< tags.count {
|
||||||
let (count, maxId) = counts[i]
|
let (count, maxId) = counts[i]
|
||||||
if let count = count {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -170,7 +170,7 @@ func _internal_requestUnpinAllMessages(account: Account, peerId: PeerId) -> Sign
|
|||||||
}, delayIncrement: 0.0, maxDelay: 0.0, maxRetries: 100, onQueue: .concurrentDefaultQueue())
|
}, delayIncrement: 0.0, maxDelay: 0.0, maxRetries: 100, onQueue: .concurrentDefaultQueue())
|
||||||
|> mapToSignal { _ -> Signal<Never, InternalError> in
|
|> mapToSignal { _ -> Signal<Never, InternalError> in
|
||||||
let signal: Signal<Never, InternalError> = account.postbox.transaction { transaction -> Void 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
|
transaction.updateMessage(index.id, update: { currentMessage in
|
||||||
var storeForwardInfo: StoreMessageForwardInfo?
|
var storeForwardInfo: StoreMessageForwardInfo?
|
||||||
if let forwardInfo = currentMessage.forwardInfo {
|
if let forwardInfo = currentMessage.forwardInfo {
|
||||||
|
|||||||
@ -1,17 +1,41 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Postbox
|
import Postbox
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
import TelegramApi
|
||||||
|
|
||||||
|
func _internal_togglePeerMuted(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<Void, NoError> {
|
||||||
func _internal_togglePeerMuted(account: Account, peerId: PeerId) -> Signal<Void, NoError> {
|
|
||||||
return account.postbox.transaction { transaction -> Void in
|
return account.postbox.transaction { transaction -> Void in
|
||||||
if let peer = transaction.getPeer(peerId) {
|
guard let peer = transaction.getPeer(peerId) else {
|
||||||
var notificationPeerId = peerId
|
return
|
||||||
if let associatedPeerId = peer.associatedPeerId {
|
}
|
||||||
notificationPeerId = associatedPeerId
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
|
let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings
|
||||||
let previousSettings: TelegramPeerNotificationSettings
|
let previousSettings: TelegramPeerNotificationSettings
|
||||||
if let currentSettings = currentSettings {
|
if let currentSettings = currentSettings {
|
||||||
previousSettings = 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
|
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) {
|
if let peer = transaction.getPeer(peerId) {
|
||||||
var notificationPeerId = peerId
|
if let threadId = threadId {
|
||||||
if let associatedPeerId = peer.associatedPeerId {
|
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||||
notificationPeerId = associatedPeerId
|
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
|
||||||
}
|
|
||||||
|
let muteState: PeerMuteState
|
||||||
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
|
if let muteInterval = muteInterval {
|
||||||
let previousSettings: TelegramPeerNotificationSettings
|
if muteInterval == 0 {
|
||||||
if let currentSettings = currentSettings {
|
muteState = .unmuted
|
||||||
previousSettings = currentSettings
|
} else {
|
||||||
} else {
|
let absoluteUntil: Int32
|
||||||
previousSettings = TelegramPeerNotificationSettings.defaultSettings
|
if muteInterval == Int32.max {
|
||||||
}
|
absoluteUntil = Int32.max
|
||||||
|
} else {
|
||||||
let muteState: PeerMuteState
|
absoluteUntil = Int32(Date().timeIntervalSince1970) + muteInterval
|
||||||
if let muteInterval = muteInterval {
|
}
|
||||||
if muteInterval == 0 {
|
muteState = .muted(until: absoluteUntil)
|
||||||
muteState = .unmuted
|
}
|
||||||
} else {
|
|
||||||
let absoluteUntil: Int32
|
|
||||||
if muteInterval == Int32.max {
|
|
||||||
absoluteUntil = Int32.max
|
|
||||||
} else {
|
} 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 {
|
} 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
|
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) {
|
if let peer = transaction.getPeer(peerId) {
|
||||||
var notificationPeerId = peerId
|
if let threadId = threadId {
|
||||||
if let associatedPeerId = peer.associatedPeerId {
|
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||||
notificationPeerId = associatedPeerId
|
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
|
||||||
}
|
|
||||||
|
data.notificationSettings = previousSettings.withUpdatedDisplayPreviews(displayPreviews)
|
||||||
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
|
|
||||||
let previousSettings: TelegramPeerNotificationSettings
|
if let entry = CodableEntry(data) {
|
||||||
if let currentSettings = currentSettings {
|
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
|
||||||
previousSettings = currentSettings
|
}
|
||||||
|
|
||||||
|
//TODO:loc
|
||||||
|
let _ = pushPeerNotificationSettings(postbox: account.postbox, network: account.network, peerId: peerId, threadId: threadId, settings: TelegramPeerNotificationSettings.defaultSettings).start()
|
||||||
|
}
|
||||||
} else {
|
} 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
|
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) {
|
if let peer = transaction.getPeer(peerId) {
|
||||||
var notificationPeerId = peerId
|
if let threadId = threadId {
|
||||||
if let associatedPeerId = peer.associatedPeerId {
|
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||||
notificationPeerId = associatedPeerId
|
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
|
||||||
}
|
|
||||||
|
data.notificationSettings = previousSettings.withUpdatedMessageSound(sound)
|
||||||
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
|
|
||||||
let previousSettings: TelegramPeerNotificationSettings
|
if let entry = CodableEntry(data) {
|
||||||
if let currentSettings = currentSettings {
|
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
|
||||||
previousSettings = currentSettings
|
}
|
||||||
|
|
||||||
|
//TODO:loc
|
||||||
|
let _ = pushPeerNotificationSettings(postbox: account.postbox, network: account.network, peerId: peerId, threadId: threadId, settings: TelegramPeerNotificationSettings.defaultSettings).start()
|
||||||
|
}
|
||||||
} else {
|
} 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.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, threadId: nil, 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: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
|
||||||
|
|
||||||
if let pts = pts {
|
if let pts = pts {
|
||||||
if transaction.getPeerChatState(peerId) == nil {
|
if transaction.getPeerChatState(peerId) == nil {
|
||||||
|
|||||||
@ -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 {
|
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))])
|
transaction.updateCurrentPeerNotificationSettings([peerId: notificationSettings.withUpdatedMuteState(.muted(until: Int32.max))])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -183,28 +183,28 @@ public extension TelegramEngine {
|
|||||||
return _internal_reportRepliesMessage(account: self.account, messageId: messageId, deleteMessage: deleteMessage, deleteHistory: deleteHistory, reportSpam: reportSpam)
|
return _internal_reportRepliesMessage(account: self.account, messageId: messageId, deleteMessage: deleteMessage, deleteHistory: deleteHistory, reportSpam: reportSpam)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func togglePeerMuted(peerId: PeerId) -> Signal<Void, NoError> {
|
public func togglePeerMuted(peerId: PeerId, threadId: Int64?) -> Signal<Void, NoError> {
|
||||||
return _internal_togglePeerMuted(account: self.account, peerId: peerId)
|
return _internal_togglePeerMuted(account: self.account, peerId: peerId, threadId: threadId)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updatePeerMuteSetting(peerId: PeerId, muteInterval: Int32?) -> Signal<Void, NoError> {
|
public func updatePeerMuteSetting(peerId: PeerId, threadId: Int64?, muteInterval: Int32?) -> Signal<Void, NoError> {
|
||||||
return _internal_updatePeerMuteSetting(account: self.account, peerId: peerId, muteInterval: muteInterval)
|
return _internal_updatePeerMuteSetting(account: self.account, peerId: peerId, threadId: threadId, muteInterval: muteInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updatePeerDisplayPreviewsSetting(peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
|
public func updatePeerDisplayPreviewsSetting(peerId: PeerId, threadId: Int64?, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
|
||||||
return _internal_updatePeerDisplayPreviewsSetting(account: self.account, peerId: peerId, displayPreviews: displayPreviews)
|
return _internal_updatePeerDisplayPreviewsSetting(account: self.account, peerId: peerId, threadId: threadId, displayPreviews: displayPreviews)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updatePeerNotificationSoundInteractive(peerId: PeerId, sound: PeerMessageSound) -> Signal<Void, NoError> {
|
public func updatePeerNotificationSoundInteractive(peerId: PeerId, threadId: Int64?, sound: PeerMessageSound) -> Signal<Void, NoError> {
|
||||||
return _internal_updatePeerNotificationSoundInteractive(account: self.account, peerId: peerId, sound: sound)
|
return _internal_updatePeerNotificationSoundInteractive(account: self.account, peerId: peerId, threadId: threadId, sound: sound)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeCustomNotificationSettings(peerIds: [PeerId]) -> Signal<Never, NoError> {
|
public func removeCustomNotificationSettings(peerIds: [PeerId]) -> Signal<Never, NoError> {
|
||||||
return self.account.postbox.transaction { transaction -> Void in
|
return self.account.postbox.transaction { transaction -> Void in
|
||||||
for peerId in peerIds {
|
for peerId in peerIds {
|
||||||
TelegramCore.updatePeerNotificationSoundInteractive(transaction: transaction, peerId: peerId, sound: .default)
|
_internal_updatePeerNotificationSoundInteractive(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, sound: .default)
|
||||||
TelegramCore.updatePeerMuteSetting(transaction: transaction, peerId: peerId, muteInterval: nil)
|
_internal_updatePeerMuteSetting(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, muteInterval: nil)
|
||||||
TelegramCore.updatePeerDisplayPreviewsSetting(transaction: transaction, peerId: peerId, displayPreviews: .default)
|
_internal_updatePeerDisplayPreviewsSetting(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, displayPreviews: .default)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
|
|||||||
@ -71,7 +71,8 @@ public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?,
|
|||||||
}
|
}
|
||||||
case Namespaces.Peer.CloudChannel:
|
case Namespaces.Peer.CloudChannel:
|
||||||
if let channel = updated as? TelegramChannel {
|
if let channel = updated as? TelegramChannel {
|
||||||
switch channel.participationStatus {
|
if case .personal = channel.accessHash {
|
||||||
|
switch channel.participationStatus {
|
||||||
case .member:
|
case .member:
|
||||||
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: channel.creationDate, forceRootGroupIfNotExists: true)
|
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: channel.creationDate, forceRootGroupIfNotExists: true)
|
||||||
case .left:
|
case .left:
|
||||||
@ -80,6 +81,7 @@ public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?,
|
|||||||
transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded)
|
transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded)
|
||||||
default:
|
default:
|
||||||
transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded)
|
transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
|
|||||||
@ -31,7 +31,7 @@ public enum ChatTitleContent {
|
|||||||
case replies
|
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 replyThread(type: ReplyThreadType, count: Int)
|
||||||
case custom(String, String?, Bool)
|
case custom(String, String?, Bool)
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
var titleCredibilityIcon: ChatTitleCredibilityIcon = .none
|
var titleCredibilityIcon: ChatTitleCredibilityIcon = .none
|
||||||
var isEnabled = true
|
var isEnabled = true
|
||||||
switch titleContent {
|
switch titleContent {
|
||||||
case let .peer(peerView, customTitle, _, isScheduledMessages):
|
case let .peer(peerView, customTitle, _, isScheduledMessages, isMuted):
|
||||||
if peerView.peerId.isReplies {
|
if peerView.peerId.isReplies {
|
||||||
let typeText: String = self.strings.DialogList_Replies
|
let typeText: String = self.strings.DialogList_Replies
|
||||||
segments = [.text(0, NSAttributedString(string: typeText, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))]
|
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 {
|
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
titleLeftIcon = .lock
|
titleLeftIcon = .lock
|
||||||
}
|
}
|
||||||
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
|
if let isMuted {
|
||||||
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
|
if isMuted {
|
||||||
if titleCredibilityIcon != .verified {
|
titleRightIcon = .mute
|
||||||
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
|
var inputActivitiesAllowed = true
|
||||||
if let titleContent = self.titleContent {
|
if let titleContent = self.titleContent {
|
||||||
switch titleContent {
|
switch titleContent {
|
||||||
case let .peer(peerView, _, _, isScheduledMessages):
|
case let .peer(peerView, _, _, isScheduledMessages, _):
|
||||||
if let peer = peerViewMainPeer(peerView) {
|
if let peer = peerViewMainPeer(peerView) {
|
||||||
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies {
|
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies {
|
||||||
inputActivitiesAllowed = false
|
inputActivitiesAllowed = false
|
||||||
@ -414,7 +420,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
} else {
|
} else {
|
||||||
if let titleContent = self.titleContent {
|
if let titleContent = self.titleContent {
|
||||||
switch titleContent {
|
switch titleContent {
|
||||||
case let .peer(peerView, _, onlineMemberCount, isScheduledMessages):
|
case let .peer(peerView, _, onlineMemberCount, isScheduledMessages, _):
|
||||||
if let peer = peerViewMainPeer(peerView) {
|
if let peer = peerViewMainPeer(peerView) {
|
||||||
let servicePeer = isServicePeer(peer)
|
let servicePeer = isServicePeer(peer)
|
||||||
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies {
|
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies {
|
||||||
|
|||||||
@ -342,10 +342,14 @@ public final class AccountContextImpl: AccountContext {
|
|||||||
public func chatLocationInput(for location: ChatLocation, contextHolder: Atomic<ChatLocationContextHolder?>) -> ChatLocationInput {
|
public func chatLocationInput(for location: ChatLocation, contextHolder: Atomic<ChatLocationContextHolder?>) -> ChatLocationInput {
|
||||||
switch location {
|
switch location {
|
||||||
case let .peer(peerId):
|
case let .peer(peerId):
|
||||||
return .peer(peerId: peerId)
|
return .peer(peerId: peerId, threadId: nil)
|
||||||
case let .replyThread(data):
|
case let .replyThread(data):
|
||||||
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
|
if data.isForumPost {
|
||||||
return .thread(peerId: data.messageId.peerId, threadId: makeMessageThreadId(data.messageId), data: context.state)
|
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):
|
case let .feed(id):
|
||||||
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
||||||
return .feed(id: id, data: context.state)
|
return .feed(id: id, data: context.state)
|
||||||
@ -357,8 +361,20 @@ public final class AccountContextImpl: AccountContext {
|
|||||||
case .peer:
|
case .peer:
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
case let .replyThread(data):
|
case let .replyThread(data):
|
||||||
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
|
if data.isForumPost, let peerId = location.peerId {
|
||||||
return context.maxReadOutgoingMessageId
|
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):
|
case let .feed(id):
|
||||||
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
||||||
return context.maxReadOutgoingMessageId
|
return context.maxReadOutgoingMessageId
|
||||||
@ -372,18 +388,30 @@ public final class AccountContextImpl: AccountContext {
|
|||||||
return self.account.postbox.combinedView(keys: [unreadCountsKey])
|
return self.account.postbox.combinedView(keys: [unreadCountsKey])
|
||||||
|> map { views in
|
|> map { views in
|
||||||
var unreadCount: Int32 = 0
|
var unreadCount: Int32 = 0
|
||||||
|
|
||||||
if let view = views.views[unreadCountsKey] as? UnreadMessageCountsView {
|
if let view = views.views[unreadCountsKey] as? UnreadMessageCountsView {
|
||||||
if let count = view.count(for: .peer(peerId)) {
|
if let count = view.count(for: .peer(peerId)) {
|
||||||
unreadCount = count
|
unreadCount = count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Int(unreadCount)
|
return Int(unreadCount)
|
||||||
}
|
}
|
||||||
case let .replyThread(data):
|
case let .replyThread(data):
|
||||||
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
|
if data.isForumPost {
|
||||||
return context.unreadCount
|
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):
|
case let .feed(id):
|
||||||
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
||||||
return context.unreadCount
|
return context.unreadCount
|
||||||
|
|||||||
@ -252,7 +252,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
|
|||||||
break
|
break
|
||||||
case .muteNotifications, .unmuteNotifications:
|
case .muteNotifications, .unmuteNotifications:
|
||||||
if let context = self.context, let presentationInterfaceState = self.presentationInterfaceState, let peer = presentationInterfaceState.renderedPeer?.peer {
|
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:
|
case .hidePinnedMessages, .unpinMessages:
|
||||||
self.interfaceInteraction?.unpinAllMessages()
|
self.interfaceInteraction?.unpinAllMessages()
|
||||||
|
|||||||
@ -4384,7 +4384,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if case .pinnedMessages = presentationInterfaceState.subject {
|
if case .pinnedMessages = presentationInterfaceState.subject {
|
||||||
strongSelf.chatTitleView?.titleContent = .custom(presentationInterfaceState.strings.Chat_TitlePinnedMessages(Int32(displayedCount ?? 1)), nil, false)
|
strongSelf.chatTitleView?.titleContent = .custom(presentationInterfaceState.strings.Chat_TitlePinnedMessages(Int32(displayedCount ?? 1)), nil, false)
|
||||||
} else {
|
} 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?
|
let imageOverride: AvatarNodeImageOverride?
|
||||||
if strongSelf.context.account.peerId == peer.id {
|
if strongSelf.context.account.peerId == peer.id {
|
||||||
imageOverride = .savedMessagesIcon
|
imageOverride = .savedMessagesIcon
|
||||||
@ -4741,18 +4741,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let peerView = context.account.viewTracker.peerView(peerId)
|
let peerView = context.account.viewTracker.peerView(peerId)
|
||||||
|
|
||||||
let messageAndTopic = messagePromise.get()
|
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 {
|
guard let message = message else {
|
||||||
return .single((nil, nil))
|
return .single((nil, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: Int64(message.id.id))
|
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: Int64(message.id.id))
|
||||||
return context.account.postbox.combinedView(keys: [viewKey])
|
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 {
|
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
|
||||||
return (message, nil)
|
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 {
|
var peerIsMuted = false
|
||||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: threadInfo.title, onlineMemberCount: onlineMemberCount, isScheduledMessages: 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
|
let avatarContent: EmojiStatusComponent.Content
|
||||||
if let fileId = threadInfo.icon {
|
if let fileId = threadInfo.icon {
|
||||||
@ -4829,12 +4840,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if strongSelf.isNodeLoaded {
|
if strongSelf.isNodeLoaded {
|
||||||
strongSelf.chatDisplayNode.peerView = peerView
|
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 peerDiscussionId: PeerId?
|
||||||
var peerGeoLocation: PeerGeoLocation?
|
var peerGeoLocation: PeerGeoLocation?
|
||||||
var currentSendAsPeerId: PeerId?
|
var currentSendAsPeerId: PeerId?
|
||||||
@ -6813,8 +6819,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.chatDisplayNode.navigateButtons.mentionsPressed = { [weak self] in
|
self.chatDisplayNode.navigateButtons.mentionsPressed = { [weak self] in
|
||||||
if let strongSelf = self, strongSelf.isNodeLoaded, case let .peer(peerId) = strongSelf.chatLocation {
|
if let strongSelf = self, strongSelf.isNodeLoaded, let peerId = strongSelf.chatLocation.peerId {
|
||||||
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalMentionMessage(peerId: peerId)
|
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalMentionMessage(peerId: peerId, threadId: strongSelf.chatLocation.threadId)
|
||||||
strongSelf.navigationActionDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
|
strongSelf.navigationActionDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
switch result {
|
switch result {
|
||||||
@ -6850,10 +6856,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
action: { _, f in
|
action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
guard let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation else {
|
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId else {
|
||||||
return
|
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))
|
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
|
self.chatDisplayNode.navigateButtons.reactionsPressed = { [weak self] in
|
||||||
if let strongSelf = self, strongSelf.isNodeLoaded, case let .peer(peerId) = strongSelf.chatLocation {
|
if let strongSelf = self, strongSelf.isNodeLoaded, let peerId = strongSelf.chatLocation.peerId {
|
||||||
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalReactionMessage(peerId: peerId)
|
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalReactionMessage(peerId: peerId, threadId: strongSelf.chatLocation.threadId)
|
||||||
strongSelf.navigationActionDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
|
strongSelf.navigationActionDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
switch result {
|
switch result {
|
||||||
@ -7017,10 +7023,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
action: { _, f in
|
action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
guard let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation else {
|
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId else {
|
||||||
return
|
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))
|
let items = ContextController.Items(content: .list(menuItems))
|
||||||
@ -7851,7 +7857,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self?.navigationButtonAction(.openChatInfo(expandAvatar: false))
|
self?.navigationButtonAction(.openChatInfo(expandAvatar: false))
|
||||||
}, togglePeerNotifications: { [weak self] in
|
}, togglePeerNotifications: { [weak self] in
|
||||||
if let strongSelf = self, let peerId = strongSelf.chatLocation.peerId {
|
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
|
}, sendContextResult: { [weak self] results, result, node, rect in
|
||||||
guard let strongSelf = self else {
|
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 let strongSelf = self {
|
||||||
if case let .standard(previewing) = strongSelf.presentationInterfaceState.mode, previewing {
|
if case let .standard(previewing) = strongSelf.presentationInterfaceState.mode, previewing {
|
||||||
strongSelf.chatDisplayNode.navigateButtons.mentionCount = 0
|
strongSelf.chatDisplayNode.navigateButtons.mentionCount = 0
|
||||||
|
|||||||
@ -86,6 +86,14 @@ func chatHistoryEntriesForView(
|
|||||||
continue
|
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 let maybeJoinMessage = joinMessage {
|
||||||
if message.timestamp > maybeJoinMessage.timestamp, (!view.holeEarlier || count > 0) {
|
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)))
|
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
||||||
|
|||||||
@ -127,7 +127,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
|
|||||||
return true
|
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
|
self.context = context
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
@ -174,7 +174,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let signal: Signal<([ChatHistorySearchEntry], [MessageId: Message])?, NoError>
|
let signal: Signal<([ChatHistorySearchEntry], [MessageId: Message])?, NoError>
|
||||||
if let query = query, !query.isEmpty {
|
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 }
|
|> map { $0.0.messages }
|
||||||
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
||||||
|
|
||||||
|
|||||||
@ -229,6 +229,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
}, setPeerIdWithRevealedOptions: { _, _ in
|
}, setPeerIdWithRevealedOptions: { _, _ in
|
||||||
}, setItemPinned: { _, _ in
|
}, setItemPinned: { _, _ in
|
||||||
}, setPeerMuted: { _, _ in
|
}, setPeerMuted: { _, _ in
|
||||||
|
}, setPeerThreadMuted: { _, _, _ in
|
||||||
}, deletePeer: { _, _ in
|
}, deletePeer: { _, _ in
|
||||||
}, deletePeerThread: { _, _ in
|
}, deletePeerThread: { _, _ in
|
||||||
}, updatePeerGrouping: { _, _ in
|
}, updatePeerGrouping: { _, _ in
|
||||||
|
|||||||
@ -147,7 +147,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.statusPromise.set(context.engine.data.subscribe(
|
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
|
|> map { count -> PeerInfoStatusData? in
|
||||||
let count: Int = count ?? 0
|
let count: Int = count ?? 0
|
||||||
|
|||||||
@ -2031,7 +2031,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
}
|
}
|
||||||
|
|
||||||
return context.engine.data.subscribe(EngineDataMap(
|
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
|
|> map { summaries -> (ContentType, [MessageTags: Int32]) in
|
||||||
var result: [MessageTags: Int32] = [:]
|
var result: [MessageTags: Int32] = [:]
|
||||||
|
|||||||
@ -187,7 +187,7 @@ final class PeerInfoScreenData {
|
|||||||
let invitations: PeerExportedInvitationsState?
|
let invitations: PeerExportedInvitationsState?
|
||||||
let requests: PeerInvitationImportersState?
|
let requests: PeerInvitationImportersState?
|
||||||
let requestsContext: PeerInvitationImportersContext?
|
let requestsContext: PeerInvitationImportersContext?
|
||||||
let threadInfo: EngineMessageHistoryThread.Info?
|
let threadData: MessageHistoryThreadData?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
peer: Peer?,
|
peer: Peer?,
|
||||||
@ -206,7 +206,7 @@ final class PeerInfoScreenData {
|
|||||||
invitations: PeerExportedInvitationsState?,
|
invitations: PeerExportedInvitationsState?,
|
||||||
requests: PeerInvitationImportersState?,
|
requests: PeerInvitationImportersState?,
|
||||||
requestsContext: PeerInvitationImportersContext?,
|
requestsContext: PeerInvitationImportersContext?,
|
||||||
threadInfo: EngineMessageHistoryThread.Info?
|
threadData: MessageHistoryThreadData?
|
||||||
) {
|
) {
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.chatPeer = chatPeer
|
self.chatPeer = chatPeer
|
||||||
@ -224,7 +224,7 @@ final class PeerInfoScreenData {
|
|||||||
self.invitations = invitations
|
self.invitations = invitations
|
||||||
self.requests = requests
|
self.requests = requests
|
||||||
self.requestsContext = requestsContext
|
self.requestsContext = requestsContext
|
||||||
self.threadInfo = threadInfo
|
self.threadData = threadData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,7 +477,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
invitations: nil,
|
invitations: nil,
|
||||||
requests: nil,
|
requests: nil,
|
||||||
requestsContext: nil,
|
requestsContext: nil,
|
||||||
threadInfo: nil
|
threadData: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -504,7 +504,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
invitations: nil,
|
invitations: nil,
|
||||||
requests: nil,
|
requests: nil,
|
||||||
requestsContext: nil,
|
requestsContext: nil,
|
||||||
threadInfo: nil
|
threadData: nil
|
||||||
))
|
))
|
||||||
case let .user(userPeerId, secretChatId, kind):
|
case let .user(userPeerId, secretChatId, kind):
|
||||||
let groupsInCommon: GroupsInCommonContext?
|
let groupsInCommon: GroupsInCommonContext?
|
||||||
@ -635,7 +635,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
invitations: nil,
|
invitations: nil,
|
||||||
requests: nil,
|
requests: nil,
|
||||||
requestsContext: nil,
|
requestsContext: nil,
|
||||||
threadInfo: nil
|
threadData: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case .channel:
|
case .channel:
|
||||||
@ -711,7 +711,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
invitations: invitations,
|
invitations: invitations,
|
||||||
requests: requests,
|
requests: requests,
|
||||||
requestsContext: currentRequestsContext,
|
requestsContext: currentRequestsContext,
|
||||||
threadInfo: nil
|
threadData: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case let .group(groupId):
|
case let .group(groupId):
|
||||||
@ -815,19 +815,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
let requestsContextPromise = Promise<PeerInvitationImportersContext?>(nil)
|
let requestsContextPromise = Promise<PeerInvitationImportersContext?>(nil)
|
||||||
let requestsStatePromise = Promise<PeerInvitationImportersState?>(nil)
|
let requestsStatePromise = Promise<PeerInvitationImportersState?>(nil)
|
||||||
|
|
||||||
let threadInfo: Signal<EngineMessageHistoryThread.Info?, NoError>
|
let threadData: Signal<MessageHistoryThreadData?, NoError>
|
||||||
if case let .replyThread(message) = chatLocation {
|
if case let .replyThread(message) = chatLocation {
|
||||||
let threadId = Int64(message.messageId.id)
|
let threadId = Int64(message.messageId.id)
|
||||||
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
|
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
|
||||||
threadInfo = context.account.postbox.combinedView(keys: [viewKey])
|
threadData = context.account.postbox.combinedView(keys: [viewKey])
|
||||||
|> map { views -> EngineMessageHistoryThread.Info? in
|
|> map { views -> MessageHistoryThreadData? in
|
||||||
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
|
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return view.info?.get(MessageHistoryThreadData.self)?.info
|
return view.info?.get(MessageHistoryThreadData.self)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
threadInfo = .single(nil)
|
threadData = .single(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return combineLatest(queue: .mainQueue(),
|
return combineLatest(queue: .mainQueue(),
|
||||||
@ -840,9 +840,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
invitationsStatePromise.get(),
|
invitationsStatePromise.get(),
|
||||||
requestsContextPromise.get(),
|
requestsContextPromise.get(),
|
||||||
requestsStatePromise.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?
|
var discussionPeer: Peer?
|
||||||
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
||||||
discussionPeer = peer
|
discussionPeer = peer
|
||||||
@ -882,13 +882,20 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
requestsStatePromise.set(requestsContext.state |> map(Optional.init))
|
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(
|
return PeerInfoScreenData(
|
||||||
peer: peerView.peers[groupId],
|
peer: peerView.peers[groupId],
|
||||||
chatPeer: peerView.peers[groupId],
|
chatPeer: peerView.peers[groupId],
|
||||||
cachedData: peerView.cachedData,
|
cachedData: peerView.cachedData,
|
||||||
status: status,
|
status: status,
|
||||||
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
notificationSettings: notificationSettings,
|
||||||
globalNotificationSettings: globalNotificationSettings,
|
globalNotificationSettings: globalNotificationSettings,
|
||||||
isContact: peerView.peerIsContact,
|
isContact: peerView.peerIsContact,
|
||||||
availablePanes: availablePanes ?? [],
|
availablePanes: availablePanes ?? [],
|
||||||
@ -900,20 +907,29 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
invitations: invitations,
|
invitations: invitations,
|
||||||
requests: requests,
|
requests: requests,
|
||||||
requestsContext: currentRequestsContext,
|
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 {
|
if context.account.peerId == peer?.id {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if let channel = peer as? TelegramChannel {
|
if let channel = peer as? TelegramChannel {
|
||||||
if channel.hasPermission(.changeInfo) {
|
if let threadData = threadData {
|
||||||
return true
|
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 {
|
} else if let group = peer as? TelegramGroup {
|
||||||
switch group.role {
|
switch group.role {
|
||||||
|
|||||||
@ -634,7 +634,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
|
|||||||
transition.updateAlpha(node: self, alpha: 1.0 - fraction)
|
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 {
|
guard let peer = peer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -644,7 +644,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
|
|||||||
|
|
||||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .linear)
|
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
|
var overlayHidden = true
|
||||||
if let updatingAvatar = updatingAvatar {
|
if let updatingAvatar = updatingAvatar {
|
||||||
overlayHidden = false
|
overlayHidden = false
|
||||||
@ -730,12 +730,12 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var removedPhotoResourceIds = Set<String>()
|
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 {
|
guard let peer = peer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let canEdit = canEditPeerInfo(context: self.context, peer: peer)
|
let canEdit = canEditPeerInfo(context: self.context, peer: peer, threadData: threadData)
|
||||||
|
|
||||||
let previousItem = self.item
|
let previousItem = self.item
|
||||||
var item = item
|
var item = item
|
||||||
@ -1906,14 +1906,14 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
|||||||
self.itemNodes[key]?.layer.addShakeAnimation()
|
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 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))
|
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()))
|
transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize()))
|
||||||
|
|
||||||
var contentHeight: CGFloat = statusBarHeight + 10.0 + avatarSize + 20.0
|
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 {
|
if self.avatarButtonNode.supernode == nil {
|
||||||
self.addSubnode(self.avatarButtonNode)
|
self.addSubnode(self.avatarButtonNode)
|
||||||
}
|
}
|
||||||
@ -1936,12 +1936,12 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
} else if let _ = peer as? TelegramGroup {
|
} else if let _ = peer as? TelegramGroup {
|
||||||
fieldKeys.append(.title)
|
fieldKeys.append(.title)
|
||||||
if canEditPeerInfo(context: self.context, peer: peer) {
|
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
|
||||||
fieldKeys.append(.description)
|
fieldKeys.append(.description)
|
||||||
}
|
}
|
||||||
} else if let _ = peer as? TelegramChannel {
|
} else if let _ = peer as? TelegramChannel {
|
||||||
fieldKeys.append(.title)
|
fieldKeys.append(.title)
|
||||||
if canEditPeerInfo(context: self.context, peer: peer) {
|
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
|
||||||
fieldKeys.append(.description)
|
fieldKeys.append(.description)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1995,10 +1995,10 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
placeholder = presentationData.strings.GroupInfo_GroupNamePlaceholder
|
placeholder = presentationData.strings.GroupInfo_GroupNamePlaceholder
|
||||||
}
|
}
|
||||||
isEnabled = canEditPeerInfo(context: self.context, peer: peer)
|
isEnabled = canEditPeerInfo(context: self.context, peer: peer, threadData: threadData)
|
||||||
case .description:
|
case .description:
|
||||||
placeholder = presentationData.strings.Channel_Edit_AboutItem
|
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)
|
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)))
|
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 presentationData: PresentationData?
|
||||||
private var state: PeerInfoState?
|
private var state: PeerInfoState?
|
||||||
private var peer: Peer?
|
private var peer: Peer?
|
||||||
|
private var threadData: MessageHistoryThreadData?
|
||||||
private var avatarSize: CGFloat?
|
private var avatarSize: CGFloat?
|
||||||
|
|
||||||
private let isOpenedFromChat: Bool
|
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 {
|
guard let strongSelf = self, let state = strongSelf.state, let peer = strongSelf.peer, let presentationData = strongSelf.presentationData, let avatarSize = strongSelf.avatarSize else {
|
||||||
return
|
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
|
self.avatarListNode.animateOverlaysFadeIn = { [weak self] in
|
||||||
@ -2344,9 +2345,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
private var currentCredibilityIcon: CredibilityIcon?
|
private var currentCredibilityIcon: CredibilityIcon?
|
||||||
|
|
||||||
private var currentPanelStatusData: PeerInfoStatusData?
|
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.state = state
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
|
self.threadData = threadData
|
||||||
self.avatarListNode.listContainerNode.peer = peer
|
self.avatarListNode.listContainerNode.peer = peer
|
||||||
|
|
||||||
let previousPanelStatusData = self.currentPanelStatusData
|
let previousPanelStatusData = self.currentPanelStatusData
|
||||||
@ -2503,7 +2505,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
self.buttonsContainerNode.alpha = self.regularContentNode.alpha
|
self.buttonsContainerNode.alpha = self.regularContentNode.alpha
|
||||||
self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0
|
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)))
|
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)
|
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 expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
|
||||||
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
|
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 isPremium = false
|
||||||
var isVerified = false
|
var isVerified = false
|
||||||
@ -2591,8 +2593,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
title = presentationData.strings.Conversation_SavedMessages
|
title = presentationData.strings.Conversation_SavedMessages
|
||||||
} else if peer.id == self.context.account.peerId && !self.isSettings {
|
} else if peer.id == self.context.account.peerId && !self.isSettings {
|
||||||
title = presentationData.strings.DialogList_Replies
|
title = presentationData.strings.DialogList_Replies
|
||||||
} else if let threadInfo = threadInfo {
|
} else if let threadData = threadData {
|
||||||
title = threadInfo.title
|
title = threadData.info.title
|
||||||
} else {
|
} else {
|
||||||
title = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
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))
|
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)
|
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)
|
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
|
let subtitleColor: UIColor = presentationData.theme.list.itemSecondaryTextColor
|
||||||
|
|
||||||
//TODO:localize
|
//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.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, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
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, 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 {
|
if additive {
|
||||||
transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale)
|
transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale)
|
||||||
transition.updateSublayerTransformScaleAdditive(node: self.avatarOverlayNode, scale: avatarScale)
|
transition.updateSublayerTransformScaleAdditive(node: self.avatarOverlayNode, scale: avatarScale)
|
||||||
|
|||||||
@ -1078,7 +1078,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
let ItemMembers = 6
|
let ItemMembers = 6
|
||||||
let ItemMemberRequests = 7
|
let ItemMemberRequests = 7
|
||||||
|
|
||||||
if let _ = data.threadInfo {
|
if let _ = data.threadData {
|
||||||
let mainUsername: String
|
let mainUsername: String
|
||||||
if let addressName = channel.addressName {
|
if let addressName = channel.addressName {
|
||||||
mainUsername = 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: {
|
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()
|
interaction.editingOpenStickerPackSetup()
|
||||||
}))
|
}))
|
||||||
@ -2817,7 +2817,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
case .edit:
|
case .edit:
|
||||||
if case let .replyThread(message) = strongSelf.chatLocation {
|
if case let .replyThread(message) = strongSelf.chatLocation {
|
||||||
let threadId = Int64(message.messageId.id)
|
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))
|
let controller = ForumCreateTopicScreen(context: strongSelf.context, peerId: strongSelf.peerId, mode: .edit(topic: threadInfo))
|
||||||
controller.navigationPresentation = .modal
|
controller.navigationPresentation = .modal
|
||||||
let context = strongSelf.context
|
let context = strongSelf.context
|
||||||
@ -2990,7 +2990,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
} else {
|
} else {
|
||||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
|
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 title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? ""
|
||||||
let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? ""
|
let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? ""
|
||||||
|
|
||||||
@ -3049,7 +3049,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
|
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 title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? ""
|
||||||
let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? ""
|
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 {
|
deinit {
|
||||||
@ -3557,7 +3557,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
self.view.endEditing(true)
|
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)
|
self?.view.endEditing(true)
|
||||||
}, present: { [weak self] c, a in
|
}, present: { [weak self] c, a in
|
||||||
self?.controller?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
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)
|
self.requestCall(isVideo: false, gesture: gesture)
|
||||||
case .mute:
|
case .mute:
|
||||||
if let notificationSettings = self.data?.notificationSettings, case .muted = notificationSettings.muteState {
|
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
|
let iconColor: UIColor = .white
|
||||||
self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
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)
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
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)
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
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)
|
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 {
|
guard let strongSelf = self, let peer = strongSelf.data?.peer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let threadId = strongSelf.chatLocation.threadId
|
||||||
|
|
||||||
let context = strongSelf.context
|
let context = strongSelf.context
|
||||||
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
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
|
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
|
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
|
let mode: NotificationExceptionMode
|
||||||
@ -4063,7 +4064,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
mode = .groups([:])
|
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)
|
let _ = (updatePeerSound(peer.id, sound)
|
||||||
|> deliverOnMainQueue).start(next: { _ in
|
|> deliverOnMainQueue).start(next: { _ in
|
||||||
|
|
||||||
@ -4107,7 +4108,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
return
|
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
|
let iconColor: UIColor = .white
|
||||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
|
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)
|
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 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?.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?.threadData?.info))
|
||||||
|
|
||||||
let filteredButtons = allHeaderButtons.subtracting(headerButtons)
|
let filteredButtons = allHeaderButtons.subtracting(headerButtons)
|
||||||
|
|
||||||
@ -4820,9 +4821,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if value <= 0 {
|
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 {
|
} 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)
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
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
|
soundController.navigationPresentation = .modal
|
||||||
strongSelf.controller?.push(soundController)
|
strongSelf.controller?.push(soundController)
|
||||||
@ -5277,7 +5278,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
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.view.endEditing(true)
|
||||||
strongSelf.controller?.present(muteSettingsController, in: .window(.root))
|
strongSelf.controller?.present(muteSettingsController, in: .window(.root))
|
||||||
@ -5298,7 +5299,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
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)
|
strongSelf.controller?.push(soundController)
|
||||||
})
|
})
|
||||||
@ -5310,7 +5311,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
guard let strongSelf = self, let peer = peer else {
|
guard let strongSelf = self, let peer = peer else {
|
||||||
return
|
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 = {}) {
|
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
|
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()
|
self?.deactivateSearch()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -7364,8 +7365,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
let peerId = self.peerId
|
let peerId = self.peerId
|
||||||
|
|
||||||
let _ = (self.context.engine.data.get(EngineDataMap([
|
let _ = (self.context.engine.data.get(EngineDataMap([
|
||||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: .photo),
|
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: self.chatLocation.threadId, tag: .photo),
|
||||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: .video)
|
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: self.chatLocation.threadId, tag: .video)
|
||||||
]))
|
]))
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] messageCounts in
|
|> deliverOnMainQueue).start(next: { [weak self] messageCounts in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -7417,17 +7418,19 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
items.append(.action(generateAction(false)))
|
items.append(.action(generateAction(false)))
|
||||||
|
|
||||||
var ignoreNextActions = false
|
var ignoreNextActions = false
|
||||||
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowCalendar, icon: { theme in
|
if strongSelf.chatLocation.threadId == nil {
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.contextMenu.primaryColor)
|
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowCalendar, icon: { theme in
|
||||||
}, action: { _, a in
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.contextMenu.primaryColor)
|
||||||
if ignoreNextActions {
|
}, action: { _, a in
|
||||||
return
|
if ignoreNextActions {
|
||||||
}
|
return
|
||||||
ignoreNextActions = true
|
}
|
||||||
a(.default)
|
ignoreNextActions = true
|
||||||
|
a(.default)
|
||||||
self?.openMediaCalendar()
|
|
||||||
})))
|
self?.openMediaCalendar()
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
if photoCount != 0 && videoCount != 0 {
|
if photoCount != 0 && videoCount != 0 {
|
||||||
items.append(.separator)
|
items.append(.separator)
|
||||||
@ -7665,7 +7668,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
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 {
|
if !self.isSettings && !self.state.isEditing {
|
||||||
headerHeight += 71.0
|
headerHeight += 71.0
|
||||||
}
|
}
|
||||||
@ -8025,7 +8028,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
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
|
let paneAreaExpansionDistance: CGFloat = 32.0
|
||||||
@ -9042,7 +9045,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
|
|||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
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
|
let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height
|
||||||
|
|||||||
@ -880,7 +880,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
|
|||||||
animationTimer.start()
|
animationTimer.start()
|
||||||
|
|
||||||
self.statusPromise.set(context.engine.data.subscribe(
|
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
|
|> map { count -> PeerInfoStatusData? in
|
||||||
let count: Int = count ?? 0
|
let count: Int = count ?? 0
|
||||||
@ -925,7 +925,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.isRequestingView = true
|
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
|
|> deliverOnMainQueue).start(next: { [weak self] (view, updateType, _) in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -213,7 +213,7 @@ private final class PrefetchManagerInnerImpl {
|
|||||||
context = PrefetchMediaContext()
|
context = PrefetchMediaContext()
|
||||||
self.contexts[id] = context
|
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 {
|
if case .full = automaticDownload {
|
||||||
let fetchSignal = freeMediaFileInteractiveFetched(fetchManager: self.fetchManager, fileReference: .standalone(media: media), priority: priority)
|
let fetchSignal = freeMediaFileInteractiveFetched(fetchManager: self.fetchManager, fileReference: .standalone(media: media), priority: priority)
|
||||||
|
|||||||
@ -91,7 +91,7 @@ final class WatchChatMessagesHandler: WatchRequestHandler {
|
|||||||
|> take(1)
|
|> take(1)
|
||||||
|> mapToSignal({ context -> Signal<(MessageHistoryView, Bool, PresentationData), NoError> in
|
|> mapToSignal({ context -> Signal<(MessageHistoryView, Bool, PresentationData), NoError> in
|
||||||
if let context = context {
|
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
|
|> map { messageHistoryView, _, _ -> (MessageHistoryView, Bool, PresentationData) in
|
||||||
return (messageHistoryView, peerId == context.account.peerId, context.sharedContext.currentPresentationData.with { $0 })
|
return (messageHistoryView, peerId == context.account.peerId, context.sharedContext.currentPresentationData.with { $0 })
|
||||||
}
|
}
|
||||||
@ -833,7 +833,7 @@ final class WatchPeerSettingsHandler: WatchRequestHandler {
|
|||||||
var signal: Signal<Void, NoError>?
|
var signal: Signal<Void, NoError>?
|
||||||
|
|
||||||
if let args = subscription as? TGBridgePeerUpdateNotificationSettingsSubscription, let peerId = makePeerIdFromBridgeIdentifier(args.peerId) {
|
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) {
|
} else if let args = subscription as? TGBridgePeerUpdateBlockStatusSubscription, let peerId = makePeerIdFromBridgeIdentifier(args.peerId) {
|
||||||
signal = context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peerId, isBlocked: args.blocked)
|
signal = context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peerId, isBlocked: args.blocked)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user