Experimental chat list filtering

This commit is contained in:
Ali
2020-01-24 13:01:49 +04:00
parent 13b0847b1e
commit d2e3c9d54a
18 changed files with 880 additions and 87 deletions

View File

@@ -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)

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -11,6 +11,7 @@ struct ChatListNodeView {
let originalView: ChatListView
let filteredEntries: [ChatListNodeEntry]
let isLoading: Bool
let filter: ChatListNodeFilter
}
enum ChatListNodeViewTransitionReason {