Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
overtake 2020-03-16 18:33:54 +04:00
commit e66140094e
21 changed files with 501 additions and 207 deletions

View File

@ -40,7 +40,7 @@ func archiveContextMenuItems(context: AccountContext, groupId: PeerGroupId, chat
} }
enum ChatContextMenuSource { enum ChatContextMenuSource {
case chatList(isFilter: Bool) case chatList(filter: ChatListFilter?)
case search(ChatListSearchContextActionSource) case search(ChatListSearchContextActionSource)
} }
@ -146,10 +146,16 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, source: ChatC
}))) })))
} }
if case .chatList(false) = source { if case let .chatList(filter) = source {
let isPinned = index.pinningIndex != nil let isPinned = index.pinningIndex != nil
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = (toggleItemPinned(postbox: context.account.postbox, groupId: group, itemId: .peer(peerId)) let location: TogglePeerChatPinnedLocation
if let filter = filter {
location = .filter(filter.id)
} else {
location = .group(group)
}
let _ = (toggleItemPinned(postbox: context.account.postbox, location: location, itemId: .peer(peerId))
|> deliverOnMainQueue).start(next: { result in |> deliverOnMainQueue).start(next: { result in
switch result { switch result {
case .done: case .done:

View File

@ -923,7 +923,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
case let .peer(peer): case let .peer(peer):
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true)) let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false) chatController.canReadHistory.set(false)
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peer.peerId, source: .chatList(isFilter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter != nil), chatListController: strongSelf), reactionItems: [], gesture: gesture) let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peer.peerId, source: .chatList(filter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter), chatListController: strongSelf), reactionItems: [], gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController) strongSelf.presentInGlobalOverlay(contextController)
} }
} }

View File

@ -200,7 +200,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
}, present: { _ in }) }, present: { _ in })
let items = (0 ..< 2).map { _ -> ChatListItem in let items = (0 ..< 2).map { _ -> ChatListItem in
return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
} }
var itemNodes: [ChatListItemNode] = [] var itemNodes: [ChatListItemNode] = []

View File

