mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Implement Knock Logic (#3573)
* WIP RequestToJoin struct * implemented the logic to display the cells * knock request banner accept flow * mark all knocks as seen implemented * details logic * implemented accept, decline and ban in the list * added a loader and modified the stacked view of the banner * pr suggestions * updated naming and loading strings * added the initial loading state improved code and the tests * updated a string that has changed * code improvement * tests for the room screen view model * room details tests and improved the knock requests tests for the room screen * knock requests list tests * added error state alerts with retry * struct has been renamed on the sdk so I renamed it also on the app side * update SDK
This commit is contained in:
@@ -103,12 +103,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
case .resolvePinViolation(let userID):
|
||||
Task { await resolveIdentityPinningViolation(userID) }
|
||||
}
|
||||
case .acceptKnock(userID: let userID):
|
||||
// TODO: API to accept a knock required
|
||||
break
|
||||
case .acceptKnock(let eventID):
|
||||
Task { await acceptKnock(eventID: eventID) }
|
||||
case .dismissKnockRequests:
|
||||
// TODO: API to mark knocks as seen required
|
||||
break
|
||||
Task { await markAllKnocksAsSeen() }
|
||||
case .viewKnockRequests:
|
||||
actionsSubject.send(.displayKnockRequests)
|
||||
}
|
||||
@@ -181,6 +179,23 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
state.shouldShowCallButton = ongoingCallRoomID != roomProxy.id
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
roomProxy.knockRequestsStatePublisher
|
||||
// We only care about unseen requests
|
||||
.map { knockRequestsState in
|
||||
guard case let .loaded(requests) = knockRequestsState else {
|
||||
return []
|
||||
}
|
||||
|
||||
return requests
|
||||
.filter { !$0.isSeen }
|
||||
.map(KnockRequestInfo.init)
|
||||
}
|
||||
// If the requests have the same event ids we can discard the output
|
||||
.removeDuplicates { Set($0.map(\.eventID)) == Set($1.map(\.eventID)) }
|
||||
.throttle(for: .milliseconds(100), scheduler: DispatchQueue.main, latest: true)
|
||||
.weakAssign(to: \.state.unseenKnockRequests, on: self)
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func processIdentityStatusChanges(_ changes: [IdentityStatusChange]) async {
|
||||
@@ -277,10 +292,49 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func acceptKnock(eventID: String) async {
|
||||
guard case let .loaded(requests) = roomProxy.knockRequestsStatePublisher.value,
|
||||
let request = requests.first(where: { $0.eventID == eventID }) else {
|
||||
return
|
||||
}
|
||||
|
||||
state.handledEventIDs.insert(eventID)
|
||||
switch await request.accept() {
|
||||
case .success:
|
||||
break
|
||||
case .failure:
|
||||
userIndicatorController.submitIndicator(.init(id: Self.errorIndicatorIdentifier, type: .toast, title: L10n.errorUnknown))
|
||||
state.handledEventIDs.remove(eventID)
|
||||
}
|
||||
}
|
||||
|
||||
private func markAllKnocksAsSeen() async {
|
||||
guard case let .loaded(requests) = roomProxy.knockRequestsStatePublisher.value else {
|
||||
return
|
||||
}
|
||||
state.handledEventIDs.formUnion(Set(requests.map(\.eventID)))
|
||||
|
||||
let failedIDs = await withTaskGroup(of: (String, Result<Void, KnockRequestProxyError>).self) { group in
|
||||
for request in requests {
|
||||
group.addTask {
|
||||
await (request.eventID, request.markAsSeen())
|
||||
}
|
||||
}
|
||||
|
||||
var failedIDs = [String]()
|
||||
for await result in group where result.1.isFailure {
|
||||
failedIDs.append(result.0)
|
||||
}
|
||||
return failedIDs
|
||||
}
|
||||
state.handledEventIDs.subtract(failedIDs)
|
||||
}
|
||||
|
||||
// MARK: Loading indicators
|
||||
|
||||
private static let loadingIndicatorIdentifier = "\(RoomScreenViewModel.self)-Loading"
|
||||
private static let errorIndicatorIdentifier = "\(RoomScreenViewModel.self)-Error"
|
||||
|
||||
private func showLoadingIndicator() {
|
||||
userIndicatorController.submitIndicator(.init(id: Self.loadingIndicatorIdentifier, type: .toast, title: L10n.commonLoading))
|
||||
@@ -304,3 +358,13 @@ extension RoomScreenViewModel {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}
|
||||
}
|
||||
|
||||
private extension KnockRequestInfo {
|
||||
init(from proxy: KnockRequestProxyProtocol) {
|
||||
self.init(displayName: proxy.displayName,
|
||||
avatarURL: proxy.avatarURL,
|
||||
userID: proxy.userID,
|
||||
reason: proxy.reason,
|
||||
eventID: proxy.eventID)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user