mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Tab fixes
This commit is contained in:
parent
dd0b7b2b2a
commit
e5f3d2df63
@ -165,8 +165,8 @@ swift_library(
|
||||
"//submodules/PasswordSetupUI:PasswordSetupUIAssets",
|
||||
"//submodules/TelegramUI:TelegramUIResources",
|
||||
"//submodules/TelegramUI:TelegramUIAssets",
|
||||
"//submodules/WalletUI:WalletUIResources",
|
||||
"//submodules/WalletUI:WalletUIAssets",
|
||||
#"//submodules/WalletUI:WalletUIResources",
|
||||
#"//submodules/WalletUI:WalletUIAssets",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/TelegramUI:TelegramUI",
|
||||
|
@ -5354,7 +5354,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"ChatList.EmptyChatListNewMessage" = "New Message";
|
||||
"ChatList.EmptyChatListEditFilter" = "Edit Folder";
|
||||
|
||||
"ChatListFilter.AddChatsTitle" = "Add Chats";
|
||||
"ChatListFilter.AddChatsTitle" = "Add Chats...";
|
||||
|
||||
"Stats.Overview" = "OVERVIEW";
|
||||
"Stats.Followers" = "Followers";
|
||||
@ -5393,3 +5393,62 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"InstantPage.Views_many" = "%@ views";
|
||||
"InstantPage.Views_any" = "%@ views";
|
||||
"InstantPage.FeedbackButtonShort" = "Leave feedback";
|
||||
|
||||
"ChatList.EditFolder" = "Edit Folder";
|
||||
"ChatList.AddChatsToFolder" = "Add Chats";
|
||||
"ChatList.RemoveFolderConfirmation" = "This will remove the folder, your chats will not be deleted.";
|
||||
"ChatList.RemoveFolderAction" = "Remove";
|
||||
"ChatList.RemoveFolder" = "Remove";
|
||||
"ChatList.ReorderTabs" = "Reorder Tabs";
|
||||
"ChatList.TabIconFoldersTooltipNonEmptyFolders" = "Hold on 'Chats' to edit folders and switch between views.";
|
||||
"ChatList.TabIconFoldersTooltipEmptyFolders" = "Hold to organize your chats with folders.";
|
||||
"ChatList.AddFolder" = "Add Folder";
|
||||
"ChatList.EditFolders" = "Edit Folders";
|
||||
"ChatList.FolderAllChats" = "All Chats";
|
||||
"ChatList.Tabs.AllChats" = "All Chats";
|
||||
"ChatList.Tabs.All" = "All";
|
||||
"Settings.ChatFolders" = "Chat Folders";
|
||||
"ChatList.ChatTypesSection" = "CHAT TYPES";
|
||||
"ChatList.PeerTypeNonContact" = "user";
|
||||
"ChatList.PeerTypeContact" = "contact";
|
||||
"ChatList.PeerTypeBot" = "bot";
|
||||
"ChatList.PeerTypeGroup" = "group";
|
||||
"ChatList.PeerTypeChannel" = "channel";
|
||||
"ChatListFolderSettings.Info" = "Create folders for different groups of chats and\nquickly switch between them.";
|
||||
|
||||
"ChatListFolderSettings.Title" = "Folders";
|
||||
"ChatListFolderSettings.FoldersSection" = "FOLDERS";
|
||||
"ChatListFolderSettings.NewFolder" = "Create New Folder";
|
||||
"ChatListFolderSettings.EditFoldersInfo" = "Tap \"Edit\" to change the order or delete folders.";
|
||||
"ChatListFolderSettings.RecommendedFoldersSection" = "RECOMMENDED FOLDERS";
|
||||
"ChatListFolderSettings.RecommendedNewFolder" = "Add Custom Folder";
|
||||
|
||||
"ChatListFolder.TitleCreate" = "New Folder";
|
||||
"ChatListFolder.TitleEdit" = "Edit Folder";
|
||||
"ChatListFolder.CategoryContacts" = "Contacts";
|
||||
"ChatListFolder.CategoryNonContacts" = "Non-Contacts";
|
||||
"ChatListFolder.CategoryBots" = "Bots";
|
||||
"ChatListFolder.CategoryGroups" = "Groups";
|
||||
"ChatListFolder.CategoryChannels" = "Channels";
|
||||
"ChatListFolder.CategoryMuted" = "Muted";
|
||||
"ChatListFolder.CategoryRead" = "Muted";
|
||||
"ChatListFolder.CategoryArchived" = "Archived";
|
||||
"ChatListFolder.NameSectionHeader" = "FOLDER NAME";
|
||||
"ChatListFolder.NamePlaceholder" = "Folder Name";
|
||||
"ChatListFolder.IncludedSectionHeader" = "INCLUDED CHATS";
|
||||
"ChatListFolder.AddChats" = "Add Chats";
|
||||
"ChatListFolder.IncludeSectionInfo" = "Choose chats and types of chats that will appear in this filter.";
|
||||
"ChatListFolder.ExcludedSectionHeader" = "EXCLUDED CHATS";
|
||||
"ChatListFolder.ExcludeSectionInfo" = "Choose chats and types of chats that will never appear in the filter.";
|
||||
"ChatListFolder.NameNonMuted" = "Not Muted";
|
||||
"ChatListFolder.NameUnread" = "Unread";
|
||||
"ChatListFolder.NameChannels" = "Channels";
|
||||
"ChatListFolder.NameContacts" = "Contacts";
|
||||
"ChatListFolder.NameNonContacts" = "Non-Contacts";
|
||||
"ChatListFolder.NameBots" = "Bots";
|
||||
"ChatListFolder.NameGroups" = "Groups";
|
||||
"ChatListFolder.DiscardConfirmation" = "You have changed the filter. Discard changes?";
|
||||
"ChatListFolder.DiscardDiscard" = "Discard";
|
||||
"ChatListFolder.DiscardCancel" = "No";
|
||||
"ChatListFolder.IncludeChatsTitle" = "Include Chats";
|
||||
"ChatListFolder.ExcludeChatsTitle" = "Exclude Chats";
|
||||
|
@ -16,7 +16,7 @@ static_library(
|
||||
"//submodules/Postbox:Postbox#shared",
|
||||
"//submodules/TelegramCore:TelegramCore#shared",
|
||||
"//submodules/SyncCore:SyncCore#shared",
|
||||
"//submodules/WalletCore:WalletCore",
|
||||
#"//submodules/WalletCore:WalletCore",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -30,7 +30,7 @@ public enum ContactMultiselectionControllerMode {
|
||||
case groupCreation
|
||||
case peerSelection(searchChatList: Bool, searchGroups: Bool, searchChannels: Bool)
|
||||
case channelCreation
|
||||
case chatSelection(selectedChats: Set<PeerId>, additionalCategories: ContactMultiselectionControllerAdditionalCategories?)
|
||||
case chatSelection(title: String, selectedChats: Set<PeerId>, additionalCategories: ContactMultiselectionControllerAdditionalCategories?)
|
||||
}
|
||||
|
||||
public enum ContactListFilter {
|
||||
|
@ -106,8 +106,7 @@ public final class ChatListSearchItemHeaderNode: ListViewItemHeaderNode {
|
||||
case .chats:
|
||||
self.sectionHeaderNode.title = strings.Cache_ByPeerHeader.uppercased()
|
||||
case .chatTypes:
|
||||
//TODO:localize
|
||||
self.sectionHeaderNode.title = "CHAT TYPES"
|
||||
self.sectionHeaderNode.title = strings.ChatList_ChatTypesSection.uppercased()
|
||||
}
|
||||
|
||||
self.sectionHeaderNode.action = actionTitle
|
||||
@ -157,8 +156,7 @@ public final class ChatListSearchItemHeaderNode: ListViewItemHeaderNode {
|
||||
case .chats:
|
||||
self.sectionHeaderNode.title = strings.Cache_ByPeerHeader.uppercased()
|
||||
case .chatTypes:
|
||||
//TODO:localize
|
||||
self.sectionHeaderNode.title = "CHAT TYPES"
|
||||
self.sectionHeaderNode.title = strings.ChatList_ChatTypesSection.uppercased()
|
||||
}
|
||||
|
||||
self.sectionHeaderNode.action = actionTitle
|
||||
|
@ -517,8 +517,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
return
|
||||
}
|
||||
var items: [ContextMenuItem] = []
|
||||
//TODO:localization
|
||||
items.append(.action(ContextMenuActionItem(text: "Edit Folder", icon: { theme in
|
||||
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: {
|
||||
@ -546,8 +545,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
})
|
||||
})))
|
||||
if let filter = filters.first(where: { $0.id == id }), filter.data.includePeers.count < 100 {
|
||||
//TODO:localization
|
||||
items.append(.action(ContextMenuActionItem(text: "Add Chats", icon: { theme in
|
||||
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: {
|
||||
@ -574,8 +572,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
})
|
||||
})
|
||||
})))
|
||||
//TODO:localize
|
||||
items.append(.action(ContextMenuActionItem(text: "Remove", textColor: .destructive, icon: { theme in
|
||||
|
||||
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: {
|
||||
@ -588,7 +586,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
|
||||
if filters.count > 1 {
|
||||
items.append(.separator)
|
||||
items.append(.action(ContextMenuActionItem(text: "Reorder Tabs", icon: { theme in
|
||||
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)
|
||||
@ -900,6 +898,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.cancelEditing = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.reorderingDonePressed()
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.toolbarActionSelected = { [weak self] action in
|
||||
self?.toolbarActionSelected(action: action)
|
||||
}
|
||||
@ -1152,12 +1157,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
let hasFilters = !filters.isEmpty
|
||||
if let _ = strongSelf.validLayout, let parentController = strongSelf.parent as? TabBarController, let sourceFrame = parentController.frameForControllerTab(controller: strongSelf) {
|
||||
let absoluteFrame = sourceFrame
|
||||
//TODO:localize
|
||||
let text: String
|
||||
if hasFilters {
|
||||
text = "Hold on 'Chats' to edit folders and switch between views."
|
||||
text = strongSelf.presentationData.strings.ChatList_TabIconFoldersTooltipNonEmptyFolders
|
||||
} else {
|
||||
text = "Hold to organize your chats with folders."
|
||||
text = strongSelf.presentationData.strings.ChatList_TabIconFoldersTooltipEmptyFolders
|
||||
}
|
||||
parentController.present(TooltipScreen(text: text, location: CGPoint(x: absoluteFrame.midX - 14.0, y: absoluteFrame.minY - 8.0), shouldDismissOnTouch: { point in
|
||||
guard let strongSelf = self, let parentController = strongSelf.parent as? TabBarController else {
|
||||
@ -1416,11 +1420,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
private func askForFilterRemoval(id: Int32) {
|
||||
let actionSheet = ActionSheetController(presentationData: self.presentationData)
|
||||
|
||||
//TODO:localization
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetTextItem(title: "This will remove the filter, your chats will not be deleted."),
|
||||
ActionSheetButtonItem(title: "Remove", color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
ActionSheetTextItem(title: self.presentationData.strings.ChatList_RemoveFolderConfirmation),
|
||||
ActionSheetButtonItem(title: self.presentationData.strings.ChatList_RemoveFolderAction, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
@ -2330,7 +2333,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
let (_, filterItems) = filterItemsAndTotalCount
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: presetList.isEmpty ? "Add Folder" : "Edit Folders", icon: { theme in
|
||||
items.append(.action(ContextMenuActionItem(text: presetList.isEmpty ? strongSelf.presentationData.strings.ChatList_AddFolder : strongSelf.presentationData.strings.ChatList_EditFolders, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: presetList.isEmpty ? "Chat/Context Menu/Add" : "Chat/Context Menu/ItemList"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
@ -2342,7 +2345,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
})))
|
||||
|
||||
if strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter != nil {
|
||||
items.append(.action(ContextMenuActionItem(text: "All Chats", icon: { theme in
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_FolderAllChats, icon: { theme in
|
||||
return nil
|
||||
}, action: { c, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
@ -542,6 +542,14 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
guard let strongSelf = self, strongSelf.availableFilters.count > 1 else {
|
||||
return []
|
||||
}
|
||||
switch strongSelf.currentItemNode.visibleContentOffset() {
|
||||
case let .known(value):
|
||||
if value < -1.0 {
|
||||
return []
|
||||
}
|
||||
case .none, .unknown:
|
||||
break
|
||||
}
|
||||
let directions: InteractiveTransitionGestureRecognizerDirections = [.leftCenter, .rightCenter]
|
||||
return directions
|
||||
}, edgeWidth: .widthMultiplier(factor: 1.0 / 6.0, min: 22.0, max: 80.0))
|
||||
@ -935,6 +943,7 @@ final class ChatListControllerNode: ASDisplayNode {
|
||||
private var presentationData: PresentationData
|
||||
|
||||
let containerNode: ChatListContainerNode
|
||||
private var tapRecognizer: UITapGestureRecognizer?
|
||||
var navigationBar: NavigationBar?
|
||||
weak var controller: ChatListControllerImpl?
|
||||
|
||||
@ -958,6 +967,7 @@ final class ChatListControllerNode: ASDisplayNode {
|
||||
var dismissSelfIfCompletedPresentation: (() -> Void)?
|
||||
var isEmptyUpdated: ((Bool) -> Void)?
|
||||
var emptyListAction: (() -> Void)?
|
||||
var cancelEditing: (() -> Void)?
|
||||
|
||||
let debugListView = ListView()
|
||||
|
||||
@ -1008,6 +1018,17 @@ final class ChatListControllerNode: ASDisplayNode {
|
||||
super.didLoad()
|
||||
|
||||
(self.view as? ChatListControllerNodeView)?.controller = self.controller
|
||||
|
||||
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
|
||||
self.tapRecognizer = tapRecognizer
|
||||
self.view.addGestureRecognizer(tapRecognizer)
|
||||
tapRecognizer.isEnabled = false
|
||||
}
|
||||
|
||||
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.cancelEditing?()
|
||||
}
|
||||
}
|
||||
|
||||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
@ -1078,6 +1099,8 @@ final class ChatListControllerNode: ASDisplayNode {
|
||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
self.containerNode.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, transition: transition)
|
||||
|
||||
self.tapRecognizer?.isEnabled = self.isReorderingFilters
|
||||
|
||||
if let searchDisplayController = self.searchDisplayController {
|
||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: cleanNavigationBarHeight, transition: transition)
|
||||
}
|
||||
|
@ -144,15 +144,15 @@ private enum ChatListFilterIncludeCategory: Int32, CaseIterable {
|
||||
func title(strings: PresentationStrings) -> String {
|
||||
switch self {
|
||||
case .contacts:
|
||||
return "Contacts"
|
||||
return strings.ChatListFolder_CategoryContacts
|
||||
case .nonContacts:
|
||||
return "Non-Contacts"
|
||||
return strings.ChatListFolder_CategoryNonContacts
|
||||
case .groups:
|
||||
return "Groups"
|
||||
return strings.ChatListFolder_CategoryGroups
|
||||
case .channels:
|
||||
return "Channels"
|
||||
return strings.ChatListFolder_CategoryChannels
|
||||
case .bots:
|
||||
return "Bots"
|
||||
return strings.ChatListFolder_CategoryBots
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,11 +165,11 @@ private enum ChatListFilterExcludeCategory: Int32, CaseIterable {
|
||||
func title(strings: PresentationStrings) -> String {
|
||||
switch self {
|
||||
case .muted:
|
||||
return "Muted"
|
||||
return strings.ChatListFolder_CategoryMuted
|
||||
case .read:
|
||||
return "Read"
|
||||
return strings.ChatListFolder_CategoryRead
|
||||
case .archived:
|
||||
return "Archived"
|
||||
return strings.ChatListFolder_CategoryArchived
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -425,7 +425,6 @@ private struct ChatListFilterPresetControllerState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO:localization
|
||||
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, isNewFilter: Bool, state: ChatListFilterPresetControllerState, includePeers: [RenderedPeer], excludePeers: [RenderedPeer]) -> [ChatListFilterPresetEntry] {
|
||||
var entries: [ChatListFilterPresetEntry] = []
|
||||
|
||||
@ -433,11 +432,11 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
||||
entries.append(.screenHeader)
|
||||
}
|
||||
|
||||
entries.append(.nameHeader("FOLDER NAME"))
|
||||
entries.append(.name(placeholder: "Folder Name", value: state.name))
|
||||
entries.append(.nameHeader(presentationData.strings.ChatListFolder_NameSectionHeader))
|
||||
entries.append(.name(placeholder: presentationData.strings.ChatListFolder_NamePlaceholder, value: state.name))
|
||||
|
||||
entries.append(.includePeersHeader("INCLUDED CHATS"))
|
||||
entries.append(.addIncludePeer(title: "Add Chats"))
|
||||
entries.append(.includePeersHeader(presentationData.strings.ChatListFolder_IncludedSectionHeader))
|
||||
entries.append(.addIncludePeer(title: presentationData.strings.ChatListFolder_AddChats))
|
||||
|
||||
var includeCategoryIndex = 0
|
||||
for category in ChatListFilterIncludeCategory.allCases {
|
||||
@ -451,10 +450,10 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
||||
entries.append(.includePeer(index: entries.count, peer: peer, isRevealed: state.revealedItemId == .peer(peer.peerId)))
|
||||
}
|
||||
|
||||
entries.append(.includePeerInfo("Choose chats and types of chats that will appear in this filter."))
|
||||
entries.append(.includePeerInfo(presentationData.strings.ChatListFolder_IncludeSectionInfo))
|
||||
|
||||
entries.append(.excludePeersHeader("EXCLUDED CHATS"))
|
||||
entries.append(.addExcludePeer(title: "Add Chats"))
|
||||
entries.append(.excludePeersHeader(presentationData.strings.ChatListFolder_ExcludedSectionHeader))
|
||||
entries.append(.addExcludePeer(title: presentationData.strings.ChatListFolder_AddChats))
|
||||
|
||||
var excludeCategoryIndex = 0
|
||||
for category in ChatListFilterExcludeCategory.allCases {
|
||||
@ -478,7 +477,7 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
||||
entries.append(.excludePeer(index: entries.count, peer: peer, isRevealed: state.revealedItemId == .peer(peer.peerId)))
|
||||
}
|
||||
|
||||
entries.append(.excludePeerInfo("Choose chats and types of chats that will never appear in the filter."))
|
||||
entries.append(.excludePeerInfo(presentationData.strings.ChatListFolder_ExcludeSectionInfo))
|
||||
|
||||
return entries
|
||||
}
|
||||
@ -502,31 +501,32 @@ func chatListFilterAddChatsController(context: AccountContext, filter: ChatListF
|
||||
}
|
||||
|
||||
private func internalChatListFilterAddChatsController(context: AccountContext, filter: ChatListFilter, applyAutomatically: Bool, updated: @escaping (ChatListFilter) -> Void) -> ViewController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let additionalCategories: [ChatListNodeAdditionalCategory] = [
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.contacts.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: .white), color: .blue),
|
||||
title: "Contacts"
|
||||
title: presentationData.strings.ChatListFolder_CategoryContacts
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.nonContacts.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/UnknownUser"), color: .white), color: .yellow),
|
||||
title: "Non-Contacts"
|
||||
title: presentationData.strings.ChatListFolder_CategoryNonContacts
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.groups.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Groups"), color: .white), color: .green),
|
||||
title: "Groups"
|
||||
title: presentationData.strings.ChatListFolder_CategoryGroups
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.channels.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Channels"), color: .white), color: .red),
|
||||
title: "Channels"
|
||||
title: presentationData.strings.ChatListFolder_CategoryChannels
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.bots.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Bots"), color: .white), color: .violet),
|
||||
title: "Bots"
|
||||
title: presentationData.strings.ChatListFolder_CategoryBots
|
||||
)
|
||||
]
|
||||
var selectedCategories = Set<Int>()
|
||||
@ -543,7 +543,7 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
|
||||
}
|
||||
}
|
||||
|
||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(selectedChats: Set(filter.data.includePeers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories)), options: [], alwaysEnabled: true))
|
||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(title: presentationData.strings.ChatListFolder_IncludeChatsTitle, selectedChats: Set(filter.data.includePeers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories)), options: [], alwaysEnabled: true))
|
||||
controller.navigationPresentation = .modal
|
||||
let _ = (controller.result
|
||||
|> take(1)
|
||||
@ -601,21 +601,22 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
|
||||
}
|
||||
|
||||
private func internalChatListFilterExcludeChatsController(context: AccountContext, filter: ChatListFilter, applyAutomatically: Bool, updated: @escaping (ChatListFilter) -> Void) -> ViewController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let additionalCategories: [ChatListNodeAdditionalCategory] = [
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalExcludeCategoryId.muted.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: .white), color: .red),
|
||||
title: "Muted"
|
||||
title: presentationData.strings.ChatListFolder_CategoryMuted
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalExcludeCategoryId.read.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: .white), color: .blue),
|
||||
title: "Read"
|
||||
title: presentationData.strings.ChatListFolder_CategoryRead
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalExcludeCategoryId.archived.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Archive"), color: .white), color: .yellow),
|
||||
title: "Archived"
|
||||
title: presentationData.strings.ChatListFolder_CategoryArchived
|
||||
),
|
||||
]
|
||||
var selectedCategories = Set<Int>()
|
||||
@ -629,7 +630,7 @@ private func internalChatListFilterExcludeChatsController(context: AccountContex
|
||||
selectedCategories.insert(AdditionalExcludeCategoryId.archived.rawValue)
|
||||
}
|
||||
|
||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(selectedChats: Set(filter.data.excludePeers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories)), options: [], alwaysEnabled: true))
|
||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(title: presentationData.strings.ChatListFolder_ExcludeChatsTitle, selectedChats: Set(filter.data.excludePeers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories)), options: [], alwaysEnabled: true))
|
||||
controller.navigationPresentation = .modal
|
||||
let _ = (controller.result
|
||||
|> take(1)
|
||||
@ -729,7 +730,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
if let currentPreset = currentPreset {
|
||||
initialName = currentPreset.title
|
||||
} else {
|
||||
initialName = "New Folder"
|
||||
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 ?? [], additionallyExcludePeers: currentPreset?.data.excludePeers ?? [])
|
||||
let stateValue = Atomic(value: initialState)
|
||||
@ -738,24 +739,25 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
statePromise.set(stateValue.modify { current in
|
||||
var state = f(current)
|
||||
if !state.changedName {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers))
|
||||
switch chatListFilterType(filter) {
|
||||
case .generic:
|
||||
state.name = initialName
|
||||
case .unmuted:
|
||||
state.name = "Not Muted"
|
||||
state.name = presentationData.strings.ChatListFolder_NameNonMuted
|
||||
case .unread:
|
||||
state.name = "Unread"
|
||||
state.name = presentationData.strings.ChatListFolder_NameUnread
|
||||
case .channels:
|
||||
state.name = "Channels"
|
||||
state.name = presentationData.strings.ChatListFolder_NameChannels
|
||||
case .groups:
|
||||
state.name = "Groups"
|
||||
state.name = presentationData.strings.ChatListFolder_NameGroups
|
||||
case .bots:
|
||||
state.name = "Bots"
|
||||
state.name = presentationData.strings.ChatListFolder_NameBots
|
||||
case .contacts:
|
||||
state.name = "Contacts"
|
||||
state.name = presentationData.strings.ChatListFolder_NameContacts
|
||||
case .nonContacts:
|
||||
state.name = "Non-Contacts"
|
||||
state.name = presentationData.strings.ChatListFolder_NameNonContacts
|
||||
}
|
||||
}
|
||||
return state
|
||||
@ -968,7 +970,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
applyImpl?()
|
||||
})
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(currentPreset != nil ? "Edit Folder" : "Create Folder"), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
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
|
||||
|
||||
@ -1001,12 +1003,11 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
}
|
||||
let displaySaveAlert: () -> Void = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: "You have changed the filter. Apply changes?", actions: [
|
||||
TextAlertAction(type: .genericAction, title: "Discard", action: {
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.ChatListFolder_DiscardConfirmation, actions: [
|
||||
TextAlertAction(type: .genericAction, title: presentationData.strings.ChatListFolder_DiscardDiscard, action: {
|
||||
dismissImpl?()
|
||||
}),
|
||||
TextAlertAction(type: .defaultAction, title: "Apply", action: {
|
||||
applyImpl?()
|
||||
TextAlertAction(type: .defaultAction, title: presentationData.strings.ChatListFolder_DiscardCancel, action: {
|
||||
})]), nil)
|
||||
}
|
||||
attemptNavigationImpl = {
|
||||
|
@ -193,8 +193,7 @@ private func filtersWithAppliedOrder(filters: [(ChatListFilter, Int)], order: [I
|
||||
private func chatListFilterPresetListControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetListControllerState, filters: [(ChatListFilter, Int)], updatedFilterOrder: [Int32]?, suggestedFilters: [ChatListFeaturedFilter], settings: ChatListFilterSettings) -> [ChatListFilterPresetListEntry] {
|
||||
var entries: [ChatListFilterPresetListEntry] = []
|
||||
|
||||
|
||||
entries.append(.screenHeader("Create folders for different groups of chats and\nquickly switch between them."))
|
||||
entries.append(.screenHeader(presentationData.strings.ChatListFolderSettings_Info))
|
||||
|
||||
let filteredSuggestedFilters = suggestedFilters.filter { suggestedFilter in
|
||||
for (filter, _) in filters {
|
||||
@ -206,24 +205,24 @@ private func chatListFilterPresetListControllerEntries(presentationData: Present
|
||||
}
|
||||
|
||||
if !filters.isEmpty || suggestedFilters.isEmpty {
|
||||
entries.append(.listHeader("FOLDERS"))
|
||||
entries.append(.listHeader(presentationData.strings.ChatListFolderSettings_FoldersSection))
|
||||
|
||||
for (filter, chatCount) in filtersWithAppliedOrder(filters: filters, order: updatedFilterOrder) {
|
||||
entries.append(.preset(index: PresetIndex(value: entries.count), title: filter.title, label: chatCount == 0 ? "" : "\(chatCount)", preset: filter, canBeReordered: filters.count > 1, canBeDeleted: true, isEditing: state.isEditing))
|
||||
}
|
||||
if filters.count < 10 {
|
||||
entries.append(.addItem(text: "Create New Folder", isEditing: state.isEditing))
|
||||
entries.append(.addItem(text: presentationData.strings.ChatListFolderSettings_NewFolder, isEditing: state.isEditing))
|
||||
}
|
||||
entries.append(.listFooter("Tap \"Edit\" to change the order or delete folders."))
|
||||
entries.append(.listFooter(presentationData.strings.ChatListFolderSettings_EditFoldersInfo))
|
||||
}
|
||||
|
||||
if !filteredSuggestedFilters.isEmpty && filters.count < 10 {
|
||||
entries.append(.suggestedListHeader("RECOMMENDED FOLDERS"))
|
||||
entries.append(.suggestedListHeader(presentationData.strings.ChatListFolderSettings_RecommendedFoldersSection))
|
||||
for filter in filteredSuggestedFilters {
|
||||
entries.append(.suggestedPreset(index: PresetIndex(value: entries.count), title: filter.title, label: filter.description, preset: filter.data))
|
||||
}
|
||||
if filters.isEmpty {
|
||||
entries.append(.suggestedAddCustom("Add Custom Folder"))
|
||||
entries.append(.suggestedAddCustom(presentationData.strings.ChatListFolderSettings_RecommendedNewFolder))
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,7 +399,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
||||
rightNavigationButton = nil
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Folders"), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ChatListFolderSettings_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: chatListFilterPresetListControllerEntries(presentationData: presentationData, state: state, filters: filtersWithCountsValue, updatedFilterOrder: updatedFilterOrderValue, suggestedFilters: suggestedFilters, settings: filterSettings), style: .blocks, animateChanges: true)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
|
@ -373,7 +373,7 @@ enum ChatListFilterTabEntry: Equatable {
|
||||
func title(strings: PresentationStrings) -> String {
|
||||
switch self {
|
||||
case .all:
|
||||
return "All Chats"
|
||||
return strings.ChatList_Tabs_AllChats
|
||||
case let .filter(filter):
|
||||
return filter.text
|
||||
}
|
||||
@ -382,7 +382,7 @@ enum ChatListFilterTabEntry: Equatable {
|
||||
func shortTitle(strings: PresentationStrings) -> String {
|
||||
switch self {
|
||||
case .all:
|
||||
return "All"
|
||||
return strings.ChatList_Tabs_All
|
||||
case let .filter(filter):
|
||||
return filter.text
|
||||
}
|
||||
|
@ -1717,30 +1717,29 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
private func statusStringForPeerType(strings: PresentationStrings, peer: Peer, isContact: Bool) -> String {
|
||||
if let user = peer as? TelegramUser {
|
||||
if user.botInfo != nil || user.flags.contains(.isSupport) {
|
||||
return "bot"
|
||||
return strings.ChatList_PeerTypeBot
|
||||
} else if isContact {
|
||||
return "contact"
|
||||
return strings.ChatList_PeerTypeContact
|
||||
} else {
|
||||
return "user"
|
||||
return strings.ChatList_PeerTypeNonContact
|
||||
}
|
||||
} else if peer is TelegramSecretChat {
|
||||
if isContact {
|
||||
return "contact"
|
||||
return strings.ChatList_PeerTypeContact
|
||||
} else {
|
||||
return "user"
|
||||
return strings.ChatList_PeerTypeNonContact
|
||||
}
|
||||
} else if peer is TelegramGroup {
|
||||
return "group"
|
||||
return strings.ChatList_PeerTypeGroup
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
if case .group = channel.info {
|
||||
return "group"
|
||||
return strings.ChatList_PeerTypeGroup
|
||||
} else {
|
||||
return "channel"
|
||||
return strings.ChatList_PeerTypeChannel
|
||||
}
|
||||
}
|
||||
return "user"
|
||||
return strings.ChatList_PeerTypeNonContact
|
||||
}
|
||||
|
@ -125,7 +125,7 @@
|
||||
[_mapModeControl setDividerImage:pallete.searchBarPallete.segmentedControlDividerImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
||||
|
||||
[_mapModeControl setTitleTextAttributes:@{UITextAttributeTextColor:pallete.searchBarPallete.accentColor, UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateNormal];
|
||||
[_mapModeControl setTitleTextAttributes:@{UITextAttributeTextColor:pallete.searchBarPallete.accentContrastColor, UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateSelected];
|
||||
[_mapModeControl setTitleTextAttributes:@{UITextAttributeTextColor:pallete.searchBarPallete.accentColor, UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateSelected];
|
||||
}
|
||||
|
||||
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
|
||||
|
@ -4,14 +4,7 @@ static_library(
|
||||
name = "LegacyMediaPickerUI",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
"Sources/**/*.m",
|
||||
]),
|
||||
headers = glob([
|
||||
"Sources/**/*.h",
|
||||
], exclude = ["Sources/LegacyMediaPickerUI.h"]),
|
||||
exported_headers = glob([
|
||||
"Sources/**/*.h",
|
||||
], exclude = ["Sources/LegacyMediaPickerUI.h"]),
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit#shared",
|
||||
@ -27,6 +20,7 @@ static_library(
|
||||
"//submodules/LocalMediaResources:LocalMediaResources",
|
||||
"//submodules/SearchPeerMembers:SearchPeerMembers",
|
||||
"//submodules/SaveToCameraRoll:SaveToCameraRoll",
|
||||
"//submodules/LegacyMediaPickerUI/LegacyImageProcessors:LegacyImageProcessors",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
21
submodules/LegacyMediaPickerUI/LegacyImageProcessors/BUCK
Normal file
21
submodules/LegacyMediaPickerUI/LegacyImageProcessors/BUCK
Normal file
@ -0,0 +1,21 @@
|
||||
load("//Config:buck_rule_macros.bzl", "static_library")
|
||||
|
||||
static_library(
|
||||
name = "LegacyImageProcessors",
|
||||
srcs = glob([
|
||||
"Sources/**/*.m",
|
||||
]),
|
||||
headers = glob([
|
||||
"Sources/**/*.h",
|
||||
]),
|
||||
exported_headers = glob([
|
||||
"PublicHeaders/**/*.h",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/LegacyComponents:LegacyComponents",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||
],
|
||||
)
|
@ -706,8 +706,7 @@ private func settingsEntries(account: Account, presentationData: PresentationDat
|
||||
entries.append(.devices(presentationData.theme, UIImage(bundleImageName: "Settings/MenuIcons/Sessions")?.precomposed(), presentationData.strings.Settings_Devices, otherSessionCount == 0 ? "" : "\(otherSessionCount + 1)"))
|
||||
}
|
||||
if enableFilters {
|
||||
//TODO:localize
|
||||
entries.append(.filters(presentationData.theme, UIImage(bundleImageName: "Settings/MenuIcons/ChatListFilters")?.precomposed(), "Chat Folders", ""))
|
||||
entries.append(.filters(presentationData.theme, UIImage(bundleImageName: "Settings/MenuIcons/ChatListFilters")?.precomposed(), presentationData.strings.Settings_ChatFolders, ""))
|
||||
}
|
||||
|
||||
let notificationsWarning = shouldDisplayNotificationsPermissionWarning(status: notificationsAuthorizationStatus, suppressed: notificationsWarningSuppressed)
|
||||
|
@ -518,6 +518,23 @@ public func updatedChatListFilters(postbox: Postbox) -> Signal<[ChatListFilter],
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
|
||||
public func updatedChatListFiltersInfo(postbox: Postbox) -> Signal<(filters: [ChatListFilter], synchronized: Bool), NoError> {
|
||||
return postbox.preferencesView(keys: [PreferencesKeys.chatListFilters])
|
||||
|> map { preferences -> (filters: [ChatListFilter], synchronized: Bool) in
|
||||
let filtersState = preferences.values[PreferencesKeys.chatListFilters] as? ChatListFiltersState ?? ChatListFiltersState.default
|
||||
return (filtersState.filters, filtersState.remoteFilters != nil)
|
||||
}
|
||||
|> distinctUntilChanged(isEqual: { lhs, rhs -> Bool in
|
||||
if lhs.filters != rhs.filters {
|
||||
return false
|
||||
}
|
||||
if lhs.synchronized != rhs.synchronized {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
public func currentChatListFilters(postbox: Postbox) -> Signal<[ChatListFilter], NoError> {
|
||||
return postbox.transaction { transaction -> [ChatListFilter] in
|
||||
let settings = transaction.getPreferencesEntry(key: PreferencesKeys.chatListFilters) as? ChatListFiltersState ?? ChatListFiltersState.default
|
||||
|
@ -525,7 +525,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
|
||||
destructiveColor: UIColor(rgb: 0xeb5545),
|
||||
badgeFillColor: UIColor(rgb: 0xeb5545),
|
||||
badgeForegroundColor: UIColor(rgb: 0xffffff, alpha: 1.0),
|
||||
extractedContentTintColor: UIColor(rgb: 0x252525, alpha: 0.78)
|
||||
extractedContentTintColor: UIColor(rgb: 0xffffff, alpha: 1.0)
|
||||
)
|
||||
|
||||
let inAppNotification = PresentationThemeInAppNotification(
|
||||
|
@ -774,7 +774,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres
|
||||
destructiveColor: UIColor(rgb: 0xff6767),
|
||||
badgeFillColor: UIColor(rgb: 0xff6767),
|
||||
badgeForegroundColor: UIColor(rgb: 0xffffff, alpha: 1.0),
|
||||
extractedContentTintColor: rootNavigationBar.backgroundColor.withAlphaComponent(0.78)
|
||||
extractedContentTintColor: UIColor(rgb: 0xffffff, alpha: 1.0)
|
||||
)
|
||||
|
||||
let inAppNotification = PresentationThemeInAppNotification(
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -116,7 +116,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
})
|
||||
|
||||
switch self.mode {
|
||||
case let .chatSelection(selectedChats, _):
|
||||
case let .chatSelection(_, selectedChats, additionalCategories):
|
||||
let _ = (self.context.account.postbox.transaction { transaction -> [Peer] in
|
||||
return selectedChats.compactMap(transaction.getPeer)
|
||||
}
|
||||
@ -124,9 +124,16 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.contactsNode.editableTokens = peers.map { peer -> EditableTokenListToken in
|
||||
return EditableTokenListToken(id: peer.id, title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
if let additionalCategories = additionalCategories {
|
||||
for i in 0 ..< additionalCategories.categories.count {
|
||||
if additionalCategories.selectedCategories.contains(additionalCategories.categories[i].id) {
|
||||
strongSelf.contactsNode.editableTokens.append(EditableTokenListToken(id: additionalCategories.categories[i].id, title: additionalCategories.categories[i].title, fixedPosition: i))
|
||||
}
|
||||
}
|
||||
}
|
||||
strongSelf.contactsNode.editableTokens.append(contentsOf: peers.map { peer -> EditableTokenListToken in
|
||||
return EditableTokenListToken(id: peer.id, title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), fixedPosition: nil)
|
||||
})
|
||||
strongSelf._peersReady.set(.single(true))
|
||||
if strongSelf.isNodeLoaded {
|
||||
strongSelf.requestLayout(transition: .immediate)
|
||||
@ -185,8 +192,8 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed))
|
||||
self.navigationItem.rightBarButtonItem = self.rightNavigationButton
|
||||
rightNavigationButton.isEnabled = false
|
||||
case .chatSelection:
|
||||
self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.ChatListFilter_AddChatsTitle, counter: "")
|
||||
case let .chatSelection(chatSelection):
|
||||
self.titleView.title = CounterContollerTitle(title: chatSelection.title, counter: "")
|
||||
let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed))
|
||||
self.rightNavigationButton = rightNavigationButton
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed))
|
||||
@ -230,7 +237,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
displayCountAlert = true
|
||||
updatedState = updatedState.withToggledPeerId(.peer(peer.id))
|
||||
} else {
|
||||
addedToken = EditableTokenListToken(id: peer.id, title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
addedToken = EditableTokenListToken(id: peer.id, title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), fixedPosition: nil)
|
||||
}
|
||||
}
|
||||
updatedCount = updatedState.selectedPeerIndices.count
|
||||
@ -247,7 +254,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
state.selectedPeerIds.remove(peer.id)
|
||||
removedTokenId = peer.id
|
||||
} else {
|
||||
addedToken = EditableTokenListToken(id: peer.id, title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
addedToken = EditableTokenListToken(id: peer.id, title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), fixedPosition: nil)
|
||||
state.selectedPeerIds.insert(peer.id)
|
||||
}
|
||||
updatedCount = state.selectedPeerIds.count
|
||||
@ -370,10 +377,11 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
}
|
||||
}
|
||||
|
||||
self.contactsNode.additionalCategorySelected = { [weak self] id in
|
||||
self.contactsNode.removeSelectedCategory = { [weak self] id in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var removedTokenId: AnyHashable?
|
||||
switch strongSelf.contactsNode.contentNode {
|
||||
case .contacts:
|
||||
break
|
||||
@ -382,11 +390,76 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
var state = state
|
||||
if state.selectedAdditionalCategoryIds.contains(id) {
|
||||
state.selectedAdditionalCategoryIds.remove(id)
|
||||
} else {
|
||||
state.selectedAdditionalCategoryIds.insert(id)
|
||||
removedTokenId = id
|
||||
}
|
||||
return state
|
||||
}
|
||||
if let removedTokenId = removedTokenId {
|
||||
strongSelf.contactsNode.editableTokens = strongSelf.contactsNode.editableTokens.filter { token in
|
||||
return token.id != removedTokenId
|
||||
}
|
||||
}
|
||||
strongSelf.requestLayout(transition: ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
}
|
||||
|
||||
self.contactsNode.additionalCategorySelected = { [weak self] id in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var addedToken: EditableTokenListToken?
|
||||
var removedTokenId: AnyHashable?
|
||||
switch strongSelf.contactsNode.contentNode {
|
||||
case .contacts:
|
||||
break
|
||||
case let .chats(chatsNode):
|
||||
var categoryToken: EditableTokenListToken?
|
||||
if case let .chatSelection(_, _, additionalCategories) = strongSelf.mode {
|
||||
if let additionalCategories = additionalCategories {
|
||||
for i in 0 ..< additionalCategories.categories.count {
|
||||
if additionalCategories.categories[i].id == id {
|
||||
categoryToken = EditableTokenListToken(id: id, title: additionalCategories.categories[i].title, fixedPosition: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
chatsNode.updateState { state in
|
||||
var state = state
|
||||
if state.selectedAdditionalCategoryIds.contains(id) {
|
||||
state.selectedAdditionalCategoryIds.remove(id)
|
||||
removedTokenId = id
|
||||
} else {
|
||||
state.selectedAdditionalCategoryIds.insert(id)
|
||||
addedToken = categoryToken
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
if let addedToken = addedToken, let insertFixedIndex = addedToken.fixedPosition {
|
||||
var added = false
|
||||
for i in 0 ..< strongSelf.contactsNode.editableTokens.count {
|
||||
if let fixedIndex = strongSelf.contactsNode.editableTokens[i].fixedPosition {
|
||||
if fixedIndex > insertFixedIndex {
|
||||
strongSelf.contactsNode.editableTokens.insert(addedToken, at: i)
|
||||
added = true
|
||||
break
|
||||
}
|
||||
} else {
|
||||
strongSelf.contactsNode.editableTokens.insert(addedToken, at: i)
|
||||
added = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !added {
|
||||
strongSelf.contactsNode.editableTokens.append(addedToken)
|
||||
}
|
||||
} else if let removedTokenId = removedTokenId {
|
||||
strongSelf.contactsNode.editableTokens = strongSelf.contactsNode.editableTokens.filter { token in
|
||||
return token.id != removedTokenId
|
||||
}
|
||||
}
|
||||
strongSelf.requestLayout(transition: ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
var requestOpenPeerFromSearch: ((ContactListPeerId) -> Void)?
|
||||
var openPeer: ((ContactListPeer) -> Void)?
|
||||
var removeSelectedPeer: ((ContactListPeerId) -> Void)?
|
||||
var removeSelectedCategory: ((Int) -> Void)?
|
||||
var additionalCategorySelected: ((Int) -> Void)?
|
||||
|
||||
var editableTokens: [EditableTokenListToken] = []
|
||||
@ -83,8 +84,8 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
placeholder = self.presentationData.strings.Compose_TokenListPlaceholder
|
||||
}
|
||||
|
||||
if case let .chatSelection(selectedChats, additionalCategories) = mode {
|
||||
placeholder = self.presentationData.strings.Common_Search
|
||||
if case let .chatSelection(_, selectedChats, additionalCategories) = mode {
|
||||
placeholder = self.presentationData.strings.ChatListFilter_AddChatsTitle
|
||||
let chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, controlsHistoryPreload: false, mode: .peers(filter: [.excludeSavedMessages], isSelecting: true, additionalCategories: additionalCategories?.categories ?? []), theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
chatListNode.updateState { state in
|
||||
var state = state
|
||||
@ -136,7 +137,11 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
let searchText = ValuePromise<String>()
|
||||
|
||||
self.tokenListNode.deleteToken = { [weak self] id in
|
||||
self?.removeSelectedPeer?(ContactListPeerId.peer(id as! PeerId))
|
||||
if let id = id as? PeerId {
|
||||
self?.removeSelectedPeer?(ContactListPeerId.peer(id))
|
||||
} else if let id = id as? Int {
|
||||
self?.removeSelectedCategory?(id)
|
||||
}
|
||||
}
|
||||
|
||||
self.tokenListNode.textUpdated = { [weak self] text in
|
||||
|
@ -7,6 +7,7 @@ import TelegramPresentationData
|
||||
struct EditableTokenListToken {
|
||||
let id: AnyHashable
|
||||
let title: String
|
||||
let fixedPosition: Int?
|
||||
}
|
||||
|
||||
private let caretIndicatorImage = generateVerticallyStretchableFilledCircleImage(radius: 1.0, color: UIColor(rgb: 0x3350ee))
|
||||
@ -203,7 +204,7 @@ final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
||||
self.selectedTokenId = nil
|
||||
}
|
||||
|
||||
let sideInset: CGFloat = 4.0 + leftInset
|
||||
let sideInset: CGFloat = 12.0 + leftInset
|
||||
let verticalInset: CGFloat = 6.0
|
||||
|
||||
let placeholderSize = self.placeholderNode.measure(CGSize(width: max(1.0, width - sideInset - sideInset), height: CGFloat.greatestFiniteMagnitude))
|
||||
@ -251,8 +252,8 @@ final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
||||
let previousFrame = tokenNode.frame
|
||||
if !previousFrame.origin.y.isEqual(to: tokenFrame.origin.y) && previousFrame.size.width.isEqual(to: tokenFrame.size.width) {
|
||||
let initialStartPosition = CGPoint(x: previousFrame.midX, y: previousFrame.midY)
|
||||
let initialEndPosition = CGPoint(x: -previousFrame.size.width / 2.0, y: previousFrame.midY)
|
||||
let targetStartPosition = CGPoint(x: width + tokenFrame.size.width, y: tokenFrame.midY)
|
||||
let initialEndPosition = CGPoint(x: previousFrame.midY > tokenFrame.midY ? -previousFrame.size.width / 2.0 : width, y: previousFrame.midY)
|
||||
let targetStartPosition = CGPoint(x: (previousFrame.midY > tokenFrame.midY ? (width + tokenFrame.size.width) : -tokenFrame.size.width), y: tokenFrame.midY)
|
||||
let targetEndPosition = CGPoint(x: tokenFrame.midX, y: tokenFrame.midY)
|
||||
tokenNode.frame = tokenFrame
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user