From c8df835a9dc45979f3e5010200894d71bd7eba12 Mon Sep 17 00:00:00 2001 From: Flavio Alescio Date: Wed, 3 May 2023 17:35:49 +0200 Subject: [PATCH] UI on create room screen --- .../Form Styles/FormButtonStyles.swift | 17 +++- .../CreateRoom/View/CreateRoomScreen.swift | 84 +++++++++++-------- 2 files changed, 67 insertions(+), 34 deletions(-) diff --git a/ElementX/Sources/Other/SwiftUI/Form Styles/FormButtonStyles.swift b/ElementX/Sources/Other/SwiftUI/Form Styles/FormButtonStyles.swift index 3a0e6dc1e..fd40c3305 100644 --- a/ElementX/Sources/Other/SwiftUI/Form Styles/FormButtonStyles.swift +++ b/ElementX/Sources/Other/SwiftUI/Form Styles/FormButtonStyles.swift @@ -21,6 +21,7 @@ enum FormRowAccessory: View { case navigationLink case progressView case selection(isSelected: Bool) + case singleSelection(isSelected: Bool) var body: some View { switch self { @@ -34,6 +35,10 @@ enum FormRowAccessory: View { Image(systemName: isSelected ? "checkmark.circle.fill" : "circle") .font(.compound.bodyLG) .foregroundColor(isSelected ? .element.primaryContent : .element.tertiaryContent) + case .singleSelection(let isSelected): + Image(systemName: "checkmark") + .font(.compound.bodyLG) + .foregroundColor(isSelected ? .element.primaryContent : .clear) } } } @@ -43,13 +48,15 @@ enum FormRowAccessory: View { /// The primitive style is needed to set the list row insets to `0`. The inner style is then needed /// to change the background colour depending on whether the button is currently pressed or not. struct FormButtonStyle: PrimitiveButtonStyle { + var iconAlignment: VerticalAlignment = .firstTextBaseline + /// An accessory to be added on the trailing side of the row. var accessory: FormRowAccessory? func makeBody(configuration: Configuration) -> some View { Button(action: configuration.trigger) { configuration.label - .labelStyle(FormRowLabelStyle(role: configuration.role)) + .labelStyle(FormRowLabelStyle(alignment: iconAlignment, role: configuration.role)) .frame(maxHeight: .infinity) // Make sure the label fills the cell vertically. } .buttonStyle(Style(accessory: accessory)) @@ -133,6 +140,14 @@ struct FormButtonStyles_Previews: PreviewProvider { Text("Selection") } .buttonStyle(FormButtonStyle(accessory: .selection(isSelected: false))) + Button { } label: { + VStack(alignment: .listRowSeparatorLeading, spacing: 0) { + Label("Hello world", systemImage: "globe") + Text("subtitle\nsubtitle") + .foregroundColor(.secondary) + } + } + .buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: true))) } .formSectionStyle() diff --git a/ElementX/Sources/Screens/CreateRoom/View/CreateRoomScreen.swift b/ElementX/Sources/Screens/CreateRoom/View/CreateRoomScreen.swift index 1cfc4c651..772eb9b44 100644 --- a/ElementX/Sources/Screens/CreateRoom/View/CreateRoomScreen.swift +++ b/ElementX/Sources/Screens/CreateRoom/View/CreateRoomScreen.swift @@ -34,38 +34,41 @@ struct CreateRoomScreen: View { /// The main content of the view to be shown in a scroll view. var mainContent: some View { - VStack(alignment: .center, spacing: 24) { - // TODO: check spacing + Form { roomSection - Form { - topicSection - } + topicSection selectedUsersSection + // TODO: Spacer not working properly Spacer() - Form { - securitySection - } + .listRowBackground(Color.clear) + securitySection } } + @ScaledMetric private var roomIconSide: CGFloat = 64 private var roomSection: some View { - // TODO: Style better - HStack(alignment: .top, spacing: 0) { - Image(systemName: "camera") - .frame(width: 70, height: 70) - .clipShape(Circle()) - Form { - Section { + Section { + HStack(alignment: .center, spacing: 16) { + Image(systemName: "camera") + .foregroundColor(.element.secondaryContent) + .frame(width: roomIconSide, height: roomIconSide) + .background(Color.element.quinaryContent) + .clipShape(Circle()) + VStack(alignment: .leading, spacing: 8) { + Text(L10n.screenCreateRoomRoomNameLabel.uppercased()) + .formSectionHeader() TextField(L10n.screenCreateRoomRoomNameLabel, text: $context.roomName, prompt: Text(L10n.screenCreateRoomRoomNamePlaceholder), axis: .horizontal) - } header: { - Text(L10n.screenCreateRoomRoomNameLabel) + .padding(FormRow.insets) + .background(Color.element.formRowBackground) + .clipShape(RoundedRectangle(cornerRadius: 8)) } - .formSectionStyle() } + .listRowBackground(Color.clear) } + .formSectionStyle() } private var topicSection: some View { @@ -83,33 +86,46 @@ struct CreateRoomScreen: View { @ScaledMetric private var cellWidth: CGFloat = 64 private var selectedUsersSection: some View { - ScrollView(.horizontal, showsIndicators: false) { - HStack(spacing: 28) { - ForEach(context.viewState.selectedUsers, id: \.userID) { user in - InviteUsersScreenSelectedItem(user: user, imageProvider: context.imageProvider) { - deselect(user) + Section { + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 28) { + ForEach(context.viewState.selectedUsers, id: \.userID) { user in + InviteUsersScreenSelectedItem(user: user, imageProvider: context.imageProvider) { + deselect(user) + } + .frame(width: cellWidth) } - .frame(width: cellWidth) } } - .padding(.horizontal, 18) + .listRowBackground(Color.clear) } } private var securitySection: some View { Section { - // TODO: style this items with descrition text and proper selection image Button(action: selectPrivate) { - Label(L10n.screenCreateRoomPrivateOptionTitle, systemImage: "lock.shield") + 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) + } } - .buttonStyle(FormButtonStyle(accessory: .selection(isSelected: context.isRoomPrivate))) + .buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: context.isRoomPrivate))) Button(action: selectPublic) { - Label(L10n.screenCreateRoomPublicOptionTitle, systemImage: "exclamationmark.shield") + VStack(alignment: .listRowSeparatorLeading, spacing: 0) { + Label(L10n.screenCreateRoomPublicOptionTitle, systemImage: "exclamationmark.shield") + Text(L10n.screenCreateRoomPublicOptionDescription) + .font(.compound.bodyMD) + .padding(.horizontal) + .foregroundColor(.element.secondaryContent) + } } - .buttonStyle(FormButtonStyle(accessory: .selection(isSelected: !context.isRoomPrivate))) + .buttonStyle(FormButtonStyle(iconAlignment: .top, accessory: .singleSelection(isSelected: !context.isRoomPrivate))) } header: { - // TODO: localize - Text("SECURITY") + Text(L10n.commonSecurity.uppercased()) } .formSectionStyle() } @@ -140,7 +156,9 @@ struct CreateRoom_Previews: PreviewProvider { static let viewModel = { let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "@userid:example.com"), mediaProvider: MockMediaProvider()) - return CreateRoomViewModel(userSession: userSession, selectedUsers: [.mockAlice, .mockBob, .mockCharlie]) + let parameters = CreateRoomVolatileParameters() + parameters.selectedUsers = [.mockAlice, .mockBob, .mockCharlie] + return CreateRoomViewModel(userSession: userSession, createRoomParameters: parameters) }() static var previews: some View {