@ -740,7 +740,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
var state = f(current) var state = f(current)
if !state.changedName { if !state.changedName {
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers)) let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers, pinnedPeers: currentPreset?.data.pinnedPeers ?? []))
switch chatListFilterType(filter) { switch chatListFilterType(filter) {
case .generic: case .generic:
state.name = initialName state.name = initialName
@ -781,7 +781,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
}, },
openAddIncludePeer: { openAddIncludePeer: {
let state = stateValue.with { $0 } let state = stateValue.with { $0 }
let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers)) let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers, pinnedPeers: currentPreset?.data.pinnedPeers ?? []))
let controller = internalChatListFilterAddChatsController(context: context, filter: filter, applyAutomatically: false, updated: { filter in let controller = internalChatListFilterAddChatsController(context: context, filter: filter, applyAutomatically: false, updated: { filter in
skipStateAnimation = true skipStateAnimation = true
@ -797,7 +797,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
}, },
openAddExcludePeer: { openAddExcludePeer: {
let state = stateValue.with { $0 } let state = stateValue.with { $0 }
let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers)) let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers, pinnedPeers: currentPreset?.data.pinnedPeers ?? []))
let controller = internalChatListFilterExcludeChatsController(context: context, filter: filter, applyAutomatically: false, updated: { filter in let controller = internalChatListFilterExcludeChatsController(context: context, filter: filter, applyAutomatically: false, updated: { filter in
skipStateAnimation = true skipStateAnimation = true
@ -918,7 +918,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
var attemptNavigationImpl: (() -> Bool)? var attemptNavigationImpl: (() -> Bool)?
var applyImpl: (() -> Void)? = { var applyImpl: (() -> Void)? = {
let state = stateValue.with { $0 } let state = stateValue.with { $0 }
let preset = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers)) let preset = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers, pinnedPeers: currentPreset?.data.pinnedPeers ?? []))
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
var preset = preset var preset = preset
if currentPreset == nil { if currentPreset == nil {
@ -1013,7 +1013,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
attemptNavigationImpl = { attemptNavigationImpl = {
let state = stateValue.with { $0 } let state = stateValue.with { $0 }
if let currentPreset = currentPreset { if let currentPreset = currentPreset {
let filter = ChatListFilter(id: currentPreset.id, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers)) let filter = ChatListFilter(id: currentPreset.id, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers, pinnedPeers: currentPreset.data.pinnedPeers))
if currentPreset != filter { if currentPreset != filter {
displaySaveAlert() displaySaveAlert()
return false return false

View File

@ -484,7 +484,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
} }
}) })
case let .message(message, peer, readState, presentationData): case let .message(message, peer, readState, presentationData):
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: enableHeaders ? ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: enableHeaders ? ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
case let .addContact(phoneNumber, theme, strings): case let .addContact(phoneNumber, theme, strings):
return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
interaction.addContact(phoneNumber) interaction.addContact(phoneNumber)

View File

@ -37,7 +37,7 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
let presentationData: ChatListPresentationData let presentationData: ChatListPresentationData
let context: AccountContext let context: AccountContext
let peerGroupId: PeerGroupId let peerGroupId: PeerGroupId
let isInFilter: Bool let filterData: ChatListItemFilterData?
let index: ChatListIndex let index: ChatListIndex
public let content: ChatListItemContent public let content: ChatListItemContent
let editing: Bool let editing: Bool
@ -59,10 +59,10 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
return self.index.pinningIndex != nil return self.index.pinningIndex != nil
} }
public init(presentationData: ChatListPresentationData, context: AccountContext, peerGroupId: PeerGroupId, isInFilter: Bool, index: ChatListIndex, content: ChatListItemContent, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, header: ListViewItemHeader?, enableContextActions: Bool, hiddenOffset: Bool, interaction: ChatListNodeInteraction) { public init(presentationData: ChatListPresentationData, context: AccountContext, peerGroupId: PeerGroupId, filterData: ChatListItemFilterData?, index: ChatListIndex, content: ChatListItemContent, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, header: ListViewItemHeader?, enableContextActions: Bool, hiddenOffset: Bool, interaction: ChatListNodeInteraction) {
self.presentationData = presentationData self.presentationData = presentationData
self.peerGroupId = peerGroupId self.peerGroupId = peerGroupId
self.isInFilter = isInFilter self.filterData = filterData
self.context = context self.context = context
self.index = index self.index = index
self.content = content self.content = content
@ -204,7 +204,15 @@ private func canArchivePeer(id: PeerId, accountPeerId: PeerId) -> Bool {
return true return true
} }
private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool, isMuted: Bool?, groupId: PeerGroupId, peerId: PeerId, accountPeerId: PeerId, canDelete: Bool, isEditing: Bool, isInFilter: Bool) -> [ItemListRevealOption] { public struct ChatListItemFilterData: Equatable {
public var excludesArchived: Bool
public init(excludesArchived: Bool) {
self.excludesArchived = excludesArchived
}
}
private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool, isMuted: Bool?, groupId: PeerGroupId, peerId: PeerId, accountPeerId: PeerId, canDelete: Bool, isEditing: Bool, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] {
var options: [ItemListRevealOption] = [] var options: [ItemListRevealOption] = []
if !isEditing { if !isEditing {
if case .group = groupId { if case .group = groupId {
@ -226,7 +234,7 @@ private func revealOptions(strings: PresentationStrings, theme: PresentationThem
if canDelete { if canDelete {
options.append(ItemListRevealOption(key: RevealOptionKey.delete.rawValue, title: strings.Common_Delete, icon: deleteIcon, color: theme.list.itemDisclosureActions.destructive.fillColor, textColor: theme.list.itemDisclosureActions.destructive.foregroundColor)) options.append(ItemListRevealOption(key: RevealOptionKey.delete.rawValue, title: strings.Common_Delete, icon: deleteIcon, color: theme.list.itemDisclosureActions.destructive.fillColor, textColor: theme.list.itemDisclosureActions.destructive.foregroundColor))
} }
if !isEditing && !isInFilter { if !isEditing && filterData == nil {
if case .root = groupId { if case .root = groupId {
if canArchivePeer(id: peerId, accountPeerId: accountPeerId) { if canArchivePeer(id: peerId, accountPeerId: accountPeerId) {
options.append(ItemListRevealOption(key: RevealOptionKey.archive.rawValue, title: strings.ChatList_ArchiveAction, icon: archiveIcon, color: theme.list.itemDisclosureActions.inactive.fillColor, textColor: theme.list.itemDisclosureActions.inactive.foregroundColor)) options.append(ItemListRevealOption(key: RevealOptionKey.archive.rawValue, title: strings.ChatList_ArchiveAction, icon: archiveIcon, color: theme.list.itemDisclosureActions.inactive.fillColor, textColor: theme.list.itemDisclosureActions.inactive.foregroundColor))
@ -250,7 +258,7 @@ private func groupReferenceRevealOptions(strings: PresentationStrings, theme: Pr
return options return options
} }
private func leftRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isUnread: Bool, isEditing: Bool, isPinned: Bool, isSavedMessages: Bool, groupId: PeerGroupId, isInFilter: Bool) -> [ItemListRevealOption] { private func leftRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isUnread: Bool, isEditing: Bool, isPinned: Bool, isSavedMessages: Bool, groupId: PeerGroupId, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] {
if case .group = groupId { if case .group = groupId {
return [] return []
} }
@ -260,7 +268,7 @@ private func leftRevealOptions(strings: PresentationStrings, theme: Presentation
} else { } else {
options.append(ItemListRevealOption(key: RevealOptionKey.toggleMarkedUnread.rawValue, title: strings.DialogList_Unread, icon: unreadIcon, color: theme.list.itemDisclosureActions.accent.fillColor, textColor: theme.list.itemDisclosureActions.accent.foregroundColor)) options.append(ItemListRevealOption(key: RevealOptionKey.toggleMarkedUnread.rawValue, title: strings.DialogList_Unread, icon: unreadIcon, color: theme.list.itemDisclosureActions.accent.fillColor, textColor: theme.list.itemDisclosureActions.accent.foregroundColor))
} }
if !isEditing && !isInFilter { if !isEditing {
if isPinned { if isPinned {
options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor)) options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor))
} else { } else {
@ -1169,9 +1177,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let isPinned = item.index.pinningIndex != nil let isPinned = item.index.pinningIndex != nil
if item.enableContextActions && !isAd { if item.enableContextActions && !isAd {
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: item.context.account.peerId != item.index.messageIndex.id.peerId ? (currentMutedIconImage != nil) : nil, groupId: item.peerGroupId, peerId: renderedPeer.peerId, accountPeerId: item.context.account.peerId, canDelete: true, isEditing: item.editing, isInFilter: item.isInFilter) peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: item.context.account.peerId != item.index.messageIndex.id.peerId ? (currentMutedIconImage != nil) : nil, groupId: item.peerGroupId, peerId: renderedPeer.peerId, accountPeerId: item.context.account.peerId, canDelete: true, isEditing: item.editing, filterData: item.filterData)
if case let .chat(itemPeer) = contentPeer { if case let .chat(itemPeer) = contentPeer {
peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread, isEditing: item.editing, isPinned: isPinned, isSavedMessages: itemPeer.peerId == item.context.account.peerId, groupId: item.peerGroupId, isInFilter: item.isInFilter) peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread, isEditing: item.editing, isPinned: isPinned, isSavedMessages: itemPeer.peerId == item.context.account.peerId, groupId: item.peerGroupId, filterData: item.filterData)
} else { } else {
peerLeftRevealOptions = [] peerLeftRevealOptions = []
} }

View File

@ -153,7 +153,7 @@ public struct ChatListNodeState: Equatable {
} }
} }
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, isInFilter: Bool, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] { private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
return entries.map { entry -> ListViewInsertItem in return entries.map { entry -> ListViewInsertItem in
switch entry.entry { switch entry.entry {
case .HeaderEntry: case .HeaderEntry:
@ -172,7 +172,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
case let .PeerEntry(index, presentationData, message, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages, isContact): case let .PeerEntry(index, presentationData, message, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages, isContact):
switch mode { switch mode {
case .chatList: case .chatList:
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, isInFilter: isInFilter, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, filterData: filterData, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint)
case let .peers(filter, isSelecting, _): case let .peers(filter, isSelecting, _):
let itemPeer = peer.chatMainPeer let itemPeer = peer.chatMainPeer
var chatPeer: Peer? var chatPeer: Peer?
@ -266,20 +266,20 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
case let .HoleEntry(_, theme): case let .HoleEntry(_, theme):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint)
case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault): case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, isInFilter: isInFilter, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, filterData: filterData, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint)
case let .ArchiveIntro(presentationData): case let .ArchiveIntro(presentationData):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
} }
} }
} }
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, isInFilter: Bool, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] { private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
return entries.map { entry -> ListViewUpdateItem in return entries.map { entry -> ListViewUpdateItem in
switch entry.entry { switch entry.entry {
case let .PeerEntry(index, presentationData, message, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages, isContact): case let .PeerEntry(index, presentationData, message, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages, isContact):
switch mode { switch mode {
case .chatList: case .chatList:
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, isInFilter: isInFilter, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, filterData: filterData, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint)
case let .peers(filter, isSelecting, _): case let .peers(filter, isSelecting, _):
let itemPeer = peer.chatMainPeer let itemPeer = peer.chatMainPeer
var chatPeer: Peer? var chatPeer: Peer?
@ -329,7 +329,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
case let .HoleEntry(_, theme): case let .HoleEntry(_, theme):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint)
case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault): case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, isInFilter: isInFilter, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, filterData: filterData, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint)
case let .ArchiveIntro(presentationData): case let .ArchiveIntro(presentationData):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
case .HeaderEntry: case .HeaderEntry:
@ -349,8 +349,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
} }
} }
private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, isInFilter: Bool, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition { private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, isInFilter: isInFilter, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, isInFilter: isInFilter, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem, animateCrossfade: transition.animateCrossfade) return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, filterData: filterData, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, filterData: filterData, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem, animateCrossfade: transition.animateCrossfade)
} }
private final class ChatListOpaqueTransactionState { private final class ChatListOpaqueTransactionState {
@ -560,7 +560,13 @@ public final class ChatListNode: ListView {
} }
} }
}, setItemPinned: { [weak self] itemId, _ in }, setItemPinned: { [weak self] itemId, _ in
let _ = (toggleItemPinned(postbox: context.account.postbox, groupId: groupId, itemId: itemId) let location: TogglePeerChatPinnedLocation
if let chatListFilter = chatListFilter {
location = .filter(chatListFilter.id)
} else {
location = .group(groupId)
}
let _ = (toggleItemPinned(postbox: context.account.postbox, location: location, itemId: itemId)
|> deliverOnMainQueue).start(next: { result in |> deliverOnMainQueue).start(next: { result in
if let strongSelf = self { if let strongSelf = self {
switch result { switch result {
@ -856,10 +862,12 @@ public final class ChatListNode: ListView {
updatedScrollPosition = nil updatedScrollPosition = nil
} }
let isInFilter = filter != nil let filterData = filter.flatMap { filter -> ChatListItemFilterData in
return ChatListItemFilterData(excludesArchived: filter.data.excludeArchived)
}
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode) return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode)
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, peerGroupId: groupId, isInFilter: isInFilter, mode: mode, transition: $0) }) |> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, peerGroupId: groupId, filterData: filterData, mode: mode, transition: $0) })
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue) |> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
} }
@ -1033,30 +1041,33 @@ public final class ChatListNode: ListView {
var referenceId: PinnedItemId? var referenceId: PinnedItemId?
var beforeAll = false var beforeAll = false
switch toEntry { switch toEntry {
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, isAd, _, _): case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, isAd, _, _):
if isAd { if isAd {
beforeAll = true beforeAll = true
} else { } else {
referenceId = .peer(index.messageIndex.id.peerId) referenceId = .peer(index.messageIndex.id.peerId)
} }
/*case let .GroupReferenceEntry(_, _, groupId, _, _, _, _):
referenceId = .group(groupId)*/
default: default:
break break
} }
if case let .index(index) = fromEntry.sortIndex, let _ = index.pinningIndex { if case let .index(index) = fromEntry.sortIndex, let _ = index.pinningIndex {
return strongSelf.context.account.postbox.transaction { transaction -> Bool in return strongSelf.context.account.postbox.transaction { transaction -> Bool in
var itemIds = transaction.getPinnedItemIds(groupId: groupId) let location: TogglePeerChatPinnedLocation
if let chatListFilter = chatListFilter {
location = .filter(chatListFilter.id)
} else {
location = .group(groupId)
}
var itemIds = getPinnedItemIds(transaction: transaction, location: location)
var itemId: PinnedItemId? var itemId: PinnedItemId?
switch fromEntry { switch fromEntry {
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
itemId = .peer(index.messageIndex.id.peerId) itemId = .peer(index.messageIndex.id.peerId)
/*case let .GroupReferenceEntry(_, _, groupId, _, _, _, _): default:
itemId = .group(groupId)*/ break
default:
break
} }
if let itemId = itemId { if let itemId = itemId {
@ -1082,7 +1093,7 @@ public final class ChatListNode: ListView {
} else { } else {
itemIds.append(itemId) itemIds.append(itemId)
} }
return reorderPinnedItemIds(transaction: transaction, groupId: groupId, itemIds: itemIds) return reorderPinnedItemIds(transaction: transaction, location: location, itemIds: itemIds)
} else { } else {
return false return false
} }

View File

@ -30,8 +30,14 @@ struct ChatListNodeViewUpdate {
} }
func chatListFilterPredicate(filter: ChatListFilterData) -> ChatListFilterPredicate { func chatListFilterPredicate(filter: ChatListFilterData) -> ChatListFilterPredicate {
let includePeers = Set(filter.includePeers) var includePeers = Set(filter.includePeers)
let excludePeers = Set(filter.excludePeers) var excludePeers = Set(filter.excludePeers)
if !filter.pinnedPeers.isEmpty {
includePeers.subtract(filter.pinnedPeers)
excludePeers.subtract(filter.pinnedPeers)
}
var includeAdditionalPeerGroupIds: [PeerGroupId] = [] var includeAdditionalPeerGroupIds: [PeerGroupId] = []
if !filter.excludeArchived { if !filter.excludeArchived {
includeAdditionalPeerGroupIds.append(Namespaces.PeerGroup.archive) includeAdditionalPeerGroupIds.append(Namespaces.PeerGroup.archive)
@ -41,7 +47,7 @@ func chatListFilterPredicate(filter: ChatListFilterData) -> ChatListFilterPredic
if filter.excludeRead { if filter.excludeRead {
messageTagSummary = ChatListMessageTagSummaryResultCalculation(addCount: ChatListMessageTagSummaryResultComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), subtractCount: ChatListMessageTagActionsSummaryResultComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud)) messageTagSummary = ChatListMessageTagSummaryResultCalculation(addCount: ChatListMessageTagSummaryResultComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), subtractCount: ChatListMessageTagActionsSummaryResultComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud))
} }
return ChatListFilterPredicate(includePeerIds: includePeers, excludePeerIds: excludePeers, messageTagSummary: messageTagSummary, includeAdditionalPeerGroupIds: includeAdditionalPeerGroupIds, include: { peer, isMuted, isUnread, isContact, messageTagSummaryResult in return ChatListFilterPredicate(includePeerIds: includePeers, excludePeerIds: excludePeers, pinnedPeerIds: filter.pinnedPeers, messageTagSummary: messageTagSummary, includeAdditionalPeerGroupIds: includeAdditionalPeerGroupIds, include: { peer, isMuted, isUnread, isContact, messageTagSummaryResult in
if filter.excludeRead { if filter.excludeRead {
var effectiveUnread = isUnread var effectiveUnread = isUnread
if let messageTagSummaryResult = messageTagSummaryResult, messageTagSummaryResult { if let messageTagSummaryResult = messageTagSummaryResult, messageTagSummaryResult {

View File

@ -188,9 +188,23 @@ func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toV
} }
} }
} else if fromView.filteredEntries.isEmpty || fromView.filter != toView.filter { } else if fromView.filteredEntries.isEmpty || fromView.filter != toView.filter {
options.remove(.AnimateInsertion) var updateEmpty = true
options.remove(.AnimateAlpha) if !fromView.filteredEntries.isEmpty, let fromFilter = fromView.filter, let toFilter = toView.filter, fromFilter.data.pinnedPeers != toFilter.data.pinnedPeers {
fromEmptyView = true var fromData = fromFilter.data
var toData = toFilter.data
fromData.pinnedPeers = []
toData.pinnedPeers = []
if fromData == toData {
options.insert(.AnimateInsertion)
updateEmpty = false
}
}
if updateEmpty {
options.remove(.AnimateInsertion)
options.remove(.AnimateAlpha)
fromEmptyView = true
}
} }
} else { } else {
fromEmptyView = true fromEmptyView = true

View File

@ -174,6 +174,13 @@ open class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerD
} }
} }
open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
/*if gestureRecognizer === self.recognizer && otherGestureRecognizer is InteractiveTransitionGestureRecognizer {
return true
}*/
return false
}
@objc private func revealTapGesture(_ recognizer: UITapGestureRecognizer) { @objc private func revealTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state { if case .ended = recognizer.state {
self.updateRevealOffsetInternal(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring)) self.updateRevealOffsetInternal(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))

View File

@ -253,19 +253,24 @@ private enum ChatListEntryType {
public struct ChatListFilterPredicate { public struct ChatListFilterPredicate {
public var includePeerIds: Set<PeerId> public var includePeerIds: Set<PeerId>
public var excludePeerIds: Set<PeerId> public var excludePeerIds: Set<PeerId>
public var pinnedPeerIds: [PeerId]
public var messageTagSummary: ChatListMessageTagSummaryResultCalculation? public var messageTagSummary: ChatListMessageTagSummaryResultCalculation?
public var includeAdditionalPeerGroupIds: [PeerGroupId] public var includeAdditionalPeerGroupIds: [PeerGroupId]
public var include: (Peer, Bool, Bool, Bool, Bool?) -> Bool public var include: (Peer, Bool, Bool, Bool, Bool?) -> Bool
public init(includePeerIds: Set<PeerId>, excludePeerIds: Set<PeerId>, messageTagSummary: ChatListMessageTagSummaryResultCalculation?, includeAdditionalPeerGroupIds: [PeerGroupId], include: @escaping (Peer, Bool, Bool, Bool, Bool?) -> Bool) { public init(includePeerIds: Set<PeerId>, excludePeerIds: Set<PeerId>, pinnedPeerIds: [PeerId], messageTagSummary: ChatListMessageTagSummaryResultCalculation?, includeAdditionalPeerGroupIds: [PeerGroupId], include: @escaping (Peer, Bool, Bool, Bool, Bool?) -> Bool) {
self.includePeerIds = includePeerIds self.includePeerIds = includePeerIds
self.excludePeerIds = excludePeerIds self.excludePeerIds = excludePeerIds
self.pinnedPeerIds = pinnedPeerIds
self.messageTagSummary = messageTagSummary self.messageTagSummary = messageTagSummary
self.includeAdditionalPeerGroupIds = includeAdditionalPeerGroupIds self.includeAdditionalPeerGroupIds = includeAdditionalPeerGroupIds
self.include = include self.include = include
} }
func includes(peer: Peer, groupId: PeerGroupId, isRemovedFromTotalUnreadCount: Bool, isUnread: Bool, isContact: Bool, messageTagSummaryResult: Bool?) -> Bool { func includes(peer: Peer, groupId: PeerGroupId, isRemovedFromTotalUnreadCount: Bool, isUnread: Bool, isContact: Bool, messageTagSummaryResult: Bool?) -> Bool {
if self.pinnedPeerIds.contains(peer.id) {
return false
}
let includePeerId = peer.associatedPeerId ?? peer.id let includePeerId = peer.associatedPeerId ?? peer.id
if self.excludePeerIds.contains(includePeerId) { if self.excludePeerIds.contains(includePeerId) {
return false return false
@ -299,19 +304,22 @@ final class MutableChatListView {
self.summaryComponents = summaryComponents self.summaryComponents = summaryComponents
var spaces: [ChatListViewSpace] = [ var spaces: [ChatListViewSpace] = [
.group(groupId: self.groupId, pinned: .notPinned) .group(groupId: self.groupId, pinned: .notPinned, predicate: filterPredicate)
] ]
if let filterPredicate = self.filterPredicate { if let filterPredicate = self.filterPredicate {
spaces.append(.group(groupId: self.groupId, pinned: .includePinnedAsUnpinned)) spaces.append(.group(groupId: self.groupId, pinned: .includePinnedAsUnpinned, predicate: filterPredicate))
for additionalGroupId in filterPredicate.includeAdditionalPeerGroupIds { for additionalGroupId in filterPredicate.includeAdditionalPeerGroupIds {
spaces.append(.group(groupId: additionalGroupId, pinned: .notPinned)) spaces.append(.group(groupId: additionalGroupId, pinned: .notPinned, predicate: filterPredicate))
spaces.append(.group(groupId: additionalGroupId, pinned: .includePinnedAsUnpinned)) spaces.append(.group(groupId: additionalGroupId, pinned: .includePinnedAsUnpinned, predicate: filterPredicate))
}
if !filterPredicate.pinnedPeerIds.isEmpty {
spaces.append(.peers(peerIds: filterPredicate.pinnedPeerIds, asPinned: true))
} }
} else { } else {
spaces.append(.group(groupId: self.groupId, pinned: .includePinned)) spaces.append(.group(groupId: self.groupId, pinned: .includePinned, predicate: filterPredicate))
} }
self.spaces = spaces self.spaces = spaces
self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: aroundIndex, filterPredicate: self.filterPredicate, summaryComponents: self.summaryComponents, halfLimit: count) self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: aroundIndex, summaryComponents: self.summaryComponents, halfLimit: count)
self.sampledState = self.state.sample(postbox: postbox) self.sampledState = self.state.sample(postbox: postbox)
self.count = count self.count = count
@ -404,7 +412,7 @@ final class MutableChatListView {
func refreshDueToExternalTransaction(postbox: Postbox) -> Bool { func refreshDueToExternalTransaction(postbox: Postbox) -> Bool {
var updated = false var updated = false
self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: .absoluteUpperBound, filterPredicate: self.filterPredicate, summaryComponents: self.summaryComponents, halfLimit: self.count) self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: .absoluteUpperBound, summaryComponents: self.summaryComponents, halfLimit: self.count)
self.sampledState = self.state.sample(postbox: postbox) self.sampledState = self.state.sample(postbox: postbox)
updated = true updated = true
@ -423,7 +431,7 @@ final class MutableChatListView {
var hasChanges = false var hasChanges = false
if transaction.updatedGlobalNotificationSettings && self.filterPredicate != nil { if transaction.updatedGlobalNotificationSettings && self.filterPredicate != nil {
self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: .absoluteUpperBound, filterPredicate: self.filterPredicate, summaryComponents: self.summaryComponents, halfLimit: self.count) self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: .absoluteUpperBound, summaryComponents: self.summaryComponents, halfLimit: self.count)
self.sampledState = self.state.sample(postbox: postbox) self.sampledState = self.state.sample(postbox: postbox)
hasChanges = true hasChanges = true
} else { } else {

View File

@ -15,7 +15,42 @@ enum ChatListViewSpacePinned {
} }
enum ChatListViewSpace: Hashable { enum ChatListViewSpace: Hashable {
case group(groupId: PeerGroupId, pinned: ChatListViewSpacePinned) case group(groupId: PeerGroupId, pinned: ChatListViewSpacePinned, predicate: ChatListFilterPredicate?)
case peers(peerIds: [PeerId], asPinned: Bool)
static func ==(lhs: ChatListViewSpace, rhs: ChatListViewSpace) -> Bool {
switch lhs {
case let .group(groupId, pinned, _):
if case let .group(rhsGroupId, rhsPinned, _) = rhs {
if groupId != rhsGroupId {
return false
}
if pinned != rhsPinned {
return false
}
return true
} else {
return false
}
case let .peers(peerIds, asPinned):
if case .peers(peerIds, asPinned) = rhs {
return true
} else {
return false
}
}
}
func hash(into hasher: inout Hasher) {
switch self {
case let .group(groupId, pinned, _):
hasher.combine(groupId)
hasher.combine(pinned)
case let .peers(peerIds, asPinned):
hasher.combine(peerIds)
hasher.combine(asPinned)
}
}
} }
private func mappedChatListFilterPredicate(postbox: Postbox, groupId: PeerGroupId, predicate: ChatListFilterPredicate) -> (ChatListIntermediateEntry) -> Bool { private func mappedChatListFilterPredicate(postbox: Postbox, groupId: PeerGroupId, predicate: ChatListFilterPredicate) -> (ChatListIntermediateEntry) -> Bool {
@ -91,16 +126,14 @@ private func updatedRenderedPeer(_ renderedPeer: RenderedPeer, updatedPeers: [Pe
private final class ChatListViewSpaceState { private final class ChatListViewSpaceState {
private let space: ChatListViewSpace private let space: ChatListViewSpace
private let anchorIndex: MutableChatListEntryIndex private let anchorIndex: MutableChatListEntryIndex
private let filterPredicate: ChatListFilterPredicate?
private let summaryComponents: ChatListEntrySummaryComponents private let summaryComponents: ChatListEntrySummaryComponents
private let halfLimit: Int private let halfLimit: Int
var orderedEntries: OrderedChatListViewEntries var orderedEntries: OrderedChatListViewEntries
init(postbox: Postbox, space: ChatListViewSpace, anchorIndex: MutableChatListEntryIndex, filterPredicate: ChatListFilterPredicate?, summaryComponents: ChatListEntrySummaryComponents, halfLimit: Int) { init(postbox: Postbox, space: ChatListViewSpace, anchorIndex: MutableChatListEntryIndex, summaryComponents: ChatListEntrySummaryComponents, halfLimit: Int) {
self.space = space self.space = space
self.anchorIndex = anchorIndex self.anchorIndex = anchorIndex
self.filterPredicate = filterPredicate
self.summaryComponents = summaryComponents self.summaryComponents = summaryComponents
self.halfLimit = halfLimit self.halfLimit = halfLimit
self.orderedEntries = OrderedChatListViewEntries(anchorIndex: anchorIndex.index, lowerOrAtAnchor: [], higherThanAnchor: []) self.orderedEntries = OrderedChatListViewEntries(anchorIndex: anchorIndex.index, lowerOrAtAnchor: [], higherThanAnchor: [])
@ -109,7 +142,7 @@ private final class ChatListViewSpaceState {
private func fillSpace(postbox: Postbox) { private func fillSpace(postbox: Postbox) {
switch self.space { switch self.space {
case let .group(groupId, pinned): case let .group(groupId, pinned, filterPredicate):
let lowerBound: MutableChatListEntryIndex let lowerBound: MutableChatListEntryIndex
let upperBound: MutableChatListEntryIndex let upperBound: MutableChatListEntryIndex
if pinned.include { if pinned.include {
@ -145,7 +178,7 @@ private final class ChatListViewSpaceState {
let resolvedUnpinnedAnchorIndex = min(unpinnedUpperBound, max(self.anchorIndex, unpinnedLowerBound)) let resolvedUnpinnedAnchorIndex = min(unpinnedUpperBound, max(self.anchorIndex, unpinnedLowerBound))
if lowerOrAtAnchorMessages.count < self.halfLimit || higherThanAnchorMessages.count < self.halfLimit { if lowerOrAtAnchorMessages.count < self.halfLimit || higherThanAnchorMessages.count < self.halfLimit {
let loadedMessages = postbox.chatListTable.entries(groupId: groupId, from: (ChatListIndex.pinnedLowerBound, true), to: (ChatListIndex.absoluteUpperBound, true), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit * 2, predicate: self.filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry).sorted(by: { $0.entryIndex < $1.entryIndex }) let loadedMessages = postbox.chatListTable.entries(groupId: groupId, from: (ChatListIndex.pinnedLowerBound, true), to: (ChatListIndex.absoluteUpperBound, true), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit * 2, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry).sorted(by: { $0.entryIndex < $1.entryIndex })
if lowerOrAtAnchorMessages.count < self.halfLimit { if lowerOrAtAnchorMessages.count < self.halfLimit {
var nextLowerIndex: MutableChatListEntryIndex var nextLowerIndex: MutableChatListEntryIndex
@ -184,7 +217,7 @@ private final class ChatListViewSpaceState {
} else { } else {
nextLowerIndex = resolvedAnchorIndex nextLowerIndex = resolvedAnchorIndex
} }
let loadedLowerMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextLowerIndex.index, nextLowerIndex.isMessage), to: (lowerBound.index, lowerBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - lowerOrAtAnchorMessages.count, predicate: self.filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry) let loadedLowerMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextLowerIndex.index, nextLowerIndex.isMessage), to: (lowerBound.index, lowerBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - lowerOrAtAnchorMessages.count, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry)
lowerOrAtAnchorMessages.append(contentsOf: loadedLowerMessages) lowerOrAtAnchorMessages.append(contentsOf: loadedLowerMessages)
} }
if higherThanAnchorMessages.count < self.halfLimit { if higherThanAnchorMessages.count < self.halfLimit {
@ -194,7 +227,7 @@ private final class ChatListViewSpaceState {
} else { } else {
nextHigherIndex = resolvedAnchorIndex nextHigherIndex = resolvedAnchorIndex
} }
let loadedHigherMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextHigherIndex.index, nextHigherIndex.isMessage), to: (upperBound.index, upperBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - higherThanAnchorMessages.count, predicate: self.filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry) let loadedHigherMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextHigherIndex.index, nextHigherIndex.isMessage), to: (upperBound.index, upperBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - higherThanAnchorMessages.count, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry)
higherThanAnchorMessages.append(contentsOf: loadedHigherMessages) higherThanAnchorMessages.append(contentsOf: loadedHigherMessages)
} }
} }
@ -210,6 +243,78 @@ private final class ChatListViewSpaceState {
let entries = OrderedChatListViewEntries(anchorIndex: self.anchorIndex.index, lowerOrAtAnchor: lowerOrAtAnchorMessages, higherThanAnchor: higherThanAnchorMessages) let entries = OrderedChatListViewEntries(anchorIndex: self.anchorIndex.index, lowerOrAtAnchor: lowerOrAtAnchorMessages, higherThanAnchor: higherThanAnchorMessages)
self.orderedEntries = entries self.orderedEntries = entries
case let .peers(peerIds, asPinned):
var lowerOrAtAnchorMessages: [MutableChatListEntry] = self.orderedEntries.lowerOrAtAnchor.reversed()
var higherThanAnchorMessages: [MutableChatListEntry] = self.orderedEntries.higherThanAnchor
let unpinnedLowerBound: MutableChatListEntryIndex
let unpinnedUpperBound: MutableChatListEntryIndex
unpinnedUpperBound = .absoluteUpperBound
unpinnedLowerBound = MutableChatListEntryIndex(index: ChatListIndex.absoluteLowerBound, isMessage: true)
let resolvedUnpinnedAnchorIndex = min(unpinnedUpperBound, max(self.anchorIndex, unpinnedLowerBound))
if lowerOrAtAnchorMessages.count < self.halfLimit || higherThanAnchorMessages.count < self.halfLimit {
func mapEntry(_ entry: ChatListIntermediateEntry, pinningIndex: UInt16?) -> MutableChatListEntry {
switch entry {
case let .message(index, messageIndex):
var updatedIndex = index
updatedIndex = ChatListIndex(pinningIndex: pinningIndex, messageIndex: index.messageIndex)
return .IntermediateMessageEntry(index: updatedIndex, messageIndex: messageIndex)
case let .hole(hole):
return .HoleEntry(hole)
}
}
var loadedMessages: [MutableChatListEntry] = []
for i in 0 ..< peerIds.count {
let peerId = peerIds[i]
if let entry = postbox.chatListTable.getEntry(peerId: peerId, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable) {
loadedMessages.append(mapEntry(entry, pinningIndex: asPinned ? UInt16(i) : nil))
}
}
loadedMessages.sort(by: { $0.entryIndex < $1.entryIndex })
if lowerOrAtAnchorMessages.count < self.halfLimit {
var nextLowerIndex: MutableChatListEntryIndex
if let lastMessage = lowerOrAtAnchorMessages.min(by: { $0.entryIndex < $1.entryIndex }) {
nextLowerIndex = lastMessage.entryIndex.predecessor
} else {
nextLowerIndex = min(resolvedUnpinnedAnchorIndex, self.anchorIndex)
}
var loadedLowerMessages = Array(loadedMessages.filter({ $0.entryIndex <= nextLowerIndex }).reversed())
let lowerLimit = self.halfLimit - lowerOrAtAnchorMessages.count
if loadedLowerMessages.count > lowerLimit {
loadedLowerMessages.removeLast(loadedLowerMessages.count - lowerLimit)
}
lowerOrAtAnchorMessages.append(contentsOf: loadedLowerMessages)
}
if higherThanAnchorMessages.count < self.halfLimit {
var nextHigherIndex: MutableChatListEntryIndex
if let lastMessage = higherThanAnchorMessages.max(by: { $0.entryIndex < $1.entryIndex }) {
nextHigherIndex = lastMessage.entryIndex.successor
} else {
nextHigherIndex = max(resolvedUnpinnedAnchorIndex, self.anchorIndex.successor)
}
var loadedHigherMessages = loadedMessages.filter({ $0.entryIndex > nextHigherIndex })
let higherLimit = self.halfLimit - higherThanAnchorMessages.count
if loadedHigherMessages.count > higherLimit {
loadedHigherMessages.removeLast(loadedHigherMessages.count - higherLimit)
}
higherThanAnchorMessages.append(contentsOf: loadedHigherMessages)
}
lowerOrAtAnchorMessages.reverse()
assert(lowerOrAtAnchorMessages.count <= self.halfLimit)
assert(higherThanAnchorMessages.count <= self.halfLimit)
let allIndices = (lowerOrAtAnchorMessages + higherThanAnchorMessages).map { $0.entryIndex }
assert(Set(allIndices).count == allIndices.count)
assert(allIndices.sorted() == allIndices)
let entries = OrderedChatListViewEntries(anchorIndex: self.anchorIndex.index, lowerOrAtAnchor: lowerOrAtAnchorMessages, higherThanAnchor: higherThanAnchorMessages)
self.orderedEntries = entries
}
} }
} }
@ -218,27 +323,21 @@ private final class ChatListViewSpaceState {
var hadRemovals = false var hadRemovals = false
var globalNotificationSettings: PostboxGlobalNotificationSettings? var globalNotificationSettings: PostboxGlobalNotificationSettings?
for (groupId, operations) in transaction.chatListOperations { for (groupId, operations) in transaction.chatListOperations {
let matchesSpace: Bool
switch self.space {
case .group(groupId, _):
matchesSpace = true
default:
matchesSpace = false
}
if !matchesSpace {
continue
}
inner: for operation in operations { inner: for operation in operations {
switch operation { switch operation {
case let .InsertEntry(index, messageIndex): case let .InsertEntry(index, messageIndex):
switch self.space { switch self.space {
case let .group(_, pinned) where (index.pinningIndex != nil) == pinned.include: case let .group(spaceGroupId, pinned, filterPredicate):
let matchesGroup = groupId == spaceGroupId && (index.pinningIndex != nil) == pinned.include
if !matchesGroup {
continue inner
}
var updatedIndex = index var updatedIndex = index
if case .includePinnedAsUnpinned = pinned { if case .includePinnedAsUnpinned = pinned {
updatedIndex = ChatListIndex(pinningIndex: nil, messageIndex: index.messageIndex) updatedIndex = ChatListIndex(pinningIndex: nil, messageIndex: index.messageIndex)
} }
if let filterPredicate = self.filterPredicate { if let filterPredicate = filterPredicate {
if let peer = postbox.peerTable.get(updatedIndex.messageIndex.id.peerId) { if let peer = postbox.peerTable.get(updatedIndex.messageIndex.id.peerId) {
let notificationsPeerId = peer.notificationSettingsPeerId ?? peer.id let notificationsPeerId = peer.notificationSettingsPeerId ?? peer.id
let globalNotificationSettingsValue: PostboxGlobalNotificationSettings let globalNotificationSettingsValue: PostboxGlobalNotificationSettings
@ -263,42 +362,80 @@ private final class ChatListViewSpaceState {
if self.add(entry: .IntermediateMessageEntry(index: updatedIndex, messageIndex: messageIndex)) { if self.add(entry: .IntermediateMessageEntry(index: updatedIndex, messageIndex: messageIndex)) {
hasUpdates = true hasUpdates = true
} }
default: case let .peers(peerIds, asPinned):
break if let peerIndex = peerIds.firstIndex(of: index.messageIndex.id.peerId) {
var updatedIndex = index
if asPinned {
updatedIndex = ChatListIndex(pinningIndex: UInt16(peerIndex), messageIndex: index.messageIndex)
}
if self.add(entry: .IntermediateMessageEntry(index: updatedIndex, messageIndex: messageIndex)) {
hasUpdates = true
}
} else {
continue inner
}
} }
case let .InsertHole(hole): case let .InsertHole(hole):
switch self.space { switch self.space {
case let .group(_, pinned) where !pinned.include: case let .group(spaceGroupId, pinned, _):
if self.add(entry: .HoleEntry(hole)) { if spaceGroupId == groupId && !pinned.include {
hasUpdates = true if self.add(entry: .HoleEntry(hole)) {
hasUpdates = true
}
} }
default: case .peers:
break break
} }
case let .RemoveEntry(indices): case let .RemoveEntry(indices):
for index in indices { switch self.space {
var updatedIndex = index case let .group(spaceGroupId, pinned, _):
if case .group(_, .includePinnedAsUnpinned) = self.space { if spaceGroupId == groupId {
updatedIndex = ChatListIndex(pinningIndex: nil, messageIndex: index.messageIndex) for index in indices {
var updatedIndex = index
if case .includePinnedAsUnpinned = pinned {
updatedIndex = ChatListIndex(pinningIndex: nil, messageIndex: index.messageIndex)
}
if self.orderedEntries.remove(index: MutableChatListEntryIndex(index: updatedIndex, isMessage: true)) {
hasUpdates = true
hadRemovals = true
}
}
} }
case let .peers(peerIds, asPinned):
if self.orderedEntries.remove(index: MutableChatListEntryIndex(index: updatedIndex, isMessage: true)) { for index in indices {
hasUpdates = true if let peerIndex = peerIds.firstIndex(of: index.messageIndex.id.peerId) {
hadRemovals = true var updatedIndex = index
if asPinned {
updatedIndex = ChatListIndex(pinningIndex: UInt16(peerIndex), messageIndex: index.messageIndex)
}
if self.orderedEntries.remove(index: MutableChatListEntryIndex(index: updatedIndex, isMessage: true)) {
hasUpdates = true
hadRemovals = true
}
}
} }
} }
case let .RemoveHoles(indices): case let .RemoveHoles(indices):
for index in indices { switch self.space {
if self.orderedEntries.remove(index: MutableChatListEntryIndex(index: index, isMessage: false)) { case let .group(spaceGroupId, pinned, _):
hasUpdates = true if spaceGroupId == groupId && !pinned.include {
hadRemovals = true for index in indices {
if self.orderedEntries.remove(index: MutableChatListEntryIndex(index: index, isMessage: false)) {
hasUpdates = true
hadRemovals = true
}
}
} }
case .peers:
break
} }
} }
} }
} }
if !transaction.currentUpdatedPeerNotificationSettings.isEmpty, let filterPredicate = self.filterPredicate, case let .group(groupId, pinned) = self.space { if !transaction.currentUpdatedPeerNotificationSettings.isEmpty, case let .group(groupId, pinned, maybeFilterPredicate) = self.space, let filterPredicate = maybeFilterPredicate {
var removeEntryIndices: [MutableChatListEntryIndex] = [] var removeEntryIndices: [MutableChatListEntryIndex] = []
let _ = self.orderedEntries.mutableScan { entry in let _ = self.orderedEntries.mutableScan { entry in
let entryPeer: Peer let entryPeer: Peer
@ -485,7 +622,7 @@ private final class ChatListViewSpaceState {
} }
} }
if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty, let filterPredicate = self.filterPredicate, let filterMessageTagSummary = filterPredicate.messageTagSummary, case let .group(groupId, pinned) = self.space { if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty, case let .group(groupId, pinned, maybeFilterPredicate) = self.space, let filterPredicate = maybeFilterPredicate, let filterMessageTagSummary = filterPredicate.messageTagSummary {
var removeEntryIndices: [MutableChatListEntryIndex] = [] var removeEntryIndices: [MutableChatListEntryIndex] = []
let _ = self.orderedEntries.mutableScan { entry in let _ = self.orderedEntries.mutableScan { entry in
let entryPeer: Peer let entryPeer: Peer
@ -954,19 +1091,17 @@ final class ChatListViewSample {
struct ChatListViewState { struct ChatListViewState {
private let anchorIndex: MutableChatListEntryIndex private let anchorIndex: MutableChatListEntryIndex
private let filterPredicate: ChatListFilterPredicate?
private let summaryComponents: ChatListEntrySummaryComponents private let summaryComponents: ChatListEntrySummaryComponents
private let halfLimit: Int private let halfLimit: Int
private var stateBySpace: [ChatListViewSpace: ChatListViewSpaceState] = [:] private var stateBySpace: [ChatListViewSpace: ChatListViewSpaceState] = [:]
init(postbox: Postbox, spaces: [ChatListViewSpace], anchorIndex: ChatListIndex, filterPredicate: ChatListFilterPredicate?, summaryComponents: ChatListEntrySummaryComponents, halfLimit: Int) { init(postbox: Postbox, spaces: [ChatListViewSpace], anchorIndex: ChatListIndex, summaryComponents: ChatListEntrySummaryComponents, halfLimit: Int) {
self.anchorIndex = MutableChatListEntryIndex(index: anchorIndex, isMessage: true) self.anchorIndex = MutableChatListEntryIndex(index: anchorIndex, isMessage: true)
self.filterPredicate = filterPredicate
self.summaryComponents = summaryComponents self.summaryComponents = summaryComponents
self.halfLimit = halfLimit self.halfLimit = halfLimit
for space in spaces { for space in spaces {
self.stateBySpace[space] = ChatListViewSpaceState(postbox: postbox, space: space, anchorIndex: self.anchorIndex, filterPredicate: self.filterPredicate, summaryComponents: summaryComponents, halfLimit: halfLimit) self.stateBySpace[space] = ChatListViewSpaceState(postbox: postbox, space: space, anchorIndex: self.anchorIndex, summaryComponents: summaryComponents, halfLimit: halfLimit)
} }
} }
@ -1215,8 +1350,10 @@ struct ChatListViewState {
return ChatListViewSample(entries: result.map { $0.1 }, lower: lower, upper: upper, anchorIndex: self.anchorIndex.index, hole: sampledHole.flatMap { space, hole in return ChatListViewSample(entries: result.map { $0.1 }, lower: lower, upper: upper, anchorIndex: self.anchorIndex.index, hole: sampledHole.flatMap { space, hole in
switch space { switch space {
case let .group(groupId, _): case let .group(groupId, _, _):
return (groupId, hole) return (groupId, hole)
case .peers:
return nil
} }
}) })
} }

View File

@ -234,22 +234,22 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
let timestamp = self.referenceTimestamp let timestamp = self.referenceTimestamp
let timestamp1 = timestamp + 120 let timestamp1 = timestamp + 120
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60) let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
let timestamp2 = timestamp + 3660 let timestamp2 = timestamp + 3660
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let timestamp3 = timestamp + 3200 let timestamp3 = timestamp + 3200
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let timestamp4 = timestamp + 3000 let timestamp4 = timestamp + 3000
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let timestamp5 = timestamp + 1000 let timestamp5 = timestamp + 1000
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer5), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer5), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let width: CGFloat let width: CGFloat
if case .regular = layout.metrics.widthClass { if case .regular = layout.metrics.widthClass {

View File

@ -785,17 +785,17 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
let timestamp = self.referenceTimestamp let timestamp = self.referenceTimestamp
let timestamp1 = timestamp + 120 let timestamp1 = timestamp + 120
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60) let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
let timestamp2 = timestamp + 3660 let timestamp2 = timestamp + 3660
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let timestamp3 = timestamp + 3200 let timestamp3 = timestamp + 3200
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let timestamp4 = timestamp + 3000 let timestamp4 = timestamp + 3000
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height) let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
if let chatNodes = self.chatNodes { if let chatNodes = self.chatNodes {

View File

@ -372,24 +372,24 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
let timestamp = self.referenceTimestamp let timestamp = self.referenceTimestamp
let timestamp1 = timestamp + 120 let timestamp1 = timestamp + 120
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60) let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
let timestamp2 = timestamp + 3660 let timestamp2 = timestamp + 3660
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let timestamp3 = timestamp + 3200 let timestamp3 = timestamp + 3200
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let timestamp4 = timestamp + 3000 let timestamp4 = timestamp + 3000
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let timestamp5 = timestamp + 1000 let timestamp5 = timestamp + 1000
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer5), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer5), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer7.id, namespace: 0, id: 0), timestamp: timestamp - 420)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer7.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 420, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer7), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer7.id, namespace: 0, id: 0), timestamp: timestamp - 420)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer7.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 420, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer7), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
let width: CGFloat let width: CGFloat
if case .regular = layout.metrics.widthClass { if case .regular = layout.metrics.widthClass {

View File

@ -605,7 +605,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1551583367] = { return Api.ReceivedNotifyMessage.parse_receivedNotifyMessage($0) } dict[-1551583367] = { return Api.ReceivedNotifyMessage.parse_receivedNotifyMessage($0) }
dict[-57668565] = { return Api.ChatParticipants.parse_chatParticipantsForbidden($0) } dict[-57668565] = { return Api.ChatParticipants.parse_chatParticipantsForbidden($0) }
dict[1061556205] = { return Api.ChatParticipants.parse_chatParticipants($0) } dict[1061556205] = { return Api.ChatParticipants.parse_chatParticipants($0) }
dict[1687327098] = { return Api.DialogFilter.parse_dialogFilter($0) } dict[-878553771] = { return Api.DialogFilter.parse_dialogFilter($0) }
dict[-1056001329] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsSaved($0) } dict[-1056001329] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsSaved($0) }
dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) } dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) }
dict[178373535] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsApplePay($0) } dict[178373535] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsApplePay($0) }

View File

@ -17276,18 +17276,23 @@ public extension Api {
} }
public enum DialogFilter: TypeConstructorDescription { public enum DialogFilter: TypeConstructorDescription {
case dialogFilter(flags: Int32, id: Int32, title: String, includePeers: [Api.InputPeer], excludePeers: [Api.InputPeer]) case dialogFilter(flags: Int32, id: Int32, title: String, pinnedPeers: [Api.InputPeer], includePeers: [Api.InputPeer], excludePeers: [Api.InputPeer])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .dialogFilter(let flags, let id, let title, let includePeers, let excludePeers): case .dialogFilter(let flags, let id, let title, let pinnedPeers, let includePeers, let excludePeers):
if boxed { if boxed {
buffer.appendInt32(1687327098) buffer.appendInt32(-878553771)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false)
serializeString(title, buffer: buffer, boxed: false) serializeString(title, buffer: buffer, boxed: false)
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
buffer.appendInt32(Int32(pinnedPeers.count))
for item in pinnedPeers {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(includePeers.count)) buffer.appendInt32(Int32(includePeers.count))
for item in includePeers { for item in includePeers {
item.serialize(buffer, true) item.serialize(buffer, true)
@ -17303,8 +17308,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .dialogFilter(let flags, let id, let title, let includePeers, let excludePeers): case .dialogFilter(let flags, let id, let title, let pinnedPeers, let includePeers, let excludePeers):
return ("dialogFilter", [("flags", flags), ("id", id), ("title", title), ("includePeers", includePeers), ("excludePeers", excludePeers)]) return ("dialogFilter", [("flags", flags), ("id", id), ("title", title), ("pinnedPeers", pinnedPeers), ("includePeers", includePeers), ("excludePeers", excludePeers)])
} }
} }
@ -17323,13 +17328,18 @@ public extension Api {
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputPeer.self) _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputPeer.self)
} }
var _6: [Api.InputPeer]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputPeer.self)
}
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
let _c4 = _4 != nil let _c4 = _4 != nil
let _c5 = _5 != nil let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 { let _c6 = _6 != nil
return Api.DialogFilter.dialogFilter(flags: _1!, id: _2!, title: _3!, includePeers: _4!, excludePeers: _5!) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.DialogFilter.dialogFilter(flags: _1!, id: _2!, title: _3!, pinnedPeers: _4!, includePeers: _5!, excludePeers: _6!)
} }
else { else {
return nil return nil

View File

@ -103,6 +103,7 @@ public struct ChatListFilterData: Equatable, Hashable {
public var excludeArchived: Bool public var excludeArchived: Bool
public var includePeers: [PeerId] public var includePeers: [PeerId]
public var excludePeers: [PeerId] public var excludePeers: [PeerId]
public var pinnedPeers: [PeerId]
public init( public init(
categories: ChatListFilterPeerCategories, categories: ChatListFilterPeerCategories,
@ -110,7 +111,8 @@ public struct ChatListFilterData: Equatable, Hashable {
excludeRead: Bool, excludeRead: Bool,
excludeArchived: Bool, excludeArchived: Bool,
includePeers: [PeerId], includePeers: [PeerId],
excludePeers: [PeerId] excludePeers: [PeerId],
pinnedPeers: [PeerId]
) { ) {
self.categories = categories self.categories = categories
self.excludeMuted = excludeMuted self.excludeMuted = excludeMuted
@ -118,6 +120,7 @@ public struct ChatListFilterData: Equatable, Hashable {
self.excludeArchived = excludeArchived self.excludeArchived = excludeArchived
self.includePeers = includePeers self.includePeers = includePeers
self.excludePeers = excludePeers self.excludePeers = excludePeers
self.pinnedPeers = pinnedPeers
} }
} }
@ -145,7 +148,8 @@ public struct ChatListFilter: PostboxCoding, Equatable {
excludeRead: decoder.decodeInt32ForKey("excludeRead", orElse: 0) != 0, excludeRead: decoder.decodeInt32ForKey("excludeRead", orElse: 0) != 0,
excludeArchived: decoder.decodeInt32ForKey("excludeArchived", orElse: 0) != 0, excludeArchived: decoder.decodeInt32ForKey("excludeArchived", orElse: 0) != 0,
includePeers: decoder.decodeInt64ArrayForKey("includePeers").map(PeerId.init), includePeers: decoder.decodeInt64ArrayForKey("includePeers").map(PeerId.init),
excludePeers: decoder.decodeInt64ArrayForKey("excludePeers").map(PeerId.init) excludePeers: decoder.decodeInt64ArrayForKey("excludePeers").map(PeerId.init),
pinnedPeers: decoder.decodeInt64ArrayForKey("pinnedPeers").map(PeerId.init)
) )
} }
@ -158,13 +162,14 @@ public struct ChatListFilter: PostboxCoding, Equatable {
encoder.encodeInt32(self.data.excludeArchived ? 1 : 0, forKey: "excludeArchived") encoder.encodeInt32(self.data.excludeArchived ? 1 : 0, forKey: "excludeArchived")
encoder.encodeInt64Array(self.data.includePeers.map { $0.toInt64() }, forKey: "includePeers") encoder.encodeInt64Array(self.data.includePeers.map { $0.toInt64() }, forKey: "includePeers")
encoder.encodeInt64Array(self.data.excludePeers.map { $0.toInt64() }, forKey: "excludePeers") encoder.encodeInt64Array(self.data.excludePeers.map { $0.toInt64() }, forKey: "excludePeers")
encoder.encodeInt64Array(self.data.pinnedPeers.map { $0.toInt64() }, forKey: "pinnedPeers")
} }
} }
extension ChatListFilter { extension ChatListFilter {
init(apiFilter: Api.DialogFilter) { init(apiFilter: Api.DialogFilter) {
switch apiFilter { switch apiFilter {
case let .dialogFilter(flags, id, title, includePeers, excludePeers): case let .dialogFilter(flags, id, title, pinnedPeers, includePeers, excludePeers):
self.init( self.init(
id: id, id: id,
title: title, title: title,
@ -196,6 +201,18 @@ extension ChatListFilter {
default: default:
return nil return nil
} }
},
pinnedPeers: pinnedPeers.compactMap { peer -> PeerId? in
switch peer {
case let .inputPeerUser(userId, _):
return PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
case let .inputPeerChat(chatId):
return PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)
case let .inputPeerChannel(channelId, _):
return PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
default:
return nil
}
} }
) )
) )
@ -214,7 +231,9 @@ extension ChatListFilter {
flags |= 1 << 13 flags |= 1 << 13
} }
flags |= self.data.categories.apiFlags flags |= self.data.categories.apiFlags
return .dialogFilter(flags: flags, id: self.id, title: self.title, includePeers: self.data.includePeers.compactMap { peerId -> Api.InputPeer? in return .dialogFilter(flags: flags, id: self.id, title: self.title, pinnedPeers: self.data.pinnedPeers.compactMap { peerId -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}, includePeers: self.data.includePeers.compactMap { peerId -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer) return transaction.getPeer(peerId).flatMap(apiInputPeer)
}, excludePeers: self.data.excludePeers.compactMap { peerId -> Api.InputPeer? in }, excludePeers: self.data.excludePeers.compactMap { peerId -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer) return transaction.getPeer(peerId).flatMap(apiInputPeer)
@ -278,27 +297,8 @@ private func requestChatListFilters(postbox: Postbox, network: Network) -> Signa
let filter = ChatListFilter(apiFilter: apiFilter) let filter = ChatListFilter(apiFilter: apiFilter)
filters.append(filter) filters.append(filter)
switch apiFilter { switch apiFilter {
case let .dialogFilter(_, _, _, includePeers, excludePeers): case let .dialogFilter(_, _, _, pinnedPeers, includePeers, excludePeers):
for peer in includePeers { for peer in pinnedPeers + includePeers + excludePeers {
var peerId: PeerId?
switch peer {
case let .inputPeerUser(userId, _):
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
case let .inputPeerChat(chatId):
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)
case let .inputPeerChannel(channelId, _):
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
default:
break
}
if let peerId = peerId {
if transaction.getPeer(peerId) == nil && !missingPeerIds.contains(peerId) {
missingPeerIds.insert(peerId)
missingPeers.append(peer)
}
}
}
for peer in excludePeers {
var peerId: PeerId? var peerId: PeerId?
switch peer { switch peer {
case let .inputPeerUser(userId, _): case let .inputPeerUser(userId, _):
@ -509,6 +509,23 @@ public func updateChatListFiltersInteractively(postbox: Postbox, _ f: @escaping
} }
} }
public func updateChatListFiltersInteractively(transaction: Transaction, _ f: ([ChatListFilter]) -> [ChatListFilter]) {
var hasUpdates = false
transaction.updatePreferencesEntry(key: PreferencesKeys.chatListFilters, { entry in
var state = entry as? ChatListFiltersState ?? ChatListFiltersState.default
let updatedFilters = f(state.filters)
if updatedFilters != state.filters {
state.filters = updatedFilters
hasUpdates = true
}
return state
})
if hasUpdates {
requestChatListFiltersSync(transaction: transaction)
}
}
public func updatedChatListFilters(postbox: Postbox) -> Signal<[ChatListFilter], NoError> { public func updatedChatListFilters(postbox: Postbox) -> Signal<[ChatListFilter], NoError> {
return postbox.preferencesView(keys: [PreferencesKeys.chatListFilters]) return postbox.preferencesView(keys: [PreferencesKeys.chatListFilters])
|> map { preferences -> [ChatListFilter] in |> map { preferences -> [ChatListFilter] in
@ -577,7 +594,8 @@ public struct ChatListFeaturedFilter: PostboxCoding, Equatable {
excludeRead: decoder.decodeInt32ForKey("excludeRead", orElse: 0) != 0, excludeRead: decoder.decodeInt32ForKey("excludeRead", orElse: 0) != 0,
excludeArchived: decoder.decodeInt32ForKey("excludeArchived", orElse: 0) != 0, excludeArchived: decoder.decodeInt32ForKey("excludeArchived", orElse: 0) != 0,
includePeers: decoder.decodeInt64ArrayForKey("includePeers").map(PeerId.init), includePeers: decoder.decodeInt64ArrayForKey("includePeers").map(PeerId.init),
excludePeers: decoder.decodeInt64ArrayForKey("excludePeers").map(PeerId.init) excludePeers: decoder.decodeInt64ArrayForKey("excludePeers").map(PeerId.init),
pinnedPeers: decoder.decodeInt64ArrayForKey("pinnedPeers").map(PeerId.init)
) )
} }
@ -590,6 +608,7 @@ public struct ChatListFeaturedFilter: PostboxCoding, Equatable {
encoder.encodeInt32(self.data.excludeArchived ? 1 : 0, forKey: "excludeArchived") encoder.encodeInt32(self.data.excludeArchived ? 1 : 0, forKey: "excludeArchived")
encoder.encodeInt64Array(self.data.includePeers.map { $0.toInt64() }, forKey: "includePeers") encoder.encodeInt64Array(self.data.includePeers.map { $0.toInt64() }, forKey: "includePeers")
encoder.encodeInt64Array(self.data.excludePeers.map { $0.toInt64() }, forKey: "excludePeers") encoder.encodeInt64Array(self.data.excludePeers.map { $0.toInt64() }, forKey: "excludePeers")
encoder.encodeInt64Array(self.data.pinnedPeers.map { $0.toInt64() }, forKey: "pinnedPeers")
} }
} }
@ -668,8 +687,6 @@ public func updateChatListFeaturedFilters(postbox: Postbox, network: Network) ->
} }
private enum SynchronizeChatListFiltersOperationContentType: Int32 { private enum SynchronizeChatListFiltersOperationContentType: Int32 {
case add
case remove
case sync case sync
} }
@ -681,7 +698,7 @@ private enum SynchronizeChatListFiltersOperationContent: PostboxCoding {
case SynchronizeChatListFiltersOperationContentType.sync.rawValue: case SynchronizeChatListFiltersOperationContentType.sync.rawValue:
self = .sync self = .sync
default: default:
assertionFailure() //assertionFailure()
self = .sync self = .sync
} }
} }

