mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 03:09:56 +00:00
Update API
This commit is contained in:
parent
3945acbe01
commit
3547bb0f2a
@ -144,6 +144,7 @@ public struct Namespaces {
|
||||
public static let channelsForPublicReaction: Int8 = 45
|
||||
public static let cachedGroupsInCommon: Int8 = 46
|
||||
public static let groupCallPersistentSettings: Int8 = 47
|
||||
public static let cachedProfileGiftsCollections: Int8 = 48
|
||||
}
|
||||
|
||||
public struct UnorderedItemList {
|
||||
|
||||
@ -1162,9 +1162,16 @@ private final class CachedProfileGifts: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
private func entryId(peerId: EnginePeer.Id) -> ItemCacheEntryId {
|
||||
let cacheKey = ValueBoxKey(length: 8)
|
||||
cacheKey.setInt64(0, value: peerId.toInt64())
|
||||
private func entryId(peerId: EnginePeer.Id, collectionId: Int32?) -> ItemCacheEntryId {
|
||||
let cacheKey: ValueBoxKey
|
||||
if let collectionId {
|
||||
cacheKey = ValueBoxKey(length: 8 + 4)
|
||||
cacheKey.setInt64(0, value: peerId.toInt64())
|
||||
cacheKey.setInt32(8, value: collectionId)
|
||||
} else {
|
||||
cacheKey = ValueBoxKey(length: 8)
|
||||
cacheKey.setInt64(0, value: peerId.toInt64())
|
||||
}
|
||||
return ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedProfileGifts, key: cacheKey)
|
||||
}
|
||||
|
||||
@ -1172,6 +1179,7 @@ private final class ProfileGiftsContextImpl {
|
||||
private let queue: Queue
|
||||
private let account: Account
|
||||
private let peerId: PeerId
|
||||
private let collectionId: Int32?
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
private let cacheDisposable = MetaDisposable()
|
||||
@ -1200,12 +1208,14 @@ private final class ProfileGiftsContextImpl {
|
||||
queue: Queue,
|
||||
account: Account,
|
||||
peerId: EnginePeer.Id,
|
||||
collectionId: Int32?,
|
||||
sorting: ProfileGiftsContext.Sorting,
|
||||
filter: ProfileGiftsContext.Filters
|
||||
) {
|
||||
self.queue = queue
|
||||
self.account = account
|
||||
self.peerId = peerId
|
||||
self.collectionId = collectionId
|
||||
self.sorting = sorting
|
||||
self.filter = filter
|
||||
|
||||
@ -1226,6 +1236,7 @@ private final class ProfileGiftsContextImpl {
|
||||
|
||||
func loadMore(reload: Bool = false) {
|
||||
let peerId = self.peerId
|
||||
let collectionId = self.collectionId
|
||||
let accountPeerId = self.account.peerId
|
||||
let network = self.account.network
|
||||
let postbox = self.account.postbox
|
||||
@ -1244,7 +1255,7 @@ private final class ProfileGiftsContextImpl {
|
||||
if case let .ready(true, initialNextOffset) = dataState {
|
||||
if !isFiltered || isUniqueOnlyFilter, self.gifts.isEmpty, initialNextOffset == nil, !reload {
|
||||
self.cacheDisposable.set((self.account.postbox.transaction { transaction -> CachedProfileGifts? in
|
||||
let cachedGifts = transaction.retrieveItemCacheEntry(id: entryId(peerId: peerId))?.get(CachedProfileGifts.self)
|
||||
let cachedGifts = transaction.retrieveItemCacheEntry(id: entryId(peerId: peerId, collectionId: collectionId))?.get(CachedProfileGifts.self)
|
||||
cachedGifts?.render(transaction: transaction)
|
||||
return cachedGifts
|
||||
} |> deliverOn(self.queue)).start(next: { [weak self] cachedGifts in
|
||||
@ -1292,6 +1303,9 @@ private final class ProfileGiftsContextImpl {
|
||||
return .single(([], 0, nil, nil))
|
||||
}
|
||||
var flags: Int32 = 0
|
||||
if let _ = collectionId {
|
||||
flags |= (1 << 6)
|
||||
}
|
||||
if case .value = sorting {
|
||||
flags |= (1 << 5)
|
||||
}
|
||||
@ -1310,7 +1324,7 @@ private final class ProfileGiftsContextImpl {
|
||||
if !filter.contains(.unique) {
|
||||
flags |= (1 << 4)
|
||||
}
|
||||
return network.request(Api.functions.payments.getSavedStarGifts(flags: flags, peer: inputPeer, collectionId: nil, offset: initialNextOffset ?? "", limit: 36))
|
||||
return network.request(Api.functions.payments.getSavedStarGifts(flags: flags, peer: inputPeer, collectionId: collectionId, offset: initialNextOffset ?? "", limit: 36))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.payments.SavedStarGifts?, NoError> in
|
||||
return .single(nil)
|
||||
@ -1363,7 +1377,7 @@ private final class ProfileGiftsContextImpl {
|
||||
self.gifts = gifts
|
||||
self.cacheDisposable.set(self.account.postbox.transaction { transaction in
|
||||
if let entry = CodableEntry(CachedProfileGifts(gifts: gifts, count: count, notificationsEnabled: notificationsEnabled)) {
|
||||
transaction.putItemCacheEntry(id: entryId(peerId: peerId), entry: entry)
|
||||
transaction.putItemCacheEntry(id: entryId(peerId: peerId, collectionId: collectionId), entry: entry)
|
||||
}
|
||||
}.start())
|
||||
} else {
|
||||
@ -2063,12 +2077,13 @@ public final class ProfileGiftsContext {
|
||||
public init(
|
||||
account: Account,
|
||||
peerId: EnginePeer.Id,
|
||||
collectionId: Int32? = nil,
|
||||
sorting: ProfileGiftsContext.Sorting = .date,
|
||||
filter: ProfileGiftsContext.Filters = .All
|
||||
) {
|
||||
let queue = self.queue
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return ProfileGiftsContextImpl(queue: queue, account: account, peerId: peerId, sorting: sorting, filter: filter)
|
||||
return ProfileGiftsContextImpl(queue: queue, account: account, peerId: peerId, collectionId: collectionId, sorting: sorting, filter: filter)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,407 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import MtProtoKit
|
||||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
|
||||
public struct StarGiftCollection: Codable, Equatable {
|
||||
public let id: Int32
|
||||
public let title: String
|
||||
public let icon: TelegramMediaFile?
|
||||
public let count: Int32
|
||||
public let hash: Int64
|
||||
|
||||
public init(id: Int32, title: String, icon: TelegramMediaFile?, count: Int32, hash: Int64) {
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.icon = icon
|
||||
self.count = count
|
||||
self.hash = hash
|
||||
}
|
||||
|
||||
public static func ==(lhs: StarGiftCollection, rhs: StarGiftCollection) -> Bool {
|
||||
if lhs.id != rhs.id {
|
||||
return false
|
||||
}
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
if lhs.icon != rhs.icon {
|
||||
return false
|
||||
}
|
||||
if lhs.count != rhs.count {
|
||||
return false
|
||||
}
|
||||
if lhs.hash != rhs.hash {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension StarGiftCollection {
|
||||
init?(apiStarGiftCollection: Api.StarGiftCollection) {
|
||||
switch apiStarGiftCollection {
|
||||
case let .starGiftCollection(_, collectionId, title, icon, giftsCount, hash):
|
||||
self.id = collectionId
|
||||
self.title = title
|
||||
self.icon = icon.flatMap { telegramMediaFileFromApiDocument($0, altDocuments: nil) }
|
||||
self.count = giftsCount
|
||||
self.hash = hash
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class CachedProfileGiftsCollections: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case collections
|
||||
}
|
||||
|
||||
let collections: [StarGiftCollection]
|
||||
|
||||
init(collections: [StarGiftCollection]) {
|
||||
self.collections = collections
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.collections = try container.decode([StarGiftCollection].self, forKey: .collections)
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.collections, forKey: .collections)
|
||||
}
|
||||
}
|
||||
|
||||
private func entryId(peerId: EnginePeer.Id) -> ItemCacheEntryId {
|
||||
let cacheKey = ValueBoxKey(length: 8)
|
||||
cacheKey.setInt64(0, value: peerId.toInt64())
|
||||
return ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedProfileGiftsCollections, key: cacheKey)
|
||||
}
|
||||
|
||||
private func intListSimpleHash(_ list: [Int64]) -> Int64 {
|
||||
var acc: Int64 = 0
|
||||
for value in list {
|
||||
acc = ((acc * 20261) + Int64(0x80000000) + Int64(value)) % Int64(0x80000000)
|
||||
}
|
||||
return Int64(Int32(truncatingIfNeeded: acc))
|
||||
}
|
||||
|
||||
private func _internal_getStarGiftCollections(postbox: Postbox, network: Network, peerId: EnginePeer.Id) -> Signal<[StarGiftCollection]?, NoError> {
|
||||
return postbox.transaction { transaction -> (Api.InputPeer, [StarGiftCollection]?)? in
|
||||
guard let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer) else {
|
||||
return nil
|
||||
}
|
||||
let collections = transaction.retrieveItemCacheEntry(id: entryId(peerId: peerId))?.get(CachedProfileGiftsCollections.self)
|
||||
return (inputPeer, collections?.collections)
|
||||
}
|
||||
|> mapToSignal { inputPeerAndHash -> Signal<[StarGiftCollection]?, NoError> in
|
||||
guard let (inputPeer, cachedCollections) = inputPeerAndHash else {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
var hash: Int64 = 0
|
||||
if let cachedCollections {
|
||||
hash = intListSimpleHash(cachedCollections.map { $0.hash })
|
||||
}
|
||||
|
||||
return network.request(Api.functions.payments.getStarGiftCollections(peer: inputPeer, hash: hash))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.payments.StarGiftCollections?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<[StarGiftCollection]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
return postbox.transaction { transaction -> [StarGiftCollection]? in
|
||||
switch result {
|
||||
case let .starGiftCollections(collections):
|
||||
let collections = collections.compactMap { StarGiftCollection(apiStarGiftCollection: $0) }
|
||||
if let entry = CodableEntry(CachedProfileGiftsCollections(collections: collections)) {
|
||||
transaction.putItemCacheEntry(id: entryId(peerId: peerId), entry: entry)
|
||||
}
|
||||
return collections
|
||||
case .starGiftCollectionsNotModified:
|
||||
return cachedCollections ?? []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func _internal_createStarGiftCollection(account: Account, peerId: EnginePeer.Id, title: String, starGifts: [StarGiftReference]) -> Signal<StarGiftCollection?, NoError> {
|
||||
return account.postbox.transaction { transaction -> (Api.InputPeer, [Api.InputSavedStarGift])? in
|
||||
guard let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer) else {
|
||||
return nil
|
||||
}
|
||||
let inputStarGifts = starGifts.compactMap { $0.apiStarGiftReference(transaction: transaction) }
|
||||
return (inputPeer, inputStarGifts)
|
||||
}
|
||||
|> mapToSignal { inputPeerAndGifts -> Signal<StarGiftCollection?, NoError> in
|
||||
guard let (inputPeer, inputStarGifts) = inputPeerAndGifts else {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.payments.createStarGiftCollection(peer: inputPeer, title: title, stargift: inputStarGifts))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.StarGiftCollection?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> StarGiftCollection? in
|
||||
guard let result else {
|
||||
return nil
|
||||
}
|
||||
return StarGiftCollection(apiStarGiftCollection: result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func _internal_reorderStarGiftCollections(account: Account, peerId: EnginePeer.Id, order: [Int32]) -> Signal<Bool, NoError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<Bool, NoError> in
|
||||
guard let inputPeer else {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.payments.reorderStarGiftCollections(peer: inputPeer, order: order))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.Bool?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> Bool in
|
||||
if let result, case .boolTrue = result {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func _internal_updateStarGiftCollection(account: Account, peerId: EnginePeer.Id, collectionId: Int32, actions: [StarGiftCollectionsContext.UpdateAction]) -> Signal<StarGiftCollection?, NoError> {
|
||||
return account.postbox.transaction { transaction -> (Api.InputPeer, (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.StarGiftCollection>))? in
|
||||
guard let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var flags: Int32 = 0
|
||||
var title: String?
|
||||
var deleteStarGift: [Api.InputSavedStarGift] = []
|
||||
var addStarGift: [Api.InputSavedStarGift] = []
|
||||
var order: [Api.InputSavedStarGift] = []
|
||||
|
||||
for action in actions {
|
||||
switch action {
|
||||
case let .updateTitle(newTitle):
|
||||
flags |= (1 << 0)
|
||||
title = newTitle
|
||||
case let .addGifts(gifts):
|
||||
flags |= (1 << 2)
|
||||
addStarGift.append(contentsOf: gifts.compactMap { $0.apiStarGiftReference(transaction: transaction) })
|
||||
case let .removeGifts(gifts):
|
||||
flags |= (1 << 1)
|
||||
deleteStarGift.append(contentsOf: gifts.compactMap { $0.apiStarGiftReference(transaction: transaction) })
|
||||
case let .reorderGifts(gifts):
|
||||
flags |= (1 << 3)
|
||||
order = gifts.compactMap { $0.apiStarGiftReference(transaction: transaction) }
|
||||
}
|
||||
}
|
||||
|
||||
let request = Api.functions.payments.updateStarGiftCollection(flags: flags, peer: inputPeer, collectionId: collectionId, title: title, deleteStargift: deleteStarGift, addStargift: addStarGift, order: order)
|
||||
|
||||
return (inputPeer, request)
|
||||
}
|
||||
|> mapToSignal { peerAndRequest -> Signal<StarGiftCollection?, NoError> in
|
||||
guard let (_, request) = peerAndRequest else {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
return account.network.request(request)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.StarGiftCollection?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> StarGiftCollection? in
|
||||
guard let result else {
|
||||
return nil
|
||||
}
|
||||
return StarGiftCollection(apiStarGiftCollection: result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func _internal_deleteStarGiftCollection(account: Account, peerId: EnginePeer.Id, collectionId: Int32) -> Signal<Bool, NoError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<Bool, NoError> in
|
||||
guard let inputPeer else {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.payments.deleteStarGiftCollection(peer: inputPeer, collectionId: collectionId))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.Bool?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> Bool in
|
||||
if let result, case .boolTrue = result {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class StarGiftCollectionsContext {
|
||||
public struct State: Equatable {
|
||||
public var collections: [StarGiftCollection]
|
||||
public var isLoading: Bool
|
||||
}
|
||||
|
||||
public enum UpdateAction {
|
||||
case updateTitle(String)
|
||||
case addGifts([StarGiftReference])
|
||||
case removeGifts([StarGiftReference])
|
||||
case reorderGifts([StarGiftReference])
|
||||
}
|
||||
|
||||
private let queue: Queue = .mainQueue()
|
||||
private let account: Account
|
||||
private let peerId: EnginePeer.Id
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
private var collections: [StarGiftCollection] = []
|
||||
private var isLoading: Bool = false
|
||||
|
||||
private let stateValue = Promise<State>()
|
||||
public var state: Signal<State, NoError> {
|
||||
return self.stateValue.get()
|
||||
}
|
||||
|
||||
public init(account: Account, peerId: EnginePeer.Id) {
|
||||
self.account = account
|
||||
self.peerId = peerId
|
||||
|
||||
self.reload()
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
public func reload() {
|
||||
guard !self.isLoading else { return }
|
||||
|
||||
self.isLoading = true
|
||||
self.pushState()
|
||||
|
||||
self.disposable.set((_internal_getStarGiftCollections(postbox: self.account.postbox, network: self.account.network, peerId: self.peerId)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] collections in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.collections = collections ?? []
|
||||
self.isLoading = false
|
||||
self.pushState()
|
||||
}))
|
||||
}
|
||||
|
||||
public func createCollection(title: String, starGifts: [StarGiftReference]) -> Signal<StarGiftCollection?, NoError> {
|
||||
return _internal_createStarGiftCollection(account: self.account, peerId: self.peerId, title: title, starGifts: starGifts)
|
||||
|> deliverOn(self.queue)
|
||||
|> afterNext { [weak self] collection in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let collection {
|
||||
self.collections.append(collection)
|
||||
self.pushState()
|
||||
}
|
||||
self.reload()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateCollection(id: Int32, actions: [UpdateAction]) -> Signal<StarGiftCollection?, NoError> {
|
||||
return _internal_updateStarGiftCollection(account: self.account, peerId: self.peerId, collectionId: id, actions: actions)
|
||||
|> deliverOn(self.queue)
|
||||
|> afterNext { [weak self] collection in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let collection {
|
||||
if let index = self.collections.firstIndex(where: { $0.id == id }) {
|
||||
self.collections[index] = collection
|
||||
self.pushState()
|
||||
}
|
||||
}
|
||||
self.reload()
|
||||
}
|
||||
}
|
||||
|
||||
public func addGifts(id: Int32, gifts: [StarGiftReference]) -> Signal<StarGiftCollection?, NoError> {
|
||||
return self.updateCollection(id: id, actions: [.addGifts(gifts)])
|
||||
}
|
||||
|
||||
public func removeGifts(id: Int32, gifts: [StarGiftReference]) -> Signal<StarGiftCollection?, NoError> {
|
||||
return self.updateCollection(id: id, actions: [.addGifts(gifts)])
|
||||
}
|
||||
|
||||
public func reorderGifts(id: Int32, gifts: [StarGiftReference]) -> Signal<StarGiftCollection?, NoError> {
|
||||
return self.updateCollection(id: id, actions: [.reorderGifts(gifts)])
|
||||
}
|
||||
|
||||
public func renameCollection(id: Int32, title: String) -> Signal<StarGiftCollection?, NoError> {
|
||||
return self.updateCollection(id: id, actions: [.updateTitle(title)])
|
||||
}
|
||||
|
||||
public func reorderCollections(order: [Int32]) -> Signal<Bool, NoError> {
|
||||
return _internal_reorderStarGiftCollections(account: self.account, peerId: self.peerId, order: order)
|
||||
|> deliverOn(self.queue)
|
||||
|> afterNext { [weak self] collection in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var collectionMap: [Int32: StarGiftCollection] = [:]
|
||||
for collection in self.collections {
|
||||
collectionMap[collection.id] = collection
|
||||
}
|
||||
var collections: [StarGiftCollection] = []
|
||||
for id in order {
|
||||
if let collection = collectionMap[id] {
|
||||
collections.append(collection)
|
||||
}
|
||||
}
|
||||
self.collections = collections
|
||||
self.pushState()
|
||||
self.reload()
|
||||
}
|
||||
}
|
||||
|
||||
public func deleteCollection(id: Int32) -> Signal<Bool, NoError> {
|
||||
return _internal_deleteStarGiftCollection(account: self.account, peerId: self.peerId, collectionId: id)
|
||||
|> deliverOn(self.queue)
|
||||
|> afterNext { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.collections.removeAll(where: { $0.id == id })
|
||||
self.pushState()
|
||||
self.reload()
|
||||
}
|
||||
}
|
||||
|
||||
private func pushState() {
|
||||
let state = State(
|
||||
collections: self.collections,
|
||||
isLoading: self.isLoading
|
||||
)
|
||||
self.stateValue.set(.single(state))
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user