mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Folder improvements
This commit is contained in:
parent
d3c82bdfb9
commit
a1a5b12125
@ -5455,3 +5455,10 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"ChatListFolder.ExcludeChatsTitle" = "Exclude Chats";
|
||||
|
||||
"ChatListFolderSettings.AddRecommended" = "ADD";
|
||||
|
||||
"ChatListFilter.ShowMoreChats_0" = "Show %@ More Chats";
|
||||
"ChatListFilter.ShowMoreChats_1" = "Show %@ More Chat";
|
||||
"ChatListFilter.ShowMoreChats_2" = "Show %@ More Chats";
|
||||
"ChatListFilter.ShowMoreChats_3_10" = "Show %@ More Chats";
|
||||
"ChatListFilter.ShowMoreChats_many" = "Show %@ More Chats";
|
||||
"ChatListFilter.ShowMoreChats_any" = "Show %@ More Chats";
|
||||
|
@ -169,7 +169,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
|
||||
super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .always, locationBroadcastPanelSource: .summary)
|
||||
|
||||
self.tabBarItemContextActionType = .whenActive
|
||||
self.tabBarItemContextActionType = .always
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
@ -881,7 +881,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
}
|
||||
|
||||
let tabContextGesture: (Int32, ContextExtractedContentContainingNode, ContextGesture, Bool) -> Void = { [weak self] id, sourceNode, gesture, keepInPlace in
|
||||
let tabContextGesture: (Int32?, ContextExtractedContentContainingNode, ContextGesture, Bool) -> Void = { [weak self] id, sourceNode, gesture, keepInPlace in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -891,36 +891,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
return
|
||||
}
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_EditFolder, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (currentChatListFilters(postbox: strongSelf.context.account.postbox)
|
||||
|> deliverOnMainQueue).start(next: { presetList in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var found = false
|
||||
for filter in presetList {
|
||||
if filter.id == id {
|
||||
strongSelf.push(chatListFilterPresetController(context: strongSelf.context, currentPreset: filter, updated: { _ in }))
|
||||
f(.dismissWithoutContent)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
f(.default)
|
||||
}
|
||||
})
|
||||
})
|
||||
})))
|
||||
if let filter = filters.first(where: { $0.id == id }), filter.data.includePeers.peers.count < 100 {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_AddChatsToFolder, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
||||
if let id = id {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_EditFolder, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
@ -934,7 +907,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
var found = false
|
||||
for filter in presetList {
|
||||
if filter.id == id {
|
||||
strongSelf.push(chatListFilterAddChatsController(context: strongSelf.context, filter: filter))
|
||||
strongSelf.push(chatListFilterPresetController(context: strongSelf.context, currentPreset: filter, updated: { _ in }))
|
||||
f(.dismissWithoutContent)
|
||||
found = true
|
||||
break
|
||||
@ -946,38 +919,78 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
})
|
||||
})
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_RemoveFolder, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
||||
if let filter = filters.first(where: { $0.id == id }), filter.data.includePeers.peers.count < 100 {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_AddChatsToFolder, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (currentChatListFilters(postbox: strongSelf.context.account.postbox)
|
||||
|> deliverOnMainQueue).start(next: { presetList in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var found = false
|
||||
for filter in presetList {
|
||||
if filter.id == id {
|
||||
strongSelf.push(chatListFilterAddChatsController(context: strongSelf.context, filter: filter))
|
||||
f(.dismissWithoutContent)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
f(.default)
|
||||
}
|
||||
})
|
||||
})
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_RemoveFolder, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.askForFilterRemoval(id: id)
|
||||
})
|
||||
})))
|
||||
}
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_EditFolders, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.askForFilterRemoval(id: id)
|
||||
strongSelf.openFilterSettings()
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
if filters.count > 1 {
|
||||
items.append(.separator)
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_ReorderTabs, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.chatListDisplayNode.isReorderingFilters = true
|
||||
strongSelf.isReorderingTabsValue.set(true)
|
||||
strongSelf.searchContentNode?.setIsEnabled(false, animated: true)
|
||||
(strongSelf.parent as? TabBarController)?.updateIsTabBarEnabled(false, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
if let layout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
})
|
||||
})))
|
||||
|
||||
if filters.count > 1 {
|
||||
items.append(.separator)
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_ReorderTabs, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
//f(.default)
|
||||
c.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.chatListDisplayNode.isReorderingFilters = true
|
||||
strongSelf.isReorderingTabsValue.set(true)
|
||||
strongSelf.searchContentNode?.setIsEnabled(false, animated: true)
|
||||
if let layout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
})
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode, keepInPlace: keepInPlace)), items: .single(items), reactionItems: [], recognizer: nil, gesture: gesture)
|
||||
@ -1114,6 +1127,18 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
})
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.containerNode.didBeginSelectingChats = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing {
|
||||
strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing = true
|
||||
if let layout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !self.processedFeaturedFilters {
|
||||
self.featuredFiltersDisposable.set((
|
||||
self.context.account.postbox.transaction { transaction -> ChatListFiltersFeaturedState? in
|
||||
@ -1213,13 +1238,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.tabContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: self.visualNavigationInsetHeight - self.additionalHeight - 46.0 + tabContainerOffset), size: CGSize(width: layout.size.width, height: 46.0)))
|
||||
self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing, isEditing: false, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||
self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||
if let tabContainerData = self.tabContainerData {
|
||||
self.chatListDisplayNode.inlineTabContainerNode.isHidden = !tabContainerData.1 || tabContainerData.0.count <= 1
|
||||
} else {
|
||||
self.chatListDisplayNode.inlineTabContainerNode.isHidden = true
|
||||
}
|
||||
self.chatListDisplayNode.inlineTabContainerNode.update(size: CGSize(width: layout.size.width, height: 40.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing, isEditing: false, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||
self.chatListDisplayNode.inlineTabContainerNode.update(size: CGSize(width: layout.size.width, height: 40.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||
|
||||
self.chatListDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationInsetHeight, visualNavigationHeight: self.visualNavigationInsetHeight, cleanNavigationBarHeight: self.cleanNavigationHeight, transition: transition)
|
||||
}
|
||||
@ -1240,6 +1265,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
self.searchContentNode?.setIsEnabled(false, animated: true)
|
||||
|
||||
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
||||
self.chatListDisplayNode.containerNode.updateState { state in
|
||||
var state = state
|
||||
state.editing = true
|
||||
@ -1264,6 +1290,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(nil, transition: .animated(duration: 0.4, curve: .spring))
|
||||
self.searchContentNode?.setIsEnabled(true, animated: true)
|
||||
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
||||
self.chatListDisplayNode.containerNode.updateState { state in
|
||||
var state = state
|
||||
state.editing = false
|
||||
@ -1324,6 +1351,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
strongSelf.chatListDisplayNode.isReorderingFilters = false
|
||||
strongSelf.isReorderingTabsValue.set(false)
|
||||
(strongSelf.parent as? TabBarController)?.updateIsTabBarEnabled(true, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
strongSelf.searchContentNode?.setIsEnabled(true, animated: true)
|
||||
if let layout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
@ -1437,6 +1465,19 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
|
||||
private func selectTab(id: ChatListFilterTabEntryId) {
|
||||
if self.parent == nil {
|
||||
if let navigationController = self.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
for controller in navigationController.viewControllers {
|
||||
if let controller = controller as? TabBarController {
|
||||
if let index = controller.controllers.firstIndex(of: self) {
|
||||
controller.selectedIndex = index
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (currentChatListFilters(postbox: self.context.account.postbox)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] filters in
|
||||
guard let strongSelf = self else {
|
||||
@ -2365,9 +2406,15 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
|
||||
private func openFilterSettings() {
|
||||
self.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(false)
|
||||
self.push(chatListFilterPresetListController(context: self.context, mode: .modal, dismissed: { [weak self] in
|
||||
self?.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(true)
|
||||
}))
|
||||
if let navigationController = self.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
navigationController.pushViewController(chatListFilterPresetListController(context: self.context, mode: .modal, dismissed: { [weak self] in
|
||||
self?.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(true)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
override public func tabBarDisabledAction() {
|
||||
self.donePressed()
|
||||
}
|
||||
|
||||
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
|
||||
|
@ -455,6 +455,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
previousItemNode.listNode.contentScrollingEnded = nil
|
||||
previousItemNode.listNode.activateChatPreview = nil
|
||||
previousItemNode.listNode.addedVisibleChatsWithPeerIds = nil
|
||||
previousItemNode.listNode.didBeginSelectingChats = nil
|
||||
|
||||
previousItemNode.accessibilityElementsHidden = true
|
||||
}
|
||||
@ -497,6 +498,9 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
itemNode.listNode.addedVisibleChatsWithPeerIds = { [weak self] ids in
|
||||
self?.addedVisibleChatsWithPeerIds?(ids)
|
||||
}
|
||||
itemNode.listNode.didBeginSelectingChats = { [weak self] in
|
||||
self?.didBeginSelectingChats?()
|
||||
}
|
||||
|
||||
self.currentItemStateValue.set(itemNode.listNode.state)
|
||||
|
||||
@ -517,6 +521,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
var contentScrollingEnded: ((ListView) -> Bool)?
|
||||
var activateChatPreview: ((ChatListItem, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
var addedVisibleChatsWithPeerIds: (([PeerId]) -> Void)?
|
||||
var didBeginSelectingChats: (() -> Void)?
|
||||
|
||||
init(context: AccountContext, groupId: PeerGroupId, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, filterBecameEmpty: @escaping (ChatListFilter?) -> Void, filterEmptyAction: @escaping (ChatListFilter?) -> Void) {
|
||||
self.context = context
|
||||
@ -970,6 +975,7 @@ final class ChatListControllerNode: ASDisplayNode {
|
||||
private(set) var searchDisplayController: SearchDisplayController?
|
||||
|
||||
var isReorderingFilters: Bool = false
|
||||
var didBeginSelectingChatsWhileEditing: Bool = false
|
||||
var isEditing: Bool = false
|
||||
|
||||
private var containerLayout: (ContainerViewLayout, CGFloat, CGFloat, CGFloat)?
|
||||
|
@ -14,6 +14,11 @@ import ItemListPeerItem
|
||||
import ItemListPeerActionItem
|
||||
import AvatarNode
|
||||
|
||||
private enum FilterSection: Int32, Hashable {
|
||||
case include
|
||||
case exclude
|
||||
}
|
||||
|
||||
private final class ChatListFilterPresetControllerArguments {
|
||||
let context: AccountContext
|
||||
let updateState: ((ChatListFilterPresetControllerState) -> ChatListFilterPresetControllerState) -> Void
|
||||
@ -25,6 +30,7 @@ private final class ChatListFilterPresetControllerArguments {
|
||||
let deleteIncludeCategory: (ChatListFilterIncludeCategory) -> Void
|
||||
let deleteExcludeCategory: (ChatListFilterExcludeCategory) -> Void
|
||||
let focusOnName: () -> Void
|
||||
let expandSection: (FilterSection) -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
@ -36,7 +42,8 @@ private final class ChatListFilterPresetControllerArguments {
|
||||
setItemIdWithRevealedOptions: @escaping (ChatListFilterRevealedItemId?, ChatListFilterRevealedItemId?) -> Void,
|
||||
deleteIncludeCategory: @escaping (ChatListFilterIncludeCategory) -> Void,
|
||||
deleteExcludeCategory: @escaping (ChatListFilterExcludeCategory) -> Void,
|
||||
focusOnName: @escaping () -> Void
|
||||
focusOnName: @escaping () -> Void,
|
||||
expandSection: @escaping (FilterSection) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.updateState = updateState
|
||||
@ -48,6 +55,7 @@ private final class ChatListFilterPresetControllerArguments {
|
||||
self.deleteIncludeCategory = deleteIncludeCategory
|
||||
self.deleteExcludeCategory = deleteExcludeCategory
|
||||
self.focusOnName = focusOnName
|
||||
self.expandSection = expandSection
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +73,8 @@ private enum ChatListFilterPresetEntryStableId: Hashable {
|
||||
case excludePeerInfo
|
||||
case includeCategory(ChatListFilterIncludeCategory)
|
||||
case excludeCategory(ChatListFilterExcludeCategory)
|
||||
case includeExpand
|
||||
case excludeExpand
|
||||
}
|
||||
|
||||
private enum ChatListFilterPresetEntrySortId: Comparable {
|
||||
@ -222,6 +232,8 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||
case excludeCategory(index: Int, category: ChatListFilterExcludeCategory, title: String, isRevealed: Bool)
|
||||
case excludePeer(index: Int, peer: RenderedPeer, isRevealed: Bool)
|
||||
case excludePeerInfo(String)
|
||||
case includeExpand(String)
|
||||
case excludeExpand(String)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
@ -229,9 +241,9 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||
return ChatListFilterPresetControllerSection.screenHeader.rawValue
|
||||
case .nameHeader, .name:
|
||||
return ChatListFilterPresetControllerSection.name.rawValue
|
||||
case .includePeersHeader, .addIncludePeer, .includeCategory, .includePeer, .includePeerInfo:
|
||||
case .includePeersHeader, .addIncludePeer, .includeCategory, .includePeer, .includePeerInfo, .includeExpand:
|
||||
return ChatListFilterPresetControllerSection.includePeers.rawValue
|
||||
case .excludePeersHeader, .addExcludePeer, .excludeCategory, .excludePeer, .excludePeerInfo:
|
||||
case .excludePeersHeader, .addExcludePeer, .excludeCategory, .excludePeer, .excludePeerInfo, .excludeExpand:
|
||||
return ChatListFilterPresetControllerSection.excludePeers.rawValue
|
||||
}
|
||||
}
|
||||
@ -250,16 +262,20 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||
return .index(4)
|
||||
case let .includeCategory(includeCategory):
|
||||
return .includeCategory(includeCategory.category)
|
||||
case .includePeerInfo:
|
||||
case .includeExpand:
|
||||
return .index(5)
|
||||
case .excludePeersHeader:
|
||||
case .includePeerInfo:
|
||||
return .index(6)
|
||||
case .addExcludePeer:
|
||||
case .excludePeersHeader:
|
||||
return .index(7)
|
||||
case .addExcludePeer:
|
||||
return .index(8)
|
||||
case let .excludeCategory(excludeCategory):
|
||||
return .excludeCategory(excludeCategory.category)
|
||||
case .excludeExpand:
|
||||
return .index(9)
|
||||
case .excludePeerInfo:
|
||||
return .index(8)
|
||||
return .index(10)
|
||||
case let .includePeer(peer):
|
||||
return .peer(peer.peer.peerId)
|
||||
case let .excludePeer(peer):
|
||||
@ -283,6 +299,8 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||
return .includeIndex(2 + includeCategory.index)
|
||||
case let .includePeer(includePeer):
|
||||
return .includeIndex(200 + includePeer.index)
|
||||
case .includeExpand:
|
||||
return .includeIndex(999)
|
||||
case .includePeerInfo:
|
||||
return .includeIndex(1000)
|
||||
case .excludePeersHeader:
|
||||
@ -293,6 +311,8 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||
return .excludeIndex(2 + excludeCategory.index)
|
||||
case let .excludePeer(excludePeer):
|
||||
return .excludeIndex(200 + excludePeer.index)
|
||||
case .excludeExpand:
|
||||
return .excludeIndex(999)
|
||||
case .excludePeerInfo:
|
||||
return .excludeIndex(1000)
|
||||
}
|
||||
@ -384,6 +404,14 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||
}, removePeer: { id in
|
||||
arguments.deleteExcludePeer(id)
|
||||
})
|
||||
case let .includeExpand(text):
|
||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(presentationData.theme), title: text, sectionId: self.section, editing: false, action: {
|
||||
arguments.expandSection(.include)
|
||||
})
|
||||
case let .excludeExpand(text):
|
||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(presentationData.theme), title: text, sectionId: self.section, editing: false, action: {
|
||||
arguments.expandSection(.exclude)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -399,6 +427,7 @@ private struct ChatListFilterPresetControllerState: Equatable {
|
||||
var additionallyExcludePeers: [PeerId]
|
||||
|
||||
var revealedItemId: ChatListFilterRevealedItemId?
|
||||
var expandedSections: Set<FilterSection>
|
||||
|
||||
var isComplete: Bool {
|
||||
if self.name.isEmpty {
|
||||
@ -446,8 +475,18 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
||||
includeCategoryIndex += 1
|
||||
}
|
||||
|
||||
for peer in includePeers {
|
||||
entries.append(.includePeer(index: entries.count, peer: peer, isRevealed: state.revealedItemId == .peer(peer.peerId)))
|
||||
if !includePeers.isEmpty {
|
||||
var count = 0
|
||||
for peer in includePeers {
|
||||
entries.append(.includePeer(index: entries.count, peer: peer, isRevealed: state.revealedItemId == .peer(peer.peerId)))
|
||||
count += 1
|
||||
if includePeers.count >= 6 && count == 5 && !state.expandedSections.contains(.include) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if count < includePeers.count {
|
||||
entries.append(.includeExpand(presentationData.strings.ChatListFilter_ShowMoreChats(Int32(includePeers.count - count))))
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.includePeerInfo(presentationData.strings.ChatListFolder_IncludeSectionInfo))
|
||||
@ -473,8 +512,18 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
||||
excludeCategoryIndex += 1
|
||||
}
|
||||
|
||||
for peer in excludePeers {
|
||||
entries.append(.excludePeer(index: entries.count, peer: peer, isRevealed: state.revealedItemId == .peer(peer.peerId)))
|
||||
if !excludePeers.isEmpty {
|
||||
var count = 0
|
||||
for peer in excludePeers {
|
||||
entries.append(.excludePeer(index: entries.count, peer: peer, isRevealed: state.revealedItemId == .peer(peer.peerId)))
|
||||
count += 1
|
||||
if excludePeers.count >= 6 && count == 5 && !state.expandedSections.contains(.exclude) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if count < excludePeers.count {
|
||||
entries.append(.excludeExpand(presentationData.strings.ChatListFilter_ShowMoreChats(Int32(excludePeers.count - count))))
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.excludePeerInfo(presentationData.strings.ChatListFolder_ExcludeSectionInfo))
|
||||
@ -732,7 +781,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
} else {
|
||||
initialName = ""
|
||||
}
|
||||
let initialState = ChatListFilterPresetControllerState(name: initialName, changedName: currentPreset != nil, includeCategories: currentPreset?.data.categories ?? [], excludeMuted: currentPreset?.data.excludeMuted ?? false, excludeRead: currentPreset?.data.excludeRead ?? false, excludeArchived: currentPreset?.data.excludeArchived ?? false, additionallyIncludePeers: currentPreset?.data.includePeers.peers ?? [], additionallyExcludePeers: currentPreset?.data.excludePeers ?? [])
|
||||
let initialState = ChatListFilterPresetControllerState(name: initialName, changedName: currentPreset != nil, includeCategories: currentPreset?.data.categories ?? [], excludeMuted: currentPreset?.data.excludeMuted ?? false, excludeRead: currentPreset?.data.excludeRead ?? false, excludeArchived: currentPreset?.data.excludeArchived ?? false, additionallyIncludePeers: currentPreset?.data.includePeers.peers ?? [], additionallyExcludePeers: currentPreset?.data.excludePeers ?? [], expandedSections: [])
|
||||
let stateValue = Atomic(value: initialState)
|
||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||
let updateState: ((ChatListFilterPresetControllerState) -> ChatListFilterPresetControllerState) -> Void = { f in
|
||||
@ -870,6 +919,13 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
},
|
||||
focusOnName: {
|
||||
focusOnNameImpl?()
|
||||
},
|
||||
expandSection: { section in
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.expandedSections.insert(section)
|
||||
return state
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@ -922,7 +978,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
}
|
||||
|
||||
var attemptNavigationImpl: (() -> Bool)?
|
||||
var applyImpl: (() -> Void)? = {
|
||||
let applyImpl: (() -> Void)? = {
|
||||
let state = stateValue.with { $0 }
|
||||
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
|
||||
var includePeers = ChatListFilterIncludePeers()
|
||||
@ -963,6 +1019,8 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
})
|
||||
}
|
||||
|
||||
var previousState = stateValue.with { $0 }
|
||||
|
||||
let signal = combineLatest(queue: .mainQueue(),
|
||||
context.sharedContext.presentationData,
|
||||
stateWithPeers
|
||||
@ -980,6 +1038,12 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
applyImpl?()
|
||||
})
|
||||
|
||||
let previousStateValue = previousState
|
||||
previousState = state
|
||||
if previousStateValue.expandedSections != state.expandedSections {
|
||||
skipStateAnimation = true
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(currentPreset != nil ? presentationData.strings.ChatListFolder_TitleEdit : presentationData.strings.ChatListFolder_TitleCreate), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: chatListFilterPresetControllerEntries(presentationData: presentationData, isNewFilter: currentPreset == nil, state: state, includePeers: includePeers, excludePeers: excludePeers), style: .blocks, emptyStateItem: nil, animateChanges: !skipStateAnimation)
|
||||
skipStateAnimation = false
|
||||
|
@ -91,12 +91,16 @@ private final class ItemNode: ASDisplayNode {
|
||||
self.extractedBackgroundNode = ASImageNode()
|
||||
self.extractedBackgroundNode.alpha = 0.0
|
||||
|
||||
let titleInset: CGFloat = 4.0
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
self.titleNode.displaysAsynchronously = false
|
||||
self.titleNode.insets = UIEdgeInsets(top: titleInset, left: 0.0, bottom: titleInset, right: 0.0)
|
||||
|
||||
self.shortTitleNode = ImmediateTextNode()
|
||||
self.shortTitleNode.displaysAsynchronously = false
|
||||
self.shortTitleNode.alpha = 0.0
|
||||
self.shortTitleNode.insets = UIEdgeInsets(top: titleInset, left: 0.0, bottom: titleInset, right: 0.0)
|
||||
|
||||
self.badgeContainerNode = ASDisplayNode()
|
||||
|
||||
@ -166,7 +170,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
self.badgeBackgroundInactiveNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: presentationData.theme.chatList.unreadBadgeInactiveBackgroundColor)
|
||||
}
|
||||
|
||||
self.containerNode.isGestureEnabled = !isNoFilter && !isEditing && !isReordering
|
||||
self.containerNode.isGestureEnabled = !isEditing && !isReordering
|
||||
self.buttonNode.isUserInteractionEnabled = !isEditing && !isReordering
|
||||
|
||||
self.isSelected = isSelected
|
||||
@ -217,10 +221,10 @@ private final class ItemNode: ASDisplayNode {
|
||||
|
||||
func updateLayout(height: CGFloat, transition: ContainedViewLayoutTransition) -> (width: CGFloat, shortWidth: CGFloat) {
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: 160.0, height: .greatestFiniteMagnitude))
|
||||
self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
||||
self.titleNode.frame = CGRect(origin: CGPoint(x: -self.titleNode.insets.left, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
||||
|
||||
let shortTitleSize = self.shortTitleNode.updateLayout(CGSize(width: 160.0, height: .greatestFiniteMagnitude))
|
||||
self.shortTitleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - shortTitleSize.height) / 2.0)), size: shortTitleSize)
|
||||
self.shortTitleNode.frame = CGRect(origin: CGPoint(x: -self.shortTitleNode.insets.left, y: floor((height - shortTitleSize.height) / 2.0)), size: shortTitleSize)
|
||||
|
||||
if let deleteButtonNode = self.deleteButtonNode {
|
||||
if let theme = self.theme {
|
||||
@ -231,7 +235,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
|
||||
let badgeSize = self.badgeTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
||||
let badgeInset: CGFloat = 4.0
|
||||
let badgeBackgroundFrame = CGRect(origin: CGPoint(x: titleSize.width + 5.0, y: floor((height - 18.0) / 2.0)), size: CGSize(width: max(18.0, badgeSize.width + badgeInset * 2.0), height: 18.0))
|
||||
let badgeBackgroundFrame = CGRect(origin: CGPoint(x: titleSize.width - self.titleNode.insets.left - self.titleNode.insets.right + 5.0 + 5.0, y: floor((height - 18.0) / 2.0)), size: CGSize(width: max(18.0, badgeSize.width + badgeInset * 2.0), height: 18.0))
|
||||
self.badgeContainerNode.frame = badgeBackgroundFrame
|
||||
self.badgeBackgroundActiveNode.frame = CGRect(origin: CGPoint(), size: badgeBackgroundFrame.size)
|
||||
self.badgeBackgroundInactiveNode.frame = CGRect(origin: CGPoint(), size: badgeBackgroundFrame.size)
|
||||
@ -242,7 +246,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
if !self.isReordering {
|
||||
self.badgeContainerNode.alpha = 0.0
|
||||
}
|
||||
width = titleSize.width
|
||||
width = titleSize.width - self.titleNode.insets.left - self.titleNode.insets.right
|
||||
} else {
|
||||
if !self.isReordering {
|
||||
self.badgeContainerNode.alpha = 1.0
|
||||
@ -254,7 +258,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
let extractedBackgroundInset: CGFloat = 14.0
|
||||
self.extractedBackgroundNode.frame = CGRect(origin: CGPoint(x: -extractedBackgroundInset, y: floor((height - extractedBackgroundHeight) / 2.0)), size: CGSize(width: width + extractedBackgroundInset * 2.0, height: extractedBackgroundHeight))
|
||||
|
||||
return (width, shortTitleSize.width)
|
||||
return (width, shortTitleSize.width - self.shortTitleNode.insets.left - self.shortTitleNode.insets.right + 5.0)
|
||||
}
|
||||
|
||||
func updateArea(size: CGSize, sideInset: CGFloat, useShortTitle: Bool, transition: ContainedViewLayoutTransition) {
|
||||
@ -397,7 +401,7 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
|
||||
var tabSelected: ((ChatListFilterTabEntryId) -> Void)?
|
||||
var tabRequestedDeletion: ((ChatListFilterTabEntryId) -> Void)?
|
||||
var addFilter: (() -> Void)?
|
||||
var contextGesture: ((Int32, ContextExtractedContentContainingNode, ContextGesture) -> Void)?
|
||||
var contextGesture: ((Int32?, ContextExtractedContentContainingNode, ContextGesture) -> Void)?
|
||||
|
||||
private var reorderingGesture: ReorderingGestureRecognizer?
|
||||
private var reorderingItem: ChatListFilterTabEntryId?
|
||||
@ -641,14 +645,14 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = false
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = true
|
||||
strongSelf.scrollNode.view.setContentOffset(strongSelf.scrollNode.view.contentOffset, animated: false)
|
||||
switch filter {
|
||||
case let .filter(filter):
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = false
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = true
|
||||
strongSelf.scrollNode.view.setContentOffset(strongSelf.scrollNode.view.contentOffset, animated: false)
|
||||
strongSelf.contextGesture?(filter.id, sourceNode, gesture)
|
||||
default:
|
||||
break
|
||||
strongSelf.contextGesture?(nil, sourceNode, gesture)
|
||||
}
|
||||
})
|
||||
self.itemNodes[filter.id] = itemNode
|
||||
|
@ -91,12 +91,16 @@ private final class ItemNode: ASDisplayNode {
|
||||
self.extractedBackgroundNode = ASImageNode()
|
||||
self.extractedBackgroundNode.alpha = 0.0
|
||||
|
||||
let titleInset: CGFloat = 4.0
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
self.titleNode.displaysAsynchronously = false
|
||||
self.titleNode.insets = UIEdgeInsets(top: titleInset, left: 0.0, bottom: titleInset, right: 0.0)
|
||||
|
||||
self.shortTitleNode = ImmediateTextNode()
|
||||
self.shortTitleNode.displaysAsynchronously = false
|
||||
self.shortTitleNode.alpha = 0.0
|
||||
self.shortTitleNode.insets = UIEdgeInsets(top: titleInset, left: 0.0, bottom: titleInset, right: 0.0)
|
||||
|
||||
self.badgeContainerNode = ASDisplayNode()
|
||||
|
||||
@ -166,7 +170,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
self.badgeBackgroundInactiveNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: presentationData.theme.chatList.unreadBadgeInactiveBackgroundColor)
|
||||
}
|
||||
|
||||
self.containerNode.isGestureEnabled = !isNoFilter && !isEditing && !isReordering
|
||||
self.containerNode.isGestureEnabled = !isEditing && !isReordering
|
||||
self.buttonNode.isUserInteractionEnabled = !isEditing && !isReordering
|
||||
|
||||
self.isSelected = isSelected
|
||||
@ -217,10 +221,10 @@ private final class ItemNode: ASDisplayNode {
|
||||
|
||||
func updateLayout(height: CGFloat, transition: ContainedViewLayoutTransition) -> (width: CGFloat, shortWidth: CGFloat) {
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: 160.0, height: .greatestFiniteMagnitude))
|
||||
self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
||||
self.titleNode.frame = CGRect(origin: CGPoint(x: -self.titleNode.insets.left, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
||||
|
||||
let shortTitleSize = self.shortTitleNode.updateLayout(CGSize(width: 160.0, height: .greatestFiniteMagnitude))
|
||||
self.shortTitleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - shortTitleSize.height) / 2.0)), size: shortTitleSize)
|
||||
self.shortTitleNode.frame = CGRect(origin: CGPoint(x: -self.shortTitleNode.insets.left, y: floor((height - shortTitleSize.height) / 2.0)), size: shortTitleSize)
|
||||
|
||||
if let deleteButtonNode = self.deleteButtonNode {
|
||||
if let theme = self.theme {
|
||||
@ -231,7 +235,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
|
||||
let badgeSize = self.badgeTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
||||
let badgeInset: CGFloat = 4.0
|
||||
let badgeBackgroundFrame = CGRect(origin: CGPoint(x: titleSize.width + 5.0, y: floor((height - 18.0) / 2.0)), size: CGSize(width: max(18.0, badgeSize.width + badgeInset * 2.0), height: 18.0))
|
||||
let badgeBackgroundFrame = CGRect(origin: CGPoint(x: titleSize.width - self.titleNode.insets.left - self.titleNode.insets.right + 5.0, y: floor((height - 18.0) / 2.0)), size: CGSize(width: max(18.0, badgeSize.width + badgeInset * 2.0), height: 18.0))
|
||||
self.badgeContainerNode.frame = badgeBackgroundFrame
|
||||
self.badgeBackgroundActiveNode.frame = CGRect(origin: CGPoint(), size: badgeBackgroundFrame.size)
|
||||
self.badgeBackgroundInactiveNode.frame = CGRect(origin: CGPoint(), size: badgeBackgroundFrame.size)
|
||||
@ -242,7 +246,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
if !self.isReordering {
|
||||
self.badgeContainerNode.alpha = 0.0
|
||||
}
|
||||
width = titleSize.width
|
||||
width = titleSize.width - self.titleNode.insets.left - self.titleNode.insets.right
|
||||
} else {
|
||||
if !self.isReordering {
|
||||
self.badgeContainerNode.alpha = 1.0
|
||||
@ -254,7 +258,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
let extractedBackgroundInset: CGFloat = 14.0
|
||||
self.extractedBackgroundNode.frame = CGRect(origin: CGPoint(x: -extractedBackgroundInset, y: floor((height - extractedBackgroundHeight) / 2.0)), size: CGSize(width: width + extractedBackgroundInset * 2.0, height: extractedBackgroundHeight))
|
||||
|
||||
return (width, shortTitleSize.width)
|
||||
return (width, shortTitleSize.width - self.shortTitleNode.insets.left - self.shortTitleNode.insets.right)
|
||||
}
|
||||
|
||||
func updateArea(size: CGSize, sideInset: CGFloat, useShortTitle: Bool, transition: ContainedViewLayoutTransition) {
|
||||
@ -371,7 +375,7 @@ final class ChatListFilterTabInlineContainerNode: ASDisplayNode {
|
||||
var tabSelected: ((ChatListFilterTabEntryId) -> Void)?
|
||||
var tabRequestedDeletion: ((ChatListFilterTabEntryId) -> Void)?
|
||||
var addFilter: (() -> Void)?
|
||||
var contextGesture: ((Int32, ContextExtractedContentContainingNode, ContextGesture) -> Void)?
|
||||
var contextGesture: ((Int32?, ContextExtractedContentContainingNode, ContextGesture) -> Void)?
|
||||
|
||||
private var reorderingGesture: ReorderingGestureRecognizer?
|
||||
private var reorderingItem: ChatListFilterTabEntryId?
|
||||
@ -645,14 +649,14 @@ final class ChatListFilterTabInlineContainerNode: ASDisplayNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = false
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = true
|
||||
strongSelf.scrollNode.view.setContentOffset(strongSelf.scrollNode.view.contentOffset, animated: false)
|
||||
switch filter {
|
||||
case let .filter(filter):
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = false
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = true
|
||||
strongSelf.scrollNode.view.setContentOffset(strongSelf.scrollNode.view.contentOffset, animated: false)
|
||||
strongSelf.contextGesture?(filter.id, sourceNode, gesture)
|
||||
default:
|
||||
break
|
||||
strongSelf.contextGesture?(nil, sourceNode, gesture)
|
||||
}
|
||||
}), highlighted: ItemNode(pressed: { [weak self] in
|
||||
self?.tabSelected?(filter.id)
|
||||
@ -669,7 +673,7 @@ final class ChatListFilterTabInlineContainerNode: ASDisplayNode {
|
||||
strongSelf.scrollNode.view.setContentOffset(strongSelf.scrollNode.view.contentOffset, animated: false)
|
||||
strongSelf.contextGesture?(filter.id, sourceNode, gesture)
|
||||
default:
|
||||
break
|
||||
strongSelf.contextGesture?(nil, sourceNode, gesture)
|
||||
}
|
||||
}))
|
||||
self.itemNodePairs[filter.id] = itemNodePair
|
||||
|
@ -487,6 +487,8 @@ public final class ChatListNode: ListView {
|
||||
|
||||
let preloadItems = Promise<[ChatHistoryPreloadItem]>([])
|
||||
|
||||
var didBeginSelectingChats: (() -> Void)?
|
||||
|
||||
public init(context: AccountContext, groupId: PeerGroupId, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
|
||||
self.context = context
|
||||
self.groupId = groupId
|
||||
@ -525,17 +527,24 @@ public final class ChatListNode: ListView {
|
||||
disabledPeerSelected(peer)
|
||||
}
|
||||
}, togglePeerSelected: { [weak self] peerId in
|
||||
var didBeginSelecting = false
|
||||
self?.updateState { state in
|
||||
var state = state
|
||||
if state.selectedPeerIds.contains(peerId) {
|
||||
state.selectedPeerIds.remove(peerId)
|
||||
} else {
|
||||
if state.selectedPeerIds.count < 100 {
|
||||
if state.selectedPeerIds.isEmpty {
|
||||
didBeginSelecting = true
|
||||
}
|
||||
state.selectedPeerIds.insert(peerId)
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
if didBeginSelecting {
|
||||
self?.didBeginSelectingChats?()
|
||||
}
|
||||
}, additionalCategorySelected: { [weak self] id in
|
||||
self?.additionalCategorySelected?(id)
|
||||
}, messageSelected: { [weak self] peer, message, isAd in
|
||||
|
@ -51,7 +51,7 @@ func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilt
|
||||
|
||||
var result: [(ChatListFilter, Int, Bool)] = []
|
||||
|
||||
var peerTagAndCount: [PeerId: (PeerSummaryCounterTags, Int, Bool)] = [:]
|
||||
var peerTagAndCount: [PeerId: (PeerSummaryCounterTags, Int, Bool, PeerGroupId?)] = [:]
|
||||
|
||||
var totalStates: [PeerGroupId: ChatListTotalUnreadState] = [:]
|
||||
for entry in unreadCounts.entries {
|
||||
@ -71,9 +71,9 @@ func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilt
|
||||
}
|
||||
|
||||
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings, case .muted = notificationSettings.muteState {
|
||||
peerTagAndCount[peerId] = (tag, peerCount, false)
|
||||
peerTagAndCount[peerId] = (tag, peerCount, false, peerView.groupId)
|
||||
} else {
|
||||
peerTagAndCount[peerId] = (tag, peerCount, true)
|
||||
peerTagAndCount[peerId] = (tag, peerCount, true, peerView.groupId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,9 +147,20 @@ func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilt
|
||||
}
|
||||
}
|
||||
for peerId in filter.data.includePeers.peers {
|
||||
if let (tag, peerCount, hasUnmuted) = peerTagAndCount[peerId] {
|
||||
if !tags.contains(tag) {
|
||||
if peerCount != 0 {
|
||||
if let (tag, peerCount, hasUnmuted, groupId) = peerTagAndCount[peerId] {
|
||||
if let groupId = groupId, !tags.contains(tag) {
|
||||
let matchesGroup: Bool
|
||||
switch groupId {
|
||||
case .root:
|
||||
matchesGroup = true
|
||||
case .group:
|
||||
if groupId == Namespaces.PeerGroup.archive {
|
||||
matchesGroup = !filter.data.excludeArchived
|
||||
} else {
|
||||
matchesGroup = false
|
||||
}
|
||||
}
|
||||
if matchesGroup && peerCount != 0 {
|
||||
count += 1
|
||||
if hasUnmuted {
|
||||
hasUnmutedUnread = true
|
||||
@ -159,9 +170,20 @@ func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilt
|
||||
}
|
||||
}
|
||||
for peerId in filter.data.excludePeers {
|
||||
if let (tag, peerCount, _) = peerTagAndCount[peerId] {
|
||||
if tags.contains(tag) {
|
||||
if peerCount != 0 {
|
||||
if let (tag, peerCount, _, groupId) = peerTagAndCount[peerId] {
|
||||
if let groupId = groupId, tags.contains(tag) {
|
||||
let matchesGroup: Bool
|
||||
switch groupId {
|
||||
case .root:
|
||||
matchesGroup = true
|
||||
case .group:
|
||||
if groupId == Namespaces.PeerGroup.archive {
|
||||
matchesGroup = !filter.data.excludeArchived
|
||||
} else {
|
||||
matchesGroup = false
|
||||
}
|
||||
}
|
||||
if matchesGroup && peerCount != 0 {
|
||||
count -= 1
|
||||
}
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ public enum ToolbarActionOption {
|
||||
final class TabBarControllerNode: ASDisplayNode {
|
||||
private var theme: TabBarControllerTheme
|
||||
let tabBarNode: TabBarNode
|
||||
private let disabledOverlayNode: ASDisplayNode
|
||||
private let navigationBar: NavigationBar?
|
||||
private var toolbarNode: ToolbarNode?
|
||||
private let toolbarActionSelected: (ToolbarActionOption) -> Void
|
||||
private let disabledPressed: () -> Void
|
||||
|
||||
var currentControllerNode: ASDisplayNode? {
|
||||
didSet {
|
||||
@ -25,11 +27,15 @@ final class TabBarControllerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
init(theme: TabBarControllerTheme, navigationBar: NavigationBar?, itemSelected: @escaping (Int, Bool, [ASDisplayNode]) -> Void, contextAction: @escaping (Int, ContextExtractedContentContainingNode, ContextGesture) -> Void, swipeAction: @escaping (Int, TabBarItemSwipeDirection) -> Void, toolbarActionSelected: @escaping (ToolbarActionOption) -> Void) {
|
||||
init(theme: TabBarControllerTheme, navigationBar: NavigationBar?, itemSelected: @escaping (Int, Bool, [ASDisplayNode]) -> Void, contextAction: @escaping (Int, ContextExtractedContentContainingNode, ContextGesture) -> Void, swipeAction: @escaping (Int, TabBarItemSwipeDirection) -> Void, toolbarActionSelected: @escaping (ToolbarActionOption) -> Void, disabledPressed: @escaping () -> Void) {
|
||||
self.theme = theme
|
||||
self.navigationBar = navigationBar
|
||||
self.tabBarNode = TabBarNode(theme: theme, itemSelected: itemSelected, contextAction: contextAction, swipeAction: swipeAction)
|
||||
self.disabledOverlayNode = ASDisplayNode()
|
||||
self.disabledOverlayNode.backgroundColor = theme.backgroundColor.withAlphaComponent(0.5)
|
||||
self.disabledOverlayNode.alpha = 0.0
|
||||
self.toolbarActionSelected = toolbarActionSelected
|
||||
self.disabledPressed = disabledPressed
|
||||
|
||||
super.init()
|
||||
|
||||
@ -40,6 +46,19 @@ final class TabBarControllerNode: ASDisplayNode {
|
||||
self.backgroundColor = theme.backgroundColor
|
||||
|
||||
self.addSubnode(self.tabBarNode)
|
||||
self.addSubnode(self.disabledOverlayNode)
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.disabledOverlayNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.disabledTapGesture(_:))))
|
||||
}
|
||||
|
||||
@objc private func disabledTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.disabledPressed()
|
||||
}
|
||||
}
|
||||
|
||||
func updateTheme(_ theme: TabBarControllerTheme) {
|
||||
@ -47,9 +66,14 @@ final class TabBarControllerNode: ASDisplayNode {
|
||||
self.backgroundColor = theme.backgroundColor
|
||||
|
||||
self.tabBarNode.updateTheme(theme)
|
||||
self.disabledOverlayNode.backgroundColor = theme.backgroundColor.withAlphaComponent(0.5)
|
||||
self.toolbarNode?.updateTheme(theme)
|
||||
}
|
||||
|
||||
func updateIsTabBarEnabled(_ value: Bool, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateAlpha(node: self.disabledOverlayNode, alpha: value ? 0.0 : 1.0)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, toolbar: Toolbar?, transition: ContainedViewLayoutTransition) {
|
||||
var tabBarHeight: CGFloat
|
||||
var options: ContainerViewLayoutInsetOptions = []
|
||||
@ -68,6 +92,8 @@ final class TabBarControllerNode: ASDisplayNode {
|
||||
transition.updateFrame(node: self.tabBarNode, frame: tabBarFrame)
|
||||
self.tabBarNode.updateLayout(size: layout.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: bottomInset, transition: transition)
|
||||
|
||||
transition.updateFrame(node: self.disabledOverlayNode, frame: tabBarFrame)
|
||||
|
||||
if let toolbar = toolbar {
|
||||
if let toolbarNode = self.toolbarNode {
|
||||
transition.updateFrame(node: toolbarNode, frame: tabBarFrame)
|
||||
|
@ -181,6 +181,10 @@ open class TabBarController: ViewController {
|
||||
return false
|
||||
}
|
||||
|
||||
public func updateIsTabBarEnabled(_ value: Bool, transition: ContainedViewLayoutTransition) {
|
||||
self.tabBarControllerNode.updateIsTabBarEnabled(value, transition: transition)
|
||||
}
|
||||
|
||||
override open func loadDisplayNode() {
|
||||
self.displayNode = TabBarControllerNode(theme: self.theme, navigationBar: self.navigationBar, itemSelected: { [weak self] index, longTap, itemNodes in
|
||||
if let strongSelf = self {
|
||||
@ -264,6 +268,8 @@ open class TabBarController: ViewController {
|
||||
}
|
||||
}, toolbarActionSelected: { [weak self] action in
|
||||
self?.currentController?.toolbarActionSelected(action: action)
|
||||
}, disabledPressed: { [weak self] in
|
||||
self?.currentController?.tabBarDisabledAction()
|
||||
})
|
||||
|
||||
self.updateSelectedIndex()
|
||||
|
@ -636,6 +636,9 @@ public enum TabBarItemContextActionType {
|
||||
open func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
|
||||
}
|
||||
|
||||
open func tabBarDisabledAction() {
|
||||
}
|
||||
|
||||
open func tabBarItemSwipeAction(direction: TabBarItemSwipeDirection) {
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -278,7 +278,7 @@ final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
if width - currentOffset.x < 200.0 {
|
||||
if width - currentOffset.x < 90.0 {
|
||||
currentOffset.y += 28.0
|
||||
currentOffset.x = sideInset
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user