Knock and knocked state for the join room screen (#3424)
* 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 --------- Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com>
This commit is contained in:
@@ -29,7 +29,17 @@ struct JoinRoomScreen: View {
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var mainContent: some View {
|
||||
if context.viewState.mode == .knocked {
|
||||
knockedView
|
||||
} else {
|
||||
defaultView
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var defaultView: some View {
|
||||
VStack(spacing: 16) {
|
||||
RoomAvatarImage(avatar: context.viewState.avatar,
|
||||
avatarSize: .room(on: .joinRoom),
|
||||
@@ -66,10 +76,59 @@ struct JoinRoomScreen: View {
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(3)
|
||||
}
|
||||
|
||||
if context.viewState.mode == .knock {
|
||||
knockMessage
|
||||
.padding(.top, 19)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var knockedView: some View {
|
||||
VStack(spacing: 16) {
|
||||
HeroImage(icon: \.checkCircleSolid, style: .success)
|
||||
VStack(spacing: 8) {
|
||||
Text(L10n.screenJoinRoomKnockSentTitle)
|
||||
.font(.compound.headingMDBold)
|
||||
.foregroundStyle(.compound.textPrimary)
|
||||
.multilineTextAlignment(.center)
|
||||
Text(L10n.screenJoinRoomKnockSentDescription)
|
||||
.font(.compound.bodyMD)
|
||||
.foregroundStyle(.compound.textSecondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var knockMessage: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack(spacing: 0) {
|
||||
TextField("", text: $context.knockMessage, axis: .vertical)
|
||||
.onChange(of: context.knockMessage) { newValue in
|
||||
context.knockMessage = String(newValue.prefix(1000))
|
||||
}
|
||||
.lineLimit(4, reservesSpace: true)
|
||||
.font(.compound.bodyMD)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 12)
|
||||
}
|
||||
.background(.compound.bgCanvasDefault)
|
||||
.cornerRadius(8)
|
||||
.overlay {
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.inset(by: 0.5)
|
||||
.stroke(.compound.borderInteractivePrimary)
|
||||
}
|
||||
|
||||
Text(L10n.screenJoinRoomKnockMessageDescription)
|
||||
.font(.compound.bodyMD)
|
||||
.foregroundStyle(.compound.textSecondary)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var buttons: some View {
|
||||
switch context.viewState.mode {
|
||||
@@ -77,7 +136,10 @@ struct JoinRoomScreen: View {
|
||||
EmptyView()
|
||||
case .knock:
|
||||
Button(L10n.screenJoinRoomKnockAction) { context.send(viewAction: .knock) }
|
||||
.buttonStyle(.compound(.primary))
|
||||
.buttonStyle(.compound(.super))
|
||||
case .knocked:
|
||||
Button(L10n.screenJoinRoomCancelKnockAction) { context.send(viewAction: .cancelKnock) }
|
||||
.buttonStyle(.compound(.secondary))
|
||||
case .join:
|
||||
Button(L10n.screenJoinRoomJoinAction) { context.send(viewAction: .join) }
|
||||
.buttonStyle(.compound(.super))
|
||||
@@ -105,6 +167,7 @@ struct JoinRoomScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let knockViewModel = makeViewModel(mode: .knock)
|
||||
static let joinViewModel = makeViewModel(mode: .join)
|
||||
static let inviteViewModel = makeViewModel(mode: .invited)
|
||||
static let knockedViewModel = makeViewModel(mode: .knocked)
|
||||
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
@@ -130,6 +193,12 @@ struct JoinRoomScreen_Previews: PreviewProvider, TestablePreview {
|
||||
}
|
||||
.previewDisplayName("Invite")
|
||||
.snapshotPreferences(delay: 0.25)
|
||||
|
||||
NavigationStack {
|
||||
JoinRoomScreen(context: knockedViewModel.context)
|
||||
}
|
||||
.previewDisplayName("Knocked")
|
||||
.snapshotPreferences(delay: 0.25)
|
||||
}
|
||||
|
||||
static func makeViewModel(mode: JoinRoomScreenInteractionMode) -> JoinRoomScreenViewModel {
|
||||
@@ -145,11 +214,18 @@ struct JoinRoomScreen_Previews: PreviewProvider, TestablePreview {
|
||||
(false, false, true, false)
|
||||
case .knock:
|
||||
(false, false, false, true)
|
||||
case .knocked:
|
||||
(false, false, false, false)
|
||||
}
|
||||
|
||||
if mode == .unknown {
|
||||
clientProxy.roomPreviewForIdentifierViaReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
|
||||
} else {
|
||||
if mode == .knocked {
|
||||
clientProxy.roomForIdentifierClosure = { _ in
|
||||
.knocked(KnockedRoomProxyMock(.init()))
|
||||
}
|
||||
}
|
||||
clientProxy.roomPreviewForIdentifierViaReturnValue = .success(.init(roomID: "1",
|
||||
name: "The Three-Body Problem - 三体",
|
||||
canonicalAlias: "#3🌞problem:matrix.org",
|
||||
@@ -164,9 +240,11 @@ struct JoinRoomScreen_Previews: PreviewProvider, TestablePreview {
|
||||
canKnock: membership.canKnock))
|
||||
}
|
||||
|
||||
ServiceLocator.shared.settings.knockingEnabled = true
|
||||
|
||||
return JoinRoomScreenViewModel(roomID: "1",
|
||||
via: [],
|
||||
allowKnocking: true,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
clientProxy: clientProxy,
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
Reference in New Issue
Block a user