mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Chat List Filter improvements
This commit is contained in:
@@ -1822,7 +1822,23 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.push(chatListFilterPresetListController(context: strongSelf.context))
|
strongSelf.push(chatListFilterPresetListController(context: strongSelf.context, updated: { presets in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let currentPreset = strongSelf.chatListDisplayNode.chatListNode.chatListFilter {
|
||||||
|
var found = false
|
||||||
|
if let index = presets.index(where: { $0.id == currentPreset.id }) {
|
||||||
|
found = true
|
||||||
|
if currentPreset != presets[index] {
|
||||||
|
strongSelf.chatListDisplayNode.chatListNode.chatListFilter = presets[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
strongSelf.chatListDisplayNode.chatListNode.chatListFilter = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
}, updatePreset: { value in
|
}, updatePreset: { value in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -53,9 +53,11 @@ private func filterEntry(presentationData: ItemListPresentationData, arguments:
|
|||||||
private enum ChatListFilterPresetEntryStableId: Hashable {
|
private enum ChatListFilterPresetEntryStableId: Hashable {
|
||||||
case index(Int)
|
case index(Int)
|
||||||
case peer(PeerId)
|
case peer(PeerId)
|
||||||
|
case additionalPeerInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||||
|
case nameHeader(String)
|
||||||
case name(placeholder: String, value: String)
|
case name(placeholder: String, value: String)
|
||||||
case filterPrivateChats(title: String, value: Bool)
|
case filterPrivateChats(title: String, value: Bool)
|
||||||
case filterSecretChats(title: String, value: Bool)
|
case filterSecretChats(title: String, value: Bool)
|
||||||
@@ -68,46 +70,51 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
case additionalPeersHeader(String)
|
case additionalPeersHeader(String)
|
||||||
case addAdditionalPeer(title: String)
|
case addAdditionalPeer(title: String)
|
||||||
case additionalPeer(index: Int, peer: RenderedPeer, isRevealed: Bool)
|
case additionalPeer(index: Int, peer: RenderedPeer, isRevealed: Bool)
|
||||||
|
case additionalPeerInfo(String)
|
||||||
|
|
||||||
var section: ItemListSectionId {
|
var section: ItemListSectionId {
|
||||||
switch self {
|
switch self {
|
||||||
case .name:
|
case .nameHeader, .name:
|
||||||
return ChatListFilterPresetControllerSection.name.rawValue
|
return ChatListFilterPresetControllerSection.name.rawValue
|
||||||
case .filterPrivateChats, .filterSecretChats, .filterPrivateGroups, .filterBots, .filterPublicGroups, .filterChannels:
|
case .filterPrivateChats, .filterSecretChats, .filterPrivateGroups, .filterBots, .filterPublicGroups, .filterChannels:
|
||||||
return ChatListFilterPresetControllerSection.categories.rawValue
|
return ChatListFilterPresetControllerSection.categories.rawValue
|
||||||
case .filterMuted, .filterRead:
|
case .filterMuted, .filterRead:
|
||||||
return ChatListFilterPresetControllerSection.excludeCategories.rawValue
|
return ChatListFilterPresetControllerSection.excludeCategories.rawValue
|
||||||
case .additionalPeersHeader, .addAdditionalPeer, .additionalPeer:
|
case .additionalPeersHeader, .addAdditionalPeer, .additionalPeer, .additionalPeerInfo:
|
||||||
return ChatListFilterPresetControllerSection.additionalPeers.rawValue
|
return ChatListFilterPresetControllerSection.additionalPeers.rawValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var stableId: ChatListFilterPresetEntryStableId {
|
var stableId: ChatListFilterPresetEntryStableId {
|
||||||
switch self {
|
switch self {
|
||||||
case .name:
|
case .nameHeader:
|
||||||
return .index(0)
|
return .index(0)
|
||||||
case .filterPrivateChats:
|
case .name:
|
||||||
return .index(1)
|
return .index(1)
|
||||||
case .filterSecretChats:
|
case .filterPrivateChats:
|
||||||
return .index(2)
|
return .index(2)
|
||||||
case .filterPrivateGroups:
|
case .filterSecretChats:
|
||||||
return .index(3)
|
return .index(3)
|
||||||
case .filterBots:
|
case .filterPrivateGroups:
|
||||||
return .index(4)
|
return .index(4)
|
||||||
case .filterPublicGroups:
|
case .filterBots:
|
||||||
return .index(5)
|
return .index(5)
|
||||||
case .filterChannels:
|
case .filterPublicGroups:
|
||||||
return .index(6)
|
return .index(6)
|
||||||
case .filterMuted:
|
case .filterChannels:
|
||||||
return .index(7)
|
return .index(7)
|
||||||
case .filterRead:
|
case .filterMuted:
|
||||||
return .index(8)
|
return .index(8)
|
||||||
case .additionalPeersHeader:
|
case .filterRead:
|
||||||
return .index(9)
|
return .index(9)
|
||||||
case .addAdditionalPeer:
|
case .additionalPeersHeader:
|
||||||
return .index(10)
|
return .index(10)
|
||||||
|
case .addAdditionalPeer:
|
||||||
|
return .index(11)
|
||||||
case let .additionalPeer(additionalPeer):
|
case let .additionalPeer(additionalPeer):
|
||||||
return .peer(additionalPeer.peer.peerId)
|
return .peer(additionalPeer.peer.peerId)
|
||||||
|
case .additionalPeerInfo:
|
||||||
|
return .additionalPeerInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +126,8 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
return lhsIndex < rhsIndex
|
return lhsIndex < rhsIndex
|
||||||
case .peer:
|
case .peer:
|
||||||
return true
|
return true
|
||||||
|
case .additionalPeerInfo:
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
case .peer:
|
case .peer:
|
||||||
switch lhs {
|
switch lhs {
|
||||||
@@ -126,6 +135,8 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
switch rhs.stableId {
|
switch rhs.stableId {
|
||||||
case .index:
|
case .index:
|
||||||
return false
|
return false
|
||||||
|
case .additionalPeerInfo:
|
||||||
|
return true
|
||||||
case .peer:
|
case .peer:
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case let .additionalPeer(rhsIndex, _, _):
|
case let .additionalPeer(rhsIndex, _, _):
|
||||||
@@ -137,12 +148,23 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
default:
|
default:
|
||||||
preconditionFailure()
|
preconditionFailure()
|
||||||
}
|
}
|
||||||
|
case .additionalPeerInfo:
|
||||||
|
switch rhs.stableId {
|
||||||
|
case .index:
|
||||||
|
return false
|
||||||
|
case .peer:
|
||||||
|
return false
|
||||||
|
case .additionalPeerInfo:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||||
let arguments = arguments as! ChatListFilterPresetControllerArguments
|
let arguments = arguments as! ChatListFilterPresetControllerArguments
|
||||||
switch self {
|
switch self {
|
||||||
|
case let .nameHeader(title):
|
||||||
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||||
case let .name(placeholder, value):
|
case let .name(placeholder, value):
|
||||||
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(), text: value, placeholder: placeholder, type: .regular(capitalization: true, autocorrection: false), sectionId: self.section, textUpdated: { value in
|
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(), text: value, placeholder: placeholder, type: .regular(capitalization: true, autocorrection: false), sectionId: self.section, textUpdated: { value in
|
||||||
arguments.updateState { current in
|
arguments.updateState { current in
|
||||||
@@ -201,6 +223,8 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
}, removePeer: { id in
|
}, removePeer: { id in
|
||||||
arguments.deleteAdditionalPeer(id)
|
arguments.deleteAdditionalPeer(id)
|
||||||
})
|
})
|
||||||
|
case let .additionalPeerInfo(text):
|
||||||
|
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,6 +250,7 @@ private struct ChatListFilterPresetControllerState: Equatable {
|
|||||||
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetControllerState, peers: [RenderedPeer]) -> [ChatListFilterPresetEntry] {
|
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetControllerState, peers: [RenderedPeer]) -> [ChatListFilterPresetEntry] {
|
||||||
var entries: [ChatListFilterPresetEntry] = []
|
var entries: [ChatListFilterPresetEntry] = []
|
||||||
|
|
||||||
|
entries.append(.nameHeader("NAME"))
|
||||||
entries.append(.name(placeholder: "Preset Name", value: state.name))
|
entries.append(.name(placeholder: "Preset Name", value: state.name))
|
||||||
|
|
||||||
entries.append(.filterPrivateChats(title: "Private Chats", value: state.includeCategories.contains(.privateChats)))
|
entries.append(.filterPrivateChats(title: "Private Chats", value: state.includeCategories.contains(.privateChats)))
|
||||||
@@ -245,10 +270,12 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
|||||||
entries.append(.additionalPeer(index: entries.count, peer: peer, isRevealed: state.revealedPeerId == peer.peerId))
|
entries.append(.additionalPeer(index: entries.count, peer: peer, isRevealed: state.revealedPeerId == peer.peerId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entries.append(.additionalPeerInfo("These chats will always be included in the list."))
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatListFilterPresetController(context: AccountContext, currentPreset: ChatListFilterPreset?) -> ViewController {
|
func chatListFilterPresetController(context: AccountContext, currentPreset: ChatListFilterPreset?, updated: @escaping ([ChatListFilterPreset]) -> Void) -> ViewController {
|
||||||
let initialName: String
|
let initialName: String
|
||||||
if let currentPreset = currentPreset {
|
if let currentPreset = currentPreset {
|
||||||
switch currentPreset.name {
|
switch currentPreset.name {
|
||||||
@@ -352,14 +379,15 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
})
|
})
|
||||||
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: {
|
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: {
|
||||||
let state = stateValue.with { $0 }
|
let state = stateValue.with { $0 }
|
||||||
let preset = ChatListFilterPreset(name: .custom(state.name), includeCategories: state.includeCategories, additionallyIncludePeers: state.additionallyIncludePeers)
|
let preset = ChatListFilterPreset(id: currentPreset?.id ?? arc4random64(), name: .custom(state.name), includeCategories: state.includeCategories, additionallyIncludePeers: state.additionallyIncludePeers)
|
||||||
let _ = (updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { settings in
|
let _ = (updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { settings in
|
||||||
var settings = settings
|
var settings = settings
|
||||||
settings.presets = settings.presets.filter { $0 != preset && $0 != currentPreset }
|
settings.presets = settings.presets.filter { $0 != preset && $0 != currentPreset }
|
||||||
settings.presets.append(preset)
|
settings.presets.append(preset)
|
||||||
return settings
|
return settings
|
||||||
})
|
})
|
||||||
|> deliverOnMainQueue).start(completed: {
|
|> deliverOnMainQueue).start(next: { settings in
|
||||||
|
updated(settings.presets)
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ private func stringForUserCount(_ peers: [PeerId: SelectivePrivacyPeer], strings
|
|||||||
|
|
||||||
private enum ChatListFilterPresetListEntryStableId: Hashable {
|
private enum ChatListFilterPresetListEntryStableId: Hashable {
|
||||||
case listHeader
|
case listHeader
|
||||||
case preset(ChatListFilterPresetName)
|
case preset(Int64)
|
||||||
case addItem
|
case addItem
|
||||||
case listFooter
|
case listFooter
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
case .listHeader:
|
case .listHeader:
|
||||||
return .listHeader
|
return .listHeader
|
||||||
case let .preset(preset):
|
case let .preset(preset):
|
||||||
return .preset(preset.preset.name)
|
return .preset(preset.preset.id)
|
||||||
case .addItem:
|
case .addItem:
|
||||||
return .addItem
|
return .addItem
|
||||||
case .listFooter:
|
case .listFooter:
|
||||||
@@ -141,7 +141,7 @@ private func chatListFilterPresetListControllerEntries(presentationData: Present
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatListFilterPresetListController(context: AccountContext) -> ViewController {
|
func chatListFilterPresetListController(context: AccountContext, updated: @escaping ([ChatListFilterPreset]) -> Void) -> ViewController {
|
||||||
let initialState = ChatListFilterPresetListControllerState()
|
let initialState = ChatListFilterPresetListControllerState()
|
||||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||||
let stateValue = Atomic(value: initialState)
|
let stateValue = Atomic(value: initialState)
|
||||||
@@ -154,9 +154,9 @@ func chatListFilterPresetListController(context: AccountContext) -> ViewControll
|
|||||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||||
|
|
||||||
let arguments = ChatListFilterPresetListControllerArguments(context: context, openPreset: { preset in
|
let arguments = ChatListFilterPresetListControllerArguments(context: context, openPreset: { preset in
|
||||||
pushControllerImpl?(chatListFilterPresetController(context: context, currentPreset: preset))
|
pushControllerImpl?(chatListFilterPresetController(context: context, currentPreset: preset, updated: updated))
|
||||||
}, addNew: {
|
}, addNew: {
|
||||||
pushControllerImpl?(chatListFilterPresetController(context: context, currentPreset: nil))
|
pushControllerImpl?(chatListFilterPresetController(context: context, currentPreset: nil, updated: updated))
|
||||||
}, setItemWithRevealedOptions: { preset, fromPreset in
|
}, setItemWithRevealedOptions: { preset, fromPreset in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
@@ -166,13 +166,16 @@ func chatListFilterPresetListController(context: AccountContext) -> ViewControll
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}, removePreset: { preset in
|
}, removePreset: { preset in
|
||||||
let _ = updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { settings in
|
let _ = (updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { settings in
|
||||||
var settings = settings
|
var settings = settings
|
||||||
if let index = settings.presets.index(of: preset) {
|
if let index = settings.presets.index(of: preset) {
|
||||||
settings.presets.remove(at: index)
|
settings.presets.remove(at: index)
|
||||||
}
|
}
|
||||||
return settings
|
return settings
|
||||||
}).start()
|
})
|
||||||
|
|> deliverOnMainQueue).start(next: { settings in
|
||||||
|
updated(settings.presets)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
let preferences = context.account.postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.chatListFilterSettings])
|
let preferences = context.account.postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.chatListFilterSettings])
|
||||||
|
|||||||
@@ -370,6 +370,12 @@ public final class ChatListNode: ListView {
|
|||||||
didSet {
|
didSet {
|
||||||
if self.chatListFilter != oldValue {
|
if self.chatListFilter != oldValue {
|
||||||
self.chatListFilterValue.set(self.chatListFilter)
|
self.chatListFilterValue.set(self.chatListFilter)
|
||||||
|
|
||||||
|
if self.chatListFilter?.includeCategories != oldValue?.includeCategories || self.chatListFilter?.additionallyIncludePeers != oldValue?.additionallyIncludePeers {
|
||||||
|
if let currentLocation = self.currentLocation {
|
||||||
|
self.setChatListLocation(.initial(count: 50, filter: self.chatListFilter))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -533,20 +539,12 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
let viewProcessingQueue = self.viewProcessingQueue
|
let viewProcessingQueue = self.viewProcessingQueue
|
||||||
|
|
||||||
let chatListViewUpdate = combineLatest(self.chatListLocation.get(), self.chatListFilterValue.get())
|
let chatListViewUpdate = self.chatListLocation.get()
|
||||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
|> distinctUntilChanged
|
||||||
if lhs.0 != rhs.0 {
|
|> mapToSignal { location -> Signal<(ChatListNodeViewUpdate, ChatListFilterPreset?), NoError> in
|
||||||
return false
|
return chatListViewForLocation(groupId: groupId, location: location, account: context.account)
|
||||||
}
|
|
||||||
if lhs.1 != rhs.1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|> mapToSignal { location, filter -> Signal<(ChatListNodeViewUpdate, ChatListFilterPreset?), NoError> in
|
|
||||||
return chatListViewForLocation(groupId: groupId, filter: filter, location: location, account: context.account)
|
|
||||||
|> map { update in
|
|> map { update in
|
||||||
return (update, filter)
|
return (update, location.filter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,9 +790,9 @@ public final class ChatListNode: ListView {
|
|||||||
if let range = range.loadedRange {
|
if let range = range.loadedRange {
|
||||||
var location: ChatListNodeLocation?
|
var location: ChatListNodeLocation?
|
||||||
if range.firstIndex < 5 && originalView.laterIndex != nil {
|
if range.firstIndex < 5 && originalView.laterIndex != nil {
|
||||||
location = .navigation(index: originalView.entries[originalView.entries.count - 1].index)
|
location = .navigation(index: originalView.entries[originalView.entries.count - 1].index, filter: strongSelf.chatListFilter)
|
||||||
} else if range.firstIndex >= 5 && range.lastIndex >= originalView.entries.count - 5 && originalView.earlierIndex != nil {
|
} else if range.firstIndex >= 5 && range.lastIndex >= originalView.entries.count - 5 && originalView.earlierIndex != nil {
|
||||||
location = .navigation(index: originalView.entries[0].index)
|
location = .navigation(index: originalView.entries[0].index, filter: strongSelf.chatListFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let location = location, location != strongSelf.currentLocation {
|
if let location = location, location != strongSelf.currentLocation {
|
||||||
@@ -850,10 +848,10 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
let initialLocation: ChatListNodeLocation
|
let initialLocation: ChatListNodeLocation
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
initialLocation = .initial(count: 50)
|
initialLocation = .initial(count: 50, filter: self.chatListFilter)
|
||||||
case .peers:
|
case .peers:
|
||||||
initialLocation = .initial(count: 200)
|
initialLocation = .initial(count: 200, filter: self.chatListFilter)
|
||||||
}
|
}
|
||||||
self.setChatListLocation(initialLocation)
|
self.setChatListLocation(initialLocation)
|
||||||
|
|
||||||
@@ -1332,12 +1330,12 @@ public final class ChatListNode: ListView {
|
|||||||
if view.laterIndex == nil {
|
if view.laterIndex == nil {
|
||||||
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 })
|
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 {
|
} else {
|
||||||
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound, scrollPosition: .top(0.0), animated: true)
|
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound, scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound
|
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound
|
||||||
, scrollPosition: .top(0.0), animated: true)
|
, scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1373,11 +1371,11 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
if let index = index {
|
if let index = index {
|
||||||
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: self?.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound
|
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: self?.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound
|
||||||
, scrollPosition: .center(.top), animated: true)
|
, scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
|
||||||
strongSelf.setChatListLocation(location)
|
strongSelf.setChatListLocation(location)
|
||||||
} else {
|
} else {
|
||||||
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound
|
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound
|
||||||
, scrollPosition: .top(0.0), animated: true)
|
, scrollPosition: .top(0.0), animated: true, filter: strongSelf.chatListFilter)
|
||||||
strongSelf.setChatListLocation(location)
|
strongSelf.setChatListLocation(location)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1433,7 +1431,7 @@ public final class ChatListNode: ListView {
|
|||||||
guard let strongSelf = self, let index = index else {
|
guard let strongSelf = self, let index = index else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: strongSelf.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound, scrollPosition: .center(.top), animated: true)
|
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: strongSelf.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound, scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
|
||||||
strongSelf.setChatListLocation(location)
|
strongSelf.setChatListLocation(location)
|
||||||
strongSelf.peerSelected?(index.messageIndex.id.peerId, false, false)
|
strongSelf.peerSelected?(index.messageIndex.id.peerId, false, false)
|
||||||
})
|
})
|
||||||
@@ -1457,7 +1455,7 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let target = target {
|
if let target = target {
|
||||||
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true)
|
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: self.chatListFilter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
self.peerSelected?(target.1, false, false)
|
self.peerSelected?(target.1, false, false)
|
||||||
}
|
}
|
||||||
@@ -1473,12 +1471,12 @@ public final class ChatListNode: ListView {
|
|||||||
guard let self = self else {
|
guard let self = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = (chatListViewForLocation(groupId: self.groupId, filter: filter, location: .initial(count: 10), account: self.context.account)
|
let _ = (chatListViewForLocation(groupId: self.groupId, location: .initial(count: 10, filter: filter), account: self.context.account)
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { update in
|
|> deliverOnMainQueue).start(next: { update in
|
||||||
let entries = update.view.entries
|
let entries = update.view.entries
|
||||||
if entries.count > index, case let .MessageEntry(index, _, _, _, _, renderedPeer, _, _, _) = entries[10 - index - 1] {
|
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)
|
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: filter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
self.peerSelected?(renderedPeer.peerId, false, false)
|
self.peerSelected?(renderedPeer.peerId, false, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,21 +7,18 @@ import Display
|
|||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
|
|
||||||
enum ChatListNodeLocation: Equatable {
|
enum ChatListNodeLocation: Equatable {
|
||||||
case initial(count: Int)
|
case initial(count: Int, filter: ChatListFilterPreset?)
|
||||||
case navigation(index: ChatListIndex)
|
case navigation(index: ChatListIndex, filter: ChatListFilterPreset?)
|
||||||
case scroll(index: ChatListIndex, sourceIndex: ChatListIndex, scrollPosition: ListViewScrollPosition, animated: Bool)
|
case scroll(index: ChatListIndex, sourceIndex: ChatListIndex, scrollPosition: ListViewScrollPosition, animated: Bool, filter: ChatListFilterPreset?)
|
||||||
|
|
||||||
static func ==(lhs: ChatListNodeLocation, rhs: ChatListNodeLocation) -> Bool {
|
var filter: ChatListFilterPreset? {
|
||||||
switch lhs {
|
switch self {
|
||||||
case let .navigation(index):
|
case let .initial(initial):
|
||||||
switch rhs {
|
return initial.filter
|
||||||
case .navigation(index):
|
case let .navigation(navigation):
|
||||||
return true
|
return navigation.filter
|
||||||
default:
|
case let .scroll(scroll):
|
||||||
return false
|
return scroll.filter
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,9 +29,9 @@ struct ChatListNodeViewUpdate {
|
|||||||
let scrollPosition: ChatListNodeViewScrollPosition?
|
let scrollPosition: ChatListNodeViewScrollPosition?
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatListViewForLocation(groupId: PeerGroupId, filter: ChatListFilterPreset?, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
||||||
let filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?
|
let filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?
|
||||||
if let filter = filter {
|
if let filter = location.filter {
|
||||||
let includePeers = Set(filter.additionallyIncludePeers)
|
let includePeers = Set(filter.additionallyIncludePeers)
|
||||||
filterPredicate = { peer, notificationSettings, isUnread in
|
filterPredicate = { peer, notificationSettings, isUnread in
|
||||||
if includePeers.contains(peer.id) {
|
if includePeers.contains(peer.id) {
|
||||||
@@ -107,14 +104,14 @@ func chatListViewForLocation(groupId: PeerGroupId, filter: ChatListFilterPreset?
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch location {
|
switch location {
|
||||||
case let .initial(count):
|
case let .initial(count, _):
|
||||||
let signal: Signal<(ChatListView, ViewUpdateType), NoError>
|
let signal: Signal<(ChatListView, ViewUpdateType), NoError>
|
||||||
signal = account.viewTracker.tailChatListView(groupId: groupId, filterPredicate: filterPredicate, count: count)
|
signal = account.viewTracker.tailChatListView(groupId: groupId, filterPredicate: filterPredicate, count: count)
|
||||||
return signal
|
return signal
|
||||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||||
return ChatListNodeViewUpdate(view: view, type: updateType, scrollPosition: nil)
|
return ChatListNodeViewUpdate(view: view, type: updateType, scrollPosition: nil)
|
||||||
}
|
}
|
||||||
case let .navigation(index):
|
case let .navigation(index, _):
|
||||||
var first = true
|
var first = true
|
||||||
return account.viewTracker.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: index, count: 80)
|
return account.viewTracker.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: index, count: 80)
|
||||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||||
@@ -127,7 +124,7 @@ func chatListViewForLocation(groupId: PeerGroupId, filter: ChatListFilterPreset?
|
|||||||
}
|
}
|
||||||
return ChatListNodeViewUpdate(view: view, type: genericType, scrollPosition: nil)
|
return ChatListNodeViewUpdate(view: view, type: genericType, scrollPosition: nil)
|
||||||
}
|
}
|
||||||
case let .scroll(index, sourceIndex, scrollPosition, animated):
|
case let .scroll(index, sourceIndex, scrollPosition, animated, _):
|
||||||
let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up
|
let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up
|
||||||
let chatScrollPosition: ChatListNodeViewScrollPosition = .index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated)
|
let chatScrollPosition: ChatListNodeViewScrollPosition = .index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated)
|
||||||
var first = true
|
var first = true
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toV
|
|||||||
|
|
||||||
var fromEmptyView = false
|
var fromEmptyView = false
|
||||||
if let fromView = fromView {
|
if let fromView = fromView {
|
||||||
if fromView.filteredEntries.isEmpty {
|
if fromView.filteredEntries.isEmpty || fromView.filter != toView.filter {
|
||||||
options.remove(.AnimateInsertion)
|
options.remove(.AnimateInsertion)
|
||||||
options.remove(.AnimateAlpha)
|
options.remove(.AnimateAlpha)
|
||||||
fromEmptyView = true
|
fromEmptyView = true
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ private final class TabBarChatListFilterControllerNode: ViewControllerTracingNod
|
|||||||
if preset.includeCategories.contains(.publicGroups) {
|
if preset.includeCategories.contains(.publicGroups) {
|
||||||
tags.append(.publicGroup)
|
tags.append(.publicGroup)
|
||||||
}
|
}
|
||||||
if preset.includeCategories.contains(.privateChats) {
|
if preset.includeCategories.contains(.channels) {
|
||||||
tags.append(.channel)
|
tags.append(.channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
63
submodules/Postbox/Sources/AllChatListHolesView.swift
Normal file
63
submodules/Postbox/Sources/AllChatListHolesView.swift
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class MutableAllChatListHolesView: MutablePostboxView {
|
||||||
|
fileprivate let groupId: PeerGroupId
|
||||||
|
private var holes = Set<ChatListHole>()
|
||||||
|
fileprivate var latestHole: ChatListHole?
|
||||||
|
|
||||||
|
init(postbox: Postbox, groupId: PeerGroupId) {
|
||||||
|
self.groupId = groupId
|
||||||
|
self.holes = Set(postbox.chatListTable.allHoles(groupId: groupId))
|
||||||
|
self.latestHole = self.holes.max(by: { $0.index < $1.index })
|
||||||
|
}
|
||||||
|
|
||||||
|
func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool {
|
||||||
|
if let operations = transaction.chatListOperations[self.groupId] {
|
||||||
|
var updated = false
|
||||||
|
for operation in operations {
|
||||||
|
switch operation {
|
||||||
|
case let .InsertHole(hole):
|
||||||
|
if !self.holes.contains(hole) {
|
||||||
|
self.holes.insert(hole)
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
case let .RemoveHoles(indices):
|
||||||
|
for index in indices {
|
||||||
|
if self.holes.contains(ChatListHole(index: index.messageIndex)) {
|
||||||
|
self.holes.remove(ChatListHole(index: index.messageIndex))
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
let updatedLatestHole = self.holes.max(by: { $0.index < $1.index })
|
||||||
|
if updatedLatestHole != self.latestHole {
|
||||||
|
self.latestHole = updatedLatestHole
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func immutableView() -> PostboxView {
|
||||||
|
return AllChatListHolesView(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class AllChatListHolesView: PostboxView {
|
||||||
|
public let latestHole: ChatListHole?
|
||||||
|
|
||||||
|
init(_ view: MutableAllChatListHolesView) {
|
||||||
|
self.latestHole = view.latestHole
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -570,13 +570,10 @@ final class ChatListIndexTable: Table {
|
|||||||
|
|
||||||
func debugReindexUnreadCounts(postbox: Postbox) -> (ChatListTotalUnreadState, [PeerGroupId: PeerGroupUnreadCountersCombinedSummary]) {
|
func debugReindexUnreadCounts(postbox: Postbox) -> (ChatListTotalUnreadState, [PeerGroupId: PeerGroupUnreadCountersCombinedSummary]) {
|
||||||
var peerIds: [PeerId] = []
|
var peerIds: [PeerId] = []
|
||||||
self.valueBox.scanInt64(self.table, values: { key, _ in
|
for groupId in postbox.chatListTable.existingGroups() + [.root] {
|
||||||
let peerId = PeerId(key)
|
let groupPeerIds = postbox.chatListTable.allPeerIds(groupId: groupId)
|
||||||
if peerId.namespace != Int32.max {
|
peerIds.append(contentsOf: groupPeerIds)
|
||||||
peerIds.append(peerId)
|
}
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
var rootState = ChatListTotalUnreadState(absoluteCounters: [:], filteredCounters: [:])
|
var rootState = ChatListTotalUnreadState(absoluteCounters: [:], filteredCounters: [:])
|
||||||
var summaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary] = [:]
|
var summaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary] = [:]
|
||||||
for peerId in peerIds {
|
for peerId in peerIds {
|
||||||
|
|||||||
@@ -680,6 +680,35 @@ final class ChatListTable: Table {
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allPeerIds(groupId: PeerGroupId) -> [PeerId] {
|
||||||
|
var peerIds: [PeerId] = []
|
||||||
|
self.valueBox.range(self.table, start: self.upperBound(groupId: groupId), end: self.lowerBound(groupId: groupId), keys: { key in
|
||||||
|
let (keyGroupId, pinningIndex, messageIndex, type) = extractKey(key)
|
||||||
|
assert(groupId == keyGroupId)
|
||||||
|
|
||||||
|
let index = ChatListIndex(pinningIndex: pinningIndex, messageIndex: messageIndex)
|
||||||
|
if type == ChatListEntryType.message.rawValue {
|
||||||
|
peerIds.append(messageIndex.id.peerId)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, limit: 0)
|
||||||
|
return peerIds
|
||||||
|
}
|
||||||
|
|
||||||
|
func allHoles(groupId: PeerGroupId) -> [ChatListHole] {
|
||||||
|
var entries: [ChatListHole] = []
|
||||||
|
self.valueBox.range(self.table, start: self.upperBound(groupId: groupId), end: self.lowerBound(groupId: groupId), keys: { key in
|
||||||
|
let (keyGroupId, pinningIndex, messageIndex, type) = extractKey(key)
|
||||||
|
assert(groupId == keyGroupId)
|
||||||
|
if type == ChatListEntryType.hole.rawValue {
|
||||||
|
let index = ChatListIndex(pinningIndex: pinningIndex, messageIndex: messageIndex)
|
||||||
|
entries.append(ChatListHole(index: index.messageIndex))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, limit: 0)
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
func entriesInRange(groupId: PeerGroupId, upperBound: ChatListIndex, lowerBound: ChatListIndex) -> [ChatListEntryInfo] {
|
func entriesInRange(groupId: PeerGroupId, upperBound: ChatListIndex, lowerBound: ChatListIndex) -> [ChatListEntryInfo] {
|
||||||
var entries: [ChatListEntryInfo] = []
|
var entries: [ChatListEntryInfo] = []
|
||||||
let upperBoundKey: ValueBoxKey
|
let upperBoundKey: ValueBoxKey
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public enum PostboxViewKey: Hashable {
|
|||||||
case peerNotificationSettingsBehaviorTimestampView
|
case peerNotificationSettingsBehaviorTimestampView
|
||||||
case peerChatInclusion(PeerId)
|
case peerChatInclusion(PeerId)
|
||||||
case basicPeer(PeerId)
|
case basicPeer(PeerId)
|
||||||
|
case allChatListHoles(PeerGroupId)
|
||||||
|
|
||||||
public var hashValue: Int {
|
public var hashValue: Int {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -82,6 +83,8 @@ public enum PostboxViewKey: Hashable {
|
|||||||
return peerId.hashValue
|
return peerId.hashValue
|
||||||
case let .basicPeer(peerId):
|
case let .basicPeer(peerId):
|
||||||
return peerId.hashValue
|
return peerId.hashValue
|
||||||
|
case let .allChatListHoles(groupId):
|
||||||
|
return groupId.hashValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,6 +246,12 @@ public enum PostboxViewKey: Hashable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case let .allChatListHoles(groupId):
|
||||||
|
if case .allChatListHoles(groupId) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,5 +310,7 @@ func postboxViewForKey(postbox: Postbox, key: PostboxViewKey) -> MutablePostboxV
|
|||||||
return MutablePeerChatInclusionView(postbox: postbox, peerId: peerId)
|
return MutablePeerChatInclusionView(postbox: postbox, peerId: peerId)
|
||||||
case let .basicPeer(peerId):
|
case let .basicPeer(peerId):
|
||||||
return MutableBasicPeerView(postbox: postbox, peerId: peerId)
|
return MutableBasicPeerView(postbox: postbox, peerId: peerId)
|
||||||
|
case let .allChatListHoles(groupId):
|
||||||
|
return MutableAllChatListHolesView(postbox: postbox, groupId: groupId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import SwiftSignalKit
|
|||||||
|
|
||||||
private final class ManagedChatListHolesState {
|
private final class ManagedChatListHolesState {
|
||||||
private var holeDisposables: [ChatListHolesEntry: Disposable] = [:]
|
private var holeDisposables: [ChatListHolesEntry: Disposable] = [:]
|
||||||
|
private var additionalLatestHoleDisposable: (ChatListHole, Disposable)?
|
||||||
|
|
||||||
func clearDisposables() -> [Disposable] {
|
func clearDisposables() -> [Disposable] {
|
||||||
let disposables = Array(self.holeDisposables.values)
|
let disposables = Array(self.holeDisposables.values)
|
||||||
@@ -11,7 +12,7 @@ private final class ManagedChatListHolesState {
|
|||||||
return disposables
|
return disposables
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(entries: Set<ChatListHolesEntry>) -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable]) {
|
func update(entries: Set<ChatListHolesEntry>, additionalLatestHole: ChatListHole?) -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable], addedAdditionalLatestHole: (ChatListHole, MetaDisposable)?) {
|
||||||
var removed: [Disposable] = []
|
var removed: [Disposable] = []
|
||||||
var added: [ChatListHolesEntry: MetaDisposable] = [:]
|
var added: [ChatListHolesEntry: MetaDisposable] = [:]
|
||||||
|
|
||||||
@@ -30,7 +31,21 @@ private final class ManagedChatListHolesState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (removed, added)
|
var addedAdditionalLatestHole: (ChatListHole, MetaDisposable)?
|
||||||
|
if self.holeDisposables.isEmpty {
|
||||||
|
if self.additionalLatestHoleDisposable?.0 != additionalLatestHole {
|
||||||
|
if let (_, disposable) = self.additionalLatestHoleDisposable {
|
||||||
|
removed.append(disposable)
|
||||||
|
}
|
||||||
|
if let additionalLatestHole = additionalLatestHole {
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
self.additionalLatestHoleDisposable = (additionalLatestHole, disposable)
|
||||||
|
addedAdditionalLatestHole = (additionalLatestHole, disposable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (removed, added, addedAdditionalLatestHole)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,9 +53,17 @@ func managedChatListHoles(network: Network, postbox: Postbox, accountPeerId: Pee
|
|||||||
return Signal { _ in
|
return Signal { _ in
|
||||||
let state = Atomic(value: ManagedChatListHolesState())
|
let state = Atomic(value: ManagedChatListHolesState())
|
||||||
|
|
||||||
let disposable = postbox.chatListHolesView().start(next: { view in
|
let topRootHoleKey = PostboxViewKey.allChatListHoles(.root)
|
||||||
let (removed, added) = state.with { state -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable]) in
|
let topRootHole = postbox.combinedView(keys: [topRootHoleKey])
|
||||||
return state.update(entries: view.entries)
|
|
||||||
|
let disposable = combineLatest(postbox.chatListHolesView(), topRootHole).start(next: { view, topRootHoleView in
|
||||||
|
var additionalLatestHole: ChatListHole?
|
||||||
|
if let topRootHole = topRootHoleView.views[topRootHoleKey] as? AllChatListHolesView {
|
||||||
|
additionalLatestHole = topRootHole.latestHole
|
||||||
|
}
|
||||||
|
|
||||||
|
let (removed, added, addedAdditionalLatestHole) = state.with { state in
|
||||||
|
return state.update(entries: view.entries, additionalLatestHole: additionalLatestHole)
|
||||||
}
|
}
|
||||||
|
|
||||||
for disposable in removed {
|
for disposable in removed {
|
||||||
@@ -50,6 +73,10 @@ func managedChatListHoles(network: Network, postbox: Postbox, accountPeerId: Pee
|
|||||||
for (entry, disposable) in added {
|
for (entry, disposable) in added {
|
||||||
disposable.set(fetchChatListHole(postbox: postbox, network: network, accountPeerId: accountPeerId, groupId: entry.groupId, hole: entry.hole).start())
|
disposable.set(fetchChatListHole(postbox: postbox, network: network, accountPeerId: accountPeerId, groupId: entry.groupId, hole: entry.hole).start())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let (hole, disposable) = addedAdditionalLatestHole {
|
||||||
|
disposable.set(fetchChatListHole(postbox: postbox, network: network, accountPeerId: accountPeerId, groupId: .root, hole: hole).start())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return ActionDisposable {
|
return ActionDisposable {
|
||||||
|
|||||||
@@ -59,23 +59,27 @@ public enum ChatListFilterPresetName: Equatable, Hashable, PostboxCoding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct ChatListFilterPreset: Equatable, PostboxCoding {
|
public struct ChatListFilterPreset: Equatable, PostboxCoding {
|
||||||
|
public var id: Int64
|
||||||
public var name: ChatListFilterPresetName
|
public var name: ChatListFilterPresetName
|
||||||
public var includeCategories: ChatListIncludeCategoryFilter
|
public var includeCategories: ChatListIncludeCategoryFilter
|
||||||
public var additionallyIncludePeers: [PeerId]
|
public var additionallyIncludePeers: [PeerId]
|
||||||
|
|
||||||
public init(name: ChatListFilterPresetName, includeCategories: ChatListIncludeCategoryFilter, additionallyIncludePeers: [PeerId]) {
|
public init(id: Int64, name: ChatListFilterPresetName, includeCategories: ChatListIncludeCategoryFilter, additionallyIncludePeers: [PeerId]) {
|
||||||
|
self.id = id
|
||||||
self.name = name
|
self.name = name
|
||||||
self.includeCategories = includeCategories
|
self.includeCategories = includeCategories
|
||||||
self.additionallyIncludePeers = additionallyIncludePeers
|
self.additionallyIncludePeers = additionallyIncludePeers
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
|
self.id = decoder.decodeInt64ForKey("id", orElse: 0)
|
||||||
self.name = decoder.decodeObjectForKey("name", decoder: { ChatListFilterPresetName(decoder: $0) }) as? ChatListFilterPresetName ?? ChatListFilterPresetName.custom("Preset")
|
self.name = decoder.decodeObjectForKey("name", decoder: { ChatListFilterPresetName(decoder: $0) }) as? ChatListFilterPresetName ?? ChatListFilterPresetName.custom("Preset")
|
||||||
self.includeCategories = ChatListIncludeCategoryFilter(rawValue: decoder.decodeInt32ForKey("includeCategories", orElse: 0))
|
self.includeCategories = ChatListIncludeCategoryFilter(rawValue: decoder.decodeInt32ForKey("includeCategories", orElse: 0))
|
||||||
self.additionallyIncludePeers = decoder.decodeInt64ArrayForKey("additionallyIncludePeers").map(PeerId.init)
|
self.additionallyIncludePeers = decoder.decodeInt64ArrayForKey("additionallyIncludePeers").map(PeerId.init)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
|
encoder.encodeInt64(self.id, forKey: "id")
|
||||||
encoder.encodeObject(self.name, forKey: "name")
|
encoder.encodeObject(self.name, forKey: "name")
|
||||||
encoder.encodeInt32(self.includeCategories.rawValue, forKey: "includeCategories")
|
encoder.encodeInt32(self.includeCategories.rawValue, forKey: "includeCategories")
|
||||||
encoder.encodeInt64Array(self.additionallyIncludePeers.map { $0.toInt64() }, forKey: "additionallyIncludePeers")
|
encoder.encodeInt64Array(self.additionallyIncludePeers.map { $0.toInt64() }, forKey: "additionallyIncludePeers")
|
||||||
@@ -88,6 +92,7 @@ public struct ChatListFilterSettings: PreferencesEntry, Equatable {
|
|||||||
public static var `default`: ChatListFilterSettings {
|
public static var `default`: ChatListFilterSettings {
|
||||||
return ChatListFilterSettings(presets: [
|
return ChatListFilterSettings(presets: [
|
||||||
ChatListFilterPreset(
|
ChatListFilterPreset(
|
||||||
|
id: Int64(arc4random()),
|
||||||
name: .unread,
|
name: .unread,
|
||||||
includeCategories: ChatListIncludeCategoryFilter.all.subtracting(.read),
|
includeCategories: ChatListIncludeCategoryFilter.all.subtracting(.read),
|
||||||
additionallyIncludePeers: []
|
additionallyIncludePeers: []
|
||||||
@@ -116,12 +121,15 @@ public struct ChatListFilterSettings: PreferencesEntry, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateChatListFilterSettingsInteractively(postbox: Postbox, _ f: @escaping (ChatListFilterSettings) -> ChatListFilterSettings) -> Signal<Never, NoError> {
|
public func updateChatListFilterSettingsInteractively(postbox: Postbox, _ f: @escaping (ChatListFilterSettings) -> ChatListFilterSettings) -> Signal<ChatListFilterSettings, NoError> {
|
||||||
return postbox.transaction { transaction -> Void in
|
return postbox.transaction { transaction -> ChatListFilterSettings in
|
||||||
|
var result: ChatListFilterSettings?
|
||||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.chatListFilterSettings, { entry in
|
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.chatListFilterSettings, { entry in
|
||||||
var settings = entry as? ChatListFilterSettings ?? ChatListFilterSettings.default
|
var settings = entry as? ChatListFilterSettings ?? ChatListFilterSettings.default
|
||||||
return f(settings)
|
let updated = f(settings)
|
||||||
|
result = updated
|
||||||
|
return updated
|
||||||
})
|
})
|
||||||
|
return result ?? .default
|
||||||
}
|
}
|
||||||
|> ignoreValues
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user