Fixes #2624, fixes #2625 - Add user suggestions in the create room flows.

This commit is contained in:
Stefan Ceriu
2024-04-01 11:37:39 +03:00
committed by Stefan Ceriu
parent c85c1593ee
commit 97d9189077
17 changed files with 252 additions and 60 deletions
@@ -18,11 +18,13 @@ import Combine
import SwiftUI
struct InviteUsersScreenCoordinatorParameters {
let selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>
let roomType: InviteUsersScreenRoomType
let clientProxy: ClientProxyProtocol
let mediaProvider: MediaProviderProtocol
let userDiscoveryService: UserDiscoveryServiceProtocol
let userIndicatorController: UserIndicatorControllerProtocol
let selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>
let roomType: InviteUsersScreenRoomType
}
enum InviteUsersScreenCoordinatorAction {
@@ -42,11 +44,12 @@ final class InviteUsersScreenCoordinator: CoordinatorProtocol {
}
init(parameters: InviteUsersScreenCoordinatorParameters) {
viewModel = InviteUsersScreenViewModel(selectedUsers: parameters.selectedUsers,
roomType: parameters.roomType,
viewModel = InviteUsersScreenViewModel(clientProxy: parameters.clientProxy,
mediaProvider: parameters.mediaProvider,
userDiscoveryService: parameters.userDiscoveryService,
userIndicatorController: parameters.userIndicatorController)
userIndicatorController: parameters.userIndicatorController,
selectedUsers: parameters.selectedUsers,
roomType: parameters.roomType)
}
func start() {
@@ -21,28 +21,42 @@ import SwiftUI
typealias InviteUsersScreenViewModelType = StateStoreViewModel<InviteUsersScreenViewState, InviteUsersScreenViewAction>
class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScreenViewModelProtocol {
private let clientProxy: ClientProxyProtocol
private let roomType: InviteUsersScreenRoomType
private let userDiscoveryService: UserDiscoveryServiceProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
private let actionsSubject: PassthroughSubject<InviteUsersScreenViewModelAction, Never> = .init()
private var suggestedUsers = [UserProfileProxy]()
private let actionsSubject: PassthroughSubject<InviteUsersScreenViewModelAction, Never> = .init()
var actions: AnyPublisher<InviteUsersScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>,
roomType: InviteUsersScreenRoomType,
init(clientProxy: ClientProxyProtocol,
mediaProvider: MediaProviderProtocol,
userDiscoveryService: UserDiscoveryServiceProtocol,
userIndicatorController: UserIndicatorControllerProtocol) {
self.roomType = roomType
userIndicatorController: UserIndicatorControllerProtocol,
selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>,
roomType: InviteUsersScreenRoomType) {
self.clientProxy = clientProxy
self.userDiscoveryService = userDiscoveryService
self.userIndicatorController = userIndicatorController
self.roomType = roomType
super.init(initialViewState: InviteUsersScreenViewState(selectedUsers: selectedUsers.value, isCreatingRoom: roomType.isCreatingRoom), imageProvider: mediaProvider)
setupSubscriptions(selectedUsers: selectedUsers)
fetchMembersIfNeeded()
Task {
suggestedUsers = await clientProxy.recentConversationCounterparts()
if state.usersSection.type == .suggestions {
state.usersSection = .init(type: .suggestions, users: suggestedUsers)
}
}
}
// MARK: - Public
@@ -127,29 +141,28 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
private func fetchUsers() {
guard searchQuery.count >= 3 else {
state.usersSection = .init(type: .suggestions, users: [])
state.usersSection = .init(type: .suggestions, users: suggestedUsers)
return
}
state.isSearching = true
fetchUsersTask = Task {
let result = await userDiscoveryService.searchProfiles(with: searchQuery)
guard !Task.isCancelled else { return }
handleResult(for: .searchResult, result: result)
state.isSearching = false
switch result {
case .success(let users):
state.usersSection = .init(type: .searchResult, users: users)
case .failure:
break
}
}
}
private func handleResult(for sectionType: UserDiscoverySectionType, result: Result<[UserProfileProxy], UserDiscoveryErrorType>) {
state.isSearching = false
switch result {
case .success(let users):
state.usersSection = .init(type: sectionType, users: users)
case .failure:
break
}
}
private var searchQuery: String {
context.searchQuery
}
@@ -160,11 +160,12 @@ struct InviteUsersScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = {
let userDiscoveryService = UserDiscoveryServiceMock()
userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice])
return InviteUsersScreenViewModel(selectedUsers: .init([]),
roomType: .draft,
return InviteUsersScreenViewModel(clientProxy: ClientProxyMock(.init()),
mediaProvider: MockMediaProvider(),
userDiscoveryService: userDiscoveryService,
userIndicatorController: UserIndicatorControllerMock())
userIndicatorController: UserIndicatorControllerMock(),
selectedUsers: .init([]),
roomType: .draft)
}()
static var previews: some View {