mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Open stories from search
This commit is contained in:
parent
052311553e
commit
9a50913b57
@ -2347,7 +2347,9 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
self?.controller?.present(c, in: .window(.root), with: a)
|
||||
}, presentInGlobalOverlay: { [weak self] c, a in
|
||||
self?.controller?.presentInGlobalOverlay(c, with: a)
|
||||
}, navigationController: navigationController)
|
||||
}, navigationController: navigationController, parentController: { [weak self] in
|
||||
return self?.controller
|
||||
})
|
||||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, contentNode: contentNode, cancel: { [weak self] in
|
||||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
|
@ -34,6 +34,8 @@ import TelegramAnimatedStickerNode
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import PremiumUI
|
||||
import AvatarNode
|
||||
import StoryContainerScreen
|
||||
|
||||
private enum ChatListTokenId: Int32 {
|
||||
case archive
|
||||
@ -57,8 +59,9 @@ final class ChatListSearchInteraction {
|
||||
let present: (ViewController, Any?) -> Void
|
||||
let dismissInput: () -> Void
|
||||
let getSelectedMessageIds: () -> Set<EngineMessage.Id>?
|
||||
let openStories: ((PeerId, ASDisplayNode) -> Void)?
|
||||
|
||||
init(openPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?) -> Void, openMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (EngineMessage.Id, Bool) -> Void, messageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void), mediaMessageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set<EngineMessage.Id>?) {
|
||||
init(openPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?) -> Void, openMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (EngineMessage.Id, Bool) -> Void, messageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void), mediaMessageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set<EngineMessage.Id>?, openStories: ((PeerId, ASDisplayNode) -> Void)?) {
|
||||
self.openPeer = openPeer
|
||||
self.openDisabledPeer = openDisabledPeer
|
||||
self.openMessage = openMessage
|
||||
@ -72,6 +75,7 @@ final class ChatListSearchInteraction {
|
||||
self.present = present
|
||||
self.dismissInput = dismissInput
|
||||
self.getSelectedMessageIds = getSelectedMessageIds
|
||||
self.openStories = openStories
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +144,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
public init(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?) -> Void, openRecentPeerOptions: @escaping (EnginePeer) -> Void, openMessage originalOpenMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?) {
|
||||
private let sharedOpenStoryDisposable = MetaDisposable()
|
||||
|
||||
public init(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?) -> Void, openRecentPeerOptions: @escaping (EnginePeer) -> Void, openMessage originalOpenMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?, parentController: @escaping () -> ViewController?) {
|
||||
var initialFilter = initialFilter
|
||||
if case .chats = initialFilter, case .forum = location {
|
||||
initialFilter = .topics
|
||||
@ -258,6 +264,20 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, openStories: { [weak self] peerId, sourceNode in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard let parentController = parentController() else {
|
||||
return
|
||||
}
|
||||
StoryContainerScreen.openPeerStories(
|
||||
context: context,
|
||||
peerId: peerId,
|
||||
parentController: parentController,
|
||||
avatarNode: sourceNode as? AvatarNode,
|
||||
sharedProgressDisposable: self.sharedOpenStoryDisposable
|
||||
)
|
||||
})
|
||||
self.paneContainerNode.interaction = interaction
|
||||
|
||||
@ -500,6 +520,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
self.presentationDataDisposable?.dispose()
|
||||
self.suggestedFiltersDisposable.dispose()
|
||||
self.shareStatusDisposable?.dispose()
|
||||
self.sharedOpenStoryDisposable.dispose()
|
||||
|
||||
self.copyProtectionTooltipController?.dismiss()
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import Postbox
|
||||
import FetchManagerImpl
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import AvatarNode
|
||||
|
||||
private enum ChatListRecentEntryStableId: Hashable {
|
||||
case topPeers
|
||||
@ -38,13 +39,13 @@ private enum ChatListRecentEntryStableId: Hashable {
|
||||
|
||||
private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
case topPeers([EnginePeer], PresentationTheme, PresentationStrings)
|
||||
case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, EngineGlobalNotificationSettings)
|
||||
case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, EngineGlobalNotificationSettings, PeerStoryStats?)
|
||||
|
||||
var stableId: ChatListRecentEntryStableId {
|
||||
switch self {
|
||||
case .topPeers:
|
||||
return .topPeers
|
||||
case let .peer(_, peer, _, _, _, _, _, _):
|
||||
case let .peer(_, peer, _, _, _, _, _, _, _):
|
||||
return .peerId(peer.peer.peerId)
|
||||
}
|
||||
}
|
||||
@ -66,8 +67,8 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .peer(lhsIndex, lhsPeer, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsGlobalNotificationsSettings):
|
||||
if case let .peer(rhsIndex, rhsPeer, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsGlobalNotificationsSettings) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings && lhsTimeFormat == rhsTimeFormat && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsGlobalNotificationsSettings == rhsGlobalNotificationsSettings {
|
||||
case let .peer(lhsIndex, lhsPeer, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsGlobalNotificationsSettings, lhsStoryStats):
|
||||
if case let .peer(rhsIndex, rhsPeer, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsGlobalNotificationsSettings, rhsStoryStats) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings && lhsTimeFormat == rhsTimeFormat && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsGlobalNotificationsSettings == rhsGlobalNotificationsSettings && lhsStoryStats == rhsStoryStats {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -79,17 +80,17 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
switch lhs {
|
||||
case .topPeers:
|
||||
return true
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _):
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .topPeers:
|
||||
return false
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _):
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex <= rhsIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func item(context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer, Int64?) -> Void, disabledPeerSelected: @escaping (EnginePeer, Int64?) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> ListViewItem {
|
||||
func item(context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer, Int64?) -> Void, disabledPeerSelected: @escaping (EnginePeer, Int64?) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, openStories: @escaping (EnginePeer.Id, AvatarNode) -> Void) -> ListViewItem {
|
||||
switch self {
|
||||
case let .topPeers(peers, theme, strings):
|
||||
return ChatListRecentPeersListItem(theme: theme, strings: strings, context: context, peers: peers, peerSelected: { peer in
|
||||
@ -101,7 +102,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
gesture?.cancel()
|
||||
}
|
||||
})
|
||||
case let .peer(_, peer, theme, strings, timeFormat, nameSortOrder, nameDisplayOrder, globalNotificationSettings):
|
||||
case let .peer(_, peer, theme, strings, timeFormat, nameSortOrder, nameDisplayOrder, globalNotificationSettings, storyStats):
|
||||
let primaryPeer: EnginePeer
|
||||
var chatPeer: EnginePeer?
|
||||
let maybeChatPeer = EnginePeer(peer.peer.peers[peer.peer.peerId]!)
|
||||
@ -248,7 +249,18 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
}
|
||||
},
|
||||
animationCache: animationCache,
|
||||
animationRenderer: animationRenderer
|
||||
animationRenderer: animationRenderer,
|
||||
storyStats: storyStats.flatMap { stats in
|
||||
return (stats.totalCount, unseen: stats.unseenCount, stats.hasUnseenCloseFriends)
|
||||
},
|
||||
openStories: { itemPeer, sourceNode in
|
||||
guard case let .peer(_, chatPeer) = itemPeer, let peer = chatPeer else {
|
||||
return
|
||||
}
|
||||
if let sourceNode = sourceNode as? ContactsPeerItemNode {
|
||||
openStories(peer.id, sourceNode.avatarNode)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -480,7 +492,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
public func item(context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, key: ChatListSearchPaneKey, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?, openClearRecentlyDownloaded: @escaping () -> Void, toggleAllPaused: @escaping () -> Void) -> ListViewItem {
|
||||
public func item(context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, key: ChatListSearchPaneKey, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?, openClearRecentlyDownloaded: @escaping () -> Void, toggleAllPaused: @escaping () -> Void, openStories: @escaping (EnginePeer.Id, AvatarNode) -> Void) -> ListViewItem {
|
||||
switch self {
|
||||
case let .topic(peer, threadInfo, _, theme, strings, expandType):
|
||||
let actionTitle: String?
|
||||
@ -576,6 +588,13 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
}
|
||||
}, arrowAction: nil, animationCache: interaction.animationCache, animationRenderer: interaction.animationRenderer, storyStats: storyStats.flatMap { stats in
|
||||
return (stats.totalCount, stats.unseenCount, stats.hasUnseenCloseFriends)
|
||||
}, openStories: { itemPeer, sourceNode in
|
||||
guard case let .peer(_, chatPeer) = itemPeer, let peer = chatPeer else {
|
||||
return
|
||||
}
|
||||
if let sourceNode = sourceNode as? ContactsPeerItemNode {
|
||||
openStories(peer.id, sourceNode.avatarNode)
|
||||
}
|
||||
})
|
||||
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType, storyStats):
|
||||
let primaryPeer: EnginePeer
|
||||
@ -669,6 +688,13 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
}
|
||||
}, arrowAction: nil, animationCache: interaction.animationCache, animationRenderer: interaction.animationRenderer, storyStats: storyStats.flatMap { stats in
|
||||
return (stats.totalCount, stats.unseenCount, stats.hasUnseenCloseFriends)
|
||||
}, openStories: { itemPeer, sourceNode in
|
||||
guard case let .peer(_, chatPeer) = itemPeer, let peer = chatPeer else {
|
||||
return
|
||||
}
|
||||
if let sourceNode = sourceNode as? ContactsPeerItemNode {
|
||||
openStories(peer.id, sourceNode.avatarNode)
|
||||
}
|
||||
})
|
||||
case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType, storyStats):
|
||||
var enabled = true
|
||||
@ -730,6 +756,13 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
}
|
||||
}, animationCache: interaction.animationCache, animationRenderer: interaction.animationRenderer, storyStats: storyStats.flatMap { stats in
|
||||
return (stats.totalCount, stats.unseenCount, stats.hasUnseenCloseFriends)
|
||||
}, openStories: { itemPeer, sourceNode in
|
||||
guard case let .peer(_, chatPeer) = itemPeer, let peer = chatPeer else {
|
||||
return
|
||||
}
|
||||
if let sourceNode = sourceNode as? ContactsPeerItemNode {
|
||||
openStories(peer.id, sourceNode.avatarNode)
|
||||
}
|
||||
})
|
||||
case let .message(message, peer, readState, threadInfo, presentationData, _, selected, displayCustomHeader, orderingKey, _, _, allPaused, storyStats):
|
||||
let header: ChatListSearchItemHeader
|
||||
@ -855,22 +888,22 @@ public struct ChatListSearchContainerTransition {
|
||||
}
|
||||
}
|
||||
|
||||
private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ChatListRecentEntry], to toEntries: [ChatListRecentEntry], context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer, Int64?) -> Void, disabledPeerSelected: @escaping (EnginePeer, Int64?) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> ChatListSearchContainerRecentTransition {
|
||||
private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ChatListRecentEntry], to toEntries: [ChatListRecentEntry], context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer, Int64?) -> Void, disabledPeerSelected: @escaping (EnginePeer, Int64?) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, openStories: @escaping (EnginePeer.Id, AvatarNode) -> Void) -> ChatListSearchContainerRecentTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, filter: filter, peerSelected: peerSelected, disabledPeerSelected: disabledPeerSelected, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, deletePeer: deletePeer, animationCache: animationCache, animationRenderer: animationRenderer), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, filter: filter, peerSelected: peerSelected, disabledPeerSelected: disabledPeerSelected, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, deletePeer: deletePeer, animationCache: animationCache, animationRenderer: animationRenderer), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, filter: filter, peerSelected: peerSelected, disabledPeerSelected: disabledPeerSelected, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, deletePeer: deletePeer, animationCache: animationCache, animationRenderer: animationRenderer, openStories: openStories), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, filter: filter, peerSelected: peerSelected, disabledPeerSelected: disabledPeerSelected, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, deletePeer: deletePeer, animationCache: animationCache, animationRenderer: animationRenderer, openStories: openStories), directionHint: nil) }
|
||||
|
||||
return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates)
|
||||
}
|
||||
|
||||
public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, isEmpty: Bool, isLoading: Bool, animated: Bool, context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, key: ChatListSearchPaneKey, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?, openClearRecentlyDownloaded: @escaping () -> Void, toggleAllPaused: @escaping () -> Void) -> ChatListSearchContainerTransition {
|
||||
public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, isEmpty: Bool, isLoading: Bool, animated: Bool, context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, key: ChatListSearchPaneKey, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?, openClearRecentlyDownloaded: @escaping () -> Void, toggleAllPaused: @escaping () -> Void, openStories: @escaping (EnginePeer.Id, AvatarNode) -> Void) -> ChatListSearchContainerTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, requestPeerType: requestPeerType, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, requestPeerType: requestPeerType, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, requestPeerType: requestPeerType, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused, openStories: openStories), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, requestPeerType: requestPeerType, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused, openStories: openStories), directionHint: nil) }
|
||||
|
||||
return ChatListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, displayingResults: displayingResults, isEmpty: isEmpty, isLoading: isLoading, query: searchQuery, animated: animated)
|
||||
}
|
||||
@ -2185,7 +2218,16 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
}, openPremiumIntro: {
|
||||
}, openChatFolderUpdates: {
|
||||
}, hideChatFolderUpdates: {
|
||||
}, openStories: { _, _ in
|
||||
}, openStories: { [weak self] subject, sourceNode in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard case let .peer(id) = subject else {
|
||||
return
|
||||
}
|
||||
if let sourceNode = sourceNode as? ChatListItemNode {
|
||||
self.interaction.openStories?(id, sourceNode.avatarNode)
|
||||
}
|
||||
})
|
||||
chatListInteraction.isSearchMode = true
|
||||
|
||||
@ -2293,7 +2335,58 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
})
|
||||
|
||||
|
||||
self.searchDisposable.set((foundItems
|
||||
self.searchDisposable.set((foundItems |> mapToSignal { items -> Signal<([ChatListSearchEntry], Bool)?, NoError> in
|
||||
guard let (items, isSearching) = items else {
|
||||
return .single(nil)
|
||||
}
|
||||
var storyStatsIds: [EnginePeer.Id] = []
|
||||
for item in items {
|
||||
switch item {
|
||||
case let .recentlySearchedPeer(peer, _, _, _, _, _, _, _, _):
|
||||
if case .user = peer {
|
||||
storyStatsIds.append(peer.id)
|
||||
}
|
||||
case let .localPeer(peer, _, _, _, _, _, _, _, _, _):
|
||||
if case .user = peer {
|
||||
storyStatsIds.append(peer.id)
|
||||
}
|
||||
case let .globalPeer(foundPeer, _, _, _, _, _, _, _, _):
|
||||
if foundPeer.peer is TelegramUser {
|
||||
storyStatsIds.append(foundPeer.peer.id)
|
||||
}
|
||||
case let .message(_, peer, _, _, _, _, _, _, _, _, _, _, _):
|
||||
if let peer = peer.peer, case .user = peer {
|
||||
storyStatsIds.append(peer.id)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return context.engine.data.subscribe(
|
||||
EngineDataMap(
|
||||
storyStatsIds.map(TelegramEngine.EngineData.Item.Peer.StoryStats.init(id:))
|
||||
)
|
||||
)
|
||||
|> map { stats -> ([ChatListSearchEntry], Bool)? in
|
||||
var mappedItems = items
|
||||
for i in 0 ..< mappedItems.count {
|
||||
switch mappedItems[i] {
|
||||
case let .recentlySearchedPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, _):
|
||||
mappedItems[i] = .recentlySearchedPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, stats[peer.id] ?? nil)
|
||||
case let .localPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _):
|
||||
mappedItems[i] = .localPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.id] ?? nil)
|
||||
case let .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _):
|
||||
mappedItems[i] = .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.peer.id] ?? nil)
|
||||
case let .message(message, peer, combinedPeerReadState, threadInfo, presentationData, totalCount, selected, displayCustomHeader, key, resourceId, section, allPaused, _):
|
||||
mappedItems[i] = .message(message, peer, combinedPeerReadState, threadInfo, presentationData, totalCount, selected, displayCustomHeader, key, resourceId, section, allPaused, stats[peer.peerId] ?? nil)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
return (mappedItems, isSearching)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] foundItems in
|
||||
if let strongSelf = self {
|
||||
let previousSelectedMessageIds = previousSelectedMessages.swap(strongSelf.selectedMessages)
|
||||
@ -2418,6 +2511,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
strongSelf.context.fetchManager.toggleInteractiveFetchPaused(resourceId: entry.resourceReference.resource.id.stringRepresentation, isPaused: !allPaused)
|
||||
}
|
||||
})
|
||||
}, openStories: { peerId, avatarNode in
|
||||
strongSelf.interaction.openStories?(peerId, avatarNode)
|
||||
})
|
||||
strongSelf.currentEntries = newEntries
|
||||
if strongSelf.key == .downloads {
|
||||
@ -2451,11 +2546,28 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
|
||||
var recentItems = combineLatest(
|
||||
hasRecentPeers,
|
||||
fixedRecentlySearchedPeers,
|
||||
fixedRecentlySearchedPeers |> mapToSignal { peers -> Signal<([RecentlySearchedPeer], [EnginePeer.Id: PeerStoryStats]), NoError> in
|
||||
return context.engine.data.subscribe(
|
||||
EngineDataMap(peers.map(\.peer.peerId).map { id in
|
||||
return TelegramEngine.EngineData.Item.Peer.StoryStats(id: id)
|
||||
})
|
||||
)
|
||||
|> map { stats -> ([RecentlySearchedPeer], [EnginePeer.Id: PeerStoryStats]) in
|
||||
var mappedStats: [EnginePeer.Id: PeerStoryStats] = [:]
|
||||
for (id, value) in stats {
|
||||
if let value {
|
||||
mappedStats[id] = value
|
||||
}
|
||||
}
|
||||
return (peers, mappedStats)
|
||||
}
|
||||
},
|
||||
presentationDataPromise.get(),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global())
|
||||
)
|
||||
|> mapToSignal { hasRecentPeers, peers, presentationData, globalNotificationSettings -> Signal<[ChatListRecentEntry], NoError> in
|
||||
|> mapToSignal { hasRecentPeers, peersAndStories, presentationData, globalNotificationSettings -> Signal<[ChatListRecentEntry], NoError> in
|
||||
let (peers, peerStoryStats) = peersAndStories
|
||||
|
||||
var entries: [ChatListRecentEntry] = []
|
||||
if !peersFilter.contains(.onlyGroups) {
|
||||
if hasRecentPeers {
|
||||
@ -2474,7 +2586,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
}
|
||||
peerIds.insert(peer.id)
|
||||
|
||||
entries.append(.peer(index: index, peer: searchedPeer, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalNotificationSettings))
|
||||
entries.append(.peer(index: index, peer: searchedPeer, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalNotificationSettings, peerStoryStats[peer.id]))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -2517,7 +2629,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
interaction.clearRecentSearch()
|
||||
}, deletePeer: { peerId in
|
||||
let _ = context.engine.peers.removeRecentlySearchedPeer(peerId: peerId).start()
|
||||
}, animationCache: strongSelf.animationCache, animationRenderer: strongSelf.animationRenderer)
|
||||
}, animationCache: strongSelf.animationCache, animationRenderer: strongSelf.animationRenderer, openStories: { peerId, avatarNode in
|
||||
interaction.openStories?(peerId, avatarNode)
|
||||
})
|
||||
strongSelf.enqueueRecentTransition(transition, firstTime: firstTime)
|
||||
}
|
||||
}))
|
||||
|
@ -20,7 +20,6 @@ import ComponentFlow
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import EmojiStatusComponent
|
||||
import AvatarStoryIndicatorComponent
|
||||
|
||||
public final class ContactItemHighlighting {
|
||||
public var chatLocation: ChatLocation?
|
||||
@ -400,7 +399,6 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
private let offsetContainerNode: ASDisplayNode
|
||||
private let avatarNodeContainer: ASDisplayNode
|
||||
public let avatarNode: AvatarNode
|
||||
private var avatarStoryIndicator: ComponentView<Empty>?
|
||||
private var avatarIconView: ComponentHostView<Empty>?
|
||||
private var avatarIconComponent: EmojiStatusComponent?
|
||||
private let titleNode: TextNode
|
||||
@ -414,6 +412,8 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
private var actionButtonNodes: [HighlightableButtonNode]?
|
||||
private var arrowButtonNode: HighlightableButtonNode?
|
||||
|
||||
private var avatarTapRecognizer: UITapGestureRecognizer?
|
||||
|
||||
private var isHighlighted: Bool = false
|
||||
|
||||
private var peerPresenceManager: PeerPresenceStatusManager?
|
||||
@ -1033,6 +1033,29 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
break
|
||||
}
|
||||
|
||||
strongSelf.avatarNode.setStoryStats(
|
||||
storyStats: item.storyStats.flatMap { stats in
|
||||
return AvatarNode.StoryStats(
|
||||
totalCount: stats.total,
|
||||
unseenCount: stats.unseen,
|
||||
hasUnseenCloseFriendsItems: stats.hasUnseenCloseFriends
|
||||
)
|
||||
},
|
||||
presentationParams: AvatarNode.StoryPresentationParams(
|
||||
colors: AvatarNode.Colors(theme: item.presentationData.theme),
|
||||
lineWidth: 1.33,
|
||||
inactiveLineWidth: 1.33
|
||||
),
|
||||
transition: animated ? Transition(animation: .curve(duration: 0.25, curve: .easeInOut)) : .immediate
|
||||
)
|
||||
|
||||
if strongSelf.avatarTapRecognizer == nil {
|
||||
let avatarTapRecognizer = UITapGestureRecognizer(target: strongSelf, action: #selector(strongSelf.avatarStoryTapGesture(_:)))
|
||||
strongSelf.avatarTapRecognizer = avatarTapRecognizer
|
||||
strongSelf.avatarNode.view.addGestureRecognizer(avatarTapRecognizer)
|
||||
}
|
||||
strongSelf.avatarNode.isUserInteractionEnabled = item.storyStats != nil
|
||||
|
||||
let transition: ContainedViewLayoutTransition
|
||||
if animated {
|
||||
transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
||||
@ -1086,62 +1109,10 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
transition.updatePosition(node: strongSelf.avatarNodeContainer, position: avatarFrame.center)
|
||||
transition.updateBounds(node: strongSelf.avatarNodeContainer, bounds: CGRect(origin: CGPoint(), size: avatarFrame.size))
|
||||
|
||||
var avatarScale: CGFloat = 1.0
|
||||
|
||||
if item.storyStats != nil {
|
||||
avatarScale *= (avatarFrame.width - 2.0 * 2.0) / avatarFrame.width
|
||||
}
|
||||
let avatarScale: CGFloat = 1.0
|
||||
|
||||
transition.updateTransformScale(node: strongSelf.avatarNodeContainer, scale: CGPoint(x: avatarScale, y: avatarScale))
|
||||
|
||||
let storyIndicatorScale: CGFloat = 1.0
|
||||
|
||||
if let storyStats = item.storyStats {
|
||||
var indicatorTransition = Transition(transition)
|
||||
let avatarStoryIndicator: ComponentView<Empty>
|
||||
if let current = strongSelf.avatarStoryIndicator {
|
||||
avatarStoryIndicator = current
|
||||
} else {
|
||||
indicatorTransition = .immediate
|
||||
avatarStoryIndicator = ComponentView()
|
||||
strongSelf.avatarStoryIndicator = avatarStoryIndicator
|
||||
}
|
||||
|
||||
var indicatorFrame = CGRect(origin: CGPoint(x: avatarFrame.minX + 2.0, y: avatarFrame.minY + 2.0), size: CGSize(width: avatarFrame.width - 2.0 - 2.0, height: avatarFrame.height - 2.0 - 2.0))
|
||||
indicatorFrame.origin.x -= (avatarFrame.width - avatarFrame.width * storyIndicatorScale) * 0.5
|
||||
|
||||
let _ = avatarStoryIndicator.update(
|
||||
transition: indicatorTransition,
|
||||
component: AnyComponent(AvatarStoryIndicatorComponent(
|
||||
hasUnseen: storyStats.unseen != 0,
|
||||
hasUnseenCloseFriendsItems: storyStats.hasUnseenCloseFriends,
|
||||
colors: AvatarStoryIndicatorComponent.Colors(theme: item.presentationData.theme),
|
||||
activeLineWidth: 1.0 + UIScreenPixel,
|
||||
inactiveLineWidth: 1.0 + UIScreenPixel,
|
||||
counters: AvatarStoryIndicatorComponent.Counters(totalCount: storyStats.total, unseenCount: storyStats.unseen)
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: indicatorFrame.size
|
||||
)
|
||||
if let avatarStoryIndicatorView = avatarStoryIndicator.view {
|
||||
if avatarStoryIndicatorView.superview == nil {
|
||||
avatarStoryIndicatorView.isUserInteractionEnabled = true
|
||||
avatarStoryIndicatorView.addGestureRecognizer(UITapGestureRecognizer(target: strongSelf, action: #selector(strongSelf.avatarStoryTapGesture(_:))))
|
||||
|
||||
strongSelf.offsetContainerNode.view.insertSubview(avatarStoryIndicatorView, belowSubview: strongSelf.avatarNodeContainer.view)
|
||||
}
|
||||
|
||||
indicatorTransition.setPosition(view: avatarStoryIndicatorView, position: indicatorFrame.center)
|
||||
indicatorTransition.setBounds(view: avatarStoryIndicatorView, bounds: CGRect(origin: CGPoint(), size: indicatorFrame.size))
|
||||
indicatorTransition.setScale(view: avatarStoryIndicatorView, scale: storyIndicatorScale)
|
||||
}
|
||||
} else {
|
||||
if let avatarStoryIndicator = strongSelf.avatarStoryIndicator {
|
||||
strongSelf.avatarStoryIndicator = nil
|
||||
avatarStoryIndicator.view?.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
if case let .thread(_, title, icon, color) = item.peer {
|
||||
let animationCache = item.context.animationCache
|
||||
let animationRenderer = item.context.animationRenderer
|
||||
@ -1543,7 +1514,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if let avatarStoryIndicatorView = self.avatarStoryIndicator?.view, let result = avatarStoryIndicatorView.hitTest(self.view.convert(point, to: avatarStoryIndicatorView), with: event) {
|
||||
if let result = self.avatarNode.view.hitTest(self.view.convert(point, to: self.avatarNode.view), with: event) {
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,8 @@ public final class HashtagSearchController: TelegramBaseController {
|
||||
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entries, displayingResults: true, isEmpty: entries.isEmpty, isLoading: false, animated: false, context: strongSelf.context, presentationData: strongSelf.presentationData, enableHeaders: false, filter: [], requestPeerType: nil, location: .chatList(groupId: .root), key: .chats, tagMask: nil, interaction: interaction, listInteraction: listInteraction, peerContextAction: nil, toggleExpandLocalResults: {
|
||||
}, toggleExpandGlobalResults: {
|
||||
}, searchPeer: { _ in
|
||||
}, searchQuery: "", searchOptions: nil, messageContextAction: nil, openClearRecentlyDownloaded: {}, toggleAllPaused: {})
|
||||
}, searchQuery: "", searchOptions: nil, messageContextAction: nil, openClearRecentlyDownloaded: {}, toggleAllPaused: {}, openStories: { _, _ in
|
||||
})
|
||||
strongSelf.controllerNode.enqueueTransition(transition, firstTime: firstTime)
|
||||
}
|
||||
})
|
||||
|
@ -1090,5 +1090,34 @@ public extension TelegramEngine.EngineData.Item {
|
||||
return view.info?.data.get(MessageHistoryThreadData.self)
|
||||
}
|
||||
}
|
||||
|
||||
public struct StoryStats: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = PeerStoryStats?
|
||||
|
||||
fileprivate var id: EnginePeer.Id
|
||||
public var mapKey: EnginePeer.Id {
|
||||
return self.id
|
||||
}
|
||||
|
||||
public init(id: EnginePeer.Id) {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .peerStoryStats(peerIds: Set([self.id]))
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? PeerStoryStatsView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
if let result = view.storyStats[self.id] {
|
||||
return result
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1179,7 +1179,10 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
},
|
||||
presentInGlobalOverlay: { _, _ in
|
||||
},
|
||||
navigationController: nil
|
||||
navigationController: nil,
|
||||
parentController: { [weak self] in
|
||||
return self?.controller
|
||||
}
|
||||
), cancel: { [weak self] in
|
||||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
|
Loading…
x
Reference in New Issue
Block a user