mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Experimental chat list filtering
This commit is contained in:
@@ -699,7 +699,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
isPeerGroup = false
|
||||
isAd = isAdValue
|
||||
displayAsMessage = displayAsMessageValue
|
||||
hasFailedMessages = hasFailedMessagesValue
|
||||
hasFailedMessages = messageValue?.flags.contains(.Failed) ?? false // hasFailedMessagesValue
|
||||
case let .groupReference(_, peers, messageValue, unreadState, hiddenByDefault):
|
||||
if let _ = messageValue, !peers.isEmpty {
|
||||
contentPeer = .chat(peers[0].peer)
|
||||
|
||||
@@ -366,6 +366,14 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
|
||||
private var currentLocation: ChatListNodeLocation?
|
||||
var chatListFilter: ChatListNodeFilter = .all {
|
||||
didSet {
|
||||
if self.chatListFilter != oldValue {
|
||||
self.chatListFilterValue.set(self.chatListFilter)
|
||||
}
|
||||
}
|
||||
}
|
||||
private let chatListFilterValue = ValuePromise<ChatListNodeFilter>(.all)
|
||||
private let chatListLocation = ValuePromise<ChatListNodeLocation>()
|
||||
private let chatListDisposable = MetaDisposable()
|
||||
private var activityStatusesDisposable: Disposable?
|
||||
@@ -522,10 +530,21 @@ public final class ChatListNode: ListView {
|
||||
|
||||
let viewProcessingQueue = self.viewProcessingQueue
|
||||
|
||||
let chatListViewUpdate = self.chatListLocation.get()
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { location in
|
||||
return chatListViewForLocation(groupId: groupId, location: location, account: context.account)
|
||||
let chatListViewUpdate = combineLatest(self.chatListLocation.get(), self.chatListFilterValue.get())
|
||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||
if lhs.0 != rhs.0 {
|
||||
return false
|
||||
}
|
||||
if lhs.1 != rhs.1 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|> mapToSignal { location, filter -> Signal<(ChatListNodeViewUpdate, ChatListNodeFilter), NoError> in
|
||||
return chatListViewForLocation(groupId: groupId, filter: filter, location: location, account: context.account)
|
||||
|> map { update in
|
||||
return (update, filter)
|
||||
}
|
||||
}
|
||||
|
||||
let previousState = Atomic<ChatListNodeState>(value: self.currentState)
|
||||
@@ -575,7 +594,8 @@ public final class ChatListNode: ListView {
|
||||
let currentPeerId: PeerId = context.account.peerId
|
||||
|
||||
let chatListNodeViewTransition = combineLatest(queue: viewProcessingQueue, hideArchivedFolderByDefault, displayArchiveIntro, savedMessagesPeer, chatListViewUpdate, self.statePromise.get())
|
||||
|> mapToQueue { (hideArchivedFolderByDefault, displayArchiveIntro, savedMessagesPeer, update, state) -> Signal<ChatListNodeListViewTransition, NoError> in
|
||||
|> mapToQueue { (hideArchivedFolderByDefault, displayArchiveIntro, savedMessagesPeer, updateAndFilter, state) -> Signal<ChatListNodeListViewTransition, NoError> in
|
||||
let (update, filter) = updateAndFilter
|
||||
|
||||
let previousHideArchivedFolderByDefaultValue = previousHideArchivedFolderByDefault.swap(hideArchivedFolderByDefault)
|
||||
|
||||
@@ -633,7 +653,7 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
}
|
||||
|
||||
let processedView = ChatListNodeView(originalView: update.view, filteredEntries: entries, isLoading: isLoading)
|
||||
let processedView = ChatListNodeView(originalView: update.view, filteredEntries: entries, isLoading: isLoading, filter: filter)
|
||||
let previousView = previousView.swap(processedView)
|
||||
let previousState = previousState.swap(state)
|
||||
|
||||
@@ -746,6 +766,10 @@ public final class ChatListNode: ListView {
|
||||
searchMode = true
|
||||
}
|
||||
|
||||
if filter != previousView?.filter {
|
||||
disableAnimations = true
|
||||
}
|
||||
|
||||
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, mode: mode, transition: $0) })
|
||||
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
||||
@@ -1439,17 +1463,23 @@ public final class ChatListNode: ListView {
|
||||
guard index < 10 else {
|
||||
return
|
||||
}
|
||||
let _ = (chatListViewForLocation(groupId: self.groupId, location: .initial(count: 10), account: self.context.account)
|
||||
let _ = (self.chatListFilterValue.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { update in
|
||||
let entries = update.view.entries
|
||||
if entries.count > index, case let .MessageEntry(index, _, _, _, _, renderedPeer, _, _, _) = entries[10 - index - 1] {
|
||||
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true)
|
||||
self.setChatListLocation(location)
|
||||
self.peerSelected?(renderedPeer.peerId, false, false)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] filter in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
let _ = (chatListViewForLocation(groupId: self.groupId, filter: filter, location: .initial(count: 10), 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[10 - index - 1] {
|
||||
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true)
|
||||
self.setChatListLocation(location)
|
||||
self.peerSelected?(renderedPeer.peerId, false, false)
|
||||
}
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,18 +31,90 @@ struct ChatListNodeViewUpdate {
|
||||
let scrollPosition: ChatListNodeViewScrollPosition?
|
||||
}
|
||||
|
||||
func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
||||
struct ChatListNodeFilter: OptionSet {
|
||||
var rawValue: Int32
|
||||
|
||||
init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
static let muted = ChatListNodeFilter(rawValue: 1 << 1)
|
||||
static let privateChats = ChatListNodeFilter(rawValue: 1 << 2)
|
||||
static let groups = ChatListNodeFilter(rawValue: 1 << 3)
|
||||
static let bots = ChatListNodeFilter(rawValue: 1 << 4)
|
||||
static let channels = ChatListNodeFilter(rawValue: 1 << 5)
|
||||
|
||||
static let all: ChatListNodeFilter = [
|
||||
.muted,
|
||||
.privateChats,
|
||||
.groups,
|
||||
.bots,
|
||||
.channels
|
||||
]
|
||||
}
|
||||
|
||||
func chatListViewForLocation(groupId: PeerGroupId, filter: ChatListNodeFilter, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
||||
let filterPredicate: ((Peer, PeerNotificationSettings?) -> Bool)?
|
||||
if filter == .all {
|
||||
filterPredicate = nil
|
||||
} else {
|
||||
filterPredicate = { peer, notificationSettings in
|
||||
if !filter.contains(.muted) {
|
||||
if let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings {
|
||||
if case .muted = notificationSettings.muteState {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if !filter.contains(.privateChats) {
|
||||
if let user = peer as? TelegramUser {
|
||||
if user.botInfo == nil {
|
||||
return false
|
||||
}
|
||||
} else if let _ = peer as? TelegramSecretChat {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if !filter.contains(.bots) {
|
||||
if let user = peer as? TelegramUser {
|
||||
if user.botInfo != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if !filter.contains(.groups) {
|
||||
if let _ = peer as? TelegramGroup {
|
||||
return false
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
if case .group = channel.info {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if !filter.contains(.channels) {
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
switch location {
|
||||
case let .initial(count):
|
||||
let signal: Signal<(ChatListView, ViewUpdateType), NoError>
|
||||
signal = account.viewTracker.tailChatListView(groupId: groupId, count: count)
|
||||
signal = account.viewTracker.tailChatListView(groupId: groupId, filterPredicate: filterPredicate, count: count)
|
||||
return signal
|
||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||
return ChatListNodeViewUpdate(view: view, type: updateType, scrollPosition: nil)
|
||||
}
|
||||
case let .navigation(index):
|
||||
var first = true
|
||||
return account.viewTracker.aroundChatListView(groupId: groupId, index: index, count: 80)
|
||||
return account.viewTracker.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: index, count: 80)
|
||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||
let genericType: ViewUpdateType
|
||||
if first {
|
||||
@@ -57,7 +129,7 @@ func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocatio
|
||||
let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up
|
||||
let chatScrollPosition: ChatListNodeViewScrollPosition = .index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated)
|
||||
var first = true
|
||||
return account.viewTracker.aroundChatListView(groupId: groupId, index: index, count: 80)
|
||||
return account.viewTracker.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: index, count: 80)
|
||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||
let genericType: ViewUpdateType
|
||||
let scrollPosition: ChatListNodeViewScrollPosition? = first ? chatScrollPosition : nil
|
||||
|
||||
@@ -11,6 +11,7 @@ struct ChatListNodeView {
|
||||
let originalView: ChatListView
|
||||
let filteredEntries: [ChatListNodeEntry]
|
||||
let isLoading: Bool
|
||||
let filter: ChatListNodeFilter
|
||||
}
|
||||
|
||||
enum ChatListNodeViewTransitionReason {
|
||||
|
||||
Reference in New Issue
Block a user