[WIP] Topic APIs

This commit is contained in:
Ali
2022-09-28 12:15:06 +02:00
parent d7d3b1b9cb
commit d01a7853fa
60 changed files with 4264 additions and 1861 deletions

View File

@@ -56,12 +56,12 @@ public final class ChatListNodeInteraction {
}
let activateSearch: () -> Void
let peerSelected: (EnginePeer, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void
let peerSelected: (EnginePeer, Int64?, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void
let disabledPeerSelected: (EnginePeer) -> Void
let togglePeerSelected: (EnginePeer) -> Void
let togglePeersSelection: ([PeerEntry], Bool) -> Void
let additionalCategorySelected: (Int) -> Void
let messageSelected: (EnginePeer, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void
let messageSelected: (EnginePeer, Int64?, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void
let groupSelected: (EngineChatList.Group) -> Void
let addContact: (String) -> Void
let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void
@@ -86,12 +86,12 @@ public final class ChatListNodeInteraction {
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
activateSearch: @escaping () -> Void,
peerSelected: @escaping (EnginePeer, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void,
peerSelected: @escaping (EnginePeer, Int64?, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void,
disabledPeerSelected: @escaping (EnginePeer) -> Void,
togglePeerSelected: @escaping (EnginePeer) -> Void,
togglePeersSelection: @escaping ([PeerEntry], Bool) -> Void,
additionalCategorySelected: @escaping (Int) -> Void,
messageSelected: @escaping (EnginePeer, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void,
messageSelected: @escaping (EnginePeer, Int64?, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void,
groupSelected: @escaping (EngineChatList.Group) -> Void,
addContact: @escaping (String) -> Void,
setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void,
@@ -219,7 +219,7 @@ public struct ChatListNodeState: Equatable {
}
}
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
return entries.map { entry -> ListViewInsertItem in
switch entry.entry {
case .HeaderEntry:
@@ -242,18 +242,19 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
nodeInteraction.additionalCategorySelected(id)
}
), directionHint: entry.directionHint)
case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, presence, hasUnseenMentions, hasUnseenReactions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact):
case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, threadInfo, presence, hasUnseenMentions, hasUnseenReactions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact):
switch mode {
case .chatList:
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
presentationData: presentationData,
context: context,
peerGroupId: peerGroupId,
chatListLocation: location,
filterData: filterData,
index: index,
content: .peer(
messages: messages,
peer: peer,
threadInfo: threadInfo,
combinedReadState: combinedReadState,
isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount,
presence: presence,
@@ -386,7 +387,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
if editing {
nodeInteraction.togglePeerSelected(chatPeer)
} else {
nodeInteraction.peerSelected(chatPeer, nil, nil)
nodeInteraction.peerSelected(chatPeer, nil, nil, nil)
}
}
}, disabledAction: { _ in
@@ -404,7 +405,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
presentationData: presentationData,
context: context,
peerGroupId: peerGroupId,
chatListLocation: location,
filterData: filterData,
index: index,
content: .groupReference(
@@ -428,21 +429,22 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
}
}
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
return entries.map { entry -> ListViewUpdateItem in
switch entry.entry {
case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, presence, hasUnseenMentions, hasUnseenReactions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact):
case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, threadInfo, presence, hasUnseenMentions, hasUnseenReactions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact):
switch mode {
case .chatList:
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
presentationData: presentationData,
context: context,
peerGroupId: peerGroupId,
chatListLocation: location,
filterData: filterData,
index: index,
content: .peer(
messages: messages,
peer: peer,
threadInfo: threadInfo,
combinedReadState: combinedReadState,
isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount,
presence: presence,
@@ -528,7 +530,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
if editing {
nodeInteraction.togglePeerSelected(chatPeer)
} else {
nodeInteraction.peerSelected(chatPeer, nil, nil)
nodeInteraction.peerSelected(chatPeer, nil, nil, nil)
}
}
}, disabledAction: { _ in
@@ -546,7 +548,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
presentationData: presentationData,
context: context,
peerGroupId: peerGroupId,
chatListLocation: location,
filterData: filterData,
index: index,
content: .groupReference(
@@ -590,8 +592,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
}
}
private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
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 func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, location: location, filterData: filterData, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, location: location, 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 {
@@ -627,7 +629,7 @@ public enum ChatListNodeEmptyState: Equatable {
public final class ChatListNode: ListView {
private let fillPreloadItems: Bool
private let context: AccountContext
private let groupId: EngineChatList.Group
private let location: ChatListControllerLocation
private let mode: ChatListNodeMode
private let animationCache: AnimationCache
private let animationRenderer: MultiAnimationRenderer
@@ -644,7 +646,7 @@ public final class ChatListNode: ListView {
return _contentsReady.get()
}
public var peerSelected: ((EnginePeer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
public var peerSelected: ((EnginePeer, Int64?, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
public var disabledPeerSelected: ((EnginePeer) -> Void)?
public var additionalCategorySelected: ((Int) -> Void)?
public var groupSelected: ((EngineChatList.Group) -> Void)?
@@ -745,9 +747,9 @@ public final class ChatListNode: ListView {
public var selectionLimit: Int32 = 100
public var reachedSelectionLimit: ((Int32) -> Void)?
public init(context: AccountContext, groupId: EngineChatList.Group, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, disableAnimations: Bool) {
public init(context: AccountContext, location: ChatListControllerLocation, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, disableAnimations: Bool) {
self.context = context
self.groupId = groupId
self.location = location
self.chatListFilter = chatListFilter
self.chatListFilterValue.set(.single(chatListFilter))
self.fillPreloadItems = fillPreloadItems
@@ -776,9 +778,9 @@ public final class ChatListNode: ListView {
if let strongSelf = self, let activateSearch = strongSelf.activateSearch {
activateSearch()
}
}, peerSelected: { [weak self] peer, _, promoInfo in
}, peerSelected: { [weak self] peer, threadId, _, promoInfo in
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
peerSelected(peer, true, true, promoInfo)
peerSelected(peer, threadId, true, true, promoInfo)
}
}, disabledPeerSelected: { [weak self] peer in
if let strongSelf = self, let disabledPeerSelected = strongSelf.disabledPeerSelected {
@@ -842,7 +844,7 @@ public final class ChatListNode: ListView {
}
}, additionalCategorySelected: { [weak self] id in
self?.additionalCategorySelected?(id)
}, messageSelected: { [weak self] peer, message, promoInfo in
}, messageSelected: { [weak self] peer, threadId, message, promoInfo in
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
var activateInput = false
for media in message.media {
@@ -855,7 +857,7 @@ public final class ChatListNode: ListView {
}
}
}
peerSelected(peer, true, activateInput, promoInfo)
peerSelected(peer, threadId, true, activateInput, promoInfo)
}
}, groupSelected: { [weak self] groupId in
if let strongSelf = self, let groupSelected = strongSelf.groupSelected {
@@ -876,7 +878,14 @@ public final class ChatListNode: ListView {
}
}, setItemPinned: { [weak self] itemId, _ in
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|> deliverOnMainQueue).start(next: { [weak self] peer in
|> deliverOnMainQueue).start(next: { peer in
guard let strongSelf = self else {
return
}
guard case let .chatList(groupId) = strongSelf.location else {
return
}
let isPremium = peer?.isPremium ?? false
let location: TogglePeerChatPinnedLocation
if let chatListFilter = chatListFilter {
@@ -979,10 +988,10 @@ public final class ChatListNode: ListView {
let chatListViewUpdate = self.chatListLocation.get()
|> distinctUntilChanged
|> mapToSignal { location -> Signal<(ChatListNodeViewUpdate, ChatListFilter?), NoError> in
return chatListViewForLocation(groupId: groupId._asGroup(), location: location, account: context.account)
|> mapToSignal { listLocation -> Signal<(ChatListNodeViewUpdate, ChatListFilter?), NoError> in
return chatListViewForLocation(chatListLocation: location, location: listLocation, account: context.account)
|> map { update in
return (update, location.filter)
return (update, listLocation.filter)
}
}
@@ -1010,7 +1019,7 @@ public final class ChatListNode: ListView {
|> distinctUntilChanged
let displayArchiveIntro: Signal<Bool, NoError>
if case .archive = groupId {
if case .chatList(.archive) = location {
displayArchiveIntro = context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.archiveIntroDismissedKey())
|> map { entry -> Bool in
if let value = entry.value?.get(ApplicationSpecificVariantNotice.self) {
@@ -1041,123 +1050,123 @@ public final class ChatListNode: ListView {
let previousHideArchivedFolderByDefaultValue = previousHideArchivedFolderByDefault.swap(hideArchivedFolderByDefault)
let (rawEntries, isLoading) = chatListNodeEntriesForView(EngineChatList(update.view), state: state, savedMessagesPeer: savedMessagesPeer, foundPeers: state.foundPeers, hideArchivedFolderByDefault: hideArchivedFolderByDefault, displayArchiveIntro: displayArchiveIntro, mode: mode)
let (rawEntries, isLoading) = chatListNodeEntriesForView(update.list, state: state, savedMessagesPeer: savedMessagesPeer, foundPeers: state.foundPeers, hideArchivedFolderByDefault: hideArchivedFolderByDefault, displayArchiveIntro: displayArchiveIntro, mode: mode)
let entries = rawEntries.filter { entry in
switch entry {
case let .PeerEntry(_, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _):
case let .PeerEntry(_, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _):
switch mode {
case .chatList:
return true
case let .peers(filter, _, _, _):
guard !filter.contains(.excludeSavedMessages) || peer.peerId != currentPeerId else { return false }
guard !filter.contains(.excludeSavedMessages) || !peer.peerId.isReplies else { return false }
guard !filter.contains(.excludeSecretChats) || peer.peerId.namespace != Namespaces.Peer.SecretChat else { return false }
guard !filter.contains(.onlyPrivateChats) || peer.peerId.namespace == Namespaces.Peer.CloudUser else { return false }
case .chatList:
return true
case let .peers(filter, _, _, _):
guard !filter.contains(.excludeSavedMessages) || peer.peerId != currentPeerId else { return false }
guard !filter.contains(.excludeSavedMessages) || !peer.peerId.isReplies else { return false }
guard !filter.contains(.excludeSecretChats) || peer.peerId.namespace != Namespaces.Peer.SecretChat else { return false }
guard !filter.contains(.onlyPrivateChats) || peer.peerId.namespace == Namespaces.Peer.CloudUser else { return false }
if let peer = peer.peer {
switch peer {
case let .user(user):
if user.botInfo != nil {
if filter.contains(.excludeBots) {
return false
}
} else {
if filter.contains(.excludeUsers) {
return false
}
}
case .legacyGroup:
if filter.contains(.excludeGroups) {
return false
}
case let .channel(channel):
switch channel.info {
case .broadcast:
if filter.contains(.excludeChannels) {
return false
}
case .group:
if filter.contains(.excludeGroups) {
return false
}
}
default:
break
if let peer = peer.peer {
switch peer {
case let .user(user):
if user.botInfo != nil {
if filter.contains(.excludeBots) {
return false
}
} else {
if filter.contains(.excludeUsers) {
return false
}
}
case .legacyGroup:
if filter.contains(.excludeGroups) {
return false
}
case let .channel(channel):
switch channel.info {
case .broadcast:
if filter.contains(.excludeChannels) {
return false
}
case .group:
if filter.contains(.excludeGroups) {
return false
}
}
default:
break
}
}
if filter.contains(.onlyGroupsAndChannels) {
if case .channel = peer.chatMainPeer {
} else if case .legacyGroup = peer.chatMainPeer {
} else {
return false
}
} else {
if filter.contains(.onlyGroups) {
var isGroup: Bool = false
if case let .channel(peer) = peer.chatMainPeer, case .group = peer.info {
isGroup = true
} else if peer.peerId.namespace == Namespaces.Peer.CloudGroup {
isGroup = true
}
if !isGroup {
return false
}
}
if filter.contains(.onlyGroupsAndChannels) {
if case .channel = peer.chatMainPeer {
} else if case .legacyGroup = peer.chatMainPeer {
if filter.contains(.onlyChannels) {
if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info {
} else {
return false
}
}
}
if filter.contains(.excludeChannels) {
if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info {
}
}
if filter.contains(.onlyWriteable) && filter.contains(.excludeDisabled) {
if let peer = peer.peers[peer.peerId] {
if !canSendMessagesToPeer(peer._asPeer()) {
return false
}
} else {
return false
}
}
if filter.contains(.onlyManageable) && filter.contains(.excludeDisabled) {
if let peer = peer.peers[peer.peerId] {
var canManage = false
if case let .legacyGroup(peer) = peer {
switch peer.role {
case .creator, .admin:
canManage = true
default:
break
}
}
if canManage {
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
} else {
return false
}
} else {
if filter.contains(.onlyGroups) {
var isGroup: Bool = false
if case let .channel(peer) = peer.chatMainPeer, case .group = peer.info {
isGroup = true
} else if peer.peerId.namespace == Namespaces.Peer.CloudGroup {
isGroup = true
}
if !isGroup {
return false
}
}
if filter.contains(.onlyChannels) {
if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info {
} else {
return false
}
}
return false
}
if filter.contains(.excludeChannels) {
if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info {
}
}
if filter.contains(.onlyWriteable) && filter.contains(.excludeDisabled) {
if let peer = peer.peers[peer.peerId] {
if !canSendMessagesToPeer(peer._asPeer()) {
return false
}
} else {
return false
}
}
if filter.contains(.onlyManageable) && filter.contains(.excludeDisabled) {
if let peer = peer.peers[peer.peerId] {
var canManage = false
if case let .legacyGroup(peer) = peer {
switch peer.role {
case .creator, .admin:
canManage = true
default:
break
}
}
if canManage {
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
} else {
return false
}
} else {
return false
}
}
return true
}
default:
return true
}
default:
return true
}
}
let processedView = ChatListNodeView(originalView: update.view, filteredEntries: entries, isLoading: isLoading, filter: filter)
let processedView = ChatListNodeView(originalList: update.list, filteredEntries: entries, isLoading: isLoading, filter: filter)
let previousView = previousView.swap(processedView)
let previousState = previousState.swap(state)
@@ -1185,7 +1194,7 @@ public final class ChatListNode: ListView {
prepareOnMainQueue = true
}
} else {
if previousView?.originalView === update.view {
if previousView?.originalList === update.list {
reason = .interactiveChanges
updatedScrollPosition = nil
} else {
@@ -1216,12 +1225,14 @@ public final class ChatListNode: ListView {
var didIncludeHiddenByDefaultArchive = false
if let previous = previousView {
for entry in previous.filteredEntries {
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
if index.pinningIndex != nil {
previousPinnedChats.append(index.messageIndex.id.peerId)
}
if index.messageIndex.id.peerId == removingPeerId {
didIncludeRemovingPeerId = true
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
if case let .chatList(chatListIndex) = index {
if chatListIndex.pinningIndex != nil {
previousPinnedChats.append(chatListIndex.messageIndex.id.peerId)
}
if chatListIndex.messageIndex.id.peerId == removingPeerId {
didIncludeRemovingPeerId = true
}
}
} else if case let .GroupReferenceEntry(_, _, _, _, _, _, _, _, hiddenByDefault) = entry {
didIncludeHiddenByDefaultArchive = hiddenByDefault
@@ -1232,11 +1243,11 @@ public final class ChatListNode: ListView {
var doesIncludeArchive = false
var doesIncludeHiddenByDefaultArchive = false
for entry in processedView.filteredEntries {
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
if index.pinningIndex != nil {
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
if case let .chatList(index) = index, index.pinningIndex != nil {
updatedPinnedChats.append(index.messageIndex.id.peerId)
}
if index.messageIndex.id.peerId == removingPeerId {
if case let .chatList(index) = index, index.messageIndex.id.peerId == removingPeerId {
doesIncludeRemovingPeerId = true
}
} else if case let .GroupReferenceEntry(_, _, _, _, _, _, _, _, hiddenByDefault) = entry {
@@ -1287,7 +1298,7 @@ public final class ChatListNode: ListView {
}
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, filterData: filterData, mode: mode, transition: $0) })
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, location: location, filterData: filterData, mode: mode, transition: $0) })
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
}
@@ -1300,13 +1311,13 @@ public final class ChatListNode: ListView {
self.displayedItemRangeChanged = { [weak self] range, transactionOpaqueState in
if let strongSelf = self, let chatListView = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView {
let originalView = chatListView.originalView
let originalList = chatListView.originalList
if let range = range.loadedRange {
var location: ChatListNodeLocation?
if range.firstIndex < 5, let laterIndex = originalView.laterIndex {
location = .navigation(index: laterIndex, filter: strongSelf.chatListFilter)
} else if range.firstIndex >= 5, range.lastIndex >= originalView.entries.count - 5, let earlierIndex = originalView.earlierIndex {
location = .navigation(index: earlierIndex, filter: strongSelf.chatListFilter)
if range.firstIndex < 5, let lastItem = originalList.items.last, originalList.hasLater {
location = .navigation(index: lastItem.index, filter: strongSelf.chatListFilter)
} else if range.firstIndex >= 5, range.lastIndex >= originalList.items.count - 5, originalList.hasEarlier, let firstItem = originalList.items.first {
location = .navigation(index: firstItem.index, filter: strongSelf.chatListFilter)
}
if let location = location, location != strongSelf.currentLocation {
@@ -1485,6 +1496,10 @@ public final class ChatListNode: ListView {
self.reorderItem = { [weak self] fromIndex, toIndex, transactionOpaqueState -> Signal<Bool, NoError> in
if let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries {
guard case let .chatList(groupId) = strongSelf.location else {
return .single(false)
}
if fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count {
let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex]
let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex]
@@ -1492,17 +1507,19 @@ public final class ChatListNode: ListView {
var referenceId: EngineChatList.PinnedItem.Id?
var beforeAll = false
switch toEntry {
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _):
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _):
if promoInfo != nil {
beforeAll = true
} else {
referenceId = .peer(index.messageIndex.id.peerId)
if case let .chatList(chatListIndex) = index {
referenceId = .peer(chatListIndex.messageIndex.id.peerId)
}
}
default:
break
}
if case let .index(index) = fromEntry.sortIndex, let _ = index.pinningIndex {
if case let .index(index) = fromEntry.sortIndex, case let .chatList(chatListIndex) = index, let _ = chatListIndex.pinningIndex {
let location: TogglePeerChatPinnedLocation
if let chatListFilter = chatListFilter {
location = .filter(chatListFilter.id)
@@ -1517,8 +1534,10 @@ public final class ChatListNode: ListView {
var itemId: EngineChatList.PinnedItem.Id?
switch fromEntry {
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
itemId = .peer(index.messageIndex.id.peerId)
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
if case let .chatList(index) = index {
itemId = .peer(index.messageIndex.id.peerId)
}
default:
break
}
@@ -1763,16 +1782,18 @@ public final class ChatListNode: ListView {
if strongSelf.fillPreloadItems {
let filteredEntries = transition.chatListView.filteredEntries
var preloadItems: [ChatHistoryPreloadItem] = []
if transition.chatListView.originalView.laterIndex == nil {
if !transition.chatListView.originalList.hasLater {
for entry in filteredEntries.reversed() {
switch entry {
case let .PeerEntry(index, _, _, combinedReadState, isMuted, _, _, _, _, _, _, _, _, _, promoInfo, _, _):
case let .PeerEntry(index, _, _, combinedReadState, isMuted, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _):
if promoInfo == nil {
var hasUnread = false
if let combinedReadState = combinedReadState {
hasUnread = combinedReadState.count > 0
}
preloadItems.append(ChatHistoryPreloadItem(index: index, isMuted: isMuted, hasUnread: hasUnread))
if case let .chatList(index) = index {
preloadItems.append(ChatHistoryPreloadItem(index: index, isMuted: isMuted, hasUnread: hasUnread))
}
}
default:
break
@@ -1789,7 +1810,7 @@ public final class ChatListNode: ListView {
if case .chatList = strongSelf.mode {
let entryCount = transition.chatListView.filteredEntries.count
if entryCount >= 1 {
if case let .index(index) = transition.chatListView.filteredEntries[entryCount - 1].sortIndex, index.pinningIndex != nil {
if case let .index(index) = transition.chatListView.filteredEntries[entryCount - 1].sortIndex, case let .chatList(chatListIndex) = index, chatListIndex.pinningIndex != nil {
pinnedOverscroll = true
}
}
@@ -1887,10 +1908,10 @@ public final class ChatListNode: ListView {
for item in transition.insertItems {
if let item = item.item as? ChatListItem {
switch item.content {
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _):
insertedPeerIds.append(peer.peerId)
case .groupReference:
break
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _):
insertedPeerIds.append(peer.peerId)
case .groupReference:
break
}
}
}
@@ -2002,16 +2023,15 @@ public final class ChatListNode: ListView {
}
public func scrollToPosition(_ position: ChatListNodeScrollPosition) {
if let view = self.chatListView?.originalView {
if view.laterIndex == nil {
if let list = self.chatListView?.originalList {
if !list.hasLater {
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
} else {
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound, scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
let location: ChatListNodeLocation = .scroll(index: .chatList(.absoluteUpperBound), sourceIndex: .chatList(.absoluteLowerBound), scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
self.setChatListLocation(location)
}
} else {
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound
, scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
let location: ChatListNodeLocation = .scroll(index: .chatList(.absoluteUpperBound), sourceIndex: .chatList(.absoluteLowerBound), scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
self.setChatListLocation(location)
}
}
@@ -2022,7 +2042,10 @@ public final class ChatListNode: ListView {
}
private func relativeUnreadChatListIndex(position: EngineChatList.RelativePosition) -> Signal<EngineChatList.Item.Index?, NoError> {
let groupId = self.groupId
guard case let .chatList(groupId) = self.location else {
return .single(nil)
}
let engine = self.context.engine
return self.context.sharedContext.accountManager.transaction { transaction -> Signal<EngineChatList.Item.Index?, NoError> in
var filter = true
@@ -2061,7 +2084,7 @@ public final class ChatListNode: ListView {
continue
}
switch chatListView.filteredEntries[entryCount - i - 1] {
case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _):
case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _):
if interaction.highlightedChatLocation?.location == ChatLocation.peer(id: peer.peerId) {
current = (index, peer.peer!, entryCount - i - 1)
break outer
@@ -2086,11 +2109,11 @@ public final class ChatListNode: ListView {
let engine = self.context.engine
let _ = (relativeUnreadChatListIndex(position: position)
|> mapToSignal { index -> Signal<(EngineChatList.Item.Index, EnginePeer)?, NoError> in
if let index = index {
if case let .chatList(index) = index {
return engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: index.messageIndex.id.peerId))
|> map { peer -> (EngineChatList.Item.Index, EnginePeer)? in
return peer.flatMap { peer -> (EngineChatList.Item.Index, EnginePeer)? in
(index, peer)
(.chatList(index), peer)
}
}
} else {
@@ -2101,17 +2124,17 @@ public final class ChatListNode: ListView {
guard let strongSelf = self, let (index, peer) = indexAndPeer else {
return
}
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: strongSelf.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound, scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: strongSelf.currentlyVisibleLatestChatListIndex() ?? .chatList(.absoluteLowerBound), scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
strongSelf.setChatListLocation(location)
strongSelf.peerSelected?(peer, false, false, nil)
strongSelf.peerSelected?(peer, nil, false, false, nil)
})
case .previous(unread: false), .next(unread: false):
var target: (EngineChatList.Item.Index, EnginePeer)? = nil
if let current = current, entryCount > 1 {
if current.2 > 0, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 - 1] {
if current.2 > 0, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 - 1] {
next = (index, peer.peer!)
}
if current.2 <= entryCount - 2, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 + 1] {
if current.2 <= entryCount - 2, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 + 1] {
previous = (index, peer.peer!)
}
if case .previous = option {
@@ -2120,14 +2143,14 @@ public final class ChatListNode: ListView {
target = next
}
} else if entryCount > 0 {
if case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[entryCount - 1] {
if case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[entryCount - 1] {
target = (index, peer.peer!)
}
}
if let target = target {
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: self.chatListFilter)
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .chatList(.absoluteLowerBound), scrollPosition: .center(.top), animated: true, filter: self.chatListFilter)
self.setChatListLocation(location)
self.peerSelected?(target.1, false, false, nil)
self.peerSelected?(target.1, nil, false, false, nil)
}
case let .peerId(peerId):
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
@@ -2135,7 +2158,7 @@ public final class ChatListNode: ListView {
guard let strongSelf = self, let peer = peer else {
return
}
strongSelf.peerSelected?(peer, false, false, nil)
strongSelf.peerSelected?(peer, nil, false, false, nil)
})
case let .index(index):
guard index < 10 else {
@@ -2147,14 +2170,18 @@ public final class ChatListNode: ListView {
guard let self = self else {
return
}
let _ = (chatListViewForLocation(groupId: self.groupId._asGroup(), location: .initial(count: 10, filter: filter), account: self.context.account)
guard case let .chatList(groupId) = self.location else {
return
}
let _ = (chatListViewForLocation(chatListLocation: .chatList(groupId: groupId), location: .initial(count: 10, filter: filter), account: self.context.account)
|> take(1)
|> deliverOnMainQueue).start(next: { update in
let entries = update.view.entries
if entries.count > index, case let .MessageEntry(index, _, _, _, _, renderedPeer, _, _, _, _) = entries[9 - index - 1] {
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: filter)
let items = update.list.items
if items.count > index {
let item = items[9 - index - 1]
let location: ChatListNodeLocation = .scroll(index: item.index, sourceIndex: .chatList(.absoluteLowerBound), scrollPosition: .center(.top), animated: true, filter: filter)
self.setChatListLocation(location)
self.peerSelected?(EnginePeer(renderedPeer.peer!), false, false, nil)
self.peerSelected?(EnginePeer(item.renderedPeer.peer!._asPeer()), nil, false, false, nil)
}
})
})
@@ -2194,7 +2221,7 @@ public final class ChatListNode: ListView {
continue
}
switch chatListView.filteredEntries[entryCount - i - 1] {
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
return index
default:
break
@@ -2210,7 +2237,7 @@ public final class ChatListNode: ListView {
if resultPeer == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) {
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
switch item.content {
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _):
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _):
resultPeer = peer.peer
default:
break