mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
[WIP] Topic APIs
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user