Folder improvements

This commit is contained in:
Ali 2020-03-19 00:24:27 +04:00
parent d3c82bdfb9
commit a1a5b12125
14 changed files with 4013 additions and 3810 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -636,6 +636,9 @@ public enum TabBarItemContextActionType {
open func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
}
open func tabBarDisabledAction() {
}
open func tabBarItemSwipeAction(direction: TabBarItemSwipeDirection) {
}
}

View File

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