From 4e8fb6561d57655b426beaac94dc6eca45416483 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 14 Apr 2020 18:32:04 +0400 Subject: [PATCH] Load additional featured packs while scrolling --- submodules/TelegramApi/Sources/Api0.swift | 4 +- submodules/TelegramApi/Sources/Api1.swift | 48 +++++++++----- submodules/TelegramApi/Sources/Api3.swift | 16 +++++ .../Sources/StickerManagement.swift | 45 +++++++++---- .../Sources/FeaturedStickersScreen.swift | 66 +++++++++++++++++-- 5 files changed, 140 insertions(+), 39 deletions(-) diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 9b60f90d1e..8386199c52 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -623,8 +623,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) } dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) } dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) } - dict[82699215] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) } - dict[-123893531] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) } + dict[-958657434] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) } + dict[-1230257343] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) } dict[-2048646399] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonMissed($0) } dict[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) } dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) } diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 583277c93b..a1f699fd94 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -1363,22 +1363,23 @@ public struct messages { } public enum FeaturedStickers: TypeConstructorDescription { - case featuredStickersNotModified - case featuredStickers(hash: Int32, sets: [Api.StickerSetCovered], unread: [Int64]) + case featuredStickersNotModified(count: Int32) + case featuredStickers(hash: Int32, count: Int32, sets: [Api.StickerSetCovered], unread: [Int64]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .featuredStickersNotModified: + case .featuredStickersNotModified(let count): if boxed { - buffer.appendInt32(82699215) + buffer.appendInt32(-958657434) } - + serializeInt32(count, buffer: buffer, boxed: false) break - case .featuredStickers(let hash, let sets, let unread): + case .featuredStickers(let hash, let count, let sets, let unread): if boxed { - buffer.appendInt32(-123893531) + buffer.appendInt32(-1230257343) } serializeInt32(hash, buffer: buffer, boxed: false) + serializeInt32(count, buffer: buffer, boxed: false) buffer.appendInt32(481674261) buffer.appendInt32(Int32(sets.count)) for item in sets { @@ -1395,32 +1396,43 @@ public struct messages { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .featuredStickersNotModified: - return ("featuredStickersNotModified", []) - case .featuredStickers(let hash, let sets, let unread): - return ("featuredStickers", [("hash", hash), ("sets", sets), ("unread", unread)]) + case .featuredStickersNotModified(let count): + return ("featuredStickersNotModified", [("count", count)]) + case .featuredStickers(let hash, let count, let sets, let unread): + return ("featuredStickers", [("hash", hash), ("count", count), ("sets", sets), ("unread", unread)]) } } public static func parse_featuredStickersNotModified(_ reader: BufferReader) -> FeaturedStickers? { - return Api.messages.FeaturedStickers.featuredStickersNotModified + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.messages.FeaturedStickers.featuredStickersNotModified(count: _1!) + } + else { + return nil + } } public static func parse_featuredStickers(_ reader: BufferReader) -> FeaturedStickers? { var _1: Int32? _1 = reader.readInt32() - var _2: [Api.StickerSetCovered]? + var _2: Int32? + _2 = reader.readInt32() + var _3: [Api.StickerSetCovered]? if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self) + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self) } - var _3: [Int64]? + var _4: [Int64]? if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + _4 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.messages.FeaturedStickers.featuredStickers(hash: _1!, sets: _2!, unread: _3!) + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.FeaturedStickers.featuredStickers(hash: _1!, count: _2!, sets: _3!, unread: _4!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 7ce03aebc6..596cfa15b5 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -3276,6 +3276,22 @@ public extension Api { return result }) } + + public static func getOldFeaturedStickers(offset: Int32, limit: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1608974939) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getOldFeaturedStickers", parameters: [("offset", offset), ("limit", limit), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.FeaturedStickers? in + let reader = BufferReader(buffer) + var result: Api.messages.FeaturedStickers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.FeaturedStickers + } + return result + }) + } } public struct channels { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { diff --git a/submodules/TelegramCore/Sources/StickerManagement.swift b/submodules/TelegramCore/Sources/StickerManagement.swift index 1ec8db6630..574c4669f2 100644 --- a/submodules/TelegramCore/Sources/StickerManagement.swift +++ b/submodules/TelegramCore/Sources/StickerManagement.swift @@ -46,27 +46,46 @@ func updatedFeaturedStickerPacks(network: Network, postbox: Postbox) -> Signal mapToSignal { result -> Signal in return postbox.transaction { transaction -> Void in switch result { - case .featuredStickersNotModified: - break - case let .featuredStickers(_, sets, unread): - let unreadIds = Set(unread) - var updatedPacks: [FeaturedStickerPackItem] = [] - for set in sets { - var (info, items) = parsePreviewStickerSet(set) - if let previousPack = initialPackMap[info.id.id] { - if previousPack.info.hash == info.hash { - items = previousPack.topItems - } + case .featuredStickersNotModified: + break + case let .featuredStickers(_, _, sets, unread): + let unreadIds = Set(unread) + var updatedPacks: [FeaturedStickerPackItem] = [] + for set in sets { + var (info, items) = parsePreviewStickerSet(set) + if let previousPack = initialPackMap[info.id.id] { + if previousPack.info.hash == info.hash { + items = previousPack.topItems } - updatedPacks.append(FeaturedStickerPackItem(info: info, topItems: items, unread: unreadIds.contains(info.id.id))) } - transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, items: updatedPacks.map { OrderedItemListEntry(id: FeaturedStickerPackItemId($0.info.id.id).rawValue, contents: $0) }) + updatedPacks.append(FeaturedStickerPackItem(info: info, topItems: items, unread: unreadIds.contains(info.id.id))) + } + transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, items: updatedPacks.map { OrderedItemListEntry(id: FeaturedStickerPackItemId($0.info.id.id).rawValue, contents: $0) }) } } } } |> switchToLatest } +public func requestOldFeaturedStickerPacks(network: Network, postbox: Postbox, offset: Int, limit: Int) -> Signal<[FeaturedStickerPackItem], NoError> { + return network.request(Api.functions.messages.getOldFeaturedStickers(offset: Int32(offset), limit: Int32(limit), hash: 0)) + |> retryRequest + |> map { result -> [FeaturedStickerPackItem] in + switch result { + case .featuredStickersNotModified: + return [] + case let .featuredStickers(_, _, sets, unread): + let unreadIds = Set(unread) + var updatedPacks: [FeaturedStickerPackItem] = [] + for set in sets { + let (info, items) = parsePreviewStickerSet(set) + updatedPacks.append(FeaturedStickerPackItem(info: info, topItems: items, unread: unreadIds.contains(info.id.id))) + } + return updatedPacks + } + } +} + public func preloadedFeaturedStickerSet(network: Network, postbox: Postbox, id: ItemCollectionId) -> Signal { return postbox.transaction { transaction -> Signal in if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents as? FeaturedStickerPackItem { diff --git a/submodules/TelegramUI/Sources/FeaturedStickersScreen.swift b/submodules/TelegramUI/Sources/FeaturedStickersScreen.swift index 2588ebfd43..8074a2d7d9 100644 --- a/submodules/TelegramUI/Sources/FeaturedStickersScreen.swift +++ b/submodules/TelegramUI/Sources/FeaturedStickersScreen.swift @@ -177,12 +177,23 @@ private func preparedTransition(from fromEntries: [FeaturedEntry], to toEntries: return FeaturedTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial) } -private func featuredScreenEntries(featuredEntries: [FeaturedStickerPackItem], installedPacks: Set, theme: PresentationTheme, strings: PresentationStrings, fixedUnread: Set) -> [FeaturedEntry] { +private func featuredScreenEntries(featuredEntries: [FeaturedStickerPackItem], installedPacks: Set, theme: PresentationTheme, strings: PresentationStrings, fixedUnread: Set, additionalPacks: [FeaturedStickerPackItem]) -> [FeaturedEntry] { var result: [FeaturedEntry] = [] var index = 0 + var existingIds = Set() for item in featuredEntries { - 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))) - index += 1 + 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))) + 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))) + index += 1 + } } return result } @@ -195,12 +206,18 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode { let gridNode: GridNode + private let additionalPacks = Promise<[FeaturedStickerPackItem]>([]) + private var additionalPacksValue: [FeaturedStickerPackItem] = [] + private var canLoadMore: Bool = true + private var isLoadingMore: Bool = false + private var enqueuedTransitions: [FeaturedTransition] = [] private var validLayout: ContainerViewLayout? private var disposable: Disposable? private let installDisposable = MetaDisposable() + private let loadMoreDisposable = MetaDisposable() private var searchNode: FeaturedPaneSearchContentNode? @@ -251,6 +268,12 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode { if !addedRead.isEmpty { let _ = markFeaturedStickerPacksAsSeenInteractively(postbox: strongSelf.context.account.postbox, ids: addedRead).start() } + + if bottomIndex >= strongSelf.gridNode.items.count - 15 { + if strongSelf.canLoadMore { + strongSelf.loadMore() + } + } } } @@ -405,8 +428,13 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode { return (items, fixedUnread) } - self.disposable = (combineLatest(queue: .mainQueue(), mappedFeatured, context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])]), context.sharedContext.presentationData) - |> map { featuredEntries, view, presentationData -> FeaturedTransition in + self.disposable = (combineLatest(queue: .mainQueue(), + mappedFeatured, + self.additionalPacks.get(), + context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])]), + context.sharedContext.presentationData + ) + |> map { featuredEntries, additionalPacks, view, presentationData -> FeaturedTransition in var installedPacks = Set() if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView { if let packsEntries = stickerPacksView.entriesByNamespace[Namespaces.ItemCollection.CloudStickerPacks] { @@ -415,7 +443,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode { } } } - let entries = featuredScreenEntries(featuredEntries: featuredEntries.0, installedPacks: installedPacks, theme: presentationData.theme, strings: presentationData.strings, fixedUnread: featuredEntries.1) + let entries = featuredScreenEntries(featuredEntries: featuredEntries.0, installedPacks: installedPacks, theme: presentationData.theme, strings: presentationData.strings, fixedUnread: featuredEntries.1, additionalPacks: additionalPacks) let previous = previousEntries.swap(entries) return preparedTransition(from: previous ?? [], to: entries, account: context.account, interaction: interaction, initial: previous == nil) @@ -446,6 +474,32 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode { deinit { self.disposable?.dispose() self.installDisposable.dispose() + self.loadMoreDisposable.dispose() + } + + private func loadMore() { + if self.isLoadingMore || !self.canLoadMore { + return + } + self.isLoadingMore = true + self.loadMoreDisposable.set((requestOldFeaturedStickerPacks(network: self.context.account.network, postbox: self.context.account.postbox, offset: self.additionalPacksValue.count, limit: 50) + |> deliverOnMainQueue).start(next: { [weak self] result in + guard let strongSelf = self else { + return + } + var existingIds = Set(strongSelf.additionalPacksValue.map { $0.info.id }) + var updatedItems = strongSelf.additionalPacksValue + for item in result { + if !existingIds.contains(item.info.id) { + existingIds.insert(item.info.id) + updatedItems.append(item) + } + } + strongSelf.additionalPacksValue = updatedItems + strongSelf.additionalPacks.set(.single(strongSelf.additionalPacksValue)) + strongSelf.canLoadMore = result.count >= 50 + strongSelf.isLoadingMore = false + })) } override func didLoad() {