Load additional featured packs while scrolling

This commit is contained in:
Ali 2020-04-14 18:32:04 +04:00
parent b3266c8273
commit 4e8fb6561d
5 changed files with 140 additions and 39 deletions

View File

@ -623,8 +623,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) } dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) }
dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) } dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) }
dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) } dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) }
dict[82699215] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) } dict[-958657434] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) }
dict[-123893531] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) } dict[-1230257343] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) }
dict[-2048646399] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonMissed($0) } dict[-2048646399] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonMissed($0) }
dict[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) } dict[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) }
dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) } dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) }

View File

@ -1363,22 +1363,23 @@ public struct messages {
} }
public enum FeaturedStickers: TypeConstructorDescription { public enum FeaturedStickers: TypeConstructorDescription {
case featuredStickersNotModified case featuredStickersNotModified(count: Int32)
case featuredStickers(hash: Int32, sets: [Api.StickerSetCovered], unread: [Int64]) case featuredStickers(hash: Int32, count: Int32, sets: [Api.StickerSetCovered], unread: [Int64])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .featuredStickersNotModified: case .featuredStickersNotModified(let count):
if boxed { if boxed {
buffer.appendInt32(82699215) buffer.appendInt32(-958657434)
} }
serializeInt32(count, buffer: buffer, boxed: false)
break break
case .featuredStickers(let hash, let sets, let unread): case .featuredStickers(let hash, let count, let sets, let unread):
if boxed { if boxed {
buffer.appendInt32(-123893531) buffer.appendInt32(-1230257343)
} }
serializeInt32(hash, buffer: buffer, boxed: false) serializeInt32(hash, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
buffer.appendInt32(Int32(sets.count)) buffer.appendInt32(Int32(sets.count))
for item in sets { for item in sets {
@ -1395,32 +1396,43 @@ public struct messages {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .featuredStickersNotModified: case .featuredStickersNotModified(let count):
return ("featuredStickersNotModified", []) return ("featuredStickersNotModified", [("count", count)])
case .featuredStickers(let hash, let sets, let unread): case .featuredStickers(let hash, let count, let sets, let unread):
return ("featuredStickers", [("hash", hash), ("sets", sets), ("unread", unread)]) return ("featuredStickers", [("hash", hash), ("count", count), ("sets", sets), ("unread", unread)])
} }
} }
public static func parse_featuredStickersNotModified(_ reader: BufferReader) -> FeaturedStickers? { 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? { public static func parse_featuredStickers(_ reader: BufferReader) -> FeaturedStickers? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()
var _2: [Api.StickerSetCovered]? var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.StickerSetCovered]?
if let _ = reader.readInt32() { 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() { 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 _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
if _c1 && _c2 && _c3 { let _c4 = _4 != nil
return Api.messages.FeaturedStickers.featuredStickers(hash: _1!, sets: _2!, unread: _3!) if _c1 && _c2 && _c3 && _c4 {
return Api.messages.FeaturedStickers.featuredStickers(hash: _1!, count: _2!, sets: _3!, unread: _4!)
} }
else { else {
return nil return nil

View File

@ -3276,6 +3276,22 @@ public extension Api {
return result return result
}) })
} }
public static func getOldFeaturedStickers(offset: Int32, limit: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.FeaturedStickers>) {
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 struct channels {
public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {

View File

@ -46,27 +46,46 @@ func updatedFeaturedStickerPacks(network: Network, postbox: Postbox) -> Signal<V
|> mapToSignal { result -> Signal<Void, NoError> in |> mapToSignal { result -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in return postbox.transaction { transaction -> Void in
switch result { switch result {
case .featuredStickersNotModified: case .featuredStickersNotModified:
break break
case let .featuredStickers(_, sets, unread): case let .featuredStickers(_, _, sets, unread):
let unreadIds = Set(unread) let unreadIds = Set(unread)
var updatedPacks: [FeaturedStickerPackItem] = [] var updatedPacks: [FeaturedStickerPackItem] = []
for set in sets { for set in sets {
var (info, items) = parsePreviewStickerSet(set) var (info, items) = parsePreviewStickerSet(set)
if let previousPack = initialPackMap[info.id.id] { if let previousPack = initialPackMap[info.id.id] {
if previousPack.info.hash == info.hash { if previousPack.info.hash == info.hash {
items = previousPack.topItems 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 } |> 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<Void, NoError> { public func preloadedFeaturedStickerSet(network: Network, postbox: Postbox, id: ItemCollectionId) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Signal<Void, NoError> in return postbox.transaction { transaction -> Signal<Void, NoError> in
if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents as? FeaturedStickerPackItem { if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents as? FeaturedStickerPackItem {

View File

@ -177,12 +177,23 @@ private func preparedTransition(from fromEntries: [FeaturedEntry], to toEntries:
return FeaturedTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial) return FeaturedTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial)
} }
private func featuredScreenEntries(featuredEntries: [FeaturedStickerPackItem], installedPacks: Set<ItemCollectionId>, theme: PresentationTheme, strings: PresentationStrings, fixedUnread: Set<ItemCollectionId>) -> [FeaturedEntry] { private func featuredScreenEntries(featuredEntries: [FeaturedStickerPackItem], installedPacks: Set<ItemCollectionId>, theme: PresentationTheme, strings: PresentationStrings, fixedUnread: Set<ItemCollectionId>, additionalPacks: [FeaturedStickerPackItem]) -> [FeaturedEntry] {
var result: [FeaturedEntry] = [] var result: [FeaturedEntry] = []
var index = 0 var index = 0
var existingIds = Set<ItemCollectionId>()
for item in featuredEntries { 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))) if !existingIds.contains(item.info.id) {
index += 1 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 return result
} }
@ -195,12 +206,18 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
let gridNode: GridNode 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 enqueuedTransitions: [FeaturedTransition] = []
private var validLayout: ContainerViewLayout? private var validLayout: ContainerViewLayout?
private var disposable: Disposable? private var disposable: Disposable?
private let installDisposable = MetaDisposable() private let installDisposable = MetaDisposable()
private let loadMoreDisposable = MetaDisposable()
private var searchNode: FeaturedPaneSearchContentNode? private var searchNode: FeaturedPaneSearchContentNode?
@ -251,6 +268,12 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
if !addedRead.isEmpty { if !addedRead.isEmpty {
let _ = markFeaturedStickerPacksAsSeenInteractively(postbox: strongSelf.context.account.postbox, ids: addedRead).start() 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) return (items, fixedUnread)
} }
self.disposable = (combineLatest(queue: .mainQueue(), mappedFeatured, context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])]), context.sharedContext.presentationData) self.disposable = (combineLatest(queue: .mainQueue(),
|> map { featuredEntries, view, presentationData -> FeaturedTransition in 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<ItemCollectionId>() var installedPacks = Set<ItemCollectionId>()
if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView { if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView {
if let packsEntries = stickerPacksView.entriesByNamespace[Namespaces.ItemCollection.CloudStickerPacks] { 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) let previous = previousEntries.swap(entries)
return preparedTransition(from: previous ?? [], to: entries, account: context.account, interaction: interaction, initial: previous == nil) return preparedTransition(from: previous ?? [], to: entries, account: context.account, interaction: interaction, initial: previous == nil)
@ -446,6 +474,32 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
deinit { deinit {
self.disposable?.dispose() self.disposable?.dispose()
self.installDisposable.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() { override func didLoad() {