Fix featured sticker packs UI

This commit is contained in:
Ali 2020-04-18 16:52:12 +04:00
parent d5142c876e
commit 046c620242
10 changed files with 1882 additions and 1826 deletions

View file

@ -5492,3 +5492,5 @@ Any member of this group will be able to see messages in the channel.";
"CreatePoll.ExplanationHeader" = "EXPLANATION";
"CreatePoll.Explanation" = "Add a Comment (Optional)";
"CreatePoll.ExplanationInfo" = "Users will see this comment after choosing a wrong answer, good for educational purposes.";
"FeaturedStickers.OtherSection" = "OTHER";

View file

@ -809,10 +809,16 @@ final class ChatMediaInputNode: ChatInputNode {
var gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, strings: strings, theme: theme)
if view.higher == nil {
var hasTopSeparator = true
if gridEntries.count == 1, case .search = gridEntries[0] {
hasTopSeparator = false
}
var index = 0
for item in trendingPacks {
if !installedPacks.contains(item.info.id) {
gridEntries.append(.trending(TrendingPanePackEntry(index: index, info: item.info, theme: theme, strings: strings, topItems: item.topItems, installed: installedPacks.contains(item.info.id), unread: item.unread, topSeparator: true)))
gridEntries.append(.trending(TrendingPanePackEntry(index: index, info: item.info, theme: theme, strings: strings, topItems: item.topItems, installed: installedPacks.contains(item.info.id), unread: item.unread, topSeparator: hasTopSeparator)))
hasTopSeparator = true
index += 1
}
}

View file

@ -88,7 +88,7 @@ final class TrendingPanePackEntry: Identifiable, Comparable {
func item(account: Account, interaction: TrendingPaneInteraction, grid: Bool) -> GridItem {
let info = self.info
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, listAppearance: false, info: self.info, topItems: self.topItems, grid: grid, topSeparator: self.topSeparator, installed: self.installed, unread: self.unread, open: {
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, listAppearance: false, info: self.info, topItems: self.topItems, grid: grid, topSeparator: self.topSeparator, regularInsets: false, installed: self.installed, unread: self.unread, open: {
interaction.openPack(info)
}, install: {
interaction.installPack(info)

View file

@ -40,8 +40,9 @@ private final class FeaturedPackEntry: Identifiable, Comparable {
let installed: Bool
let unread: Bool
let topSeparator: Bool
let regularInsets: Bool
init(index: Int, info: StickerPackCollectionInfo, theme: PresentationTheme, strings: PresentationStrings, topItems: [StickerPackItem], installed: Bool, unread: Bool, topSeparator: Bool) {
init(index: Int, info: StickerPackCollectionInfo, theme: PresentationTheme, strings: PresentationStrings, topItems: [StickerPackItem], installed: Bool, unread: Bool, topSeparator: Bool, regularInsets: Bool = false) {
self.index = index
self.info = info
self.theme = theme
@ -50,6 +51,7 @@ private final class FeaturedPackEntry: Identifiable, Comparable {
self.installed = installed
self.unread = unread
self.topSeparator = topSeparator
self.regularInsets = regularInsets
}
var stableId: ItemCollectionId {
@ -81,6 +83,9 @@ private final class FeaturedPackEntry: Identifiable, Comparable {
if lhs.topSeparator != rhs.topSeparator {
return false
}
if lhs.regularInsets != rhs.regularInsets {
return false
}
return true
}
@ -88,46 +93,36 @@ private final class FeaturedPackEntry: Identifiable, Comparable {
return lhs.index < rhs.index
}
func item(account: Account, interaction: FeaturedInteraction, grid: Bool) -> GridItem {
func item(account: Account, interaction: FeaturedInteraction, isOther: Bool) -> GridItem {
let info = self.info
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, listAppearance: true, info: self.info, topItems: self.topItems, grid: grid, topSeparator: self.topSeparator, installed: self.installed, unread: self.unread, open: {
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, listAppearance: true, info: self.info, topItems: self.topItems, grid: false, topSeparator: self.topSeparator, regularInsets: self.regularInsets, installed: self.installed, unread: self.unread, open: {
interaction.openPack(info)
}, install: {
interaction.installPack(info, !self.installed)
}, getItemIsPreviewed: { item in
return interaction.getItemIsPreviewed(item)
}, itemContext: interaction.itemContext)
}, itemContext: interaction.itemContext, sectionTitle: isOther ? self.strings.FeaturedStickers_OtherSection : nil)
}
}
private enum FeaturedEntryId: Hashable {
case search
case pack(ItemCollectionId)
}
private enum FeaturedEntry: Identifiable, Comparable {
case search(theme: PresentationTheme, strings: PresentationStrings)
case pack(FeaturedPackEntry)
case pack(FeaturedPackEntry, Bool)
var stableId: FeaturedEntryId {
switch self {
case .search:
return .search
case let .pack(pack):
case let .pack(pack, _):
return .pack(pack.stableId)
}
}
static func ==(lhs: FeaturedEntry, rhs: FeaturedEntry) -> Bool {
switch lhs {
case let .search(lhsTheme, lhsStrings):
if case let .search(rhsTheme, rhsStrings) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings {
return true
} else {
return false
}
case let .pack(pack):
if case .pack(pack) = rhs {
case let .pack(pack, isOther):
if case .pack(pack, isOther) = rhs {
return true
} else {
return false
@ -137,26 +132,18 @@ private enum FeaturedEntry: Identifiable, Comparable {
static func <(lhs: FeaturedEntry, rhs: FeaturedEntry) -> Bool {
switch lhs {
case .search:
return false
case let .pack(lhsPack):
case let .pack(lhsPack, _):
switch rhs {
case .search:
return false
case let .pack(rhsPack):
case let .pack(rhsPack, _):
return lhsPack < rhsPack
}
}
}
func item(account: Account, interaction: FeaturedInteraction, grid: Bool) -> GridItem {
func item(account: Account, interaction: FeaturedInteraction) -> GridItem {
switch self {
case let .search(theme, strings):
return PaneSearchBarPlaceholderItem(theme: theme, strings: strings, type: .stickers, activate: {
interaction.openSearch()
})
case let .pack(pack):
return pack.item(account: account, interaction: interaction, grid: grid)
case let .pack(pack, isOther):
return pack.item(account: account, interaction: interaction, isOther: isOther)
}
}
}
@ -172,8 +159,8 @@ private func preparedTransition(from fromEntries: [FeaturedEntry], to toEntries:
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, grid: false), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction, grid: false)) }
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)) }
return FeaturedTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial)
}
@ -185,14 +172,14 @@ private func featuredScreenEntries(featuredEntries: [FeaturedStickerPackItem], i
for item in featuredEntries {
if !existingIds.contains(item.info.id) {
existingIds.insert(item.info.id)
result.append(.pack(FeaturedPackEntry(index: index, info: item.info, theme: theme, strings: strings, topItems: item.topItems, installed: installedPacks.contains(item.info.id), unread: item.unread || fixedUnread.contains(item.info.id), topSeparator: index != 0)))
result.append(.pack(FeaturedPackEntry(index: index, info: item.info, theme: theme, strings: strings, topItems: item.topItems, installed: installedPacks.contains(item.info.id), unread: item.unread || fixedUnread.contains(item.info.id), topSeparator: index != 0, regularInsets: true), false))
index += 1
}
}
for item in additionalPacks {
if !existingIds.contains(item.info.id) {
existingIds.insert(item.info.id)
result.append(.pack(FeaturedPackEntry(index: index, info: item.info, theme: theme, strings: strings, topItems: item.topItems, installed: installedPacks.contains(item.info.id), unread: item.unread || fixedUnread.contains(item.info.id), topSeparator: index != 0)))
result.append(.pack(FeaturedPackEntry(index: index, info: item.info, theme: theme, strings: strings, topItems: item.topItems, installed: installedPacks.contains(item.info.id), unread: item.unread || fixedUnread.contains(item.info.id), topSeparator: index != 0, regularInsets: true), true))
index += 1
}
}
@ -238,6 +225,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
self.sendSticker = sendSticker
self.gridNode = GridNode()
self.gridNode.floatingSections = true
super.init()
@ -1040,7 +1028,7 @@ private enum FeaturedSearchEntry: Identifiable, Comparable {
interaction.sendSticker(.standalone(media: stickerItem.file), node, rect)
})
case let .global(_, info, topItems, installed, topSeparator):
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, listAppearance: false, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, installed: installed, unread: false, open: {
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, listAppearance: false, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, regularInsets: false, installed: installed, unread: false, open: {
interaction.open(info)
}, install: {
interaction.install(info, topItems, !installed)

View file

@ -106,7 +106,7 @@ private enum StickerSearchEntry: Identifiable, Comparable {
case let .global(_, info, topItems, installed, topSeparator):
let itemContext = StickerPaneSearchGlobalItemContext()
itemContext.canPlayMedia = true
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, listAppearance: false, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, installed: installed, unread: false, open: {
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, listAppearance: false, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, regularInsets: false, installed: installed, unread: false, open: {
interaction.open(info)
}, install: {
interaction.install(info, topItems, !installed)

View file

@ -8,27 +8,65 @@ import SwiftSignalKit
import Postbox
import TelegramPresentationData
import StickerPackPreviewUI
import ListSectionHeaderNode
final class StickerPaneSearchGlobalSection: GridSection {
let height: CGFloat = 0.0
let title: String?
let theme: PresentationTheme
var hashValue: Int {
return 0
var height: CGFloat {
if let _ = self.title {
return 28.0
} else {
return 0.0
}
}
init() {
var hashValue: Int {
if let _ = self.title {
return 1
} else {
return 0
}
}
init(title: String?, theme: PresentationTheme) {
self.title = title
self.theme = theme
}
func isEqual(to: GridSection) -> Bool {
if to is StickerPaneSearchGlobalSection {
return true
if let to = to as? StickerPaneSearchGlobalSection {
return to.hashValue == self.hashValue
} else {
return false
}
}
func node() -> ASDisplayNode {
return ASDisplayNode()
return StickerPaneSearchGlobalSectionNode(theme: self.theme, title: self.title ?? "")
}
}
private final class StickerPaneSearchGlobalSectionNode: ASDisplayNode {
private let node: ListSectionHeaderNode
init(theme: PresentationTheme, title: String) {
self.node = ListSectionHeaderNode(theme: theme)
super.init()
if !title.isEmpty {
self.node.title = title
self.addSubnode(self.node)
}
}
override func layout() {
super.layout()
self.node.frame = self.bounds
self.node.updateLayout(size: self.bounds.size, leftInset: 0.0, rightInset: 0.0)
}
}
@ -45,6 +83,7 @@ final class StickerPaneSearchGlobalItem: GridItem {
let topItems: [StickerPackItem]
let grid: Bool
let topSeparator: Bool
let regularInsets: Bool
let installed: Bool
let installing: Bool
let unread: Bool
@ -53,12 +92,22 @@ final class StickerPaneSearchGlobalItem: GridItem {
let getItemIsPreviewed: (StickerPackItem) -> Bool
let itemContext: StickerPaneSearchGlobalItemContext
let section: GridSection? = StickerPaneSearchGlobalSection()
let section: GridSection?
var fillsRowWithHeight: CGFloat? {
return self.grid ? nil : (128.0 + (self.topSeparator ? 12.0 : 0.0))
var additionalHeight: CGFloat = 0.0
if self.regularInsets {
additionalHeight = 12.0 + 12.0
} else {
additionalHeight += 12.0
if self.topSeparator {
additionalHeight += 12.0
}
}
return self.grid ? nil : (128.0 + additionalHeight)
}
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, listAppearance: Bool, info: StickerPackCollectionInfo, topItems: [StickerPackItem], grid: Bool, topSeparator: Bool, installed: Bool, installing: Bool = false, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool, itemContext: StickerPaneSearchGlobalItemContext) {
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, listAppearance: Bool, info: StickerPackCollectionInfo, topItems: [StickerPackItem], grid: Bool, topSeparator: Bool, regularInsets: Bool, installed: Bool, installing: Bool = false, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool, itemContext: StickerPaneSearchGlobalItemContext, sectionTitle: String? = nil) {
self.account = account
self.theme = theme
self.strings = strings
@ -67,6 +116,7 @@ final class StickerPaneSearchGlobalItem: GridItem {
self.topItems = topItems
self.grid = grid
self.topSeparator = topSeparator
self.regularInsets = regularInsets
self.installed = installed
self.installing = installing
self.unread = unread
@ -74,6 +124,7 @@ final class StickerPaneSearchGlobalItem: GridItem {
self.install = install
self.getItemIsPreviewed = getItemIsPreviewed
self.itemContext = itemContext
self.section = StickerPaneSearchGlobalSection(title: sectionTitle, theme: theme)
}
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
@ -279,13 +330,21 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
let params = ListViewItemLayoutParams(width: size.width, leftInset: 0.0, rightInset: 0.0, availableHeight: size.height)
var topOffset: CGFloat = 12.0
if item.topSeparator {
let topSeparatorOffset: CGFloat
var topOffset: CGFloat = 0.0
if item.regularInsets {
topOffset = 12.0
topSeparatorOffset = -UIScreenPixel
} else {
topSeparatorOffset = 16.0
topOffset += 12.0
if item.topSeparator {
topOffset += 12.0
}
}
self.topSeparatorNode.isHidden = !item.topSeparator
self.topSeparatorNode.frame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: CGSize(width: params.width - 16.0 * 2.0, height: UIScreenPixel))
self.topSeparatorNode.frame = CGRect(origin: CGPoint(x: 16.0, y: topSeparatorOffset), size: CGSize(width: params.width - 16.0 * 2.0, height: UIScreenPixel))
if item.listAppearance {
self.topSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
} else {

View file

@ -449,12 +449,12 @@ public final class WalletStrings: Equatable {
public var Wallet_SecureStorageReset_Title: String { return self._s[219]! }
public var Wallet_Receive_CommentHeader: String { return self._s[220]! }
public var Wallet_Info_ReceiveGrams: String { return self._s[221]! }
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
let form = getPluralizationForm(self.lc, value)
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
}
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
let form = getPluralizationForm(self.lc, value)
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)