diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewUI.h b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewUI.h deleted file mode 100644 index f1eca381ba..0000000000 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewUI.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// StickerPackPreviewUI.h -// StickerPackPreviewUI -// -// Created by Peter on 8/15/19. -// Copyright © 2019 Telegram Messenger LLP. All rights reserved. -// - -#import - -//! Project version number for StickerPackPreviewUI. -FOUNDATION_EXPORT double StickerPackPreviewUIVersionNumber; - -//! Project version string for StickerPackPreviewUI. -FOUNDATION_EXPORT const unsigned char StickerPackPreviewUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift new file mode 100644 index 0000000000..5f3ec60bfc --- /dev/null +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift @@ -0,0 +1,10 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import Postbox +import TelegramCore +import SyncCore +import SwiftSignalKit +import AccountContext + diff --git a/submodules/TelegramUI/TelegramUI/ChatMediaInputGridEntries.swift b/submodules/TelegramUI/TelegramUI/ChatMediaInputGridEntries.swift index 9ca8ec1163..7f16035d60 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMediaInputGridEntries.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMediaInputGridEntries.swift @@ -11,60 +11,75 @@ enum ChatMediaInputGridEntryStableId: Equatable, Hashable { case search case peerSpecificSetup case sticker(ItemCollectionId, ItemCollectionItemIndex.Id) + case trending(ItemCollectionId) } enum ChatMediaInputGridEntryIndex: Equatable, Comparable { case search case peerSpecificSetup(dismissed: Bool) case collectionIndex(ItemCollectionViewEntryIndex) + case trending(ItemCollectionId, Int) var stableId: ChatMediaInputGridEntryStableId { switch self { - case .search: - return .search - case .peerSpecificSetup: - return .peerSpecificSetup - case let .collectionIndex(index): - return .sticker(index.collectionId, index.itemIndex.id) + case .search: + return .search + case .peerSpecificSetup: + return .peerSpecificSetup + case let .collectionIndex(index): + return .sticker(index.collectionId, index.itemIndex.id) + case let .trending(id, index): + return .trending(id) } } static func <(lhs: ChatMediaInputGridEntryIndex, rhs: ChatMediaInputGridEntryIndex) -> Bool { switch lhs { - case .search: - if case .search = rhs { + case .search: + if case .search = rhs { + return false + } else { + return true + } + case let .peerSpecificSetup(lhsDismissed): + switch rhs { + case .search, .peerSpecificSetup: + return false + case let .collectionIndex(index): + if lhsDismissed { return false } else { + if index.collectionId.id == 0 { + return false + } else { + return true + } + } + case .trending: + return true + } + case let .collectionIndex(lhsIndex): + switch rhs { + case .search: + return false + case let .peerSpecificSetup(dismissed): + if dismissed { return true + } else { + return false } - case let .peerSpecificSetup(lhsDismissed): - switch rhs { - case .search, .peerSpecificSetup: - return false - case let .collectionIndex(index): - if lhsDismissed { - return false - } else { - if index.collectionId.id == 0 { - return false - } else { - return true - } - } - } - case let .collectionIndex(lhsIndex): - switch rhs { - case .search: - return false - case let .peerSpecificSetup(dismissed): - if dismissed { - return true - } else { - return false - } - case let .collectionIndex(rhsIndex): - return lhsIndex < rhsIndex - } + case let .collectionIndex(rhsIndex): + return lhsIndex < rhsIndex + case .trending: + return true + } + case let .trending(_, lhsIndex): + switch rhs { + case .search, .peerSpecificSetup, .collectionIndex: + return false + case let .trending(_, rhsIndex): + return lhsIndex < rhsIndex + } } } } @@ -73,15 +88,18 @@ enum ChatMediaInputGridEntry: Equatable, Comparable, Identifiable { case search(theme: PresentationTheme, strings: PresentationStrings) case peerSpecificSetup(theme: PresentationTheme, strings: PresentationStrings, dismissed: Bool) case sticker(index: ItemCollectionViewEntryIndex, stickerItem: StickerPackItem, stickerPackInfo: StickerPackCollectionInfo?, canManagePeerSpecificPack: Bool?, theme: PresentationTheme) + case trending(TrendingPaneEntry) var index: ChatMediaInputGridEntryIndex { switch self { - case .search: - return .search - case let .peerSpecificSetup(_, _, dismissed): - return .peerSpecificSetup(dismissed: dismissed) - case let .sticker(index, _, _, _, _): - return .collectionIndex(index) + case .search: + return .search + case let .peerSpecificSetup(_, _, dismissed): + return .peerSpecificSetup(dismissed: dismissed) + case let .sticker(index, _, _, _, _): + return .collectionIndex(index) + case let .trending(entry): + return .trending(entry.info.id, entry.index) } } @@ -91,45 +109,51 @@ enum ChatMediaInputGridEntry: Equatable, Comparable, Identifiable { static func ==(lhs: ChatMediaInputGridEntry, rhs: ChatMediaInputGridEntry) -> Bool { switch lhs { - case let .search(lhsTheme, lhsStrings): - if case let .search(rhsTheme, rhsStrings) = rhs { - if lhsTheme !== rhsTheme { - return false - } - if lhsStrings !== rhsStrings { - return false - } - return true - } else { + case let .search(lhsTheme, lhsStrings): + if case let .search(rhsTheme, rhsStrings) = rhs { + if lhsTheme !== rhsTheme { return false } - case let .peerSpecificSetup(lhsTheme, lhsStrings, lhsDismissed): - if case let .peerSpecificSetup(rhsTheme, rhsStrings, rhsDismissed) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDismissed == rhsDismissed { - return true - } else { + if lhsStrings !== rhsStrings { return false } - case let .sticker(lhsIndex, lhsStickerItem, lhsStickerPackInfo, lhsCanManagePeerSpecificPack, lhsTheme): - if case let .sticker(rhsIndex, rhsStickerItem, rhsStickerPackInfo, rhsCanManagePeerSpecificPack, rhsTheme) = rhs { - if lhsIndex != rhsIndex { - return false - } - if lhsStickerItem != rhsStickerItem { - return false - } - if lhsStickerPackInfo != rhsStickerPackInfo { - return false - } - if lhsCanManagePeerSpecificPack != rhsCanManagePeerSpecificPack { - return false - } - if lhsTheme !== rhsTheme { - return false - } - return true - } else { + return true + } else { + return false + } + case let .peerSpecificSetup(lhsTheme, lhsStrings, lhsDismissed): + if case let .peerSpecificSetup(rhsTheme, rhsStrings, rhsDismissed) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDismissed == rhsDismissed { + return true + } else { + return false + } + case let .sticker(lhsIndex, lhsStickerItem, lhsStickerPackInfo, lhsCanManagePeerSpecificPack, lhsTheme): + if case let .sticker(rhsIndex, rhsStickerItem, rhsStickerPackInfo, rhsCanManagePeerSpecificPack, rhsTheme) = rhs { + if lhsIndex != rhsIndex { return false } + if lhsStickerItem != rhsStickerItem { + return false + } + if lhsStickerPackInfo != rhsStickerPackInfo { + return false + } + if lhsCanManagePeerSpecificPack != rhsCanManagePeerSpecificPack { + return false + } + if lhsTheme !== rhsTheme { + return false + } + return true + } else { + return false + } + case let .trending(entry): + if case .trending(entry) = rhs { + return true + } else { + return false + } } } @@ -137,20 +161,22 @@ enum ChatMediaInputGridEntry: Equatable, Comparable, Identifiable { return lhs.index < rhs.index } - func item(account: Account, interfaceInteraction: ChatControllerInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction) -> GridItem { + func item(account: Account, interfaceInteraction: ChatControllerInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction, trendingInteraction: TrendingPaneInteraction) -> GridItem { switch self { - case let .search(theme, strings): - return PaneSearchBarPlaceholderItem(theme: theme, strings: strings, type: .stickers, activate: { - inputNodeInteraction.toggleSearch(true, .sticker) - }) - case let .peerSpecificSetup(theme, strings, dismissed): - return StickerPanePeerSpecificSetupGridItem(theme: theme, strings: strings, setup: { - inputNodeInteraction.openPeerSpecificSettings() - }, dismiss: dismissed ? nil : { - inputNodeInteraction.dismissPeerSpecificSettings() - }) - case let .sticker(index, stickerItem, stickerPackInfo, canManagePeerSpecificPack, theme): - return ChatMediaInputStickerGridItem(account: account, collectionId: index.collectionId, stickerPackInfo: stickerPackInfo, index: index, stickerItem: stickerItem, canManagePeerSpecificPack: canManagePeerSpecificPack, interfaceInteraction: interfaceInteraction, inputNodeInteraction: inputNodeInteraction, theme: theme, selected: { }) + case let .search(theme, strings): + return PaneSearchBarPlaceholderItem(theme: theme, strings: strings, type: .stickers, activate: { + inputNodeInteraction.toggleSearch(true, .sticker) + }) + case let .peerSpecificSetup(theme, strings, dismissed): + return StickerPanePeerSpecificSetupGridItem(theme: theme, strings: strings, setup: { + inputNodeInteraction.openPeerSpecificSettings() + }, dismiss: dismissed ? nil : { + inputNodeInteraction.dismissPeerSpecificSettings() + }) + case let .sticker(index, stickerItem, stickerPackInfo, canManagePeerSpecificPack, theme): + return ChatMediaInputStickerGridItem(account: account, collectionId: index.collectionId, stickerPackInfo: stickerPackInfo, index: index, stickerItem: stickerItem, canManagePeerSpecificPack: canManagePeerSpecificPack, interfaceInteraction: interfaceInteraction, inputNodeInteraction: inputNodeInteraction, theme: theme, selected: { }) + case let .trending(entry): + return entry.item(account: account, interaction: trendingInteraction, grid: false) } } } diff --git a/submodules/TelegramUI/TelegramUI/ChatMediaInputNode.swift b/submodules/TelegramUI/TelegramUI/ChatMediaInputNode.swift index ea1b72b82d..b160206b67 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMediaInputNode.swift @@ -15,6 +15,8 @@ import PeerInfoUI import SettingsUI import ContextUI import GalleryUI +import OverlayStatusController +import PresentationDataUtils private struct PeerSpecificPackData { let peer: Peer @@ -54,7 +56,7 @@ private func preparedChatMediaInputPanelEntryTransition(account: Account, from f return ChatMediaInputPanelTransition(deletions: deletions, insertions: insertions, updates: updates) } -private func preparedChatMediaInputGridEntryTransition(account: Account, view: ItemCollectionsView, from fromEntries: [ChatMediaInputGridEntry], to toEntries: [ChatMediaInputGridEntry], update: StickerPacksCollectionUpdate, interfaceInteraction: ChatControllerInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction) -> ChatMediaInputGridTransition { +private func preparedChatMediaInputGridEntryTransition(account: Account, view: ItemCollectionsView, from fromEntries: [ChatMediaInputGridEntry], to toEntries: [ChatMediaInputGridEntry], update: StickerPacksCollectionUpdate, interfaceInteraction: ChatControllerInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction, trendingInteraction: TrendingPaneInteraction) -> ChatMediaInputGridTransition { var stationaryItems: GridNodeStationaryItems = .none var scrollToItem: GridNodeScrollToItem? var animated = false @@ -62,10 +64,10 @@ private func preparedChatMediaInputGridEntryTransition(account: Account, view: I case .initial: for i in (0 ..< toEntries.count).reversed() { switch toEntries[i] { - case .search, .peerSpecificSetup: - break - case .sticker: - scrollToItem = GridNodeScrollToItem(index: i, position: .top(0.0), transition: .immediate, directionHint: .down, adjustForSection: true, adjustForTopInset: true) + case .search, .peerSpecificSetup, .trending: + break + case .sticker: + scrollToItem = GridNodeScrollToItem(index: i, position: .top(0.0), transition: .immediate, directionHint: .down, adjustForSection: true, adjustForTopInset: true) } } case .generic: @@ -131,16 +133,16 @@ private func preparedChatMediaInputGridEntryTransition(account: Account, view: I let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices - let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interfaceInteraction: interfaceInteraction, inputNodeInteraction: inputNodeInteraction), previousIndex: $0.2) } - let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interfaceInteraction: interfaceInteraction, inputNodeInteraction: inputNodeInteraction)) } + let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interfaceInteraction: interfaceInteraction, inputNodeInteraction: inputNodeInteraction, trendingInteraction: trendingInteraction), previousIndex: $0.2) } + let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interfaceInteraction: interfaceInteraction, inputNodeInteraction: inputNodeInteraction, trendingInteraction: trendingInteraction)) } var firstIndexInSectionOffset = 0 if !toEntries.isEmpty { switch toEntries[0].index { - case .search, .peerSpecificSetup: - break - case let .collectionIndex(index): - firstIndexInSectionOffset = Int(index.itemIndex.index) + case .search, .peerSpecificSetup, .trending: + break + case let .collectionIndex(index): + firstIndexInSectionOffset = Int(index.itemIndex.index) } } @@ -704,21 +706,55 @@ final class ChatMediaInputNode: ChatInputNode { peerSpecificPack = .single((nil, .none)) } - let hasUnreadTrending = context.account.viewTracker.featuredStickerPacks() - |> map { packs -> Bool in - for pack in packs { - if pack.unread { - return true + let trendingInteraction = TrendingPaneInteraction(installPack: { [weak self] info in + guard let strongSelf = self, let info = info as? StickerPackCollectionInfo else { + return + } + let _ = (loadedStickerPack(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, reference: .id(id: info.id.id, accessHash: info.accessHash), forceActualized: false) + |> mapToSignal { result -> Signal in + switch result { + case let .result(info, items, installed): + if installed { + return .complete() + } else { + return addStickerPackInteractively(postbox: strongSelf.context.account.postbox, info: info, items: items) + } + case .fetching: + break + case .none: + break + } + return .complete() + } + |> deliverOnMainQueue).start(completed: { + guard let strongSelf = self else { + return + } + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + strongSelf.controllerInteraction.presentController(OverlayStatusController(theme: presentationData.theme, type: .success), nil) + }) + }, openPack: { [weak self] info in + guard let strongSelf = self, let info = info as? StickerPackCollectionInfo else { + return + } + strongSelf.view.window?.endEditing(true) + let controller = StickerPackPreviewController(context: strongSelf.context, stickerPack: .id(id: info.id.id, accessHash: info.accessHash), parentNavigationController: strongSelf.controllerInteraction.navigationController()) + controller.sendSticker = { fileReference, sourceNode, sourceRect in + if let strongSelf = self { + return strongSelf.controllerInteraction.sendSticker(fileReference, false, sourceNode, sourceRect) + } else { + return false } } - return false - } - |> distinctUntilChanged + strongSelf.controllerInteraction.presentController(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + }, getItemIsPreviewed: { item in + return getItemIsPreviewedImpl?(item) ?? false + }) let previousView = Atomic(value: nil) let transitionQueue = Queue() - let transitions = combineLatest(queue: transitionQueue, itemCollectionsView, peerSpecificPack, hasUnreadTrending, self.themeAndStringsPromise.get()) - |> map { viewAndUpdate, peerSpecificPack, hasUnreadTrending, themeAndStrings -> (ItemCollectionsView, ChatMediaInputPanelTransition, Bool, ChatMediaInputGridTransition, Bool) in + let transitions = combineLatest(queue: transitionQueue, itemCollectionsView, peerSpecificPack, context.account.viewTracker.featuredStickerPacks(), self.themeAndStringsPromise.get()) + |> map { viewAndUpdate, peerSpecificPack, trendingPacks, themeAndStrings -> (ItemCollectionsView, ChatMediaInputPanelTransition, Bool, ChatMediaInputGridTransition, Bool) in let (view, viewUpdate) = viewAndUpdate let previous = previousView.swap(view) var update = viewUpdate @@ -736,10 +772,35 @@ final class ChatMediaInputNode: ChatInputNode { savedStickers = orderedView } } + + var installedPacks = Set() + for info in view.collectionInfos { + installedPacks.insert(info.0) + } + + var hasUnreadTrending = false + for pack in trendingPacks { + if pack.unread { + hasUnreadTrending = true + break + } + } + let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, hasUnreadTrending: hasUnreadTrending, theme: theme) - let gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, strings: strings, theme: theme) + var gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, strings: strings, theme: theme) + + if view.higher == nil { + var index = 0 + for item in trendingPacks { + if !installedPacks.contains(item.info.id) { + gridEntries.append(.trending(TrendingPaneEntry(index: index, info: item.info, theme: theme, strings: strings, topItems: item.topItems, installed: installedPacks.contains(item.info.id), unread: item.unread))) + index += 1 + } + } + } + let (previousPanelEntries, previousGridEntries) = previousEntries.swap((panelEntries, gridEntries)) - return (view, preparedChatMediaInputPanelEntryTransition(account: context.account, from: previousPanelEntries, to: panelEntries, inputNodeInteraction: inputNodeInteraction), previousPanelEntries.isEmpty, preparedChatMediaInputGridEntryTransition(account: context.account, view: view, from: previousGridEntries, to: gridEntries, update: update, interfaceInteraction: controllerInteraction, inputNodeInteraction: inputNodeInteraction), previousGridEntries.isEmpty) + return (view, preparedChatMediaInputPanelEntryTransition(account: context.account, from: previousPanelEntries, to: panelEntries, inputNodeInteraction: inputNodeInteraction), previousPanelEntries.isEmpty, preparedChatMediaInputGridEntryTransition(account: context.account, view: view, from: previousGridEntries, to: gridEntries, update: update, interfaceInteraction: controllerInteraction, inputNodeInteraction: inputNodeInteraction, trendingInteraction: trendingInteraction), previousGridEntries.isEmpty) } self.disposable.set((transitions @@ -1086,14 +1147,23 @@ final class ChatMediaInputNode: ChatInputNode { } private func setCurrentPane(_ pane: ChatMediaInputPaneType, transition: ContainedViewLayoutTransition, collectionIdHint: Int32? = nil) { + var transition = transition + if let index = self.paneArrangement.panes.firstIndex(of: pane), index != self.paneArrangement.currentIndex { let previousGifPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .gifs + let previousTrendingPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .trending self.paneArrangement = self.paneArrangement.withIndexTransition(0.0).withCurrentIndex(index) + let updatedGifPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .gifs + let updatedTrendingPanelIsActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .trending + + if updatedTrendingPanelIsActive != previousTrendingPanelWasActive { + transition = .immediate + } + if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, deviceMetrics, isVisible) = self.validLayout { - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .animated(duration: 0.25, curve: .spring), interfaceState: interfaceState, deviceMetrics: deviceMetrics, isVisible: isVisible) + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: transition, interfaceState: interfaceState, deviceMetrics: deviceMetrics, isVisible: isVisible) self.updateAppearanceTransition(transition: transition) } - let updatedGifPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .gifs if updatedGifPanelWasActive != previousGifPanelWasActive { self.gifPaneIsActiveUpdated(updatedGifPanelWasActive) } @@ -1109,6 +1179,20 @@ final class ChatMediaInputNode: ChatInputNode { case .trending: self.setHighlightedItemCollectionId(ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue, id: 0)) } + if updatedTrendingPanelIsActive != previousTrendingPanelWasActive { + self.controllerInteraction.updateInputMode { current in + switch current { + case let .media(mode, _): + if updatedTrendingPanelIsActive { + return .media(mode: mode, expanded: .content) + } else { + return .media(mode: mode, expanded: nil) + } + default: + return current + } + } + } } else { if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, deviceMetrics, isVisible) = self.validLayout { let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .animated(duration: 0.25, curve: .spring), interfaceState: interfaceState, deviceMetrics: deviceMetrics, isVisible: isVisible) diff --git a/submodules/TelegramUI/TelegramUI/ChatMediaInputTrendingPane.swift b/submodules/TelegramUI/TelegramUI/ChatMediaInputTrendingPane.swift index 1c8abfcf7c..1d1113ec81 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMediaInputTrendingPane.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMediaInputTrendingPane.swift @@ -25,7 +25,7 @@ final class TrendingPaneInteraction { } } -private final class TrendingPaneEntry: Identifiable, Comparable { +final class TrendingPaneEntry: Identifiable, Comparable { let index: Int let info: StickerPackCollectionInfo let theme: PresentationTheme @@ -77,9 +77,9 @@ private final class TrendingPaneEntry: Identifiable, Comparable { return lhs.index < rhs.index } - func item(account: Account, interaction: TrendingPaneInteraction) -> GridItem { + func item(account: Account, interaction: TrendingPaneInteraction, grid: Bool) -> GridItem { let info = self.info - return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, info: self.info, topItems: self.topItems, grid: true, installed: self.installed, unread: self.unread, open: { + return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, info: self.info, topItems: self.topItems, grid: grid, installed: self.installed, unread: self.unread, open: { interaction.openPack(info) }, install: { interaction.installPack(info) @@ -100,13 +100,13 @@ private func preparedTransition(from fromEntries: [TrendingPaneEntry], to toEntr let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices - let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interaction: interaction), previousIndex: $0.2) } - let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction)) } + let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interaction: interaction, grid: true), previousIndex: $0.2) } + let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction, grid: true)) } return TrendingPaneTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial) } -private func trendingPaneEntries(trendingEntries: [FeaturedStickerPackItem], installedPacks: Set, theme: PresentationTheme, strings: PresentationStrings) -> [TrendingPaneEntry] { +func trendingPaneEntries(trendingEntries: [FeaturedStickerPackItem], installedPacks: Set, theme: PresentationTheme, strings: PresentationStrings) -> [TrendingPaneEntry] { var result: [TrendingPaneEntry] = [] var index = 0 for item in trendingEntries {