add UI test, separate model class in Services, UI fix for button with single selection style

This commit is contained in:
Flavio Alescio 2023-05-10 16:40:00 +02:00 committed by Flescio
parent 4ab30f9632
commit f8b7b86641
7 changed files with 91 additions and 28 deletions

View File

@ -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)))

View File

@ -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")
}
}

View File

@ -89,10 +89,3 @@ final class StartChatScreenCoordinator: CoordinatorProtocol {
parameters.navigationStackCoordinator?.push(coordinator)
}
}
class CreateRoomVolatileParameters {
var name = ""
var topic = ""
var selectedUsers: [UserProfile] = []
var isRoomPrivate = true
}

View File

@ -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
}

View File

@ -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
}
}()
}

View File

@ -57,6 +57,7 @@ enum UITestsScreenIdentifier: String {
case invitesNoInvites
case inviteUsers
case createRoom
case createRoomNoUsers
}
extension UITestsScreenIdentifier: CustomStringConvertible {

View File

@ -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)
}
}