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 {
|
||||
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: index.messageIndex.id.peerId), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: .combinedLocation)
|
||||
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: index.messageIndex.id.peerId, threadId: nil), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: .combinedLocation)
|
||||
|> take(1)
|
||||
|> map { view -> [INMessage] in
|
||||
var messages: [INMessage] = []
|
||||
|
||||
@ -8114,3 +8114,5 @@ Sorry for the inconvenience.";
|
||||
|
||||
"ChatList.StartAction" = "Start";
|
||||
"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 {
|
||||
var isMuted = false
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(peer.id) as? TelegramPeerNotificationSettings {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(id: peer.id) as? TelegramPeerNotificationSettings {
|
||||
isMuted = notificationSettings.isRemovedFromTotalUnreadCount(default: false)
|
||||
}
|
||||
badge = WidgetDataPeer.Badge(
|
||||
|
||||
@ -397,7 +397,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
isMuted = true
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: isMuted ? strings.ChatList_Context_Unmute : strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
|
||||
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId, threadId: nil)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
|
||||
@ -492,7 +492,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
return
|
||||
}
|
||||
|
||||
chatTitleView.titleContent = .peer(peerView: peerView, customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false)
|
||||
chatTitleView.titleContent = .peer(peerView: peerView, customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: nil)
|
||||
strongSelf.infoReady.set(.single(true))
|
||||
|
||||
if let channel = peerView.peers[peerView.peerId] as? TelegramChannel, !channel.flags.contains(.isForum) {
|
||||
@ -2468,6 +2468,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
|
||||
public static func openMoreMenu(context: AccountContext, peerId: EnginePeer.Id, sourceController: ViewController, isViewingAsTopics: Bool, sourceView: UIView, gesture: ContextGesture?) {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
guard case let .channel(channel) = peer else {
|
||||
return
|
||||
}
|
||||
|
||||
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
@ -2521,6 +2527,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
})
|
||||
})))
|
||||
|
||||
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)
|
||||
@ -2537,10 +2544,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
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(.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
|
||||
@ -2548,7 +2555,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
sourceController?.beginMessageSearch("")
|
||||
})))
|
||||
} else {
|
||||
} 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)
|
||||
@ -2574,6 +2583,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: sourceController, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
sourceController.presentInGlobalOverlay(contextController)
|
||||
})
|
||||
}
|
||||
|
||||
private var initializedFilters = false
|
||||
|
||||
@ -183,7 +183,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
||||
let timestamp1: Int32 = 100000
|
||||
let peers: [EnginePeer.Id: EnginePeer] = [:]
|
||||
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture, _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture, _ in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
||||
|
||||
@ -1741,6 +1741,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
}, setPeerIdWithRevealedOptions: { _, _ in
|
||||
}, setItemPinned: { _, _ in
|
||||
}, setPeerMuted: { _, _ in
|
||||
}, setPeerThreadMuted: { _, _, _ in
|
||||
}, deletePeer: { _, _ in
|
||||
}, deletePeerThread: { _, _ in
|
||||
}, updatePeerGrouping: { _, _ in
|
||||
@ -2952,7 +2953,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||
var peers: [EnginePeer.Id: EnginePeer] = [:]
|
||||
peers[peer1.id] = peer1
|
||||
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture, _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture, _ in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
||||
|
||||
@ -2688,6 +2688,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
switch option.key {
|
||||
case RevealOptionKey.delete.rawValue:
|
||||
item.interaction.deletePeerThread(peerId, threadId)
|
||||
case RevealOptionKey.mute.rawValue:
|
||||
item.interaction.setPeerThreadMuted(peerId, threadId, true)
|
||||
close = false
|
||||
case RevealOptionKey.unmute.rawValue:
|
||||
item.interaction.setPeerThreadMuted(peerId, threadId, false)
|
||||
close = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ public final class ChatListNodeInteraction {
|
||||
let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void
|
||||
let setItemPinned: (EngineChatList.PinnedItem.Id, Bool) -> Void
|
||||
let setPeerMuted: (EnginePeer.Id, Bool) -> Void
|
||||
let setPeerThreadMuted: (EnginePeer.Id, Int64?, Bool) -> Void
|
||||
let deletePeer: (EnginePeer.Id, Bool) -> Void
|
||||
let deletePeerThread: (EnginePeer.Id, Int64) -> Void
|
||||
let updatePeerGrouping: (EnginePeer.Id, Bool) -> Void
|
||||
@ -98,6 +99,7 @@ public final class ChatListNodeInteraction {
|
||||
setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void,
|
||||
setItemPinned: @escaping (EngineChatList.PinnedItem.Id, Bool) -> Void,
|
||||
setPeerMuted: @escaping (EnginePeer.Id, Bool) -> Void,
|
||||
setPeerThreadMuted: @escaping (EnginePeer.Id, Int64?, Bool) -> Void,
|
||||
deletePeer: @escaping (EnginePeer.Id, Bool) -> Void,
|
||||
deletePeerThread: @escaping (EnginePeer.Id, Int64) -> Void,
|
||||
updatePeerGrouping: @escaping (EnginePeer.Id, Bool) -> Void,
|
||||
@ -119,6 +121,7 @@ public final class ChatListNodeInteraction {
|
||||
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
||||
self.setItemPinned = setItemPinned
|
||||
self.setPeerMuted = setPeerMuted
|
||||
self.setPeerThreadMuted = setPeerThreadMuted
|
||||
self.deletePeer = deletePeer
|
||||
self.deletePeerThread = deletePeerThread
|
||||
self.updatePeerGrouping = updatePeerGrouping
|
||||
@ -946,7 +949,7 @@ public final class ChatListNode: ListView {
|
||||
return
|
||||
}
|
||||
strongSelf.setCurrentRemovingPeerId(peerId)
|
||||
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
|
||||
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId, threadId: nil)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
self?.updateState { state in
|
||||
var state = state
|
||||
@ -955,6 +958,17 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
self?.setCurrentRemovingPeerId(nil)
|
||||
})
|
||||
}, setPeerThreadMuted: { [weak self] peerId, threadId, _ in
|
||||
//self?.setCurrentRemovingPeerId(peerId)
|
||||
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId, threadId: threadId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
self?.updateState { state in
|
||||
var state = state
|
||||
state.peerIdWithRevealedOptions = nil
|
||||
return state
|
||||
}
|
||||
//self?.setCurrentRemovingPeerId(nil)
|
||||
})
|
||||
}, deletePeer: { [weak self] peerId, joined in
|
||||
self?.deletePeerChat?(peerId, joined)
|
||||
}, deletePeerThread: { [weak self] peerId, threadId in
|
||||
@ -1799,8 +1813,11 @@ public final class ChatListNode: ListView {
|
||||
if let combinedReadState = combinedReadState {
|
||||
hasUnread = combinedReadState.count > 0
|
||||
}
|
||||
if case let .chatList(index) = index {
|
||||
preloadItems.append(ChatHistoryPreloadItem(index: index, isMuted: isMuted, hasUnread: hasUnread))
|
||||
switch index {
|
||||
case let .chatList(index):
|
||||
preloadItems.append(ChatHistoryPreloadItem(index: index, threadId: nil, isMuted: isMuted, hasUnread: hasUnread))
|
||||
case .forum:
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
||||
@ -166,7 +166,27 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
||||
}
|
||||
}
|
||||
case let .forum(peerId):
|
||||
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(id: peerId)
|
||||
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(
|
||||
id: peerId,
|
||||
summaryComponents: ChatListEntrySummaryComponents(
|
||||
components: [
|
||||
ChatListEntryMessageTagSummaryKey(
|
||||
tag: .unseenPersonalMessage,
|
||||
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
|
||||
): ChatListEntrySummaryComponents.Component(
|
||||
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
|
||||
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
|
||||
),
|
||||
ChatListEntryMessageTagSummaryKey(
|
||||
tag: .unseenReaction,
|
||||
actionType: PendingMessageActionType.readReaction
|
||||
): ChatListEntrySummaryComponents.Component(
|
||||
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
|
||||
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
var isFirst = false
|
||||
return account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> ChatListNodeViewUpdate in
|
||||
@ -182,18 +202,41 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
||||
guard let data = item.info.get(MessageHistoryThreadData.self) else {
|
||||
continue
|
||||
}
|
||||
|
||||
var hasUnseenMentions = false
|
||||
|
||||
var isMuted = false
|
||||
if case .muted = data.notificationSettings.muteState {
|
||||
isMuted = true
|
||||
}
|
||||
|
||||
if let info = item.tagSummaryInfo[ChatListEntryMessageTagSummaryKey(
|
||||
tag: .unseenPersonalMessage,
|
||||
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
|
||||
)] {
|
||||
hasUnseenMentions = (info.tagSummaryCount ?? 0) > (info.actionsSummaryCount ?? 0)
|
||||
}
|
||||
|
||||
var hasUnseenReactions = false
|
||||
if let info = item.tagSummaryInfo[ChatListEntryMessageTagSummaryKey(
|
||||
tag: .unseenReaction,
|
||||
actionType: PendingMessageActionType.readReaction
|
||||
)] {
|
||||
hasUnseenReactions = (info.tagSummaryCount ?? 0) != 0// > (info.actionsSummaryCount ?? 0)
|
||||
}
|
||||
|
||||
items.append(EngineChatList.Item(
|
||||
id: .forum(item.id),
|
||||
index: .forum(timestamp: item.index.timestamp, threadId: item.id, namespace: item.index.id.namespace, id: item.index.id.id),
|
||||
messages: item.topMessage.flatMap { [EngineMessage($0)] } ?? [],
|
||||
readCounters: EnginePeerReadCounters(state: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, .idBased(maxIncomingReadId: 1, maxOutgoingReadId: 1, maxKnownId: 1, count: data.incomingUnreadCount, markedUnread: false))])),
|
||||
isMuted: false,
|
||||
isMuted: isMuted,
|
||||
draft: nil,
|
||||
threadInfo: data.info,
|
||||
renderedPeer: EngineRenderedPeer(peer: EnginePeer(peer)),
|
||||
presence: nil,
|
||||
hasUnseenMentions: false,
|
||||
hasUnseenReactions: false,
|
||||
hasUnseenMentions: hasUnseenMentions,
|
||||
hasUnseenReactions: hasUnseenReactions,
|
||||
forumTopicTitle: nil,
|
||||
hasFailed: false,
|
||||
isContact: false
|
||||
|
||||
@ -18,6 +18,17 @@ public extension ChatLocation {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var threadId: Int64? {
|
||||
switch self {
|
||||
case .peer:
|
||||
return nil
|
||||
case let .replyThread(replyThreadMessage):
|
||||
return Int64(replyThreadMessage.messageId.id)
|
||||
case .feed:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChatPresentationInputQueryKind: Int32 {
|
||||
|
||||
@ -76,6 +76,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
||||
}, setPeerIdWithRevealedOptions: { _, _ in
|
||||
}, setItemPinned: { _, _ in
|
||||
}, setPeerMuted: { _, _ in
|
||||
}, setPeerThreadMuted: { _, _, _ in
|
||||
}, deletePeer: { _, _ in
|
||||
}, deletePeerThread: { _, _ 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) {
|
||||
return isGroup ? strings.Group_EditAdmin_PermissionChangeInfo : strings.Channel_EditAdmin_PermissionChangeInfo
|
||||
} else if right.contains(.canPostMessages) {
|
||||
@ -438,7 +438,11 @@ private func stringForRight(strings: PresentationStrings, right: TelegramChatAdm
|
||||
return strings.Channel_EditAdmin_PermissionInviteSubscribers
|
||||
}
|
||||
} else if right.contains(.canPinMessages) {
|
||||
if isForum {
|
||||
return strings.Channel_EditAdmin_PermissionCreateTopics
|
||||
} else {
|
||||
return strings.Channel_EditAdmin_PermissionPinMessages
|
||||
}
|
||||
} else if right.contains(.canAddAdmins) {
|
||||
return strings.Channel_EditAdmin_PermissionAddAdmins
|
||||
} else if right.contains(.canBeAnonymous) {
|
||||
@ -612,7 +616,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
if accountUserRightsFlags.contains(right) {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), right == .canBeAnonymous))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, isForum: channel.flags.contains(.isForum), defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), right == .canBeAnonymous))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -651,7 +655,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
if accountUserRightsFlags.contains(right) {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && admin.id != accountPeerId && !rightEnabledByDefault(channelPeer: channel, right: right)))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, isForum: channel.flags.contains(.isForum), defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && admin.id != accountPeerId && !rightEnabledByDefault(channelPeer: channel, right: right)))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -683,7 +687,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
} else if let initialParticipant = initialParticipant, case let .member(_, _, maybeAdminInfo, _, _) = initialParticipant, let adminInfo = maybeAdminInfo {
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, adminInfo.rights.rights, adminInfo.rights.rights.contains(right), false))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, isForum: channel.flags.contains(.isForum), defaultBannedRights: channel.defaultBannedRights), right, adminInfo.rights.rights, adminInfo.rights.rights.contains(right), false))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -782,7 +786,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
if accountUserRightsFlags.contains(right) {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: group.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && accountIsCreator))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, isForum: false, defaultBannedRights: group.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && accountIsCreator))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,7 +293,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
|
||||
var index = 0
|
||||
for (right, _) in allGroupPermissionList {
|
||||
let defaultEnabled = !defaultBannedRights.flags.contains(right) && channel.hasPermission(.banMembers)
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForGroupPermission(strings: presentationData.strings, right: right), right, defaultEnabled && !currentRightsFlags.contains(right), defaultEnabled && !state.updating))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForGroupPermission(strings: presentationData.strings, right: right, isForum: channel.flags.contains(.isForum)), right, defaultEnabled && !currentRightsFlags.contains(right), defaultEnabled && !state.updating))
|
||||
index += 1
|
||||
}
|
||||
|
||||
@ -339,7 +339,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
|
||||
var index = 0
|
||||
for (right, _) in allGroupPermissionList {
|
||||
let defaultEnabled = !defaultBannedRightsFlags.contains(right)
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForGroupPermission(strings: presentationData.strings, right: right), right, defaultEnabled && !currentRightsFlags.contains(right), defaultEnabled && !state.updating))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForGroupPermission(strings: presentationData.strings, right: right, isForum: false), right, defaultEnabled && !currentRightsFlags.contains(right), defaultEnabled && !state.updating))
|
||||
index += 1
|
||||
}
|
||||
|
||||
|
||||
@ -336,7 +336,7 @@ private struct ChannelPermissionsControllerState: Equatable {
|
||||
var modifiedSlowmodeTimeout: Int32?
|
||||
}
|
||||
|
||||
func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatBannedRightsFlags) -> String {
|
||||
func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatBannedRightsFlags, isForum: Bool) -> String {
|
||||
if right.contains(.banSendMessages) {
|
||||
return strings.Channel_BanUser_PermissionSendMessages
|
||||
} else if right.contains(.banSendMedia) {
|
||||
@ -352,7 +352,11 @@ func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatB
|
||||
} else if right.contains(.banAddMembers) {
|
||||
return strings.Channel_BanUser_PermissionAddMembers
|
||||
} else if right.contains(.banPinMessages) {
|
||||
if isForum {
|
||||
return strings.Channel_EditAdmin_PermissionCreateTopics
|
||||
} else {
|
||||
return strings.Channel_EditAdmin_PermissionPinMessages
|
||||
}
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
@ -442,7 +446,7 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
|
||||
if !channel.hasPermission(correspondingAdminRight) {
|
||||
enabled = false
|
||||
}
|
||||
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights), !effectiveRightsFlags.contains(rights), rights, enabled))
|
||||
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights, isForum: channel.flags.contains(.isForum)), !effectiveRightsFlags.contains(rights), rights, enabled))
|
||||
rightIndex += 1
|
||||
}
|
||||
|
||||
@ -479,7 +483,7 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
|
||||
entries.append(.permissionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_SectionTitle))
|
||||
var rightIndex: Int = 0
|
||||
for (rights, _) in allGroupPermissionList {
|
||||
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights), !effectiveRightsFlags.contains(rights), rights, true))
|
||||
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights, isForum: false), !effectiveRightsFlags.contains(rights), rights, true))
|
||||
rightIndex += 1
|
||||
}
|
||||
|
||||
|
||||
@ -260,7 +260,7 @@ final class ChatListTable: Table {
|
||||
|
||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(messageIndex.id.peerId))
|
||||
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: filterPredicate.messageTagSummary)
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: filterPredicate.messageTagSummary)
|
||||
|
||||
if filterPredicate.pinnedPeerIds.contains(peer.id) {
|
||||
passFilter = true
|
||||
@ -895,7 +895,7 @@ final class ChatListTable: Table {
|
||||
}
|
||||
var tagSummary: MessageHistoryTagNamespaceSummary?
|
||||
if let summaryTag = summaryTag {
|
||||
tagSummary = summaryTable.get(MessageHistoryTagsSummaryKey(tag: summaryTag, peerId: peerIndex.messageIndex.id.peerId, namespace: namespace))
|
||||
tagSummary = summaryTable.get(MessageHistoryTagsSummaryKey(tag: summaryTag, peerId: peerIndex.messageIndex.id.peerId, threadId: nil, namespace: namespace))
|
||||
}
|
||||
var topMessageAttributes: [MessageAttribute] = []
|
||||
if let topMessage = topMessage {
|
||||
|
||||
@ -10,7 +10,7 @@ public struct ChatListEntryMessageTagSummaryKey: Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatListEntryMessageTagSummaryComponent {
|
||||
public struct ChatListEntryMessageTagSummaryComponent: Equatable {
|
||||
public let namespace: MessageId.Namespace
|
||||
|
||||
public init(namespace: MessageId.Namespace) {
|
||||
@ -18,7 +18,7 @@ public struct ChatListEntryMessageTagSummaryComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatListEntryPendingMessageActionsSummaryComponent {
|
||||
public struct ChatListEntryPendingMessageActionsSummaryComponent: Equatable {
|
||||
public let namespace: MessageId.Namespace
|
||||
|
||||
public init(namespace: MessageId.Namespace) {
|
||||
@ -26,8 +26,8 @@ public struct ChatListEntryPendingMessageActionsSummaryComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatListEntrySummaryComponents {
|
||||
public struct Component {
|
||||
public struct ChatListEntrySummaryComponents: Equatable {
|
||||
public struct Component: Equatable {
|
||||
public let tagSummary: ChatListEntryMessageTagSummaryComponent?
|
||||
public let actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent?
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ private func mappedChatListFilterPredicate(postbox: PostboxImpl, currentTransact
|
||||
let notificationsPeerId = peer.notificationSettingsPeerId ?? peer.id
|
||||
let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId)
|
||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId))
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: predicate.messageTagSummary)
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: predicate.messageTagSummary)
|
||||
|
||||
if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) {
|
||||
return true
|
||||
@ -402,7 +402,7 @@ private final class ChatListViewSpaceState {
|
||||
|
||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId))
|
||||
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: filterPredicate.messageTagSummary)
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: filterPredicate.messageTagSummary)
|
||||
|
||||
if !filterPredicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: postbox.readStateTable.getCombinedState(peer.id)?.isUnread ?? false, isContact: postbox.contactsTable.isContact(peerId: notificationsPeerId), messageTagSummaryResult: messageTagSummaryResult) {
|
||||
continue inner
|
||||
@ -498,7 +498,7 @@ private final class ChatListViewSpaceState {
|
||||
|
||||
if !transaction.currentUpdatedPeerNotificationSettings.isEmpty, case let .group(groupId, pinned, maybeFilterPredicate) = self.space, let filterPredicate = maybeFilterPredicate {
|
||||
var removeEntryIndices: [MutableChatListEntryIndex] = []
|
||||
let _ = self.orderedEntries.mutableScan { entry in
|
||||
let _ = self.orderedEntries.mutableScan { entry -> MutableChatListEntry? in
|
||||
let entryPeer: Peer
|
||||
let entryNotificationsPeerId: PeerId
|
||||
switch entry {
|
||||
@ -532,7 +532,7 @@ private final class ChatListViewSpaceState {
|
||||
|
||||
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: entryPeer, peerSettings: settingsChange.1)
|
||||
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, calculation: filterPredicate.messageTagSummary)
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, threadId: nil, calculation: filterPredicate.messageTagSummary)
|
||||
|
||||
let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId), messageTagSummaryResult: messageTagSummaryResult)
|
||||
if !isIncluded {
|
||||
@ -570,7 +570,7 @@ private final class ChatListViewSpaceState {
|
||||
|
||||
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: settingsChange.1)
|
||||
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, calculation: filterPredicate.messageTagSummary)
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, threadId: nil, calculation: filterPredicate.messageTagSummary)
|
||||
|
||||
let isIncluded = filterPredicate.includes(peer: mainPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: peerId), messageTagSummaryResult: messageTagSummaryResult)
|
||||
if isIncluded && self.orderedEntries.indicesForPeerId(mainPeer.id) == nil {
|
||||
@ -730,7 +730,7 @@ private final class ChatListViewSpaceState {
|
||||
|
||||
if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty, case let .group(groupId, pinned, maybeFilterPredicate) = self.space, let filterPredicate = maybeFilterPredicate, let filterMessageTagSummary = filterPredicate.messageTagSummary {
|
||||
var removeEntryIndices: [MutableChatListEntryIndex] = []
|
||||
let _ = self.orderedEntries.mutableScan { entry in
|
||||
let _ = self.orderedEntries.mutableScan { entry -> MutableChatListEntry? in
|
||||
let entryPeer: Peer
|
||||
let entryNotificationsPeerId: PeerId
|
||||
switch entry {
|
||||
@ -752,7 +752,7 @@ private final class ChatListViewSpaceState {
|
||||
return nil
|
||||
}
|
||||
|
||||
let updatedMessageSummary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: filterMessageTagSummary.addCount.tag, peerId: entryPeer.id, namespace: filterMessageTagSummary.addCount.namespace)]
|
||||
let updatedMessageSummary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: filterMessageTagSummary.addCount.tag, peerId: entryPeer.id, threadId: nil, namespace: filterMessageTagSummary.addCount.namespace)]
|
||||
let updatedActionsSummary = transaction.currentUpdatedMessageActionsSummaries[PendingMessageActionsSummaryKey(type: filterMessageTagSummary.subtractCount.type, peerId: entryPeer.id, namespace: filterMessageTagSummary.subtractCount.namespace)]
|
||||
|
||||
if updatedMessageSummary != nil || updatedActionsSummary != nil {
|
||||
@ -768,7 +768,7 @@ private final class ChatListViewSpaceState {
|
||||
|
||||
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: entryPeer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(entryPeer.id))
|
||||
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, calculation: filterPredicate.messageTagSummary)
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, threadId: nil, calculation: filterPredicate.messageTagSummary)
|
||||
|
||||
let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId), messageTagSummaryResult: messageTagSummaryResult)
|
||||
if !isIncluded {
|
||||
@ -813,7 +813,7 @@ private final class ChatListViewSpaceState {
|
||||
|
||||
let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(mainPeer.id))
|
||||
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, calculation: filterPredicate.messageTagSummary)
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, threadId: nil, calculation: filterPredicate.messageTagSummary)
|
||||
|
||||
let isIncluded = filterPredicate.includes(peer: mainPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: peerId), messageTagSummaryResult: messageTagSummaryResult)
|
||||
if isIncluded && self.orderedEntries.indicesForPeerId(mainPeer.id) == nil {
|
||||
@ -852,7 +852,7 @@ private final class ChatListViewSpaceState {
|
||||
for (key, component) in self.summaryComponents.components {
|
||||
var updatedTagSummaryCount: Int32?
|
||||
if let tagSummary = component.tagSummary {
|
||||
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: index.messageIndex.id.peerId, namespace: tagSummary.namespace)
|
||||
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: index.messageIndex.id.peerId, threadId: nil, namespace: tagSummary.namespace)
|
||||
if let summary = transaction.currentUpdatedMessageTagSummaries[key] {
|
||||
updatedTagSummaryCount = summary.count
|
||||
}
|
||||
@ -1428,7 +1428,7 @@ struct ChatListViewState {
|
||||
var actionsSummaryCount: Int32?
|
||||
|
||||
if let tagSummary = component.tagSummary {
|
||||
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: index.messageIndex.id.peerId, namespace: tagSummary.namespace)
|
||||
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: index.messageIndex.id.peerId, threadId: nil, namespace: tagSummary.namespace)
|
||||
if let summary = postbox.messageHistoryTagsSummaryTable.get(key) {
|
||||
tagSummaryCount = summary.count
|
||||
}
|
||||
|
||||
@ -2,12 +2,36 @@ import Foundation
|
||||
import SwiftSignalKit
|
||||
|
||||
public enum ChatLocationInput {
|
||||
case peer(peerId: PeerId)
|
||||
case peer(peerId: PeerId, threadId: Int64?)
|
||||
case thread(peerId: PeerId, threadId: Int64, data: Signal<MessageHistoryViewExternalInput, NoError>)
|
||||
case feed(id: Int32, data: Signal<MessageHistoryViewExternalInput, NoError>)
|
||||
}
|
||||
|
||||
public extension ChatLocationInput {
|
||||
var peerId: PeerId? {
|
||||
switch self {
|
||||
case let .peer(peerId, _):
|
||||
return peerId
|
||||
case let .thread(peerId, _, _):
|
||||
return peerId
|
||||
case .feed:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var threadId: Int64? {
|
||||
switch self {
|
||||
case let .peer(_, threadId):
|
||||
return threadId
|
||||
case let .thread(_, threadId, _):
|
||||
return threadId
|
||||
case .feed:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ResolvedChatLocationInput {
|
||||
case peer(PeerId)
|
||||
case peer(peerId: PeerId, threadId: Int64?)
|
||||
case external(MessageHistoryViewExternalInput)
|
||||
}
|
||||
|
||||
@ -3,7 +3,15 @@ import Foundation
|
||||
struct MessageHistoryIndexHoleOperationKey: Hashable {
|
||||
let peerId: PeerId
|
||||
let namespace: MessageId.Namespace
|
||||
let threadId: Int64?
|
||||
let space: MessageHistoryHoleSpace
|
||||
|
||||
init(peerId: PeerId, namespace: MessageId.Namespace, threadId: Int64?, space: MessageHistoryHoleSpace) {
|
||||
self.peerId = peerId
|
||||
self.namespace = namespace
|
||||
self.threadId = threadId
|
||||
self.space = space
|
||||
}
|
||||
}
|
||||
|
||||
enum MessageHistoryIndexHoleOperation {
|
||||
@ -25,8 +33,8 @@ public enum MessageHistoryHoleSpace: Equatable, Hashable, CustomStringConvertibl
|
||||
}
|
||||
}
|
||||
|
||||
private func addOperation(_ operation: MessageHistoryIndexHoleOperation, peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, to operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
|
||||
let key = MessageHistoryIndexHoleOperationKey(peerId: peerId, namespace: namespace, space: space)
|
||||
func addMessageHistoryHoleOperation(_ operation: MessageHistoryIndexHoleOperation, peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, to operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
|
||||
let key = MessageHistoryIndexHoleOperationKey(peerId: peerId, namespace: namespace, threadId: threadId, space: space)
|
||||
if operations[key] == nil {
|
||||
operations[key] = []
|
||||
}
|
||||
@ -365,7 +373,7 @@ final class MessageHistoryHoleIndexTable: Table {
|
||||
self.valueBox.set(self.table, key: self.key(id: MessageId(peerId: peerId, namespace: namespace, id: closedRange.upperBound), space: space), value: MemoryBuffer(memory: &lowerBound, capacity: 4, length: 4, freeWhenDone: false))
|
||||
}
|
||||
|
||||
addOperation(.insert(clippedRange), peerId: peerId, namespace: namespace, space: space, to: &operations)
|
||||
addMessageHistoryHoleOperation(.insert(clippedRange), peerId: peerId, threadId: nil, namespace: namespace, space: space, to: &operations)
|
||||
}
|
||||
|
||||
func remove(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
|
||||
@ -431,7 +439,7 @@ final class MessageHistoryHoleIndexTable: Table {
|
||||
}
|
||||
|
||||
if !removeKeys.isEmpty {
|
||||
addOperation(.remove(range), peerId: peerId, namespace: namespace, space: space, to: &operations)
|
||||
addMessageHistoryHoleOperation(.remove(range), peerId: peerId, threadId: nil, namespace: namespace, space: space, to: &operations)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -81,6 +81,7 @@ final class MessageHistoryTable: Table {
|
||||
let failedTable: MessageHistoryFailedTable
|
||||
let tagsTable: MessageHistoryTagsTable
|
||||
let threadsTable: MessageHistoryThreadsTable
|
||||
let threadTagsTable: MessageHistoryThreadTagsTable
|
||||
let globalTagsTable: GlobalMessageHistoryTagsTable
|
||||
let localTagsTable: LocalMessageHistoryTagsTable
|
||||
let timeBasedAttributesTable: TimestampBasedMessageAttributesTable
|
||||
@ -90,7 +91,7 @@ final class MessageHistoryTable: Table {
|
||||
let summaryTable: MessageHistoryTagsSummaryTable
|
||||
let pendingActionsTable: PendingMessageActionsTable
|
||||
|
||||
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, threadsTable: MessageHistoryThreadsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, timeBasedAttributesTable: TimestampBasedMessageAttributesTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) {
|
||||
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, threadsTable: MessageHistoryThreadsTable, threadTagsTable: MessageHistoryThreadTagsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, timeBasedAttributesTable: TimestampBasedMessageAttributesTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) {
|
||||
self.seedConfiguration = seedConfiguration
|
||||
self.messageHistoryIndexTable = messageHistoryIndexTable
|
||||
self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable
|
||||
@ -101,6 +102,7 @@ final class MessageHistoryTable: Table {
|
||||
self.failedTable = failedTable
|
||||
self.tagsTable = tagsTable
|
||||
self.threadsTable = threadsTable
|
||||
self.threadTagsTable = threadTagsTable
|
||||
self.globalTagsTable = globalTagsTable
|
||||
self.localTagsTable = localTagsTable
|
||||
self.timeBasedAttributesTable = timeBasedAttributesTable
|
||||
@ -278,6 +280,9 @@ final class MessageHistoryTable: Table {
|
||||
if (currentTags & 1) != 0 {
|
||||
let tag = MessageTags(rawValue: 1 << UInt32(i))
|
||||
self.tagsTable.add(tags: tag, index: message.index, isNewlyAdded: true, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
||||
if let threadId = message.threadId {
|
||||
self.threadTagsTable.add(tags: tag, threadId: threadId, index: message.index, isNewlyAdded: true, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -434,13 +439,15 @@ final class MessageHistoryTable: Table {
|
||||
return globallyUniqueIdToMessageId
|
||||
}
|
||||
|
||||
func removeMessages(_ messageIds: [MessageId], operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
|
||||
func removeMessages(_ messageIds: [MessageId], operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
|
||||
for (peerId, messageIds) in self.messageIdsByPeerId(messageIds) {
|
||||
var operations: [MessageHistoryIndexOperation] = []
|
||||
|
||||
for id in messageIds {
|
||||
self.messageHistoryIndexTable.removeMessage(id, operations: &operations)
|
||||
}
|
||||
|
||||
if let forEachMedia = forEachMedia {
|
||||
for operation in operations {
|
||||
if case let .Remove(index) = operation {
|
||||
if let message = self.getMessage(index) {
|
||||
@ -450,13 +457,16 @@ 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) {
|
||||
func removeMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
|
||||
var operations: [MessageHistoryIndexOperation] = []
|
||||
self.messageHistoryIndexTable.removeMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, operations: &operations)
|
||||
if let forEachMedia = forEachMedia {
|
||||
for operation in operations {
|
||||
if case let .Remove(index) = operation {
|
||||
if let message = self.getMessage(index) {
|
||||
@ -466,11 +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 clearHistoryInRange(peerId: PeerId, threadId: Int64?, minTimestamp: Int32, maxTimestamp: Int32, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
|
||||
func clearHistoryInRange(peerId: PeerId, threadId: Int64?, minTimestamp: Int32, maxTimestamp: Int32, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: ((Media) -> Void)?) {
|
||||
var indices = self.allMessageIndices(peerId: peerId).filter { namespaces.contains($0.id.namespace) }
|
||||
if let threadId = threadId {
|
||||
indices = indices.filter { index in
|
||||
@ -491,7 +502,7 @@ final class MessageHistoryTable: Table {
|
||||
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×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) }
|
||||
if let threadId = threadId {
|
||||
indices = indices.filter { index in
|
||||
@ -509,12 +520,12 @@ final class MessageHistoryTable: Table {
|
||||
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×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)
|
||||
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] = []
|
||||
for entry in self.allIndicesWithGlobalTag(tag: tag) {
|
||||
switch entry {
|
||||
@ -527,7 +538,7 @@ final class MessageHistoryTable: Table {
|
||||
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×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)
|
||||
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 {
|
||||
self.tagsTable.remove(tags: tag, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
||||
if let threadId = message.threadId {
|
||||
self.threadTagsTable.remove(tags: tag, threadId: threadId, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
||||
}
|
||||
}
|
||||
if let threadId = message.threadId {
|
||||
self.threadsTable.remove(threadId: threadId, index: index)
|
||||
@ -1539,10 +1553,17 @@ final class MessageHistoryTable: Table {
|
||||
if previousMessage.tags != message.tags || index != updatedIndex {
|
||||
if !previousMessage.tags.isEmpty {
|
||||
self.tagsTable.remove(tags: previousMessage.tags, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
||||
if let threadId = previousMessage.threadId {
|
||||
self.threadTagsTable.remove(tags: previousMessage.tags, threadId: threadId, index: index, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
||||
}
|
||||
}
|
||||
if !message.tags.isEmpty {
|
||||
//let isNewlyAdded = previousMessage.tags.isEmpty
|
||||
self.tagsTable.add(tags: message.tags, index: message.index, isNewlyAdded: false, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
||||
|
||||
if let threadId = message.threadId {
|
||||
self.threadTagsTable.add(tags: message.tags, threadId: threadId, index: message.index, isNewlyAdded: false, updatedSummaries: &updatedMessageTagSummaries, invalidateSummaries: &invalidateMessageTagSummaries)
|
||||
}
|
||||
}
|
||||
}
|
||||
if previousMessage.threadId != message.threadId || index != message.index {
|
||||
@ -2977,6 +2998,35 @@ final class MessageHistoryTable: Table {
|
||||
precondition(fromIndex.id.namespace == toIndex.id.namespace)
|
||||
var result: [IntermediateMessage] = []
|
||||
if let threadId = threadId {
|
||||
if let tag = tag {
|
||||
let indices: [MessageIndex]
|
||||
if fromIndex < toIndex {
|
||||
indices = self.threadTagsTable.laterIndices(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace, index: fromIndex, includeFrom: includeFrom, count: limit)
|
||||
} else {
|
||||
indices = self.threadTagsTable.earlierIndices(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace, index: fromIndex, includeFrom: includeFrom, count: limit)
|
||||
}
|
||||
for index in indices {
|
||||
if let ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange {
|
||||
if ignoreMessagesInTimestampRange.contains(index.timestamp) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if fromIndex < toIndex {
|
||||
if index < fromIndex || index > toIndex {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if index < toIndex || index > fromIndex {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if let message = self.getMessage(index) {
|
||||
result.append(message)
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var indices: [MessageIndex] = []
|
||||
var startIndex = fromIndex
|
||||
var localIncludeFrom = includeFrom
|
||||
@ -2990,6 +3040,7 @@ final class MessageHistoryTable: Table {
|
||||
if sliceIndices.isEmpty {
|
||||
break
|
||||
}
|
||||
|
||||
startIndex = sliceIndices[sliceIndices.count - 1]
|
||||
localIncludeFrom = false
|
||||
|
||||
@ -3027,6 +3078,7 @@ final class MessageHistoryTable: Table {
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let tag = tag {
|
||||
let indices: [MessageIndex]
|
||||
if fromIndex < toIndex {
|
||||
|
||||
@ -3,22 +3,24 @@ import Foundation
|
||||
final class MutableMessageHistoryTagSummaryView: MutablePostboxView {
|
||||
private let tag: MessageTags
|
||||
private let peerId: PeerId
|
||||
private let threadId: Int64?
|
||||
private let namespace: MessageId.Namespace
|
||||
|
||||
fileprivate var count: Int32?
|
||||
|
||||
init(postbox: PostboxImpl, tag: MessageTags, peerId: PeerId, namespace: MessageId.Namespace) {
|
||||
init(postbox: PostboxImpl, tag: MessageTags, peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace) {
|
||||
self.tag = tag
|
||||
self.peerId = peerId
|
||||
self.threadId = threadId
|
||||
self.namespace = namespace
|
||||
|
||||
self.count = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: tag, peerId: peerId, namespace: namespace))?.count
|
||||
self.count = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: tag, peerId: peerId, threadId: threadId, namespace: namespace))?.count
|
||||
}
|
||||
|
||||
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
||||
var hasChanges = false
|
||||
|
||||
if let summary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: self.tag, peerId: self.peerId, namespace: self.namespace)] {
|
||||
if let summary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: self.tag, peerId: self.peerId, threadId: self.threadId, namespace: self.namespace)] {
|
||||
self.count = summary.count
|
||||
hasChanges = true
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ public struct MessageHistoryTagNamespaceSummary: Equatable, CustomStringConverti
|
||||
struct MessageHistoryTagsSummaryKey: Equatable, Hashable {
|
||||
let tag: MessageTags
|
||||
let peerId: PeerId
|
||||
let threadId: Int64?
|
||||
let namespace: MessageId.Namespace
|
||||
}
|
||||
|
||||
@ -80,7 +81,8 @@ class MessageHistoryTagsSummaryTable: Table {
|
||||
private var cachedSummaries: [MessageHistoryTagsSummaryKey: CachedEntry] = [:]
|
||||
private var updatedKeys = Set<MessageHistoryTagsSummaryKey>()
|
||||
|
||||
private let sharedKey = ValueBoxKey(length: 4 + 8 + 4)
|
||||
private let sharedSimpleKey = ValueBoxKey(length: 4 + 8 + 4)
|
||||
private let sharedThreadKey = ValueBoxKey(length: 4 + 8 + 4 + 8)
|
||||
|
||||
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, invalidateTable: InvalidatedMessageHistoryTagsSummaryTable) {
|
||||
self.invalidateTable = invalidateTable
|
||||
@ -88,17 +90,25 @@ class MessageHistoryTagsSummaryTable: Table {
|
||||
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
|
||||
}
|
||||
|
||||
private func key(key: MessageHistoryTagsSummaryKey, sharedKey: ValueBoxKey = ValueBoxKey(length: 4 + 8 + 4)) -> ValueBoxKey {
|
||||
sharedKey.setUInt32(0, value: key.tag.rawValue)
|
||||
sharedKey.setInt64(4, value: key.peerId.toInt64())
|
||||
sharedKey.setInt32(4 + 8, value: key.namespace)
|
||||
return sharedKey
|
||||
private func keyShared(key: MessageHistoryTagsSummaryKey) -> ValueBoxKey {
|
||||
if let threadId = key.threadId {
|
||||
self.sharedThreadKey.setUInt32(0, value: key.tag.rawValue)
|
||||
self.sharedThreadKey.setInt64(4, value: key.peerId.toInt64())
|
||||
self.sharedThreadKey.setInt32(4 + 8, value: key.namespace)
|
||||
self.sharedThreadKey.setInt64(4 + 8 + 4, value: threadId)
|
||||
return self.sharedSimpleKey
|
||||
} else {
|
||||
self.sharedSimpleKey.setUInt32(0, value: key.tag.rawValue)
|
||||
self.sharedSimpleKey.setInt64(4, value: key.peerId.toInt64())
|
||||
self.sharedSimpleKey.setInt32(4 + 8, value: key.namespace)
|
||||
return self.sharedSimpleKey
|
||||
}
|
||||
}
|
||||
|
||||
func get(_ key: MessageHistoryTagsSummaryKey) -> MessageHistoryTagNamespaceSummary? {
|
||||
if let cached = self.cachedSummaries[key] {
|
||||
return cached.summary
|
||||
} else if let value = self.valueBox.get(self.table, key: self.key(key: key, sharedKey: self.sharedKey)) {
|
||||
} else if let value = self.valueBox.get(self.table, key: self.keyShared(key: key)) {
|
||||
let entry = readSummary(value)
|
||||
self.cachedSummaries[key] = CachedEntry(summary: entry)
|
||||
return entry
|
||||
@ -164,10 +174,10 @@ class MessageHistoryTagsSummaryTable: Table {
|
||||
if let summary = cached.summary {
|
||||
buffer.reset()
|
||||
writeSummary(summary, to: buffer)
|
||||
self.valueBox.set(self.table, key: self.key(key: key, sharedKey: self.sharedKey), value: buffer)
|
||||
self.valueBox.set(self.table, key: self.keyShared(key: key), value: buffer)
|
||||
} else {
|
||||
assertionFailure()
|
||||
self.valueBox.remove(self.table, key: self.key(key: key, sharedKey: self.sharedKey), secure: false)
|
||||
self.valueBox.remove(self.table, key: self.keyShared(key: key), secure: false)
|
||||
}
|
||||
} else {
|
||||
assertionFailure()
|
||||
|
||||
@ -46,7 +46,7 @@ class MessageHistoryTagsTable: Table {
|
||||
for tag in tags {
|
||||
self.valueBox.set(self.table, key: self.key(tag: tag, index: index, key: self.sharedKey), value: MemoryBuffer())
|
||||
if self.summaryTags.contains(tag) {
|
||||
self.summaryTable.addMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, namespace: index.id.namespace), id: index.id.id, isNewlyAdded: isNewlyAdded, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
|
||||
self.summaryTable.addMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, threadId: nil, namespace: index.id.namespace), id: index.id.id, isNewlyAdded: isNewlyAdded, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,7 +56,7 @@ class MessageHistoryTagsTable: Table {
|
||||
self.valueBox.remove(self.table, key: self.key(tag: tag, index: index, key: self.sharedKey), secure: false)
|
||||
|
||||
if self.summaryTags.contains(tag) {
|
||||
self.summaryTable.removeMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, namespace: index.id.namespace), id: index.id.id, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
|
||||
self.summaryTable.removeMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, threadId: nil, namespace: index.id.namespace), id: index.id.id, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,7 +329,7 @@ final class MessageHistoryThreadHoleIndexTable: Table {
|
||||
self.valueBox.set(self.table, key: self.key(threadId: threadId, id: MessageId(peerId: peerId, namespace: namespace, id: closedRange.upperBound), space: space), value: MemoryBuffer(memory: &lowerBound, capacity: 4, length: 4, freeWhenDone: false))
|
||||
}
|
||||
|
||||
//addOperation(.insert(clippedRange), peerId: peerId, namespace: namespace, space: space, to: &operations)
|
||||
addMessageHistoryHoleOperation(.insert(clippedRange), peerId: peerId, threadId: threadId, namespace: namespace, space: space, to: &operations)
|
||||
}
|
||||
|
||||
func remove(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
|
||||
@ -337,7 +337,7 @@ final class MessageHistoryThreadHoleIndexTable: Table {
|
||||
|
||||
self.removeInternal(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &operations)
|
||||
|
||||
/*switch space {
|
||||
switch space {
|
||||
case .everywhere:
|
||||
if let namespaceHoleTags = self.seedConfiguration.messageHoles[peerId.namespace]?[namespace] {
|
||||
for tag in namespaceHoleTags {
|
||||
@ -346,7 +346,7 @@ final class MessageHistoryThreadHoleIndexTable: Table {
|
||||
}
|
||||
case .tag:
|
||||
break
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
private func removeInternal(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) {
|
||||
@ -393,9 +393,9 @@ final class MessageHistoryThreadHoleIndexTable: Table {
|
||||
self.valueBox.set(self.table, key: self.key(threadId: threadId, id: MessageId(peerId: peerId, namespace: namespace, id: closedRange.upperBound), space: space), value: MemoryBuffer(memory: &lowerBound, capacity: 4, length: 4, freeWhenDone: false))
|
||||
}
|
||||
|
||||
/*if !removeKeys.isEmpty {
|
||||
addOperation(.remove(range), peerId: peerId, namespace: namespace, space: space, to: &operations)
|
||||
}*/
|
||||
if !removeKeys.isEmpty {
|
||||
addMessageHistoryHoleOperation(.remove(range), peerId: peerId, threadId: threadId, namespace: namespace, space: space, to: &operations)
|
||||
}
|
||||
}
|
||||
|
||||
func debugList(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace) -> [ClosedRange<MessageId.Id>] {
|
||||
|
||||
@ -5,27 +5,32 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
|
||||
let id: Int64
|
||||
let index: MessageIndex
|
||||
var info: CodableEntry
|
||||
var tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo]
|
||||
var topMessage: Message?
|
||||
|
||||
init(
|
||||
id: Int64,
|
||||
index: MessageIndex,
|
||||
info: CodableEntry,
|
||||
tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo],
|
||||
topMessage: Message?
|
||||
) {
|
||||
self.id = id
|
||||
self.index = index
|
||||
self.info = info
|
||||
self.tagSummaryInfo = tagSummaryInfo
|
||||
self.topMessage = topMessage
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let peerId: PeerId
|
||||
fileprivate let summaryComponents: ChatListEntrySummaryComponents
|
||||
fileprivate var peer: Peer?
|
||||
fileprivate var items: [Item] = []
|
||||
|
||||
init(postbox: PostboxImpl, peerId: PeerId) {
|
||||
init(postbox: PostboxImpl, peerId: PeerId, summaryComponents: ChatListEntrySummaryComponents) {
|
||||
self.peerId = peerId
|
||||
self.summaryComponents = summaryComponents
|
||||
|
||||
self.reload(postbox: postbox)
|
||||
}
|
||||
@ -36,10 +41,34 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
|
||||
self.peer = postbox.peerTable.get(self.peerId)
|
||||
|
||||
for item in postbox.messageHistoryThreadIndexTable.getAll(peerId: self.peerId) {
|
||||
var tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo] = [:]
|
||||
for (key, component) in self.summaryComponents.components {
|
||||
var tagSummaryCount: Int32?
|
||||
var actionsSummaryCount: Int32?
|
||||
|
||||
if let tagSummary = component.tagSummary {
|
||||
let key = MessageHistoryTagsSummaryKey(tag: key.tag, peerId: self.peerId, threadId: item.threadId, namespace: tagSummary.namespace)
|
||||
if let summary = postbox.messageHistoryTagsSummaryTable.get(key) {
|
||||
tagSummaryCount = summary.count
|
||||
}
|
||||
}
|
||||
|
||||
if let actionsSummary = component.actionsSummary {
|
||||
let key = PendingMessageActionsSummaryKey(type: key.actionType, peerId: self.peerId, namespace: actionsSummary.namespace)
|
||||
actionsSummaryCount = postbox.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(key.peerId, key.namespace, key.type))
|
||||
}
|
||||
|
||||
tagSummaryInfo[key] = ChatListMessageTagSummaryInfo(
|
||||
tagSummaryCount: tagSummaryCount,
|
||||
actionsSummaryCount: actionsSummaryCount
|
||||
)
|
||||
}
|
||||
|
||||
self.items.append(Item(
|
||||
id: item.threadId,
|
||||
index: item.index,
|
||||
info: item.info,
|
||||
tagSummaryInfo: tagSummaryInfo,
|
||||
topMessage: postbox.getMessage(item.index.id)
|
||||
))
|
||||
}
|
||||
@ -48,7 +77,7 @@ final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
|
||||
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
||||
var updated = false
|
||||
|
||||
if transaction.updatedMessageThreadPeerIds.contains(self.peerId) {
|
||||
if transaction.updatedMessageThreadPeerIds.contains(self.peerId) || transaction.currentUpdatedMessageTagSummaries.contains(where: { $0.key.peerId == self.peerId }) || transaction.currentUpdatedMessageActionsSummaries.contains(where: { $0.key.peerId == self.peerId }) {
|
||||
self.reload(postbox: postbox)
|
||||
updated = true
|
||||
}
|
||||
@ -70,17 +99,20 @@ public final class EngineMessageHistoryThread {
|
||||
public let id: Int64
|
||||
public let index: MessageIndex
|
||||
public let info: CodableEntry
|
||||
public let tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo]
|
||||
public let topMessage: Message?
|
||||
|
||||
public init(
|
||||
id: Int64,
|
||||
index: MessageIndex,
|
||||
info: CodableEntry,
|
||||
tagSummaryInfo: [ChatListEntryMessageTagSummaryKey: ChatListMessageTagSummaryInfo],
|
||||
topMessage: Message?
|
||||
) {
|
||||
self.id = id
|
||||
self.index = index
|
||||
self.info = info
|
||||
self.tagSummaryInfo = tagSummaryInfo
|
||||
self.topMessage = topMessage
|
||||
}
|
||||
|
||||
@ -94,6 +126,9 @@ public final class EngineMessageHistoryThread {
|
||||
if lhs.info != rhs.info {
|
||||
return false
|
||||
}
|
||||
if lhs.tagSummaryInfo != rhs.tagSummaryInfo {
|
||||
return false
|
||||
}
|
||||
if let lhsMessage = lhs.topMessage, let rhsMessage = rhs.topMessage {
|
||||
if lhsMessage.index != rhsMessage.index {
|
||||
return false
|
||||
@ -123,6 +158,7 @@ public final class MessageHistoryThreadIndexView: PostboxView {
|
||||
id: item.id,
|
||||
index: item.index,
|
||||
info: item.info,
|
||||
tagSummaryInfo: item.tagSummaryInfo,
|
||||
topMessage: item.topMessage
|
||||
))
|
||||
}
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
private func extractKey(_ key: ValueBoxKey) -> MessageIndex {
|
||||
return MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(0)), namespace: key.getInt32(8 + 8), id: key.getInt32(8 + 8 + 4 + 4)), timestamp: key.getInt32(8 + 8 + 4))
|
||||
}
|
||||
|
||||
class MessageHistoryThreadsTable: Table {
|
||||
struct ItemId: Hashable {
|
||||
var peerId: PeerId
|
||||
@ -31,6 +27,10 @@ class MessageHistoryThreadsTable: Table {
|
||||
return key
|
||||
}
|
||||
|
||||
private func extractKey(_ key: ValueBoxKey) -> MessageIndex {
|
||||
return MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(0)), namespace: key.getInt32(8 + 8), id: key.getInt32(8 + 8 + 4 + 4)), timestamp: key.getInt32(8 + 8 + 4))
|
||||
}
|
||||
|
||||
private func lowerBound(threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey {
|
||||
let key = ValueBoxKey(length: 8 + 8 + 4)
|
||||
key.setInt64(0, value: peerId.toInt64())
|
||||
@ -146,3 +146,199 @@ class MessageHistoryThreadsTable: Table {
|
||||
self.updatedIds.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
class MessageHistoryThreadTagsTable: Table {
|
||||
static func tableSpec(_ id: Int32) -> ValueBoxTable {
|
||||
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true)
|
||||
}
|
||||
|
||||
private let summaryTable: MessageHistoryTagsSummaryTable
|
||||
private let summaryTags: MessageTags
|
||||
|
||||
private let sharedKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4 + 4)
|
||||
|
||||
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, summaryTable: MessageHistoryTagsSummaryTable) {
|
||||
self.summaryTable = summaryTable
|
||||
self.summaryTags = seedConfiguration.messageTagsWithSummary
|
||||
|
||||
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
|
||||
}
|
||||
|
||||
private func key(tag: MessageTags, threadId: Int64, index: MessageIndex, key: ValueBoxKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4 + 4)) -> ValueBoxKey {
|
||||
key.setInt64(0, value: index.id.peerId.toInt64())
|
||||
key.setInt64(8, value: threadId)
|
||||
key.setUInt32(8 + 8, value: tag.rawValue)
|
||||
key.setInt32(8 + 8 + 4, value: index.id.namespace)
|
||||
key.setInt32(8 + 8 + 4 + 4, value: index.timestamp)
|
||||
key.setInt32(8 + 8 + 4 + 4 + 4, value: index.id.id)
|
||||
return key
|
||||
}
|
||||
|
||||
private func extractKey(_ key: ValueBoxKey) -> MessageIndex {
|
||||
return MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(0)), namespace: key.getInt32(8 + 8 + 4), id: key.getInt32(8 + 8 + 4 + 4 + 4)), timestamp: key.getInt32(8 + 8 + 4 + 4))
|
||||
}
|
||||
|
||||
private func lowerBound(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey {
|
||||
let key = ValueBoxKey(length: 8 + 8 + 4 + 4)
|
||||
key.setInt64(0, value: peerId.toInt64())
|
||||
key.setInt64(8, value: threadId)
|
||||
key.setUInt32(8 + 8, value: tag.rawValue)
|
||||
key.setInt32(8 + 8 + 4, value: namespace)
|
||||
return key
|
||||
}
|
||||
|
||||
private func upperBound(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey {
|
||||
return self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace).successor
|
||||
}
|
||||
|
||||
func add(tags: MessageTags, threadId: Int64, index: MessageIndex, isNewlyAdded: Bool, updatedSummaries: inout[MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation]) {
|
||||
for tag in tags {
|
||||
self.valueBox.set(self.table, key: self.key(tag: tag, threadId: threadId, index: index, key: self.sharedKey), value: MemoryBuffer())
|
||||
if self.summaryTags.contains(tag) {
|
||||
self.summaryTable.addMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, threadId: threadId, namespace: index.id.namespace), id: index.id.id, isNewlyAdded: isNewlyAdded, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func remove(tags: MessageTags, threadId: Int64, index: MessageIndex, updatedSummaries: inout[MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation]) {
|
||||
for tag in tags {
|
||||
self.valueBox.remove(self.table, key: self.key(tag: tag, threadId: threadId, index: index, key: self.sharedKey), secure: false)
|
||||
if self.summaryTags.contains(tag) {
|
||||
self.summaryTable.removeMessage(key: MessageHistoryTagsSummaryKey(tag: tag, peerId: index.id.peerId, threadId: threadId, namespace: index.id.namespace), id: index.id.id, updatedSummaries: &updatedSummaries, invalidateSummaries: &invalidateSummaries)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func entryExists(tag: MessageTags, threadId: Int64, index: MessageIndex) -> Bool {
|
||||
return self.valueBox.exists(self.table, key: self.key(tag: tag, threadId: threadId, index: index, key: self.sharedKey))
|
||||
}
|
||||
|
||||
func entryLocation(at index: MessageIndex, threadId: Int64, tag: MessageTags) -> MessageHistoryEntryLocation? {
|
||||
if let _ = self.valueBox.get(self.table, key: self.key(tag: tag, threadId: threadId, index: index)) {
|
||||
var greaterCount = 0
|
||||
self.valueBox.range(self.table, start: self.key(tag: tag, threadId: threadId, index: index), end: self.upperBound(tag: tag, threadId: threadId, peerId: index.id.peerId, namespace: index.id.namespace), keys: { _ in
|
||||
greaterCount += 1
|
||||
return true
|
||||
}, limit: 0)
|
||||
|
||||
var lowerCount = 0
|
||||
self.valueBox.range(self.table, start: self.key(tag: tag, threadId: threadId, index: index), end: self.lowerBound(tag: tag, threadId: threadId, peerId: index.id.peerId, namespace: index.id.namespace), keys: { _ in
|
||||
lowerCount += 1
|
||||
return true
|
||||
}, limit: 0)
|
||||
|
||||
return MessageHistoryEntryLocation(index: lowerCount, count: greaterCount + lowerCount + 1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func earlierIndices(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, index: MessageIndex?, includeFrom: Bool, minIndex: MessageIndex? = nil, count: Int) -> [MessageIndex] {
|
||||
var indices: [MessageIndex] = []
|
||||
let key: ValueBoxKey
|
||||
if let index = index {
|
||||
if includeFrom {
|
||||
key = self.key(tag: tag, threadId: threadId, index: index).successor
|
||||
} else {
|
||||
key = self.key(tag: tag, threadId: threadId, index: index)
|
||||
}
|
||||
} else {
|
||||
key = self.upperBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace)
|
||||
}
|
||||
let endKey: ValueBoxKey
|
||||
if let minIndex = minIndex {
|
||||
endKey = self.key(tag: tag, threadId: threadId, index: minIndex)
|
||||
} else {
|
||||
endKey = self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace)
|
||||
}
|
||||
self.valueBox.range(self.table, start: key, end: endKey, keys: { key in
|
||||
indices.append(self.extractKey(key))
|
||||
return true
|
||||
}, limit: count)
|
||||
return indices
|
||||
}
|
||||
|
||||
func laterIndices(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, index: MessageIndex?, includeFrom: Bool, count: Int) -> [MessageIndex] {
|
||||
var indices: [MessageIndex] = []
|
||||
let key: ValueBoxKey
|
||||
if let index = index {
|
||||
if includeFrom {
|
||||
key = self.key(tag: tag, threadId: threadId, index: index).predecessor
|
||||
} else {
|
||||
key = self.key(tag: tag, threadId: threadId, index: index)
|
||||
}
|
||||
} else {
|
||||
key = self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace)
|
||||
}
|
||||
self.valueBox.range(self.table, start: key, end: self.upperBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), keys: { key in
|
||||
indices.append(self.extractKey(key))
|
||||
return true
|
||||
}, limit: count)
|
||||
return indices
|
||||
}
|
||||
|
||||
func getMessageCountInRange(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, lowerBound: MessageIndex, upperBound: MessageIndex) -> Int {
|
||||
precondition(lowerBound.id.namespace == namespace)
|
||||
precondition(upperBound.id.namespace == namespace)
|
||||
var lowerBoundKey = self.key(tag: tag, threadId: threadId, index: lowerBound)
|
||||
if lowerBound.timestamp > 1 {
|
||||
lowerBoundKey = lowerBoundKey.predecessor
|
||||
}
|
||||
var upperBoundKey = self.key(tag: tag, threadId: threadId, index: upperBound)
|
||||
if upperBound.timestamp < Int32.max - 1 {
|
||||
upperBoundKey = upperBoundKey.successor
|
||||
}
|
||||
return Int(self.valueBox.count(self.table, start: lowerBoundKey, end: upperBoundKey))
|
||||
}
|
||||
|
||||
func latestIndex(tag: MessageTags, threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace) -> MessageIndex? {
|
||||
var result: MessageIndex?
|
||||
self.valueBox.range(self.table, start: self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), end: self.upperBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), keys: { key in
|
||||
result = extractKey(key)
|
||||
return true
|
||||
}, limit: 1)
|
||||
return result
|
||||
}
|
||||
|
||||
func findRandomIndex(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, tag: MessageTags, ignoreIds: ([MessageId], Set<MessageId>), isMessage: (MessageIndex) -> Bool) -> MessageIndex? {
|
||||
var indices: [MessageIndex] = []
|
||||
self.valueBox.range(self.table, start: self.lowerBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), end: self.upperBound(tag: tag, threadId: threadId, peerId: peerId, namespace: namespace), keys: { key in
|
||||
indices.append(extractKey(key))
|
||||
return true
|
||||
}, limit: 0)
|
||||
var checkedIndices = Set<Int>()
|
||||
while checkedIndices.count < indices.count {
|
||||
let i = Int(arc4random_uniform(UInt32(indices.count)))
|
||||
if checkedIndices.contains(i) {
|
||||
continue
|
||||
}
|
||||
checkedIndices.insert(i)
|
||||
let index = indices[i]
|
||||
if isMessage(index) && !ignoreIds.1.contains(index.id) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
checkedIndices.removeAll()
|
||||
let lastId = ignoreIds.0.last
|
||||
while checkedIndices.count < indices.count {
|
||||
let i = Int(arc4random_uniform(UInt32(indices.count)))
|
||||
if checkedIndices.contains(i) {
|
||||
continue
|
||||
}
|
||||
checkedIndices.insert(i)
|
||||
let index = indices[i]
|
||||
if isMessage(index) && lastId != index.id {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func debugGetAllIndices() -> [MessageIndex] {
|
||||
var indices: [MessageIndex] = []
|
||||
self.valueBox.scan(self.table, values: { key, value in
|
||||
indices.append(extractKey(key))
|
||||
return true
|
||||
})
|
||||
return indices
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ public final class MessageHistoryViewExternalInput: Equatable {
|
||||
}
|
||||
|
||||
public enum MessageHistoryViewInput: Equatable {
|
||||
case single(PeerId)
|
||||
case single(peerId: PeerId, threadId: Int64?)
|
||||
case associated(PeerId, MessageId?)
|
||||
case external(MessageHistoryViewExternalInput)
|
||||
}
|
||||
@ -362,7 +362,7 @@ final class MutableMessageHistoryView {
|
||||
switch peerIds {
|
||||
case let .associated(peerId, _):
|
||||
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, _):
|
||||
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
||||
case let .external(input):
|
||||
switch input.content {
|
||||
@ -420,7 +420,7 @@ final class MutableMessageHistoryView {
|
||||
|
||||
func updatePeerIds(transaction: PostboxTransaction) {
|
||||
switch self.peerIds {
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, _):
|
||||
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId] {
|
||||
if updatedData.associatedHistoryMessageId != nil {
|
||||
self.peerIds = .associated(peerId, updatedData.associatedHistoryMessageId)
|
||||
@ -445,7 +445,7 @@ final class MutableMessageHistoryView {
|
||||
switch peerIds {
|
||||
case let .associated(peerId, _):
|
||||
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, _):
|
||||
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: peerId) != nil
|
||||
case let .external(input):
|
||||
switch input.content {
|
||||
@ -458,7 +458,7 @@ final class MutableMessageHistoryView {
|
||||
}
|
||||
|
||||
switch self.peerIds {
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, _):
|
||||
holePeerIdsSet.insert(peerId)
|
||||
if let value = transaction.currentOperationsByPeerId[peerId] {
|
||||
operations.append(value)
|
||||
@ -497,7 +497,10 @@ final class MutableMessageHistoryView {
|
||||
let externalThreadId: Int64?
|
||||
let isExternal: Bool
|
||||
switch self.peerIds {
|
||||
case .single, .associated:
|
||||
case let .single(_, threadId):
|
||||
externalThreadId = threadId
|
||||
isExternal = false
|
||||
case .associated:
|
||||
externalThreadId = nil
|
||||
isExternal = false
|
||||
case let .external(input):
|
||||
@ -527,7 +530,7 @@ final class MutableMessageHistoryView {
|
||||
}
|
||||
}
|
||||
if matchesSpace {
|
||||
if holePeerIdsSet.contains(key.peerId) {
|
||||
if holePeerIdsSet.contains(key.peerId) && key.threadId == externalThreadId {
|
||||
for operation in holeOperations {
|
||||
switch operation {
|
||||
case let .insert(range):
|
||||
@ -865,9 +868,11 @@ final class MutableMessageHistoryView {
|
||||
|
||||
if !transaction.currentPeerHoleOperations.isEmpty {
|
||||
var holePeerIdsSet: [PeerId] = []
|
||||
var threadId: Int64?
|
||||
switch self.peerIds {
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, threadIdValue):
|
||||
holePeerIdsSet.append(peerId)
|
||||
threadId = threadIdValue
|
||||
case let .associated(peerId, associatedId):
|
||||
holePeerIdsSet.append(peerId)
|
||||
if let associatedId = associatedId {
|
||||
@ -878,7 +883,7 @@ final class MutableMessageHistoryView {
|
||||
}
|
||||
let space: MessageHistoryHoleSpace = self.tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
|
||||
for key in transaction.currentPeerHoleOperations.keys {
|
||||
if holePeerIdsSet.contains(key.peerId) && key.space == space {
|
||||
if holePeerIdsSet.contains(key.peerId) && threadId == key.threadId && key.space == space {
|
||||
hasChanges = true
|
||||
}
|
||||
}
|
||||
@ -1177,4 +1182,83 @@ public final class MessageHistoryView {
|
||||
|
||||
self.entries = entries
|
||||
}
|
||||
|
||||
public init(base: MessageHistoryView, fixed combinedReadStates: MessageHistoryViewReadState?, transient transientReadStates: MessageHistoryViewReadState?) {
|
||||
self.tagMask = base.tagMask
|
||||
self.namespaces = base.namespaces
|
||||
self.anchorIndex = base.anchorIndex
|
||||
self.earlierId = base.earlierId
|
||||
self.laterId = base.laterId
|
||||
self.holeEarlier = base.holeEarlier
|
||||
self.holeLater = base.holeLater
|
||||
self.entries = base.entries
|
||||
self.fixedReadStates = combinedReadStates
|
||||
self.transientReadStates = transientReadStates
|
||||
self.topTaggedMessages = base.topTaggedMessages
|
||||
self.additionalData = base.additionalData
|
||||
self.isLoading = base.isLoading
|
||||
self.isAddedToChatList = base.isAddedToChatList
|
||||
|
||||
if let combinedReadStates = combinedReadStates {
|
||||
switch combinedReadStates {
|
||||
case let .peer(states):
|
||||
var hasUnread = false
|
||||
for (_, readState) in states {
|
||||
if readState.count > 0 {
|
||||
hasUnread = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var maxIndex: MessageIndex?
|
||||
|
||||
if hasUnread {
|
||||
var peerIds = Set<PeerId>()
|
||||
for entry in entries {
|
||||
peerIds.insert(entry.index.id.peerId)
|
||||
}
|
||||
for peerId in peerIds {
|
||||
if let combinedReadState = states[peerId] {
|
||||
for (namespace, state) in combinedReadState.states {
|
||||
var maxNamespaceIndex: MessageIndex?
|
||||
var index = entries.count - 1
|
||||
for entry in entries.reversed() {
|
||||
if entry.index.id.peerId == peerId && entry.index.id.namespace == namespace && state.isIncomingMessageIndexRead(entry.index) {
|
||||
maxNamespaceIndex = entry.index
|
||||
break
|
||||
}
|
||||
index -= 1
|
||||
}
|
||||
if maxNamespaceIndex == nil && index == -1 && entries.count != 0 {
|
||||
index = 0
|
||||
for entry in entries {
|
||||
if entry.index.id.peerId == peerId && entry.index.id.namespace == namespace {
|
||||
maxNamespaceIndex = entry.index.peerLocalPredecessor()
|
||||
break
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
if let _ = maxNamespaceIndex , index + 1 < entries.count {
|
||||
for i in index + 1 ..< entries.count {
|
||||
if entries[i].message.flags.intersection(.IsIncomingMask).isEmpty {
|
||||
maxNamespaceIndex = entries[i].message.index
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if let maxNamespaceIndex = maxNamespaceIndex, maxIndex == nil || maxIndex! < maxNamespaceIndex {
|
||||
maxIndex = maxNamespaceIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.maxReadIndex = maxIndex
|
||||
}
|
||||
} else {
|
||||
self.maxReadIndex = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ public enum MessageHistoryInput: Equatable, Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
case automatic(Automatic?)
|
||||
case automatic(threadId: Int64?, info: Automatic?)
|
||||
case external(MessageHistoryViewExternalInput, MessageTags?)
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
@ -27,8 +27,8 @@ public enum MessageHistoryInput: Equatable, Hashable {
|
||||
private extension MessageHistoryInput {
|
||||
func fetch(postbox: PostboxImpl, peerId: PeerId, namespace: MessageId.Namespace, from fromIndex: MessageIndex, includeFrom: Bool, to toIndex: MessageIndex, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, limit: Int) -> [IntermediateMessage] {
|
||||
switch self {
|
||||
case let .automatic(automatic):
|
||||
var items = postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: automatic?.tag, threadId: nil, from: fromIndex, includeFrom: includeFrom, to: toIndex, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, limit: limit)
|
||||
case let .automatic(threadId, automatic):
|
||||
var items = postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: automatic?.tag, threadId: threadId, from: fromIndex, includeFrom: includeFrom, to: toIndex, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, limit: limit)
|
||||
if let automatic = automatic, automatic.appendMessagesFromTheSameGroup {
|
||||
enum Direction {
|
||||
case lowToHigh
|
||||
@ -171,12 +171,20 @@ private extension MessageHistoryInput {
|
||||
|
||||
func getMessageCountInRange(postbox: PostboxImpl, peerId: PeerId, namespace: MessageId.Namespace, lowerBound: MessageIndex, upperBound: MessageIndex) -> Int {
|
||||
switch self {
|
||||
case let .automatic(automatic):
|
||||
case let .automatic(threadId, automatic):
|
||||
if let automatic = automatic {
|
||||
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 {
|
||||
if let threadId = threadId {
|
||||
return postbox.messageHistoryThreadsTable.getMessageCountInRange(threadId: threadId, peerId: peerId, namespace: namespace, lowerBound: lowerBound, upperBound: upperBound)
|
||||
} else {
|
||||
return postbox.messageHistoryTable.getMessageCountInRange(peerId: peerId, namespace: namespace, tag: nil, lowerBound: lowerBound, upperBound: upperBound)
|
||||
}
|
||||
}
|
||||
case .external:
|
||||
return 0
|
||||
}
|
||||
@ -492,8 +500,9 @@ private func sampleHoleRanges(input: MessageHistoryInput, orderedEntriesBySpace:
|
||||
var tag: MessageTags?
|
||||
var threadId: Int64?
|
||||
switch input {
|
||||
case let .automatic(automatic):
|
||||
case let .automatic(threadIdValue, automatic):
|
||||
tag = automatic?.tag
|
||||
threadId = threadIdValue
|
||||
case let .external(value, _):
|
||||
switch value.content {
|
||||
case let .thread(_, id, _):
|
||||
@ -1016,9 +1025,9 @@ final class HistoryViewLoadedState {
|
||||
|
||||
let input: MessageHistoryInput
|
||||
switch locations {
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, threadId):
|
||||
peerIds.append(peerId)
|
||||
input = .automatic(tag.flatMap { tag in
|
||||
input = .automatic(threadId: threadId, info: tag.flatMap { tag in
|
||||
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup)
|
||||
})
|
||||
case let .associated(peerId, associatedId):
|
||||
@ -1026,7 +1035,7 @@ final class HistoryViewLoadedState {
|
||||
if let associatedId = associatedId {
|
||||
peerIds.append(associatedId.peerId)
|
||||
}
|
||||
input = .automatic(tag.flatMap { tag in
|
||||
input = .automatic(threadId: nil, info: tag.flatMap { tag in
|
||||
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup)
|
||||
})
|
||||
case let .external(external):
|
||||
@ -1482,9 +1491,11 @@ final class HistoryViewLoadedState {
|
||||
|
||||
private func fetchHoles(postbox: PostboxImpl, locations: MessageHistoryViewInput, tag: MessageTags?, namespaces: MessageIdNamespaces) -> [PeerIdAndNamespace: IndexSet] {
|
||||
var peerIds: [PeerId] = []
|
||||
var threadId: Int64?
|
||||
switch locations {
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, threadIdValue):
|
||||
peerIds.append(peerId)
|
||||
threadId = threadIdValue
|
||||
case let .associated(peerId, associatedId):
|
||||
peerIds.append(peerId)
|
||||
if let associatedId = associatedId {
|
||||
@ -1508,12 +1519,26 @@ private func fetchHoles(postbox: PostboxImpl, locations: MessageHistoryViewInput
|
||||
var holesBySpace: [PeerIdAndNamespace: IndexSet] = [:]
|
||||
let holeSpace = tag.flatMap(MessageHistoryHoleSpace.tag) ?? .everywhere
|
||||
for peerId in peerIds {
|
||||
if let threadId = threadId {
|
||||
for namespace in postbox.messageHistoryThreadHoleIndexTable.existingNamespaces(peerId: peerId, threadId: threadId, holeSpace: holeSpace) {
|
||||
if namespaces.contains(namespace) {
|
||||
let indices = postbox.messageHistoryThreadHoleIndexTable.closest(peerId: peerId, threadId: threadId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
|
||||
if !indices.isEmpty {
|
||||
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
|
||||
assert(canContainHoles(peerIdAndNamespace, input: .automatic(threadId: threadId, info: tag.flatMap { tag in
|
||||
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: false)
|
||||
}), seedConfiguration: postbox.seedConfiguration))
|
||||
holesBySpace[peerIdAndNamespace] = indices
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for namespace in postbox.messageHistoryHoleIndexTable.existingNamespaces(peerId: peerId, holeSpace: holeSpace) {
|
||||
if namespaces.contains(namespace) {
|
||||
let indices = postbox.messageHistoryHoleIndexTable.closest(peerId: peerId, namespace: namespace, space: holeSpace, range: 1 ... (Int32.max - 1))
|
||||
if !indices.isEmpty {
|
||||
let peerIdAndNamespace = PeerIdAndNamespace(peerId: peerId, namespace: namespace)
|
||||
assert(canContainHoles(peerIdAndNamespace, input: .automatic(tag.flatMap { tag in
|
||||
assert(canContainHoles(peerIdAndNamespace, input: .automatic(threadId: nil, info: tag.flatMap { tag in
|
||||
MessageHistoryInput.Automatic(tag: tag, appendMessagesFromTheSameGroup: false)
|
||||
}), seedConfiguration: postbox.seedConfiguration))
|
||||
holesBySpace[peerIdAndNamespace] = indices
|
||||
@ -1521,6 +1546,7 @@ private func fetchHoles(postbox: PostboxImpl, locations: MessageHistoryViewInput
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return holesBySpace
|
||||
case let .external(input):
|
||||
switch input.content {
|
||||
@ -1612,8 +1638,12 @@ enum HistoryViewState {
|
||||
case .unread:
|
||||
let anchorPeerId: PeerId
|
||||
switch locations {
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, threadId):
|
||||
anchorPeerId = peerId
|
||||
if threadId != nil {
|
||||
self = .loaded(HistoryViewLoadedState(anchor: .upperBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
|
||||
return
|
||||
}
|
||||
case let .associated(peerId, _):
|
||||
anchorPeerId = peerId
|
||||
case .external:
|
||||
@ -1661,6 +1691,8 @@ enum HistoryViewState {
|
||||
case let .message(messageId):
|
||||
var threadId: Int64?
|
||||
switch locations {
|
||||
case let .single(_, threadIdValue):
|
||||
threadId = threadIdValue
|
||||
case let .external(input):
|
||||
switch input.content {
|
||||
case let .thread(_, id, _):
|
||||
|
||||
@ -25,7 +25,7 @@ public struct MessageOfInterestHole: Hashable, Equatable, CustomStringConvertibl
|
||||
}
|
||||
|
||||
public enum MessageOfInterestViewLocation: Hashable {
|
||||
case peer(PeerId)
|
||||
case peer(peerId: PeerId, threadId: Int64?)
|
||||
}
|
||||
|
||||
final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
||||
@ -45,9 +45,9 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
||||
let mainPeerId: PeerId
|
||||
let peerIds: MessageHistoryViewInput
|
||||
switch self.location {
|
||||
case let .peer(id):
|
||||
case let .peer(id, threadId):
|
||||
mainPeerId = id
|
||||
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
|
||||
peerIds = postbox.peerIdsForLocation(.peer(peerId: id, threadId: threadId), ignoreRelatedChats: false)
|
||||
}
|
||||
self.peerIds = peerIds
|
||||
var anchor: HistoryViewInputAnchor = .upperBound
|
||||
@ -107,12 +107,14 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
||||
|
||||
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
||||
var peerId: PeerId
|
||||
var threadId: Int64?
|
||||
switch self.location {
|
||||
case let .peer(id):
|
||||
case let .peer(id, threadIdValue):
|
||||
peerId = id
|
||||
threadId = threadIdValue
|
||||
}
|
||||
var anchor: HistoryViewInputAnchor = self.anchor
|
||||
if transaction.alteredInitialPeerCombinedReadStates[peerId] != nil {
|
||||
if threadId == nil, transaction.alteredInitialPeerCombinedReadStates[peerId] != nil {
|
||||
let updatedAnchor: HistoryViewInputAnchor = .upperBound
|
||||
if let combinedState = postbox.readStateTable.getCombinedState(peerId), let state = combinedState.states.first, state.1.count != 0 {
|
||||
switch state.1 {
|
||||
@ -129,8 +131,8 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
||||
self.anchor = anchor
|
||||
let peerIds: MessageHistoryViewInput
|
||||
switch self.location {
|
||||
case let .peer(id):
|
||||
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
|
||||
case let .peer(id, threadId):
|
||||
peerIds = postbox.peerIdsForLocation(.peer(peerId: id, threadId: threadId), ignoreRelatedChats: false)
|
||||
}
|
||||
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, ignoreMessagesInTimestampRange: nil, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
|
||||
return self.updateFromView()
|
||||
@ -138,9 +140,11 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
||||
var reloadView = false
|
||||
if !transaction.currentPeerHoleOperations.isEmpty {
|
||||
var allPeerIds: [PeerId]
|
||||
var threadId: Int64?
|
||||
switch peerIds {
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, threadIdValue):
|
||||
allPeerIds = [peerId]
|
||||
threadId = threadIdValue
|
||||
case let .associated(peerId, attachedMessageId):
|
||||
allPeerIds = [peerId]
|
||||
if let attachedMessageId = attachedMessageId {
|
||||
@ -151,7 +155,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
||||
break
|
||||
}
|
||||
for (key, _) in transaction.currentPeerHoleOperations {
|
||||
if allPeerIds.contains(key.peerId) {
|
||||
if allPeerIds.contains(key.peerId) && key.threadId == threadId {
|
||||
reloadView = true
|
||||
break
|
||||
}
|
||||
@ -160,8 +164,8 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
||||
if reloadView {
|
||||
let peerIds: MessageHistoryViewInput
|
||||
switch self.location {
|
||||
case let .peer(id):
|
||||
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
|
||||
case let .peer(id, threadId):
|
||||
peerIds = postbox.peerIdsForLocation(.peer(peerId: id, threadId: threadId), ignoreRelatedChats: false)
|
||||
}
|
||||
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, ignoreMessagesInTimestampRange: nil, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
|
||||
}
|
||||
|
||||
@ -67,14 +67,14 @@ public final class Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
public func addHole(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
public func addHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.addHole(peerId: peerId, namespace: namespace, space: space, range: range)
|
||||
self.postbox?.addHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range)
|
||||
}
|
||||
|
||||
public func removeHole(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
public func removeHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.removeHole(peerId: peerId, namespace: namespace, space: space, range: range)
|
||||
self.postbox?.removeHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range)
|
||||
}
|
||||
|
||||
public func getHole(containing id: MessageId) -> [MessageHistoryHoleSpace: ClosedRange<MessageId.Id>] {
|
||||
@ -87,16 +87,6 @@ public final class Transaction {
|
||||
return self.postbox?.messageHistoryHoleIndexTable.closest(peerId: peerId, namespace: namespace, space: .everywhere, range: 1 ... (Int32.max - 1)) ?? IndexSet()
|
||||
}
|
||||
|
||||
public func addThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.addThreadIndexHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range)
|
||||
}
|
||||
|
||||
public func removeThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.removeThreadIndexHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range)
|
||||
}
|
||||
|
||||
public func getThreadIndexHoles(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace) -> IndexSet {
|
||||
assert(!self.disposed)
|
||||
return self.postbox!.messageHistoryThreadHoleIndexTable.closest(peerId: peerId, threadId: threadId, namespace: namespace, space: .everywhere, range: 1 ... (Int32.max - 1))
|
||||
@ -137,12 +127,12 @@ public final class Transaction {
|
||||
self.postbox?.replaceChatListHole(groupId: groupId, index: index, hole: hole)
|
||||
}
|
||||
|
||||
public func deleteMessages(_ messageIds: [MessageId], forEachMedia: (Media) -> Void) {
|
||||
public func deleteMessages(_ messageIds: [MessageId], forEachMedia: ((Media) -> Void)?) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.deleteMessages(messageIds, forEachMedia: forEachMedia)
|
||||
}
|
||||
|
||||
public func deleteMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, forEachMedia: (Media) -> Void) {
|
||||
public func deleteMessagesInRange(peerId: PeerId, namespace: MessageId.Namespace, minId: MessageId.Id, maxId: MessageId.Id, forEachMedia: ((Media) -> Void)?) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.deleteMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, forEachMedia: forEachMedia)
|
||||
}
|
||||
@ -151,12 +141,12 @@ public final class Transaction {
|
||||
self.postbox?.withAllMessages(peerId: peerId, namespace: namespace, f)
|
||||
}
|
||||
|
||||
public func clearHistory(_ peerId: PeerId, threadId: Int64?, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: (Media) -> Void) {
|
||||
public func clearHistory(_ peerId: PeerId, threadId: Int64?, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: ((Media) -> Void)?) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.clearHistory(peerId, threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, forEachMedia: forEachMedia)
|
||||
}
|
||||
|
||||
public func removeAllMessagesWithAuthor(_ peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, forEachMedia: (Media) -> Void) {
|
||||
public func removeAllMessagesWithAuthor(_ peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, forEachMedia: ((Media) -> Void)?) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.removeAllMessagesWithAuthor(peerId, authorId: authorId, namespace: namespace, forEachMedia: forEachMedia)
|
||||
}
|
||||
@ -166,7 +156,7 @@ public final class Transaction {
|
||||
self.postbox?.removeAllMessagesWithGlobalTag(tag: tag)
|
||||
}
|
||||
|
||||
public func removeAllMessagesWithForwardAuthor(_ peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace, forEachMedia: (Media) -> Void) {
|
||||
public func removeAllMessagesWithForwardAuthor(_ peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace, forEachMedia: ((Media) -> Void)?) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.removeAllMessagesWithForwardAuthor(peerId, forwardAuthorId: forwardAuthorId, namespace: namespace, forEachMedia: forEachMedia)
|
||||
}
|
||||
@ -188,7 +178,7 @@ public final class Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
public func deleteMessagesWithGlobalIds(_ ids: [Int32], forEachMedia: (Media) -> Void) {
|
||||
public func deleteMessagesWithGlobalIds(_ ids: [Int32], forEachMedia: ((Media) -> Void)?) {
|
||||
assert(!self.disposed)
|
||||
if let postbox = self.postbox {
|
||||
let messageIds = postbox.messageIdsForGlobalIds(ids)
|
||||
@ -229,7 +219,7 @@ public final class Transaction {
|
||||
public func applyInteractiveReadMaxIndex(_ messageIndex: MessageIndex) -> [MessageId] {
|
||||
assert(!self.disposed)
|
||||
if let postbox = self.postbox {
|
||||
return postbox.applyInteractiveReadMaxIndex(messageIndex)
|
||||
return postbox.applyInteractiveReadMaxIndex(messageIndex: messageIndex)
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
@ -328,7 +318,7 @@ public final class Transaction {
|
||||
return self.postbox?.readStateTable.getCombinedState(id)
|
||||
}
|
||||
|
||||
public func getPeerNotificationSettings(_ id: PeerId) -> PeerNotificationSettings? {
|
||||
public func getPeerNotificationSettings(id: PeerId) -> PeerNotificationSettings? {
|
||||
assert(!self.disposed)
|
||||
return self.postbox?.peerNotificationSettingsTable.getEffective(id)
|
||||
}
|
||||
@ -894,7 +884,7 @@ public final class Transaction {
|
||||
let notificationsPeerId = peer.notificationSettingsPeerId ?? peerId
|
||||
let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId)
|
||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId))
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: predicate.messageTagSummary)
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: predicate.messageTagSummary)
|
||||
|
||||
if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) {
|
||||
includedPeerIds[peer.id] = true
|
||||
@ -1002,14 +992,14 @@ public final class Transaction {
|
||||
return self.postbox?.getPendingMessageAction(type: type, id: id)
|
||||
}
|
||||
|
||||
public func getMessageTagSummary(peerId: PeerId, tagMask: MessageTags, namespace: MessageId.Namespace) -> MessageHistoryTagNamespaceSummary? {
|
||||
public func getMessageTagSummary(peerId: PeerId, threadId: Int64?, tagMask: MessageTags, namespace: MessageId.Namespace) -> MessageHistoryTagNamespaceSummary? {
|
||||
assert(!self.disposed)
|
||||
return self.postbox?.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, namespace: namespace))
|
||||
return self.postbox?.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, threadId: threadId, namespace: namespace))
|
||||
}
|
||||
|
||||
public func replaceMessageTagSummary(peerId: PeerId, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
|
||||
public func replaceMessageTagSummary(peerId: PeerId, threadId: Int64?, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.replaceMessageTagSummary(peerId: peerId, tagMask: tagMask, namespace: namespace, count: count, maxId: maxId)
|
||||
self.postbox?.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: tagMask, namespace: namespace, count: count, maxId: maxId)
|
||||
}
|
||||
|
||||
public func getPendingMessageActionsSummary(peerId: PeerId, type: PendingMessageActionType, namespace: MessageId.Namespace) -> Int32? {
|
||||
@ -1017,13 +1007,17 @@ public final class Transaction {
|
||||
return self.postbox?.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(peerId, namespace, type))
|
||||
}
|
||||
|
||||
public func getMessageIndicesWithTag(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags) -> [MessageIndex] {
|
||||
public func getMessageIndicesWithTag(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, tag: MessageTags) -> [MessageIndex] {
|
||||
assert(!self.disposed)
|
||||
guard let postbox = self.postbox else {
|
||||
return []
|
||||
}
|
||||
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] {
|
||||
assert(!self.disposed)
|
||||
@ -1447,6 +1441,7 @@ final class PostboxImpl {
|
||||
let messageHistoryFailedTable: MessageHistoryFailedTable
|
||||
let messageHistoryTagsTable: MessageHistoryTagsTable
|
||||
let messageHistoryThreadsTable: MessageHistoryThreadsTable
|
||||
let messageHistoryThreadTagsTable: MessageHistoryThreadTagsTable
|
||||
let messageHistoryThreadHoleIndexTable: MessageHistoryThreadHoleIndexTable
|
||||
let messageHistoryThreadReverseIndexTable: MessageHistoryThreadReverseIndexTable
|
||||
let messageHistoryThreadIndexTable: MessageHistoryThreadIndexTable
|
||||
@ -1524,6 +1519,7 @@ final class PostboxImpl {
|
||||
self.pendingMessageActionsTable = PendingMessageActionsTable(valueBox: self.valueBox, table: PendingMessageActionsTable.tableSpec(46), useCaches: useCaches, metadataTable: self.pendingMessageActionsMetadataTable)
|
||||
self.messageHistoryTagsTable = MessageHistoryTagsTable(valueBox: self.valueBox, table: MessageHistoryTagsTable.tableSpec(12), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
|
||||
self.messageHistoryThreadsTable = MessageHistoryThreadsTable(valueBox: self.valueBox, table: MessageHistoryThreadsTable.tableSpec(62), useCaches: useCaches)
|
||||
self.messageHistoryThreadTagsTable = MessageHistoryThreadTagsTable(valueBox: self.valueBox, table: MessageHistoryThreadTagsTable.tableSpec(71), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
|
||||
self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
|
||||
self.messageHistoryThreadReverseIndexTable = MessageHistoryThreadReverseIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadReverseIndexTable.tableSpec(69), useCaches: useCaches)
|
||||
self.messageHistoryThreadIndexTable = MessageHistoryThreadIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadIndexTable.tableSpec(70), reverseIndexTable: self.messageHistoryThreadReverseIndexTable, useCaches: useCaches)
|
||||
@ -1538,7 +1534,7 @@ final class PostboxImpl {
|
||||
self.timestampBasedMessageAttributesTable = TimestampBasedMessageAttributesTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(34), useCaches: useCaches, indexTable: self.timestampBasedMessageAttributesIndexTable)
|
||||
self.textIndexTable = MessageHistoryTextIndexTable(valueBox: self.valueBox, table: MessageHistoryTextIndexTable.tableSpec(41))
|
||||
self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55), useCaches: useCaches)
|
||||
self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), useCaches: useCaches, seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, threadsTable: self.messageHistoryThreadsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, timeBasedAttributesTable: self.timestampBasedMessageAttributesTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable)
|
||||
self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), useCaches: useCaches, seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, threadsTable: self.messageHistoryThreadsTable, threadTagsTable: self.messageHistoryThreadTagsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, timeBasedAttributesTable: self.timestampBasedMessageAttributesTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable)
|
||||
self.peerChatStateTable = PeerChatStateTable(valueBox: self.valueBox, table: PeerChatStateTable.tableSpec(13), useCaches: useCaches)
|
||||
self.peerNameTokenIndexTable = ReverseIndexReferenceTable<PeerIdReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<PeerIdReverseIndexReference>.tableSpec(26), useCaches: useCaches)
|
||||
self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), useCaches: useCaches, peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable)
|
||||
@ -1582,6 +1578,7 @@ final class PostboxImpl {
|
||||
tables.append(self.messageHistoryFailedTable)
|
||||
tables.append(self.messageHistoryTagsTable)
|
||||
tables.append(self.messageHistoryThreadsTable)
|
||||
tables.append(self.messageHistoryThreadTagsTable)
|
||||
tables.append(self.messageHistoryThreadHoleIndexTable)
|
||||
tables.append(self.messageHistoryThreadReverseIndexTable)
|
||||
tables.append(self.messageHistoryThreadIndexTable)
|
||||
@ -1818,20 +1815,20 @@ final class PostboxImpl {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func addHole(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
fileprivate func addHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
if let threadId = threadId {
|
||||
self.messageHistoryThreadHoleIndexTable.add(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
||||
} else {
|
||||
self.messageHistoryHoleIndexTable.add(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func removeHole(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
fileprivate func removeHole(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
if let threadId = threadId {
|
||||
self.messageHistoryThreadHoleIndexTable.remove(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
||||
} else {
|
||||
self.messageHistoryHoleIndexTable.remove(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
||||
}
|
||||
|
||||
fileprivate func addThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
self.messageHistoryThreadHoleIndexTable.add(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
||||
}
|
||||
|
||||
fileprivate func removeThreadIndexHole(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange<MessageId.Id>) {
|
||||
self.messageHistoryThreadHoleIndexTable.remove(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations)
|
||||
}
|
||||
|
||||
fileprivate func recalculateChatListGroupStats(groupId: PeerGroupId) {
|
||||
@ -1844,11 +1841,11 @@ final class PostboxImpl {
|
||||
self.chatListTable.replaceHole(groupId: groupId, index: index, hole: hole, operations: &self.currentChatListOperations)
|
||||
}
|
||||
|
||||
fileprivate func deleteMessages(_ messageIds: [MessageId], forEachMedia: (Media) -> Void) {
|
||||
fileprivate func deleteMessages(_ messageIds: [MessageId], forEachMedia: ((Media) -> Void)?) {
|
||||
self.messageHistoryTable.removeMessages(messageIds, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤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)
|
||||
}
|
||||
|
||||
@ -1864,7 +1861,7 @@ final class PostboxImpl {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func clearHistory(_ peerId: PeerId, threadId: Int64?, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: (Media) -> Void) {
|
||||
fileprivate func clearHistory(_ peerId: PeerId, threadId: Int64?, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: ((Media) -> Void)?) {
|
||||
if let minTimestamp = minTimestamp, let maxTimestamp = maxTimestamp {
|
||||
self.messageHistoryTable.clearHistoryInRange(peerId: peerId, threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤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 {
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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 })
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -1907,8 +1904,8 @@ final class PostboxImpl {
|
||||
self.messageHistoryTable.applyOutgoingReadMaxId(messageId, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations)
|
||||
}
|
||||
|
||||
fileprivate func applyInteractiveReadMaxIndex(_ messageIndex: MessageIndex) -> [MessageId] {
|
||||
let peerIds = self.peerIdsForLocation(.peer(messageIndex.id.peerId), ignoreRelatedChats: false)
|
||||
fileprivate func applyInteractiveReadMaxIndex(messageIndex: MessageIndex) -> [MessageId] {
|
||||
let peerIds = self.peerIdsForLocation(.peer(peerId: messageIndex.id.peerId, threadId: nil), ignoreRelatedChats: false)
|
||||
switch peerIds {
|
||||
case let .associated(_, messageId):
|
||||
if let messageId = messageId, let readState = self.readStateTable.getCombinedState(messageId.peerId), readState.count != 0 {
|
||||
@ -2487,8 +2484,8 @@ final class PostboxImpl {
|
||||
return self.pendingMessageActionsTable.getAction(id: id, type: type)
|
||||
}
|
||||
|
||||
fileprivate func replaceMessageTagSummary(peerId: PeerId, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
|
||||
let key = MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, namespace: namespace)
|
||||
fileprivate func replaceMessageTagSummary(peerId: PeerId, threadId: Int64?, tagMask: MessageTags, namespace: MessageId.Namespace, count: Int32, maxId: MessageId.Id) {
|
||||
let key = MessageHistoryTagsSummaryKey(tag: tagMask, peerId: peerId, threadId: threadId, namespace: namespace)
|
||||
self.messageHistoryTagsSummaryTable.replace(key: key, count: count, maxId: maxId, updatedSummaries: &self.currentUpdatedMessageTagSummaries)
|
||||
}
|
||||
|
||||
@ -2611,8 +2608,8 @@ final class PostboxImpl {
|
||||
|
||||
func resolvedChatLocationInput(chatLocation: ChatLocationInput) -> Signal<(ResolvedChatLocationInput, Bool), NoError> {
|
||||
switch chatLocation {
|
||||
case let .peer(peerId):
|
||||
return .single((.peer(peerId), false))
|
||||
case let .peer(peerId, threadId):
|
||||
return .single((.peer(peerId: peerId, threadId: threadId), false))
|
||||
case .thread(_, _, let data), .feed(_, let data):
|
||||
return Signal { subscriber in
|
||||
var isHoleFill = false
|
||||
@ -2629,9 +2626,9 @@ final class PostboxImpl {
|
||||
func peerIdsForLocation(_ chatLocation: ResolvedChatLocationInput, ignoreRelatedChats: Bool) -> MessageHistoryViewInput {
|
||||
var peerIds: MessageHistoryViewInput
|
||||
switch chatLocation {
|
||||
case let .peer(peerId):
|
||||
peerIds = .single(peerId)
|
||||
if !ignoreRelatedChats, let associatedMessageId = self.cachedPeerDataTable.get(peerId)?.associatedHistoryMessageId, associatedMessageId.peerId != peerId {
|
||||
case let .peer(peerId, threadId):
|
||||
peerIds = .single(peerId: peerId, threadId: threadId)
|
||||
if !ignoreRelatedChats, threadId == nil, let associatedMessageId = self.cachedPeerDataTable.get(peerId)?.associatedHistoryMessageId, associatedMessageId.peerId != peerId {
|
||||
peerIds = .associated(peerId, associatedMessageId)
|
||||
}
|
||||
case let .external(input):
|
||||
@ -2640,7 +2637,7 @@ final class PostboxImpl {
|
||||
return peerIds
|
||||
}
|
||||
|
||||
public func aroundMessageOfInterestHistoryViewForChatLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, count: Int, clipHoles: Bool = true, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
public func aroundMessageOfInterestHistoryViewForChatLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, count: Int, clipHoles: Bool = true, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, customUnreadMessageId: MessageId?, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
return self.resolvedChatLocationInput(chatLocation: chatLocation)
|
||||
|> mapToSignal { chatLocationData in
|
||||
let (chatLocation, isHoleFill) = chatLocationData
|
||||
@ -2650,8 +2647,10 @@ final class PostboxImpl {
|
||||
|
||||
var anchor: HistoryViewInputAnchor = .upperBound
|
||||
switch peerIds {
|
||||
case let .single(peerId):
|
||||
if self.chatListTable.getPeerChatListIndex(peerId: peerId) != nil {
|
||||
case let .single(peerId, threadId):
|
||||
if let customUnreadMessageId = customUnreadMessageId {
|
||||
anchor = .message(customUnreadMessageId)
|
||||
} else if threadId == nil, self.chatListTable.getPeerChatListIndex(peerId: peerId) != nil {
|
||||
if let combinedState = self.readStateTable.getCombinedState(peerId), let state = combinedState.states.first, state.1.count != 0 {
|
||||
switch state.1 {
|
||||
case let .idBased(maxIncomingReadId, _, _, _, _):
|
||||
@ -2770,8 +2769,10 @@ final class PostboxImpl {
|
||||
var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] = [:]
|
||||
var mainPeerIdForTopTaggedMessages: PeerId?
|
||||
switch peerIds {
|
||||
case let .single(id):
|
||||
case let .single(id, threadId):
|
||||
if threadId == nil {
|
||||
mainPeerIdForTopTaggedMessages = id
|
||||
}
|
||||
case let .associated(id, _):
|
||||
mainPeerIdForTopTaggedMessages = id
|
||||
case .external:
|
||||
@ -2844,8 +2845,8 @@ final class PostboxImpl {
|
||||
var readStates: MessageHistoryViewReadState?
|
||||
var transientReadStates: MessageHistoryViewReadState?
|
||||
switch peerIds {
|
||||
case let .single(peerId):
|
||||
if let readState = self.readStateTable.getCombinedState(peerId) {
|
||||
case let .single(peerId, threadId):
|
||||
if threadId == nil, let readState = self.readStateTable.getCombinedState(peerId) {
|
||||
transientReadStates = .peer([peerId: readState])
|
||||
}
|
||||
case let .associated(peerId, _):
|
||||
@ -2876,8 +2877,8 @@ final class PostboxImpl {
|
||||
|
||||
let initialData: InitialMessageHistoryData
|
||||
switch peerIds {
|
||||
case let .single(peerId):
|
||||
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: nil)
|
||||
case let .single(peerId, threadId):
|
||||
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: threadId)
|
||||
case let .associated(peerId, _):
|
||||
initialData = self.initialMessageHistoryData(peerId: peerId, threadId: nil)
|
||||
case let .external(input):
|
||||
@ -3671,7 +3672,7 @@ final class PostboxImpl {
|
||||
fileprivate func addHolesEverywhere(peerNamespaces: [PeerId.Namespace], holeNamespace: MessageId.Namespace) {
|
||||
for peerId in self.chatListIndexTable.getAllPeerIds() {
|
||||
if peerNamespaces.contains(peerId.namespace) && self.messageHistoryMetadataTable.isInitialized(peerId) {
|
||||
self.addHole(peerId: peerId, namespace: holeNamespace, space: .everywhere, range: 1 ... Int32.max - 1)
|
||||
self.addHole(peerId: peerId, threadId: nil, namespace: holeNamespace, space: .everywhere, range: 1 ... Int32.max - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3818,6 +3819,7 @@ public class Postbox {
|
||||
appendMessagesFromTheSameGroup: Bool,
|
||||
namespaces: MessageIdNamespaces,
|
||||
orderStatistics: MessageHistoryViewOrderStatistics,
|
||||
customUnreadMessageId: MessageId?,
|
||||
additionalData: [AdditionalMessageHistoryViewData]
|
||||
) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
return Signal { subscriber in
|
||||
@ -3834,6 +3836,7 @@ public class Postbox {
|
||||
appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup,
|
||||
namespaces: namespaces,
|
||||
orderStatistics: orderStatistics,
|
||||
customUnreadMessageId: customUnreadMessageId,
|
||||
additionalData: additionalData
|
||||
).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion))
|
||||
}
|
||||
|
||||
@ -45,11 +45,11 @@ func resolveChatListMessageTagSummaryResultCalculation(addSummary: MessageHistor
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func resolveChatListMessageTagSummaryResultCalculation(postbox: PostboxImpl, peerId: PeerId, calculation: ChatListMessageTagSummaryResultCalculation?) -> Bool? {
|
||||
func resolveChatListMessageTagSummaryResultCalculation(postbox: PostboxImpl, peerId: PeerId, threadId: Int64?, calculation: ChatListMessageTagSummaryResultCalculation?) -> Bool? {
|
||||
guard let calculation = calculation else {
|
||||
return nil
|
||||
}
|
||||
let addSummary = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: calculation.addCount.tag, peerId: peerId, namespace: calculation.addCount.namespace))
|
||||
let addSummary = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: calculation.addCount.tag, peerId: peerId, threadId: threadId, namespace: calculation.addCount.namespace))
|
||||
let subtractSummary = postbox.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(peerId, calculation.subtractCount.namespace, calculation.subtractCount.type))
|
||||
let count = (addSummary?.count ?? 0) - subtractSummary
|
||||
return count > 0
|
||||
|
||||
@ -269,9 +269,9 @@ final class ViewTracker {
|
||||
|
||||
var updateType: ViewUpdateType = .Generic
|
||||
switch mutableView.peerIds {
|
||||
case let .single(peerId):
|
||||
case let .single(peerId, threadId):
|
||||
for key in transaction.currentPeerHoleOperations.keys {
|
||||
if key.peerId == peerId {
|
||||
if key.peerId == peerId && key.threadId == threadId {
|
||||
updateType = .FillHole
|
||||
break
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ public enum PostboxViewKey: Hashable {
|
||||
case pendingMessageActions(type: PendingMessageActionType)
|
||||
case invalidatedMessageHistoryTagSummaries(tagMask: MessageTags, namespace: MessageId.Namespace)
|
||||
case pendingMessageActionsSummary(type: PendingMessageActionType, peerId: PeerId, namespace: MessageId.Namespace)
|
||||
case historyTagSummaryView(tag: MessageTags, peerId: PeerId, namespace: MessageId.Namespace)
|
||||
case historyTagSummaryView(tag: MessageTags, peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace)
|
||||
case cachedPeerData(peerId: PeerId)
|
||||
case unreadCounts(items: [UnreadMessageCountsItem])
|
||||
case combinedReadState(peerId: PeerId)
|
||||
@ -38,7 +38,7 @@ public enum PostboxViewKey: Hashable {
|
||||
case isContact(id: PeerId)
|
||||
case chatListIndex(id: PeerId)
|
||||
case peerTimeoutAttributes
|
||||
case messageHistoryThreadIndex(id: PeerId)
|
||||
case messageHistoryThreadIndex(id: PeerId, summaryComponents: ChatListEntrySummaryComponents)
|
||||
case messageHistoryThreadInfo(peerId: PeerId, threadId: Int64)
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
@ -68,9 +68,10 @@ public enum PostboxViewKey: Hashable {
|
||||
hasher.combine(type)
|
||||
hasher.combine(peerId)
|
||||
hasher.combine(namespace)
|
||||
case let .historyTagSummaryView(tag, peerId, namespace):
|
||||
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
|
||||
hasher.combine(tag)
|
||||
hasher.combine(peerId)
|
||||
hasher.combine(threadId)
|
||||
hasher.combine(namespace)
|
||||
case let .cachedPeerData(peerId):
|
||||
hasher.combine(peerId)
|
||||
@ -126,7 +127,7 @@ public enum PostboxViewKey: Hashable {
|
||||
hasher.combine(id)
|
||||
case .peerTimeoutAttributes:
|
||||
hasher.combine(17)
|
||||
case let .messageHistoryThreadIndex(id):
|
||||
case let .messageHistoryThreadIndex(id, _):
|
||||
hasher.combine(id)
|
||||
case let .messageHistoryThreadInfo(peerId, threadId):
|
||||
hasher.combine(peerId)
|
||||
@ -202,8 +203,8 @@ public enum PostboxViewKey: Hashable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .historyTagSummaryView(tag, peerId, namespace):
|
||||
if case .historyTagSummaryView(tag, peerId, namespace) = rhs {
|
||||
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
|
||||
if case .historyTagSummaryView(tag, peerId, threadId, namespace) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -358,8 +359,8 @@ public enum PostboxViewKey: Hashable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .messageHistoryThreadIndex(id):
|
||||
if case .messageHistoryThreadIndex(id) = rhs {
|
||||
case let .messageHistoryThreadIndex(id, summaryComponents):
|
||||
if case .messageHistoryThreadIndex(id, summaryComponents) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -398,8 +399,8 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
|
||||
return MutableInvalidatedMessageHistoryTagSummariesView(postbox: postbox, tagMask: tagMask, namespace: namespace)
|
||||
case let .pendingMessageActionsSummary(type, peerId, namespace):
|
||||
return MutablePendingMessageActionsSummaryView(postbox: postbox, type: type, peerId: peerId, namespace: namespace)
|
||||
case let .historyTagSummaryView(tag, peerId, namespace):
|
||||
return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, namespace: namespace)
|
||||
case let .historyTagSummaryView(tag, peerId, threadId, namespace):
|
||||
return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, threadId: threadId, namespace: namespace)
|
||||
case let .cachedPeerData(peerId):
|
||||
return MutableCachedPeerDataView(postbox: postbox, peerId: peerId)
|
||||
case let .unreadCounts(items):
|
||||
@ -450,8 +451,8 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
|
||||
return MutableChatListIndexView(postbox: postbox, id: id)
|
||||
case .peerTimeoutAttributes:
|
||||
return MutablePeerTimeoutAttributesView(postbox: postbox)
|
||||
case let .messageHistoryThreadIndex(id):
|
||||
return MutableMessageHistoryThreadIndexView(postbox: postbox, peerId: id)
|
||||
case let .messageHistoryThreadIndex(id, summaryComponents):
|
||||
return MutableMessageHistoryThreadIndexView(postbox: postbox, peerId: id, summaryComponents: summaryComponents)
|
||||
case let .messageHistoryThreadInfo(peerId, threadId):
|
||||
return MutableMessageHistoryThreadInfoView(postbox: postbox, peerId: peerId, threadId: threadId)
|
||||
}
|
||||
|
||||
@ -781,16 +781,16 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
|
||||
let presentationData = context.sharedContext.currentPresentationData.modify {$0}
|
||||
|
||||
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
||||
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: nil, sound: sound) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
|
||||
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, muteInterval: muteInterval) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: nil, muteInterval: muteInterval) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerDisplayPreviews:(PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
|
||||
peerId, displayPreviews in
|
||||
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, displayPreviews: displayPreviews) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: nil, displayPreviews: displayPreviews) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
self.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
||||
@ -814,7 +814,7 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
|
||||
let mode = stateValue.with { $0.mode }
|
||||
|
||||
dismissInputImpl?()
|
||||
presentControllerImpl?(notificationPeerExceptionController(context: context, peer: peer._asPeer(), mode: mode, updatePeerSound: { peerId, sound in
|
||||
presentControllerImpl?(notificationPeerExceptionController(context: context, peer: peer._asPeer(), threadId: nil, mode: mode, updatePeerSound: { peerId, sound in
|
||||
_ = updatePeerSound(peer.id, sound).start(next: { _ in
|
||||
updateNotificationsDisposable.set(nil)
|
||||
_ = combineLatest(updatePeerSound(peer.id, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in
|
||||
|
||||
@ -365,7 +365,7 @@ private struct NotificationExceptionPeerState : Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public func notificationPeerExceptionController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: Peer, mode: NotificationExceptionMode, edit: Bool = false, updatePeerSound: @escaping(PeerId, PeerMessageSound) -> Void, updatePeerNotificationInterval: @escaping(PeerId, Int32?) -> Void, updatePeerDisplayPreviews: @escaping(PeerId, PeerNotificationDisplayPreviews) -> Void, removePeerFromExceptions: @escaping () -> Void, modifiedPeer: @escaping () -> Void) -> ViewController {
|
||||
public func notificationPeerExceptionController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: Peer, threadId: Int64?, mode: NotificationExceptionMode, edit: Bool = false, updatePeerSound: @escaping(PeerId, PeerMessageSound) -> Void, updatePeerNotificationInterval: @escaping(PeerId, Int32?) -> Void, updatePeerDisplayPreviews: @escaping(PeerId, PeerNotificationDisplayPreviews) -> Void, removePeerFromExceptions: @escaping () -> Void, modifiedPeer: @escaping () -> Void) -> ViewController {
|
||||
let initialState = NotificationExceptionPeerState(canRemove: false)
|
||||
let statePromise = Promise(initialState)
|
||||
let stateValue = Atomic(value: initialState)
|
||||
@ -420,10 +420,13 @@ public func notificationPeerExceptionController(context: AccountContext, updated
|
||||
|
||||
statePromise.set(context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peer.id),
|
||||
EngineDataOptional(threadId.flatMap { TelegramEngine.EngineData.Item.Peer.ThreadNotificationSettings(id: peer.id, threadId: $0) }),
|
||||
TelegramEngine.EngineData.Item.NotificationSettings.Global()
|
||||
)
|
||||
|> map { notificationSettings, globalNotificationSettings -> NotificationExceptionPeerState in
|
||||
var state = NotificationExceptionPeerState(canRemove: mode.peerIds.contains(peer.id), notifications: notificationSettings._asNotificationSettings())
|
||||
|> map { peerNotificationSettings, threadNotificationSettings, globalNotificationSettings -> NotificationExceptionPeerState in
|
||||
let effectiveSettings = threadNotificationSettings ?? peerNotificationSettings
|
||||
|
||||
var state = NotificationExceptionPeerState(canRemove: mode.peerIds.contains(peer.id), notifications: effectiveSettings._asNotificationSettings())
|
||||
let globalSettings = globalNotificationSettings
|
||||
switch mode {
|
||||
case .channels:
|
||||
|
||||
@ -438,16 +438,16 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
|
||||
}
|
||||
|
||||
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
||||
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: nil, sound: sound) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
|
||||
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, muteInterval: muteInterval) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: nil, muteInterval: muteInterval) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerDisplayPreviews:(PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
|
||||
peerId, displayPreviews in
|
||||
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, displayPreviews: displayPreviews) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: nil, displayPreviews: displayPreviews) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
var peerIds: Set<PeerId> = Set(mode.peerIds)
|
||||
@ -502,7 +502,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
|
||||
}
|
||||
|
||||
let mode = stateValue.with { $0.mode }
|
||||
pushControllerImpl?(notificationPeerExceptionController(context: context, peer: peer._asPeer(), mode: mode, updatePeerSound: { peerId, sound in
|
||||
pushControllerImpl?(notificationPeerExceptionController(context: context, peer: peer._asPeer(), threadId: nil, mode: mode, updatePeerSound: { peerId, sound in
|
||||
_ = updatePeerSound(peer.id, sound).start(next: { _ in
|
||||
updateNotificationsDisposable.set(nil)
|
||||
_ = combineLatest(updatePeerSound(peer.id, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in
|
||||
|
||||
@ -219,7 +219,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
||||
var items: [ChatListItem] = []
|
||||
|
||||
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, activateChatPreview: { _, _, gesture, _ in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
||||
@ -839,7 +839,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
var items: [ChatListItem] = []
|
||||
|
||||
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, activateChatPreview: { _, _, gesture, _ in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in
|
||||
|
||||
@ -363,7 +363,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
var items: [ChatListItem] = []
|
||||
|
||||
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, activateChatPreview: { _, _, gesture, _ in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in
|
||||
|
||||
@ -447,7 +447,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
||||
contextActionImpl?(messageId, node, gesture)
|
||||
})
|
||||
|
||||
let messageView = context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .upperBound, anchorIndex: .upperBound, count: 100, fixedCombinedReadStates: nil)
|
||||
let messageView = context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 100, fixedCombinedReadStates: nil)
|
||||
|> map { messageHistoryView, _, _ -> MessageHistoryView? in
|
||||
return messageHistoryView
|
||||
}
|
||||
|
||||
@ -222,7 +222,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-207944868] = { return Api.FileHash.parse_fileHash($0) }
|
||||
dict[-11252123] = { return Api.Folder.parse_folder($0) }
|
||||
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
||||
dict[413771876] = { return Api.ForumTopic.parse_forumTopic($0) }
|
||||
dict[1495324380] = { return Api.ForumTopic.parse_forumTopic($0) }
|
||||
dict[-1107729093] = { return Api.Game.parse_game($0) }
|
||||
dict[-1297942941] = { return Api.GeoPoint.parse_geoPoint($0) }
|
||||
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) }
|
||||
@ -315,6 +315,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) }
|
||||
dict[-1311015810] = { return Api.InputNotifyPeer.parse_inputNotifyBroadcasts($0) }
|
||||
dict[1251338318] = { return Api.InputNotifyPeer.parse_inputNotifyChats($0) }
|
||||
dict[1548122514] = { return Api.InputNotifyPeer.parse_inputNotifyForumTopic($0) }
|
||||
dict[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) }
|
||||
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
|
||||
dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) }
|
||||
|
||||
@ -4985,16 +4985,18 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func getSearchCounters(peer: Api.InputPeer, filters: [Api.MessagesFilter]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.messages.SearchCounter]>) {
|
||||
static func getSearchCounters(flags: Int32, peer: Api.InputPeer, topMsgId: Int32?, filters: [Api.MessagesFilter]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.messages.SearchCounter]>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1932455680)
|
||||
buffer.appendInt32(11435201)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(topMsgId!, buffer: buffer, boxed: false)}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(filters.count))
|
||||
for item in filters {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
return (FunctionDescription(name: "messages.getSearchCounters", parameters: [("peer", String(describing: peer)), ("filters", String(describing: filters))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.messages.SearchCounter]? in
|
||||
return (FunctionDescription(name: "messages.getSearchCounters", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("topMsgId", String(describing: topMsgId)), ("filters", String(describing: filters))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.messages.SearchCounter]? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: [Api.messages.SearchCounter]?
|
||||
if let _ = reader.readInt32() {
|
||||
@ -5470,11 +5472,13 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func readReactions(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AffectedHistory>) {
|
||||
static func readReactions(flags: Int32, peer: Api.InputPeer, topMsgId: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AffectedHistory>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-2099097129)
|
||||
buffer.appendInt32(1420459918)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "messages.readReactions", parameters: [("peer", String(describing: peer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedHistory? in
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(topMsgId!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "messages.readReactions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("topMsgId", String(describing: topMsgId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedHistory? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.messages.AffectedHistory?
|
||||
if let signature = reader.readInt32() {
|
||||
|
||||
@ -1094,13 +1094,13 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
enum ForumTopic: TypeConstructorDescription {
|
||||
case forumTopic(flags: Int32, id: Int32, date: Int32, title: String, iconColor: Int32, iconEmojiId: Int64?, topMessage: Int32, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, unreadMentionsCount: Int32, unreadReactionsCount: Int32, fromId: Api.Peer)
|
||||
case forumTopic(flags: Int32, id: Int32, date: Int32, title: String, iconColor: Int32, iconEmojiId: Int64?, topMessage: Int32, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, unreadMentionsCount: Int32, unreadReactionsCount: Int32, fromId: Api.Peer, notifySettings: Api.PeerNotifySettings)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .forumTopic(let flags, let id, let date, let title, let iconColor, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let unreadReactionsCount, let fromId):
|
||||
case .forumTopic(let flags, let id, let date, let title, let iconColor, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let unreadReactionsCount, let fromId, let notifySettings):
|
||||
if boxed {
|
||||
buffer.appendInt32(413771876)
|
||||
buffer.appendInt32(1495324380)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(id, buffer: buffer, boxed: false)
|
||||
@ -1115,14 +1115,15 @@ public extension Api {
|
||||
serializeInt32(unreadMentionsCount, buffer: buffer, boxed: false)
|
||||
serializeInt32(unreadReactionsCount, buffer: buffer, boxed: false)
|
||||
fromId.serialize(buffer, true)
|
||||
notifySettings.serialize(buffer, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .forumTopic(let flags, let id, let date, let title, let iconColor, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let unreadReactionsCount, let fromId):
|
||||
return ("forumTopic", [("flags", String(describing: flags)), ("id", String(describing: id)), ("date", String(describing: date)), ("title", String(describing: title)), ("iconColor", String(describing: iconColor)), ("iconEmojiId", String(describing: iconEmojiId)), ("topMessage", String(describing: topMessage)), ("readInboxMaxId", String(describing: readInboxMaxId)), ("readOutboxMaxId", String(describing: readOutboxMaxId)), ("unreadCount", String(describing: unreadCount)), ("unreadMentionsCount", String(describing: unreadMentionsCount)), ("unreadReactionsCount", String(describing: unreadReactionsCount)), ("fromId", String(describing: fromId))])
|
||||
case .forumTopic(let flags, let id, let date, let title, let iconColor, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let unreadReactionsCount, let fromId, let notifySettings):
|
||||
return ("forumTopic", [("flags", String(describing: flags)), ("id", String(describing: id)), ("date", String(describing: date)), ("title", String(describing: title)), ("iconColor", String(describing: iconColor)), ("iconEmojiId", String(describing: iconEmojiId)), ("topMessage", String(describing: topMessage)), ("readInboxMaxId", String(describing: readInboxMaxId)), ("readOutboxMaxId", String(describing: readOutboxMaxId)), ("unreadCount", String(describing: unreadCount)), ("unreadMentionsCount", String(describing: unreadMentionsCount)), ("unreadReactionsCount", String(describing: unreadReactionsCount)), ("fromId", String(describing: fromId)), ("notifySettings", String(describing: notifySettings))])
|
||||
}
|
||||
}
|
||||
|
||||
@ -1155,6 +1156,10 @@ public extension Api {
|
||||
if let signature = reader.readInt32() {
|
||||
_13 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||
}
|
||||
var _14: Api.PeerNotifySettings?
|
||||
if let signature = reader.readInt32() {
|
||||
_14 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -1168,8 +1173,9 @@ public extension Api {
|
||||
let _c11 = _11 != nil
|
||||
let _c12 = _12 != nil
|
||||
let _c13 = _13 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 {
|
||||
return Api.ForumTopic.forumTopic(flags: _1!, id: _2!, date: _3!, title: _4!, iconColor: _5!, iconEmojiId: _6, topMessage: _7!, readInboxMaxId: _8!, readOutboxMaxId: _9!, unreadCount: _10!, unreadMentionsCount: _11!, unreadReactionsCount: _12!, fromId: _13!)
|
||||
let _c14 = _14 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 {
|
||||
return Api.ForumTopic.forumTopic(flags: _1!, id: _2!, date: _3!, title: _4!, iconColor: _5!, iconEmojiId: _6, topMessage: _7!, readInboxMaxId: _8!, readOutboxMaxId: _9!, unreadCount: _10!, unreadMentionsCount: _11!, unreadReactionsCount: _12!, fromId: _13!, notifySettings: _14!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
||||
@ -860,6 +860,7 @@ public extension Api {
|
||||
indirect enum InputNotifyPeer: TypeConstructorDescription {
|
||||
case inputNotifyBroadcasts
|
||||
case inputNotifyChats
|
||||
case inputNotifyForumTopic(peer: Api.InputPeer, topMsgId: Int32)
|
||||
case inputNotifyPeer(peer: Api.InputPeer)
|
||||
case inputNotifyUsers
|
||||
|
||||
@ -876,6 +877,13 @@ public extension Api {
|
||||
buffer.appendInt32(1251338318)
|
||||
}
|
||||
|
||||
break
|
||||
case .inputNotifyForumTopic(let peer, let topMsgId):
|
||||
if boxed {
|
||||
buffer.appendInt32(1548122514)
|
||||
}
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(topMsgId, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .inputNotifyPeer(let peer):
|
||||
if boxed {
|
||||
@ -898,6 +906,8 @@ public extension Api {
|
||||
return ("inputNotifyBroadcasts", [])
|
||||
case .inputNotifyChats:
|
||||
return ("inputNotifyChats", [])
|
||||
case .inputNotifyForumTopic(let peer, let topMsgId):
|
||||
return ("inputNotifyForumTopic", [("peer", String(describing: peer)), ("topMsgId", String(describing: topMsgId))])
|
||||
case .inputNotifyPeer(let peer):
|
||||
return ("inputNotifyPeer", [("peer", String(describing: peer))])
|
||||
case .inputNotifyUsers:
|
||||
@ -911,6 +921,22 @@ public extension Api {
|
||||
public static func parse_inputNotifyChats(_ reader: BufferReader) -> InputNotifyPeer? {
|
||||
return Api.InputNotifyPeer.inputNotifyChats
|
||||
}
|
||||
public static func parse_inputNotifyForumTopic(_ reader: BufferReader) -> InputNotifyPeer? {
|
||||
var _1: Api.InputPeer?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
|
||||
}
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.InputNotifyPeer.inputNotifyForumTopic(peer: _1!, topMsgId: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_inputNotifyPeer(_ reader: BufferReader) -> InputNotifyPeer? {
|
||||
var _1: Api.InputPeer?
|
||||
if let signature = reader.readInt32() {
|
||||
|
||||
@ -117,7 +117,7 @@ enum AccountStateMutationOperation {
|
||||
case UpdateAudioTranscription(messageId: MessageId, id: Int64, isPending: Bool, text: String)
|
||||
case UpdateConfig
|
||||
case UpdateExtendedMedia(MessageId, Api.MessageExtendedMedia)
|
||||
case ResetForumTopic(topicId: MessageId, data: MessageHistoryThreadData, pts: Int32)
|
||||
case ResetForumTopic(topicId: MessageId, data: StoreMessageHistoryThreadData, pts: Int32)
|
||||
}
|
||||
|
||||
struct HoleFromPreviousState {
|
||||
|
||||
@ -62,8 +62,14 @@ public struct MessageHistoryThreadData: Codable, Equatable {
|
||||
public var maxIncomingReadId: Int32
|
||||
public var maxKnownMessageId: Int32
|
||||
public var maxOutgoingReadId: Int32
|
||||
public var unreadMentionCount: Int32
|
||||
public var unreadReactionCount: Int32
|
||||
public var notificationSettings: TelegramPeerNotificationSettings
|
||||
}
|
||||
|
||||
struct StoreMessageHistoryThreadData {
|
||||
var data: MessageHistoryThreadData
|
||||
var topMessageId: Int32
|
||||
var unreadMentionCount: Int32
|
||||
var unreadReactionCount: Int32
|
||||
}
|
||||
|
||||
public enum CreateForumChannelTopicError {
|
||||
@ -247,7 +253,7 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
|
||||
|
||||
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
|
||||
|
||||
let _ = transaction.addMessages(messages.compactMap { message -> StoreMessage? in
|
||||
let _ = InternalAccountState.addMessages(transaction: transaction, messages: messages.compactMap { message -> StoreMessage? in
|
||||
return StoreMessage(apiMessage: message)
|
||||
}, location: .Random)
|
||||
|
||||
@ -261,7 +267,7 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
|
||||
|
||||
for topic in topics {
|
||||
switch topic {
|
||||
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId):
|
||||
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings):
|
||||
let data = MessageHistoryThreadData(
|
||||
creationDate: date,
|
||||
author: fromId.peerId,
|
||||
@ -274,13 +280,15 @@ func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Si
|
||||
maxIncomingReadId: readInboxMaxId,
|
||||
maxKnownMessageId: topMessage,
|
||||
maxOutgoingReadId: readOutboxMaxId,
|
||||
unreadMentionCount: unreadMentionsCount,
|
||||
unreadReactionCount: unreadReactionsCount
|
||||
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
||||
)
|
||||
guard let info = CodableEntry(data) else {
|
||||
continue
|
||||
}
|
||||
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: info)
|
||||
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: Int64(id), tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: Int64(id), tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -316,25 +324,6 @@ public final class ForumChannelTopics {
|
||||
|
||||
let _ = _internal_loadMessageHistoryThreads(account: self.account, peerId: peerId).start()
|
||||
|
||||
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(id: self.peerId)
|
||||
self.statePromise.set(self.account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> State in
|
||||
guard let view = views.views[viewKey] as? MessageHistoryThreadIndexView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
return State(items: view.items.compactMap { item -> ForumChannelTopics.Item? in
|
||||
guard let data = item.info.get(MessageHistoryThreadData.self) else {
|
||||
return nil
|
||||
}
|
||||
return ForumChannelTopics.Item(
|
||||
id: item.id,
|
||||
info: data.info,
|
||||
index: item.index,
|
||||
topMessage: item.topMessage.flatMap(EngineMessage.init)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
self.updateDisposable.set(account.viewTracker.polledChannel(peerId: peerId).start())
|
||||
}
|
||||
|
||||
|
||||
@ -65,5 +65,5 @@ public func unarchiveAutomaticallyArchivedPeer(account: Account, peerId: PeerId)
|
||||
}
|
||||
|> deliverOnMainQueue).start()
|
||||
|
||||
let _ = _internal_updatePeerMuteSetting(account: account, peerId: peerId, muteInterval: nil).start()
|
||||
let _ = _internal_updatePeerMuteSetting(account: account, peerId: peerId, threadId: nil, muteInterval: nil).start()
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ private func activeChannelsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set<Peer
|
||||
switch chat {
|
||||
case .channel:
|
||||
if let channel = parseTelegramGroupOrChannel(chat: chat) as? TelegramChannel {
|
||||
if channel.participationStatus == .member {
|
||||
if channel.participationStatus == .member, case .personal = channel.accessHash {
|
||||
peerIds.insert(channel.id)
|
||||
}
|
||||
}
|
||||
@ -469,13 +469,13 @@ private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set<Pe
|
||||
hasValidInclusion = false
|
||||
}
|
||||
if hasValidInclusion {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) {
|
||||
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
||||
}
|
||||
} else {
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
if let channel = peer as? TelegramChannel, channel.participationStatus != .member {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) {
|
||||
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
||||
Logger.shared.log("State", "Peer \(peerId) (\(peer.debugDisplayTitle) has no stored inclusion, using synthesized one")
|
||||
}
|
||||
@ -1694,9 +1694,10 @@ func resolveForumThreads(postbox: Postbox, network: Network, state: AccountMutab
|
||||
|
||||
for topic in topics {
|
||||
switch topic {
|
||||
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId):
|
||||
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings):
|
||||
state.operations.append(.ResetForumTopic(
|
||||
topicId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id),
|
||||
data: StoreMessageHistoryThreadData(
|
||||
data: MessageHistoryThreadData(
|
||||
creationDate: date,
|
||||
author: fromId.peerId,
|
||||
@ -1709,6 +1710,9 @@ func resolveForumThreads(postbox: Postbox, network: Network, state: AccountMutab
|
||||
maxIncomingReadId: readInboxMaxId,
|
||||
maxKnownMessageId: topMessage,
|
||||
maxOutgoingReadId: readOutboxMaxId,
|
||||
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
||||
),
|
||||
topMessageId: topMessage,
|
||||
unreadMentionCount: unreadMentionsCount,
|
||||
unreadReactionCount: unreadReactionsCount
|
||||
),
|
||||
@ -1786,7 +1790,7 @@ func resolveForumThreads(postbox: Postbox, network: Network, ids: [MessageId]) -
|
||||
|
||||
for topic in topics {
|
||||
switch topic {
|
||||
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId):
|
||||
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings):
|
||||
let data = MessageHistoryThreadData(
|
||||
creationDate: date,
|
||||
author: fromId.peerId,
|
||||
@ -1799,12 +1803,14 @@ func resolveForumThreads(postbox: Postbox, network: Network, ids: [MessageId]) -
|
||||
maxIncomingReadId: readInboxMaxId,
|
||||
maxKnownMessageId: topMessage,
|
||||
maxOutgoingReadId: readOutboxMaxId,
|
||||
unreadMentionCount: unreadMentionsCount,
|
||||
unreadReactionCount: unreadReactionsCount
|
||||
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
||||
)
|
||||
if let entry = CodableEntry(data) {
|
||||
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: entry)
|
||||
}
|
||||
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: Int64(id), tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: Int64(id), tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1900,8 +1906,9 @@ func resolveForumThreads(postbox: Postbox, network: Network, fetchedChatList: Fe
|
||||
|
||||
for topic in topics {
|
||||
switch topic {
|
||||
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId):
|
||||
fetchedChatList.threadInfos[MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)] = MessageHistoryThreadData(
|
||||
case let .forumTopic(_, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings):
|
||||
fetchedChatList.threadInfos[MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)] = StoreMessageHistoryThreadData(
|
||||
data: MessageHistoryThreadData(
|
||||
creationDate: date,
|
||||
author: fromId.peerId,
|
||||
info: EngineMessageHistoryThread.Info(
|
||||
@ -1913,6 +1920,9 @@ func resolveForumThreads(postbox: Postbox, network: Network, fetchedChatList: Fe
|
||||
maxIncomingReadId: readInboxMaxId,
|
||||
maxKnownMessageId: topMessage,
|
||||
maxOutgoingReadId: readOutboxMaxId,
|
||||
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
||||
),
|
||||
topMessageId: topMessage,
|
||||
unreadMentionCount: unreadMentionsCount,
|
||||
unreadReactionCount: unreadReactionsCount
|
||||
)
|
||||
@ -2209,7 +2219,7 @@ func pollChannelOnce(postbox: Postbox, network: Network, peerId: PeerId, stateMa
|
||||
hasValidInclusion = false
|
||||
}
|
||||
if hasValidInclusion {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) as? TelegramPeerNotificationSettings {
|
||||
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
||||
}
|
||||
}
|
||||
@ -2263,7 +2273,7 @@ public func standalonePollChannelOnce(postbox: Postbox, network: Network, peerId
|
||||
hasValidInclusion = false
|
||||
}
|
||||
if hasValidInclusion {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) as? TelegramPeerNotificationSettings {
|
||||
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
|
||||
}
|
||||
}
|
||||
@ -3099,7 +3109,7 @@ func replayFinalState(
|
||||
case .groupCreated, .channelMigratedFromGroup:
|
||||
let holesAtHistoryStart = transaction.getHole(containing: MessageId(peerId: chatPeerId, namespace: Namespaces.Message.Cloud, id: id.id - 1))
|
||||
for (space, _) in holesAtHistoryStart {
|
||||
transaction.removeHole(peerId: chatPeerId, namespace: Namespaces.Message.Cloud, space: space, range: 1 ... id.id)
|
||||
transaction.removeHole(peerId: chatPeerId, threadId: nil, namespace: Namespaces.Message.Cloud, space: space, range: 1 ... id.id)
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -3422,11 +3432,11 @@ func replayFinalState(
|
||||
case let .UpdatePeerChatUnreadMark(peerId, namespace, value):
|
||||
transaction.applyMarkUnread(peerId: peerId, namespace: namespace, value: value, interactive: false)
|
||||
case let .ResetMessageTagSummary(peerId, tag, namespace, count, range):
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: tag, namespace: namespace, count: count, maxId: range.maxId)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: tag, namespace: namespace, count: count, maxId: range.maxId)
|
||||
if count == 0 {
|
||||
transaction.removeHole(peerId: peerId, namespace: namespace, space: .tag(tag), range: 1 ... (Int32.max - 1))
|
||||
transaction.removeHole(peerId: peerId, threadId: nil, namespace: namespace, space: .tag(tag), range: 1 ... (Int32.max - 1))
|
||||
if tag == .unseenPersonalMessage {
|
||||
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, namespace: namespace, tag: tag).map({ $0.id })
|
||||
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, threadId: nil, namespace: namespace, tag: tag).map({ $0.id })
|
||||
Logger.shared.log("State", "will call markUnseenPersonalMessage for \(ids.count) messages")
|
||||
for id in ids {
|
||||
markUnseenPersonalMessage(transaction: transaction, id: id, addSynchronizeAction: false)
|
||||
@ -3942,11 +3952,13 @@ func replayFinalState(
|
||||
case let .ResetForumTopic(topicId, data, pts):
|
||||
if finalState.state.resetForumTopicLists[topicId.peerId] == nil {
|
||||
let _ = pts
|
||||
if let entry = CodableEntry(data) {
|
||||
if let entry = CodableEntry(data.data) {
|
||||
transaction.setMessageHistoryThreadInfo(peerId: topicId.peerId, threadId: Int64(topicId.id), info: entry)
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
transaction.replaceMessageTagSummary(peerId: topicId.peerId, threadId: Int64(topicId.id), tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: data.unreadMentionCount, maxId: data.topMessageId)
|
||||
transaction.replaceMessageTagSummary(peerId: topicId.peerId, threadId: Int64(topicId.id), tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: data.unreadReactionCount, maxId: data.topMessageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3959,9 +3971,9 @@ func replayFinalState(
|
||||
upperId = Int32.max
|
||||
}
|
||||
if upperId >= messageId.id {
|
||||
transaction.addHole(peerId: messageId.peerId, namespace: messageId.namespace, space: .everywhere, range: messageId.id ... upperId)
|
||||
transaction.addHole(peerId: messageId.peerId, threadId: nil, namespace: messageId.namespace, space: .everywhere, range: messageId.id ... upperId)
|
||||
|
||||
transaction.addHole(peerId: messageId.peerId, namespace: messageId.namespace, space: .tag(.pinned), range: 1 ... upperId)
|
||||
transaction.addHole(peerId: messageId.peerId, threadId: nil, namespace: messageId.namespace, space: .tag(.pinned), range: 1 ... upperId)
|
||||
|
||||
Logger.shared.log("State", "adding hole for peer \(messageId.peerId), \(messageId.id) ... \(upperId)")
|
||||
} else {
|
||||
@ -4269,7 +4281,7 @@ func replayFinalState(
|
||||
let currentInclusion = transaction.getPeerChatListInclusion(peerId)
|
||||
if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive {
|
||||
if let peer = transaction.getPeer(peerId) as? TelegramSecretChat {
|
||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: transaction.getGlobalNotificationSettings(), peer: peer, peerSettings: transaction.getPeerNotificationSettings(peer.regularPeerId))
|
||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: transaction.getGlobalNotificationSettings(), peer: peer, peerSettings: transaction.getPeerNotificationSettings(id: peer.regularPeerId))
|
||||
|
||||
if !isRemovedFromTotalUnreadCount {
|
||||
transaction.updatePeerChatListInclusion(peerId, inclusion: currentInclusion.withGroupId(groupId: .root))
|
||||
|
||||
@ -1358,7 +1358,7 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
|
||||
notificationPeerId = author.id
|
||||
}
|
||||
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings {
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings {
|
||||
var defaultSound: PeerMessageSound = defaultCloudPeerNotificationSound
|
||||
var defaultNotify: Bool = true
|
||||
if let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) {
|
||||
|
||||
@ -181,7 +181,7 @@ private func fetchPoll(account: Account, messageId: MessageId) -> Signal<Void, N
|
||||
private func wrappedHistoryViewAdditionalData(chatLocation: ChatLocationInput, additionalData: [AdditionalMessageHistoryViewData]) -> [AdditionalMessageHistoryViewData] {
|
||||
var result = additionalData
|
||||
switch chatLocation {
|
||||
case let .peer(peerId):
|
||||
case let .peer(peerId, _):
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
if result.firstIndex(where: { if case .peerChatState = $0 { return true } else { return false } }) == nil {
|
||||
result.append(.peerChatState(peerId))
|
||||
@ -1220,13 +1220,13 @@ public final class AccountViewTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public func updateMarkAllMentionsSeen(peerId: PeerId) {
|
||||
public func updateMarkAllMentionsSeen(peerId: PeerId, threadId: Int64?) {
|
||||
self.queue.async {
|
||||
guard let account = self.account else {
|
||||
return
|
||||
}
|
||||
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
|
||||
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id }))
|
||||
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id }))
|
||||
|
||||
for id in ids {
|
||||
transaction.updateMessage(id, update: { currentMessage in
|
||||
@ -1244,13 +1244,13 @@ public final class AccountViewTracker {
|
||||
})
|
||||
}
|
||||
|
||||
if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), summary.count > 0 {
|
||||
if let summary = transaction.getMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), summary.count > 0 {
|
||||
var maxId: Int32 = summary.range.maxId
|
||||
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||
maxId = index.id.id
|
||||
}
|
||||
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId)
|
||||
addSynchronizeMarkAllUnseenPersonalMessagesOperation(transaction: transaction, peerId: peerId, maxId: summary.range.maxId)
|
||||
}
|
||||
|
||||
@ -1303,13 +1303,13 @@ public final class AccountViewTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public func updateMarkAllReactionsSeen(peerId: PeerId) {
|
||||
public func updateMarkAllReactionsSeen(peerId: PeerId, threadId: Int64?) {
|
||||
self.queue.async {
|
||||
guard let account = self.account else {
|
||||
return
|
||||
}
|
||||
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
|
||||
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id }))
|
||||
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id }))
|
||||
|
||||
for id in ids {
|
||||
transaction.updateMessage(id, update: { currentMessage in
|
||||
@ -1327,13 +1327,13 @@ public final class AccountViewTracker {
|
||||
})
|
||||
}
|
||||
|
||||
if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud) {
|
||||
if let summary = transaction.getMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud) {
|
||||
var maxId: Int32 = summary.range.maxId
|
||||
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||
maxId = index.id.id
|
||||
}
|
||||
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId)
|
||||
addSynchronizeMarkAllUnseenReactionsOperation(transaction: transaction, peerId: peerId, maxId: summary.range.maxId)
|
||||
}
|
||||
|
||||
@ -1513,6 +1513,35 @@ public final class AccountViewTracker {
|
||||
}
|
||||
|
||||
func wrappedMessageHistorySignal(chatLocation: ChatLocationInput, signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>, addHoleIfNeeded: Bool) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
var signal = signal
|
||||
if let postbox = self.account?.postbox, let peerId = chatLocation.peerId, let threadId = chatLocation.threadId {
|
||||
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
|
||||
let fixedReadStates = Atomic<MessageHistoryViewReadState?>(value: nil)
|
||||
signal = combineLatest(signal, postbox.combinedView(keys: [viewKey]))
|
||||
|> map { view, additionalViews -> (MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?) in
|
||||
var view = view
|
||||
if let threadInfo = additionalViews.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.get(MessageHistoryThreadData.self) {
|
||||
let readState = CombinedPeerReadState(states: [(Namespaces.Message.Cloud, .idBased(maxIncomingReadId: data.maxIncomingReadId, maxOutgoingReadId: data.maxOutgoingReadId, maxKnownId: data.maxKnownMessageId, count: data.incomingUnreadCount, markedUnread: false))])
|
||||
|
||||
let fixed = fixedReadStates.modify { current in
|
||||
if let current = current {
|
||||
return current
|
||||
} else {
|
||||
return view.0.fixedReadStates ?? .peer([peerId: readState])
|
||||
}
|
||||
}
|
||||
|
||||
view.0 = MessageHistoryView(
|
||||
base: view.0,
|
||||
fixed: fixed,
|
||||
transient: .peer([peerId: readState])
|
||||
)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
||||
|
||||
let history = withState(signal, { [weak self] () -> Int32 in
|
||||
if let strongSelf = self {
|
||||
return OSAtomicIncrement32(&strongSelf.nextViewId)
|
||||
@ -1526,7 +1555,7 @@ public final class AccountViewTracker {
|
||||
strongSelf.updatePendingWebpages(viewId: viewId, messageIds: messageIds, localWebpages: localWebpages)
|
||||
let (pollMessageIds, pollMessageDict) = pollMessages(entries: next.0.entries)
|
||||
strongSelf.updatePolls(viewId: viewId, messageIds: pollMessageIds, messages: pollMessageDict)
|
||||
if case let .peer(peerId) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
if case let .peer(peerId, _) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0)
|
||||
} else if case let .thread(peerId, _, _) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0, location: chatLocation)
|
||||
@ -1539,7 +1568,7 @@ public final class AccountViewTracker {
|
||||
strongSelf.updatePendingWebpages(viewId: viewId, messageIds: [], localWebpages: [:])
|
||||
strongSelf.updatePolls(viewId: viewId, messageIds: [], messages: [:])
|
||||
switch chatLocation {
|
||||
case let .peer(peerId):
|
||||
case let .peer(peerId, _):
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: nil)
|
||||
}
|
||||
@ -1556,7 +1585,7 @@ public final class AccountViewTracker {
|
||||
|
||||
let peerId: PeerId?
|
||||
switch chatLocation {
|
||||
case let .peer(peerIdValue):
|
||||
case let .peer(peerIdValue, _):
|
||||
peerId = peerIdValue
|
||||
case let .thread(peerIdValue, _, _):
|
||||
peerId = peerIdValue
|
||||
@ -1583,7 +1612,7 @@ public final class AccountViewTracker {
|
||||
let isAutomaticallyTracked = self.account!.postbox.transaction { transaction -> Bool in
|
||||
if transaction.getPeerChatListIndex(peerId) == nil {
|
||||
if addHole {
|
||||
transaction.addHole(peerId: peerId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: 1 ... (Int32.max - 1))
|
||||
transaction.addHole(peerId: peerId, threadId: nil, namespace: Namespaces.Message.Cloud, space: .everywhere, range: 1 ... (Int32.max - 1))
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
@ -1670,7 +1699,40 @@ public final class AccountViewTracker {
|
||||
|
||||
public func aroundMessageOfInterestHistoryViewForLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>? = nil, count: Int, tagMask: MessageTags? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
if let account = self.account {
|
||||
let signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
let signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>
|
||||
if let peerId = chatLocation.peerId, let threadId = chatLocation.threadId, tagMask == nil {
|
||||
return account.postbox.transaction { transaction -> MessageHistoryThreadData? in
|
||||
return transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self)
|
||||
}
|
||||
|> mapToSignal { threadInfo -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in
|
||||
if let threadInfo = threadInfo {
|
||||
let anchor: HistoryViewInputAnchor
|
||||
if threadInfo.incomingUnreadCount > 0 && tagMask == nil {
|
||||
let customUnreadMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: threadInfo.maxIncomingReadId)
|
||||
anchor = .message(customUnreadMessageId)
|
||||
} else {
|
||||
anchor = .upperBound
|
||||
}
|
||||
|
||||
return account.postbox.aroundMessageHistoryViewForLocation(
|
||||
chatLocation,
|
||||
anchor: anchor,
|
||||
ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange,
|
||||
count: count,
|
||||
fixedCombinedReadStates: nil,
|
||||
topTaggedMessageIdNamespaces: [],
|
||||
tagMask: tagMask,
|
||||
appendMessagesFromTheSameGroup: false,
|
||||
namespaces: .not(Namespaces.Message.allScheduled),
|
||||
orderStatistics: orderStatistics
|
||||
)
|
||||
}
|
||||
|
||||
return account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, customUnreadMessageId: nil, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
}
|
||||
} else {
|
||||
signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, customUnreadMessageId: nil, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
|
||||
}
|
||||
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal, addHoleIfNeeded: true)
|
||||
} else {
|
||||
return .never()
|
||||
@ -1961,13 +2023,13 @@ public final class AccountViewTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public func unseenPersonalMessagesAndReactionCount(peerId: PeerId) -> Signal<(mentionCount: Int32, reactionCount: Int32), NoError> {
|
||||
public func unseenPersonalMessagesAndReactionCount(peerId: PeerId, threadId: Int64?) -> Signal<(mentionCount: Int32, reactionCount: Int32), NoError> {
|
||||
if let account = self.account {
|
||||
let pendingMentionsKey: PostboxViewKey = .pendingMessageActionsSummary(type: .consumeUnseenPersonalMessage, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||
let summaryMentionsKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenPersonalMessage, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||
let summaryMentionsKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenPersonalMessage, peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud)
|
||||
|
||||
let pendingReactionsKey: PostboxViewKey = .pendingMessageActionsSummary(type: .readReaction, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||
let summaryReactionsKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenReaction, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||
let summaryReactionsKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenReaction, peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud)
|
||||
|
||||
return account.postbox.combinedView(keys: [pendingMentionsKey, summaryMentionsKey, pendingReactionsKey, summaryReactionsKey])
|
||||
|> map { views -> (mentionCount: Int32, reactionCount: Int32) in
|
||||
|
||||
@ -5,12 +5,14 @@ import SwiftSignalKit
|
||||
|
||||
public struct HistoryPreloadIndex: Hashable, Comparable, CustomStringConvertible {
|
||||
public let index: ChatListIndex?
|
||||
public let threadId: Int64?
|
||||
public let hasUnread: Bool
|
||||
public let isMuted: Bool
|
||||
public let isPriority: Bool
|
||||
|
||||
public init(index: ChatListIndex?, hasUnread: Bool, isMuted: Bool, isPriority: Bool) {
|
||||
public init(index: ChatListIndex?, threadId: Int64?, hasUnread: Bool, isMuted: Bool, isPriority: Bool) {
|
||||
self.index = index
|
||||
self.threadId = threadId
|
||||
self.hasUnread = hasUnread
|
||||
self.isMuted = isMuted
|
||||
self.isPriority = isPriority
|
||||
@ -38,6 +40,15 @@ public struct HistoryPreloadIndex: Hashable, Comparable, CustomStringConvertible
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if lhs.index == rhs.index {
|
||||
if let lhsThreadId = lhs.threadId, let rhsThreadId = rhs.threadId {
|
||||
if lhsThreadId != rhsThreadId {
|
||||
return lhsThreadId < rhsThreadId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let lhsIndex = lhs.index, let rhsIndex = rhs.index {
|
||||
return lhsIndex > rhsIndex
|
||||
} else if lhs.index != nil {
|
||||
@ -117,6 +128,7 @@ private final class HistoryPreloadEntry: Comparable {
|
||||
|
||||
private final class HistoryPreloadViewContext {
|
||||
var index: ChatListIndex?
|
||||
var threadId: Int64?
|
||||
var hasUnread: Bool?
|
||||
var isMuted: Bool?
|
||||
var isPriority: Bool
|
||||
@ -125,7 +137,7 @@ private final class HistoryPreloadViewContext {
|
||||
var media: [HolesViewMedia] = []
|
||||
|
||||
var preloadIndex: HistoryPreloadIndex {
|
||||
return HistoryPreloadIndex(index: self.index, hasUnread: self.hasUnread ?? false, isMuted: self.isMuted ?? true, isPriority: self.isPriority)
|
||||
return HistoryPreloadIndex(index: self.index, threadId: self.threadId, hasUnread: self.hasUnread ?? false, isMuted: self.isMuted ?? true, isPriority: self.isPriority)
|
||||
}
|
||||
|
||||
var currentHole: HistoryPreloadHole? {
|
||||
@ -136,8 +148,9 @@ private final class HistoryPreloadViewContext {
|
||||
}
|
||||
}
|
||||
|
||||
init(index: ChatListIndex?, hasUnread: Bool?, isMuted: Bool?, isPriority: Bool) {
|
||||
init(index: ChatListIndex?, threadId: Int64?, hasUnread: Bool?, isMuted: Bool?, isPriority: Bool) {
|
||||
self.index = index
|
||||
self.threadId = threadId
|
||||
self.hasUnread = hasUnread
|
||||
self.isMuted = isMuted
|
||||
self.isPriority = isPriority
|
||||
@ -149,7 +162,7 @@ private final class HistoryPreloadViewContext {
|
||||
}
|
||||
|
||||
private enum ChatHistoryPreloadEntity: Hashable {
|
||||
case peer(PeerId)
|
||||
case peer(peerId: PeerId, threadId: Int64?)
|
||||
}
|
||||
|
||||
private struct ChatHistoryPreloadIndex {
|
||||
@ -236,11 +249,13 @@ private final class AdditionalPreloadPeerIdsContext {
|
||||
|
||||
public struct ChatHistoryPreloadItem : Equatable {
|
||||
public let index: ChatListIndex
|
||||
public let threadId: Int64?
|
||||
public let isMuted: Bool
|
||||
public let hasUnread: Bool
|
||||
|
||||
public init(index: ChatListIndex, isMuted: Bool, hasUnread: Bool) {
|
||||
public init(index: ChatListIndex, threadId: Int64?, isMuted: Bool, hasUnread: Bool) {
|
||||
self.index = index
|
||||
self.threadId = threadId
|
||||
self.isMuted = isMuted
|
||||
self.hasUnread = hasUnread
|
||||
}
|
||||
@ -365,7 +380,7 @@ final class ChatHistoryPreloadManager {
|
||||
|
||||
var indices: [(ChatHistoryPreloadIndex, Bool, Bool)] = []
|
||||
for item in loadItems {
|
||||
indices.append((ChatHistoryPreloadIndex(index: item.index, entity: .peer(item.index.messageIndex.id.peerId)), item.hasUnread, item.isMuted))
|
||||
indices.append((ChatHistoryPreloadIndex(index: item.index, entity: .peer(peerId: item.index.messageIndex.id.peerId, threadId: item.threadId)), item.hasUnread, item.isMuted))
|
||||
}
|
||||
|
||||
strongSelf.update(indices: indices, additionalPeerIds: additionalPeerIds)
|
||||
@ -376,7 +391,7 @@ final class ChatHistoryPreloadManager {
|
||||
self.queue.async {
|
||||
var validEntityIds = Set(indices.map { $0.0.entity })
|
||||
for peerId in additionalPeerIds {
|
||||
validEntityIds.insert(.peer(peerId))
|
||||
validEntityIds.insert(.peer(peerId: peerId, threadId: nil))
|
||||
}
|
||||
|
||||
var removedEntityIds: [ChatHistoryPreloadEntity] = []
|
||||
@ -400,7 +415,7 @@ final class ChatHistoryPreloadManager {
|
||||
}
|
||||
for peerId in additionalPeerIds {
|
||||
if !existingPeerIds.contains(peerId) {
|
||||
combinedIndices.append((ChatHistoryPreloadIndex(index: ChatListIndex.absoluteLowerBound, entity: .peer(peerId)), false, true, true))
|
||||
combinedIndices.append((ChatHistoryPreloadIndex(index: ChatListIndex.absoluteLowerBound, entity: .peer(peerId: peerId, threadId: nil)), false, true, true))
|
||||
}
|
||||
}
|
||||
|
||||
@ -418,12 +433,17 @@ final class ChatHistoryPreloadManager {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let view = HistoryPreloadViewContext(index: index.index, hasUnread: hasUnread, isMuted: isMuted, isPriority: isPriority)
|
||||
var threadId: Int64?
|
||||
switch index.entity {
|
||||
case let .peer(_, threadIdValue):
|
||||
threadId = threadIdValue
|
||||
}
|
||||
let view = HistoryPreloadViewContext(index: index.index, threadId: threadId, hasUnread: hasUnread, isMuted: isMuted, isPriority: isPriority)
|
||||
self.views[index.entity] = view
|
||||
let key: PostboxViewKey
|
||||
switch index.entity {
|
||||
case let .peer(peerId):
|
||||
key = .messageOfInterestHole(location: .peer(peerId), namespace: Namespaces.Message.Cloud, count: 70)
|
||||
case let .peer(peerId, threadId):
|
||||
key = .messageOfInterestHole(location: .peer(peerId: peerId, threadId: threadId), namespace: Namespaces.Message.Cloud, count: 70)
|
||||
}
|
||||
view.disposable.set((self.postbox.combinedView(keys: [key])
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] next in
|
||||
@ -453,8 +473,8 @@ final class ChatHistoryPreloadManager {
|
||||
let holeIsUpdated = previousHole != updatedHole
|
||||
|
||||
switch index.entity {
|
||||
case let .peer(peerId):
|
||||
Logger.shared.log("HistoryPreload", "view \(peerId) hole \(String(describing: updatedHole)) isUpdated: \(holeIsUpdated)")
|
||||
case let .peer(peerId, threadId):
|
||||
Logger.shared.log("HistoryPreload", "view \(peerId) (threadId: \(String(describing: threadId)) hole \(String(describing: updatedHole)) isUpdated: \(holeIsUpdated)")
|
||||
}
|
||||
|
||||
if previousHole != updatedHole {
|
||||
|
||||
@ -203,7 +203,7 @@ struct FetchedChatList {
|
||||
var pinnedItemIds: [PeerId]?
|
||||
var folderSummaries: [PeerGroupId: PeerGroupUnreadCountersSummary]
|
||||
var peerGroupIds: [PeerId: PeerGroupId]
|
||||
var threadInfos: [MessageId: MessageHistoryThreadData]
|
||||
var threadInfos: [MessageId: StoreMessageHistoryThreadData]
|
||||
}
|
||||
|
||||
func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLocation, upperBound: MessageIndex, hash: Int64, limit: Int32) -> Signal<FetchedChatList?, NoError> {
|
||||
|
||||
@ -1,3 +1,16 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
enum InternalAccountState {
|
||||
static func addMessages(transaction: Transaction, messages: [StoreMessage], location: AddMessagesLocation) -> [Int64 : MessageId] {
|
||||
return transaction.addMessages(messages, location: location)
|
||||
}
|
||||
|
||||
static func deleteMessages(transaction: Transaction, ids: [MessageId], forEachMedia: ((Media) -> Void)?) {
|
||||
transaction.deleteMessages(ids, forEachMedia: forEachMedia)
|
||||
}
|
||||
|
||||
static func invalidateChannelState(peerId: PeerId) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ final class HistoryViewStateValidationContexts {
|
||||
}
|
||||
}
|
||||
|
||||
if let location = location, case let .thread(peerId, threadId, _) = location {
|
||||
if let location = location, let peerId = location.peerId, let threadId = location.threadId {
|
||||
var rangesToInvalidate: [[MessageId]] = []
|
||||
let addToRange: (MessageId, inout [[MessageId]]) -> Void = { id, ranges in
|
||||
if ranges.isEmpty {
|
||||
@ -219,7 +219,7 @@ final class HistoryViewStateValidationContexts {
|
||||
context.batchReferences[messageId] = batch
|
||||
}
|
||||
|
||||
disposable.set((validateReplyThreadMessagesBatch(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, peerId: peerId, threadMessageId: makeThreadIdMessageId(peerId: peerId, threadId: threadId).id, messageIds: messages)
|
||||
disposable.set((validateReplyThreadMessagesBatch(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, peerId: peerId, threadMessageId: makeThreadIdMessageId(peerId: peerId, threadId: threadId).id, tag: view.tagMask, messageIds: messages)
|
||||
|> deliverOn(self.queue)).start(completed: { [weak self, weak batch] in
|
||||
if let strongSelf = self, let context = strongSelf.contexts[id], let batch = batch {
|
||||
var completedMessageIds: [MessageId] = []
|
||||
@ -355,7 +355,7 @@ final class HistoryViewStateValidationContexts {
|
||||
}
|
||||
} else if view.namespaces.contains(Namespaces.Message.ScheduledCloud) {
|
||||
if let _ = self.contexts[id] {
|
||||
} else if let location = location, case let .peer(peerId) = location {
|
||||
} else if let location = location, case let .peer(peerId, _) = location {
|
||||
let timestamp = self.network.context.globalTime()
|
||||
if let previousTimestamp = self.previousPeerValidationTimestamps[peerId], timestamp < previousTimestamp + 60 {
|
||||
} else {
|
||||
@ -543,7 +543,7 @@ private func validateChannelMessagesBatch(postbox: Postbox, network: Network, ac
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, threadMessageId: Int32, messageIds: [MessageId]) -> Signal<Void, NoError> {
|
||||
private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, threadMessageId: Int32, tag: MessageTags?, messageIds: [MessageId]) -> Signal<Void, NoError> {
|
||||
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
var previousMessages: [Message] = []
|
||||
var previous: [MessageId: Message] = [:]
|
||||
@ -556,10 +556,22 @@ private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network
|
||||
|
||||
var signal: Signal<ValidatedMessages, MTRpcError>
|
||||
let hash = hashForMessages(previousMessages, withChannelIds: false)
|
||||
Logger.shared.log("HistoryValidation", "validate reply thread batch for \(peerId): \(previousMessages.map({ $0.id }))")
|
||||
Logger.shared.log("HistoryValidation", "validate reply thread batch (tag: \(String(describing: tag?.rawValue)) for \(peerId): \(previousMessages.map({ $0.id }))")
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
let requestSignal: Signal<Api.messages.Messages, MTRpcError>
|
||||
|
||||
if let tag = tag {
|
||||
if let filter = messageFilterForTagMask(tag) {
|
||||
var flags: Int32 = 0
|
||||
flags |= (1 << 1)
|
||||
|
||||
requestSignal = network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: threadMessageId, filter: filter, minDate: 0, maxDate: 0, offsetId: messageIds[messageIds.count - 1].id + 1, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
requestSignal = network.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: threadMessageId, offsetId: messageIds[messageIds.count - 1].id, offsetDate: 0, addOffset: -1, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
|
||||
}
|
||||
|
||||
signal = requestSignal
|
||||
|> map { result -> ValidatedMessages in
|
||||
|
||||
@ -406,7 +406,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
||||
minMaxRange = 1 ... Int32.max - 1
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.getUnreadMentions(flags: 0, peer: inputPeer, topMsgId: nil, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
|
||||
var flags: Int32 = 0
|
||||
var topMsgId: Int32?
|
||||
if let threadId = peerInput.requestThreadId {
|
||||
flags |= (1 << 1)
|
||||
topMsgId = threadId.id
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.getUnreadMentions(flags: flags, peer: inputPeer, topMsgId: topMsgId, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
|
||||
} else if tag == .unseenReaction {
|
||||
let offsetId: Int32
|
||||
let addOffset: Int32
|
||||
@ -454,7 +461,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
||||
minMaxRange = 1 ... Int32.max - 1
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.getUnreadReactions(flags: 0, peer: inputPeer, topMsgId: nil, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
|
||||
var flags: Int32 = 0
|
||||
var topMsgId: Int32?
|
||||
if let threadId = peerInput.requestThreadId {
|
||||
flags |= (1 << 0)
|
||||
topMsgId = threadId.id
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.getUnreadReactions(flags: flags, peer: inputPeer, topMsgId: topMsgId, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
|
||||
} else if tag == .liveLocation {
|
||||
let selectedLimit = count
|
||||
|
||||
@ -511,7 +525,14 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
||||
minMaxRange = 1 ... (Int32.max - 1)
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, topMsgId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
|
||||
var flags: Int32 = 0
|
||||
var topMsgId: Int32?
|
||||
if let threadId = peerInput.requestThreadId {
|
||||
flags |= (1 << 1)
|
||||
topMsgId = threadId.id
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
|
||||
} else {
|
||||
assertionFailure()
|
||||
minMaxRange = 1 ... 1
|
||||
@ -669,13 +690,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
||||
|
||||
switch peerInput {
|
||||
case let .direct(peerId, threadId):
|
||||
if let threadId = threadId {
|
||||
for range in strictFilledIndices.rangeView {
|
||||
transaction.removeThreadIndexHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: Int32(range.lowerBound) ... Int32(range.upperBound))
|
||||
}
|
||||
} else {
|
||||
transaction.removeHole(peerId: peerId, namespace: namespace, space: space, range: filledRange)
|
||||
}
|
||||
transaction.removeHole(peerId: peerId, threadId: threadId, namespace: namespace, space: space, range: filledRange)
|
||||
case .threadFromChannel:
|
||||
break
|
||||
}
|
||||
@ -736,9 +751,11 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId
|
||||
})
|
||||
|
||||
for (threadMessageId, data) in fetchedChats.threadInfos {
|
||||
if let entry = CodableEntry(data) {
|
||||
if let entry = CodableEntry(data.data) {
|
||||
transaction.setMessageHistoryThreadInfo(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id), info: entry)
|
||||
}
|
||||
transaction.replaceMessageTagSummary(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id), tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: data.unreadMentionCount, maxId: data.topMessageId)
|
||||
transaction.replaceMessageTagSummary(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id), tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: data.unreadReactionCount, maxId: data.topMessageId)
|
||||
}
|
||||
|
||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: fetchedChats.peerPresences)
|
||||
@ -778,10 +795,10 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId
|
||||
}
|
||||
|
||||
for (peerId, summary) in fetchedChats.mentionTagSummaries {
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
|
||||
}
|
||||
for (peerId, summary) in fetchedChats.reactionTagSummaries {
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
|
||||
}
|
||||
|
||||
for (groupId, summary) in fetchedChats.folderSummaries {
|
||||
|
||||
@ -377,7 +377,7 @@ private func synchronizeUnseenPersonalMentionsTag(postbox: Postbox, network: Net
|
||||
}
|
||||
|
||||
return postbox.transaction { transaction -> Void in
|
||||
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadMentionsCount, maxId: apiTopMessage)
|
||||
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, threadId: nil, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadMentionsCount, maxId: apiTopMessage)
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
@ -419,7 +419,7 @@ private func synchronizeUnseenReactionsTag(postbox: Postbox, network: Network, e
|
||||
}
|
||||
|
||||
return postbox.transaction { transaction -> Void in
|
||||
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadReactionsCount, maxId: apiTopMessage)
|
||||
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, threadId: nil, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadReactionsCount, maxId: apiTopMessage)
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
|
||||
@ -24,8 +24,7 @@ private final class ManagedMessageHistoryHolesState {
|
||||
|
||||
for entry in entries {
|
||||
switch entry.hole {
|
||||
case let .peer(hole):
|
||||
if hole.threadId == nil {
|
||||
case .peer:
|
||||
if self.holeDisposables[entry] == nil {
|
||||
let disposable = MetaDisposable()
|
||||
self.holeDisposables[entry] = disposable
|
||||
@ -33,7 +32,6 @@ private final class ManagedMessageHistoryHolesState {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (removed, added)
|
||||
}
|
||||
@ -55,7 +53,7 @@ func managedMessageHistoryHoles(accountPeerId: PeerId, network: Network, postbox
|
||||
for (entry, disposable) in added {
|
||||
switch entry.hole {
|
||||
case let .peer(hole):
|
||||
disposable.set(fetchMessageHistoryHole(accountPeerId: accountPeerId, source: .network(network), postbox: postbox, peerInput: .direct(peerId: hole.peerId, threadId: nil), namespace: hole.namespace, direction: entry.direction, space: entry.space, count: entry.count).start())
|
||||
disposable.set(fetchMessageHistoryHole(accountPeerId: accountPeerId, source: .network(network), postbox: postbox, peerInput: .direct(peerId: hole.peerId, threadId: hole.threadId), namespace: hole.namespace, direction: entry.direction, space: entry.space, count: entry.count).start())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -72,7 +72,7 @@ func managedPendingPeerNotificationSettings(postbox: Postbox, network: Network)
|
||||
}
|
||||
|
||||
for (peerId, settings, disposable) in beginOperations {
|
||||
let signal = pushPeerNotificationSettings(postbox: postbox, network: network, peerId: peerId, settings: settings)
|
||||
let signal = pushPeerNotificationSettings(postbox: postbox, network: network, peerId: peerId, threadId: nil, settings: settings)
|
||||
disposable.set(signal.start())
|
||||
}
|
||||
})
|
||||
@ -89,14 +89,60 @@ func managedPendingPeerNotificationSettings(postbox: Postbox, network: Network)
|
||||
}
|
||||
}
|
||||
|
||||
private func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: PeerId, settings: PeerNotificationSettings) -> Signal<Void, NoError> {
|
||||
func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: PeerId, threadId: Int64?, settings: PeerNotificationSettings) -> Signal<Void, NoError> {
|
||||
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
var notificationPeerId = peerId
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
notificationPeerId = associatedPeerId
|
||||
}
|
||||
|
||||
if let threadId = threadId {
|
||||
if let data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||
let settings = data.notificationSettings
|
||||
|
||||
let showPreviews: Api.Bool?
|
||||
switch settings.displayPreviews {
|
||||
case .default:
|
||||
showPreviews = nil
|
||||
case .show:
|
||||
showPreviews = .boolTrue
|
||||
case .hide:
|
||||
showPreviews = .boolFalse
|
||||
}
|
||||
let muteUntil: Int32?
|
||||
switch settings.muteState {
|
||||
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: .inputNotifyForumTopic(peer: inputPeer, topMsgId: Int32(clamping: threadId)), settings: inputSettings))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
return postbox.transaction { transaction -> Void in
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
if let notificationPeer = transaction.getPeer(notificationPeerId), let inputPeer = apiInputPeer(notificationPeer), let settings = settings as? TelegramPeerNotificationSettings {
|
||||
let showPreviews: Api.Bool?
|
||||
switch settings.displayPreviews {
|
||||
@ -146,6 +192,7 @@ private func pushPeerNotificationSettings(postbox: Postbox, network: Network, pe
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
|
||||
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil)
|
||||
|
||||
@ -284,7 +284,7 @@ private func synchronizeMarkAllUnseenReactions(transaction: Transaction, postbox
|
||||
return .complete()
|
||||
}
|
||||
|
||||
let signal = network.request(Api.functions.messages.readReactions(peer: inputPeer))
|
||||
let signal = network.request(Api.functions.messages.readReactions(flags: 0, peer: inputPeer, topMsgId: nil))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.messages.AffectedHistory?, Bool> in
|
||||
return .fail(true)
|
||||
@ -308,90 +308,6 @@ private func synchronizeMarkAllUnseenReactions(transaction: Transaction, postbox
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|
||||
/*let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
let limit: Int32 = 100
|
||||
let oneOperation: (Int32) -> Signal<Int32?, MTRpcError> = { maxId in
|
||||
return network.request(Api.functions.messages.getUnreadReactions(peer: inputPeer, offsetId: maxId, addOffset: maxId == 0 ? 0 : -1, limit: limit, maxId: maxId == 0 ? 0 : (maxId + 1), minId: 1))
|
||||
|> mapToSignal { result -> Signal<[MessageId], MTRpcError> in
|
||||
switch result {
|
||||
case let .messages(messages, _, _):
|
||||
return .single(messages.compactMap({ $0.id() }))
|
||||
case let .channelMessages(_, _, _, _, messages, _, _):
|
||||
return .single(messages.compactMap({ $0.id() }))
|
||||
case .messagesNotModified:
|
||||
return .single([])
|
||||
case let .messagesSlice(_, _, _, _, messages, _, _):
|
||||
return .single(messages.compactMap({ $0.id() }))
|
||||
}
|
||||
}
|
||||
|> mapToSignal { ids -> Signal<Int32?, MTRpcError> in
|
||||
let filteredIds = ids.filter { $0.id <= operation.maxId }
|
||||
if filteredIds.isEmpty {
|
||||
return .single(ids.min()?.id)
|
||||
}
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
guard let inputChannel = inputChannel else {
|
||||
return .single(nil)
|
||||
}
|
||||
return network.request(Api.functions.channels.readMessageContents(channel: inputChannel, id: filteredIds.map { $0.id }))
|
||||
|> map { result -> Int32? in
|
||||
if ids.count < limit {
|
||||
return nil
|
||||
} else {
|
||||
return ids.min()?.id
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return network.request(Api.functions.messages.readMessageContents(id: filteredIds.map { $0.id }))
|
||||
|> map { result -> Int32? in
|
||||
switch result {
|
||||
case let .affectedMessages(pts, ptsCount):
|
||||
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
|
||||
}
|
||||
if ids.count < limit {
|
||||
return nil
|
||||
} else {
|
||||
return ids.min()?.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let currentMaxId = Atomic<Int32>(value: 0)
|
||||
let loopOperations: Signal<Void, GetUnseenIdsError> = (
|
||||
(
|
||||
deferred {
|
||||
return oneOperation(currentMaxId.with { $0 })
|
||||
}
|
||||
|> `catch` { error -> Signal<Int32?, GetUnseenIdsError> in
|
||||
return .fail(.error(error))
|
||||
}
|
||||
)
|
||||
|> mapToSignal { resultId -> Signal<Void, GetUnseenIdsError> in
|
||||
if let resultId = resultId {
|
||||
let previous = currentMaxId.swap(resultId)
|
||||
if previous == resultId {
|
||||
return .fail(.done)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .fail(.done)
|
||||
}
|
||||
}
|
||||
|> `catch` { error -> Signal<Void, GetUnseenIdsError> in
|
||||
switch error {
|
||||
case .done, .error:
|
||||
return .fail(error)
|
||||
}
|
||||
}
|
||||
|> restart
|
||||
)
|
||||
return loopOperations
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}*/
|
||||
}
|
||||
|
||||
func markUnseenReactionMessage(transaction: Transaction, id: MessageId, addSynchronizeAction: Bool) {
|
||||
|
||||
@ -68,11 +68,7 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
|
||||
if channel.flags.contains(.isForum) {
|
||||
return []
|
||||
}
|
||||
if channel.username != nil {
|
||||
return .group
|
||||
} else {
|
||||
return .group
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assertionFailure()
|
||||
|
||||
@ -73,11 +73,41 @@ public func getCloudLegacySound(id: Int64) -> (id: Int32, category: CloudSoundBu
|
||||
return nil
|
||||
}
|
||||
|
||||
public enum PeerMuteState: Equatable {
|
||||
public enum PeerMuteState: Codable, Equatable {
|
||||
case `default`
|
||||
case unmuted
|
||||
case muted(until: Int32)
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
switch try container.decode(Int32.self, forKey: "m.v") {
|
||||
case 0:
|
||||
self = .default
|
||||
case 1:
|
||||
self = .muted(until: try container.decode(Int32.self, forKey: "m.u"))
|
||||
case 2:
|
||||
self = .unmuted
|
||||
default:
|
||||
assertionFailure()
|
||||
self = .default
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
switch self {
|
||||
case .default:
|
||||
try container.encode(0 as Int32, forKey: "m.v")
|
||||
case let .muted(until):
|
||||
try container.encode(1 as Int32, forKey: "m.v")
|
||||
try container.encode(until, forKey: "m.u")
|
||||
case .unmuted:
|
||||
try container.encode(2 as Int32, forKey: "m.v")
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate static func decodeInline(_ decoder: PostboxDecoder) -> PeerMuteState {
|
||||
switch decoder.decodeInt32ForKey("m.v", orElse: 0) {
|
||||
case 0:
|
||||
@ -104,15 +134,15 @@ public enum PeerMuteState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private enum PeerMessageSoundValue: Int32 {
|
||||
case none
|
||||
case bundledModern
|
||||
case bundledClassic
|
||||
case `default`
|
||||
case cloud
|
||||
private enum PeerMessageSoundValue: Int32, Codable {
|
||||
case none = 0
|
||||
case bundledModern = 1
|
||||
case bundledClassic = 2
|
||||
case `default` = 3
|
||||
case cloud = 4
|
||||
}
|
||||
|
||||
public enum PeerMessageSound: Equatable {
|
||||
public enum PeerMessageSound: Equatable, Codable {
|
||||
public enum Id: Hashable {
|
||||
case none
|
||||
case `default`
|
||||
@ -142,6 +172,30 @@ public enum PeerMessageSound: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
switch try container.decode(Int32.self, forKey: "s.v") {
|
||||
case PeerMessageSoundValue.none.rawValue:
|
||||
self = .none
|
||||
case PeerMessageSoundValue.bundledModern.rawValue:
|
||||
self = .cloud(fileId: getCloudSoundOrDefault(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0, isModern: true))
|
||||
case PeerMessageSoundValue.bundledClassic.rawValue:
|
||||
self = .cloud(fileId: getCloudSoundOrDefault(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0, isModern: false))
|
||||
case PeerMessageSoundValue.default.rawValue:
|
||||
self = .default
|
||||
case PeerMessageSoundValue.cloud.rawValue:
|
||||
do {
|
||||
self = .cloud(fileId: try container.decode(Int64.self, forKey: "s.cloud.fileId"))
|
||||
} catch {
|
||||
self = .default
|
||||
}
|
||||
default:
|
||||
assertionFailure()
|
||||
self = defaultCloudPeerNotificationSound
|
||||
}
|
||||
}
|
||||
|
||||
static func decodeInline(_ container: KeyedDecodingContainer<StringCodingKey>) throws -> PeerMessageSound {
|
||||
switch try container.decode(Int32.self, forKey: "s.v") {
|
||||
case PeerMessageSoundValue.none.rawValue:
|
||||
@ -182,6 +236,26 @@ public enum PeerMessageSound: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
switch self {
|
||||
case .none:
|
||||
try container.encode(PeerMessageSoundValue.none.rawValue, forKey: "s.v")
|
||||
case let .bundledModern(id):
|
||||
try container.encode(PeerMessageSoundValue.bundledModern.rawValue, forKey: "s.v")
|
||||
try container.encode(id, forKey: "s.i")
|
||||
case let .bundledClassic(id):
|
||||
try container.encode(PeerMessageSoundValue.bundledClassic.rawValue, forKey: "s.v")
|
||||
try container.encode(id, forKey: "s.i")
|
||||
case let .cloud(fileId):
|
||||
try container.encode(PeerMessageSoundValue.cloud.rawValue, forKey: "s.v")
|
||||
try container.encode(fileId, forKey: "s.cloud.fileId")
|
||||
case .default:
|
||||
try container.encode(PeerMessageSoundValue.default.rawValue, forKey: "s.v")
|
||||
}
|
||||
}
|
||||
|
||||
func encodeInline(_ container: inout KeyedEncodingContainer<StringCodingKey>) throws {
|
||||
switch self {
|
||||
case .none:
|
||||
@ -254,11 +328,40 @@ public enum PeerMessageSound: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public enum PeerNotificationDisplayPreviews {
|
||||
public enum PeerNotificationDisplayPreviews: Equatable, Codable {
|
||||
case `default`
|
||||
case show
|
||||
case hide
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
switch try container.decode(Int32.self, forKey: "p.v") {
|
||||
case 0:
|
||||
self = .default
|
||||
case 1:
|
||||
self = .show
|
||||
case 2:
|
||||
self = .hide
|
||||
default:
|
||||
assertionFailure()
|
||||
self = .default
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
switch self {
|
||||
case .default:
|
||||
try container.encode(0 as Int32, forKey: "p.v")
|
||||
case .show:
|
||||
try container.encode(1 as Int32, forKey: "p.v")
|
||||
case .hide:
|
||||
try container.encode(2 as Int32, forKey: "p.v")
|
||||
}
|
||||
}
|
||||
|
||||
static func decodeInline(_ decoder: PostboxDecoder) -> PeerNotificationDisplayPreviews {
|
||||
switch decoder.decodeInt32ForKey("p.v", orElse: 0) {
|
||||
case 0:
|
||||
@ -285,7 +388,7 @@ public enum PeerNotificationDisplayPreviews {
|
||||
}
|
||||
}
|
||||
|
||||
public final class TelegramPeerNotificationSettings: PeerNotificationSettings, Equatable {
|
||||
public final class TelegramPeerNotificationSettings: PeerNotificationSettings, Codable, Equatable {
|
||||
public let muteState: PeerMuteState
|
||||
public let messageSound: PeerMessageSound
|
||||
public let displayPreviews: PeerNotificationDisplayPreviews
|
||||
@ -325,6 +428,22 @@ public final class TelegramPeerNotificationSettings: PeerNotificationSettings, E
|
||||
self.displayPreviews = PeerNotificationDisplayPreviews.decodeInline(decoder)
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.muteState = try container.decode(PeerMuteState.self, forKey: "muteState")
|
||||
self.messageSound = try container.decode(PeerMessageSound.self, forKey: "messageSound")
|
||||
self.displayPreviews = try container.decode(PeerNotificationDisplayPreviews.self, forKey: "displayPreviews")
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.muteState, forKey: "muteState")
|
||||
try container.encode(self.messageSound, forKey: "messageSound")
|
||||
try container.encode(self.displayPreviews, forKey: "displayPreviews")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
self.muteState.encodeInline(encoder)
|
||||
self.messageSound.encodeInline(encoder)
|
||||
|
||||
@ -275,23 +275,26 @@ public extension TelegramEngine.EngineData.Item {
|
||||
public struct ItemKey: Hashable {
|
||||
public var peerId: EnginePeer.Id
|
||||
public var tag: MessageTags
|
||||
public var threadId: Int64?
|
||||
}
|
||||
|
||||
public typealias Result = Int?
|
||||
|
||||
fileprivate var peerId: EnginePeer.Id
|
||||
fileprivate var tag: MessageTags
|
||||
fileprivate var threadId: Int64?
|
||||
public var mapKey: ItemKey {
|
||||
return ItemKey(peerId: self.peerId, tag: self.tag)
|
||||
return ItemKey(peerId: self.peerId, tag: self.tag, threadId: self.threadId)
|
||||
}
|
||||
|
||||
public init(peerId: EnginePeer.Id, tag: MessageTags) {
|
||||
public init(peerId: EnginePeer.Id, threadId: Int64?, tag: MessageTags) {
|
||||
self.peerId = peerId
|
||||
self.threadId = threadId
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .historyTagSummaryView(tag: tag, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||
return .historyTagSummaryView(tag: self.tag, peerId: self.peerId, threadId: self.threadId, namespace: Namespaces.Message.Cloud)
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
|
||||
@ -259,6 +259,32 @@ public extension TelegramEngine.EngineData.Item {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ThreadNotificationSettings: TelegramEngineDataItem, PostboxViewDataItem {
|
||||
public typealias Result = EnginePeer.NotificationSettings
|
||||
|
||||
fileprivate var id: EnginePeer.Id
|
||||
fileprivate var threadId: Int64
|
||||
|
||||
public init(id: EnginePeer.Id, threadId: Int64) {
|
||||
self.id = id
|
||||
self.threadId = threadId
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .messageHistoryThreadInfo(peerId: self.id, threadId: self.threadId)
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? MessageHistoryThreadInfoView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
guard let data = view.info?.get(MessageHistoryThreadData.self) else {
|
||||
return EnginePeer.NotificationSettings(TelegramPeerNotificationSettings.defaultSettings)
|
||||
}
|
||||
return EnginePeer.NotificationSettings(data.notificationSettings)
|
||||
}
|
||||
}
|
||||
|
||||
public struct ParticipantCount: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = Optional<Int>
|
||||
|
||||
|
||||
@ -115,14 +115,14 @@ public final class EngineDataOptional<Item: TelegramEngineDataItem>: TelegramEng
|
||||
}
|
||||
|
||||
func _extract(views: [PostboxViewKey: PostboxView]) -> Any {
|
||||
var result: [Item.Result] = []
|
||||
var result: Item.Result?
|
||||
|
||||
if let item = self.item {
|
||||
let itemResult = (item as! AnyPostboxViewDataItem)._extract(views: views)
|
||||
result.append(itemResult as! Item.Result)
|
||||
result = (itemResult as! Item.Result)
|
||||
}
|
||||
|
||||
return result
|
||||
return result as Any
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, viewT
|
||||
}
|
||||
|
||||
if !hasUnread && peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
let unseenSummary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud)
|
||||
let unseenSummary = transaction.getMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud)
|
||||
let actionSummary = transaction.getPendingMessageActionsSummary(peerId: peerId, type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud)
|
||||
if (unseenSummary?.count ?? 0) - (actionSummary ?? 0) > 0 {
|
||||
hasUnread = true
|
||||
@ -147,7 +147,7 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, viewT
|
||||
} else {
|
||||
transaction.applyMarkUnread(peerId: peerId, namespace: principalNamespace, value: false, interactive: true)
|
||||
}
|
||||
viewTracker.updateMarkAllMentionsSeen(peerId: peerId)
|
||||
viewTracker.updateMarkAllMentionsSeen(peerId: peerId, threadId: nil)
|
||||
}
|
||||
} else {
|
||||
if setToValue == nil || setToValue! {
|
||||
@ -156,22 +156,22 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, viewT
|
||||
}
|
||||
}
|
||||
|
||||
public func clearPeerUnseenPersonalMessagesInteractively(account: Account, peerId: PeerId) -> Signal<Never, NoError> {
|
||||
public func clearPeerUnseenPersonalMessagesInteractively(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<Never, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
return
|
||||
}
|
||||
account.viewTracker.updateMarkAllMentionsSeen(peerId: peerId)
|
||||
account.viewTracker.updateMarkAllMentionsSeen(peerId: peerId, threadId: threadId)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func clearPeerUnseenReactionsInteractively(account: Account, peerId: PeerId) -> Signal<Never, NoError> {
|
||||
public func clearPeerUnseenReactionsInteractively(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<Never, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
return
|
||||
}
|
||||
account.viewTracker.updateMarkAllReactionsSeen(peerId: peerId)
|
||||
account.viewTracker.updateMarkAllReactionsSeen(peerId: peerId, threadId: threadId)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
@ -9,14 +9,14 @@ public enum EarliestUnseenPersonalMentionMessageResult: Equatable {
|
||||
case result(MessageId?)
|
||||
}
|
||||
|
||||
func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenPersonalMessage, additionalData: [.peerChatState(peerId)])
|
||||
func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: threadId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenPersonalMessage, additionalData: [.peerChatState(peerId)])
|
||||
|> mapToSignal { view -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
|
||||
if view.0.isLoading {
|
||||
return .single(.loading)
|
||||
}
|
||||
if case .FillHole = view.1 {
|
||||
return _internal_earliestUnseenPersonalMentionMessage(account: account, peerId: peerId)
|
||||
return _internal_earliestUnseenPersonalMentionMessage(account: account, peerId: peerId, threadId: threadId)
|
||||
}
|
||||
if let message = view.0.entries.first?.message {
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
@ -53,10 +53,10 @@ func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: Pe
|
||||
} else {
|
||||
return account.postbox.transaction { transaction -> EarliestUnseenPersonalMentionMessageResult in
|
||||
if let topId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: topId.id)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: topId.id)
|
||||
|
||||
transaction.removeHole(peerId: peerId, namespace: Namespaces.Message.Cloud, space: .tag(.unseenPersonalMessage), range: 1 ... (Int32.max - 1))
|
||||
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id })
|
||||
transaction.removeHole(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, space: .tag(.unseenPersonalMessage), range: 1 ... (Int32.max - 1))
|
||||
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id })
|
||||
for id in ids {
|
||||
markUnseenPersonalMessage(transaction: transaction, id: id, addSynchronizeAction: false)
|
||||
}
|
||||
@ -76,14 +76,14 @@ func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: Pe
|
||||
})
|
||||
}
|
||||
|
||||
func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenReaction, additionalData: [.peerChatState(peerId)])
|
||||
func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||
return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: threadId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenReaction, additionalData: [.peerChatState(peerId)])
|
||||
|> mapToSignal { view -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
|
||||
if view.0.isLoading {
|
||||
return .single(.loading)
|
||||
}
|
||||
if case .FillHole = view.1 {
|
||||
return _internal_earliestUnseenPersonalReactionMessage(account: account, peerId: peerId)
|
||||
return _internal_earliestUnseenPersonalReactionMessage(account: account, peerId: peerId, threadId: threadId)
|
||||
}
|
||||
if let message = view.0.entries.first?.message {
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
@ -120,10 +120,10 @@ func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: P
|
||||
} else {
|
||||
return account.postbox.transaction { transaction -> EarliestUnseenPersonalMentionMessageResult in
|
||||
if let topId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: 0, maxId: topId.id)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: 0, maxId: topId.id)
|
||||
|
||||
transaction.removeHole(peerId: peerId, namespace: Namespaces.Message.Cloud, space: .tag(.unseenReaction), range: 1 ... (Int32.max - 1))
|
||||
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id })
|
||||
transaction.removeHole(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, space: .tag(.unseenReaction), range: 1 ... (Int32.max - 1))
|
||||
let ids = transaction.getMessageIndicesWithTag(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id })
|
||||
for id in ids {
|
||||
markUnseenReactionMessage(transaction: transaction, id: id, addSynchronizeAction: false)
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import SwiftSignalKit
|
||||
import TelegramApi
|
||||
|
||||
func _internal_topPeerActiveLiveLocationMessages(viewTracker: AccountViewTracker, accountPeerId: PeerId, peerId: PeerId) -> Signal<(Peer?, [Message]), NoError> {
|
||||
return viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .upperBound, anchorIndex: .upperBound, count: 50, fixedCombinedReadStates: nil, tagMask: .liveLocation, orderStatistics: [], additionalData: [.peer(accountPeerId)])
|
||||
return viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 50, fixedCombinedReadStates: nil, tagMask: .liveLocation, orderStatistics: [], additionalData: [.peer(accountPeerId)])
|
||||
|> map { (view, _, _) -> (Peer?, [Message]) in
|
||||
var accountPeer: Peer?
|
||||
for entry in view.additionalData {
|
||||
|
||||
@ -325,10 +325,6 @@ private class ReplyThreadHistoryContextImpl {
|
||||
return
|
||||
}
|
||||
|
||||
guard let _ = self.stateValue else {
|
||||
return
|
||||
}
|
||||
|
||||
let fromIdExclusive: Int32?
|
||||
let toIndex = messageIndex
|
||||
if let maxReadIncomingMessageId = self.maxReadIncomingMessageIdValue {
|
||||
@ -345,6 +341,7 @@ private class ReplyThreadHistoryContextImpl {
|
||||
if messageIndex.id.id >= data.maxIncomingReadId {
|
||||
if let count = transaction.getThreadMessageCount(peerId: messageId.peerId, threadId: Int64(messageId.id), namespace: messageId.namespace, fromIdExclusive: data.maxIncomingReadId, toIndex: messageIndex) {
|
||||
data.incomingUnreadCount = max(0, data.incomingUnreadCount - Int32(count))
|
||||
data.maxIncomingReadId = messageIndex.id.id
|
||||
}
|
||||
|
||||
data.maxKnownMessageId = max(data.maxKnownMessageId, messageIndex.id.id)
|
||||
@ -937,7 +934,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
|
||||
return account.postbox.transaction { transaction -> Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError> in
|
||||
if let initialFilledHoles = initialFilledHoles {
|
||||
for range in initialFilledHoles.strictRemovedIndices.rangeView {
|
||||
transaction.removeThreadIndexHole(peerId: discussionMessage.messageId.peerId, threadId: makeMessageThreadId(discussionMessage.messageId), namespace: Namespaces.Message.Cloud, space: .everywhere, range: Int32(range.lowerBound) ... Int32(range.upperBound))
|
||||
transaction.removeHole(peerId: discussionMessage.messageId.peerId, threadId: makeMessageThreadId(discussionMessage.messageId), namespace: Namespaces.Message.Cloud, space: .everywhere, range: Int32(range.lowerBound) ... Int32(range.upperBound))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -189,12 +189,7 @@ public final class SparseMessageList {
|
||||
let count: Int
|
||||
count = 200
|
||||
|
||||
let location: ChatLocationInput
|
||||
if let threadId = self.threadId {
|
||||
location = .thread(peerId: self.peerId, threadId: threadId, data: .single(MessageHistoryViewExternalInput(content: .thread(peerId: self.peerId, id: threadId, holes: [:]), maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil)))
|
||||
} else {
|
||||
location = .peer(peerId: self.peerId)
|
||||
}
|
||||
let location: ChatLocationInput = .peer(peerId: self.peerId, threadId: self.threadId)
|
||||
|
||||
self.topItemsDisposable.set((self.account.postbox.aroundMessageHistoryViewForLocation(location, anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: count, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: self.messageTag, appendMessagesFromTheSameGroup: false, namespaces: .not(Set(Namespaces.Message.allScheduled)), orderStatistics: [])
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] view, updateType, _ in
|
||||
|
||||
@ -154,32 +154,32 @@ public extension TelegramEngine {
|
||||
return PollResultsContext(account: self.account, messageId: messageId, poll: poll)
|
||||
}
|
||||
|
||||
public func earliestUnseenPersonalMentionMessage(peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||
public func earliestUnseenPersonalMentionMessage(peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||
let account = self.account
|
||||
return _internal_earliestUnseenPersonalMentionMessage(account: self.account, peerId: peerId)
|
||||
return _internal_earliestUnseenPersonalMentionMessage(account: self.account, peerId: peerId, threadId: threadId)
|
||||
|> mapToSignal { result -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
|
||||
switch result {
|
||||
case .loading:
|
||||
return .single(result)
|
||||
case let .result(messageId):
|
||||
if messageId == nil {
|
||||
let _ = clearPeerUnseenPersonalMessagesInteractively(account: account, peerId: peerId).start()
|
||||
let _ = clearPeerUnseenPersonalMessagesInteractively(account: account, peerId: peerId, threadId: threadId).start()
|
||||
}
|
||||
return .single(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func earliestUnseenPersonalReactionMessage(peerId: PeerId) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||
public func earliestUnseenPersonalReactionMessage(peerId: PeerId, threadId: Int64?) -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> {
|
||||
let account = self.account
|
||||
return _internal_earliestUnseenPersonalReactionMessage(account: self.account, peerId: peerId)
|
||||
return _internal_earliestUnseenPersonalReactionMessage(account: self.account, peerId: peerId, threadId: threadId)
|
||||
|> mapToSignal { result -> Signal<EarliestUnseenPersonalMentionMessageResult, NoError> in
|
||||
switch result {
|
||||
case .loading:
|
||||
return .single(result)
|
||||
case let .result(messageId):
|
||||
if messageId == nil {
|
||||
let _ = clearPeerUnseenReactionsInteractively(account: account, peerId: peerId).start()
|
||||
let _ = clearPeerUnseenReactionsInteractively(account: account, peerId: peerId, threadId: threadId).start()
|
||||
}
|
||||
return .single(result)
|
||||
}
|
||||
@ -297,7 +297,7 @@ public extension TelegramEngine {
|
||||
return SparseMessageScrollingContext(account: self.account, peerId: peerId)
|
||||
}
|
||||
|
||||
public func refreshMessageTagStats(peerId: EnginePeer.Id, tags: [EngineMessage.Tags]) -> Signal<Never, NoError> {
|
||||
public func refreshMessageTagStats(peerId: EnginePeer.Id, threadId: Int64?, tags: [EngineMessage.Tags]) -> Signal<Never, NoError> {
|
||||
let account = self.account
|
||||
return self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||
@ -312,7 +312,15 @@ public extension TelegramEngine {
|
||||
signals.append(.single((nil, nil)))
|
||||
continue
|
||||
}
|
||||
signals.append(self.account.network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, topMsgId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1, maxId: 0, minId: 0, hash: 0))
|
||||
|
||||
var flags: Int32 = 0
|
||||
var topMsgId: Int32?
|
||||
if let threadId = threadId {
|
||||
flags |= (1 << 1)
|
||||
topMsgId = Int32(clamping: threadId)
|
||||
}
|
||||
|
||||
signals.append(self.account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1, maxId: 0, minId: 0, hash: 0))
|
||||
|> map { result -> (count: Int32?, topId: Int32?) in
|
||||
switch result {
|
||||
case let .messagesSlice(_, count, _, _, messages, _, _):
|
||||
@ -335,7 +343,7 @@ public extension TelegramEngine {
|
||||
for i in 0 ..< tags.count {
|
||||
let (count, maxId) = counts[i]
|
||||
if let count = count {
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: tags[i], namespace: Namespaces.Message.Cloud, count: count, maxId: maxId ?? 1)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: threadId, tagMask: tags[i], namespace: Namespaces.Message.Cloud, count: count, maxId: maxId ?? 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@ func _internal_requestUnpinAllMessages(account: Account, peerId: PeerId) -> Sign
|
||||
}, delayIncrement: 0.0, maxDelay: 0.0, maxRetries: 100, onQueue: .concurrentDefaultQueue())
|
||||
|> mapToSignal { _ -> Signal<Never, InternalError> in
|
||||
let signal: Signal<Never, InternalError> = account.postbox.transaction { transaction -> Void in
|
||||
for index in transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .pinned) {
|
||||
for index in transaction.getMessageIndicesWithTag(peerId: peerId, threadId: nil, namespace: Namespaces.Message.Cloud, tag: .pinned) {
|
||||
transaction.updateMessage(index.id, update: { currentMessage in
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
|
||||
@ -1,17 +1,41 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
|
||||
|
||||
func _internal_togglePeerMuted(account: Account, peerId: PeerId) -> Signal<Void, NoError> {
|
||||
func _internal_togglePeerMuted(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
guard let peer = transaction.getPeer(peerId) else {
|
||||
return
|
||||
}
|
||||
|
||||
var notificationPeerId = peerId
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
notificationPeerId = associatedPeerId
|
||||
}
|
||||
|
||||
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
|
||||
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(id: notificationPeerId) as? TelegramPeerNotificationSettings
|
||||
let previousSettings: TelegramPeerNotificationSettings
|
||||
if let currentSettings = currentSettings {
|
||||
previousSettings = currentSettings
|
||||
@ -38,20 +62,51 @@ func _internal_togglePeerMuted(account: Account, peerId: PeerId) -> Signal<Void,
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_updatePeerMuteSetting(account: Account, peerId: PeerId, muteInterval: Int32?) -> Signal<Void, NoError> {
|
||||
func _internal_updatePeerMuteSetting(account: Account, peerId: PeerId, threadId: Int64?, muteInterval: Int32?) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
updatePeerMuteSetting(transaction: transaction, peerId: peerId, muteInterval: muteInterval)
|
||||
_internal_updatePeerMuteSetting(account: account, transaction: transaction, peerId: peerId, threadId: threadId, muteInterval: muteInterval)
|
||||
}
|
||||
}
|
||||
|
||||
func updatePeerMuteSetting(transaction: Transaction, peerId: PeerId, muteInterval: Int32?) {
|
||||
func _internal_updatePeerMuteSetting(account: Account, transaction: Transaction, peerId: PeerId, threadId: Int64?, muteInterval: Int32?) {
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
if let threadId = threadId {
|
||||
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
|
||||
|
||||
let muteState: PeerMuteState
|
||||
if let muteInterval = muteInterval {
|
||||
if muteInterval == 0 {
|
||||
muteState = .unmuted
|
||||
} else {
|
||||
let absoluteUntil: Int32
|
||||
if muteInterval == Int32.max {
|
||||
absoluteUntil = Int32.max
|
||||
} else {
|
||||
absoluteUntil = Int32(Date().timeIntervalSince1970) + muteInterval
|
||||
}
|
||||
muteState = .muted(until: absoluteUntil)
|
||||
}
|
||||
} else {
|
||||
muteState = .default
|
||||
}
|
||||
|
||||
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 {
|
||||
var notificationPeerId = peerId
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
notificationPeerId = associatedPeerId
|
||||
}
|
||||
|
||||
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
|
||||
let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings
|
||||
let previousSettings: TelegramPeerNotificationSettings
|
||||
if let currentSettings = currentSettings {
|
||||
previousSettings = currentSettings
|
||||
@ -80,21 +135,36 @@ func updatePeerMuteSetting(transaction: Transaction, peerId: PeerId, muteInterva
|
||||
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_updatePeerDisplayPreviewsSetting(account: Account, peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
|
||||
func _internal_updatePeerDisplayPreviewsSetting(account: Account, peerId: PeerId, threadId: Int64?, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
updatePeerDisplayPreviewsSetting(transaction: transaction, peerId: peerId, displayPreviews: displayPreviews)
|
||||
_internal_updatePeerDisplayPreviewsSetting(account: account, transaction: transaction, peerId: peerId, threadId: threadId, displayPreviews: displayPreviews)
|
||||
}
|
||||
}
|
||||
|
||||
func updatePeerDisplayPreviewsSetting(transaction: Transaction, peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) {
|
||||
func _internal_updatePeerDisplayPreviewsSetting(account: Account, transaction: Transaction, peerId: PeerId, threadId: Int64?, displayPreviews: PeerNotificationDisplayPreviews) {
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
if let threadId = threadId {
|
||||
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
|
||||
|
||||
data.notificationSettings = previousSettings.withUpdatedDisplayPreviews(displayPreviews)
|
||||
|
||||
if let entry = CodableEntry(data) {
|
||||
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
|
||||
}
|
||||
|
||||
//TODO:loc
|
||||
let _ = pushPeerNotificationSettings(postbox: account.postbox, network: account.network, peerId: peerId, threadId: threadId, settings: TelegramPeerNotificationSettings.defaultSettings).start()
|
||||
}
|
||||
} else {
|
||||
var notificationPeerId = peerId
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
notificationPeerId = associatedPeerId
|
||||
}
|
||||
|
||||
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
|
||||
let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings
|
||||
let previousSettings: TelegramPeerNotificationSettings
|
||||
if let currentSettings = currentSettings {
|
||||
previousSettings = currentSettings
|
||||
@ -106,21 +176,36 @@ func updatePeerDisplayPreviewsSetting(transaction: Transaction, peerId: PeerId,
|
||||
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_updatePeerNotificationSoundInteractive(account: Account, peerId: PeerId, sound: PeerMessageSound) -> Signal<Void, NoError> {
|
||||
func _internal_updatePeerNotificationSoundInteractive(account: Account, peerId: PeerId, threadId: Int64?, sound: PeerMessageSound) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
updatePeerNotificationSoundInteractive(transaction: transaction, peerId: peerId, sound: sound)
|
||||
_internal_updatePeerNotificationSoundInteractive(account: account, transaction: transaction, peerId: peerId, threadId: threadId, sound: sound)
|
||||
}
|
||||
}
|
||||
|
||||
func updatePeerNotificationSoundInteractive(transaction: Transaction, peerId: PeerId, sound: PeerMessageSound) {
|
||||
func _internal_updatePeerNotificationSoundInteractive(account: Account, transaction: Transaction, peerId: PeerId, threadId: Int64?, sound: PeerMessageSound) {
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
if let threadId = threadId {
|
||||
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||
let previousSettings: TelegramPeerNotificationSettings = data.notificationSettings
|
||||
|
||||
data.notificationSettings = previousSettings.withUpdatedMessageSound(sound)
|
||||
|
||||
if let entry = CodableEntry(data) {
|
||||
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
|
||||
}
|
||||
|
||||
//TODO:loc
|
||||
let _ = pushPeerNotificationSettings(postbox: account.postbox, network: account.network, peerId: peerId, threadId: threadId, settings: TelegramPeerNotificationSettings.defaultSettings).start()
|
||||
}
|
||||
} else {
|
||||
var notificationPeerId = peerId
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
notificationPeerId = associatedPeerId
|
||||
}
|
||||
|
||||
let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings
|
||||
let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings
|
||||
let previousSettings: TelegramPeerNotificationSettings
|
||||
if let currentSettings = currentSettings {
|
||||
previousSettings = currentSettings
|
||||
@ -132,3 +217,4 @@ func updatePeerNotificationSoundInteractive(transaction: Transaction, peerId: Pe
|
||||
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.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
|
||||
transaction.replaceMessageTagSummary(peerId: peerId, threadId: nil, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, count: unreadReactionsCount, maxId: topMessage)
|
||||
|
||||
if let pts = pts {
|
||||
if transaction.getPeerChatState(peerId) == nil {
|
||||
|
||||
@ -73,7 +73,7 @@ func _internal_joinChannel(account: Account, peerId: PeerId, hash: String?) -> S
|
||||
}
|
||||
|
||||
if let channel = transaction.getPeer(peerId) as? TelegramChannel, case .broadcast = channel.info {
|
||||
let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings ?? TelegramPeerNotificationSettings.defaultSettings
|
||||
let notificationSettings = transaction.getPeerNotificationSettings(id: peerId) as? TelegramPeerNotificationSettings ?? TelegramPeerNotificationSettings.defaultSettings
|
||||
transaction.updateCurrentPeerNotificationSettings([peerId: notificationSettings.withUpdatedMuteState(.muted(until: Int32.max))])
|
||||
}
|
||||
|
||||
|
||||
@ -183,28 +183,28 @@ public extension TelegramEngine {
|
||||
return _internal_reportRepliesMessage(account: self.account, messageId: messageId, deleteMessage: deleteMessage, deleteHistory: deleteHistory, reportSpam: reportSpam)
|
||||
}
|
||||
|
||||
public func togglePeerMuted(peerId: PeerId) -> Signal<Void, NoError> {
|
||||
return _internal_togglePeerMuted(account: self.account, peerId: peerId)
|
||||
public func togglePeerMuted(peerId: PeerId, threadId: Int64?) -> Signal<Void, NoError> {
|
||||
return _internal_togglePeerMuted(account: self.account, peerId: peerId, threadId: threadId)
|
||||
}
|
||||
|
||||
public func updatePeerMuteSetting(peerId: PeerId, muteInterval: Int32?) -> Signal<Void, NoError> {
|
||||
return _internal_updatePeerMuteSetting(account: self.account, peerId: peerId, muteInterval: muteInterval)
|
||||
public func updatePeerMuteSetting(peerId: PeerId, threadId: Int64?, muteInterval: Int32?) -> Signal<Void, NoError> {
|
||||
return _internal_updatePeerMuteSetting(account: self.account, peerId: peerId, threadId: threadId, muteInterval: muteInterval)
|
||||
}
|
||||
|
||||
public func updatePeerDisplayPreviewsSetting(peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
|
||||
return _internal_updatePeerDisplayPreviewsSetting(account: self.account, peerId: peerId, displayPreviews: displayPreviews)
|
||||
public func updatePeerDisplayPreviewsSetting(peerId: PeerId, threadId: Int64?, displayPreviews: PeerNotificationDisplayPreviews) -> Signal<Void, NoError> {
|
||||
return _internal_updatePeerDisplayPreviewsSetting(account: self.account, peerId: peerId, threadId: threadId, displayPreviews: displayPreviews)
|
||||
}
|
||||
|
||||
public func updatePeerNotificationSoundInteractive(peerId: PeerId, sound: PeerMessageSound) -> Signal<Void, NoError> {
|
||||
return _internal_updatePeerNotificationSoundInteractive(account: self.account, peerId: peerId, sound: sound)
|
||||
public func updatePeerNotificationSoundInteractive(peerId: PeerId, threadId: Int64?, sound: PeerMessageSound) -> Signal<Void, NoError> {
|
||||
return _internal_updatePeerNotificationSoundInteractive(account: self.account, peerId: peerId, threadId: threadId, sound: sound)
|
||||
}
|
||||
|
||||
public func removeCustomNotificationSettings(peerIds: [PeerId]) -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
for peerId in peerIds {
|
||||
TelegramCore.updatePeerNotificationSoundInteractive(transaction: transaction, peerId: peerId, sound: .default)
|
||||
TelegramCore.updatePeerMuteSetting(transaction: transaction, peerId: peerId, muteInterval: nil)
|
||||
TelegramCore.updatePeerDisplayPreviewsSetting(transaction: transaction, peerId: peerId, displayPreviews: .default)
|
||||
_internal_updatePeerNotificationSoundInteractive(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, sound: .default)
|
||||
_internal_updatePeerMuteSetting(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, muteInterval: nil)
|
||||
_internal_updatePeerDisplayPreviewsSetting(account: self.account, transaction: transaction, peerId: peerId, threadId: nil, displayPreviews: .default)
|
||||
}
|
||||
}
|
||||
|> ignoreValues
|
||||
|
||||
@ -71,6 +71,7 @@ public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?,
|
||||
}
|
||||
case Namespaces.Peer.CloudChannel:
|
||||
if let channel = updated as? TelegramChannel {
|
||||
if case .personal = channel.accessHash {
|
||||
switch channel.participationStatus {
|
||||
case .member:
|
||||
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: channel.creationDate, forceRootGroupIfNotExists: true)
|
||||
@ -81,6 +82,7 @@ public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?,
|
||||
default:
|
||||
transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ public enum ChatTitleContent {
|
||||
case replies
|
||||
}
|
||||
|
||||
case peer(peerView: PeerView, customTitle: String?, onlineMemberCount: Int32?, isScheduledMessages: Bool)
|
||||
case peer(peerView: PeerView, customTitle: String?, onlineMemberCount: Int32?, isScheduledMessages: Bool, isMuted: Bool?)
|
||||
case replyThread(type: ReplyThreadType, count: Int)
|
||||
case custom(String, String?, Bool)
|
||||
}
|
||||
@ -123,7 +123,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
var titleCredibilityIcon: ChatTitleCredibilityIcon = .none
|
||||
var isEnabled = true
|
||||
switch titleContent {
|
||||
case let .peer(peerView, customTitle, _, isScheduledMessages):
|
||||
case let .peer(peerView, customTitle, _, isScheduledMessages, isMuted):
|
||||
if peerView.peerId.isReplies {
|
||||
let typeText: String = self.strings.DialogList_Replies
|
||||
segments = [.text(0, NSAttributedString(string: typeText, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))]
|
||||
@ -166,6 +166,11 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
titleLeftIcon = .lock
|
||||
}
|
||||
if let isMuted {
|
||||
if isMuted {
|
||||
titleRightIcon = .mute
|
||||
}
|
||||
} else {
|
||||
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
|
||||
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
|
||||
if titleCredibilityIcon != .verified {
|
||||
@ -174,6 +179,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .replyThread(type, count):
|
||||
let textFont = titleFont
|
||||
let textColor = titleTheme.rootController.navigationBar.primaryTextColor
|
||||
@ -313,7 +319,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
var inputActivitiesAllowed = true
|
||||
if let titleContent = self.titleContent {
|
||||
switch titleContent {
|
||||
case let .peer(peerView, _, _, isScheduledMessages):
|
||||
case let .peer(peerView, _, _, isScheduledMessages, _):
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies {
|
||||
inputActivitiesAllowed = false
|
||||
@ -414,7 +420,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
} else {
|
||||
if let titleContent = self.titleContent {
|
||||
switch titleContent {
|
||||
case let .peer(peerView, _, onlineMemberCount, isScheduledMessages):
|
||||
case let .peer(peerView, _, onlineMemberCount, isScheduledMessages, _):
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
let servicePeer = isServicePeer(peer)
|
||||
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies {
|
||||
|
||||
@ -342,10 +342,14 @@ public final class AccountContextImpl: AccountContext {
|
||||
public func chatLocationInput(for location: ChatLocation, contextHolder: Atomic<ChatLocationContextHolder?>) -> ChatLocationInput {
|
||||
switch location {
|
||||
case let .peer(peerId):
|
||||
return .peer(peerId: peerId)
|
||||
return .peer(peerId: peerId, threadId: nil)
|
||||
case let .replyThread(data):
|
||||
if data.isForumPost {
|
||||
return .peer(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
|
||||
} else {
|
||||
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
|
||||
return .thread(peerId: data.messageId.peerId, threadId: makeMessageThreadId(data.messageId), data: context.state)
|
||||
}
|
||||
case let .feed(id):
|
||||
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
||||
return .feed(id: id, data: context.state)
|
||||
@ -357,8 +361,20 @@ public final class AccountContextImpl: AccountContext {
|
||||
case .peer:
|
||||
return .single(nil)
|
||||
case let .replyThread(data):
|
||||
if data.isForumPost, let peerId = location.peerId {
|
||||
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
|
||||
return self.account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> MessageId? in
|
||||
if let threadInfo = views.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.get(MessageHistoryThreadData.self) {
|
||||
return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: data.maxOutgoingReadId)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
|
||||
return context.maxReadOutgoingMessageId
|
||||
}
|
||||
case let .feed(id):
|
||||
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
||||
return context.maxReadOutgoingMessageId
|
||||
@ -382,8 +398,20 @@ public final class AccountContextImpl: AccountContext {
|
||||
return Int(unreadCount)
|
||||
}
|
||||
case let .replyThread(data):
|
||||
if data.isForumPost {
|
||||
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
|
||||
return self.account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> Int in
|
||||
if let threadInfo = views.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.get(MessageHistoryThreadData.self) {
|
||||
return Int(data.incomingUnreadCount)
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
|
||||
return context.unreadCount
|
||||
}
|
||||
case let .feed(id):
|
||||
let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id)
|
||||
return context.unreadCount
|
||||
|
||||
@ -252,7 +252,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
|
||||
break
|
||||
case .muteNotifications, .unmuteNotifications:
|
||||
if let context = self.context, let presentationInterfaceState = self.presentationInterfaceState, let peer = presentationInterfaceState.renderedPeer?.peer {
|
||||
self.actionDisposable.set(context.engine.peers.togglePeerMuted(peerId: peer.id).start())
|
||||
self.actionDisposable.set(context.engine.peers.togglePeerMuted(peerId: peer.id, threadId: nil).start())
|
||||
}
|
||||
case .hidePinnedMessages, .unpinMessages:
|
||||
self.interfaceInteraction?.unpinAllMessages()
|
||||
|
||||
@ -4384,7 +4384,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if case .pinnedMessages = presentationInterfaceState.subject {
|
||||
strongSelf.chatTitleView?.titleContent = .custom(presentationInterfaceState.strings.Chat_TitlePinnedMessages(Int32(displayedCount ?? 1)), nil, false)
|
||||
} else {
|
||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages)
|
||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil)
|
||||
let imageOverride: AvatarNodeImageOverride?
|
||||
if strongSelf.context.account.peerId == peer.id {
|
||||
imageOverride = .savedMessagesIcon
|
||||
@ -4741,18 +4741,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let peerView = context.account.viewTracker.peerView(peerId)
|
||||
|
||||
let messageAndTopic = messagePromise.get()
|
||||
|> mapToSignal { message -> Signal<(message: Message?, threadInfo: EngineMessageHistoryThread.Info?), NoError> in
|
||||
|> mapToSignal { message -> Signal<(message: Message?, threadData: MessageHistoryThreadData?), NoError> in
|
||||
guard let message = message else {
|
||||
return .single((nil, nil))
|
||||
}
|
||||
|
||||
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: Int64(message.id.id))
|
||||
return context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> (message: Message?, threadInfo: EngineMessageHistoryThread.Info?) in
|
||||
|> map { views -> (message: Message?, threadData: MessageHistoryThreadData?) in
|
||||
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
|
||||
return (message, nil)
|
||||
}
|
||||
return (message, view.info?.get(MessageHistoryThreadData.self)?.info)
|
||||
return (message, view.info?.get(MessageHistoryThreadData.self))
|
||||
}
|
||||
}
|
||||
|
||||
@ -4809,8 +4809,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
|
||||
if let threadInfo = messageAndTopic.threadInfo {
|
||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: threadInfo.title, onlineMemberCount: onlineMemberCount, isScheduledMessages: false)
|
||||
var peerIsMuted = false
|
||||
if let threadData = messageAndTopic.threadData {
|
||||
if case let .muted(until) = threadData.notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
|
||||
peerIsMuted = true
|
||||
}
|
||||
} else if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
|
||||
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
|
||||
peerIsMuted = true
|
||||
}
|
||||
}
|
||||
|
||||
if let threadInfo = messageAndTopic.threadData?.info {
|
||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: threadInfo.title, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: peerIsMuted)
|
||||
|
||||
let avatarContent: EmojiStatusComponent.Content
|
||||
if let fileId = threadInfo.icon {
|
||||
@ -4829,12 +4840,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if strongSelf.isNodeLoaded {
|
||||
strongSelf.chatDisplayNode.peerView = peerView
|
||||
}
|
||||
var peerIsMuted = false
|
||||
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
|
||||
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
|
||||
peerIsMuted = true
|
||||
}
|
||||
}
|
||||
|
||||
var peerDiscussionId: PeerId?
|
||||
var peerGeoLocation: PeerGeoLocation?
|
||||
var currentSendAsPeerId: PeerId?
|
||||
@ -6813,8 +6819,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
self.chatDisplayNode.navigateButtons.mentionsPressed = { [weak self] in
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded, case let .peer(peerId) = strongSelf.chatLocation {
|
||||
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalMentionMessage(peerId: peerId)
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded, let peerId = strongSelf.chatLocation.peerId {
|
||||
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalMentionMessage(peerId: peerId, threadId: strongSelf.chatLocation.threadId)
|
||||
strongSelf.navigationActionDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
|
||||
if let strongSelf = self {
|
||||
switch result {
|
||||
@ -6850,10 +6856,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
guard let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation else {
|
||||
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
let _ = clearPeerUnseenPersonalMessagesInteractively(account: strongSelf.context.account, peerId: peerId).start()
|
||||
let _ = clearPeerUnseenPersonalMessagesInteractively(account: strongSelf.context.account, peerId: peerId, threadId: strongSelf.chatLocation.threadId).start()
|
||||
}
|
||||
)))
|
||||
let items = ContextController.Items(content: .list(menuItems))
|
||||
@ -6870,8 +6876,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
self.chatDisplayNode.navigateButtons.reactionsPressed = { [weak self] in
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded, case let .peer(peerId) = strongSelf.chatLocation {
|
||||
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalReactionMessage(peerId: peerId)
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded, let peerId = strongSelf.chatLocation.peerId {
|
||||
let signal = strongSelf.context.engine.messages.earliestUnseenPersonalReactionMessage(peerId: peerId, threadId: strongSelf.chatLocation.threadId)
|
||||
strongSelf.navigationActionDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
|
||||
if let strongSelf = self {
|
||||
switch result {
|
||||
@ -7017,10 +7023,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
guard let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation else {
|
||||
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
let _ = clearPeerUnseenReactionsInteractively(account: strongSelf.context.account, peerId: peerId).start()
|
||||
let _ = clearPeerUnseenReactionsInteractively(account: strongSelf.context.account, peerId: peerId, threadId: strongSelf.chatLocation.threadId).start()
|
||||
}
|
||||
)))
|
||||
let items = ContextController.Items(content: .list(menuItems))
|
||||
@ -7851,7 +7857,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self?.navigationButtonAction(.openChatInfo(expandAvatar: false))
|
||||
}, togglePeerNotifications: { [weak self] in
|
||||
if let strongSelf = self, let peerId = strongSelf.chatLocation.peerId {
|
||||
let _ = strongSelf.context.engine.peers.togglePeerMuted(peerId: peerId).start()
|
||||
let _ = strongSelf.context.engine.peers.togglePeerMuted(peerId: peerId, threadId: strongSelf.chatLocation.threadId).start()
|
||||
}
|
||||
}, sendContextResult: { [weak self] results, result, node, rect in
|
||||
guard let strongSelf = self else {
|
||||
@ -9360,7 +9366,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
|
||||
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesAndReactionCount(peerId: peerId) |> deliverOnMainQueue).start(next: { [weak self] mentionCount, reactionCount in
|
||||
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesAndReactionCount(peerId: peerId, threadId: nil) |> deliverOnMainQueue).start(next: { [weak self] mentionCount, reactionCount in
|
||||
if let strongSelf = self {
|
||||
if case let .standard(previewing) = strongSelf.presentationInterfaceState.mode, previewing {
|
||||
strongSelf.chatDisplayNode.navigateButtons.mentionCount = 0
|
||||
strongSelf.chatDisplayNode.navigateButtons.reactionsCount = 0
|
||||
} else {
|
||||
strongSelf.chatDisplayNode.navigateButtons.mentionCount = mentionCount
|
||||
strongSelf.chatDisplayNode.navigateButtons.reactionsCount = reactionCount
|
||||
}
|
||||
}
|
||||
})
|
||||
} else if let peerId = self.chatLocation.peerId, let threadId = self.chatLocation.threadId {
|
||||
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesAndReactionCount(peerId: peerId, threadId: threadId) |> deliverOnMainQueue).start(next: { [weak self] mentionCount, reactionCount in
|
||||
if let strongSelf = self {
|
||||
if case let .standard(previewing) = strongSelf.presentationInterfaceState.mode, previewing {
|
||||
strongSelf.chatDisplayNode.navigateButtons.mentionCount = 0
|
||||
|
||||
@ -86,6 +86,14 @@ func chatHistoryEntriesForView(
|
||||
continue
|
||||
}
|
||||
|
||||
if case let .replyThread(replyThreadMessage) = location, replyThreadMessage.isForumPost {
|
||||
for media in message.media {
|
||||
if let action = media as? TelegramMediaAction, case .topicCreated = action.action {
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let maybeJoinMessage = joinMessage {
|
||||
if message.timestamp > maybeJoinMessage.timestamp, (!view.holeEarlier || count > 0) {
|
||||
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
||||
|
||||
@ -127,7 +127,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
|
||||
return true
|
||||
}
|
||||
|
||||
init(context: AccountContext, peerId: PeerId, tagMask: MessageTags, interfaceInteraction: ChatControllerInteraction) {
|
||||
init(context: AccountContext, peerId: PeerId, threadId: Int64?, tagMask: MessageTags, interfaceInteraction: ChatControllerInteraction) {
|
||||
self.context = context
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -174,7 +174,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
|
||||
if let strongSelf = self {
|
||||
let signal: Signal<([ChatHistorySearchEntry], [MessageId: Message])?, NoError>
|
||||
if let query = query, !query.isEmpty {
|
||||
let foundRemoteMessages: Signal<[Message], NoError> = context.engine.messages.searchMessages(location: .peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: nil, minDate: nil, maxDate: nil), query: query, state: nil)
|
||||
let foundRemoteMessages: Signal<[Message], NoError> = context.engine.messages.searchMessages(location: .peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: threadId.flatMap { makeThreadIdMessageId(peerId: peerId, threadId: $0) }, minDate: nil, maxDate: nil), query: query, state: nil)
|
||||
|> map { $0.0.messages }
|
||||
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
||||
|
||||
|
||||
@ -229,6 +229,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
}, setPeerIdWithRevealedOptions: { _, _ in
|
||||
}, setItemPinned: { _, _ in
|
||||
}, setPeerMuted: { _, _ in
|
||||
}, setPeerThreadMuted: { _, _, _ in
|
||||
}, deletePeer: { _, _ in
|
||||
}, deletePeerThread: { _, _ in
|
||||
}, updatePeerGrouping: { _, _ in
|
||||
|
||||
@ -147,7 +147,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
}
|
||||
|
||||
self.statusPromise.set(context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: tagMask)
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: chatLocation.threadId, tag: tagMask)
|
||||
)
|
||||
|> map { count -> PeerInfoStatusData? in
|
||||
let count: Int = count ?? 0
|
||||
|
||||
@ -2031,7 +2031,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
}
|
||||
|
||||
return context.engine.data.subscribe(EngineDataMap(
|
||||
summaries.map { TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: $0) }
|
||||
summaries.map { TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: chatLocation.threadId, tag: $0) }
|
||||
))
|
||||
|> map { summaries -> (ContentType, [MessageTags: Int32]) in
|
||||
var result: [MessageTags: Int32] = [:]
|
||||
|
||||
@ -187,7 +187,7 @@ final class PeerInfoScreenData {
|
||||
let invitations: PeerExportedInvitationsState?
|
||||
let requests: PeerInvitationImportersState?
|
||||
let requestsContext: PeerInvitationImportersContext?
|
||||
let threadInfo: EngineMessageHistoryThread.Info?
|
||||
let threadData: MessageHistoryThreadData?
|
||||
|
||||
init(
|
||||
peer: Peer?,
|
||||
@ -206,7 +206,7 @@ final class PeerInfoScreenData {
|
||||
invitations: PeerExportedInvitationsState?,
|
||||
requests: PeerInvitationImportersState?,
|
||||
requestsContext: PeerInvitationImportersContext?,
|
||||
threadInfo: EngineMessageHistoryThread.Info?
|
||||
threadData: MessageHistoryThreadData?
|
||||
) {
|
||||
self.peer = peer
|
||||
self.chatPeer = chatPeer
|
||||
@ -224,7 +224,7 @@ final class PeerInfoScreenData {
|
||||
self.invitations = invitations
|
||||
self.requests = requests
|
||||
self.requestsContext = requestsContext
|
||||
self.threadInfo = threadInfo
|
||||
self.threadData = threadData
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,7 +477,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
invitations: nil,
|
||||
requests: nil,
|
||||
requestsContext: nil,
|
||||
threadInfo: nil
|
||||
threadData: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -504,7 +504,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitations: nil,
|
||||
requests: nil,
|
||||
requestsContext: nil,
|
||||
threadInfo: nil
|
||||
threadData: nil
|
||||
))
|
||||
case let .user(userPeerId, secretChatId, kind):
|
||||
let groupsInCommon: GroupsInCommonContext?
|
||||
@ -635,7 +635,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitations: nil,
|
||||
requests: nil,
|
||||
requestsContext: nil,
|
||||
threadInfo: nil
|
||||
threadData: nil
|
||||
)
|
||||
}
|
||||
case .channel:
|
||||
@ -711,7 +711,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitations: invitations,
|
||||
requests: requests,
|
||||
requestsContext: currentRequestsContext,
|
||||
threadInfo: nil
|
||||
threadData: nil
|
||||
)
|
||||
}
|
||||
case let .group(groupId):
|
||||
@ -815,19 +815,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
let requestsContextPromise = Promise<PeerInvitationImportersContext?>(nil)
|
||||
let requestsStatePromise = Promise<PeerInvitationImportersState?>(nil)
|
||||
|
||||
let threadInfo: Signal<EngineMessageHistoryThread.Info?, NoError>
|
||||
let threadData: Signal<MessageHistoryThreadData?, NoError>
|
||||
if case let .replyThread(message) = chatLocation {
|
||||
let threadId = Int64(message.messageId.id)
|
||||
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
|
||||
threadInfo = context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> EngineMessageHistoryThread.Info? in
|
||||
threadData = context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> MessageHistoryThreadData? in
|
||||
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
|
||||
return nil
|
||||
}
|
||||
return view.info?.get(MessageHistoryThreadData.self)?.info
|
||||
return view.info?.get(MessageHistoryThreadData.self)
|
||||
}
|
||||
} else {
|
||||
threadInfo = .single(nil)
|
||||
threadData = .single(nil)
|
||||
}
|
||||
|
||||
return combineLatest(queue: .mainQueue(),
|
||||
@ -840,9 +840,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitationsStatePromise.get(),
|
||||
requestsContextPromise.get(),
|
||||
requestsStatePromise.get(),
|
||||
threadInfo
|
||||
threadData
|
||||
)
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadInfo -> PeerInfoScreenData in
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadData -> PeerInfoScreenData in
|
||||
var discussionPeer: Peer?
|
||||
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
||||
discussionPeer = peer
|
||||
@ -883,12 +883,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
}
|
||||
}
|
||||
|
||||
var notificationSettings: TelegramPeerNotificationSettings?
|
||||
if let threadData = threadData {
|
||||
notificationSettings = threadData.notificationSettings
|
||||
} else {
|
||||
notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings
|
||||
}
|
||||
|
||||
return PeerInfoScreenData(
|
||||
peer: peerView.peers[groupId],
|
||||
chatPeer: peerView.peers[groupId],
|
||||
cachedData: peerView.cachedData,
|
||||
status: status,
|
||||
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
||||
notificationSettings: notificationSettings,
|
||||
globalNotificationSettings: globalNotificationSettings,
|
||||
isContact: peerView.peerIsContact,
|
||||
availablePanes: availablePanes ?? [],
|
||||
@ -900,21 +907,30 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitations: invitations,
|
||||
requests: requests,
|
||||
requestsContext: currentRequestsContext,
|
||||
threadInfo: threadInfo
|
||||
threadData: threadData
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func canEditPeerInfo(context: AccountContext, peer: Peer?) -> Bool {
|
||||
func canEditPeerInfo(context: AccountContext, peer: Peer?, threadData: MessageHistoryThreadData?) -> Bool {
|
||||
if context.account.peerId == peer?.id {
|
||||
return true
|
||||
}
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if let threadData = threadData {
|
||||
if channel.hasPermission(.pinMessages) {
|
||||
return true
|
||||
}
|
||||
if threadData.author == context.account.peerId {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if channel.hasPermission(.changeInfo) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else if let group = peer as? TelegramGroup {
|
||||
switch group.role {
|
||||
case .admin, .creator:
|
||||
|
||||
@ -634,7 +634,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
|
||||
transition.updateAlpha(node: self, alpha: 1.0 - fraction)
|
||||
}
|
||||
|
||||
func update(peer: Peer?, item: PeerInfoAvatarListItem?, updatingAvatar: PeerInfoUpdatingAvatar?, uploadProgress: CGFloat?, theme: PresentationTheme, avatarSize: CGFloat, isEditing: Bool) {
|
||||
func update(peer: Peer?, threadData: MessageHistoryThreadData?, item: PeerInfoAvatarListItem?, updatingAvatar: PeerInfoUpdatingAvatar?, uploadProgress: CGFloat?, theme: PresentationTheme, avatarSize: CGFloat, isEditing: Bool) {
|
||||
guard let peer = peer else {
|
||||
return
|
||||
}
|
||||
@ -644,7 +644,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
|
||||
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .linear)
|
||||
|
||||
if canEditPeerInfo(context: self.context, peer: peer) {
|
||||
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
|
||||
var overlayHidden = true
|
||||
if let updatingAvatar = updatingAvatar {
|
||||
overlayHidden = false
|
||||
@ -730,12 +730,12 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
var removedPhotoResourceIds = Set<String>()
|
||||
func update(peer: Peer?, item: PeerInfoAvatarListItem?, updatingAvatar: PeerInfoUpdatingAvatar?, uploadProgress: CGFloat?, theme: PresentationTheme, avatarSize: CGFloat, isEditing: Bool) {
|
||||
func update(peer: Peer?, threadData: MessageHistoryThreadData?, item: PeerInfoAvatarListItem?, updatingAvatar: PeerInfoUpdatingAvatar?, uploadProgress: CGFloat?, theme: PresentationTheme, avatarSize: CGFloat, isEditing: Bool) {
|
||||
guard let peer = peer else {
|
||||
return
|
||||
}
|
||||
|
||||
let canEdit = canEditPeerInfo(context: self.context, peer: peer)
|
||||
let canEdit = canEditPeerInfo(context: self.context, peer: peer, threadData: threadData)
|
||||
|
||||
let previousItem = self.item
|
||||
var item = item
|
||||
@ -1906,14 +1906,14 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
||||
self.itemNodes[key]?.layer.addShakeAnimation()
|
||||
}
|
||||
|
||||
func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, peer: Peer?, cachedData: CachedPeerData?, isContact: Bool, isSettings: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, peer: Peer?, threadData: MessageHistoryThreadData?, cachedData: CachedPeerData?, isContact: Bool, isSettings: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let avatarSize: CGFloat = isModalOverlay ? 200.0 : 100.0
|
||||
let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 13.0), size: CGSize(width: avatarSize, height: avatarSize))
|
||||
transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize()))
|
||||
|
||||
var contentHeight: CGFloat = statusBarHeight + 10.0 + avatarSize + 20.0
|
||||
|
||||
if canEditPeerInfo(context: self.context, peer: peer) {
|
||||
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
|
||||
if self.avatarButtonNode.supernode == nil {
|
||||
self.addSubnode(self.avatarButtonNode)
|
||||
}
|
||||
@ -1936,12 +1936,12 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
||||
}
|
||||
} else if let _ = peer as? TelegramGroup {
|
||||
fieldKeys.append(.title)
|
||||
if canEditPeerInfo(context: self.context, peer: peer) {
|
||||
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
|
||||
fieldKeys.append(.description)
|
||||
}
|
||||
} else if let _ = peer as? TelegramChannel {
|
||||
fieldKeys.append(.title)
|
||||
if canEditPeerInfo(context: self.context, peer: peer) {
|
||||
if canEditPeerInfo(context: self.context, peer: peer, threadData: threadData) {
|
||||
fieldKeys.append(.description)
|
||||
}
|
||||
}
|
||||
@ -1995,10 +1995,10 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
||||
} else {
|
||||
placeholder = presentationData.strings.GroupInfo_GroupNamePlaceholder
|
||||
}
|
||||
isEnabled = canEditPeerInfo(context: self.context, peer: peer)
|
||||
isEnabled = canEditPeerInfo(context: self.context, peer: peer, threadData: threadData)
|
||||
case .description:
|
||||
placeholder = presentationData.strings.Channel_Edit_AboutItem
|
||||
isEnabled = canEditPeerInfo(context: self.context, peer: peer)
|
||||
isEnabled = canEditPeerInfo(context: self.context, peer: peer, threadData: threadData)
|
||||
}
|
||||
let itemHeight = itemNode.update(width: width, safeInset: safeInset, isSettings: isSettings, hasPrevious: hasPrevious, hasNext: key != fieldKeys.last, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText)
|
||||
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)))
|
||||
@ -2029,6 +2029,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
private var presentationData: PresentationData?
|
||||
private var state: PeerInfoState?
|
||||
private var peer: Peer?
|
||||
private var threadData: MessageHistoryThreadData?
|
||||
private var avatarSize: CGFloat?
|
||||
|
||||
private let isOpenedFromChat: Bool
|
||||
@ -2225,7 +2226,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
guard let strongSelf = self, let state = strongSelf.state, let peer = strongSelf.peer, let presentationData = strongSelf.presentationData, let avatarSize = strongSelf.avatarSize else {
|
||||
return
|
||||
}
|
||||
strongSelf.editingContentNode.avatarNode.update(peer: peer, item: strongSelf.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||
strongSelf.editingContentNode.avatarNode.update(peer: peer, threadData: strongSelf.threadData, item: strongSelf.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||
}
|
||||
|
||||
self.avatarListNode.animateOverlaysFadeIn = { [weak self] in
|
||||
@ -2344,9 +2345,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
private var currentCredibilityIcon: CredibilityIcon?
|
||||
|
||||
private var currentPanelStatusData: PeerInfoStatusData?
|
||||
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadInfo: EngineMessageHistoryThread.Info?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
|
||||
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
|
||||
self.state = state
|
||||
self.peer = peer
|
||||
self.threadData = threadData
|
||||
self.avatarListNode.listContainerNode.peer = peer
|
||||
|
||||
let previousPanelStatusData = self.currentPanelStatusData
|
||||
@ -2503,7 +2505,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
self.buttonsContainerNode.alpha = self.regularContentNode.alpha
|
||||
self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0
|
||||
|
||||
let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, isModalOverlay: isModalOverlay, peer: state.isEditing ? peer : nil, cachedData: cachedData, isContact: isContact, isSettings: isSettings, presentationData: presentationData, transition: transition)
|
||||
let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, isModalOverlay: isModalOverlay, peer: state.isEditing ? peer : nil, threadData: threadData, cachedData: cachedData, isContact: isContact, isSettings: isSettings, presentationData: presentationData, transition: transition)
|
||||
transition.updateFrame(node: self.editingContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -contentOffset), size: CGSize(width: width, height: editingContentHeight)))
|
||||
|
||||
let avatarOverlayFarme = self.editingContentNode.convert(self.editingContentNode.avatarNode.frame, to: self)
|
||||
@ -2567,7 +2569,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
let expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
|
||||
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
|
||||
|
||||
let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadInfo)
|
||||
let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadData?.info)
|
||||
|
||||
var isPremium = false
|
||||
var isVerified = false
|
||||
@ -2591,8 +2593,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
title = presentationData.strings.Conversation_SavedMessages
|
||||
} else if peer.id == self.context.account.peerId && !self.isSettings {
|
||||
title = presentationData.strings.DialogList_Replies
|
||||
} else if let threadInfo = threadInfo {
|
||||
title = threadInfo.title
|
||||
} else if let threadData = threadData {
|
||||
title = threadData.info.title
|
||||
} else {
|
||||
title = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
}
|
||||
@ -2619,7 +2621,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
smallSubtitleString = NSAttributedString(string: subtitle, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))
|
||||
subtitleString = NSAttributedString(string: subtitle, font: Font.regular(17.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
|
||||
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
|
||||
} else if let _ = threadInfo {
|
||||
} else if let _ = threadData {
|
||||
let subtitleColor: UIColor = presentationData.theme.list.itemSecondaryTextColor
|
||||
|
||||
//TODO:localize
|
||||
@ -2909,9 +2911,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
})
|
||||
}
|
||||
|
||||
self.avatarListNode.update(size: CGSize(), avatarSize: avatarSize, isExpanded: self.isAvatarExpanded, peer: peer, threadInfo: threadInfo, theme: presentationData.theme, transition: transition)
|
||||
self.editingContentNode.avatarNode.update(peer: peer, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||
self.avatarOverlayNode.update(peer: peer, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||
self.avatarListNode.update(size: CGSize(), avatarSize: avatarSize, isExpanded: self.isAvatarExpanded, peer: peer, threadInfo: threadData?.info, theme: presentationData.theme, transition: transition)
|
||||
self.editingContentNode.avatarNode.update(peer: peer, threadData: threadData, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||
self.avatarOverlayNode.update(peer: peer, threadData: threadData, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||
if additive {
|
||||
transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale)
|
||||
transition.updateSublayerTransformScaleAdditive(node: self.avatarOverlayNode, scale: avatarScale)
|
||||
|
||||
@ -1078,7 +1078,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
let ItemMembers = 6
|
||||
let ItemMemberRequests = 7
|
||||
|
||||
if let _ = data.threadInfo {
|
||||
if let _ = data.threadData {
|
||||
let mainUsername: String
|
||||
if let addressName = channel.addressName {
|
||||
mainUsername = addressName
|
||||
@ -1599,7 +1599,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
}
|
||||
}
|
||||
|
||||
if cachedData.flags.contains(.canSetStickerSet) && canEditPeerInfo(context: context, peer: channel) {
|
||||
if cachedData.flags.contains(.canSetStickerSet) && canEditPeerInfo(context: context, peer: channel, threadData: data.threadData) {
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemStickerPack, label: .text(cachedData.stickerPack?.title ?? presentationData.strings.GroupInfo_SharedMediaNone), text: presentationData.strings.Stickers_GroupStickers, icon: UIImage(bundleImageName: "Settings/Menu/Stickers"), action: {
|
||||
interaction.editingOpenStickerPackSetup()
|
||||
}))
|
||||
@ -2817,7 +2817,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
case .edit:
|
||||
if case let .replyThread(message) = strongSelf.chatLocation {
|
||||
let threadId = Int64(message.messageId.id)
|
||||
if let threadInfo = strongSelf.data?.threadInfo {
|
||||
if let threadInfo = strongSelf.data?.threadData?.info {
|
||||
let controller = ForumCreateTopicScreen(context: strongSelf.context, peerId: strongSelf.peerId, mode: .edit(topic: threadInfo))
|
||||
controller.navigationPresentation = .modal
|
||||
let context = strongSelf.context
|
||||
@ -2990,7 +2990,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
} else {
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
|
||||
}
|
||||
} else if let group = data.peer as? TelegramGroup, canEditPeerInfo(context: strongSelf.context, peer: group) {
|
||||
} else if let group = data.peer as? TelegramGroup, canEditPeerInfo(context: strongSelf.context, peer: group, threadData: data.threadData) {
|
||||
let title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? ""
|
||||
let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? ""
|
||||
|
||||
@ -3049,7 +3049,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
|
||||
}))
|
||||
}
|
||||
} else if let channel = data.peer as? TelegramChannel, canEditPeerInfo(context: strongSelf.context, peer: channel) {
|
||||
} else if let channel = data.peer as? TelegramChannel, canEditPeerInfo(context: strongSelf.context, peer: channel, threadData: data.threadData) {
|
||||
let title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? ""
|
||||
let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? ""
|
||||
|
||||
@ -3383,7 +3383,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
})
|
||||
|
||||
self.refreshMessageTagStatsDisposable = context.engine.messages.refreshMessageTagStats(peerId: peerId, tags: [.video, .photo, .gif, .music, .voiceOrInstantVideo, .webPage, .file]).start()
|
||||
self.refreshMessageTagStatsDisposable = context.engine.messages.refreshMessageTagStats(peerId: peerId, threadId: chatLocation.threadId, tags: [.video, .photo, .gif, .music, .voiceOrInstantVideo, .webPage, .file]).start()
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -3557,7 +3557,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
self.view.endEditing(true)
|
||||
|
||||
return self.context.sharedContext.openChatMessage(OpenChatMessageParams(context: self.context, chatLocation: nil, chatLocationContextHolder: nil, message: galleryMessage, standalone: false, reverseMessageGalleryOrder: true, navigationController: navigationController, dismissInput: { [weak self] in
|
||||
return self.context.sharedContext.openChatMessage(OpenChatMessageParams(context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, message: galleryMessage, standalone: false, reverseMessageGalleryOrder: true, navigationController: navigationController, dismissInput: { [weak self] in
|
||||
self?.view.endEditing(true)
|
||||
}, present: { [weak self] c, a in
|
||||
self?.controller?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
@ -3919,7 +3919,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self.requestCall(isVideo: false, gesture: gesture)
|
||||
case .mute:
|
||||
if let notificationSettings = self.data?.notificationSettings, case .muted = notificationSettings.muteState {
|
||||
let _ = self.context.engine.peers.updatePeerMuteSetting(peerId: self.peerId, muteInterval: nil).start()
|
||||
let _ = self.context.engine.peers.updatePeerMuteSetting(peerId: self.peerId, threadId: self.chatLocation.threadId, muteInterval: nil).start()
|
||||
|
||||
let iconColor: UIColor = .white
|
||||
self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
|
||||
@ -3968,7 +3968,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: value).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: value).start()
|
||||
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_mute_for", scale: 0.066, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipMutedFor(mutedForTimeIntervalString(strings: strongSelf.presentationData.strings, value: value)).string), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
@ -4006,7 +4006,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: .default).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, sound: .default).start()
|
||||
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundEnabled), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
@ -4019,7 +4019,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: .none).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, sound: .none).start()
|
||||
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundDisabled), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
@ -4033,19 +4033,20 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
guard let strongSelf = self, let peer = strongSelf.data?.peer else {
|
||||
return
|
||||
}
|
||||
let threadId = strongSelf.chatLocation.threadId
|
||||
|
||||
let context = strongSelf.context
|
||||
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
||||
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: sound) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
|
||||
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, muteInterval: muteInterval) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: muteInterval) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerDisplayPreviews: (PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
|
||||
peerId, displayPreviews in
|
||||
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, displayPreviews: displayPreviews) |> deliverOnMainQueue
|
||||
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: threadId, displayPreviews: displayPreviews) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let mode: NotificationExceptionMode
|
||||
@ -4063,7 +4064,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
mode = .groups([:])
|
||||
}
|
||||
|
||||
let exceptionController = notificationPeerExceptionController(context: context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, peer: peer, mode: mode, edit: true, updatePeerSound: { peerId, sound in
|
||||
let exceptionController = notificationPeerExceptionController(context: context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, peer: peer, threadId: threadId, mode: mode, edit: true, updatePeerSound: { peerId, sound in
|
||||
let _ = (updatePeerSound(peer.id, sound)
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
|
||||
@ -4107,7 +4108,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: Int32.max).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: Int32.max).start()
|
||||
|
||||
let iconColor: UIColor = .white
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
|
||||
@ -4151,8 +4152,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return .single(items)
|
||||
}
|
||||
|
||||
let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: false, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: data.threadInfo))
|
||||
let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: true, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: strongSelf.data?.threadInfo))
|
||||
let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: false, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: data.threadData?.info))
|
||||
let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: true, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: strongSelf.data?.threadData?.info))
|
||||
|
||||
let filteredButtons = allHeaderButtons.subtracting(headerButtons)
|
||||
|
||||
@ -4820,9 +4821,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
if value <= 0 {
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: nil).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: nil).start()
|
||||
} else {
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: value).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: value).start()
|
||||
|
||||
let timeString = stringForPreciseRelativeTimestamp(strings: strongSelf.presentationData.strings, relativeTimestamp: Int32(Date().timeIntervalSince1970) + value, relativeTo: Int32(Date().timeIntervalSince1970), dateTimeFormat: strongSelf.presentationData.dateTimeFormat)
|
||||
|
||||
@ -5269,7 +5270,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: sound).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, sound: sound).start()
|
||||
})
|
||||
soundController.navigationPresentation = .modal
|
||||
strongSelf.controller?.push(soundController)
|
||||
@ -5277,7 +5278,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, muteInterval: value).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: value).start()
|
||||
})
|
||||
strongSelf.view.endEditing(true)
|
||||
strongSelf.controller?.present(muteSettingsController, in: .window(.root))
|
||||
@ -5298,7 +5299,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: sound).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, threadId: strongSelf.chatLocation.threadId, sound: sound).start()
|
||||
})
|
||||
strongSelf.controller?.push(soundController)
|
||||
})
|
||||
@ -5310,7 +5311,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
guard let strongSelf = self, let peer = peer else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peer.id, displayPreviews: value ? .show : .hide).start()
|
||||
let _ = strongSelf.context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peer.id, threadId: strongSelf.chatLocation.threadId, displayPreviews: value ? .show : .hide).start()
|
||||
})
|
||||
}
|
||||
|
||||
@ -6526,7 +6527,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
|
||||
private func openAvatarForEditing(fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
|
||||
guard let peer = self.data?.peer, canEditPeerInfo(context: self.context, peer: peer) else {
|
||||
guard let peer = self.data?.peer, canEditPeerInfo(context: self.context, peer: peer, threadData: self.data?.threadData) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -7308,7 +7309,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, threadId: self.chatLocation.threadId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in
|
||||
self?.deactivateSearch()
|
||||
})
|
||||
}
|
||||
@ -7364,8 +7365,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let peerId = self.peerId
|
||||
|
||||
let _ = (self.context.engine.data.get(EngineDataMap([
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: .photo),
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: .video)
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: self.chatLocation.threadId, tag: .photo),
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: self.chatLocation.threadId, tag: .video)
|
||||
]))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] messageCounts in
|
||||
guard let strongSelf = self else {
|
||||
@ -7417,6 +7418,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
items.append(.action(generateAction(false)))
|
||||
|
||||
var ignoreNextActions = false
|
||||
if strongSelf.chatLocation.threadId == nil {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowCalendar, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, a in
|
||||
@ -7428,6 +7430,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
self?.openMediaCalendar()
|
||||
})))
|
||||
}
|
||||
|
||||
if photoCount != 0 && videoCount != 0 {
|
||||
items.append(.separator)
|
||||
@ -7665,7 +7668,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
let headerInset = sectionInset
|
||||
|
||||
var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadInfo: self.data?.threadInfo, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
|
||||
var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
|
||||
if !self.isSettings && !self.state.isEditing {
|
||||
headerHeight += 71.0
|
||||
}
|
||||
@ -8025,7 +8028,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
let headerInset = sectionInset
|
||||
|
||||
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadInfo: self.data?.threadInfo, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
|
||||
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
|
||||
}
|
||||
|
||||
let paneAreaExpansionDistance: CGFloat = 32.0
|
||||
@ -9042,7 +9045,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
|
||||
}
|
||||
let headerInset = sectionInset
|
||||
|
||||
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadInfo: self.screenNode.data?.threadInfo, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, transition: transition, additive: false)
|
||||
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, transition: transition, additive: false)
|
||||
}
|
||||
|
||||
let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height
|
||||
|
||||
@ -880,7 +880,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
|
||||
animationTimer.start()
|
||||
|
||||
self.statusPromise.set(context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: tagMaskForType(self.contentType))
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, threadId: chatLocation.threadId, tag: tagMaskForType(self.contentType))
|
||||
)
|
||||
|> map { count -> PeerInfoStatusData? in
|
||||
let count: Int = count ?? 0
|
||||
@ -925,7 +925,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
|
||||
return
|
||||
}
|
||||
self.isRequestingView = true
|
||||
self.listDisposable.set((self.context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: self.peerId), index: .upperBound, anchorIndex: .upperBound, count: self.numberOfItemsToRequest, fixedCombinedReadStates: nil, tagMask: tagMaskForType(self.contentType))
|
||||
self.listDisposable.set((self.context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: self.peerId, threadId: self.chatLocation.threadId), index: .upperBound, anchorIndex: .upperBound, count: self.numberOfItemsToRequest, fixedCombinedReadStates: nil, tagMask: tagMaskForType(self.contentType))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] (view, updateType, _) in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
||||
@ -213,7 +213,7 @@ private final class PrefetchManagerInnerImpl {
|
||||
context = PrefetchMediaContext()
|
||||
self.contexts[id] = context
|
||||
|
||||
let priority: FetchManagerPriority = .backgroundPrefetch(locationOrder: HistoryPreloadIndex(index: nil, hasUnread: false, isMuted: false, isPriority: true), localOrder: MessageIndex(id: MessageId(peerId: PeerId(0), namespace: 0, id: order), timestamp: 0))
|
||||
let priority: FetchManagerPriority = .backgroundPrefetch(locationOrder: HistoryPreloadIndex(index: nil, threadId: nil, hasUnread: false, isMuted: false, isPriority: true), localOrder: MessageIndex(id: MessageId(peerId: PeerId(0), namespace: 0, id: order), timestamp: 0))
|
||||
|
||||
if case .full = automaticDownload {
|
||||
let fetchSignal = freeMediaFileInteractiveFetched(fetchManager: self.fetchManager, fileReference: .standalone(media: media), priority: priority)
|
||||
|
||||
@ -91,7 +91,7 @@ final class WatchChatMessagesHandler: WatchRequestHandler {
|
||||
|> take(1)
|
||||
|> mapToSignal({ context -> Signal<(MessageHistoryView, Bool, PresentationData), NoError> in
|
||||
if let context = context {
|
||||
return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .upperBound, anchorIndex: .upperBound, count: limit, fixedCombinedReadStates: nil)
|
||||
return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: limit, fixedCombinedReadStates: nil)
|
||||
|> map { messageHistoryView, _, _ -> (MessageHistoryView, Bool, PresentationData) in
|
||||
return (messageHistoryView, peerId == context.account.peerId, context.sharedContext.currentPresentationData.with { $0 })
|
||||
}
|
||||
@ -833,7 +833,7 @@ final class WatchPeerSettingsHandler: WatchRequestHandler {
|
||||
var signal: Signal<Void, NoError>?
|
||||
|
||||
if let args = subscription as? TGBridgePeerUpdateNotificationSettingsSubscription, let peerId = makePeerIdFromBridgeIdentifier(args.peerId) {
|
||||
signal = context.engine.peers.togglePeerMuted(peerId: peerId)
|
||||
signal = context.engine.peers.togglePeerMuted(peerId: peerId, threadId: nil)
|
||||
} else if let args = subscription as? TGBridgePeerUpdateBlockStatusSubscription, let peerId = makePeerIdFromBridgeIdentifier(args.peerId) {
|
||||
signal = context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peerId, isBlocked: args.blocked)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user