Folder improvements

This commit is contained in:
Ali 2020-03-20 13:01:09 +04:00
parent 46ea78b6c3
commit ceccb98af7
16 changed files with 152 additions and 63 deletions

View File

@ -1,4 +1,5 @@
build --experimental_guard_against_concurrent_changes
build --action_env=ZERO_AR_DATE=1
build --strategy=Genrule=local
build --apple_platform_type=ios

View File

@ -279,7 +279,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
passcode,
self.chatListDisplayNode.containerNode.currentItemState,
self.isReorderingTabsValue.get()
).start(next: { [weak self] networkState, proxy, passcode, state, isReorderingTabs in
).start(next: { [weak self] networkState, proxy, passcode, stateAndFilterId, isReorderingTabs in
if let strongSelf = self {
let defaultTitle: String
if strongSelf.groupId == .root {
@ -287,12 +287,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
} else {
defaultTitle = strongSelf.presentationData.strings.ChatList_ArchivedChatsTitle
}
if state.editing {
if stateAndFilterId.state.editing {
if strongSelf.groupId == .root {
strongSelf.navigationItem.rightBarButtonItem = nil
}
let title = !state.selectedPeerIds.isEmpty ? strongSelf.presentationData.strings.ChatList_SelectedChats(Int32(state.selectedPeerIds.count)) : defaultTitle
let title = !stateAndFilterId.state.selectedPeerIds.isEmpty ? strongSelf.presentationData.strings.ChatList_SelectedChats(Int32(stateAndFilterId.state.selectedPeerIds.count)) : defaultTitle
strongSelf.titleView.title = NetworkStatusTitle(text: title, activity: false, hasProxy: false, connectsViaProxy: false, isPasscodeSet: false, isManuallyLocked: false)
} else if isReorderingTabs {
if strongSelf.groupId == .root {
@ -334,7 +334,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
strongSelf.navigationItem.leftBarButtonItem = leftBarButtonItem
} else {
let editItem: UIBarButtonItem
if state.editing {
if stateAndFilterId.state.editing {
editItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(strongSelf.donePressed))
editItem.accessibilityLabel = strongSelf.presentationData.strings.Common_Done
} else {
@ -798,16 +798,24 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
let context = self.context
let peerIdsAndOptions: Signal<(ChatListSelectionOptions, Set<PeerId>)?, NoError> = self.chatListDisplayNode.containerNode.currentItemState
|> map { state -> Set<PeerId>? in
|> map { state, filterId -> (Set<PeerId>, Int32?)? in
if !state.editing {
return nil
}
return state.selectedPeerIds
return (state.selectedPeerIds, filterId)
}
|> distinctUntilChanged
|> mapToSignal { selectedPeerIds -> Signal<(ChatListSelectionOptions, Set<PeerId>)?, NoError> in
if let selectedPeerIds = selectedPeerIds {
return chatListSelectionOptions(postbox: context.account.postbox, peerIds: selectedPeerIds)
|> distinctUntilChanged(isEqual: { lhs, rhs in
if lhs?.0 != rhs?.0 {
return false
}
if lhs?.1 != rhs?.1 {
return false
}
return true
})
|> mapToSignal { selectedPeerIdsAndFilterId -> Signal<(ChatListSelectionOptions, Set<PeerId>)?, NoError> in
if let (selectedPeerIds, filterId) = selectedPeerIdsAndFilterId {
return chatListSelectionOptions(postbox: context.account.postbox, peerIds: selectedPeerIds, filterId: filterId)
|> map { options -> (ChatListSelectionOptions, Set<PeerId>)? in
return (options, selectedPeerIds)
}
@ -1381,7 +1389,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
}
|> distinctUntilChanged
let filterItems = chatListFilterItems(context: self.context)
let filterItems = chatListFilterItems(postbox: self.context.account.postbox)
var notifiedFirstUpdate = false
self.filterDisposable.set((combineLatest(queue: .mainQueue(),
context.account.postbox.combinedView(keys: [
@ -2428,7 +2436,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
let _ = (combineLatest(queue: .mainQueue(),
currentChatListFilters(postbox: self.context.account.postbox),
chatListFilterItems(context: self.context)
chatListFilterItems(postbox: self.context.account.postbox)
|> take(1)
)
|> deliverOnMainQueue).start(next: { [weak self] presetList, filterItemsAndTotalCount in

View File

@ -431,8 +431,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
return self.currentItemNodeValue!.listNode
}
private let currentItemStateValue = Promise<ChatListNodeState>()
var currentItemState: Signal<ChatListNodeState, NoError> {
private let currentItemStateValue = Promise<(state: ChatListNodeState, filterId: Int32?)>()
var currentItemState: Signal<(state: ChatListNodeState, filterId: Int32?), NoError> {
return self.currentItemStateValue.get()
}
@ -502,7 +502,16 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
self?.didBeginSelectingChats?()
}
self.currentItemStateValue.set(itemNode.listNode.state)
self.currentItemStateValue.set(itemNode.listNode.state |> map { state in
let filterId: Int32?
switch id {
case .all:
filterId = nil
case let .filter(filter):
filterId = filter
}
return (state, filterId)
})
if self.controlsHistoryPreload {
self.context.account.viewTracker.chatListPreloadItems.set(itemNode.listNode.preloadItems.get())

View File

@ -95,12 +95,22 @@ final class ChatListEmptyNode: ASDisplayNode {
}
self.updateThemeAndStrings(theme: theme, strings: strings)
self.animationNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.animationTapGesture(_:))))
}
@objc private func buttonPressed() {
self.action()
}
@objc private func animationTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
if !self.animationNode.isPlaying {
self.animationNode.play()
}
}
}
func restartAnimation() {
self.animationNode.play()
}
@ -189,6 +199,9 @@ final class ChatListEmptyNode: ASDisplayNode {
if self.buttonNode.frame.contains(point) {
return self.buttonNode.view.hitTest(self.view.convert(point, to: self.buttonNode.view), with: event)
}
if self.animationNode.frame.contains(point) {
return self.animationNode.view.hitTest(self.view.convert(point, to: self.animationNode.view), with: event)
}
return nil
}
}

View File

@ -330,7 +330,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
case let .nameHeader(title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
case let .name(placeholder, value):
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(), text: value, placeholder: placeholder, type: .regular(capitalization: true, autocorrection: false), clearType: .always, maxLength: 20, sectionId: self.section, textUpdated: { value in
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(), text: value, placeholder: placeholder, type: .regular(capitalization: true, autocorrection: false), clearType: .always, maxLength: 12, sectionId: self.section, textUpdated: { value in
arguments.updateState { current in
var state = current
state.name = value
@ -480,7 +480,7 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
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) {
if includePeers.count >= 7 && count == 5 && !state.expandedSections.contains(.include) {
break
}
}
@ -517,7 +517,7 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
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) {
if excludePeers.count >= 7 && count == 5 && !state.expandedSections.contains(.exclude) {
break
}
}
@ -592,7 +592,7 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
}
}
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(title: presentationData.strings.ChatListFolder_IncludeChatsTitle, selectedChats: Set(filter.data.includePeers.peers), 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.peers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories)), options: [], filters: [], alwaysEnabled: true))
controller.navigationPresentation = .modal
let _ = (controller.result
|> take(1)
@ -679,7 +679,7 @@ private func internalChatListFilterExcludeChatsController(context: AccountContex
selectedCategories.insert(AdditionalExcludeCategoryId.archived.rawValue)
}
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))
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: [], filters: [], alwaysEnabled: true))
controller.navigationPresentation = .modal
let _ = (controller.result
|> take(1)

View File

@ -94,7 +94,9 @@ class ChatListFilterSettingsHeaderItemNode: ListViewItemNode {
@objc private func animationTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
self.animationNode.play()
if !self.animationNode.isPlaying {
self.animationNode.play()
}
}
}

View File

@ -254,10 +254,6 @@ private final class ItemNode: ASDisplayNode {
width = badgeBackgroundFrame.maxX
}
let extractedBackgroundHeight: CGFloat = 36.0
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 - self.shortTitleNode.insets.left - self.shortTitleNode.insets.right + 5.0)
}
@ -276,6 +272,10 @@ private final class ItemNode: ASDisplayNode {
self.extractedContainerNode.hitTestSlop = self.hitTestSlop
self.extractedContainerNode.contentNode.hitTestSlop = self.hitTestSlop
self.containerNode.hitTestSlop = self.hitTestSlop
let extractedBackgroundHeight: CGFloat = 36.0
let extractedBackgroundInset: CGFloat = 14.0
self.extractedBackgroundNode.frame = CGRect(origin: CGPoint(x: -extractedBackgroundInset, y: floor((size.height - extractedBackgroundHeight) / 2.0)), size: CGSize(width: size.width + extractedBackgroundInset * 2.0, height: extractedBackgroundHeight))
}
func animateBadgeIn() {

View File

@ -254,10 +254,6 @@ private final class ItemNode: ASDisplayNode {
width = badgeBackgroundFrame.maxX
}
let extractedBackgroundHeight: CGFloat = 32.0
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 - self.shortTitleNode.insets.left - self.shortTitleNode.insets.right)
}
@ -276,6 +272,10 @@ private final class ItemNode: ASDisplayNode {
self.extractedContainerNode.hitTestSlop = self.hitTestSlop
self.extractedContainerNode.contentNode.hitTestSlop = self.hitTestSlop
self.containerNode.hitTestSlop = self.hitTestSlop
let extractedBackgroundHeight: CGFloat = 32.0
let extractedBackgroundInset: CGFloat = 14.0
self.extractedBackgroundNode.frame = CGRect(origin: CGPoint(x: -extractedBackgroundInset, y: floor((size.height - extractedBackgroundHeight) / 2.0)), size: CGSize(width: size.width + extractedBackgroundInset * 2.0, height: extractedBackgroundHeight))
}
func animateBadgeIn() {

View File

@ -15,23 +15,36 @@ struct ChatListSelectionOptions: Equatable {
let delete: Bool
}
func chatListSelectionOptions(postbox: Postbox, peerIds: Set<PeerId>) -> Signal<ChatListSelectionOptions, NoError> {
func chatListSelectionOptions(postbox: Postbox, peerIds: Set<PeerId>, filterId: Int32?) -> Signal<ChatListSelectionOptions, NoError> {
if peerIds.isEmpty {
let key = PostboxViewKey.unreadCounts(items: [.total(nil)])
return postbox.combinedView(keys: [key])
|> map { view -> ChatListSelectionOptions in
var hasUnread = false
if let unreadCounts = view.views[key] as? UnreadMessageCountsView, let total = unreadCounts.total() {
for (_, counter) in total.1.absoluteCounters {
if counter.messageCount != 0 {
hasUnread = true
break
if let filterId = filterId {
return chatListFilterItems(postbox: postbox)
|> map { filterItems -> ChatListSelectionOptions in
for (filter, unreadCount, _) in filterItems.1 {
if filter.id == filterId {
return ChatListSelectionOptions(read: .all(enabled: unreadCount != 0), delete: false)
}
}
return ChatListSelectionOptions(read: .all(enabled: false), delete: false)
}
return ChatListSelectionOptions(read: .all(enabled: hasUnread), delete: false)
|> distinctUntilChanged
} else {
let key = PostboxViewKey.unreadCounts(items: [.total(nil)])
return postbox.combinedView(keys: [key])
|> map { view -> ChatListSelectionOptions in
var hasUnread = false
if let unreadCounts = view.views[key] as? UnreadMessageCountsView, let total = unreadCounts.total() {
for (_, counter) in total.1.absoluteCounters {
if counter.messageCount != 0 {
hasUnread = true
break
}
}
}
return ChatListSelectionOptions(read: .all(enabled: hasUnread), delete: false)
}
|> distinctUntilChanged
}
|> distinctUntilChanged
} else {
let items: [UnreadMessageCountsItem] = peerIds.map(UnreadMessageCountsItem.peer)
let key = PostboxViewKey.unreadCounts(items: items)

View File

@ -10,8 +10,8 @@ import Postbox
import TelegramUIPreferences
import TelegramCore
func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilter, Int, Bool)]), NoError> {
return updatedChatListFilters(postbox: context.account.postbox)
func chatListFilterItems(postbox: Postbox) -> Signal<(Int, [(ChatListFilter, Int, Bool)]), NoError> {
return updatedChatListFilters(postbox: postbox)
|> distinctUntilChanged
|> mapToSignal { filters -> Signal<(Int, [(ChatListFilter, Int, Bool)]), NoError> in
var unreadCountItems: [UnreadMessageCountsItem] = []
@ -40,8 +40,8 @@ func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilt
keys.append(.basicPeer(peerId))
}
return combineLatest(queue: context.account.postbox.queue,
context.account.postbox.combinedView(keys: keys),
return combineLatest(queue: postbox.queue,
postbox.combinedView(keys: keys),
Signal<Bool, NoError>.single(true)
)
|> map { view, _ -> (Int, [(ChatListFilter, Int, Bool)]) in
@ -63,7 +63,7 @@ func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilt
case let .peer(peerId, state):
if let state = state, state.isUnread {
if let peerView = view.views[.basicPeer(peerId)] as? BasicPeerView, let peer = peerView.peer {
let tag = context.account.postbox.seedConfiguration.peerSummaryCounterTags(peer, peerView.isContact)
let tag = postbox.seedConfiguration.peerSummaryCounterTags(peer, peerView.isContact)
var peerCount = Int(state.count)
if state.isUnread {

View File

@ -152,7 +152,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
}
}
func item(context: AccountContext, presentationData: PresentationData, interaction: ContactListNodeInteraction) -> ListViewItem {
func item(context: AccountContext, presentationData: PresentationData, interaction: ContactListNodeInteraction, isSearch: Bool) -> ListViewItem {
switch self {
case let .search(theme, strings):
return ChatListSearchItem(theme: theme, placeholder: strings.Contacts_SearchLabel, activate: {
@ -177,7 +177,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
case let .option(_, option, header, theme, _):
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: option.title, icon: option.icon, clearHighlightAutomatically: false, header: header, action: option.action)
case let .peer(_, peer, presence, header, selection, theme, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, enabled):
let status: ContactsPeerItemStatus
var status: ContactsPeerItemStatus
let itemPeer: ContactsPeerItemPeer
var isContextActionEnabled = false
switch peer {
@ -214,6 +214,9 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
status = .none
itemPeer = .deviceContact(stableId: id, contact: contact)
}
if isSearch {
status = .none
}
var itemContextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
if isContextActionEnabled, let contextAction = interaction.contextAction {
itemContextAction = { node, gesture in
@ -227,7 +230,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
}
}
}
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: itemPeer, status: status, enabled: enabled, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: isSearch ? .generalSearch : .peer, peer: itemPeer, status: status, enabled: enabled, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
interaction.openPeer(peer)
}, itemHighlighting: interaction.itemHighlighting, contextAction: itemContextAction)
}
@ -608,12 +611,12 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer]
return entries
}
private func preparedContactListNodeTransition(context: AccountContext, presentationData: PresentationData, from fromEntries: [ContactListNodeEntry], to toEntries: [ContactListNodeEntry], interaction: ContactListNodeInteraction, firstTime: Bool, isEmpty: Bool, generateIndexSections: Bool, animation: ContactListAnimation) -> ContactsListNodeTransition {
private func preparedContactListNodeTransition(context: AccountContext, presentationData: PresentationData, from fromEntries: [ContactListNodeEntry], to toEntries: [ContactListNodeEntry], interaction: ContactListNodeInteraction, firstTime: Bool, isEmpty: Bool, generateIndexSections: Bool, animation: ContactListAnimation, isSearch: Bool) -> ContactsListNodeTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction, isSearch: isSearch), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction, isSearch: isSearch), directionHint: nil) }
var shouldFixScroll = false
var indexSections: [String] = []
@ -783,7 +786,7 @@ public final class ContactListNode: ASDisplayNode {
private var authorizationNode: PermissionContentNode
private let displayPermissionPlaceholder: Bool
public init(context: AccountContext, presentation: Signal<ContactListPresentation, NoError>, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil, displayPermissionPlaceholder: Bool = true, displaySortOptions: Bool = false, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)? = nil) {
public init(context: AccountContext, presentation: Signal<ContactListPresentation, NoError>, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil, displayPermissionPlaceholder: Bool = true, displaySortOptions: Bool = false, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)? = nil, isSearch: Bool = false) {
self.context = context
self.filters = filters
self.displayPermissionPlaceholder = displayPermissionPlaceholder
@ -926,6 +929,7 @@ public final class ContactListNode: ASDisplayNode {
foundLocalContacts = foundChatListPeers
|> mapToSignal { peers -> Signal<([FoundPeer], [PeerId: PeerPresence]), NoError> in
var resultPeers: [FoundPeer] = []
for peer in peers {
if searchGroups || searchChannels {
let mainPeer = peer.chatMainPeer
@ -991,16 +995,21 @@ public final class ContactListNode: ASDisplayNode {
foundDeviceContacts = .single([:])
}
return combineLatest(foundLocalContacts, foundRemoteContacts, foundDeviceContacts, selectionStateSignal, presentationDataPromise.get())
|> mapToQueue { localPeersAndStatuses, remotePeers, deviceContacts, selectionState, presentationData -> Signal<ContactsListNodeTransition, NoError> in
let accountPeer = context.account.postbox.loadedPeerWithId(context.account.peerId)
|> take(1)
return combineLatest(accountPeer, foundLocalContacts, foundRemoteContacts, foundDeviceContacts, selectionStateSignal, presentationDataPromise.get())
|> mapToQueue { accountPeer, localPeersAndStatuses, remotePeers, deviceContacts, selectionState, presentationData -> Signal<ContactsListNodeTransition, NoError> in
let signal = deferred { () -> Signal<ContactsListNodeTransition, NoError> in
var existingPeerIds = Set<PeerId>()
var disabledPeerIds = Set<PeerId>()
var existingNormalizedPhoneNumbers = Set<DeviceContactNormalizedPhoneNumber>()
var excludeSelf = false
for filter in filters {
switch filter {
case .excludeSelf:
excludeSelf = true
existingPeerIds.insert(context.account.peerId)
case let .exclude(peerIds):
existingPeerIds = existingPeerIds.union(peerIds)
@ -1010,6 +1019,15 @@ public final class ContactListNode: ASDisplayNode {
}
var peers: [ContactListPeer] = []
if !excludeSelf && !existingPeerIds.contains(accountPeer.id) {
let lowercasedQuery = query.lowercased()
if presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery) {
existingPeerIds.insert(accountPeer.id)
peers.append(.peer(peer: accountPeer, isGlobal: false, participantCount: nil))
}
}
for peer in localPeersAndStatuses.0 {
if !existingPeerIds.contains(peer.peer.id) {
existingPeerIds.insert(peer.peer.id)
@ -1097,7 +1115,7 @@ public final class ContactListNode: ASDisplayNode {
let entries = contactListNodeEntries(accountPeer: nil, peers: peers, presences: localPeersAndStatuses.1, presentation: presentation, selectionState: selectionState, theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, disabledPeerIds: disabledPeerIds, authorizationStatus: .allowed, warningSuppressed: (true, true), displaySortOptions: false)
let previous = previousEntries.swap(entries)
return .single(preparedContactListNodeTransition(context: context, presentationData: presentationData, from: previous ?? [], to: entries, interaction: interaction, firstTime: previous == nil, isEmpty: false, generateIndexSections: generateSections, animation: .none))
return .single(preparedContactListNodeTransition(context: context, presentationData: presentationData, from: previous ?? [], to: entries, interaction: interaction, firstTime: previous == nil, isEmpty: false, generateIndexSections: generateSections, animation: .none, isSearch: isSearch))
}
if OSAtomicCompareAndSwap32(1, 0, &firstTime) {
@ -1203,7 +1221,7 @@ public final class ContactListNode: ASDisplayNode {
animation = .none
}
return .single(preparedContactListNodeTransition(context: context, presentationData: presentationData, from: previous ?? [], to: entries, interaction: interaction, firstTime: previous == nil, isEmpty: isEmpty, generateIndexSections: generateSections, animation: animation))
return .single(preparedContactListNodeTransition(context: context, presentationData: presentationData, from: previous ?? [], to: entries, interaction: interaction, firstTime: previous == nil, isEmpty: isEmpty, generateIndexSections: generateSections, animation: animation, isSearch: isSearch))
}
if OSAtomicCompareAndSwap32(1, 0, &firstTime) {

View File

@ -34,6 +34,18 @@ public func removePeerChat(account: Account, transaction: Transaction, mediaBox:
}
})
}
updateChatListFiltersInteractively(transaction: transaction, { filters in
var filters = filters
for i in 0 ..< filters.count {
if filters[i].data.includePeers.peers.contains(peerId) {
filters[i].data.includePeers.setPeers(filters[i].data.includePeers.peers.filter { $0 != peerId })
}
if filters[i].data.excludePeers.contains(peerId) {
filters[i].data.excludePeers = filters[i].data.excludePeers.filter { $0 != peerId }
}
}
return filters
})
if peerId.namespace == Namespaces.Peer.SecretChat {
if let state = transaction.getPeerChatState(peerId) as? SecretChatState, state.embeddedState != .terminated {
let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: SecretChatOutgoingOperationContents.terminate(reportSpam: reportChatSpam), state: state).withUpdatedEmbeddedState(.terminated)

View File

@ -7,6 +7,7 @@ import SwiftSignalKit
import TelegramCore
import SyncCore
import TelegramPresentationData
import TelegramUIPreferences
import ProgressNavigationButtonNode
import AccountContext
import AlertUI
@ -14,6 +15,14 @@ import PresentationDataUtils
import ContactListUI
import CounterContollerTitleView
private func peerTokenTitle(accountPeerId: PeerId, peer: Peer, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder) -> String {
if peer.id == accountPeerId {
return strings.DialogList_SavedMessages
} else {
return peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder)
}
}
class ContactMultiselectionControllerImpl: ViewController, ContactMultiselectionController {
private let params: ContactMultiselectionControllerParams
private let context: AccountContext
@ -132,7 +141,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
}
}
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)
return EditableTokenListToken(id: peer.id, title: peerTokenTitle(accountPeerId: params.context.account.peerId, peer: peer, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder), fixedPosition: nil)
})
strongSelf._peersReady.set(.single(true))
if strongSelf.isNodeLoaded {
@ -203,7 +212,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
}
override func loadDisplayNode() {
self.displayNode = ContactMultiselectionControllerNode(context: self.context, mode: self.mode, options: self.options, filters: filters)
self.displayNode = ContactMultiselectionControllerNode(context: self.context, mode: self.mode, options: self.options, filters: self.filters)
switch self.contactsNode.contentNode {
case let .contacts(contactsNode):
self._listReady.set(contactsNode.ready)
@ -211,6 +220,8 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
self._listReady.set(chatsNode.ready)
}
let accountPeerId = self.context.account.peerId
self.contactsNode.dismiss = { [weak self] in
self?.presentingViewController?.dismiss(animated: true, completion: nil)
}
@ -237,7 +248,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), fixedPosition: nil)
addedToken = EditableTokenListToken(id: peer.id, title: peerTokenTitle(accountPeerId: accountPeerId, peer: peer, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder), fixedPosition: nil)
}
}
updatedCount = updatedState.selectedPeerIndices.count
@ -254,7 +265,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), fixedPosition: nil)
addedToken = EditableTokenListToken(id: peer.id, title: peerTokenTitle(accountPeerId: accountPeerId, peer: peer, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder), fixedPosition: nil)
state.selectedPeerIds.insert(peer.id)
}
updatedCount = state.selectedPeerIds.count

View File

@ -86,7 +86,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
if case let .chatSelection(_, selectedChats, additionalCategories) = mode {
placeholder = self.presentationData.strings.ChatListFilter_AddChatsTitle
let chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: 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)
let chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: [], 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
for peerId in selectedChats {
@ -182,7 +182,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
searchChannels = true
globalSearch = false
}
let searchResultsNode = ContactListNode(context: context, presentation: .single(.search(signal: searchText.get(), searchChatList: searchChatList, searchDeviceContacts: false, searchGroups: searchGroups, searchChannels: searchChannels, globalSearch: globalSearch)), filters: filters, selectionState: selectionState)
let searchResultsNode = ContactListNode(context: context, presentation: .single(.search(signal: searchText.get(), searchChatList: searchChatList, searchDeviceContacts: false, searchGroups: searchGroups, searchChannels: searchChannels, globalSearch: globalSearch)), filters: filters, selectionState: selectionState, isSearch: true)
searchResultsNode.openPeer = { peer in
self?.tokenListNode.setText("")
self?.openPeer?(peer)

View File

@ -17,6 +17,7 @@ static_library(
compiler_flags = [
"-Dpixman_region_selfcheck(x)=1",
"-DLOTTIE_DISABLE_ARM_NEON=1",
"-DLOTTIE_IMAGE_MODULE_DISABLED=1",
],
headers = glob([
"rlottie/src/**/*.h",

View File

@ -24,6 +24,7 @@ objc_library(
copts = [
"-Dpixman_region_selfcheck(x)=1",
"-DLOTTIE_DISABLE_ARM_NEON=1",
"-DLOTTIE_IMAGE_MODULE_DISABLED=1",
"-I{}".format(package_name()),
"-I{}/rlottie/inc".format(package_name()),
"-I{}/rlottie/src/vector".format(package_name()),