mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
add UI test, separate model class in Services, UI fix for button with single selection style
This commit is contained in:
@@ -141,10 +141,15 @@ struct FormButtonStyles_Previews: PreviewProvider {
|
|||||||
}
|
}
|
||||||
.buttonStyle(FormButtonStyle(accessory: .selection(isSelected: false)))
|
.buttonStyle(FormButtonStyle(accessory: .selection(isSelected: false)))
|
||||||
Button { } label: {
|
Button { } label: {
|
||||||
VStack(alignment: .listRowSeparatorLeading, spacing: 0) {
|
Label {
|
||||||
Label("Hello world", systemImage: "globe")
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text("subtitle\nsubtitle")
|
Text("Hello world")
|
||||||
.foregroundColor(.secondary)
|
Text("subtitle\nsubtitle")
|
||||||
|
.font(.compound.bodyMD)
|
||||||
|
.foregroundColor(.element.secondaryContent)
|
||||||
|
}
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "globe")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: true)))
|
.buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: true)))
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ struct CreateRoomScreen: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
mainContent
|
mainContent
|
||||||
|
.scrollDismissesKeyboard(.immediately)
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
.background(Color.element.formBackground.ignoresSafeArea())
|
.background(Color.element.formBackground.ignoresSafeArea())
|
||||||
.navigationTitle(L10n.screenCreateRoomTitle)
|
.navigationTitle(L10n.screenCreateRoomTitle)
|
||||||
@@ -37,7 +38,10 @@ struct CreateRoomScreen: View {
|
|||||||
Form {
|
Form {
|
||||||
roomSection
|
roomSection
|
||||||
topicSection
|
topicSection
|
||||||
selectedUsersSection
|
if !context.viewState.selectedUsers.isEmpty {
|
||||||
|
// TODO: check clipping outside form
|
||||||
|
selectedUsersSection
|
||||||
|
}
|
||||||
// TODO: Spacer not working properly
|
// TODO: Spacer not working properly
|
||||||
Spacer()
|
Spacer()
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
@@ -56,16 +60,19 @@ struct CreateRoomScreen: View {
|
|||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text(L10n.screenCreateRoomRoomNameLabel.uppercased())
|
Text(L10n.screenCreateRoomRoomNameLabel.uppercased())
|
||||||
|
.font(.compound.bodySM)
|
||||||
|
.padding(.leading, 16)
|
||||||
.formSectionHeader()
|
.formSectionHeader()
|
||||||
TextField(L10n.screenCreateRoomRoomNameLabel,
|
TextField(L10n.screenCreateRoomRoomNameLabel,
|
||||||
text: $context.roomName,
|
text: $context.roomName,
|
||||||
prompt: Text(L10n.screenCreateRoomRoomNamePlaceholder),
|
prompt: Text(L10n.screenCreateRoomRoomNamePlaceholder),
|
||||||
axis: .horizontal)
|
axis: .horizontal)
|
||||||
.padding(FormRow.insets)
|
.padding(EdgeInsets(top: 10, leading: 16, bottom: 10, trailing: 16))
|
||||||
.background(Color.element.formRowBackground)
|
.background(Color.element.formRowBackground)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.listRowInsets(.init())
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
}
|
}
|
||||||
.formSectionStyle()
|
.formSectionStyle()
|
||||||
@@ -88,7 +95,7 @@ struct CreateRoomScreen: View {
|
|||||||
private var selectedUsersSection: some View {
|
private var selectedUsersSection: some View {
|
||||||
Section {
|
Section {
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
HStack(spacing: 28) {
|
LazyHStack(spacing: 28) {
|
||||||
ForEach(context.viewState.selectedUsers, id: \.userID) { user in
|
ForEach(context.viewState.selectedUsers, id: \.userID) { user in
|
||||||
InviteUsersScreenSelectedItem(user: user, imageProvider: context.imageProvider) {
|
InviteUsersScreenSelectedItem(user: user, imageProvider: context.imageProvider) {
|
||||||
deselect(user)
|
deselect(user)
|
||||||
@@ -97,6 +104,7 @@ struct CreateRoomScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.listRowInsets(.init())
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,23 +112,28 @@ struct CreateRoomScreen: View {
|
|||||||
private var securitySection: some View {
|
private var securitySection: some View {
|
||||||
Section {
|
Section {
|
||||||
Button(action: selectPrivate) {
|
Button(action: selectPrivate) {
|
||||||
VStack(alignment: .listRowSeparatorLeading, spacing: 0) {
|
Label {
|
||||||
Label(L10n.screenCreateRoomPrivateOptionTitle, systemImage: "lock.shield")
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text(L10n.screenCreateRoomPrivateOptionDescription)
|
Text(L10n.screenCreateRoomPrivateOptionTitle)
|
||||||
.font(.compound.bodyMD)
|
Text(L10n.screenCreateRoomPrivateOptionDescription)
|
||||||
// TODO: padding not working properly
|
.font(.compound.bodyMD)
|
||||||
.padding(.horizontal, 20)
|
.foregroundColor(.element.secondaryContent)
|
||||||
.foregroundColor(.element.secondaryContent)
|
}
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "lock.shield")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: context.isRoomPrivate)))
|
.buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: context.isRoomPrivate)))
|
||||||
Button(action: selectPublic) {
|
Button(action: selectPublic) {
|
||||||
VStack(alignment: .listRowSeparatorLeading, spacing: 0) {
|
Label {
|
||||||
Label(L10n.screenCreateRoomPublicOptionTitle, systemImage: "exclamationmark.shield")
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text(L10n.screenCreateRoomPublicOptionDescription)
|
Text(L10n.screenCreateRoomPublicOptionTitle)
|
||||||
.font(.compound.bodyMD)
|
Text(L10n.screenCreateRoomPublicOptionDescription)
|
||||||
.padding(.horizontal)
|
.font(.compound.bodyMD)
|
||||||
.foregroundColor(.element.secondaryContent)
|
.foregroundColor(.element.secondaryContent)
|
||||||
|
}
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "exclamationmark.shield")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: !context.isRoomPrivate)))
|
.buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: !context.isRoomPrivate)))
|
||||||
@@ -161,9 +174,21 @@ struct CreateRoom_Previews: PreviewProvider {
|
|||||||
return CreateRoomViewModel(userSession: userSession, createRoomParameters: parameters)
|
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 {
|
static var previews: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
CreateRoomScreen(context: viewModel.context)
|
CreateRoomScreen(context: viewModel.context)
|
||||||
}
|
}
|
||||||
|
.previewDisplayName("Create Room")
|
||||||
|
NavigationView {
|
||||||
|
CreateRoomScreen(context: emtpyViewModel.context)
|
||||||
|
}
|
||||||
|
.previewDisplayName("Create Room without users")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,10 +89,3 @@ final class StartChatScreenCoordinator: CoordinatorProtocol {
|
|||||||
parameters.navigationStackCoordinator?.push(coordinator)
|
parameters.navigationStackCoordinator?.push(coordinator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateRoomVolatileParameters {
|
|
||||||
var name = ""
|
|
||||||
var topic = ""
|
|
||||||
var selectedUsers: [UserProfile] = []
|
|
||||||
var isRoomPrivate = true
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -422,6 +422,15 @@ class MockScreen: Identifiable {
|
|||||||
let coordinator = CreateRoomCoordinator(parameters: parameters)
|
let coordinator = CreateRoomCoordinator(parameters: parameters)
|
||||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||||
return navigationStackCoordinator
|
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
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ enum UITestsScreenIdentifier: String {
|
|||||||
case invitesNoInvites
|
case invitesNoInvites
|
||||||
case inviteUsers
|
case inviteUsers
|
||||||
case createRoom
|
case createRoom
|
||||||
|
case createRoomNoUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UITestsScreenIdentifier: CustomStringConvertible {
|
extension UITestsScreenIdentifier: CustomStringConvertible {
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ import XCTest
|
|||||||
class CreateRoomScreenUITests: XCTestCase {
|
class CreateRoomScreenUITests: XCTestCase {
|
||||||
func testLanding() {
|
func testLanding() {
|
||||||
let app = Application.launch(.createRoom)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user