mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Filter improvements
This commit is contained in:
@@ -145,6 +145,8 @@ public struct ChatListNodeState: Equatable {
|
||||
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
||||
return entries.map { entry -> ListViewInsertItem in
|
||||
switch entry.entry {
|
||||
case .HeaderEntry:
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages):
|
||||
switch mode {
|
||||
case .chatList:
|
||||
@@ -278,6 +280,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint)
|
||||
case let .ArchiveIntro(presentationData):
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
||||
case .HeaderEntry:
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,6 +327,11 @@ public enum ChatListNodeEmptyState: Equatable {
|
||||
case empty(isLoading: Bool)
|
||||
}
|
||||
|
||||
enum ChatListNodePaneSwitchAnimationDirection {
|
||||
case left
|
||||
case right
|
||||
}
|
||||
|
||||
public final class ChatListNode: ListView {
|
||||
private let controlsHistoryPreload: Bool
|
||||
private let context: AccountContext
|
||||
@@ -367,8 +376,9 @@ public final class ChatListNode: ListView {
|
||||
return self.statePromise.get()
|
||||
}
|
||||
|
||||
var paneSwitchAnimation: (ChatListNodePaneSwitchAnimationDirection, ContainedViewLayoutTransition)?
|
||||
private var currentLocation: ChatListNodeLocation?
|
||||
var chatListFilter: ChatListFilter? {
|
||||
private(set) var chatListFilter: ChatListFilter? {
|
||||
didSet {
|
||||
self.chatListFilterValue.set(.single(self.chatListFilter))
|
||||
|
||||
@@ -379,10 +389,17 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
}
|
||||
}
|
||||
private let updatedFilterDisposable = MetaDisposable()
|
||||
private let chatListFilterValue = Promise<ChatListFilter?>()
|
||||
var chatListFilterSignal: Signal<ChatListFilter?, NoError> {
|
||||
return self.chatListFilterValue.get()
|
||||
}
|
||||
private var hasUpdatedAppliedChatListFilterValueOnce = false
|
||||
private var currentAppliedChatListFilterValue: ChatListFilter?
|
||||
private let appliedChatListFilterValue = Promise<ChatListFilter?>()
|
||||
var appliedChatListFilterSignal: Signal<ChatListFilter?, NoError> {
|
||||
return self.appliedChatListFilterValue.get()
|
||||
}
|
||||
private let chatListLocation = ValuePromise<ChatListNodeLocation>()
|
||||
private let chatListDisposable = MetaDisposable()
|
||||
private var activityStatusesDisposable: Disposable?
|
||||
@@ -413,7 +430,7 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
}
|
||||
|
||||
public var isEmptyUpdated: ((ChatListNodeEmptyState) -> Void)?
|
||||
var isEmptyUpdated: ((ChatListNodeEmptyState, Bool, ChatListNodePaneSwitchAnimationDirection?, ContainedViewLayoutTransition) -> Void)?
|
||||
private var currentIsEmptyState: ChatListNodeEmptyState?
|
||||
|
||||
public var addedVisibleChatsWithPeerIds: (([PeerId]) -> Void)?
|
||||
@@ -1138,11 +1155,50 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.resetFilter()
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.chatListDisposable.dispose()
|
||||
self.activityStatusesDisposable?.dispose()
|
||||
self.updatedFilterDisposable.dispose()
|
||||
}
|
||||
|
||||
func updateFilter(_ filter: ChatListFilter?) {
|
||||
if filter?.id != self.chatListFilter?.id {
|
||||
self.chatListFilter = filter
|
||||
self.resetFilter()
|
||||
}
|
||||
}
|
||||
|
||||
private func resetFilter() {
|
||||
if let chatListFilter = chatListFilter {
|
||||
let preferencesKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.chatListFilters]))
|
||||
self.updatedFilterDisposable.set((context.account.postbox.combinedView(keys: [preferencesKey])
|
||||
|> map { view -> ChatListFilter? in
|
||||
guard let preferencesView = view.views[preferencesKey] as? PreferencesView else {
|
||||
return nil
|
||||
}
|
||||
let filersState = preferencesView.values[PreferencesKeys.chatListFilters] as? ChatListFiltersState ?? ChatListFiltersState.default
|
||||
for filter in filersState.filters {
|
||||
if filter.id == chatListFilter.id {
|
||||
return filter
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] updatedFilter in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if strongSelf.chatListFilter != updatedFilter {
|
||||
strongSelf.chatListFilter = updatedFilter
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
self.updatedFilterDisposable.set(nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func updateThemeAndStrings(theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
|
||||
@@ -1200,6 +1256,13 @@ public final class ChatListNode: ListView {
|
||||
if let (transition, completion) = self.enqueuedTransition {
|
||||
self.enqueuedTransition = nil
|
||||
|
||||
let paneSwitchCopyView: UIView?
|
||||
if let (direction, transition) = self.paneSwitchAnimation, let copyView = self.view.snapshotContentTree(unhide: false, keepTransform: true) {
|
||||
paneSwitchCopyView = copyView
|
||||
} else {
|
||||
paneSwitchCopyView = nil
|
||||
}
|
||||
|
||||
let completion: (ListViewDisplayedItemRange) -> Void = { [weak self] visibleRange in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatListView = transition.chatListView
|
||||
@@ -1241,9 +1304,16 @@ public final class ChatListNode: ListView {
|
||||
if transition.chatListView.filteredEntries.isEmpty {
|
||||
isEmpty = true
|
||||
} else {
|
||||
if transition.chatListView.filteredEntries.count == 1 {
|
||||
if case .GroupReferenceEntry = transition.chatListView.filteredEntries[0] {
|
||||
isEmpty = true
|
||||
if transition.chatListView.filteredEntries.count <= 2 {
|
||||
isEmpty = true
|
||||
loop: for entry in transition.chatListView.filteredEntries {
|
||||
switch entry {
|
||||
case .GroupReferenceEntry, .HeaderEntry:
|
||||
break
|
||||
default:
|
||||
isEmpty = false
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1260,16 +1330,12 @@ public final class ChatListNode: ListView {
|
||||
case .GroupReferenceEntry, .HoleEntry, .PeerEntry:
|
||||
containsChats = true
|
||||
break loop
|
||||
case .ArchiveIntro:
|
||||
case .ArchiveIntro, .HeaderEntry:
|
||||
break
|
||||
}
|
||||
}
|
||||
isEmptyState = .notEmpty(containsChats: containsChats)
|
||||
}
|
||||
if strongSelf.currentIsEmptyState != isEmptyState {
|
||||
strongSelf.currentIsEmptyState = isEmptyState
|
||||
strongSelf.isEmptyUpdated?(isEmptyState)
|
||||
}
|
||||
|
||||
var insertedPeerIds: [PeerId] = []
|
||||
for item in transition.insertItems {
|
||||
@@ -1286,6 +1352,36 @@ public final class ChatListNode: ListView {
|
||||
strongSelf.addedVisibleChatsWithPeerIds?(insertedPeerIds)
|
||||
}
|
||||
|
||||
var isEmptyUpdate: (ChatListNodePaneSwitchAnimationDirection?, ContainedViewLayoutTransition) = (nil, .immediate)
|
||||
if let (direction, transition) = strongSelf.paneSwitchAnimation {
|
||||
strongSelf.paneSwitchAnimation = nil
|
||||
if let copyView = paneSwitchCopyView {
|
||||
let offset: CGFloat
|
||||
switch direction {
|
||||
case .left:
|
||||
offset = -strongSelf.bounds.width
|
||||
case .right:
|
||||
offset = strongSelf.bounds.width
|
||||
}
|
||||
copyView.frame = strongSelf.bounds.offsetBy(dx: offset, dy: 0.0)
|
||||
strongSelf.view.addSubview(copyView)
|
||||
transition.animateHorizontalOffsetAdditive(node: strongSelf, offset: offset, completion: { [weak copyView] in
|
||||
copyView?.removeFromSuperview()
|
||||
})
|
||||
isEmptyUpdate = (direction, transition)
|
||||
}
|
||||
}
|
||||
|
||||
if strongSelf.currentIsEmptyState != isEmptyState {
|
||||
strongSelf.currentIsEmptyState = isEmptyState
|
||||
strongSelf.isEmptyUpdated?(isEmptyState, transition.chatListView.filter != nil, isEmptyUpdate.0, isEmptyUpdate.1)
|
||||
}
|
||||
|
||||
if !strongSelf.hasUpdatedAppliedChatListFilterValueOnce || transition.chatListView.filter != strongSelf.currentAppliedChatListFilterValue {
|
||||
strongSelf.currentAppliedChatListFilterValue = transition.chatListView.filter
|
||||
strongSelf.appliedChatListFilterValue.set(.single(transition.chatListView.filter))
|
||||
}
|
||||
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user