mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-06-20 18:24:43 +00:00
Merge branch 'master' into experimental-2
# Conflicts: # submodules/ChatListUI/Sources/ChatContextMenus.swift # submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift
This commit is contained in:
@@ -49,141 +49,162 @@ enum ChatContextMenuSource {
|
||||
func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: ChatListNodeEntryPromoInfo?, source: ChatContextMenuSource, chatListController: ChatListControllerImpl?, joined: Bool) -> Signal<[ContextMenuItem], NoError> {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
|
||||
let strings = presentationData.strings
|
||||
return context.account.postbox.transaction { [weak chatListController] transaction -> [ContextMenuItem] in
|
||||
if promoInfo != nil {
|
||||
return []
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
if case let .search(search) = source {
|
||||
switch search {
|
||||
case .recentPeers:
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
let _ = (context.engine.peers.removeRecentPeer(peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
items.append(.separator)
|
||||
case .recentSearch:
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
let _ = (context.engine.peers.removeRecentlySearchedPeer(peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
items.append(.separator)
|
||||
case .search:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let isSavedMessages = peerId == context.account.peerId
|
||||
|
||||
let chatPeer = transaction.getPeer(peerId)
|
||||
var maybePeer: Peer?
|
||||
if let chatPeer = chatPeer {
|
||||
if let chatPeer = chatPeer as? TelegramSecretChat {
|
||||
maybePeer = transaction.getPeer(chatPeer.regularPeerId)
|
||||
|
||||
return context.account.postbox.transaction { transaction -> (PeerGroupId, ChatListIndex)? in
|
||||
transaction.getPeerChatListIndex(peerId)
|
||||
}
|
||||
|> mapToSignal { groupAndIndex -> Signal<[ContextMenuItem], NoError> in
|
||||
let location: TogglePeerChatPinnedLocation
|
||||
var chatListFilter: ChatListFilter?
|
||||
if case let .chatList(filter) = source, let chatFilter = filter {
|
||||
chatListFilter = chatFilter
|
||||
location = .filter(chatFilter.id)
|
||||
} else {
|
||||
if let (group, _) = groupAndIndex {
|
||||
location = .group(group)
|
||||
} else {
|
||||
maybePeer = chatPeer
|
||||
}
|
||||
}
|
||||
|
||||
guard let peer = maybePeer else {
|
||||
return []
|
||||
}
|
||||
|
||||
if !isSavedMessages, let peer = peer as? TelegramUser, !peer.flags.contains(.isSupport) && peer.botInfo == nil && !peer.isDeleted {
|
||||
if !transaction.isPeerContact(peerId: peer.id) {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
context.sharedContext.openAddPersonContact(context: context, peerId: peerId, pushController: { controller in
|
||||
if let navigationController = chatListController?.navigationController as? NavigationController {
|
||||
navigationController.pushViewController(controller)
|
||||
}
|
||||
}, present: { c, a in
|
||||
if let chatListController = chatListController {
|
||||
chatListController.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
})
|
||||
f(.default)
|
||||
})))
|
||||
items.append(.separator)
|
||||
}
|
||||
}
|
||||
|
||||
var isMuted = false
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
||||
if case .muted = notificationSettings.muteState {
|
||||
isMuted = true
|
||||
location = .group(.root)
|
||||
}
|
||||
}
|
||||
|
||||
var isUnread = false
|
||||
if let readState = transaction.getCombinedPeerReadState(peerId), readState.isUnread {
|
||||
isUnread = true
|
||||
}
|
||||
|
||||
let isContact = transaction.isPeerContact(peerId: peerId)
|
||||
|
||||
if case let .chatList(currentFilter) = source {
|
||||
if let currentFilter = currentFilter {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
updateChatListFiltersInteractively(transaction: transaction, { filters in
|
||||
var filters = filters
|
||||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == currentFilter.id {
|
||||
let _ = filters[i].data.addExcludePeer(peerId: peer.id)
|
||||
break
|
||||
return combineLatest(
|
||||
context.engine.peers.updatedChatListFilters()
|
||||
|> take(1),
|
||||
context.engine.peers.getPinnedItemIds(location: location)
|
||||
)
|
||||
|> mapToSignal { filters, pinnedItemIds -> Signal<[ContextMenuItem], NoError> in
|
||||
let isPinned = pinnedItemIds.contains(.peer(peerId))
|
||||
|
||||
return context.account.postbox.transaction { [weak chatListController] transaction -> [ContextMenuItem] in
|
||||
if promoInfo != nil {
|
||||
return []
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
if case let .search(search) = source {
|
||||
switch search {
|
||||
case .recentPeers:
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
let _ = (context.engine.peers.removeRecentPeer(peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
items.append(.separator)
|
||||
case .recentSearch:
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
let _ = (context.engine.peers.removeRecentlySearchedPeer(peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
items.append(.separator)
|
||||
case .search:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let isSavedMessages = peerId == context.account.peerId
|
||||
|
||||
let chatPeer = transaction.getPeer(peerId)
|
||||
var maybePeer: Peer?
|
||||
if let chatPeer = chatPeer {
|
||||
if let chatPeer = chatPeer as? TelegramSecretChat {
|
||||
maybePeer = transaction.getPeer(chatPeer.regularPeerId)
|
||||
} else {
|
||||
maybePeer = chatPeer
|
||||
}
|
||||
}
|
||||
|
||||
guard let peer = maybePeer else {
|
||||
return []
|
||||
}
|
||||
|
||||
if !isSavedMessages, let peer = peer as? TelegramUser, !peer.flags.contains(.isSupport) && peer.botInfo == nil && !peer.isDeleted {
|
||||
if !transaction.isPeerContact(peerId: peer.id) {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
context.sharedContext.openAddPersonContact(context: context, peerId: peerId, pushController: { controller in
|
||||
if let navigationController = chatListController?.navigationController as? NavigationController {
|
||||
navigationController.pushViewController(controller)
|
||||
}
|
||||
}, present: { c, a in
|
||||
if let chatListController = chatListController {
|
||||
chatListController.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
})
|
||||
f(.default)
|
||||
})))
|
||||
items.append(.separator)
|
||||
}
|
||||
}
|
||||
|
||||
var isMuted = false
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
||||
if case .muted = notificationSettings.muteState {
|
||||
isMuted = true
|
||||
}
|
||||
}
|
||||
|
||||
var isUnread = false
|
||||
if let readState = transaction.getCombinedPeerReadState(peerId), readState.isUnread {
|
||||
isUnread = true
|
||||
}
|
||||
|
||||
let isContact = transaction.isPeerContact(peerId: peerId)
|
||||
|
||||
if case let .chatList(currentFilter) = source {
|
||||
if let currentFilter = currentFilter {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var filters = filters
|
||||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == currentFilter.id {
|
||||
let _ = filters[i].data.addExcludePeer(peerId: peer.id)
|
||||
break
|
||||
}
|
||||
}
|
||||
return filters
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
c.dismiss(completion: {
|
||||
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatRemovedFromFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: currentFilter.title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
|
||||
return false
|
||||
}), in: .current)
|
||||
})
|
||||
})
|
||||
})))
|
||||
} else {
|
||||
var hasFolders = false
|
||||
|
||||
for filter in filters {
|
||||
let predicate = chatListFilterPredicate(filter: filter.data)
|
||||
if predicate.includes(peer: peer, groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
|
||||
continue
|
||||
}
|
||||
|
||||
var data = filter.data
|
||||
if data.addIncludePeer(peerId: peer.id) {
|
||||
hasFolders = true
|
||||
break
|
||||
}
|
||||
return filters
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
c.dismiss(completion: {
|
||||
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatRemovedFromFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: currentFilter.title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
|
||||
return false
|
||||
}), in: .current)
|
||||
})
|
||||
})
|
||||
})))
|
||||
} else {
|
||||
var hasFolders = false
|
||||
updateChatListFiltersInteractively(transaction: transaction, { filters in
|
||||
for filter in filters {
|
||||
let predicate = chatListFilterPredicate(filter: filter.data)
|
||||
if predicate.includes(peer: peer, groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
|
||||
continue
|
||||
}
|
||||
|
||||
var data = filter.data
|
||||
if data.addIncludePeer(peerId: peer.id) {
|
||||
hasFolders = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return filters
|
||||
})
|
||||
|
||||
if hasFolders {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Folder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
let _ = (context.account.postbox.transaction { transaction -> [ContextMenuItem] in
|
||||
var updatedItems: [ContextMenuItem] = []
|
||||
updateChatListFiltersInteractively(transaction: transaction, { filters in
|
||||
|
||||
if hasFolders {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Folder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
var updatedItems: [ContextMenuItem] = []
|
||||
|
||||
for filter in filters {
|
||||
let predicate = chatListFilterPredicate(filter: filter.data)
|
||||
if predicate.includes(peer: peer, groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
var data = filter.data
|
||||
if !data.addIncludePeer(peerId: peer.id) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
let filterType = chatListFilterType(filter)
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: filter.title, icon: { theme in
|
||||
let imageName: String
|
||||
@@ -208,7 +229,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var filters = filters
|
||||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == filter.id {
|
||||
@@ -217,180 +238,160 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
}
|
||||
}
|
||||
return filters
|
||||
})).start()
|
||||
|
||||
}).start()
|
||||
|
||||
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatAddedToFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: filter.title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
|
||||
return false
|
||||
}), in: .current)
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
return filters
|
||||
})
|
||||
|
||||
updatedItems.append(.separator)
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined))
|
||||
|
||||
updatedItems.append(.separator)
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined))
|
||||
})))
|
||||
|
||||
c.setItems(.single(updatedItems))
|
||||
})))
|
||||
|
||||
return updatedItems
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { updatedItems in
|
||||
c.setItems(.single(updatedItems))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if isUnread {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
|
||||
f(.default)
|
||||
})))
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsUnread, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsUnread"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isUnread {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
|
||||
f(.default)
|
||||
})))
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsUnread, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsUnread"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
let groupAndIndex = transaction.getPeerChatListIndex(peerId)
|
||||
|
||||
let archiveEnabled = !isSavedMessages && peerId != PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(777000)) && peerId == context.account.peerId
|
||||
if let (group, index) = groupAndIndex {
|
||||
if archiveEnabled {
|
||||
let isArchived = group == Namespaces.PeerGroup.archive
|
||||
items.append(.action(ContextMenuActionItem(text: isArchived ? strings.ChatList_Context_Unarchive : strings.ChatList_Context_Archive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isArchived ? "Chat/Context Menu/Unarchive" : "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
if isArchived {
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
} else {
|
||||
if let chatListController = chatListController {
|
||||
chatListController.archiveChats(peerIds: [peerId])
|
||||
f(.default)
|
||||
} else {
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: Namespaces.PeerGroup.archive)
|
||||
|
||||
let archiveEnabled = !isSavedMessages && peerId != PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(777000)) && peerId == context.account.peerId
|
||||
if let (group, _) = groupAndIndex {
|
||||
if archiveEnabled {
|
||||
let isArchived = group == Namespaces.PeerGroup.archive
|
||||
items.append(.action(ContextMenuActionItem(text: isArchived ? strings.ChatList_Context_Unarchive : strings.ChatList_Context_Archive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isArchived ? "Chat/Context Menu/Unarchive" : "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
if isArchived {
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
} else {
|
||||
if let chatListController = chatListController {
|
||||
chatListController.archiveChats(peerIds: [peerId])
|
||||
f(.default)
|
||||
} else {
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: Namespaces.PeerGroup.archive)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
}
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
if isPinned || chatListFilter == nil || peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (context.engine.peers.toggleItemPinned(location: location, itemId: .peer(peerId))
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
switch result {
|
||||
case .done:
|
||||
break
|
||||
case .limitExceeded:
|
||||
break
|
||||
}
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
if !isSavedMessages, let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
||||
var isMuted = false
|
||||
if case .muted = notificationSettings.muteState {
|
||||
isMuted = true
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: isMuted ? strings.ChatList_Context_Unmute : strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
}
|
||||
} else {
|
||||
if case .search = source {
|
||||
if let _ = peer as? TelegramChannel {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_JoinChannel, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
var createSignal = context.peerChannelMemberCategoriesContextsManager.join(engine: context.engine, peerId: peerId, hash: nil)
|
||||
var cancelImpl: (() -> Void)?
|
||||
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
|
||||
cancelImpl?()
|
||||
}))
|
||||
chatListController?.present(controller, in: .window(.root))
|
||||
return ActionDisposable { [weak controller] in
|
||||
Queue.mainQueue().async() {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|> delay(0.15, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
createSignal = createSignal
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
progressDisposable.dispose()
|
||||
}
|
||||
}
|
||||
let joinChannelDisposable = MetaDisposable()
|
||||
cancelImpl = {
|
||||
joinChannelDisposable.set(nil)
|
||||
}
|
||||
|
||||
joinChannelDisposable.set((createSignal
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
if let navigationController = (chatListController?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
}, error: { _ in
|
||||
if let chatListController = chatListController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
chatListController.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
// if {
|
||||
let location: TogglePeerChatPinnedLocation
|
||||
var chatListFilter: ChatListFilter?
|
||||
if case let .chatList(filter) = source, let chatFilter = filter {
|
||||
chatListFilter = chatFilter
|
||||
location = .filter(chatFilter.id)
|
||||
} else {
|
||||
location = .group(group)
|
||||
}
|
||||
|
||||
let isPinned = getPinnedItemIds(transaction: transaction, location: location).contains(.peer(peerId))
|
||||
|
||||
if isPinned || chatListFilter == nil || peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (toggleItemPinned(postbox: context.account.postbox, location: location, itemId: .peer(peerId))
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
switch result {
|
||||
case .done:
|
||||
break
|
||||
case .limitExceeded:
|
||||
break
|
||||
}
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
}
|
||||
// }
|
||||
|
||||
if !isSavedMessages, let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
||||
var isMuted = false
|
||||
if case .muted = notificationSettings.muteState {
|
||||
isMuted = true
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: isMuted ? strings.ChatList_Context_Unmute : strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
}
|
||||
} else {
|
||||
if case .search = source {
|
||||
if let _ = peer as? TelegramChannel {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_JoinChannel, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
var createSignal = context.peerChannelMemberCategoriesContextsManager.join(engine: context.engine, peerId: peerId, hash: nil)
|
||||
var cancelImpl: (() -> Void)?
|
||||
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
|
||||
cancelImpl?()
|
||||
}))
|
||||
chatListController?.present(controller, in: .window(.root))
|
||||
return ActionDisposable { [weak controller] in
|
||||
Queue.mainQueue().async() {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
if case .chatList = source, groupAndIndex != nil {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
if let chatListController = chatListController {
|
||||
chatListController.deletePeerChat(peerId: peerId, joined: joined)
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|> delay(0.15, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
createSignal = createSignal
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
progressDisposable.dispose()
|
||||
}
|
||||
}
|
||||
let joinChannelDisposable = MetaDisposable()
|
||||
cancelImpl = {
|
||||
joinChannelDisposable.set(nil)
|
||||
}
|
||||
|
||||
joinChannelDisposable.set((createSignal
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
if let navigationController = (chatListController?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
}, error: { _ in
|
||||
if let chatListController = chatListController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
chatListController.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
if let item = items.last, case .separator = item {
|
||||
items.removeLast()
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
if case .chatList = source, groupAndIndex != nil {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
if let chatListController = chatListController {
|
||||
chatListController.deletePeerChat(peerId: peerId, joined: joined)
|
||||
}
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
if let item = items.last, case .separator = item {
|
||||
items.removeLast()
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
@@ -892,7 +892,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
})
|
||||
|> mapToSignal { selectedPeerIdsAndFilterId -> Signal<(ChatListSelectionOptions, Set<PeerId>)?, NoError> in
|
||||
if let (selectedPeerIds, filterId) = selectedPeerIdsAndFilterId {
|
||||
return chatListSelectionOptions(postbox: context.account.postbox, peerIds: selectedPeerIds, filterId: filterId)
|
||||
return chatListSelectionOptions(context: context, peerIds: selectedPeerIds, filterId: filterId)
|
||||
|> map { options -> (ChatListSelectionOptions, Set<PeerId>)? in
|
||||
return (options, selectedPeerIds)
|
||||
}
|
||||
@@ -982,7 +982,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (currentChatListFilters(postbox: strongSelf.context.account.postbox)
|
||||
let _ = (strongSelf.context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] filters in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@@ -996,7 +996,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (currentChatListFilters(postbox: strongSelf.context.account.postbox)
|
||||
let _ = (strongSelf.context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { presetList in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@@ -1024,7 +1024,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (currentChatListFilters(postbox: strongSelf.context.account.postbox)
|
||||
let _ = (strongSelf.context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { presetList in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@@ -1032,7 +1032,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
var found = false
|
||||
for filter in presetList {
|
||||
if filter.id == id {
|
||||
let _ = (currentChatListFilters(postbox: strongSelf.context.account.postbox)
|
||||
let _ = (strongSelf.context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { filters in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@@ -1272,6 +1272,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
return
|
||||
}
|
||||
if !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing {
|
||||
var isEditing = false
|
||||
strongSelf.chatListDisplayNode.containerNode.updateState { state in
|
||||
isEditing = state.editing
|
||||
return state
|
||||
}
|
||||
if !isEditing {
|
||||
strongSelf.editPressed()
|
||||
}
|
||||
strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing = true
|
||||
if let layout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
@@ -1292,7 +1300,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
|> take(1)
|
||||
|
||||
let initializedFilters = updatedChatListFiltersInfo(postbox: self.context.account.postbox)
|
||||
let initializedFilters = self.context.engine.peers.updatedChatListFiltersInfo()
|
||||
|> mapToSignal { (filters, isInitialized) -> Signal<Bool, NoError> in
|
||||
if isInitialized {
|
||||
return .single(!filters.isEmpty)
|
||||
@@ -1328,7 +1336,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
let text: String
|
||||
if hasFilters {
|
||||
text = strongSelf.presentationData.strings.ChatList_TabIconFoldersTooltipNonEmptyFolders
|
||||
let _ = markChatListFeaturedFiltersAsSeen(postbox: strongSelf.context.account.postbox).start()
|
||||
let _ = strongSelf.context.engine.peers.markChatListFeaturedFiltersAsSeen().start()
|
||||
return
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.ChatList_TabIconFoldersTooltipEmptyFolders
|
||||
@@ -1487,7 +1495,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
|
||||
if let reorderedFilterIds = reorderedFilterIdsValue {
|
||||
let _ = (updateChatListFiltersInteractively(postbox: self.context.account.postbox, { stateFilters in
|
||||
let _ = (self.context.engine.peers.updateChatListFiltersInteractively { stateFilters in
|
||||
var updatedFilters: [ChatListFilter] = []
|
||||
for id in reorderedFilterIds {
|
||||
if let index = stateFilters.firstIndex(where: { $0.id == id }) {
|
||||
@@ -1502,7 +1510,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
})
|
||||
return updatedFilters
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@@ -1535,7 +1543,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let filterItems = chatListFilterItems(postbox: self.context.account.postbox)
|
||||
let filterItems = chatListFilterItems(context: self.context)
|
||||
var notifiedFirstUpdate = false
|
||||
self.filterDisposable.set((combineLatest(queue: .mainQueue(),
|
||||
context.account.postbox.combinedView(keys: [
|
||||
@@ -1644,7 +1652,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (currentChatListFilters(postbox: self.context.account.postbox)
|
||||
let _ = (self.context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] filters in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@@ -1701,7 +1709,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
}
|
||||
|
||||
let _ = updateChatListFiltersInteractively(postbox: strongSelf.context.account.postbox, { filters in
|
||||
let _ = (strongSelf.context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
return filters.filter({ $0.id != id })
|
||||
}).start()
|
||||
}
|
||||
@@ -2757,8 +2765,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
|
||||
let _ = (combineLatest(queue: .mainQueue(),
|
||||
currentChatListFilters(postbox: self.context.account.postbox),
|
||||
chatListFilterItems(postbox: self.context.account.postbox)
|
||||
self.context.engine.peers.currentChatListFilters(),
|
||||
chatListFilterItems(context: self.context)
|
||||
|> take(1)
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presetList, filterItemsAndTotalCount in
|
||||
@@ -2766,7 +2774,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
return
|
||||
}
|
||||
|
||||
let _ = markChatListFeaturedFiltersAsSeen(postbox: strongSelf.context.account.postbox).start()
|
||||
let _ = strongSelf.context.engine.peers.markChatListFeaturedFiltersAsSeen().start()
|
||||
|
||||
let (_, filterItems) = filterItemsAndTotalCount
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
||||
let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let timestamp1: Int32 = 100000
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
||||
@@ -624,7 +624,7 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
|
||||
}
|
||||
|
||||
if applyAutomatically {
|
||||
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var filters = filters
|
||||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == filter.id {
|
||||
@@ -634,7 +634,7 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
|
||||
}
|
||||
}
|
||||
return filters
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
controller?.dismiss()
|
||||
})
|
||||
@@ -702,7 +702,7 @@ private func internalChatListFilterExcludeChatsController(context: AccountContex
|
||||
excludePeers.sort()
|
||||
|
||||
if applyAutomatically {
|
||||
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var filters = filters
|
||||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == filter.id {
|
||||
@@ -714,7 +714,7 @@ private func internalChatListFilterExcludeChatsController(context: AccountContex
|
||||
}
|
||||
}
|
||||
return filters
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
controller?.dismiss()
|
||||
})
|
||||
@@ -835,7 +835,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
includePeers.setPeers(state.additionallyIncludePeers)
|
||||
let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||
|
||||
let _ = (currentChatListFilters(postbox: context.account.postbox)
|
||||
let _ = (context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { filters in
|
||||
let controller = internalChatListFilterAddChatsController(context: context, filter: filter, allFilters: filters, applyAutomatically: false, updated: { filter in
|
||||
skipStateAnimation = true
|
||||
@@ -856,7 +856,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
includePeers.setPeers(state.additionallyIncludePeers)
|
||||
let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||
|
||||
let _ = (currentChatListFilters(postbox: context.account.postbox)
|
||||
let _ = (context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { filters in
|
||||
let controller = internalChatListFilterExcludeChatsController(context: context, filter: filter, allFilters: filters, applyAutomatically: false, updated: { filter in
|
||||
skipStateAnimation = true
|
||||
@@ -985,12 +985,12 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
var attemptNavigationImpl: (() -> Bool)?
|
||||
let applyImpl: (() -> Void)? = {
|
||||
let state = stateValue.with { $0 }
|
||||
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var includePeers = ChatListFilterIncludePeers()
|
||||
includePeers.setPeers(state.additionallyIncludePeers)
|
||||
var updatedFilter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||
if currentPreset == nil {
|
||||
updatedFilter.id = generateNewChatListFilterId(filters: filters)
|
||||
updatedFilter.id = context.engine.peers.generateNewChatListFilterId(filters: filters)
|
||||
}
|
||||
var filters = filters
|
||||
if let _ = currentPreset {
|
||||
@@ -1017,7 +1017,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
filters.append(updatedFilter)
|
||||
}
|
||||
return filters
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { filters in
|
||||
updated(filters)
|
||||
dismissImpl?()
|
||||
|
||||
@@ -249,12 +249,12 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
||||
|
||||
let arguments = ChatListFilterPresetListControllerArguments(context: context,
|
||||
addSuggestedPresed: { title, data in
|
||||
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var filters = filters
|
||||
let id = generateNewChatListFilterId(filters: filters)
|
||||
let id = context.engine.peers.generateNewChatListFilterId(filters: filters)
|
||||
filters.insert(ChatListFilter(id: id, title: title, emoticon: nil, data: data), at: 0)
|
||||
return filters
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
})
|
||||
}, openPreset: { preset in
|
||||
@@ -279,13 +279,13 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
||||
ActionSheetButtonItem(title: presentationData.strings.ChatList_RemoveFolderAction, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var filters = filters
|
||||
if let index = filters.firstIndex(where: { $0.id == id }) {
|
||||
filters.remove(at: index)
|
||||
}
|
||||
return filters
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start()
|
||||
})
|
||||
]),
|
||||
@@ -300,30 +300,12 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
||||
|
||||
let chatCountCache = Atomic<[ChatListFilterData: Int]>(value: [:])
|
||||
|
||||
let filtersWithCountsSignal = updatedChatListFilters(postbox: context.account.postbox)
|
||||
let filtersWithCountsSignal = context.engine.peers.updatedChatListFilters()
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { filters -> Signal<[(ChatListFilter, Int)], NoError> in
|
||||
return .single(filters.map { filter -> (ChatListFilter, Int) in
|
||||
return (filter, 0)
|
||||
})
|
||||
/*return context.account.postbox.transaction { transaction -> [(ChatListFilter, Int)] in
|
||||
return filters.map { filter -> (ChatListFilter, Int) in
|
||||
let count: Int
|
||||
if let cachedValue = chatCountCache.with({ dict -> Int? in
|
||||
return dict[filter.data]
|
||||
}) {
|
||||
count = cachedValue
|
||||
} else {
|
||||
count = transaction.getChatCountMatchingPredicate(chatListFilterPredicate(filter: filter.data))
|
||||
let _ = chatCountCache.modify { dict in
|
||||
var dict = dict
|
||||
dict[filter.data] = count
|
||||
return dict
|
||||
}
|
||||
}
|
||||
return (filter, count)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
let featuredFilters = context.account.postbox.preferencesView(keys: [PreferencesKeys.chatListFiltersFeaturedState])
|
||||
@@ -368,7 +350,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak updatedFilterOrder] updatedFilterOrderValue in
|
||||
if let updatedFilterOrderValue = updatedFilterOrderValue {
|
||||
let _ = (updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in
|
||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||
var updatedFilters: [ChatListFilter] = []
|
||||
for id in updatedFilterOrderValue {
|
||||
if let index = filters.firstIndex(where: { $0.id == id }) {
|
||||
@@ -382,7 +364,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
||||
}
|
||||
|
||||
return updatedFilters
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
filtersWithCounts.set(filtersWithCountsSignal)
|
||||
let _ = (filtersWithCounts.get()
|
||||
|
||||
@@ -1217,6 +1217,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
self?.listNode.clearHighlightAnimated(true)
|
||||
}, disabledPeerSelected: { _ in
|
||||
}, togglePeerSelected: { _ in
|
||||
}, togglePeersSelection: { _, _ in
|
||||
}, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { [weak self] peer, message, _ in
|
||||
interaction.dismissInput()
|
||||
@@ -2324,7 +2325,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||
let timestamp1: Int32 = 100000
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
peers[peer1.id] = peer1
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
||||
@@ -4,6 +4,7 @@ import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import AccountContext
|
||||
|
||||
enum ChatListSelectionReadOption: Equatable {
|
||||
case all(enabled: Bool)
|
||||
@@ -15,10 +16,10 @@ struct ChatListSelectionOptions: Equatable {
|
||||
let delete: Bool
|
||||
}
|
||||
|
||||
func chatListSelectionOptions(postbox: Postbox, peerIds: Set<PeerId>, filterId: Int32?) -> Signal<ChatListSelectionOptions, NoError> {
|
||||
func chatListSelectionOptions(context: AccountContext, peerIds: Set<PeerId>, filterId: Int32?) -> Signal<ChatListSelectionOptions, NoError> {
|
||||
if peerIds.isEmpty {
|
||||
if let filterId = filterId {
|
||||
return chatListFilterItems(postbox: postbox)
|
||||
return chatListFilterItems(context: context)
|
||||
|> map { filterItems -> ChatListSelectionOptions in
|
||||
for (filter, unreadCount, _) in filterItems.1 {
|
||||
if filter.id == filterId {
|
||||
@@ -30,7 +31,7 @@ func chatListSelectionOptions(postbox: Postbox, peerIds: Set<PeerId>, filterId:
|
||||
|> distinctUntilChanged
|
||||
} else {
|
||||
let key = PostboxViewKey.unreadCounts(items: [.total(nil)])
|
||||
return postbox.combinedView(keys: [key])
|
||||
return context.account.postbox.combinedView(keys: [key])
|
||||
|> map { view -> ChatListSelectionOptions in
|
||||
var hasUnread = false
|
||||
if let unreadCounts = view.views[key] as? UnreadMessageCountsView, let total = unreadCounts.total() {
|
||||
@@ -48,7 +49,7 @@ func chatListSelectionOptions(postbox: Postbox, peerIds: Set<PeerId>, filterId:
|
||||
} else {
|
||||
let items: [UnreadMessageCountsItem] = peerIds.map(UnreadMessageCountsItem.peer)
|
||||
let key = PostboxViewKey.unreadCounts(items: items)
|
||||
return postbox.combinedView(keys: [key])
|
||||
return context.account.postbox.combinedView(keys: [key])
|
||||
|> map { view -> ChatListSelectionOptions in
|
||||
var hasUnread = false
|
||||
if let unreadCounts = view.views[key] as? UnreadMessageCountsView {
|
||||
|
||||
@@ -696,7 +696,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
|
||||
}
|
||||
|
||||
self.contextContainer.isGestureEnabled = enablePreview
|
||||
self.contextContainer.isGestureEnabled = enablePreview && !item.editing
|
||||
}
|
||||
|
||||
override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
|
||||
@@ -1509,7 +1509,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.onlineIsVoiceChat = onlineIsVoiceChat
|
||||
|
||||
strongSelf.contextContainer.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
|
||||
|
||||
if case .groupReference = item.content {
|
||||
strongSelf.layer.sublayerTransform = CATransform3DMakeTranslation(0.0, layout.contentSize.height - itemHeight, 0.0)
|
||||
}
|
||||
|
||||
@@ -48,10 +48,16 @@ final class ChatListHighlightedLocation {
|
||||
}
|
||||
|
||||
public final class ChatListNodeInteraction {
|
||||
public enum PeerEntry {
|
||||
case peerId(PeerId)
|
||||
case peer(Peer)
|
||||
}
|
||||
|
||||
let activateSearch: () -> Void
|
||||
let peerSelected: (Peer, ChatListNodeEntryPromoInfo?) -> Void
|
||||
let disabledPeerSelected: (Peer) -> Void
|
||||
let togglePeerSelected: (Peer) -> Void
|
||||
let togglePeersSelection: ([PeerEntry], Bool) -> Void
|
||||
let additionalCategorySelected: (Int) -> Void
|
||||
let messageSelected: (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void
|
||||
let groupSelected: (PeerGroupId) -> Void
|
||||
@@ -70,11 +76,12 @@ public final class ChatListNodeInteraction {
|
||||
public var searchTextHighightState: String?
|
||||
var highlightedChatLocation: ChatListHighlightedLocation?
|
||||
|
||||
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer, ChatListNodeEntryPromoInfo?) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (Peer) -> Void, additionalCategorySelected: @escaping (Int) -> Void, messageSelected: @escaping (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId, Bool) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, hidePsa: @escaping (PeerId) -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) {
|
||||
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer, ChatListNodeEntryPromoInfo?) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (Peer) -> Void, togglePeersSelection: @escaping ([PeerEntry], Bool) -> Void, additionalCategorySelected: @escaping (Int) -> Void, messageSelected: @escaping (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId, Bool) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, hidePsa: @escaping (PeerId) -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) {
|
||||
self.activateSearch = activateSearch
|
||||
self.peerSelected = peerSelected
|
||||
self.disabledPeerSelected = disabledPeerSelected
|
||||
self.togglePeerSelected = togglePeerSelected
|
||||
self.togglePeersSelection = togglePeersSelection
|
||||
self.additionalCategorySelected = additionalCategorySelected
|
||||
self.messageSelected = messageSelected
|
||||
self.groupSelected = groupSelected
|
||||
@@ -565,6 +572,8 @@ public final class ChatListNode: ListView {
|
||||
var didBeginSelectingChats: (() -> Void)?
|
||||
public var selectionCountChanged: ((Int) -> Void)?
|
||||
|
||||
var isSelectionGestureEnabled = true
|
||||
|
||||
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
|
||||
@@ -625,6 +634,34 @@ public final class ChatListNode: ListView {
|
||||
if didBeginSelecting {
|
||||
self?.didBeginSelectingChats?()
|
||||
}
|
||||
}, togglePeersSelection: { [weak self] peers, selected in
|
||||
self?.updateState { state in
|
||||
var state = state
|
||||
if selected {
|
||||
for peerEntry in peers {
|
||||
switch peerEntry {
|
||||
case let .peer(peer):
|
||||
state.selectedPeerIds.insert(peer.id)
|
||||
state.selectedPeerMap[peer.id] = peer
|
||||
case let .peerId(peerId):
|
||||
state.selectedPeerIds.insert(peerId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for peerEntry in peers {
|
||||
switch peerEntry {
|
||||
case let .peer(peer):
|
||||
state.selectedPeerIds.remove(peer.id)
|
||||
case let .peerId(peerId):
|
||||
state.selectedPeerIds.remove(peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
if selected && !peers.isEmpty {
|
||||
self?.didBeginSelectingChats?()
|
||||
}
|
||||
}, additionalCategorySelected: { [weak self] id in
|
||||
self?.additionalCategorySelected?(id)
|
||||
}, messageSelected: { [weak self] peer, message, promoInfo in
|
||||
@@ -666,7 +703,7 @@ public final class ChatListNode: ListView {
|
||||
} else {
|
||||
location = .group(groupId)
|
||||
}
|
||||
let _ = (toggleItemPinned(postbox: context.account.postbox, location: location, itemId: itemId)
|
||||
let _ = (context.engine.peers.toggleItemPinned(location: location, itemId: itemId)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
if let strongSelf = self {
|
||||
switch result {
|
||||
@@ -1167,16 +1204,18 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
|
||||
if case let .index(index) = fromEntry.sortIndex, let _ = index.pinningIndex {
|
||||
return strongSelf.context.account.postbox.transaction { transaction -> Bool in
|
||||
let location: TogglePeerChatPinnedLocation
|
||||
if let chatListFilter = chatListFilter {
|
||||
location = .filter(chatListFilter.id)
|
||||
} else {
|
||||
location = .group(groupId)
|
||||
}
|
||||
|
||||
var itemIds = getPinnedItemIds(transaction: transaction, location: location)
|
||||
|
||||
let location: TogglePeerChatPinnedLocation
|
||||
if let chatListFilter = chatListFilter {
|
||||
location = .filter(chatListFilter.id)
|
||||
} else {
|
||||
location = .group(groupId)
|
||||
}
|
||||
|
||||
let engine = strongSelf.context.engine
|
||||
return engine.peers.getPinnedItemIds(location: location)
|
||||
|> mapToSignal { itemIds -> Signal<Bool, NoError> in
|
||||
var itemIds = itemIds
|
||||
|
||||
var itemId: PinnedItemId?
|
||||
switch fromEntry {
|
||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
@@ -1184,7 +1223,7 @@ public final class ChatListNode: ListView {
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
if let itemId = itemId {
|
||||
itemIds = itemIds.filter({ $0 != itemId })
|
||||
if let referenceId = referenceId {
|
||||
@@ -1208,9 +1247,9 @@ public final class ChatListNode: ListView {
|
||||
} else {
|
||||
itemIds.append(itemId)
|
||||
}
|
||||
return reorderPinnedItemIds(transaction: transaction, location: location, itemIds: itemIds)
|
||||
return engine.peers.reorderPinnedItemIds(location: location, itemIds: itemIds)
|
||||
} else {
|
||||
return false
|
||||
return .single(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1315,6 +1354,15 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
|
||||
self.resetFilter()
|
||||
|
||||
let selectionRecognizer = ChatHistoryListSelectionRecognizer(target: self, action: #selector(self.selectionPanGesture(_:)))
|
||||
selectionRecognizer.shouldBegin = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
return strongSelf.isSelectionGestureEnabled
|
||||
}
|
||||
self.view.addGestureRecognizer(selectionRecognizer)
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -1332,7 +1380,7 @@ public final class ChatListNode: ListView {
|
||||
|
||||
private func resetFilter() {
|
||||
if let chatListFilter = self.chatListFilter {
|
||||
self.updatedFilterDisposable.set((updatedChatListFilters(postbox: self.context.account.postbox)
|
||||
self.updatedFilterDisposable.set((self.context.engine.peers.updatedChatListFilters()
|
||||
|> map { filters -> ChatListFilter? in
|
||||
for filter in filters {
|
||||
if filter.id == chatListFilter.id {
|
||||
@@ -1898,6 +1946,140 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func peerAtPoint(_ point: CGPoint) -> Peer? {
|
||||
var resultPeer: Peer?
|
||||
self.forEachVisibleItemNode { itemNode in
|
||||
if resultPeer == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) {
|
||||
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
||||
switch item.content {
|
||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _):
|
||||
resultPeer = peer.peer
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultPeer
|
||||
}
|
||||
|
||||
private var selectionPanState: (selecting: Bool, initialPeerId: PeerId, toggledPeerIds: [[PeerId]])?
|
||||
private var selectionScrollActivationTimer: SwiftSignalKit.Timer?
|
||||
private var selectionScrollDisplayLink: ConstantDisplayLinkAnimator?
|
||||
private var selectionScrollDelta: CGFloat?
|
||||
private var selectionLastLocation: CGPoint?
|
||||
|
||||
@objc private func selectionPanGesture(_ recognizer: UIGestureRecognizer) -> Void {
|
||||
let location = recognizer.location(in: self.view)
|
||||
switch recognizer.state {
|
||||
case .began:
|
||||
if let peer = self.peerAtPoint(location) {
|
||||
let selecting = !self.currentState.selectedPeerIds.contains(peer.id)
|
||||
self.selectionPanState = (selecting, peer.id, [])
|
||||
self.interaction?.togglePeersSelection([.peer(peer)], selecting)
|
||||
}
|
||||
case .changed:
|
||||
self.handlePanSelection(location: location)
|
||||
self.selectionLastLocation = location
|
||||
case .ended, .failed, .cancelled:
|
||||
self.selectionPanState = nil
|
||||
self.selectionScrollDisplayLink = nil
|
||||
self.selectionScrollActivationTimer?.invalidate()
|
||||
self.selectionScrollActivationTimer = nil
|
||||
self.selectionScrollDelta = nil
|
||||
self.selectionLastLocation = nil
|
||||
self.selectionScrollSkipUpdate = false
|
||||
case .possible:
|
||||
break
|
||||
@unknown default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
private func handlePanSelection(location: CGPoint) {
|
||||
if let state = self.selectionPanState {
|
||||
if let peer = self.peerAtPoint(location) {
|
||||
if peer.id == state.initialPeerId {
|
||||
if !state.toggledPeerIds.isEmpty {
|
||||
self.interaction?.togglePeersSelection(state.toggledPeerIds.flatMap { $0.compactMap({ .peerId($0) }) }, !state.selecting)
|
||||
self.selectionPanState = (state.selecting, state.initialPeerId, [])
|
||||
}
|
||||
} else if state.toggledPeerIds.last?.first != peer.id {
|
||||
var updatedToggledPeerIds: [[PeerId]] = []
|
||||
var previouslyToggled = false
|
||||
for i in (0 ..< state.toggledPeerIds.count) {
|
||||
if let peerId = state.toggledPeerIds[i].first {
|
||||
if peerId == peer.id {
|
||||
previouslyToggled = true
|
||||
updatedToggledPeerIds = Array(state.toggledPeerIds.prefix(i + 1))
|
||||
|
||||
let peerIdsToToggle = Array(state.toggledPeerIds.suffix(state.toggledPeerIds.count - i - 1)).flatMap { $0 }
|
||||
self.interaction?.togglePeersSelection(peerIdsToToggle.compactMap { .peerId($0) }, !state.selecting)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !previouslyToggled {
|
||||
updatedToggledPeerIds = state.toggledPeerIds
|
||||
let isSelected = self.currentState.selectedPeerIds.contains(peer.id)
|
||||
if state.selecting != isSelected {
|
||||
updatedToggledPeerIds.append([peer.id])
|
||||
self.interaction?.togglePeersSelection([.peer(peer)], state.selecting)
|
||||
}
|
||||
}
|
||||
|
||||
self.selectionPanState = (state.selecting, state.initialPeerId, updatedToggledPeerIds)
|
||||
}
|
||||
}
|
||||
|
||||
let scrollingAreaHeight: CGFloat = 50.0
|
||||
if location.y < scrollingAreaHeight + self.insets.top || location.y > self.frame.height - scrollingAreaHeight - self.insets.bottom {
|
||||
if location.y < self.frame.height / 2.0 {
|
||||
self.selectionScrollDelta = (scrollingAreaHeight - (location.y - self.insets.top)) / scrollingAreaHeight
|
||||
} else {
|
||||
self.selectionScrollDelta = -(scrollingAreaHeight - min(scrollingAreaHeight, max(0.0, (self.frame.height - self.insets.bottom - location.y)))) / scrollingAreaHeight
|
||||
}
|
||||
if let displayLink = self.selectionScrollDisplayLink {
|
||||
displayLink.isPaused = false
|
||||
} else {
|
||||
if let _ = self.selectionScrollActivationTimer {
|
||||
} else {
|
||||
let timer = SwiftSignalKit.Timer(timeout: 0.45, repeat: false, completion: { [weak self] in
|
||||
self?.setupSelectionScrolling()
|
||||
}, queue: .mainQueue())
|
||||
timer.start()
|
||||
self.selectionScrollActivationTimer = timer
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.selectionScrollDisplayLink?.isPaused = true
|
||||
self.selectionScrollActivationTimer?.invalidate()
|
||||
self.selectionScrollActivationTimer = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var selectionScrollSkipUpdate = false
|
||||
private func setupSelectionScrolling() {
|
||||
self.selectionScrollDisplayLink = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||
self?.selectionScrollActivationTimer = nil
|
||||
if let strongSelf = self, let delta = strongSelf.selectionScrollDelta {
|
||||
let distance: CGFloat = 15.0 * min(1.0, 0.15 + abs(delta * delta))
|
||||
let direction: ListViewScrollDirection = delta > 0.0 ? .up : .down
|
||||
let _ = strongSelf.scrollWithDirection(direction, distance: distance)
|
||||
|
||||
if let location = strongSelf.selectionLastLocation {
|
||||
if !strongSelf.selectionScrollSkipUpdate {
|
||||
strongSelf.handlePanSelection(location: location)
|
||||
}
|
||||
strongSelf.selectionScrollSkipUpdate = !strongSelf.selectionScrollSkipUpdate
|
||||
}
|
||||
}
|
||||
})
|
||||
self.selectionScrollDisplayLink?.isPaused = false
|
||||
}
|
||||
}
|
||||
|
||||
private func statusStringForPeerType(accountPeerId: PeerId, strings: PresentationStrings, peer: Peer, isMuted: Bool, isUnread: Bool, isContact: Bool, hasUnseenMentions: Bool, chatListFilters: [ChatListFilter]?) -> (String, Bool)? {
|
||||
@@ -1951,3 +2133,65 @@ private func statusStringForPeerType(accountPeerId: PeerId, strings: Presentatio
|
||||
}
|
||||
return (strings.ChatList_PeerTypeNonContact, false)
|
||||
}
|
||||
|
||||
public class ChatHistoryListSelectionRecognizer: UIPanGestureRecognizer {
|
||||
private let selectionGestureActivationThreshold: CGFloat = 5.0
|
||||
|
||||
var recognized: Bool? = nil
|
||||
var initialLocation: CGPoint = CGPoint()
|
||||
|
||||
public var shouldBegin: (() -> Bool)?
|
||||
|
||||
public override init(target: Any?, action: Selector?) {
|
||||
super.init(target: target, action: action)
|
||||
|
||||
self.minimumNumberOfTouches = 2
|
||||
self.maximumNumberOfTouches = 2
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
|
||||
self.recognized = nil
|
||||
}
|
||||
|
||||
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
if let shouldBegin = self.shouldBegin, !shouldBegin() {
|
||||
self.state = .failed
|
||||
} else {
|
||||
let touch = touches.first!
|
||||
self.initialLocation = touch.location(in: self.view)
|
||||
}
|
||||
}
|
||||
|
||||
public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
let location = touches.first!.location(in: self.view)
|
||||
let translation = location.offsetBy(dx: -self.initialLocation.x, dy: -self.initialLocation.y)
|
||||
|
||||
let touchesArray = Array(touches)
|
||||
if self.recognized == nil, touchesArray.count == 2 {
|
||||
if let firstTouch = touchesArray.first, let secondTouch = touchesArray.last {
|
||||
let firstLocation = firstTouch.location(in: self.view)
|
||||
let secondLocation = secondTouch.location(in: self.view)
|
||||
|
||||
func distance(_ v1: CGPoint, _ v2: CGPoint) -> CGFloat {
|
||||
let dx = v1.x - v2.x
|
||||
let dy = v1.y - v2.y
|
||||
return sqrt(dx * dx + dy * dy)
|
||||
}
|
||||
if distance(firstLocation, secondLocation) > 200.0 {
|
||||
self.state = .failed
|
||||
}
|
||||
}
|
||||
if self.state != .failed && (abs(translation.y) >= selectionGestureActivationThreshold) {
|
||||
self.recognized = true
|
||||
}
|
||||
}
|
||||
|
||||
if let recognized = self.recognized, recognized {
|
||||
super.touchesMoved(touches, with: event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import Postbox
|
||||
import TelegramUIPreferences
|
||||
import TelegramCore
|
||||
|
||||
func chatListFilterItems(postbox: Postbox) -> Signal<(Int, [(ChatListFilter, Int, Bool)]), NoError> {
|
||||
return updatedChatListFilters(postbox: postbox)
|
||||
func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilter, Int, Bool)]), NoError> {
|
||||
return context.engine.peers.updatedChatListFilters()
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { filters -> Signal<(Int, [(ChatListFilter, Int, Bool)]), NoError> in
|
||||
var unreadCountItems: [UnreadMessageCountsItem] = []
|
||||
@@ -40,8 +40,8 @@ func chatListFilterItems(postbox: Postbox) -> Signal<(Int, [(ChatListFilter, Int
|
||||
keys.append(.basicPeer(peerId))
|
||||
}
|
||||
|
||||
return combineLatest(queue: postbox.queue,
|
||||
postbox.combinedView(keys: keys),
|
||||
return combineLatest(queue: context.account.postbox.queue,
|
||||
context.account.postbox.combinedView(keys: keys),
|
||||
Signal<Bool, NoError>.single(true)
|
||||
)
|
||||
|> map { view, _ -> (Int, [(ChatListFilter, Int, Bool)]) in
|
||||
@@ -63,7 +63,7 @@ func chatListFilterItems(postbox: Postbox) -> Signal<(Int, [(ChatListFilter, Int
|
||||
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 = postbox.seedConfiguration.peerSummaryCounterTags(peer, peerView.isContact)
|
||||
let tag = context.account.postbox.seedConfiguration.peerSummaryCounterTags(peer, peerView.isContact)
|
||||
|
||||
var peerCount = Int(state.count)
|
||||
if state.isUnread {
|
||||
|
||||
Reference in New Issue
Block a user