Swiftgram/submodules/TelegramCore/Sources/MessageReactionList.swift
2020-05-27 19:48:56 +04:00

211 lines
8.1 KiB
Swift

import Foundation
import Postbox
import SwiftSignalKit
import TelegramApi
import MtProtoKit
import SyncCore
public enum MessageReactionListCategory: Hashable {
case all
case reaction(String)
}
public final class MessageReactionListCategoryItem: Equatable {
public let peer: Peer
public let reaction: String
init(peer: Peer, reaction: String) {
self.peer = peer
self.reaction = reaction
}
public static func ==(lhs: MessageReactionListCategoryItem, rhs: MessageReactionListCategoryItem) -> Bool {
if lhs.peer.id != rhs.peer.id {
return false
}
if lhs.reaction != rhs.reaction {
return false
}
return true
}
}
public struct MessageReactionListCategoryState: Equatable {
public var count: Int
public var completed: Bool
public var items: [MessageReactionListCategoryItem]
public var loadingMore: Bool
fileprivate var nextOffset: String?
}
private enum LoadReactionsError {
case generic
}
private final class MessageReactionCategoryContext {
private let postbox: Postbox
private let network: Network
private let messageId: MessageId
private let category: MessageReactionListCategory
private var state: MessageReactionListCategoryState
var statePromise: ValuePromise<MessageReactionListCategoryState>
private let loadingDisposable = MetaDisposable()
init(postbox: Postbox, network: Network, messageId: MessageId, category: MessageReactionListCategory, initialState: MessageReactionListCategoryState) {
self.postbox = postbox
self.network = network
self.messageId = messageId
self.category = category
self.state = initialState
self.statePromise = ValuePromise(initialState)
}
deinit {
self.loadingDisposable.dispose()
}
func loadMore() {
if self.state.completed || self.state.loadingMore {
return
}
/*self.state.loadingMore = true
self.statePromise.set(self.state)
var flags: Int32 = 0
var reaction: String?
switch self.category {
case .all:
break
case let .reaction(value):
flags |= 1 << 0
reaction = value
}
let messageId = self.messageId
let offset = self.state.nextOffset
var request = self.postbox.transaction { transaction -> Api.InputPeer? in
let inputPeer = transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
return inputPeer
}
|> castError(LoadReactionsError.self)
|> mapToSignal { inputPeer -> Signal<Api.messages.MessageReactionsList, LoadReactionsError> in
guard let inputPeer = inputPeer else {
return .fail(.generic)
}
return self.network.request(Api.functions.messages.getMessageReactionsList(flags: flags, peer: inputPeer, id: messageId.id, reaction: reaction, offset: offset, limit: 64))
|> mapError { _ -> LoadReactionsError in
return .generic
}
}
//#if DEBUG
//request = request |> delay(1.0, queue: .mainQueue())
//#endif
self.loadingDisposable.set((request
|> deliverOnMainQueue).start(next: { [weak self] result in
guard let strongSelf = self else {
return
}
let currentState = strongSelf.state
let _ = (strongSelf.postbox.transaction { transaction -> MessageReactionListCategoryState in
var mergedItems = currentState.items
var currentIds = Set(mergedItems.lazy.map { $0.peer.id })
switch result {
case let .messageReactionsList(_, count, reactions, users, nextOffset):
var peers: [Peer] = []
for user in users {
let parsedUser = TelegramUser(user: user)
peers.append(parsedUser)
}
updatePeers(transaction: transaction, peers: peers, update: { _, updated in updated })
for reaction in reactions {
switch reaction {
case let .messageUserReaction(userId, reaction):
if let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) {
if !currentIds.contains(peer.id) {
currentIds.insert(peer.id)
mergedItems.append(MessageReactionListCategoryItem(peer: peer, reaction: reaction))
}
}
}
}
return MessageReactionListCategoryState(count: max(mergedItems.count, Int(count)), completed: nextOffset == nil, items: mergedItems, loadingMore: false, nextOffset: nextOffset)
}
}
|> deliverOnMainQueue).start(next: { state in
guard let strongSelf = self else {
return
}
strongSelf.state = state
strongSelf.statePromise.set(state)
})
}, error: { _ in
}))*/
}
}
public struct MessageReactionListState: Equatable {
public var states: [(MessageReactionListCategory, MessageReactionListCategoryState)]
public static func ==(lhs: MessageReactionListState, rhs: MessageReactionListState) -> Bool {
if lhs.states.count != rhs.states.count {
return false
}
for i in 0 ..< lhs.states.count {
if lhs.states[i].0 != rhs.states[i].0 {
return false
}
if lhs.states[i].1 != rhs.states[i].1 {
return false
}
}
return true
}
}
public final class MessageReactionListContext {
private let postbox: Postbox
private let network: Network
private var categoryContexts: [MessageReactionListCategory: MessageReactionCategoryContext] = [:]
private let _state = Promise<MessageReactionListState>()
public var state: Signal<MessageReactionListState, NoError> {
return self._state.get()
}
public init(postbox: Postbox, network: Network, messageId: MessageId, initialReactions: [MessageReaction]) {
self.postbox = postbox
self.network = network
var allState = MessageReactionListCategoryState(count: 0, completed: false, items: [], loadingMore: false, nextOffset: nil)
var signals: [Signal<(MessageReactionListCategory, MessageReactionListCategoryState), NoError>] = []
for reaction in initialReactions {
allState.count += Int(reaction.count)
let context = MessageReactionCategoryContext(postbox: postbox, network: network, messageId: messageId, category: .reaction(reaction.value), initialState: MessageReactionListCategoryState(count: Int(reaction.count), completed: false, items: [], loadingMore: false, nextOffset: nil))
signals.append(context.statePromise.get() |> map { value -> (MessageReactionListCategory, MessageReactionListCategoryState) in
return (.reaction(reaction.value), value)
})
self.categoryContexts[.reaction(reaction.value)] = context
context.loadMore()
}
let allContext = MessageReactionCategoryContext(postbox: postbox, network: network, messageId: messageId, category: .all, initialState: allState)
signals.insert(allContext.statePromise.get() |> map { value -> (MessageReactionListCategory, MessageReactionListCategoryState) in
return (.all, value)
}, at: 0)
self.categoryContexts[.all] = allContext
self._state.set(combineLatest(queue: .mainQueue(), signals)
|> map { states in
return MessageReactionListState(states: states)
})
allContext.loadMore()
}
public func loadMore(category: MessageReactionListCategory) {
self.categoryContexts[category]?.loadMore()
}
}