View File

@ -4,62 +4,132 @@ import SwiftSignalKit
import SyncCore import SyncCore
public enum TogglePeerChatPinnedLocation {
case group(PeerGroupId)
case filter(Int32)
}
public enum TogglePeerChatPinnedResult { public enum TogglePeerChatPinnedResult {
case done case done
case limitExceeded(Int) case limitExceeded(Int)
} }
public func toggleItemPinned(postbox: Postbox, groupId: PeerGroupId, itemId: PinnedItemId) -> Signal<TogglePeerChatPinnedResult, NoError> { public func toggleItemPinned(postbox: Postbox, location: TogglePeerChatPinnedLocation, itemId: PinnedItemId) -> Signal<TogglePeerChatPinnedResult, NoError> {
return postbox.transaction { transaction -> TogglePeerChatPinnedResult in return postbox.transaction { transaction -> TogglePeerChatPinnedResult in
var itemIds = transaction.getPinnedItemIds(groupId: groupId) switch location {
let sameKind = itemIds.filter { item in case let .group(groupId):
switch itemId { var itemIds = transaction.getPinnedItemIds(groupId: groupId)
case let .peer(lhsPeerId): let sameKind = itemIds.filter { item in
if case let .peer(rhsPeerId) = item { switch itemId {
return (lhsPeerId.namespace == Namespaces.Peer.SecretChat) == (rhsPeerId.namespace == Namespaces.Peer.SecretChat) && lhsPeerId != rhsPeerId case let .peer(lhsPeerId):
} else { if case let .peer(rhsPeerId) = item {
return false return (lhsPeerId.namespace == Namespaces.Peer.SecretChat) == (rhsPeerId.namespace == Namespaces.Peer.SecretChat) && lhsPeerId != rhsPeerId
} } else {
return false
}
}
} }
} let additionalCount: Int
if let _ = itemIds.firstIndex(of: itemId) {
let additionalCount: Int additionalCount = -1
if let _ = itemIds.firstIndex(of: itemId) {
additionalCount = -1
} else {
additionalCount = 1
}
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue
let limitCount: Int
if case .root = groupId {
limitCount = Int(limitsConfiguration.maxPinnedChatCount)
} else {
limitCount = Int(limitsConfiguration.maxArchivedPinnedChatCount)
}
if sameKind.count + additionalCount > limitCount {
return .limitExceeded(limitCount)
} else {
if let index = itemIds.firstIndex(of: itemId) {
itemIds.remove(at: index)
} else { } else {
itemIds.insert(itemId, at: 0) additionalCount = 1
} }
addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId)
transaction.setPinnedItemIds(groupId: groupId, itemIds: itemIds) let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue
return .done let limitCount: Int
if case .root = groupId {
limitCount = Int(limitsConfiguration.maxPinnedChatCount)
} else {
limitCount = Int(limitsConfiguration.maxArchivedPinnedChatCount)
}
if sameKind.count + additionalCount > limitCount {
return .limitExceeded(limitCount)
} else {
if let index = itemIds.firstIndex(of: itemId) {
itemIds.remove(at: index)
} else {
itemIds.insert(itemId, at: 0)
}
addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId)
transaction.setPinnedItemIds(groupId: groupId, itemIds: itemIds)
return .done
}
case let .filter(filterId):
var result: TogglePeerChatPinnedResult = .done
updateChatListFiltersInteractively(transaction: transaction, { filters in
var filters = filters
if let index = filters.firstIndex(where: { $0.id == filterId }) {
switch itemId {
case let .peer(peerId):
if filters[index].data.pinnedPeers.contains(peerId) {
filters[index].data.pinnedPeers.removeAll(where: { $0 == peerId })
} else {
if filters[index].data.pinnedPeers.count < 100 {
filters[index].data.pinnedPeers.insert(peerId, at: 0)
} else {
result = .limitExceeded(100)
}
}
}
}
return filters
})
return result
} }
} }
} }
public func reorderPinnedItemIds(transaction: Transaction, groupId: PeerGroupId, itemIds: [PinnedItemId]) -> Bool { public func getPinnedItemIds(transaction: Transaction, location: TogglePeerChatPinnedLocation) -> [PinnedItemId] {
if transaction.getPinnedItemIds(groupId: groupId) != itemIds { switch location {
transaction.setPinnedItemIds(groupId: groupId, itemIds: itemIds) case let .group(groupId):
addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) return transaction.getPinnedItemIds(groupId: groupId)
return true case let .filter(filterId):
} else { var itemIds: [PinnedItemId] = []
return false let _ = updateChatListFiltersInteractively(transaction: transaction, { filters in
if let index = filters.firstIndex(where: { $0.id == filterId }) {
itemIds = filters[index].data.pinnedPeers.map { peerId in
return .peer(peerId)
}
}
return filters
})
return itemIds
}
}
public func reorderPinnedItemIds(transaction: Transaction, location: TogglePeerChatPinnedLocation, itemIds: [PinnedItemId]) -> Bool {
switch location {
case let .group(groupId):
if transaction.getPinnedItemIds(groupId: groupId) != itemIds {
transaction.setPinnedItemIds(groupId: groupId, itemIds: itemIds)
addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId)
return true
} else {
return false
}
case let .filter(filterId):
var result: Bool = false
updateChatListFiltersInteractively(transaction: transaction, { filters in
var filters = filters
if let index = filters.firstIndex(where: { $0.id == filterId }) {
let peerIds: [PeerId] = itemIds.map { itemId -> PeerId in
switch itemId {
case let .peer(peerId):
return peerId
}
}
if filters[index].data.pinnedPeers != peerIds {
filters[index].data.pinnedPeers = peerIds
result = true
}
}
return filters
})
return result
} }
} }

View File

@ -78,7 +78,7 @@ private enum ChatListSearchEntry: Comparable, Identifiable {
public func item(context: AccountContext, interaction: ChatListNodeInteraction) -> ListViewItem { public func item(context: AccountContext, interaction: ChatListNodeInteraction) -> ListViewItem {
switch self { switch self {
case let .message(message, peer, readState, presentationData): case let .message(message, peer, readState, presentationData):
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: true, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: true, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
} }
} }
} }

View File

@ -510,7 +510,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
super.didLoad() super.didLoad()
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), allowedDirections: { [weak self] _ in let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), allowedDirections: { [weak self] _ in
guard let strongSelf = self, let currentPaneKey = strongSelf.currentPaneKey, let availablePanes = strongSelf.currentParams?.data?.availablePanes, let index = availablePanes.index(of: currentPaneKey) else { guard let strongSelf = self, let currentPaneKey = strongSelf.currentPaneKey, let availablePanes = strongSelf.currentParams?.data?.availablePanes, let index = availablePanes.firstIndex(of: currentPaneKey) else {
return [] return []
} }
if index == 0 { if index == 0 {