Home telegram - groupsInCommon
Post
Cancel

telegram - groupsInCommon

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)
    }
}
This post is licensed under CC BY 4.0 by the author.