GroupsInCommonContext
enum
GroupsInCommonDataState
1
2
case loading
case ready(canLoadMore: Bool)
struct
GroupsInCommonState
1
2
3
public var peers: [RenderedPeer]
public var count: Int?
public var dataState: GroupsInCommonDataState
class
GroupsInCommonContextImpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
private let queue: Queue
private let account: Account
// associated peerId
private let peerId: PeerId
private let hintGroupInCommon: PeerId?
// disposable
private let disposable = MetaDisposable()
// peers
private var peers: [RenderedPeer] = []
// count
private var count: Int?
// data state
private var dataState: GroupsInCommonDataState = .ready(canLoadMore: true)
// state
private let stateValue = Promise<GroupsInCommonState>()
var state: Signal<GroupsInCommonState, NoError> {
return self.stateValue.get()
}
init(queue: Queue, account: Account, peerId: PeerId, hintGroupInCommon: PeerId?) {
self.queue = queue
self.account = account
self.peerId = peerId
self.hintGroupInCommon = hintGroupInCommon
// handle hint
if let hintGroupInCommon = hintGroupInCommon {
let _ = (self.account.postbox.loadedPeerWithId(hintGroupInCommon)
|> deliverOn(self.queue)).start(next: { [weak self] peer in
if let strongSelf = self {
// update peers
strongSelf.peers.append(RenderedPeer(peer: peer))
// push state
strongSelf.pushState()
}
})
}
self.loadMore(limit: 32)
}
// load more with limit
func loadMore(limit: Int32) {
if case .ready(true) = self.dataState {
self.dataState = .loading
self.pushState()
let maxId = self.peers.last?.peerId.id
let peerId = self.peerId
let network = self.account.network
let postbox = self.account.postbox
let signal: Signal<([Peer], Int), NoError> = self.account.postbox.transaction { transaction -> Api.InputUser? in
return transaction.getPeer(peerId).flatMap(apiInputUser)
}
|> mapToSignal { inputUser -> Signal<([Peer], Int), NoError> in
guard let inputUser = inputUser else {
return .single(([], 0))
}
// Api.functions.messages.getCommonChats
return network.request(Api.functions.messages.getCommonChats(userId: inputUser, maxId: maxId?._internalGetInt64Value() ?? 0, limit: limit))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.Chats?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<([Peer], Int), NoError> in
let chats: [Api.Chat]
let count: Int?
if let result = result {
switch result {
case let .chats(apiChats):
chats = apiChats
count = nil
case let .chatsSlice(apiCount, apiChats):
chats = apiChats
count = Int(apiCount)
}
} else {
chats = []
count = nil
}
return postbox.transaction { transaction -> ([Peer], Int) in
var peers: [Peer] = []
for chat in chats {
if let peer = parseTelegramGroupOrChannel(chat: chat) {
peers.append(peer)
}
}
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer? in
return updated
})
return (peers, count ?? 0)
}
}
}
self.disposable.set((signal
|> deliverOn(self.queue)).start(next: { [weak self] (peers, count) in
guard let strongSelf = self else {
return
}
// 去重
var existingPeers = Set(strongSelf.peers.map { $0.peerId })
for peer in peers {
if !existingPeers.contains(peer.id) {
existingPeers.insert(peer.id)
strongSelf.peers.append(RenderedPeer(peer: peer))
}
}
// update data state
let updatedCount = max(strongSelf.peers.count, count)
strongSelf.count = updatedCount
strongSelf.dataState = .ready(canLoadMore: count != 0 && updatedCount > strongSelf.peers.count)
// push state
strongSelf.pushState()
}))
}
}
// push state
// notify state to external
private func pushState() {
self.stateValue.set(.single(GroupsInCommonState(peers: self.peers, count: self.count, dataState: self.dataState)))
}
class
GroupsInCommonContext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private let queue: Queue = .mainQueue()
private let impl: QueueLocalObject<GroupsInCommonContextImpl>
// wrapped state
public var state: Signal<GroupsInCommonState, NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
self.impl.with { impl in
disposable.set(impl.state.start(next: { value in
subscriber.putNext(value)
}))
}
return disposable
}
}
public init(account: Account, peerId: PeerId, hintGroupInCommon: PeerId? = nil) {
let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: {
return GroupsInCommonContextImpl(queue: queue, account: account, peerId: peerId, hintGroupInCommon: hintGroupInCommon)
})
}
// wrapped load more with default limit 32
public func loadMore() {
self.impl.with { impl in
impl.loadMore(limit: 32)
}
}