forked from GetStream/stream-chat-swiftui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNewChatViewModel.swift
160 lines (137 loc) · 4.25 KB
/
NewChatViewModel.swift
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//
// Copyright © 2024 Stream.io Inc. All rights reserved.
//
import StreamChat
import StreamChatSwiftUI
import SwiftUI
class NewChatViewModel: ObservableObject, ChatUserSearchControllerDelegate {
@Injected(\.chatClient) var chatClient
@Published var searchText: String = "" {
didSet {
searchUsers(with: searchText)
}
}
@Published var messageText: String = ""
@Published var chatUsers = [ChatUser]()
@Published var state: NewChatState = .initial
@Published var selectedUsers = [ChatUser]() {
didSet {
if !updatingSelectedUsers {
updatingSelectedUsers = true
if !selectedUsers.isEmpty {
do {
try makeChannelController()
} catch {
state = .error
updatingSelectedUsers = false
}
} else {
withAnimation {
state = .loaded
updatingSelectedUsers = false
}
}
}
}
}
private var loadingNextUsers: Bool = false
private var updatingSelectedUsers: Bool = false
var channelController: ChatChannelController?
private lazy var searchController: ChatUserSearchController = chatClient.userSearchController()
private let lastSeenDateFormatter = DateUtils.timeAgo
init() {
chatUsers = searchController.userArray
searchController.delegate = self
// Empty initial search to get all users
searchUsers(with: nil)
}
func userTapped(_ user: ChatUser) {
if updatingSelectedUsers {
return
}
if selectedUsers.contains(user) {
selectedUsers.removeAll { selected in
selected == user
}
} else {
selectedUsers.append(user)
}
}
func onlineInfo(for user: ChatUser) -> String {
if user.isOnline {
return "Online"
} else if let lastActiveAt = user.lastActiveAt,
let timeAgo = lastSeenDateFormatter(lastActiveAt) {
return timeAgo
} else {
return "Offline"
}
}
func isSelected(user: ChatUser) -> Bool {
selectedUsers.contains(user)
}
func onChatUserAppear(_ user: ChatUser) {
guard let index = chatUsers.firstIndex(where: { element in
user.id == element.id
}) else {
return
}
if index < chatUsers.count - 10 {
return
}
if !loadingNextUsers {
loadingNextUsers = true
searchController.loadNextUsers(limit: 50) { [weak self] _ in
guard let self = self else { return }
self.chatUsers = self.searchController.userArray
self.loadingNextUsers = false
}
}
}
// MARK: - ChatUserSearchControllerDelegate
func controller(
_ controller: ChatUserSearchController,
didChangeUsers changes: [ListChange<ChatUser>]
) {
chatUsers = controller.userArray
}
// MARK: - private
private func searchUsers(with term: String?) {
state = .loading
searchController.search(term: term) { [weak self] error in
if error != nil {
self?.state = .error
} else {
self?.state = .loaded
}
}
}
private func makeChannelController() throws {
let selectedUserIds = Set(selectedUsers.map(\.id))
channelController = try chatClient.channelController(
createDirectMessageChannelWith: selectedUserIds,
name: nil,
imageURL: nil,
extraData: [:]
)
channelController?.synchronize { [weak self] error in
if error != nil {
self?.state = .error
self?.updatingSelectedUsers = false
} else {
withAnimation {
self?.state = .channel
self?.updatingSelectedUsers = false
}
}
}
}
}
enum NewChatState {
case initial
case loading
case noUsers
case error
case loaded
case channel
}