From f8b7b86641a437c85c851af119f0c75e3515003a Mon Sep 17 00:00:00 2001 From: Flavio Alescio Date: Wed, 10 May 2023 16:40:00 +0200 Subject: [PATCH] add UI test, separate model class in Services, UI fix for button with single selection style --- .../Form Styles/FormButtonStyles.swift | 13 +++-- .../CreateRoom/View/CreateRoomScreen.swift | 57 +++++++++++++------ .../StartChatScreenCoordinator.swift | 7 --- .../CreateRoom/CreateRoomParameters.swift | 25 ++++++++ .../UITests/UITestsAppCoordinator.swift | 9 +++ .../UITests/UITestsScreenIdentifier.swift | 1 + UITests/Sources/CreateRoomScreenUITests.swift | 7 ++- 7 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 ElementX/Sources/Services/CreateRoom/CreateRoomParameters.swift diff --git a/ElementX/Sources/Other/SwiftUI/Form Styles/FormButtonStyles.swift b/ElementX/Sources/Other/SwiftUI/Form Styles/FormButtonStyles.swift index fd40c3305..934620c41 100644 --- a/ElementX/Sources/Other/SwiftUI/Form Styles/FormButtonStyles.swift +++ b/ElementX/Sources/Other/SwiftUI/Form Styles/FormButtonStyles.swift @@ -141,10 +141,15 @@ struct FormButtonStyles_Previews: PreviewProvider { } .buttonStyle(FormButtonStyle(accessory: .selection(isSelected: false))) Button { } label: { - VStack(alignment: .listRowSeparatorLeading, spacing: 0) { - Label("Hello world", systemImage: "globe") - Text("subtitle\nsubtitle") - .foregroundColor(.secondary) + Label { + VStack(alignment: .leading, spacing: 8) { + Text("Hello world") + Text("subtitle\nsubtitle") + .font(.compound.bodyMD) + .foregroundColor(.element.secondaryContent) + } + } icon: { + Image(systemName: "globe") } } .buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: true))) diff --git a/ElementX/Sources/Screens/CreateRoom/View/CreateRoomScreen.swift b/ElementX/Sources/Screens/CreateRoom/View/CreateRoomScreen.swift index 772eb9b44..c17569fac 100644 --- a/ElementX/Sources/Screens/CreateRoom/View/CreateRoomScreen.swift +++ b/ElementX/Sources/Screens/CreateRoom/View/CreateRoomScreen.swift @@ -21,6 +21,7 @@ struct CreateRoomScreen: View { var body: some View { mainContent + .scrollDismissesKeyboard(.immediately) .scrollContentBackground(.hidden) .background(Color.element.formBackground.ignoresSafeArea()) .navigationTitle(L10n.screenCreateRoomTitle) @@ -37,7 +38,10 @@ struct CreateRoomScreen: View { Form { roomSection topicSection - selectedUsersSection + if !context.viewState.selectedUsers.isEmpty { + // TODO: check clipping outside form + selectedUsersSection + } // TODO: Spacer not working properly Spacer() .listRowBackground(Color.clear) @@ -56,16 +60,19 @@ struct CreateRoomScreen: View { .clipShape(Circle()) VStack(alignment: .leading, spacing: 8) { Text(L10n.screenCreateRoomRoomNameLabel.uppercased()) + .font(.compound.bodySM) + .padding(.leading, 16) .formSectionHeader() TextField(L10n.screenCreateRoomRoomNameLabel, text: $context.roomName, prompt: Text(L10n.screenCreateRoomRoomNamePlaceholder), axis: .horizontal) - .padding(FormRow.insets) + .padding(EdgeInsets(top: 10, leading: 16, bottom: 10, trailing: 16)) .background(Color.element.formRowBackground) .clipShape(RoundedRectangle(cornerRadius: 8)) } } + .listRowInsets(.init()) .listRowBackground(Color.clear) } .formSectionStyle() @@ -88,7 +95,7 @@ struct CreateRoomScreen: View { private var selectedUsersSection: some View { Section { ScrollView(.horizontal, showsIndicators: false) { - HStack(spacing: 28) { + LazyHStack(spacing: 28) { ForEach(context.viewState.selectedUsers, id: \.userID) { user in InviteUsersScreenSelectedItem(user: user, imageProvider: context.imageProvider) { deselect(user) @@ -97,6 +104,7 @@ struct CreateRoomScreen: View { } } } + .listRowInsets(.init()) .listRowBackground(Color.clear) } } @@ -104,23 +112,28 @@ struct CreateRoomScreen: View { private var securitySection: some View { Section { Button(action: selectPrivate) { - VStack(alignment: .listRowSeparatorLeading, spacing: 0) { - Label(L10n.screenCreateRoomPrivateOptionTitle, systemImage: "lock.shield") - Text(L10n.screenCreateRoomPrivateOptionDescription) - .font(.compound.bodyMD) - // TODO: padding not working properly - .padding(.horizontal, 20) - .foregroundColor(.element.secondaryContent) + Label { + VStack(alignment: .leading, spacing: 8) { + Text(L10n.screenCreateRoomPrivateOptionTitle) + Text(L10n.screenCreateRoomPrivateOptionDescription) + .font(.compound.bodyMD) + .foregroundColor(.element.secondaryContent) + } + } icon: { + Image(systemName: "lock.shield") } } .buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: context.isRoomPrivate))) Button(action: selectPublic) { - VStack(alignment: .listRowSeparatorLeading, spacing: 0) { - Label(L10n.screenCreateRoomPublicOptionTitle, systemImage: "exclamationmark.shield") - Text(L10n.screenCreateRoomPublicOptionDescription) - .font(.compound.bodyMD) - .padding(.horizontal) - .foregroundColor(.element.secondaryContent) + Label { + VStack(alignment: .leading, spacing: 8) { + Text(L10n.screenCreateRoomPublicOptionTitle) + Text(L10n.screenCreateRoomPublicOptionDescription) + .font(.compound.bodyMD) + .foregroundColor(.element.secondaryContent) + } + } icon: { + Image(systemName: "exclamationmark.shield") } } .buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: !context.isRoomPrivate))) @@ -161,9 +174,21 @@ struct CreateRoom_Previews: PreviewProvider { return CreateRoomViewModel(userSession: userSession, createRoomParameters: parameters) }() + static let emtpyViewModel = { + let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "@userid:example.com"), + mediaProvider: MockMediaProvider()) + let parameters = CreateRoomVolatileParameters() + return CreateRoomViewModel(userSession: userSession, createRoomParameters: parameters) + }() + static var previews: some View { NavigationView { CreateRoomScreen(context: viewModel.context) } + .previewDisplayName("Create Room") + NavigationView { + CreateRoomScreen(context: emtpyViewModel.context) + } + .previewDisplayName("Create Room without users") } } diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift index 870a5416a..a3b2614b9 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift @@ -89,10 +89,3 @@ final class StartChatScreenCoordinator: CoordinatorProtocol { parameters.navigationStackCoordinator?.push(coordinator) } } - -class CreateRoomVolatileParameters { - var name = "" - var topic = "" - var selectedUsers: [UserProfile] = [] - var isRoomPrivate = true -} diff --git a/ElementX/Sources/Services/CreateRoom/CreateRoomParameters.swift b/ElementX/Sources/Services/CreateRoom/CreateRoomParameters.swift new file mode 100644 index 000000000..ffdb628bf --- /dev/null +++ b/ElementX/Sources/Services/CreateRoom/CreateRoomParameters.swift @@ -0,0 +1,25 @@ +// +// Copyright 2023 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +/// This parameters are only used in the create room flow for having a a volatile persisted object that will be disposed once the flow is ended +class CreateRoomVolatileParameters { + var name = "" + var topic = "" + var selectedUsers: [UserProfile] = [] + var isRoomPrivate = true +} diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index bea394e90..e28df8871 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -422,6 +422,15 @@ class MockScreen: Identifiable { let coordinator = CreateRoomCoordinator(parameters: parameters) navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator + case .createRoomNoUsers: + let navigationStackCoordinator = NavigationStackCoordinator() + let clientProxy = MockClientProxy(userID: "@mock:client.com") + let mockUserSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider()) + let createRoomParameters = CreateRoomVolatileParameters() + let parameters = CreateRoomCoordinatorParameters(userSession: mockUserSession, createRoomParameters: createRoomParameters) + let coordinator = CreateRoomCoordinator(parameters: parameters) + navigationStackCoordinator.setRootCoordinator(coordinator) + return navigationStackCoordinator } }() } diff --git a/ElementX/Sources/UITests/UITestsScreenIdentifier.swift b/ElementX/Sources/UITests/UITestsScreenIdentifier.swift index 6563c3e8c..621f39f69 100644 --- a/ElementX/Sources/UITests/UITestsScreenIdentifier.swift +++ b/ElementX/Sources/UITests/UITestsScreenIdentifier.swift @@ -57,6 +57,7 @@ enum UITestsScreenIdentifier: String { case invitesNoInvites case inviteUsers case createRoom + case createRoomNoUsers } extension UITestsScreenIdentifier: CustomStringConvertible { diff --git a/UITests/Sources/CreateRoomScreenUITests.swift b/UITests/Sources/CreateRoomScreenUITests.swift index 7d5b49b69..49588e393 100644 --- a/UITests/Sources/CreateRoomScreenUITests.swift +++ b/UITests/Sources/CreateRoomScreenUITests.swift @@ -20,6 +20,11 @@ import XCTest class CreateRoomScreenUITests: XCTestCase { func testLanding() { let app = Application.launch(.createRoom) - app.assertScreenshot(.createRoom) + app.assertScreenshot(.createRoom, step: 0) + } + + func testLandingWithoutUsers() { + let app = Application.launch(.createRoomNoUsers) + app.assertScreenshot(.createRoom, step: 1) } }