mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Knocked Preview implementation (#3426)
* JoinRoomScreen ui for knocking * code improvement * updated previews * added knocked state with tests * send knock request * Apply suggestions from code review Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * pr comments * update tests * new API * knock implementation and cancel knock * update strings * added a knocked cell in the home screen * design update * updated SDK * simplified the invite case code * pr comments * updated previews * added message as reason * updated strings * fixing tests --------- Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com>
This commit is contained in:
@@ -49,7 +49,7 @@ final class JoinRoomScreenCoordinator: CoordinatorProtocol {
|
||||
switch action {
|
||||
case .joined:
|
||||
actionsSubject.send(.joined)
|
||||
case .cancelled:
|
||||
case .dismiss:
|
||||
actionsSubject.send(.cancelled)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import Foundation
|
||||
|
||||
enum JoinRoomScreenViewModelAction {
|
||||
case joined
|
||||
case cancelled
|
||||
case dismiss
|
||||
}
|
||||
|
||||
enum JoinRoomScreenInteractionMode {
|
||||
@@ -65,6 +65,7 @@ struct JoinRoomScreenViewStateBindings {
|
||||
|
||||
enum JoinRoomScreenAlertType {
|
||||
case declineInvite
|
||||
case cancelKnock
|
||||
}
|
||||
|
||||
enum JoinRoomScreenViewAction {
|
||||
|
||||
@@ -59,8 +59,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
||||
case .declineInvite:
|
||||
showDeclineInviteConfirmationAlert()
|
||||
case .cancelKnock:
|
||||
// TODO: implement once available
|
||||
break
|
||||
showCancelKnockConfirmationAlert()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,15 +77,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
||||
Task { await updateRoomDetails() }
|
||||
}
|
||||
|
||||
// Using only the preview API isn't enough as it's not capable
|
||||
// of giving us information for non-joined rooms (at least not on synapse)
|
||||
// See if we known about the room locally and, if so, have that
|
||||
// take priority over the preview one.
|
||||
|
||||
if let room = await clientProxy.roomForIdentifier(roomID) {
|
||||
self.room = room
|
||||
await updateRoomDetails()
|
||||
}
|
||||
await updateRoom()
|
||||
|
||||
switch await clientProxy.roomPreviewForIdentifier(roomID, via: via) {
|
||||
case .success(let roomPreviewDetails):
|
||||
@@ -99,6 +90,17 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
||||
}
|
||||
}
|
||||
|
||||
private func updateRoom() async {
|
||||
// Using only the preview API isn't enough as it's not capable
|
||||
// of giving us information for non-joined rooms (at least not on synapse)
|
||||
// See if we known about the room locally and, if so, have that
|
||||
// take priority over the preview one.
|
||||
if let room = await clientProxy.roomForIdentifier(roomID) {
|
||||
self.room = room
|
||||
await updateRoomDetails()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateRoomDetails() async {
|
||||
var roomProxy: RoomProxyProtocol?
|
||||
var inviter: RoomInviterDetails?
|
||||
@@ -188,7 +190,8 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
||||
switch await clientProxy.knockRoomAlias(alias,
|
||||
message: state.bindings.knockMessage.isBlank ? nil : state.bindings.knockMessage) {
|
||||
case .success:
|
||||
state.mode = .knocked
|
||||
// The room should become knocked through the sync
|
||||
await updateRoom()
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed knocking room alias: \(alias) with error: \(error)")
|
||||
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
|
||||
@@ -198,7 +201,8 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
||||
via: via,
|
||||
message: state.bindings.knockMessage.isBlank ? nil : state.bindings.knockMessage) {
|
||||
case .success:
|
||||
state.mode = .knocked
|
||||
// The room should become knocked through the sync
|
||||
await updateRoom()
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed knocking room id: \(roomID) with error: \(error)")
|
||||
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
|
||||
@@ -220,6 +224,14 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
||||
secondaryButton: .init(title: L10n.actionDecline, role: .destructive, action: { Task { await self.declineInvite() } }))
|
||||
}
|
||||
|
||||
private func showCancelKnockConfirmationAlert() {
|
||||
state.bindings.alertInfo = .init(id: .cancelKnock,
|
||||
title: L10n.screenJoinRoomCancelKnockAlertTitle,
|
||||
message: L10n.screenJoinRoomCancelKnockAlertDescription,
|
||||
primaryButton: .init(title: L10n.actionNo, role: .cancel, action: nil),
|
||||
secondaryButton: .init(title: L10n.screenJoinRoomCancelKnockAlertConfirmation, role: .destructive, action: { Task { await self.cancelKnock() } }))
|
||||
}
|
||||
|
||||
private func declineInvite() async {
|
||||
defer {
|
||||
userIndicatorController.retractIndicatorWithId(roomID)
|
||||
@@ -236,6 +248,29 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
||||
|
||||
if case .failure = result {
|
||||
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
|
||||
} else {
|
||||
actionsSubject.send(.dismiss)
|
||||
}
|
||||
}
|
||||
|
||||
private func cancelKnock() async {
|
||||
defer {
|
||||
userIndicatorController.retractIndicatorWithId(roomID)
|
||||
}
|
||||
|
||||
userIndicatorController.submitIndicator(UserIndicator(id: roomID, type: .modal, title: L10n.commonLoading, persistent: true))
|
||||
|
||||
guard case let .knocked(roomProxy) = room else {
|
||||
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
|
||||
return
|
||||
}
|
||||
|
||||
let result = await roomProxy.cancelKnock()
|
||||
|
||||
if case .failure = result {
|
||||
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
|
||||
} else {
|
||||
actionsSubject.send(.dismiss)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ struct JoinRoomScreen: View {
|
||||
@ObservedObject var context: JoinRoomScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
FullscreenDialog(topPadding: 80, background: .bloom) {
|
||||
FullscreenDialog(topPadding: context.viewState.mode == .knocked ? 151 : 35, background: .bloom) {
|
||||
if context.viewState.mode == .loading {
|
||||
EmptyView()
|
||||
} else {
|
||||
@@ -27,13 +27,15 @@ struct JoinRoomScreen: View {
|
||||
.background()
|
||||
.backgroundStyle(.compound.bgCanvasDefault)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar { toolbar }
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var mainContent: some View {
|
||||
if context.viewState.mode == .knocked {
|
||||
switch context.viewState.mode {
|
||||
case .knocked:
|
||||
knockedView
|
||||
} else {
|
||||
default:
|
||||
defaultView
|
||||
}
|
||||
}
|
||||
@@ -54,7 +56,7 @@ struct JoinRoomScreen: View {
|
||||
|
||||
if let subtitle = context.viewState.subtitle {
|
||||
Text(subtitle)
|
||||
.font(.compound.bodyMD)
|
||||
.font(.compound.bodyLG)
|
||||
.foregroundStyle(.compound.textSecondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
@@ -101,7 +103,7 @@ struct JoinRoomScreen: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ViewBuilder
|
||||
private var knockMessage: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
@@ -158,6 +160,17 @@ struct JoinRoomScreen: View {
|
||||
Button(L10n.actionAccept) { context.send(viewAction: .acceptInvite) }
|
||||
.buttonStyle(.compound(.primary))
|
||||
}
|
||||
|
||||
@ToolbarContentBuilder
|
||||
private var toolbar: some ToolbarContent {
|
||||
if context.viewState.mode == .knocked {
|
||||
ToolbarItem(placement: .principal) {
|
||||
RoomHeaderView(roomName: context.viewState.title,
|
||||
roomAvatar: context.viewState.avatar,
|
||||
mediaProvider: context.mediaProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
@@ -221,10 +234,17 @@ struct JoinRoomScreen_Previews: PreviewProvider, TestablePreview {
|
||||
if mode == .unknown {
|
||||
clientProxy.roomPreviewForIdentifierViaReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||
} else {
|
||||
if mode == .knocked {
|
||||
switch mode {
|
||||
case .knocked:
|
||||
clientProxy.roomForIdentifierClosure = { _ in
|
||||
.knocked(KnockedRoomProxyMock(.init()))
|
||||
.knocked(KnockedRoomProxyMock(.init(avatarURL: URL.homeDirectory)))
|
||||
}
|
||||
case .invited:
|
||||
clientProxy.roomForIdentifierClosure = { _ in
|
||||
.invited(InvitedRoomProxyMock(.init(avatarURL: URL.homeDirectory)))
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
clientProxy.roomPreviewForIdentifierViaReturnValue = .success(.init(roomID: "1",
|
||||
name: "The Three-Body Problem - 三体",
|
||||
|
||||
Reference in New Issue
Block a user