mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Tab experiment fixes
This commit is contained in:
parent
4985071385
commit
41cb303841
@ -5,7 +5,7 @@ import Postbox
|
|||||||
|
|
||||||
public enum ContactMultiselectionControllerMode {
|
public enum ContactMultiselectionControllerMode {
|
||||||
case groupCreation
|
case groupCreation
|
||||||
case peerSelection(searchChatList: Bool, searchGroups: Bool)
|
case peerSelection(searchChatList: Bool, searchGroups: Bool, searchChannels: Bool)
|
||||||
case channelCreation
|
case channelCreation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,10 +232,22 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
if strongSelf.chatListDisplayNode.searchDisplayController != nil {
|
if strongSelf.chatListDisplayNode.searchDisplayController != nil {
|
||||||
strongSelf.deactivateSearch(animated: true)
|
strongSelf.deactivateSearch(animated: true)
|
||||||
} else {
|
} else {
|
||||||
if let searchContentNode = strongSelf.searchContentNode {
|
switch strongSelf.chatListDisplayNode.chatListNode.visibleContentOffset() {
|
||||||
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
case .none, .unknown:
|
||||||
|
if let searchContentNode = strongSelf.searchContentNode {
|
||||||
|
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
||||||
|
}
|
||||||
|
strongSelf.chatListDisplayNode.chatListNode.scrollToPosition(.top)
|
||||||
|
case let .known(offset):
|
||||||
|
if offset <= navigationBarSearchContentHeight + 1.0 {
|
||||||
|
strongSelf.tabContainerNode.tabSelected?(.all)
|
||||||
|
} else {
|
||||||
|
if let searchContentNode = strongSelf.searchContentNode {
|
||||||
|
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
||||||
|
}
|
||||||
|
strongSelf.chatListDisplayNode.chatListNode.scrollToPosition(.top)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
strongSelf.chatListDisplayNode.chatListNode.scrollToPosition(.top)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.longTapWithTabBar = { [weak self] in
|
self.longTapWithTabBar = { [weak self] in
|
||||||
@ -467,7 +479,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
strongSelf.containerLayoutUpdated(layout, transition: .immediate)
|
strongSelf.containerLayoutUpdated(layout, transition: .immediate)
|
||||||
(strongSelf.parent as? TabBarController)?.updateLayout()
|
(strongSelf.parent as? TabBarController)?.updateLayout()
|
||||||
} else {
|
} else {
|
||||||
strongSelf.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: resolvedItems, selectedFilter: selectedEntryId, presentationData: strongSelf.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
strongSelf.tabContainerNode.update(size: CGSize(width: layout.size.width, height: NavigationBar.defaultSecondaryContentHeight), sideInset: layout.safeInsets.left, filters: resolvedItems, selectedFilter: selectedEntryId, presentationData: strongSelf.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -565,6 +577,36 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})))
|
})))
|
||||||
|
if let chatListFilter = strongSelf.chatListDisplayNode.chatListNode.chatListFilter, chatListFilter.includePeers.count < 100 {
|
||||||
|
//TODO:localization
|
||||||
|
items.append(.action(ContextMenuActionItem(text: "Add Chats", icon: { _ in
|
||||||
|
return nil
|
||||||
|
}, action: { c, f in
|
||||||
|
c.dismiss(completion: {
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [ChatListFilter] in
|
||||||
|
let settings = transaction.getPreferencesEntry(key: PreferencesKeys.chatListFilters) as? ChatListFiltersState ?? ChatListFiltersState.default
|
||||||
|
return settings.filters
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).start(next: { presetList in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var found = false
|
||||||
|
for filter in presetList {
|
||||||
|
if filter.id == id {
|
||||||
|
strongSelf.push(chatListFilterAddChatsController(context: strongSelf.context, filter: filter))
|
||||||
|
f(.dismissWithoutContent)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode)), items: .single(items), reactionItems: [], recognizer: nil, gesture: gesture)
|
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode)), items: .single(items), reactionItems: [], recognizer: nil, gesture: gesture)
|
||||||
strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
|
strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
|
||||||
@ -946,7 +988,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toolbar = Toolbar(leftAction: leftAction, rightAction: ToolbarAction(title: presentationData.strings.Common_Delete, isEnabled: options.delete), middleAction: ToolbarAction(title: presentationData.strings.ChatList_ArchiveAction, isEnabled: archiveEnabled))
|
toolbar = Toolbar(leftAction: leftAction, rightAction: ToolbarAction(title: presentationData.strings.Common_Delete, isEnabled: options.delete), middleAction: strongSelf.chatListDisplayNode.chatListNode.chatListFilter != nil ? nil : ToolbarAction(title: presentationData.strings.ChatList_ArchiveAction, isEnabled: archiveEnabled))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let (options, peerIds) = peerIdsAndOptions {
|
if let (options, peerIds) = peerIdsAndOptions {
|
||||||
@ -1119,8 +1161,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
tabContainerOffset += 44.0 + 44.0 + 44.0
|
tabContainerOffset += 44.0 + 44.0 + 44.0
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: self.tabContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: self.visualNavigationInsetHeight - 46.0 + tabContainerOffset), size: CGSize(width: layout.size.width, height: 46.0)))
|
transition.updateFrame(node: self.tabContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: self.visualNavigationInsetHeight - self.additionalHeight - NavigationBar.defaultSecondaryContentHeight + tabContainerOffset), size: CGSize(width: layout.size.width, height: NavigationBar.defaultSecondaryContentHeight)))
|
||||||
self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.tabContainerData?.1, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: NavigationBar.defaultSecondaryContentHeight), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.tabContainerData?.1, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
|
||||||
if let searchContentNode = self.searchContentNode, layout.inVoiceOver != wasInVoiceOver {
|
if let searchContentNode = self.searchContentNode, layout.inVoiceOver != wasInVoiceOver {
|
||||||
searchContentNode.updateListVisibleContentOffset(.known(0.0))
|
searchContentNode.updateListVisibleContentOffset(.known(0.0))
|
||||||
@ -2026,39 +2068,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.push(chatListFilterPresetListController(context: strongSelf.context, updated: { presets in
|
strongSelf.push(chatListFilterPresetListController(context: strongSelf.context, updated: { _ in
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
/*if let currentPreset = strongSelf.chatListDisplayNode.chatListNode.chatListFilter {
|
|
||||||
var found = false
|
|
||||||
if let index = presets.index(where: { $0.id == currentPreset.id }) {
|
|
||||||
found = true
|
|
||||||
if currentPreset != presets[index] {
|
|
||||||
strongSelf.chatListDisplayNode.chatListNode.chatListFilter = presets[index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
strongSelf.chatListDisplayNode.chatListNode.chatListFilter = nil
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}))
|
}))
|
||||||
}, updatePreset: { value in
|
}, updatePreset: { value in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.push(ChatListControllerImpl(context: strongSelf.context, groupId: .root, filter: value, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: false, enableDebugActions: false))
|
if let value = value {
|
||||||
//strongSelf.chatListDisplayNode.chatListNode.chatListFilter = value
|
strongSelf.tabContainerNode.tabSelected?(.filter(value.id))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
strongSelf.context.sharedContext.mainWindow?.present(controller, on: .root)
|
strongSelf.context.sharedContext.mainWindow?.present(controller, on: .root)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateTabBarPreviewingControllerPresentation(_ update: TabBarContainedControllerPresentationUpdate) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
|
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
|
||||||
let _ = (combineLatest(queue: .mainQueue(),
|
let _ = (combineLatest(queue: .mainQueue(),
|
||||||
self.context.account.postbox.transaction { transaction -> [ChatListFilter] in
|
self.context.account.postbox.transaction { transaction -> [ChatListFilter] in
|
||||||
@ -2076,14 +2100,23 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
let (_, filterItems) = filterItemsAndTotalCount
|
let (_, filterItems) = filterItemsAndTotalCount
|
||||||
|
|
||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
items.append(.action(ContextMenuActionItem(text: "Setup", icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: presetList.isEmpty ? "Add Filter" : "Edit Filters", icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { c, f in
|
}, action: { c, f in
|
||||||
c.dismiss(completion: {
|
c.dismiss(completion: {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.push(chatListFilterPresetListController(context: strongSelf.context, updated: { _ in }))
|
if presetList.isEmpty {
|
||||||
|
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||||
|
var viewControllers = navigationController.viewControllers
|
||||||
|
//viewControllers.append(chatListFilterPresetListController(context: strongSelf.context, updated: { _ in }))
|
||||||
|
viewControllers.append(chatListFilterPresetController(context: strongSelf.context, currentPreset: nil, updated: { _ in }))
|
||||||
|
navigationController.setViewControllers(viewControllers, animated: true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strongSelf.push(chatListFilterPresetListController(context: strongSelf.context, updated: { _ in }))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})))
|
})))
|
||||||
|
|
||||||
@ -2156,13 +2189,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
imageName = "Chat/Context Menu/User"
|
imageName = "Chat/Context Menu/User"
|
||||||
}
|
}
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { c, f in
|
}, action: { _, f in
|
||||||
c.dismiss(completion: {
|
f(.dismissWithoutContent)
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.push(ChatListControllerImpl(context: strongSelf.context, groupId: .root, filter: preset, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: false, enableDebugActions: false))
|
strongSelf.tabContainerNode.tabSelected?(.filter(preset.id))
|
||||||
})
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import TelegramPresentationData
|
|||||||
import AnimatedStickerNode
|
import AnimatedStickerNode
|
||||||
import AppBundle
|
import AppBundle
|
||||||
import SolidRoundedButtonNode
|
import SolidRoundedButtonNode
|
||||||
|
import ActivityIndicator
|
||||||
|
|
||||||
final class ChatListEmptyNodeContainer: ASDisplayNode {
|
final class ChatListEmptyNodeContainer: ASDisplayNode {
|
||||||
private var currentNode: ChatListEmptyNode?
|
private var currentNode: ChatListEmptyNode?
|
||||||
@ -42,10 +43,10 @@ final class ChatListEmptyNodeContainer: ASDisplayNode {
|
|||||||
|
|
||||||
func update(state: ChatListNodeEmptyState, isFilter: Bool, direction: ChatListNodePaneSwitchAnimationDirection?, transition: ContainedViewLayoutTransition) {
|
func update(state: ChatListNodeEmptyState, isFilter: Bool, direction: ChatListNodePaneSwitchAnimationDirection?, transition: ContainedViewLayoutTransition) {
|
||||||
switch state {
|
switch state {
|
||||||
case .empty:
|
case let .empty(isLoading):
|
||||||
if let direction = direction {
|
if let direction = direction {
|
||||||
let previousNode = self.currentNode
|
let previousNode = self.currentNode
|
||||||
let currentNode = ChatListEmptyNode(isFilter: isFilter, theme: self.theme, strings: self.strings, action: { [weak self] in
|
let currentNode = ChatListEmptyNode(isFilter: isFilter, isLoading: isLoading, theme: self.theme, strings: self.strings, action: { [weak self] in
|
||||||
self?.action?()
|
self?.action?()
|
||||||
})
|
})
|
||||||
self.currentNode = currentNode
|
self.currentNode = currentNode
|
||||||
@ -73,7 +74,7 @@ final class ChatListEmptyNodeContainer: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let previousNode = self.currentNode, previousNode.isFilter != isFilter {
|
if let previousNode = self.currentNode, previousNode.isFilter != isFilter {
|
||||||
let currentNode = ChatListEmptyNode(isFilter: isFilter, theme: self.theme, strings: self.strings, action: { [weak self] in
|
let currentNode = ChatListEmptyNode(isFilter: isFilter, isLoading: isLoading, theme: self.theme, strings: self.strings, action: { [weak self] in
|
||||||
self?.action?()
|
self?.action?()
|
||||||
})
|
})
|
||||||
self.currentNode = currentNode
|
self.currentNode = currentNode
|
||||||
@ -82,9 +83,15 @@ final class ChatListEmptyNodeContainer: ASDisplayNode {
|
|||||||
currentNode.updateLayout(size: size, transition: .immediate)
|
currentNode.updateLayout(size: size, transition: .immediate)
|
||||||
}
|
}
|
||||||
self.addSubnode(currentNode)
|
self.addSubnode(currentNode)
|
||||||
previousNode.removeFromSupernode()
|
currentNode.alpha = 0.0
|
||||||
} else if self.currentNode == nil {
|
transition.updateAlpha(node: currentNode, alpha: 1.0)
|
||||||
let currentNode = ChatListEmptyNode(isFilter: isFilter, theme: self.theme, strings: self.strings, action: { [weak self] in
|
transition.updateAlpha(node: previousNode, alpha: 0.0, completion: { [weak previousNode] _ in
|
||||||
|
previousNode?.removeFromSupernode()
|
||||||
|
})
|
||||||
|
} else if let currentNode = self.currentNode {
|
||||||
|
currentNode.updateIsLoading(isLoading)
|
||||||
|
} else {
|
||||||
|
let currentNode = ChatListEmptyNode(isFilter: isFilter, isLoading: isLoading, theme: self.theme, strings: self.strings, action: { [weak self] in
|
||||||
self?.action?()
|
self?.action?()
|
||||||
})
|
})
|
||||||
self.currentNode = currentNode
|
self.currentNode = currentNode
|
||||||
@ -93,6 +100,8 @@ final class ChatListEmptyNodeContainer: ASDisplayNode {
|
|||||||
currentNode.updateLayout(size: size, transition: .immediate)
|
currentNode.updateLayout(size: size, transition: .immediate)
|
||||||
}
|
}
|
||||||
self.addSubnode(currentNode)
|
self.addSubnode(currentNode)
|
||||||
|
currentNode.alpha = 0.0
|
||||||
|
transition.updateAlpha(node: currentNode, alpha: 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .notEmpty:
|
case .notEmpty:
|
||||||
@ -115,7 +124,9 @@ final class ChatListEmptyNodeContainer: ASDisplayNode {
|
|||||||
previousNode.removeFromSupernode()
|
previousNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
previousNode.removeFromSupernode()
|
transition.updateAlpha(node: previousNode, alpha: 0.0, completion: { [weak previousNode] _ in
|
||||||
|
previousNode?.removeFromSupernode()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,16 +142,19 @@ final class ChatListEmptyNodeContainer: ASDisplayNode {
|
|||||||
|
|
||||||
final class ChatListEmptyNode: ASDisplayNode {
|
final class ChatListEmptyNode: ASDisplayNode {
|
||||||
let isFilter: Bool
|
let isFilter: Bool
|
||||||
|
private(set) var isLoading: Bool
|
||||||
private let textNode: ImmediateTextNode
|
private let textNode: ImmediateTextNode
|
||||||
private let animationNode: AnimatedStickerNode
|
private let animationNode: AnimatedStickerNode
|
||||||
private let buttonNode: SolidRoundedButtonNode
|
private let buttonNode: SolidRoundedButtonNode
|
||||||
|
private let activityIndicator: ActivityIndicator
|
||||||
|
|
||||||
private var animationSize: CGSize = CGSize()
|
private var animationSize: CGSize = CGSize()
|
||||||
|
|
||||||
private var validLayout: CGSize?
|
private var validLayout: CGSize?
|
||||||
|
|
||||||
init(isFilter: Bool, theme: PresentationTheme, strings: PresentationStrings, action: @escaping () -> Void) {
|
init(isFilter: Bool, isLoading: Bool, theme: PresentationTheme, strings: PresentationStrings, action: @escaping () -> Void) {
|
||||||
self.isFilter = isFilter
|
self.isFilter = isFilter
|
||||||
|
self.isLoading = isLoading
|
||||||
|
|
||||||
self.animationNode = AnimatedStickerNode()
|
self.animationNode = AnimatedStickerNode()
|
||||||
|
|
||||||
@ -153,6 +167,8 @@ final class ChatListEmptyNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.buttonNode = SolidRoundedButtonNode(title: isFilter ? strings.ChatList_EmptyChatListEditFilter : strings.ChatList_EmptyChatListNewMessage, theme: SolidRoundedButtonTheme(backgroundColor: theme.list.itemCheckColors.fillColor, foregroundColor: theme.list.itemCheckColors.foregroundColor), height: 50.0, cornerRadius: 10.0, gloss: false)
|
self.buttonNode = SolidRoundedButtonNode(title: isFilter ? strings.ChatList_EmptyChatListEditFilter : strings.ChatList_EmptyChatListNewMessage, theme: SolidRoundedButtonTheme(backgroundColor: theme.list.itemCheckColors.fillColor, foregroundColor: theme.list.itemCheckColors.foregroundColor), height: 50.0, cornerRadius: 10.0, gloss: false)
|
||||||
|
|
||||||
|
self.activityIndicator = ActivityIndicator(type: .custom(theme.list.itemAccentColor, 22.0, 1.0, false))
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.animationNode)
|
self.addSubnode(self.animationNode)
|
||||||
@ -175,6 +191,11 @@ final class ChatListEmptyNode: ASDisplayNode {
|
|||||||
action()
|
action()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.animationNode.isHidden = self.isLoading
|
||||||
|
self.textNode.isHidden = self.isLoading
|
||||||
|
self.buttonNode.isHidden = self.isLoading
|
||||||
|
self.activityIndicator.isHidden = !self.isLoading
|
||||||
|
|
||||||
self.updateThemeAndStrings(theme: theme, strings: strings)
|
self.updateThemeAndStrings(theme: theme, strings: strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,14 +205,30 @@ final class ChatListEmptyNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.buttonNode.updateTheme(SolidRoundedButtonTheme(backgroundColor: theme.list.itemCheckColors.fillColor, foregroundColor: theme.list.itemCheckColors.foregroundColor))
|
self.buttonNode.updateTheme(SolidRoundedButtonTheme(backgroundColor: theme.list.itemCheckColors.fillColor, foregroundColor: theme.list.itemCheckColors.foregroundColor))
|
||||||
|
|
||||||
|
self.activityIndicator.type = .custom(theme.list.itemAccentColor, 22.0, 1.0, false)
|
||||||
|
|
||||||
if let size = self.validLayout {
|
if let size = self.validLayout {
|
||||||
self.updateLayout(size: size, transition: .immediate)
|
self.updateLayout(size: size, transition: .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateIsLoading(_ isLoading: Bool) {
|
||||||
|
if self.isLoading == isLoading {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.isLoading = isLoading
|
||||||
|
self.animationNode.isHidden = self.isLoading
|
||||||
|
self.textNode.isHidden = self.isLoading
|
||||||
|
self.buttonNode.isHidden = self.isLoading
|
||||||
|
self.activityIndicator.isHidden = !self.isLoading
|
||||||
|
}
|
||||||
|
|
||||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = size
|
self.validLayout = size
|
||||||
|
|
||||||
|
let indicatorSize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0))
|
||||||
|
transition.updateFrame(node: self.activityIndicator, frame: CGRect(origin: CGPoint(x: floor((size.width - indicatorSize.width) / 2.0), y: floor((size.height - indicatorSize.height - 50.0) / 2.0)), size: indicatorSize))
|
||||||
|
|
||||||
let animationSpacing: CGFloat = 10.0
|
let animationSpacing: CGFloat = 10.0
|
||||||
let buttonSpacing: CGFloat = 24.0
|
let buttonSpacing: CGFloat = 24.0
|
||||||
let buttonSideInset: CGFloat = 16.0
|
let buttonSideInset: CGFloat = 16.0
|
||||||
|
@ -245,6 +245,7 @@ private struct ChatListFilterPresetControllerState: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO:localization
|
||||||
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetControllerState, peers: [RenderedPeer]) -> [ChatListFilterPresetEntry] {
|
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetControllerState, peers: [RenderedPeer]) -> [ChatListFilterPresetEntry] {
|
||||||
var entries: [ChatListFilterPresetEntry] = []
|
var entries: [ChatListFilterPresetEntry] = []
|
||||||
|
|
||||||
@ -274,6 +275,41 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func chatListFilterAddChatsController(context: AccountContext, filter: ChatListFilter) -> ViewController {
|
||||||
|
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true, searchChannels: true), options: []))
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
|
let _ = (controller.result
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak controller] peerIds in
|
||||||
|
let _ = (updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { settings in
|
||||||
|
var settings = settings
|
||||||
|
for i in 0 ..< settings.filters.count {
|
||||||
|
if settings.filters[i].id == filter.id {
|
||||||
|
let previousIncludePeers = settings.filters[i].includePeers
|
||||||
|
|
||||||
|
var chatPeerIds: [PeerId] = []
|
||||||
|
for peerId in peerIds {
|
||||||
|
switch peerId {
|
||||||
|
case let .peer(id):
|
||||||
|
chatPeerIds.append(id)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings.filters[i].includePeers = chatPeerIds + previousIncludePeers.filter { peerId in
|
||||||
|
return !chatPeerIds.contains(peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return settings
|
||||||
|
})
|
||||||
|
|> deliverOnMainQueue).start(next: { settings in
|
||||||
|
controller?.dismiss()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
||||||
func chatListFilterPresetController(context: AccountContext, currentPreset: ChatListFilter?, updated: @escaping ([ChatListFilter]) -> Void) -> ViewController {
|
func chatListFilterPresetController(context: AccountContext, currentPreset: ChatListFilter?, updated: @escaping ([ChatListFilter]) -> Void) -> ViewController {
|
||||||
let initialName: String
|
let initialName: String
|
||||||
if let currentPreset = currentPreset {
|
if let currentPreset = currentPreset {
|
||||||
@ -302,7 +338,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
updateState(f)
|
updateState(f)
|
||||||
},
|
},
|
||||||
openAddPeer: {
|
openAddPeer: {
|
||||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true), options: []))
|
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true, searchChannels: true), options: []))
|
||||||
addPeerDisposable.set((controller.result
|
addPeerDisposable.set((controller.result
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { [weak controller] peerIds in
|
|> deliverOnMainQueue).start(next: { [weak controller] peerIds in
|
||||||
@ -313,7 +349,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
switch peerId {
|
switch peerId {
|
||||||
case let .peer(id):
|
case let .peer(id):
|
||||||
if !state.additionallyIncludePeers.contains(id) {
|
if !state.additionallyIncludePeers.contains(id) {
|
||||||
state.additionallyIncludePeers.append(id)
|
state.additionallyIncludePeers.insert(id, at: 0)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -14,15 +14,13 @@ import ItemListPeerActionItem
|
|||||||
private final class ChatListFilterPresetListControllerArguments {
|
private final class ChatListFilterPresetListControllerArguments {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
|
|
||||||
let toggleEnableTabs: (Bool) -> Void
|
|
||||||
let openPreset: (ChatListFilter) -> Void
|
let openPreset: (ChatListFilter) -> Void
|
||||||
let addNew: () -> Void
|
let addNew: () -> Void
|
||||||
let setItemWithRevealedOptions: (Int32?, Int32?) -> Void
|
let setItemWithRevealedOptions: (Int32?, Int32?) -> Void
|
||||||
let removePreset: (Int32) -> Void
|
let removePreset: (Int32) -> Void
|
||||||
|
|
||||||
init(context: AccountContext, toggleEnableTabs: @escaping (Bool) -> Void, openPreset: @escaping (ChatListFilter) -> Void, addNew: @escaping () -> Void, setItemWithRevealedOptions: @escaping (Int32?, Int32?) -> Void, removePreset: @escaping (Int32) -> Void) {
|
init(context: AccountContext, openPreset: @escaping (ChatListFilter) -> Void, addNew: @escaping () -> Void, setItemWithRevealedOptions: @escaping (Int32?, Int32?) -> Void, removePreset: @escaping (Int32) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.toggleEnableTabs = toggleEnableTabs
|
|
||||||
self.openPreset = openPreset
|
self.openPreset = openPreset
|
||||||
self.addNew = addNew
|
self.addNew = addNew
|
||||||
self.setItemWithRevealedOptions = setItemWithRevealedOptions
|
self.setItemWithRevealedOptions = setItemWithRevealedOptions
|
||||||
@ -31,7 +29,6 @@ private final class ChatListFilterPresetListControllerArguments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private enum ChatListFilterPresetListSection: Int32 {
|
private enum ChatListFilterPresetListSection: Int32 {
|
||||||
case tabs
|
|
||||||
case list
|
case list
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,8 +45,6 @@ private func stringForUserCount(_ peers: [PeerId: SelectivePrivacyPeer], strings
|
|||||||
}
|
}
|
||||||
|
|
||||||
private enum ChatListFilterPresetListEntryStableId: Hashable {
|
private enum ChatListFilterPresetListEntryStableId: Hashable {
|
||||||
case displayTabs
|
|
||||||
case displayTabsFooter
|
|
||||||
case listHeader
|
case listHeader
|
||||||
case preset(Int32)
|
case preset(Int32)
|
||||||
case addItem
|
case addItem
|
||||||
@ -57,8 +52,6 @@ private enum ChatListFilterPresetListEntryStableId: Hashable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
||||||
case displayTabs(String, Bool)
|
|
||||||
case displayTabsFooter(String)
|
|
||||||
case listHeader(String)
|
case listHeader(String)
|
||||||
case preset(index: Int, title: String?, preset: ChatListFilter, canBeReordered: Bool, canBeDeleted: Bool, isEditing: Bool)
|
case preset(index: Int, title: String?, preset: ChatListFilter, canBeReordered: Bool, canBeDeleted: Bool, isEditing: Bool)
|
||||||
case addItem(text: String, isEditing: Bool)
|
case addItem(text: String, isEditing: Bool)
|
||||||
@ -66,8 +59,6 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
|
|
||||||
var section: ItemListSectionId {
|
var section: ItemListSectionId {
|
||||||
switch self {
|
switch self {
|
||||||
case .displayTabs, .displayTabsFooter:
|
|
||||||
return ChatListFilterPresetListSection.tabs.rawValue
|
|
||||||
case .listHeader, .preset, .addItem, .listFooter:
|
case .listHeader, .preset, .addItem, .listFooter:
|
||||||
return ChatListFilterPresetListSection.list.rawValue
|
return ChatListFilterPresetListSection.list.rawValue
|
||||||
}
|
}
|
||||||
@ -75,10 +66,6 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
|
|
||||||
var sortId: Int {
|
var sortId: Int {
|
||||||
switch self {
|
switch self {
|
||||||
case .displayTabs:
|
|
||||||
return 0
|
|
||||||
case .displayTabsFooter:
|
|
||||||
return 1
|
|
||||||
case .listHeader:
|
case .listHeader:
|
||||||
return 2
|
return 2
|
||||||
case let .preset(preset):
|
case let .preset(preset):
|
||||||
@ -92,10 +79,6 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
|
|
||||||
var stableId: ChatListFilterPresetListEntryStableId {
|
var stableId: ChatListFilterPresetListEntryStableId {
|
||||||
switch self {
|
switch self {
|
||||||
case .displayTabs:
|
|
||||||
return .displayTabs
|
|
||||||
case .displayTabsFooter:
|
|
||||||
return .displayTabsFooter
|
|
||||||
case .listHeader:
|
case .listHeader:
|
||||||
return .listHeader
|
return .listHeader
|
||||||
case let .preset(preset):
|
case let .preset(preset):
|
||||||
@ -114,12 +97,6 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||||
let arguments = arguments as! ChatListFilterPresetListControllerArguments
|
let arguments = arguments as! ChatListFilterPresetListControllerArguments
|
||||||
switch self {
|
switch self {
|
||||||
case let .displayTabs(title, value):
|
|
||||||
return ItemListSwitchItem(presentationData: presentationData, title: title, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
|
||||||
arguments.toggleEnableTabs(value)
|
|
||||||
})
|
|
||||||
case let .displayTabsFooter(text):
|
|
||||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
|
||||||
case let .listHeader(text):
|
case let .listHeader(text):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
|
||||||
case let .preset(index, title, preset, canBeReordered, canBeDeleted, isEditing):
|
case let .preset(index, title, preset, canBeReordered, canBeDeleted, isEditing):
|
||||||
@ -147,15 +124,14 @@ private struct ChatListFilterPresetListControllerState: Equatable {
|
|||||||
|
|
||||||
private func chatListFilterPresetListControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetListControllerState, filtersState: ChatListFiltersState, settings: ChatListFilterSettings) -> [ChatListFilterPresetListEntry] {
|
private func chatListFilterPresetListControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetListControllerState, filtersState: ChatListFiltersState, settings: ChatListFilterSettings) -> [ChatListFilterPresetListEntry] {
|
||||||
var entries: [ChatListFilterPresetListEntry] = []
|
var entries: [ChatListFilterPresetListEntry] = []
|
||||||
|
|
||||||
entries.append(.displayTabs("Show Tabs", settings.displayTabs))
|
|
||||||
entries.append(.displayTabsFooter("Display filter tabs on the main screen for quick switching."))
|
|
||||||
|
|
||||||
entries.append(.listHeader("FILTERS"))
|
entries.append(.listHeader("FILTERS"))
|
||||||
for preset in filtersState.filters {
|
for preset in filtersState.filters {
|
||||||
entries.append(.preset(index: entries.count, title: preset.title, preset: preset, canBeReordered: filtersState.filters.count > 1, canBeDeleted: true, isEditing: state.isEditing))
|
entries.append(.preset(index: entries.count, title: preset.title, preset: preset, canBeReordered: filtersState.filters.count > 1, canBeDeleted: true, isEditing: state.isEditing))
|
||||||
}
|
}
|
||||||
entries.append(.addItem(text: "Create New Filter", isEditing: state.isEditing))
|
if filtersState.filters.count < 10 {
|
||||||
|
entries.append(.addItem(text: "Create New Filter", isEditing: state.isEditing))
|
||||||
|
}
|
||||||
entries.append(.listFooter("Tap \"Edit\" to change the order or delete filters."))
|
entries.append(.listFooter("Tap \"Edit\" to change the order or delete filters."))
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
@ -173,15 +149,7 @@ func chatListFilterPresetListController(context: AccountContext, updated: @escap
|
|||||||
var pushControllerImpl: ((ViewController) -> Void)?
|
var pushControllerImpl: ((ViewController) -> Void)?
|
||||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||||
|
|
||||||
let arguments = ChatListFilterPresetListControllerArguments(context: context, toggleEnableTabs: { value in
|
let arguments = ChatListFilterPresetListControllerArguments(context: context, openPreset: { preset in
|
||||||
let _ = context.account.postbox.transaction({ transaction -> Void in
|
|
||||||
let _ = updateChatListFilterSettings(transaction: transaction, { settings in
|
|
||||||
var settings = settings
|
|
||||||
settings.displayTabs = value
|
|
||||||
return settings
|
|
||||||
})
|
|
||||||
}).start()
|
|
||||||
}, openPreset: { preset in
|
|
||||||
pushControllerImpl?(chatListFilterPresetController(context: context, currentPreset: preset, updated: updated))
|
pushControllerImpl?(chatListFilterPresetController(context: context, currentPreset: preset, updated: updated))
|
||||||
}, addNew: {
|
}, addNew: {
|
||||||
pushControllerImpl?(chatListFilterPresetController(context: context, currentPreset: nil, updated: updated))
|
pushControllerImpl?(chatListFilterPresetController(context: context, currentPreset: nil, updated: updated))
|
||||||
|
@ -132,6 +132,11 @@ private final class ItemNode: ASDisplayNode {
|
|||||||
self.extractedContainerNode.contentNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.extractedContainerNode.contentNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
self.extractedContainerNode.contentRect = CGRect(origin: CGPoint(), size: size)
|
self.extractedContainerNode.contentRect = CGRect(origin: CGPoint(), size: size)
|
||||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
|
|
||||||
|
self.hitTestSlop = UIEdgeInsets(top: 0.0, left: -sideInset, bottom: 0.0, right: -sideInset)
|
||||||
|
self.extractedContainerNode.hitTestSlop = self.hitTestSlop
|
||||||
|
self.extractedContainerNode.contentNode.hitTestSlop = self.hitTestSlop
|
||||||
|
self.containerNode.hitTestSlop = self.hitTestSlop
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateBadgeIn() {
|
func animateBadgeIn() {
|
||||||
@ -254,6 +259,11 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
|
|||||||
|
|
||||||
func update(size: CGSize, sideInset: CGFloat, filters: [ChatListFilterTabEntry], selectedFilter: ChatListFilterTabEntryId?, presentationData: PresentationData, transition: ContainedViewLayoutTransition) {
|
func update(size: CGSize, sideInset: CGFloat, filters: [ChatListFilterTabEntry], selectedFilter: ChatListFilterTabEntryId?, presentationData: PresentationData, transition: ContainedViewLayoutTransition) {
|
||||||
let focusOnSelectedFilter = self.currentParams?.selectedFilter != selectedFilter
|
let focusOnSelectedFilter = self.currentParams?.selectedFilter != selectedFilter
|
||||||
|
var previousSelectedAbsFrame: CGRect?
|
||||||
|
let previousScrollBounds = self.scrollNode.bounds
|
||||||
|
if let currentSelectedFilter = self.currentParams?.selectedFilter, let itemNode = self.itemNodes[currentSelectedFilter] {
|
||||||
|
previousSelectedAbsFrame = itemNode.frame.offsetBy(dx: -self.scrollNode.bounds.minX, dy: 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
if self.currentParams?.presentationData.theme !== presentationData.theme {
|
if self.currentParams?.presentationData.theme !== presentationData.theme {
|
||||||
self.selectedLineNode.image = generateImage(CGSize(width: 7.0, height: 4.0), rotatedContext: { size, context in
|
self.selectedLineNode.image = generateImage(CGSize(width: 7.0, height: 4.0), rotatedContext: { size, context in
|
||||||
@ -421,6 +431,16 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
|
|||||||
let contentOffsetX = max(0.0, min(self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, floor(selectedFrame.midX - self.scrollNode.bounds.width / 2.0)))
|
let contentOffsetX = max(0.0, min(self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, floor(selectedFrame.midX - self.scrollNode.bounds.width / 2.0)))
|
||||||
transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: contentOffsetX, y: 0.0), size: self.scrollNode.bounds.size))
|
transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: contentOffsetX, y: 0.0), size: self.scrollNode.bounds.size))
|
||||||
}
|
}
|
||||||
|
} else if !wasAdded, let previousSelectedAbsFrame = previousSelectedAbsFrame {
|
||||||
|
let contentOffsetX: CGFloat
|
||||||
|
if previousScrollBounds.minX.isZero {
|
||||||
|
contentOffsetX = 0.0
|
||||||
|
} else if previousScrollBounds.maxX == previousScrollBounds.width {
|
||||||
|
contentOffsetX = self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width
|
||||||
|
} else {
|
||||||
|
contentOffsetX = selectedFrame.midX - previousSelectedAbsFrame.midX
|
||||||
|
}
|
||||||
|
transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: contentOffsetX, y: 0.0), size: self.scrollNode.bounds.size))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.selectedLineNode.isHidden = true
|
self.selectedLineNode.isHidden = true
|
||||||
|
@ -484,7 +484,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
case let .message(message, peer, readState, presentationData):
|
case let .message(message, peer, readState, presentationData):
|
||||||
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: enableHeaders ? ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: enableHeaders ? ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
case let .addContact(phoneNumber, theme, strings):
|
case let .addContact(phoneNumber, theme, strings):
|
||||||
return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
|
return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
|
||||||
interaction.addContact(phoneNumber)
|
interaction.addContact(phoneNumber)
|
||||||
@ -1409,6 +1409,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
actionSheet?.dismissAnimated()
|
actionSheet?.dismissAnimated()
|
||||||
})
|
})
|
||||||
])])
|
])])
|
||||||
|
self.view.window?.endEditing(true)
|
||||||
self.interaction?.present(actionSheet)
|
self.interaction?.present(actionSheet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||||||
let presentationData: ChatListPresentationData
|
let presentationData: ChatListPresentationData
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let peerGroupId: PeerGroupId
|
let peerGroupId: PeerGroupId
|
||||||
|
let isInFilter: Bool
|
||||||
let index: ChatListIndex
|
let index: ChatListIndex
|
||||||
public let content: ChatListItemContent
|
public let content: ChatListItemContent
|
||||||
let editing: Bool
|
let editing: Bool
|
||||||
@ -58,9 +59,10 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||||||
return self.index.pinningIndex != nil
|
return self.index.pinningIndex != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(presentationData: ChatListPresentationData, context: AccountContext, peerGroupId: PeerGroupId, index: ChatListIndex, content: ChatListItemContent, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, header: ListViewItemHeader?, enableContextActions: Bool, hiddenOffset: Bool, interaction: ChatListNodeInteraction) {
|
public init(presentationData: ChatListPresentationData, context: AccountContext, peerGroupId: PeerGroupId, isInFilter: Bool, index: ChatListIndex, content: ChatListItemContent, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, header: ListViewItemHeader?, enableContextActions: Bool, hiddenOffset: Bool, interaction: ChatListNodeInteraction) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.peerGroupId = peerGroupId
|
self.peerGroupId = peerGroupId
|
||||||
|
self.isInFilter = isInFilter
|
||||||
self.context = context
|
self.context = context
|
||||||
self.index = index
|
self.index = index
|
||||||
self.content = content
|
self.content = content
|
||||||
@ -202,7 +204,7 @@ private func canArchivePeer(id: PeerId, accountPeerId: PeerId) -> Bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool, isMuted: Bool?, groupId: PeerGroupId, peerId: PeerId, accountPeerId: PeerId, canDelete: Bool, isEditing: Bool) -> [ItemListRevealOption] {
|
private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool, isMuted: Bool?, groupId: PeerGroupId, peerId: PeerId, accountPeerId: PeerId, canDelete: Bool, isEditing: Bool, isInFilter: Bool) -> [ItemListRevealOption] {
|
||||||
var options: [ItemListRevealOption] = []
|
var options: [ItemListRevealOption] = []
|
||||||
if !isEditing {
|
if !isEditing {
|
||||||
if case .group = groupId {
|
if case .group = groupId {
|
||||||
@ -224,7 +226,7 @@ private func revealOptions(strings: PresentationStrings, theme: PresentationThem
|
|||||||
if canDelete {
|
if canDelete {
|
||||||
options.append(ItemListRevealOption(key: RevealOptionKey.delete.rawValue, title: strings.Common_Delete, icon: deleteIcon, color: theme.list.itemDisclosureActions.destructive.fillColor, textColor: theme.list.itemDisclosureActions.destructive.foregroundColor))
|
options.append(ItemListRevealOption(key: RevealOptionKey.delete.rawValue, title: strings.Common_Delete, icon: deleteIcon, color: theme.list.itemDisclosureActions.destructive.fillColor, textColor: theme.list.itemDisclosureActions.destructive.foregroundColor))
|
||||||
}
|
}
|
||||||
if !isEditing {
|
if !isEditing && !isInFilter {
|
||||||
if case .root = groupId {
|
if case .root = groupId {
|
||||||
if canArchivePeer(id: peerId, accountPeerId: accountPeerId) {
|
if canArchivePeer(id: peerId, accountPeerId: accountPeerId) {
|
||||||
options.append(ItemListRevealOption(key: RevealOptionKey.archive.rawValue, title: strings.ChatList_ArchiveAction, icon: archiveIcon, color: theme.list.itemDisclosureActions.inactive.fillColor, textColor: theme.list.itemDisclosureActions.inactive.foregroundColor))
|
options.append(ItemListRevealOption(key: RevealOptionKey.archive.rawValue, title: strings.ChatList_ArchiveAction, icon: archiveIcon, color: theme.list.itemDisclosureActions.inactive.fillColor, textColor: theme.list.itemDisclosureActions.inactive.foregroundColor))
|
||||||
@ -248,7 +250,7 @@ private func groupReferenceRevealOptions(strings: PresentationStrings, theme: Pr
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
private func leftRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isUnread: Bool, isEditing: Bool, isPinned: Bool, isSavedMessages: Bool, groupId: PeerGroupId) -> [ItemListRevealOption] {
|
private func leftRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isUnread: Bool, isEditing: Bool, isPinned: Bool, isSavedMessages: Bool, groupId: PeerGroupId, isInFilter: Bool) -> [ItemListRevealOption] {
|
||||||
if case .group = groupId {
|
if case .group = groupId {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@ -258,7 +260,7 @@ private func leftRevealOptions(strings: PresentationStrings, theme: Presentation
|
|||||||
} else {
|
} else {
|
||||||
options.append(ItemListRevealOption(key: RevealOptionKey.toggleMarkedUnread.rawValue, title: strings.DialogList_Unread, icon: unreadIcon, color: theme.list.itemDisclosureActions.accent.fillColor, textColor: theme.list.itemDisclosureActions.accent.foregroundColor))
|
options.append(ItemListRevealOption(key: RevealOptionKey.toggleMarkedUnread.rawValue, title: strings.DialogList_Unread, icon: unreadIcon, color: theme.list.itemDisclosureActions.accent.fillColor, textColor: theme.list.itemDisclosureActions.accent.foregroundColor))
|
||||||
}
|
}
|
||||||
if !isEditing {
|
if !isEditing && !isInFilter {
|
||||||
if isPinned {
|
if isPinned {
|
||||||
options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor))
|
options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor))
|
||||||
} else {
|
} else {
|
||||||
@ -1170,9 +1172,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let isPinned = item.index.pinningIndex != nil
|
let isPinned = item.index.pinningIndex != nil
|
||||||
|
|
||||||
if item.enableContextActions && !isAd {
|
if item.enableContextActions && !isAd {
|
||||||
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: item.context.account.peerId != item.index.messageIndex.id.peerId ? (currentMutedIconImage != nil) : nil, groupId: item.peerGroupId, peerId: renderedPeer.peerId, accountPeerId: item.context.account.peerId, canDelete: true, isEditing: item.editing)
|
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: item.context.account.peerId != item.index.messageIndex.id.peerId ? (currentMutedIconImage != nil) : nil, groupId: item.peerGroupId, peerId: renderedPeer.peerId, accountPeerId: item.context.account.peerId, canDelete: true, isEditing: item.editing, isInFilter: item.isInFilter)
|
||||||
if case let .chat(itemPeer) = contentPeer {
|
if case let .chat(itemPeer) = contentPeer {
|
||||||
peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread, isEditing: item.editing, isPinned: isPinned, isSavedMessages: itemPeer.peerId == item.context.account.peerId, groupId: item.peerGroupId)
|
peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread, isEditing: item.editing, isPinned: isPinned, isSavedMessages: itemPeer.peerId == item.context.account.peerId, groupId: item.peerGroupId, isInFilter: item.isInFilter)
|
||||||
} else {
|
} else {
|
||||||
peerLeftRevealOptions = []
|
peerLeftRevealOptions = []
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ public struct ChatListNodeState: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, isInFilter: Bool, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
||||||
return entries.map { entry -> ListViewInsertItem in
|
return entries.map { entry -> ListViewInsertItem in
|
||||||
switch entry.entry {
|
switch entry.entry {
|
||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
@ -152,7 +152,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages):
|
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages):
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, notificationSettings: notificationSettings, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, isInFilter: isInFilter, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, notificationSettings: notificationSettings, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint)
|
||||||
case let .peers(filter):
|
case let .peers(filter):
|
||||||
let itemPeer = peer.chatMainPeer
|
let itemPeer = peer.chatMainPeer
|
||||||
var chatPeer: Peer?
|
var chatPeer: Peer?
|
||||||
@ -231,20 +231,20 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
case let .HoleEntry(_, theme):
|
case let .HoleEntry(_, theme):
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint)
|
||||||
case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault):
|
case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault):
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, isInFilter: isInFilter, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint)
|
||||||
case let .ArchiveIntro(presentationData):
|
case let .ArchiveIntro(presentationData):
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
|
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, isInFilter: Bool, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
|
||||||
return entries.map { entry -> ListViewUpdateItem in
|
return entries.map { entry -> ListViewUpdateItem in
|
||||||
switch entry.entry {
|
switch entry.entry {
|
||||||
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages):
|
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages):
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, notificationSettings: notificationSettings, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, isInFilter: isInFilter, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, notificationSettings: notificationSettings, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint)
|
||||||
case let .peers(filter):
|
case let .peers(filter):
|
||||||
let itemPeer = peer.chatMainPeer
|
let itemPeer = peer.chatMainPeer
|
||||||
var chatPeer: Peer?
|
var chatPeer: Peer?
|
||||||
@ -279,7 +279,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
case let .HoleEntry(_, theme):
|
case let .HoleEntry(_, theme):
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint)
|
||||||
case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault):
|
case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault):
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, isInFilter: isInFilter, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint)
|
||||||
case let .ArchiveIntro(presentationData):
|
case let .ArchiveIntro(presentationData):
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
@ -288,8 +288,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
|
private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, isInFilter: Bool, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
|
||||||
return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem)
|
return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, isInFilter: isInFilter, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, isInFilter: isInFilter, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ChatListOpaqueTransactionState {
|
private final class ChatListOpaqueTransactionState {
|
||||||
@ -804,8 +804,10 @@ public final class ChatListNode: ListView {
|
|||||||
updatedScrollPosition = nil
|
updatedScrollPosition = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isInFilter = filter != nil
|
||||||
|
|
||||||
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode)
|
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode)
|
||||||
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, peerGroupId: groupId, mode: mode, transition: $0) })
|
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, peerGroupId: groupId, isInFilter: isInFilter, mode: mode, transition: $0) })
|
||||||
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,6 +1377,10 @@ public final class ChatListNode: ListView {
|
|||||||
})
|
})
|
||||||
isEmptyUpdate = (direction, transition)
|
isEmptyUpdate = (direction, transition)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if transition.options.contains(.AnimateInsertion) {
|
||||||
|
isEmptyUpdate.1 = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strongSelf.currentIsEmptyState != isEmptyState {
|
if strongSelf.currentIsEmptyState != isEmptyState {
|
||||||
|
@ -29,12 +29,9 @@ struct ChatListNodeViewUpdate {
|
|||||||
let scrollPosition: ChatListNodeViewScrollPosition?
|
let scrollPosition: ChatListNodeViewScrollPosition?
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatListFilterPredicate(filter: ChatListFilter) -> (Peer, PeerNotificationSettings?, Bool) -> Bool {
|
func chatListFilterPredicate(filter: ChatListFilter) -> ChatListFilterPredicate {
|
||||||
let includePeers = Set(filter.includePeers)
|
let includePeers = Set(filter.includePeers)
|
||||||
return { peer, notificationSettings, isUnread in
|
return ChatListFilterPredicate(includePeerIds: includePeers, include: { peer, notificationSettings, isUnread in
|
||||||
if includePeers.contains(peer.id) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if filter.excludeRead {
|
if filter.excludeRead {
|
||||||
if !isUnread {
|
if !isUnread {
|
||||||
return false
|
return false
|
||||||
@ -96,11 +93,11 @@ func chatListFilterPredicate(filter: ChatListFilter) -> (Peer, PeerNotificationS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
||||||
let filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)? = location.filter.flatMap(chatListFilterPredicate)
|
let filterPredicate: ChatListFilterPredicate? = location.filter.flatMap(chatListFilterPredicate)
|
||||||
|
|
||||||
switch location {
|
switch location {
|
||||||
case let .initial(count, _):
|
case let .initial(count, _):
|
||||||
|
@ -191,11 +191,19 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||||||
status = .presence(presence, dateTimeFormat)
|
status = .presence(presence, dateTimeFormat)
|
||||||
} else if let group = peer as? TelegramGroup {
|
} else if let group = peer as? TelegramGroup {
|
||||||
status = .custom(strings.Conversation_StatusMembers(Int32(group.participantCount)))
|
status = .custom(strings.Conversation_StatusMembers(Int32(group.participantCount)))
|
||||||
} else if let _ = peer as? TelegramChannel {
|
} else if let channel = peer as? TelegramChannel {
|
||||||
if let participantCount = participantCount, participantCount != 0 {
|
if case .group = channel.info {
|
||||||
status = .custom(strings.Conversation_StatusMembers(participantCount))
|
if let participantCount = participantCount, participantCount != 0 {
|
||||||
|
status = .custom(strings.Conversation_StatusMembers(participantCount))
|
||||||
|
} else {
|
||||||
|
status = .custom(strings.Group_Status)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
status = .custom(strings.Group_Status)
|
if let participantCount = participantCount, participantCount != 0 {
|
||||||
|
status = .custom(strings.Conversation_StatusSubscribers(participantCount))
|
||||||
|
} else {
|
||||||
|
status = .custom(strings.Channel_Status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status = .none
|
status = .none
|
||||||
@ -666,7 +674,7 @@ private struct ContactsListNodeTransition {
|
|||||||
public enum ContactListPresentation {
|
public enum ContactListPresentation {
|
||||||
case orderedByPresence(options: [ContactListAdditionalOption])
|
case orderedByPresence(options: [ContactListAdditionalOption])
|
||||||
case natural(options: [ContactListAdditionalOption], includeChatList: Bool)
|
case natural(options: [ContactListAdditionalOption], includeChatList: Bool)
|
||||||
case search(signal: Signal<String, NoError>, searchChatList: Bool, searchDeviceContacts: Bool, searchGroups: Bool)
|
case search(signal: Signal<String, NoError>, searchChatList: Bool, searchDeviceContacts: Bool, searchGroups: Bool, searchChannels: Bool)
|
||||||
|
|
||||||
public var sortOrder: ContactsSortOrder? {
|
public var sortOrder: ContactsSortOrder? {
|
||||||
switch self {
|
switch self {
|
||||||
@ -909,7 +917,7 @@ public final class ContactListNode: ASDisplayNode {
|
|||||||
includeChatList = natural.includeChatList
|
includeChatList = natural.includeChatList
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .search(query, searchChatList, searchDeviceContacts, searchGroups) = presentation {
|
if case let .search(query, searchChatList, searchDeviceContacts, searchGroups, searchChannels) = presentation {
|
||||||
return query
|
return query
|
||||||
|> mapToSignal { query in
|
|> mapToSignal { query in
|
||||||
let foundLocalContacts: Signal<([FoundPeer], [PeerId: PeerPresence]), NoError>
|
let foundLocalContacts: Signal<([FoundPeer], [PeerId: PeerPresence]), NoError>
|
||||||
@ -919,13 +927,15 @@ public final class ContactListNode: ASDisplayNode {
|
|||||||
|> mapToSignal { peers -> Signal<([FoundPeer], [PeerId: PeerPresence]), NoError> in
|
|> mapToSignal { peers -> Signal<([FoundPeer], [PeerId: PeerPresence]), NoError> in
|
||||||
var resultPeers: [FoundPeer] = []
|
var resultPeers: [FoundPeer] = []
|
||||||
for peer in peers {
|
for peer in peers {
|
||||||
if searchGroups {
|
if searchGroups || searchChannels {
|
||||||
let mainPeer = peer.chatMainPeer
|
let mainPeer = peer.chatMainPeer
|
||||||
if let _ = mainPeer as? TelegramUser {
|
if let _ = mainPeer as? TelegramUser {
|
||||||
} else if let _ = mainPeer as? TelegramGroup {
|
} else if let _ = mainPeer as? TelegramGroup {
|
||||||
} else if let channel = mainPeer as? TelegramChannel {
|
} else if let channel = mainPeer as? TelegramChannel {
|
||||||
if case .broadcast = channel.info {
|
if case .broadcast = channel.info {
|
||||||
continue
|
if !searchChannels {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
@ -1010,14 +1020,14 @@ public final class ContactListNode: ASDisplayNode {
|
|||||||
let matches: Bool
|
let matches: Bool
|
||||||
if peer.peer is TelegramUser {
|
if peer.peer is TelegramUser {
|
||||||
matches = true
|
matches = true
|
||||||
} else if searchGroups {
|
} else if searchGroups || searchChannels {
|
||||||
if peer.peer is TelegramGroup {
|
if peer.peer is TelegramGroup && searchGroups {
|
||||||
matches = true
|
matches = true
|
||||||
} else if let channel = peer.peer as? TelegramChannel {
|
} else if let channel = peer.peer as? TelegramChannel {
|
||||||
if case .group = channel.info {
|
if case .group = channel.info {
|
||||||
matches = true
|
matches = searchGroups
|
||||||
} else {
|
} else {
|
||||||
matches = false
|
matches = searchChannels
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
matches = false
|
matches = false
|
||||||
@ -1040,14 +1050,14 @@ public final class ContactListNode: ASDisplayNode {
|
|||||||
let matches: Bool
|
let matches: Bool
|
||||||
if peer.peer is TelegramUser {
|
if peer.peer is TelegramUser {
|
||||||
matches = true
|
matches = true
|
||||||
} else if searchGroups {
|
} else if searchGroups || searchChannels {
|
||||||
if peer.peer is TelegramGroup {
|
if peer.peer is TelegramGroup {
|
||||||
matches = true
|
matches = searchGroups
|
||||||
} else if let channel = peer.peer as? TelegramChannel {
|
} else if let channel = peer.peer as? TelegramChannel {
|
||||||
if case .group = channel.info {
|
if case .group = channel.info {
|
||||||
matches = true
|
matches = searchGroups
|
||||||
} else {
|
} else {
|
||||||
matches = false
|
matches = searchChannels
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
matches = false
|
matches = false
|
||||||
|
@ -49,6 +49,23 @@ private final class InnerActionsContainerNode: ASDisplayNode {
|
|||||||
private(set) var gesture: UIGestureRecognizer?
|
private(set) var gesture: UIGestureRecognizer?
|
||||||
private var currentHighlightedActionNode: ContextActionNode?
|
private var currentHighlightedActionNode: ContextActionNode?
|
||||||
|
|
||||||
|
var panSelectionGestureEnabled: Bool = true {
|
||||||
|
didSet {
|
||||||
|
if self.panSelectionGestureEnabled != oldValue, let gesture = self.gesture {
|
||||||
|
gesture.isEnabled = self.panSelectionGestureEnabled
|
||||||
|
|
||||||
|
self.itemNodes.forEach({ itemNode in
|
||||||
|
switch itemNode {
|
||||||
|
case let .action(actionNode):
|
||||||
|
actionNode.isUserInteractionEnabled = !self.panSelectionGestureEnabled
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init(presentationData: PresentationData, items: [ContextMenuItem], getController: @escaping () -> ContextController?, actionSelected: @escaping (ContextMenuActionResult) -> Void, feedbackTap: @escaping () -> Void) {
|
init(presentationData: PresentationData, items: [ContextMenuItem], getController: @escaping () -> ContextController?, actionSelected: @escaping (ContextMenuActionResult) -> Void, feedbackTap: @escaping () -> Void) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.feedbackTap = feedbackTap
|
self.feedbackTap = feedbackTap
|
||||||
@ -120,6 +137,7 @@ private final class InnerActionsContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.view.addGestureRecognizer(gesture)
|
self.view.addGestureRecognizer(gesture)
|
||||||
|
gesture.isEnabled = self.panSelectionGestureEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(widthClass: ContainerViewLayoutSizeClass, constrainedWidth: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize {
|
func updateLayout(widthClass: ContainerViewLayoutSizeClass, constrainedWidth: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||||
@ -375,6 +393,14 @@ final class ContextActionsContainerNode: ASDisplayNode {
|
|||||||
private let actionsNode: InnerActionsContainerNode
|
private let actionsNode: InnerActionsContainerNode
|
||||||
private let textSelectionTipNode: InnerTextSelectionTipContainerNode?
|
private let textSelectionTipNode: InnerTextSelectionTipContainerNode?
|
||||||
|
|
||||||
|
var panSelectionGestureEnabled: Bool = true {
|
||||||
|
didSet {
|
||||||
|
if self.panSelectionGestureEnabled != oldValue {
|
||||||
|
self.actionsNode.panSelectionGestureEnabled = self.panSelectionGestureEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init(presentationData: PresentationData, items: [ContextMenuItem], getController: @escaping () -> ContextController?, actionSelected: @escaping (ContextMenuActionResult) -> Void, feedbackTap: @escaping () -> Void, displayTextSelectionTip: Bool) {
|
init(presentationData: PresentationData, items: [ContextMenuItem], getController: @escaping () -> ContextController?, actionSelected: @escaping (ContextMenuActionResult) -> Void, feedbackTap: @escaping () -> Void, displayTextSelectionTip: Bool) {
|
||||||
self.actionsNode = InnerActionsContainerNode(presentationData: presentationData, items: items, getController: getController, actionSelected: actionSelected, feedbackTap: feedbackTap)
|
self.actionsNode = InnerActionsContainerNode(presentationData: presentationData, items: items, getController: getController, actionSelected: actionSelected, feedbackTap: feedbackTap)
|
||||||
if displayTextSelectionTip {
|
if displayTextSelectionTip {
|
||||||
|
@ -206,7 +206,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
self.scrollNode.addSubnode(self.dismissNode)
|
self.scrollNode.addSubnode(self.dismissNode)
|
||||||
|
|
||||||
self.scrollNode.addSubnode(self.actionsContainerNode)
|
self.scrollNode.addSubnode(self.actionsContainerNode)
|
||||||
self.scrollNode.addSubnode(self.contentContainerNode)
|
|
||||||
self.reactionContextNode.flatMap(self.addSubnode)
|
self.reactionContextNode.flatMap(self.addSubnode)
|
||||||
|
|
||||||
if let recognizer = recognizer {
|
if let recognizer = recognizer {
|
||||||
@ -428,6 +427,11 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
|
|
||||||
if let takenViewInfo = takenViewInfo, let parentSupernode = takenViewInfo.contentContainingNode.supernode {
|
if let takenViewInfo = takenViewInfo, let parentSupernode = takenViewInfo.contentContainingNode.supernode {
|
||||||
self.contentContainerNode.contentNode = .extracted(node: takenViewInfo.contentContainingNode, keepInPlace: source.keepInPlace)
|
self.contentContainerNode.contentNode = .extracted(node: takenViewInfo.contentContainingNode, keepInPlace: source.keepInPlace)
|
||||||
|
if source.keepInPlace {
|
||||||
|
self.clippingNode.addSubnode(self.contentContainerNode)
|
||||||
|
} else {
|
||||||
|
self.scrollNode.addSubnode(self.contentContainerNode)
|
||||||
|
}
|
||||||
let contentParentNode = takenViewInfo.contentContainingNode
|
let contentParentNode = takenViewInfo.contentContainingNode
|
||||||
takenViewInfo.contentContainingNode.layoutUpdated = { [weak contentParentNode, weak self] size in
|
takenViewInfo.contentContainingNode.layoutUpdated = { [weak contentParentNode, weak self] size in
|
||||||
guard let strongSelf = self, let contentParentNode = contentParentNode, let parentSupernode = contentParentNode.supernode else {
|
guard let strongSelf = self, let contentParentNode = contentParentNode, let parentSupernode = contentParentNode.supernode else {
|
||||||
@ -476,6 +480,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
self?.attemptTransitionControllerIntoNavigation()
|
self?.attemptTransitionControllerIntoNavigation()
|
||||||
})
|
})
|
||||||
self.contentContainerNode.contentNode = .controller(contentParentNode)
|
self.contentContainerNode.contentNode = .controller(contentParentNode)
|
||||||
|
self.scrollNode.addSubnode(self.contentContainerNode)
|
||||||
self.contentContainerNode.clipsToBounds = true
|
self.contentContainerNode.clipsToBounds = true
|
||||||
self.contentContainerNode.cornerRadius = 14.0
|
self.contentContainerNode.cornerRadius = 14.0
|
||||||
self.contentContainerNode.addSubnode(contentParentNode)
|
self.contentContainerNode.addSubnode(contentParentNode)
|
||||||
@ -493,8 +498,8 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
|
|
||||||
switch self.source {
|
switch self.source {
|
||||||
case let .extracted(source):
|
case let .extracted(source):
|
||||||
if let contentAreaInScreenSpace = contentAreaInScreenSpace {
|
if let contentAreaInScreenSpace = self.contentAreaInScreenSpace, let maybeContentNode = self.contentContainerNode.contentNode, case let .extracted(_, keepInPlace) = maybeContentNode {
|
||||||
var updatedContentAreaInScreenSpace = contentAreaInScreenSpace
|
var updatedContentAreaInScreenSpace = contentAreaInScreenSpace
|
||||||
updatedContentAreaInScreenSpace.origin.x = 0.0
|
updatedContentAreaInScreenSpace.origin.x = 0.0
|
||||||
updatedContentAreaInScreenSpace.size.width = self.bounds.width
|
updatedContentAreaInScreenSpace.size.width = self.bounds.width
|
||||||
|
|
||||||
@ -569,12 +574,19 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
let contentParentNode = extracted
|
let contentParentNode = extracted
|
||||||
let localSourceFrame = self.view.convert(originalProjectedContentViewFrame.1, to: self.scrollNode.view)
|
let localSourceFrame = self.view.convert(originalProjectedContentViewFrame.1, to: self.scrollNode.view)
|
||||||
|
|
||||||
|
let localContentSourceFrame: CGRect
|
||||||
|
if keepInPlace {
|
||||||
|
localContentSourceFrame = self.view.convert(originalProjectedContentViewFrame.1, to: self.contentContainerNode.view.superview)
|
||||||
|
} else {
|
||||||
|
localContentSourceFrame = localSourceFrame
|
||||||
|
}
|
||||||
|
|
||||||
if let reactionContextNode = self.reactionContextNode {
|
if let reactionContextNode = self.reactionContextNode {
|
||||||
reactionContextNode.animateIn(from: CGRect(origin: CGPoint(x: originalProjectedContentViewFrame.1.minX, y: originalProjectedContentViewFrame.1.minY), size: contentParentNode.contentRect.size))
|
reactionContextNode.animateIn(from: CGRect(origin: CGPoint(x: originalProjectedContentViewFrame.1.minX, y: originalProjectedContentViewFrame.1.minY), size: contentParentNode.contentRect.size))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.actionsContainerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
self.actionsContainerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||||
let contentContainerOffset = CGPoint(x: localSourceFrame.center.x - self.contentContainerNode.frame.center.x - contentParentNode.contentRect.minX, y: localSourceFrame.center.y - self.contentContainerNode.frame.center.y)
|
let contentContainerOffset = CGPoint(x: localContentSourceFrame.center.x - self.contentContainerNode.frame.center.x - contentParentNode.contentRect.minX, y: localContentSourceFrame.center.y - self.contentContainerNode.frame.center.y)
|
||||||
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||||
contentParentNode.applyAbsoluteOffsetSpring?(-contentContainerOffset.y, springDuration, springDamping)
|
contentParentNode.applyAbsoluteOffsetSpring?(-contentContainerOffset.y, springDuration, springDamping)
|
||||||
}
|
}
|
||||||
@ -636,7 +648,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
|
|
||||||
switch self.source {
|
switch self.source {
|
||||||
case let .extracted(source):
|
case let .extracted(source):
|
||||||
guard let maybeContentNode = self.contentContainerNode.contentNode, case let .extracted(contentParentNode, _) = maybeContentNode else {
|
guard let maybeContentNode = self.contentContainerNode.contentNode, case let .extracted(contentParentNode, keepInPlace) = maybeContentNode else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,8 +763,15 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
|
|
||||||
if animateOutToItem, let originalProjectedContentViewFrame = self.originalProjectedContentViewFrame {
|
if animateOutToItem, let originalProjectedContentViewFrame = self.originalProjectedContentViewFrame {
|
||||||
let localSourceFrame = self.view.convert(originalProjectedContentViewFrame.1, to: self.scrollNode.view)
|
let localSourceFrame = self.view.convert(originalProjectedContentViewFrame.1, to: self.scrollNode.view)
|
||||||
|
let localContentSourceFrame: CGRect
|
||||||
|
if keepInPlace {
|
||||||
|
localContentSourceFrame = self.view.convert(originalProjectedContentViewFrame.1, to: self.contentContainerNode.view.superview)
|
||||||
|
} else {
|
||||||
|
localContentSourceFrame = localSourceFrame
|
||||||
|
}
|
||||||
|
|
||||||
self.actionsContainerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y), duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false, additive: true)
|
self.actionsContainerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y), duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false, additive: true)
|
||||||
let contentContainerOffset = CGPoint(x: localSourceFrame.center.x - self.contentContainerNode.frame.center.x - contentParentNode.contentRect.minX, y: localSourceFrame.center.y - self.contentContainerNode.frame.center.y - contentParentNode.contentRect.minY)
|
let contentContainerOffset = CGPoint(x: localContentSourceFrame.center.x - self.contentContainerNode.frame.center.x - contentParentNode.contentRect.minX, y: localContentSourceFrame.center.y - self.contentContainerNode.frame.center.y - contentParentNode.contentRect.minY)
|
||||||
self.contentContainerNode.layer.animatePosition(from: CGPoint(), to: contentContainerOffset, duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false, additive: true, completion: { _ in
|
self.contentContainerNode.layer.animatePosition(from: CGPoint(), to: contentContainerOffset, duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false, additive: true, completion: { _ in
|
||||||
completedContentNode = true
|
completedContentNode = true
|
||||||
intermediateCompletion()
|
intermediateCompletion()
|
||||||
@ -1093,13 +1112,14 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
preferredActionsX = originalProjectedContentViewFrame.1.minX
|
preferredActionsX = originalProjectedContentViewFrame.1.minX
|
||||||
}
|
}
|
||||||
var originalActionsFrame = CGRect(origin: CGPoint(x: max(actionsSideInset, min(layout.size.width - actionsSize.width - actionsSideInset, preferredActionsX)), y: originalActionsY), size: actionsSize)
|
var originalActionsFrame = CGRect(origin: CGPoint(x: max(actionsSideInset, min(layout.size.width - actionsSize.width - actionsSideInset, preferredActionsX)), y: originalActionsY), size: actionsSize)
|
||||||
|
var originalContentX: CGFloat = originalProjectedContentViewFrame.1.minX
|
||||||
let originalContentY: CGFloat
|
let originalContentY: CGFloat
|
||||||
if keepInPlace {
|
if keepInPlace {
|
||||||
originalContentY = originalProjectedContentViewFrame.1.minY
|
originalContentY = originalProjectedContentViewFrame.1.minY
|
||||||
} else {
|
} else {
|
||||||
originalContentY = originalActionsFrame.minY - contentActionsSpacing - originalProjectedContentViewFrame.1.size.height
|
originalContentY = originalActionsFrame.minY - contentActionsSpacing - originalProjectedContentViewFrame.1.size.height
|
||||||
}
|
}
|
||||||
var originalContentFrame = CGRect(origin: CGPoint(x: originalProjectedContentViewFrame.1.minX, y: originalContentY), size: originalProjectedContentViewFrame.1.size)
|
var originalContentFrame = CGRect(origin: CGPoint(x: originalContentX, y: originalContentY), size: originalProjectedContentViewFrame.1.size)
|
||||||
let topEdge = max(contentTopInset, self.contentAreaInScreenSpace?.minY ?? 0.0)
|
let topEdge = max(contentTopInset, self.contentAreaInScreenSpace?.minY ?? 0.0)
|
||||||
if originalContentFrame.minY < topEdge {
|
if originalContentFrame.minY < topEdge {
|
||||||
let requiredOffset = topEdge - originalContentFrame.minY
|
let requiredOffset = topEdge - originalContentFrame.minY
|
||||||
@ -1109,21 +1129,43 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
originalContentFrame = originalContentFrame.offsetBy(dx: 0.0, dy: offset)
|
originalContentFrame = originalContentFrame.offsetBy(dx: 0.0, dy: offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
let contentHeight = max(layout.size.height, max(layout.size.height, originalActionsFrame.maxY + actionsBottomInset) - originalContentFrame.minY + contentTopInset)
|
var contentHeight: CGFloat
|
||||||
|
if keepInPlace {
|
||||||
|
contentHeight = max(layout.size.height, max(layout.size.height, originalActionsFrame.maxY + actionsBottomInset) - originalActionsFrame.minY + contentTopInset)
|
||||||
|
} else {
|
||||||
|
contentHeight = max(layout.size.height, max(layout.size.height, originalActionsFrame.maxY + actionsBottomInset) - originalContentFrame.minY + contentTopInset)
|
||||||
|
}
|
||||||
|
|
||||||
|
var overflowOffset: CGFloat
|
||||||
|
let contentContainerFrame: CGRect
|
||||||
|
if keepInPlace {
|
||||||
|
overflowOffset = min(0.0, originalActionsFrame.minY - contentTopInset)
|
||||||
|
contentContainerFrame = originalContentFrame.offsetBy(dx: -contentParentNode.contentRect.minX, dy: -contentParentNode.contentRect.minY)
|
||||||
|
if keepInPlace && !overflowOffset.isZero {
|
||||||
|
let offsetDelta = contentParentNode.contentRect.height + 4.0
|
||||||
|
overflowOffset += offsetDelta
|
||||||
|
originalActionsFrame.origin.x -= contentParentNode.contentRect.maxX - contentParentNode.contentRect.minX + 14.0
|
||||||
|
originalActionsFrame.origin.y += offsetDelta
|
||||||
|
contentHeight -= offsetDelta
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
overflowOffset = min(0.0, originalContentFrame.minY - contentTopInset)
|
||||||
|
contentContainerFrame = originalContentFrame.offsetBy(dx: -contentParentNode.contentRect.minX, dy: -overflowOffset - contentParentNode.contentRect.minY)
|
||||||
|
}
|
||||||
|
|
||||||
let scrollContentSize = CGSize(width: layout.size.width, height: contentHeight)
|
let scrollContentSize = CGSize(width: layout.size.width, height: contentHeight)
|
||||||
if self.scrollNode.view.contentSize != scrollContentSize {
|
if self.scrollNode.view.contentSize != scrollContentSize {
|
||||||
self.scrollNode.view.contentSize = scrollContentSize
|
self.scrollNode.view.contentSize = scrollContentSize
|
||||||
}
|
}
|
||||||
|
self.actionsContainerNode.panSelectionGestureEnabled = scrollContentSize.height <= layout.size.height
|
||||||
|
|
||||||
let overflowOffset = min(0.0, originalContentFrame.minY - contentTopInset)
|
|
||||||
|
|
||||||
let contentContainerFrame = originalContentFrame.offsetBy(dx: -contentParentNode.contentRect.minX, dy: -overflowOffset - contentParentNode.contentRect.minY)
|
|
||||||
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
|
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
|
||||||
actionsContainerTransition.updateFrame(node: self.actionsContainerNode, frame: originalActionsFrame.offsetBy(dx: 0.0, dy: -overflowOffset))
|
actionsContainerTransition.updateFrame(node: self.actionsContainerNode, frame: originalActionsFrame.offsetBy(dx: 0.0, dy: -overflowOffset))
|
||||||
|
|
||||||
if isInitialLayout {
|
if isInitialLayout {
|
||||||
self.scrollNode.view.contentOffset = CGPoint(x: 0.0, y: -overflowOffset)
|
if !keepInPlace {
|
||||||
|
self.scrollNode.view.contentOffset = CGPoint(x: 0.0, y: -overflowOffset)
|
||||||
|
}
|
||||||
let currentContainerFrame = self.view.convert(self.contentContainerNode.frame, from: self.scrollNode.view)
|
let currentContainerFrame = self.view.convert(self.contentContainerNode.frame, from: self.scrollNode.view)
|
||||||
if overflowOffset < 0.0 {
|
if overflowOffset < 0.0 {
|
||||||
transition.animateOffsetAdditive(node: self.scrollNode, offset: currentContainerFrame.minY - previousContainerFrame.minY)
|
transition.animateOffsetAdditive(node: self.scrollNode, offset: currentContainerFrame.minY - previousContainerFrame.minY)
|
||||||
@ -1246,6 +1288,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
if self.scrollNode.view.contentSize != scrollContentSize {
|
if self.scrollNode.view.contentSize != scrollContentSize {
|
||||||
self.scrollNode.view.contentSize = scrollContentSize
|
self.scrollNode.view.contentSize = scrollContentSize
|
||||||
}
|
}
|
||||||
|
self.actionsContainerNode.panSelectionGestureEnabled = true
|
||||||
|
|
||||||
let overflowOffset = min(0.0, originalContentFrame.minY - contentTopInset)
|
let overflowOffset = min(0.0, originalContentFrame.minY - contentTopInset)
|
||||||
|
|
||||||
@ -1295,9 +1338,15 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
guard let layout = self.validLayout else {
|
guard let layout = self.validLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let maybeContentNode = self.contentContainerNode.contentNode, case let .extracted(contentParentNode, _) = maybeContentNode {
|
if let maybeContentNode = self.contentContainerNode.contentNode, case let .extracted(contentParentNode, keepInPlace) = maybeContentNode {
|
||||||
let contentContainerFrame = self.contentContainerNode.frame
|
let contentContainerFrame = self.contentContainerNode.frame
|
||||||
contentParentNode.updateAbsoluteRect?(contentContainerFrame.offsetBy(dx: 0.0, dy: -self.scrollNode.view.contentOffset.y), layout.size)
|
let absoluteRect: CGRect
|
||||||
|
if keepInPlace {
|
||||||
|
absoluteRect = contentContainerFrame
|
||||||
|
} else {
|
||||||
|
absoluteRect = contentContainerFrame.offsetBy(dx: 0.0, dy: -self.scrollNode.view.contentOffset.y)
|
||||||
|
}
|
||||||
|
contentParentNode.updateAbsoluteRect?(absoluteRect, layout.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -778,7 +778,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
effectiveRootModalDismissProgress = topModalIsFlat ? 1.0 : topModalDismissProgress
|
effectiveRootModalDismissProgress = topModalIsFlat ? 1.0 : topModalDismissProgress
|
||||||
visibleRootModalDismissProgress = effectiveRootModalDismissProgress
|
visibleRootModalDismissProgress = effectiveRootModalDismissProgress
|
||||||
additionalModalFrameProgress = 0.0
|
additionalModalFrameProgress = 0.0
|
||||||
} else if visibleModalCount == 2 {
|
} else if visibleModalCount >= 2 {
|
||||||
effectiveRootModalDismissProgress = 0.0
|
effectiveRootModalDismissProgress = 0.0
|
||||||
visibleRootModalDismissProgress = topModalDismissProgress
|
visibleRootModalDismissProgress = topModalDismissProgress
|
||||||
additionalModalFrameProgress = 1.0 - topModalDismissProgress
|
additionalModalFrameProgress = 1.0 - topModalDismissProgress
|
||||||
|
@ -103,6 +103,10 @@ enum NavigationPreviousAction: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class NavigationBar: ASDisplayNode {
|
open class NavigationBar: ASDisplayNode {
|
||||||
|
public static var defaultSecondaryContentHeight: CGFloat {
|
||||||
|
return 38.0
|
||||||
|
}
|
||||||
|
|
||||||
private var presentationData: NavigationBarPresentationData
|
private var presentationData: NavigationBarPresentationData
|
||||||
|
|
||||||
private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat, CGFloat, Bool)?
|
private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat, CGFloat, Bool)?
|
||||||
@ -817,7 +821,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
transition.updateAlpha(node: secondaryContentNode, alpha: appearsHidden ? 0.0 : 1.0)
|
transition.updateAlpha(node: secondaryContentNode, alpha: appearsHidden ? 0.0 : 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
let apparentAdditionalHeight: CGFloat = self.secondaryContentNode != nil ? 46.0 : 0.0
|
let apparentAdditionalHeight: CGFloat = self.secondaryContentNode != nil ? NavigationBar.defaultSecondaryContentHeight : 0.0
|
||||||
|
|
||||||
let leftButtonInset: CGFloat = leftInset + 16.0
|
let leftButtonInset: CGFloat = leftInset + 16.0
|
||||||
let backButtonInset: CGFloat = leftInset + 27.0
|
let backButtonInset: CGFloat = leftInset + 27.0
|
||||||
@ -835,7 +839,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
contentNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height - expansionHeight - apparentAdditionalHeight), size: CGSize(width: size.width, height: expansionHeight))
|
contentNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height - expansionHeight - apparentAdditionalHeight), size: CGSize(width: size.width, height: expansionHeight))
|
||||||
if appearsHidden {
|
if appearsHidden {
|
||||||
if self.secondaryContentNode != nil {
|
if self.secondaryContentNode != nil {
|
||||||
contentNodeFrame.origin.y += 46.0
|
contentNodeFrame.origin.y += NavigationBar.defaultSecondaryContentHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1128,7 +1132,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let _ = self.secondaryContentNode {
|
if let _ = self.secondaryContentNode {
|
||||||
result += 46.0
|
result += NavigationBar.defaultSecondaryContentHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -495,12 +495,15 @@ class TabBarNode: ASDisplayNode {
|
|||||||
let nodeSize = node.textImageNode.image?.size ?? CGSize()
|
let nodeSize = node.textImageNode.image?.size ?? CGSize()
|
||||||
|
|
||||||
let originX = floor(leftNodeOriginX + CGFloat(i) * distanceBetweenNodes - nodeSize.width / 2.0)
|
let originX = floor(leftNodeOriginX + CGFloat(i) * distanceBetweenNodes - nodeSize.width / 2.0)
|
||||||
|
let horizontalHitTestInset = distanceBetweenNodes / 2.0 - nodeSize.width / 2.0
|
||||||
let nodeFrame = CGRect(origin: CGPoint(x: originX, y: 3.0), size: nodeSize)
|
let nodeFrame = CGRect(origin: CGPoint(x: originX, y: 3.0), size: nodeSize)
|
||||||
transition.updateFrame(node: node, frame: nodeFrame)
|
transition.updateFrame(node: node, frame: nodeFrame)
|
||||||
node.extractedContainerNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
node.extractedContainerNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
||||||
node.extractedContainerNode.contentNode.frame = node.extractedContainerNode.bounds
|
node.extractedContainerNode.contentNode.frame = node.extractedContainerNode.bounds
|
||||||
node.extractedContainerNode.contentRect = node.extractedContainerNode.bounds
|
node.extractedContainerNode.contentRect = node.extractedContainerNode.bounds
|
||||||
node.containerNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
node.containerNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
||||||
|
node.hitTestSlop = UIEdgeInsets(top: -3.0, left: -horizontalHitTestInset, bottom: -3.0, right: -horizontalHitTestInset)
|
||||||
|
node.containerNode.hitTestSlop = UIEdgeInsets(top: -3.0, left: -horizontalHitTestInset, bottom: -3.0, right: -horizontalHitTestInset)
|
||||||
node.imageNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
node.imageNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
||||||
node.textImageNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
node.textImageNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
||||||
node.contextImageNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
node.contextImageNode.frame = CGRect(origin: CGPoint(), size: nodeFrame.size)
|
||||||
|
@ -219,9 +219,6 @@ public enum ViewControllerNavigationPresentation {
|
|||||||
if let contentNode = navigationBar.contentNode, case .expansion = contentNode.mode {
|
if let contentNode = navigationBar.contentNode, case .expansion = contentNode.mode {
|
||||||
height += contentNode.nominalHeight - contentNode.height
|
height += contentNode.nominalHeight - contentNode.height
|
||||||
}
|
}
|
||||||
if navigationBar.secondaryContentNode != nil {
|
|
||||||
//height -= 46.0
|
|
||||||
}
|
|
||||||
return height
|
return height
|
||||||
} else {
|
} else {
|
||||||
return 0.0
|
return 0.0
|
||||||
|
@ -356,7 +356,7 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) ->
|
|||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { members in
|
|> deliverOnMainQueue).start(next: { members in
|
||||||
let disabledIds = members?.compactMap({$0.peer.id}) ?? []
|
let disabledIds = members?.compactMap({$0.peer.id}) ?? []
|
||||||
let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: false, searchGroups: false), options: [], filters: [.excludeSelf, .disable(disabledIds)]))
|
let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: [], filters: [.excludeSelf, .disable(disabledIds)]))
|
||||||
|
|
||||||
addMembersDisposable.set((contactsController.result
|
addMembersDisposable.set((contactsController.result
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|
@ -1665,7 +1665,7 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: false, searchGroups: false), options: options, filters: [.excludeSelf, .disable(recentIds)]))
|
contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: options, filters: [.excludeSelf, .disable(recentIds)]))
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmationImpl = { [weak contactsController] peerId in
|
confirmationImpl = { [weak contactsController] peerId in
|
||||||
|
@ -2152,34 +2152,16 @@ public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepr
|
|||||||
if let thumbnailImage = thumbnailImage {
|
if let thumbnailImage = thumbnailImage {
|
||||||
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
||||||
|
|
||||||
let initialThumbnailContextFittingSize = fittedSize.fitted(CGSize(width: 90.0, height: 90.0))
|
let initialThumbnailContextFittingSize = fittedSize.fitted(CGSize(width: 350.0, height: 350.0))
|
||||||
|
|
||||||
let thumbnailContextSize = thumbnailSize.aspectFitted(initialThumbnailContextFittingSize)
|
let thumbnailContextSize = thumbnailSize.aspectFilled(initialThumbnailContextFittingSize)
|
||||||
let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0)
|
let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0)
|
||||||
thumbnailContext.withFlippedContext { c in
|
thumbnailContext.withFlippedContext { c in
|
||||||
c.draw(thumbnailImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize))
|
c.draw(thumbnailImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize))
|
||||||
}
|
}
|
||||||
telegramFastBlurMore(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes)
|
imageFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes)
|
||||||
|
|
||||||
var thumbnailContextFittingSize = CGSize(width: floor(arguments.drawingSize.width * 0.5), height: floor(arguments.drawingSize.width * 0.5))
|
blurredThumbnailImage = thumbnailContext.generateImage()
|
||||||
if thumbnailContextFittingSize.width < 150.0 || thumbnailContextFittingSize.height < 150.0 {
|
|
||||||
thumbnailContextFittingSize = thumbnailContextFittingSize.aspectFilled(CGSize(width: 150.0, height: 150.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
if false, thumbnailContextFittingSize.width > thumbnailContextSize.width {
|
|
||||||
let additionalContextSize = thumbnailContextFittingSize
|
|
||||||
let additionalBlurContext = DrawingContext(size: additionalContextSize, scale: 1.0)
|
|
||||||
additionalBlurContext.withFlippedContext { c in
|
|
||||||
c.interpolationQuality = .default
|
|
||||||
if let image = thumbnailContext.generateImage()?.cgImage {
|
|
||||||
c.draw(image, in: CGRect(origin: CGPoint(), size: additionalContextSize))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imageFastBlur(Int32(additionalContextSize.width), Int32(additionalContextSize.height), Int32(additionalBlurContext.bytesPerRow), additionalBlurContext.bytes)
|
|
||||||
blurredThumbnailImage = additionalBlurContext.generateImage()
|
|
||||||
} else {
|
|
||||||
blurredThumbnailImage = thumbnailContext.generateImage()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let blurredThumbnailImage = blurredThumbnailImage, fullSizeImage == nil {
|
if let blurredThumbnailImage = blurredThumbnailImage, fullSizeImage == nil {
|
||||||
|
@ -245,7 +245,7 @@ final class ChatListTable: Table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUnreadChatListPeerIds(postbox: Postbox, groupId: PeerGroupId, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?) -> [PeerId] {
|
func getUnreadChatListPeerIds(postbox: Postbox, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?) -> [PeerId] {
|
||||||
var result: [PeerId] = []
|
var result: [PeerId] = []
|
||||||
self.valueBox.range(self.table, start: self.upperBound(groupId: groupId), end: self.lowerBound(groupId: groupId), keys: { key in
|
self.valueBox.range(self.table, start: self.upperBound(groupId: groupId), end: self.lowerBound(groupId: groupId), keys: { key in
|
||||||
let (_, _, messageIndex, _) = extractKey(key)
|
let (_, _, messageIndex, _) = extractKey(key)
|
||||||
@ -255,7 +255,7 @@ final class ChatListTable: Table {
|
|||||||
if let filterPredicate = filterPredicate {
|
if let filterPredicate = filterPredicate {
|
||||||
if let peer = postbox.peerTable.get(messageIndex.id.peerId) {
|
if let peer = postbox.peerTable.get(messageIndex.id.peerId) {
|
||||||
let isUnread = postbox.readStateTable.getCombinedState(messageIndex.id.peerId)?.isUnread ?? false
|
let isUnread = postbox.readStateTable.getCombinedState(messageIndex.id.peerId)?.isUnread ?? false
|
||||||
if filterPredicate(peer, postbox.peerNotificationSettingsTable.getEffective(messageIndex.id.peerId), isUnread) {
|
if filterPredicate.includes(peer: peer, notificationSettings: postbox.peerNotificationSettingsTable.getEffective(messageIndex.id.peerId), isUnread: isUnread) {
|
||||||
passFilter = true
|
passFilter = true
|
||||||
} else {
|
} else {
|
||||||
passFilter = false
|
passFilter = false
|
||||||
@ -670,6 +670,19 @@ final class ChatListTable: Table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getEntry(peerId: PeerId, messageHistoryTable: MessageHistoryTable, peerChatInterfaceStateTable: PeerChatInterfaceStateTable) -> ChatListIntermediateEntry? {
|
||||||
|
if let (peerGroupId, index) = self.getPeerChatListIndex(peerId: peerId) {
|
||||||
|
let key = self.key(groupId: peerGroupId, index: index, type: .message)
|
||||||
|
if let value = self.valueBox.get(self.table, key: key) {
|
||||||
|
return readEntry(groupId: peerGroupId, messageHistoryTable: messageHistoryTable, peerChatInterfaceStateTable: peerChatInterfaceStateTable, key: key, value: value)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func allEntries(groupId: PeerGroupId) -> [ChatListEntryInfo] {
|
func allEntries(groupId: PeerGroupId) -> [ChatListEntryInfo] {
|
||||||
var entries: [ChatListEntryInfo] = []
|
var entries: [ChatListEntryInfo] = []
|
||||||
self.valueBox.range(self.table, start: self.upperBound(groupId: groupId), end: self.lowerBound(groupId: groupId), values: { key, value in
|
self.valueBox.range(self.table, start: self.upperBound(groupId: groupId), end: self.lowerBound(groupId: groupId), values: { key, value in
|
||||||
|
@ -295,19 +295,39 @@ private func updatedRenderedPeer(_ renderedPeer: RenderedPeer, updatedPeers: [Pe
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct ChatListFilterPredicate {
|
||||||
|
public var includePeerIds: Set<PeerId>
|
||||||
|
public var include: (Peer, PeerNotificationSettings?, Bool) -> Bool
|
||||||
|
|
||||||
|
public init(includePeerIds: Set<PeerId>, include: @escaping (Peer, PeerNotificationSettings?, Bool) -> Bool) {
|
||||||
|
self.includePeerIds = includePeerIds
|
||||||
|
self.include = include
|
||||||
|
}
|
||||||
|
|
||||||
|
func includes(peer: Peer, notificationSettings: PeerNotificationSettings?, isUnread: Bool) -> Bool {
|
||||||
|
if self.includePeerIds.contains(peer.id) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return self.include(peer, notificationSettings, isUnread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class MutableChatListView {
|
final class MutableChatListView {
|
||||||
let groupId: PeerGroupId
|
let groupId: PeerGroupId
|
||||||
let filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?
|
let filterPredicate: ChatListFilterPredicate?
|
||||||
private let summaryComponents: ChatListEntrySummaryComponents
|
private let summaryComponents: ChatListEntrySummaryComponents
|
||||||
fileprivate var additionalItemIds: Set<PeerId>
|
fileprivate var additionalItemIds: Set<PeerId>
|
||||||
fileprivate var additionalItemEntries: [MutableChatListEntry]
|
fileprivate var additionalItemEntries: [MutableChatListEntry]
|
||||||
|
fileprivate var additionalMixedItemIds: Set<PeerId>
|
||||||
|
fileprivate var additionalMixedItemEntries: [MutableChatListEntry]
|
||||||
fileprivate var earlier: MutableChatListEntry?
|
fileprivate var earlier: MutableChatListEntry?
|
||||||
fileprivate var later: MutableChatListEntry?
|
fileprivate var later: MutableChatListEntry?
|
||||||
fileprivate var entries: [MutableChatListEntry]
|
fileprivate var entries: [MutableChatListEntry]
|
||||||
fileprivate var groupEntries: [ChatListGroupReferenceEntry]
|
fileprivate var groupEntries: [ChatListGroupReferenceEntry]
|
||||||
private var count: Int
|
private var count: Int
|
||||||
|
|
||||||
init(postbox: Postbox, groupId: PeerGroupId, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?, aroundIndex: ChatListIndex, count: Int, summaryComponents: ChatListEntrySummaryComponents) {
|
init(postbox: Postbox, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?, aroundIndex: ChatListIndex, count: Int, summaryComponents: ChatListEntrySummaryComponents) {
|
||||||
let (entries, earlier, later) = postbox.fetchAroundChatEntries(groupId: groupId, index: aroundIndex, count: count, filterPredicate: filterPredicate)
|
let (entries, earlier, later) = postbox.fetchAroundChatEntries(groupId: groupId, index: aroundIndex, count: count, filterPredicate: filterPredicate)
|
||||||
|
|
||||||
self.groupId = groupId
|
self.groupId = groupId
|
||||||
@ -318,6 +338,16 @@ final class MutableChatListView {
|
|||||||
self.count = count
|
self.count = count
|
||||||
self.summaryComponents = summaryComponents
|
self.summaryComponents = summaryComponents
|
||||||
self.additionalItemEntries = []
|
self.additionalItemEntries = []
|
||||||
|
self.additionalMixedItemEntries = []
|
||||||
|
self.additionalMixedItemIds = Set()
|
||||||
|
if let filterPredicate = self.filterPredicate {
|
||||||
|
self.additionalMixedItemIds.formUnion(filterPredicate.includePeerIds)
|
||||||
|
}
|
||||||
|
for peerId in self.additionalMixedItemIds {
|
||||||
|
if let entry = postbox.chatListTable.getEntry(peerId: peerId, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable) {
|
||||||
|
self.additionalMixedItemEntries.append(MutableChatListEntry(entry, cachedDataTable: postbox.cachedPeerDataTable, readStateTable: postbox.readStateTable, messageHistoryTable: postbox.messageHistoryTable))
|
||||||
|
}
|
||||||
|
}
|
||||||
if case .root = groupId, self.filterPredicate == nil {
|
if case .root = groupId, self.filterPredicate == nil {
|
||||||
let itemIds = postbox.additionalChatListItemsTable.get()
|
let itemIds = postbox.additionalChatListItemsTable.get()
|
||||||
self.additionalItemIds = Set(itemIds)
|
self.additionalItemIds = Set(itemIds)
|
||||||
@ -436,26 +466,55 @@ final class MutableChatListView {
|
|||||||
if let groupOperations = operations[self.groupId] {
|
if let groupOperations = operations[self.groupId] {
|
||||||
for operation in groupOperations {
|
for operation in groupOperations {
|
||||||
switch operation {
|
switch operation {
|
||||||
case let .InsertEntry(index, message, combinedReadState, embeddedState):
|
case let .InsertEntry(index, message, combinedReadState, embeddedState):
|
||||||
if self.add(.IntermediateMessageEntry(index, message, combinedReadState, embeddedState), postbox: postbox) {
|
if self.add(.IntermediateMessageEntry(index, message, combinedReadState, embeddedState), postbox: postbox) {
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
case let .InsertHole(index):
|
case let .InsertHole(index):
|
||||||
if self.add(.HoleEntry(index), postbox: postbox) {
|
if self.add(.HoleEntry(index), postbox: postbox) {
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
case let .RemoveEntry(indices):
|
case let .RemoveEntry(indices):
|
||||||
if self.remove(Set(indices), type: .message, context: context) {
|
if self.remove(Set(indices), type: .message, context: context) {
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
case let .RemoveHoles(indices):
|
case let .RemoveHoles(indices):
|
||||||
if self.remove(Set(indices), type: .hole, context: context) {
|
if self.remove(Set(indices), type: .hole, context: context) {
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*if let filterPredicate = self.filterPredicate, !filterPredicate.includePeerIds.isEmpty {
|
||||||
|
for (groupId, groupOperations) in operations {
|
||||||
|
if groupId == self.groupId {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for operation in groupOperations {
|
||||||
|
switch operation {
|
||||||
|
case let .InsertEntry(index, message, combinedReadState, embeddedState):
|
||||||
|
if filterPredicate.includePeerIds.contains(index.messageIndex.id.peerId) {
|
||||||
|
if self.add(.IntermediateMessageEntry(index, message, combinedReadState, embeddedState), postbox: postbox) {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .InsertHole:
|
||||||
|
break
|
||||||
|
case let .RemoveEntry(indices):
|
||||||
|
let updatedIndices = indices.filter { index in
|
||||||
|
return filterPredicate.includePeerIds.contains(index.messageIndex.id.peerId)
|
||||||
|
}
|
||||||
|
if !updatedIndices.isEmpty && self.remove(Set(updatedIndices), type: .message, context: context) {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
case .RemoveHoles:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
if case .root = self.groupId, self.filterPredicate == nil {
|
if case .root = self.groupId, self.filterPredicate == nil {
|
||||||
var invalidatedGroups = false
|
var invalidatedGroups = false
|
||||||
for (groupId, groupOperations) in operations {
|
for (groupId, groupOperations) in operations {
|
||||||
@ -497,11 +556,17 @@ final class MutableChatListView {
|
|||||||
for (peerId, settingsChange) in updatedPeerNotificationSettings {
|
for (peerId, settingsChange) in updatedPeerNotificationSettings {
|
||||||
if let peer = postbox.peerTable.get(peerId) {
|
if let peer = postbox.peerTable.get(peerId) {
|
||||||
let isUnread = postbox.readStateTable.getCombinedState(peerId)?.isUnread ?? false
|
let isUnread = postbox.readStateTable.getCombinedState(peerId)?.isUnread ?? false
|
||||||
let wasIncluded = filterPredicate(peer, settingsChange.0, isUnread)
|
let wasIncluded = filterPredicate.includes(peer: peer, notificationSettings: settingsChange.0, isUnread: isUnread)
|
||||||
let isIncluded = filterPredicate(peer, settingsChange.1, isUnread)
|
let isIncluded = filterPredicate.includes(peer: peer, notificationSettings: settingsChange.1, isUnread: isUnread)
|
||||||
if wasIncluded != isIncluded {
|
if wasIncluded != isIncluded {
|
||||||
if isIncluded {
|
if isIncluded {
|
||||||
if let entry = postbox.chatListTable.getEntry(groupId: self.groupId, peerId: peerId, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable) {
|
let tableEntry: ChatListIntermediateEntry?
|
||||||
|
if filterPredicate.includePeerIds.contains(peerId) {
|
||||||
|
tableEntry = postbox.chatListTable.getEntry(peerId: peerId, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable)
|
||||||
|
} else {
|
||||||
|
tableEntry = postbox.chatListTable.getEntry(groupId: self.groupId, peerId: peerId, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable)
|
||||||
|
}
|
||||||
|
if let entry = tableEntry {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .message(index, message, embeddedState):
|
case let .message(index, message, embeddedState):
|
||||||
let combinedReadState = postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId)
|
let combinedReadState = postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId)
|
||||||
@ -657,6 +722,27 @@ final class MutableChatListView {
|
|||||||
}
|
}
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
|
var updateAdditionalMixedItems = false
|
||||||
|
for peerId in self.additionalMixedItemIds {
|
||||||
|
if transaction.currentOperationsByPeerId[peerId] != nil {
|
||||||
|
updateAdditionalMixedItems = true
|
||||||
|
}
|
||||||
|
if transaction.currentUpdatedPeers[peerId] != nil {
|
||||||
|
updateAdditionalMixedItems = true
|
||||||
|
}
|
||||||
|
if transaction.currentUpdatedChatListInclusions[peerId] != nil {
|
||||||
|
updateAdditionalMixedItems = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if updateAdditionalMixedItems {
|
||||||
|
self.additionalMixedItemEntries.removeAll()
|
||||||
|
for peerId in self.additionalMixedItemIds {
|
||||||
|
if let entry = postbox.chatListTable.getEntry(peerId: peerId, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable) {
|
||||||
|
self.additionalMixedItemEntries.append(MutableChatListEntry(entry, cachedDataTable: postbox.cachedPeerDataTable, readStateTable: postbox.readStateTable, messageHistoryTable: postbox.messageHistoryTable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
return hasChanges
|
return hasChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +752,7 @@ final class MutableChatListView {
|
|||||||
case .IntermediateMessageEntry(let index, _, _, _), .MessageEntry(let index, _, _, _, _, _, _, _, _):
|
case .IntermediateMessageEntry(let index, _, _, _), .MessageEntry(let index, _, _, _, _, _, _, _, _):
|
||||||
if let peer = postbox.peerTable.get(index.messageIndex.id.peerId) {
|
if let peer = postbox.peerTable.get(index.messageIndex.id.peerId) {
|
||||||
let isUnread = postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId)?.isUnread ?? false
|
let isUnread = postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId)?.isUnread ?? false
|
||||||
if !filterPredicate(peer, postbox.peerNotificationSettingsTable.getEffective(index.messageIndex.id.peerId), isUnread) {
|
if !filterPredicate.includes(peer: peer, notificationSettings: postbox.peerNotificationSettingsTable.getEffective(index.messageIndex.id.peerId), isUnread: isUnread) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -953,6 +1039,11 @@ final class MutableChatListView {
|
|||||||
self.additionalItemEntries[i] = updatedEntry
|
self.additionalItemEntries[i] = updatedEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for i in 0 ..< self.additionalMixedItemEntries.count {
|
||||||
|
if let updatedEntry = self.renderEntry(self.additionalMixedItemEntries[i], postbox: postbox, renderMessage: renderMessage, getPeer: getPeer, getPeerNotificationSettings: getPeerNotificationSettings, getPeerPresence: getPeerPresence) {
|
||||||
|
self.additionalMixedItemEntries[i] = updatedEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,18 +1061,37 @@ public final class ChatListView {
|
|||||||
var entries: [ChatListEntry] = []
|
var entries: [ChatListEntry] = []
|
||||||
for entry in mutableView.entries {
|
for entry in mutableView.entries {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
||||||
entries.append(.MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed))
|
entries.append(.MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed))
|
||||||
case let .HoleEntry(hole):
|
case let .HoleEntry(hole):
|
||||||
entries.append(.HoleEntry(hole))
|
entries.append(.HoleEntry(hole))
|
||||||
/*case let .GroupReferenceEntry(groupId, index, message, topPeers, counters):
|
case .IntermediateMessageEntry:
|
||||||
entries.append(.GroupReferenceEntry(groupId, index, message, topPeers.getPeers(), GroupReferenceUnreadCounters(counters)))*/
|
assertionFailure()
|
||||||
case .IntermediateMessageEntry:
|
|
||||||
assertionFailure()
|
|
||||||
/*case .IntermediateGroupReferenceEntry:
|
|
||||||
assertionFailure()*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !mutableView.additionalMixedItemEntries.isEmpty {
|
||||||
|
var existingIds = Set<PeerId>()
|
||||||
|
for entry in entries {
|
||||||
|
if case let .MessageEntry(messageEntry) = entry {
|
||||||
|
existingIds.insert(messageEntry.0.messageIndex.id.peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for entry in mutableView.additionalMixedItemEntries {
|
||||||
|
if case let .MessageEntry(messageEntry) = entry {
|
||||||
|
if !existingIds.contains(messageEntry.0.messageIndex.id.peerId) {
|
||||||
|
switch entry {
|
||||||
|
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
||||||
|
entries.append(.MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed))
|
||||||
|
case let .HoleEntry(hole):
|
||||||
|
entries.append(.HoleEntry(hole))
|
||||||
|
case .IntermediateMessageEntry:
|
||||||
|
assertionFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entries.sort()
|
||||||
|
}
|
||||||
self.groupEntries = mutableView.groupEntries
|
self.groupEntries = mutableView.groupEntries
|
||||||
self.entries = entries
|
self.entries = entries
|
||||||
self.earlierIndex = mutableView.earlier?.index
|
self.earlierIndex = mutableView.earlier?.index
|
||||||
|
@ -303,7 +303,7 @@ public final class Transaction {
|
|||||||
return self.postbox?.chatListTable.getPeerChatListIndex(peerId: peerId)
|
return self.postbox?.chatListTable.getPeerChatListIndex(peerId: peerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getUnreadChatListPeerIds(groupId: PeerGroupId, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?) -> [PeerId] {
|
public func getUnreadChatListPeerIds(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?) -> [PeerId] {
|
||||||
assert(!self.disposed)
|
assert(!self.disposed)
|
||||||
if let postbox = self.postbox {
|
if let postbox = self.postbox {
|
||||||
return postbox.chatListTable.getUnreadChatListPeerIds(postbox: postbox, groupId: groupId, filterPredicate: filterPredicate)
|
return postbox.chatListTable.getUnreadChatListPeerIds(postbox: postbox, groupId: groupId, filterPredicate: filterPredicate)
|
||||||
@ -1653,13 +1653,13 @@ public final class Postbox {
|
|||||||
self.synchronizeGroupMessageStatsTable.set(groupId: groupId, namespace: namespace, needsValidation: false, operations: &self.currentUpdatedGroupSummarySynchronizeOperations)
|
self.synchronizeGroupMessageStatsTable.set(groupId: groupId, namespace: namespace, needsValidation: false, operations: &self.currentUpdatedGroupSummarySynchronizeOperations)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func mappedChatListFilterPredicate(_ predicate: @escaping (Peer, PeerNotificationSettings?, Bool) -> Bool) -> (ChatListIntermediateEntry) -> Bool {
|
private func mappedChatListFilterPredicate(_ predicate: ChatListFilterPredicate) -> (ChatListIntermediateEntry) -> Bool {
|
||||||
return { entry in
|
return { entry in
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .message(index, _, _):
|
case let .message(index, _, _):
|
||||||
if let peer = self.peerTable.get(index.messageIndex.id.peerId) {
|
if let peer = self.peerTable.get(index.messageIndex.id.peerId) {
|
||||||
let isUnread = self.readStateTable.getCombinedState(index.messageIndex.id.peerId)?.isUnread ?? false
|
let isUnread = self.readStateTable.getCombinedState(index.messageIndex.id.peerId)?.isUnread ?? false
|
||||||
if predicate(peer, self.peerNotificationSettingsTable.getEffective(index.messageIndex.id.peerId), isUnread) {
|
if predicate.includes(peer: peer, notificationSettings: self.peerNotificationSettingsTable.getEffective(index.messageIndex.id.peerId), isUnread: isUnread) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -1673,7 +1673,7 @@ public final class Postbox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAroundChatEntries(groupId: PeerGroupId, index: ChatListIndex, count: Int, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?) -> (entries: [MutableChatListEntry], earlier: MutableChatListEntry?, later: MutableChatListEntry?) {
|
func fetchAroundChatEntries(groupId: PeerGroupId, index: ChatListIndex, count: Int, filterPredicate: ChatListFilterPredicate?) -> (entries: [MutableChatListEntry], earlier: MutableChatListEntry?, later: MutableChatListEntry?) {
|
||||||
let mappedPredicate = filterPredicate.flatMap(self.mappedChatListFilterPredicate)
|
let mappedPredicate = filterPredicate.flatMap(self.mappedChatListFilterPredicate)
|
||||||
let (intermediateEntries, intermediateLower, intermediateUpper) = self.chatListTable.entriesAround(groupId: groupId, index: index, messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, count: count, predicate: mappedPredicate)
|
let (intermediateEntries, intermediateLower, intermediateUpper) = self.chatListTable.entriesAround(groupId: groupId, index: index, messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, count: count, predicate: mappedPredicate)
|
||||||
let entries: [MutableChatListEntry] = intermediateEntries.map { entry in
|
let entries: [MutableChatListEntry] = intermediateEntries.map { entry in
|
||||||
@ -1689,7 +1689,7 @@ public final class Postbox {
|
|||||||
return (entries, lower, upper)
|
return (entries, lower, upper)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchEarlierChatEntries(groupId: PeerGroupId, index: ChatListIndex?, count: Int, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?) -> [MutableChatListEntry] {
|
func fetchEarlierChatEntries(groupId: PeerGroupId, index: ChatListIndex?, count: Int, filterPredicate: ChatListFilterPredicate?) -> [MutableChatListEntry] {
|
||||||
let mappedPredicate = filterPredicate.flatMap(self.mappedChatListFilterPredicate)
|
let mappedPredicate = filterPredicate.flatMap(self.mappedChatListFilterPredicate)
|
||||||
let intermediateEntries = self.chatListTable.earlierEntries(groupId: groupId, index: index.flatMap({ ($0, true) }), messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, count: count, predicate: mappedPredicate)
|
let intermediateEntries = self.chatListTable.earlierEntries(groupId: groupId, index: index.flatMap({ ($0, true) }), messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, count: count, predicate: mappedPredicate)
|
||||||
let entries: [MutableChatListEntry] = intermediateEntries.map { entry in
|
let entries: [MutableChatListEntry] = intermediateEntries.map { entry in
|
||||||
@ -1698,7 +1698,7 @@ public final class Postbox {
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchLaterChatEntries(groupId: PeerGroupId, index: ChatListIndex?, count: Int, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?) -> [MutableChatListEntry] {
|
func fetchLaterChatEntries(groupId: PeerGroupId, index: ChatListIndex?, count: Int, filterPredicate: ChatListFilterPredicate?) -> [MutableChatListEntry] {
|
||||||
let mappedPredicate = filterPredicate.flatMap(self.mappedChatListFilterPredicate)
|
let mappedPredicate = filterPredicate.flatMap(self.mappedChatListFilterPredicate)
|
||||||
let intermediateEntries = self.chatListTable.laterEntries(groupId: groupId, index: index.flatMap({ ($0, true) }), messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, count: count, predicate: mappedPredicate)
|
let intermediateEntries = self.chatListTable.laterEntries(groupId: groupId, index: index.flatMap({ ($0, true) }), messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, count: count, predicate: mappedPredicate)
|
||||||
let entries: [MutableChatListEntry] = intermediateEntries.map { entry in
|
let entries: [MutableChatListEntry] = intermediateEntries.map { entry in
|
||||||
@ -2546,11 +2546,11 @@ public final class Postbox {
|
|||||||
|> switchToLatest
|
|> switchToLatest
|
||||||
}
|
}
|
||||||
|
|
||||||
public func tailChatListView(groupId: PeerGroupId, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)? = nil, count: Int, summaryComponents: ChatListEntrySummaryComponents) -> Signal<(ChatListView, ViewUpdateType), NoError> {
|
public func tailChatListView(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate? = nil, count: Int, summaryComponents: ChatListEntrySummaryComponents) -> Signal<(ChatListView, ViewUpdateType), NoError> {
|
||||||
return self.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: ChatListIndex.absoluteUpperBound, count: count, summaryComponents: summaryComponents, userInteractive: true)
|
return self.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: ChatListIndex.absoluteUpperBound, count: count, summaryComponents: summaryComponents, userInteractive: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func aroundChatListView(groupId: PeerGroupId, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)? = nil, index: ChatListIndex, count: Int, summaryComponents: ChatListEntrySummaryComponents, userInteractive: Bool = false) -> Signal<(ChatListView, ViewUpdateType), NoError> {
|
public func aroundChatListView(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate? = nil, index: ChatListIndex, count: Int, summaryComponents: ChatListEntrySummaryComponents, userInteractive: Bool = false) -> Signal<(ChatListView, ViewUpdateType), NoError> {
|
||||||
return self.transactionSignal(userInteractive: userInteractive, { subscriber, transaction in
|
return self.transactionSignal(userInteractive: userInteractive, { subscriber, transaction in
|
||||||
let mutableView = MutableChatListView(postbox: self, groupId: groupId, filterPredicate: filterPredicate, aroundIndex: index, count: count, summaryComponents: summaryComponents)
|
let mutableView = MutableChatListView(postbox: self, groupId: groupId, filterPredicate: filterPredicate, aroundIndex: index, count: count, summaryComponents: summaryComponents)
|
||||||
mutableView.render(postbox: self, renderMessage: self.renderIntermediateMessage, getPeer: { id in
|
mutableView.render(postbox: self, renderMessage: self.renderIntermediateMessage, getPeer: { id in
|
||||||
|
@ -767,7 +767,7 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
if peerIds.isEmpty {
|
if peerIds.isEmpty {
|
||||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true), options: []))
|
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true, searchChannels: false), options: []))
|
||||||
addPeerDisposable.set((controller.result
|
addPeerDisposable.set((controller.result
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { [weak controller] peerIds in
|
|> deliverOnMainQueue).start(next: { [weak controller] peerIds in
|
||||||
|
@ -290,7 +290,7 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri
|
|||||||
|
|
||||||
removePeerDisposable.set(applyPeers.start())
|
removePeerDisposable.set(applyPeers.start())
|
||||||
}, addPeer: {
|
}, addPeer: {
|
||||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true), options: []))
|
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true, searchChannels: false), options: []))
|
||||||
addPeerDisposable.set((controller.result
|
addPeerDisposable.set((controller.result
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { [weak controller] peerIds in
|
|> deliverOnMainQueue).start(next: { [weak controller] peerIds in
|
||||||
|
@ -803,8 +803,6 @@ private final class SettingsControllerImpl: ItemListController, SettingsControll
|
|||||||
strongSelf.addAccount?()
|
strongSelf.addAccount?()
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
})))
|
})))
|
||||||
|
|
||||||
items.append(.separator)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func accountIconSignal(account: Account, peer: Peer, size: CGSize) -> Signal<UIImage?, NoError> {
|
func accountIconSignal(account: Account, peer: Peer, size: CGSize) -> Signal<UIImage?, NoError> {
|
||||||
@ -837,6 +835,10 @@ private final class SettingsControllerImpl: ItemListController, SettingsControll
|
|||||||
f(.default)
|
f(.default)
|
||||||
})))
|
})))
|
||||||
|
|
||||||
|
if !other.isEmpty {
|
||||||
|
items.append(.separator)
|
||||||
|
}
|
||||||
|
|
||||||
for account in other {
|
for account in other {
|
||||||
let id = account.0.id
|
let id = account.0.id
|
||||||
items.append(.action(ContextMenuActionItem(text: account.1.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), badge: account.2 != 0 ? "\(account.2)" : "", icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: accountIconSignal(account: account.0, peer: account.1, size: avatarSize)), action: { [weak self] _, f in
|
items.append(.action(ContextMenuActionItem(text: account.1.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), badge: account.2 != 0 ? "\(account.2)" : "", icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: accountIconSignal(account: account.0, peer: account.1, size: avatarSize)), action: { [weak self] _, f in
|
||||||
|
@ -233,22 +233,22 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
let timestamp = self.referenceTimestamp
|
let timestamp = self.referenceTimestamp
|
||||||
|
|
||||||
let timestamp1 = timestamp + 120
|
let timestamp1 = timestamp + 120
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
||||||
let timestamp2 = timestamp + 3660
|
let timestamp2 = timestamp + 3660
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: nil, notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: nil, notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp3 = timestamp + 3200
|
let timestamp3 = timestamp + 3200
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp4 = timestamp + 3000
|
let timestamp4 = timestamp + 3000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp5 = timestamp + 1000
|
let timestamp5 = timestamp + 1000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer5), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer5), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
@ -784,17 +784,17 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
let timestamp = self.referenceTimestamp
|
let timestamp = self.referenceTimestamp
|
||||||
|
|
||||||
let timestamp1 = timestamp + 120
|
let timestamp1 = timestamp + 120
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
||||||
let timestamp2 = timestamp + 3660
|
let timestamp2 = timestamp + 3660
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp3 = timestamp + 3200
|
let timestamp3 = timestamp + 3200
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp4 = timestamp + 3000
|
let timestamp4 = timestamp + 3000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||||
if let chatNodes = self.chatNodes {
|
if let chatNodes = self.chatNodes {
|
||||||
|
@ -371,24 +371,24 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
let timestamp = self.referenceTimestamp
|
let timestamp = self.referenceTimestamp
|
||||||
|
|
||||||
let timestamp1 = timestamp + 120
|
let timestamp1 = timestamp + 120
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
||||||
let timestamp2 = timestamp + 3660
|
let timestamp2 = timestamp + 3660
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: nil, notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer2), combinedReadState: nil, notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp3 = timestamp + 3200
|
let timestamp3 = timestamp + 3200
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer3), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp4 = timestamp + 3000
|
let timestamp4 = timestamp + 3000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp5 = timestamp + 1000
|
let timestamp5 = timestamp + 1000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer5), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer5), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer7.id, namespace: 0, id: 0), timestamp: timestamp - 420)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer7.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 420, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer7), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer7.id, namespace: 0, id: 0), timestamp: timestamp - 420)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer7.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 420, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer7), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
@ -97,7 +97,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
|||||||
return super.visualNavigationInsetHeight + self.additionalHeight
|
return super.visualNavigationInsetHeight + self.additionalHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
private var additionalHeight: CGFloat {
|
public var additionalHeight: CGFloat {
|
||||||
var height: CGFloat = 0.0
|
var height: CGFloat = 0.0
|
||||||
if let _ = self.mediaAccessoryPanel {
|
if let _ = self.mediaAccessoryPanel {
|
||||||
height += MediaNavigationAccessoryHeaderNode.minimizedHeight
|
height += MediaNavigationAccessoryHeaderNode.minimizedHeight
|
||||||
|
@ -1330,7 +1330,7 @@ public final class AccountViewTracker {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func tailChatListView(groupId: PeerGroupId, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)? = nil, count: Int) -> Signal<(ChatListView, ViewUpdateType), NoError> {
|
public func tailChatListView(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate? = nil, count: Int) -> Signal<(ChatListView, ViewUpdateType), NoError> {
|
||||||
if let account = self.account {
|
if let account = self.account {
|
||||||
return self.wrappedChatListView(signal: account.postbox.tailChatListView(groupId: groupId, filterPredicate: filterPredicate, count: count, summaryComponents: ChatListEntrySummaryComponents(tagSummary: ChatListEntryMessageTagSummaryComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud))))
|
return self.wrappedChatListView(signal: account.postbox.tailChatListView(groupId: groupId, filterPredicate: filterPredicate, count: count, summaryComponents: ChatListEntrySummaryComponents(tagSummary: ChatListEntryMessageTagSummaryComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud))))
|
||||||
} else {
|
} else {
|
||||||
@ -1338,7 +1338,7 @@ public final class AccountViewTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func aroundChatListView(groupId: PeerGroupId, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)? = nil, index: ChatListIndex, count: Int) -> Signal<(ChatListView, ViewUpdateType), NoError> {
|
public func aroundChatListView(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate? = nil, index: ChatListIndex, count: Int) -> Signal<(ChatListView, ViewUpdateType), NoError> {
|
||||||
if let account = self.account {
|
if let account = self.account {
|
||||||
return self.wrappedChatListView(signal: account.postbox.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: index, count: count, summaryComponents: ChatListEntrySummaryComponents(tagSummary: ChatListEntryMessageTagSummaryComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud))))
|
return self.wrappedChatListView(signal: account.postbox.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: index, count: count, summaryComponents: ChatListEntrySummaryComponents(tagSummary: ChatListEntryMessageTagSummaryComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud))))
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,7 +161,7 @@ public func clearPeerUnseenPersonalMessagesInteractively(account: Account, peerI
|
|||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
}
|
}
|
||||||
|
|
||||||
public func markAllChatsAsReadInteractively(transaction: Transaction, viewTracker: AccountViewTracker, groupId: PeerGroupId, filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)?) {
|
public func markAllChatsAsReadInteractively(transaction: Transaction, viewTracker: AccountViewTracker, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?) {
|
||||||
for peerId in transaction.getUnreadChatListPeerIds(groupId: groupId, filterPredicate: filterPredicate) {
|
for peerId in transaction.getUnreadChatListPeerIds(groupId: groupId, filterPredicate: filterPredicate) {
|
||||||
togglePeerUnreadMarkInteractively(transaction: transaction, viewTracker: viewTracker, peerId: peerId, setToValue: false)
|
togglePeerUnreadMarkInteractively(transaction: transaction, viewTracker: viewTracker, peerId: peerId, setToValue: false)
|
||||||
}
|
}
|
||||||
|
@ -168,10 +168,10 @@ private func requestGraph(network: Network, datacenterId: Int32, token: String)
|
|||||||
signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil)
|
signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil)
|
||||||
|> castError(MTRpcError.self)
|
|> castError(MTRpcError.self)
|
||||||
|> mapToSignal { worker in
|
|> mapToSignal { worker in
|
||||||
return worker.request(Api.functions.stats.loadAsyncGraph(token: token))
|
return worker.request(Api.functions.stats.loadAsyncGraph(flags: 0, token: token, x: nil))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
signal = network.request(Api.functions.stats.loadAsyncGraph(token: token))
|
signal = network.request(Api.functions.stats.loadAsyncGraph(flags: 0, token: token, x: nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
return signal
|
return signal
|
||||||
@ -364,7 +364,7 @@ public final class ChannelStatsContext {
|
|||||||
extension ChannelStatsGraph {
|
extension ChannelStatsGraph {
|
||||||
init(apiStatsGraph: Api.StatsGraph) {
|
init(apiStatsGraph: Api.StatsGraph) {
|
||||||
switch apiStatsGraph {
|
switch apiStatsGraph {
|
||||||
case let .statsGraph(json):
|
case let .statsGraph(_, json, _):
|
||||||
if case let .dataJSON(string) = json {
|
if case let .dataJSON(string) = json {
|
||||||
self = .Loaded(data: string)
|
self = .Loaded(data: string)
|
||||||
} else {
|
} else {
|
||||||
@ -396,14 +396,14 @@ extension ChannelStatsValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ChannelStatsNamedValue {
|
/*extension ChannelStatsNamedValue {
|
||||||
init(apiStatsRowAbsValueAndPrev: Api.StatsRowAbsValueAndPrev) {
|
init(apiStatsRowAbsValueAndPrev: Api.StatsRowAbsValueAndPrev) {
|
||||||
switch apiStatsRowAbsValueAndPrev {
|
switch apiStatsRowAbsValueAndPrev {
|
||||||
case let .statsRowAbsValueAndPrev(id, title, shortTitle, values):
|
case let .statsRowAbsValueAndPrev(id, title, shortTitle, values):
|
||||||
self = ChannelStatsNamedValue(id: id, title: title, shortTitle: shortTitle, value: ChannelStatsValue(apiStatsAbsValueAndPrev: values))
|
self = ChannelStatsNamedValue(id: id, title: title, shortTitle: shortTitle, value: ChannelStatsValue(apiStatsAbsValueAndPrev: values))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
extension ChannelStatsPercentValue {
|
extension ChannelStatsPercentValue {
|
||||||
init(apiPercentValue: Api.StatsPercentValue) {
|
init(apiPercentValue: Api.StatsPercentValue) {
|
||||||
@ -416,9 +416,10 @@ extension ChannelStatsPercentValue {
|
|||||||
|
|
||||||
extension ChannelStats {
|
extension ChannelStats {
|
||||||
convenience init(apiBroadcastStats: Api.stats.BroadcastStats) {
|
convenience init(apiBroadcastStats: Api.stats.BroadcastStats) {
|
||||||
switch apiBroadcastStats {
|
preconditionFailure()
|
||||||
|
/*switch apiBroadcastStats {
|
||||||
case let .broadcastStats(period, followers, viewsPerPost, sharesPerPost, enabledNotifications, viewsBySource, newFollowersBySource, languages, growthGraph, followersGraph, muteGraph, topHoursGraph, interactionsGraph):
|
case let .broadcastStats(period, followers, viewsPerPost, sharesPerPost, enabledNotifications, viewsBySource, newFollowersBySource, languages, growthGraph, followersGraph, muteGraph, topHoursGraph, interactionsGraph):
|
||||||
self.init(period: ChannelStatsDateRange(apiStatsDateRangeDays: period), followers: ChannelStatsValue(apiStatsAbsValueAndPrev: followers), viewsPerPost: ChannelStatsValue(apiStatsAbsValueAndPrev: viewsPerPost), sharesPerPost: ChannelStatsValue(apiStatsAbsValueAndPrev: sharesPerPost), enabledNotifications: ChannelStatsPercentValue(apiPercentValue: enabledNotifications), viewsBySource: viewsBySource.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, newFollowersBySource: newFollowersBySource.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, languages: languages.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, growthGraph: ChannelStatsGraph(apiStatsGraph: growthGraph), followersGraph: ChannelStatsGraph(apiStatsGraph: followersGraph), muteGraph: ChannelStatsGraph(apiStatsGraph: muteGraph), topHoursGraph: ChannelStatsGraph(apiStatsGraph: topHoursGraph), interactionsGraph: ChannelStatsGraph(apiStatsGraph: interactionsGraph))
|
self.init(period: ChannelStatsDateRange(apiStatsDateRangeDays: period), followers: ChannelStatsValue(apiStatsAbsValueAndPrev: followers), viewsPerPost: ChannelStatsValue(apiStatsAbsValueAndPrev: viewsPerPost), sharesPerPost: ChannelStatsValue(apiStatsAbsValueAndPrev: sharesPerPost), enabledNotifications: ChannelStatsPercentValue(apiPercentValue: enabledNotifications), viewsBySource: viewsBySource.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, newFollowersBySource: newFollowersBySource.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, languages: languages.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, growthGraph: ChannelStatsGraph(apiStatsGraph: growthGraph), followersGraph: ChannelStatsGraph(apiStatsGraph: followersGraph), muteGraph: ChannelStatsGraph(apiStatsGraph: muteGraph), topHoursGraph: ChannelStatsGraph(apiStatsGraph: topHoursGraph), interactionsGraph: ChannelStatsGraph(apiStatsGraph: interactionsGraph))
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,8 +270,6 @@ private func requestChatListFilters(postbox: Postbox, network: Network) -> Signa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func managedChatListFilters(postbox: Postbox, network: Network) -> Signal<Never, NoError> {
|
func managedChatListFilters(postbox: Postbox, network: Network) -> Signal<Never, NoError> {
|
||||||
return .complete()
|
|
||||||
|
|
||||||
return requestChatListFilters(postbox: postbox, network: network)
|
return requestChatListFilters(postbox: postbox, network: network)
|
||||||
|> `catch` { _ -> Signal<[ChatListFilter], NoError> in
|
|> `catch` { _ -> Signal<[ChatListFilter], NoError> in
|
||||||
return .complete()
|
return .complete()
|
||||||
|
@ -6,6 +6,7 @@ import SyncCore
|
|||||||
private final class ManagedChatListHolesState {
|
private final class ManagedChatListHolesState {
|
||||||
private var holeDisposables: [ChatListHolesEntry: Disposable] = [:]
|
private var holeDisposables: [ChatListHolesEntry: Disposable] = [:]
|
||||||
private var additionalLatestHoleDisposable: (ChatListHole, Disposable)?
|
private var additionalLatestHoleDisposable: (ChatListHole, Disposable)?
|
||||||
|
private var additionalLatestArchiveHoleDisposable: (ChatListHole, Disposable)?
|
||||||
|
|
||||||
func clearDisposables() -> [Disposable] {
|
func clearDisposables() -> [Disposable] {
|
||||||
let disposables = Array(self.holeDisposables.values)
|
let disposables = Array(self.holeDisposables.values)
|
||||||
@ -13,7 +14,7 @@ private final class ManagedChatListHolesState {
|
|||||||
return disposables
|
return disposables
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(entries: Set<ChatListHolesEntry>, additionalLatestHole: ChatListHole?) -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable], addedAdditionalLatestHole: (ChatListHole, MetaDisposable)?) {
|
func update(entries: Set<ChatListHolesEntry>, additionalLatestHole: ChatListHole?, additionalLatestArchiveHole: ChatListHole?) -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable], addedAdditionalLatestHole: (ChatListHole, MetaDisposable)?, addedAdditionalLatestArchiveHole: (ChatListHole, MetaDisposable)?) {
|
||||||
var removed: [Disposable] = []
|
var removed: [Disposable] = []
|
||||||
var added: [ChatListHolesEntry: MetaDisposable] = [:]
|
var added: [ChatListHolesEntry: MetaDisposable] = [:]
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ private final class ManagedChatListHolesState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var addedAdditionalLatestHole: (ChatListHole, MetaDisposable)?
|
var addedAdditionalLatestHole: (ChatListHole, MetaDisposable)?
|
||||||
|
var addedAdditionalLatestArchiveHole: (ChatListHole, MetaDisposable)?
|
||||||
if self.holeDisposables.isEmpty {
|
if self.holeDisposables.isEmpty {
|
||||||
if self.additionalLatestHoleDisposable?.0 != additionalLatestHole {
|
if self.additionalLatestHoleDisposable?.0 != additionalLatestHole {
|
||||||
if let (_, disposable) = self.additionalLatestHoleDisposable {
|
if let (_, disposable) = self.additionalLatestHoleDisposable {
|
||||||
@ -44,9 +46,22 @@ private final class ManagedChatListHolesState {
|
|||||||
addedAdditionalLatestHole = (additionalLatestHole, disposable)
|
addedAdditionalLatestHole = (additionalLatestHole, disposable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if additionalLatestHole == nil {
|
||||||
|
if self.additionalLatestArchiveHoleDisposable?.0 != additionalLatestArchiveHole {
|
||||||
|
if let (_, disposable) = self.additionalLatestArchiveHoleDisposable {
|
||||||
|
removed.append(disposable)
|
||||||
|
}
|
||||||
|
if let additionalLatestArchiveHole = additionalLatestArchiveHole {
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
self.additionalLatestArchiveHoleDisposable = (additionalLatestArchiveHole, disposable)
|
||||||
|
addedAdditionalLatestArchiveHole = (additionalLatestArchiveHole, disposable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (removed, added, addedAdditionalLatestHole)
|
return (removed, added, addedAdditionalLatestHole, addedAdditionalLatestArchiveHole)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,20 +70,25 @@ func managedChatListHoles(network: Network, postbox: Postbox, accountPeerId: Pee
|
|||||||
let state = Atomic(value: ManagedChatListHolesState())
|
let state = Atomic(value: ManagedChatListHolesState())
|
||||||
|
|
||||||
let topRootHoleKey: PostboxViewKey = .allChatListHoles(.root)
|
let topRootHoleKey: PostboxViewKey = .allChatListHoles(.root)
|
||||||
|
let topArchiveHoleKey: PostboxViewKey = .allChatListHoles(Namespaces.PeerGroup.archive)
|
||||||
let filtersKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.chatListFilters]))
|
let filtersKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.chatListFilters]))
|
||||||
let combinedView = postbox.combinedView(keys: [topRootHoleKey, filtersKey])
|
let combinedView = postbox.combinedView(keys: [topRootHoleKey, topArchiveHoleKey, filtersKey])
|
||||||
|
|
||||||
let disposable = combineLatest(postbox.chatListHolesView(), combinedView).start(next: { view, combinedView in
|
let disposable = combineLatest(postbox.chatListHolesView(), combinedView).start(next: { view, combinedView in
|
||||||
var additionalLatestHole: ChatListHole?
|
var additionalLatestHole: ChatListHole?
|
||||||
|
var additionalLatestArchiveHole: ChatListHole?
|
||||||
|
|
||||||
if let preferencesView = combinedView.views[filtersKey] as? PreferencesView, let filtersState = preferencesView.values[PreferencesKeys.chatListFilters] as? ChatListFiltersState, !filtersState.filters.isEmpty {
|
if let preferencesView = combinedView.views[filtersKey] as? PreferencesView, let filtersState = preferencesView.values[PreferencesKeys.chatListFilters] as? ChatListFiltersState, !filtersState.filters.isEmpty {
|
||||||
if let topRootHole = combinedView.views[topRootHoleKey] as? AllChatListHolesView {
|
if let topRootHole = combinedView.views[topRootHoleKey] as? AllChatListHolesView {
|
||||||
additionalLatestHole = topRootHole.latestHole
|
additionalLatestHole = topRootHole.latestHole
|
||||||
}
|
}
|
||||||
|
if let topArchiveHole = combinedView.views[topArchiveHoleKey] as? AllChatListHolesView {
|
||||||
|
additionalLatestArchiveHole = topArchiveHole.latestHole
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (removed, added, addedAdditionalLatestHole) = state.with { state in
|
let (removed, added, addedAdditionalLatestHole, addedAdditionalLatestArchiveHole) = state.with { state in
|
||||||
return state.update(entries: view.entries, additionalLatestHole: additionalLatestHole)
|
return state.update(entries: view.entries, additionalLatestHole: additionalLatestHole, additionalLatestArchiveHole: additionalLatestArchiveHole)
|
||||||
}
|
}
|
||||||
|
|
||||||
for disposable in removed {
|
for disposable in removed {
|
||||||
@ -82,6 +102,10 @@ func managedChatListHoles(network: Network, postbox: Postbox, accountPeerId: Pee
|
|||||||
if let (hole, disposable) = addedAdditionalLatestHole {
|
if let (hole, disposable) = addedAdditionalLatestHole {
|
||||||
disposable.set(fetchChatListHole(postbox: postbox, network: network, accountPeerId: accountPeerId, groupId: .root, hole: hole).start())
|
disposable.set(fetchChatListHole(postbox: postbox, network: network, accountPeerId: accountPeerId, groupId: .root, hole: hole).start())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let (hole, disposable) = addedAdditionalLatestArchiveHole {
|
||||||
|
disposable.set(fetchChatListHole(postbox: postbox, network: network, accountPeerId: accountPeerId, groupId: .root, hole: hole).start())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return ActionDisposable {
|
return ActionDisposable {
|
||||||
|
@ -78,7 +78,7 @@ private enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
public func item(context: AccountContext, interaction: ChatListNodeInteraction) -> ListViewItem {
|
public func item(context: AccountContext, interaction: ChatListNodeInteraction) -> ListViewItem {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(message, peer, readState, presentationData):
|
case let .message(message, peer, readState, presentationData):
|
||||||
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: true, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: true, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,8 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
let placeholder: String
|
let placeholder: String
|
||||||
var includeChatList = false
|
var includeChatList = false
|
||||||
switch mode {
|
switch mode {
|
||||||
case let .peerSelection(_, searchGroups):
|
case let .peerSelection(_, searchGroups, searchChannels):
|
||||||
includeChatList = searchGroups
|
includeChatList = searchGroups || searchChannels
|
||||||
if searchGroups {
|
if searchGroups {
|
||||||
placeholder = self.presentationData.strings.Contacts_SearchUsersAndGroupsLabel
|
placeholder = self.presentationData.strings.Contacts_SearchUsersAndGroupsLabel
|
||||||
} else {
|
} else {
|
||||||
@ -108,11 +108,13 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
var searchChatList = false
|
var searchChatList = false
|
||||||
var searchGroups = false
|
var searchGroups = false
|
||||||
|
var searchChannels = false
|
||||||
if case let .peerSelection(peerSelection) = mode {
|
if case let .peerSelection(peerSelection) = mode {
|
||||||
searchChatList = peerSelection.searchChatList
|
searchChatList = peerSelection.searchChatList
|
||||||
searchGroups = peerSelection.searchGroups
|
searchGroups = peerSelection.searchGroups
|
||||||
|
searchChannels = peerSelection.searchChannels
|
||||||
}
|
}
|
||||||
let searchResultsNode = ContactListNode(context: context, presentation: .single(.search(signal: searchText.get(), searchChatList: searchChatList, searchDeviceContacts: false, searchGroups: searchGroups)), filters: filters, selectionState: selectionState)
|
let searchResultsNode = ContactListNode(context: context, presentation: .single(.search(signal: searchText.get(), searchChatList: searchChatList, searchDeviceContacts: false, searchGroups: searchGroups, searchChannels: searchChannels)), filters: filters, selectionState: selectionState)
|
||||||
searchResultsNode.openPeer = { peer in
|
searchResultsNode.openPeer = { peer in
|
||||||
self?.tokenListNode.setText("")
|
self?.tokenListNode.setText("")
|
||||||
self?.openPeer?(peer)
|
self?.openPeer?(peer)
|
||||||
|
@ -65,7 +65,9 @@ struct VideoConversionConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func with(appConfiguration: AppConfiguration) -> VideoConversionConfiguration {
|
static func with(appConfiguration: AppConfiguration) -> VideoConversionConfiguration {
|
||||||
|
#if DEBUG
|
||||||
return VideoConversionConfiguration(remuxToFMp4: true)
|
return VideoConversionConfiguration(remuxToFMp4: true)
|
||||||
|
#endif
|
||||||
|
|
||||||
if let data = appConfiguration.data, let conversion = data["video_conversion"] as? [String: Any] {
|
if let data = appConfiguration.data, let conversion = data["video_conversion"] as? [String: Any] {
|
||||||
let remuxToFMp4 = conversion["remux_fmp4"] as? Bool ?? VideoConversionConfiguration.defaultValue.remuxToFMp4
|
let remuxToFMp4 = conversion["remux_fmp4"] as? Bool ?? VideoConversionConfiguration.defaultValue.remuxToFMp4
|
||||||
|
@ -3274,7 +3274,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
}))
|
}))
|
||||||
contactsController.navigationPresentation = .modal
|
contactsController.navigationPresentation = .modal
|
||||||
} else {
|
} else {
|
||||||
contactsController = strongSelf.context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: strongSelf.context, mode: .peerSelection(searchChatList: false, searchGroups: false), options: options, filters: [.excludeSelf, .disable(recentIds)]))
|
contactsController = strongSelf.context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: strongSelf.context, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: options, filters: [.excludeSelf, .disable(recentIds)]))
|
||||||
contactsController.navigationPresentation = .modal
|
contactsController.navigationPresentation = .modal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +214,9 @@ end:
|
|||||||
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
|
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("Remuxed video into %s\n", outPath.UTF8String);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user