mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
Tweak the design of various Forms to match Figma (#573)
Add formBackground and formRowBackground colours and adopt them. * Include topic in UI tests.
This commit is contained in:
@@ -81,6 +81,26 @@ public struct ElementColors {
|
||||
collection.userInterfaceStyle == .light ? .element.systemGray6 : .element.system
|
||||
})
|
||||
}
|
||||
|
||||
/// The colour to use on the background of a Form or grouped List.
|
||||
///
|
||||
/// This colour is a special case as it uses `system` in light mode and `background` in dark mode.
|
||||
public var formBackground: Color {
|
||||
Color(UIColor { collection in
|
||||
// Note: Light colour doesn't currently match Figma.
|
||||
collection.userInterfaceStyle == .light ? .element.system : .element.background
|
||||
})
|
||||
}
|
||||
|
||||
/// The background colour of a row in a Form or grouped List.
|
||||
///
|
||||
/// This colour is a special case as it uses `background` in light mode and `system` in dark mode.
|
||||
public var formRowBackground: Color {
|
||||
Color(UIColor { collection in
|
||||
// Note: Light colour doesn't currently match Figma.
|
||||
collection.userInterfaceStyle == .light ? .element.background : .element.system
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: UIKit
|
||||
|
||||
@@ -21,7 +21,7 @@ struct FormSectionHeaderStyle: ViewModifier {
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.font(.element.footnoteBold)
|
||||
.font(.element.caption1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ struct SettingsActionButtonStyle: ButtonStyle {
|
||||
.frame(width: menuIconSize, height: menuIconSize)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(Color.element.background.opacity(configuration.isPressed ? 0.5 : 1))
|
||||
.fill(Color.element.formRowBackground.opacity(configuration.isPressed ? 0.5 : 1))
|
||||
}
|
||||
|
||||
Text(title)
|
||||
@@ -32,7 +32,7 @@ struct BugReportScreen: View {
|
||||
.padding(.horizontal, horizontalPadding)
|
||||
}
|
||||
.scrollDismissesKeyboard(.immediately)
|
||||
.background(Color.element.system)
|
||||
.background(Color.element.formBackground.ignoresSafeArea())
|
||||
.navigationTitle(ElementL10n.bugReportScreenTitle)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar { toolbar }
|
||||
@@ -52,18 +52,15 @@ struct BugReportScreen: View {
|
||||
private var descriptionTextEditor: some View {
|
||||
ZStack(alignment: .topLeading) {
|
||||
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
||||
.fill(Color.element.background)
|
||||
.fill(Color.element.formRowBackground)
|
||||
|
||||
TextEditor(text: $context.reportText)
|
||||
.tint(.element.brand)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 4)
|
||||
.background(Color.clear)
|
||||
.cornerRadius(14)
|
||||
.accessibilityIdentifier("reportTextView")
|
||||
.introspectTextView { textView in
|
||||
textView.backgroundColor = .clear
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
|
||||
if context.reportText.isEmpty {
|
||||
Text(ElementL10n.bugReportScreenDescription)
|
||||
@@ -90,7 +87,7 @@ struct BugReportScreen: View {
|
||||
.accessibilityIdentifier("sendLogsToggle")
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 11)
|
||||
.background(RoundedRectangle(cornerRadius: 14).fill(Color.element.background))
|
||||
.background(RoundedRectangle(cornerRadius: 14).fill(Color.element.formRowBackground))
|
||||
|
||||
Text(ElementL10n.bugReportScreenLogsDescription)
|
||||
.font(.element.caption1)
|
||||
@@ -142,9 +139,11 @@ struct BugReportScreen: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct BugReport_Previews: PreviewProvider {
|
||||
static let viewModel = BugReportViewModel(bugReportService: MockBugReportService(),
|
||||
screenshot: Asset.Images.appLogo.image,
|
||||
isModallyPresented: false)
|
||||
|
||||
static var previews: some View {
|
||||
let viewModel = BugReportViewModel(bugReportService: MockBugReportService(), screenshot: Asset.Images.appLogo.image, isModallyPresented: false)
|
||||
BugReportScreen(context: viewModel.context)
|
||||
.previewInterfaceOrientation(.portrait)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,14 +28,19 @@ struct RoomDetailsScreen: View {
|
||||
|
||||
if let topic = context.viewState.topic {
|
||||
topicSection(with: topic)
|
||||
.listRowBackground(Color.element.formRowBackground)
|
||||
}
|
||||
|
||||
aboutSection
|
||||
.listRowBackground(Color.element.formRowBackground)
|
||||
|
||||
if context.viewState.isEncrypted {
|
||||
securitySection
|
||||
.listRowBackground(Color.element.formRowBackground)
|
||||
}
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(Color.element.formBackground.ignoresSafeArea())
|
||||
.alert(item: $context.alertInfo) { $0.alert }
|
||||
}
|
||||
|
||||
@@ -82,103 +87,111 @@ struct RoomDetailsScreen: View {
|
||||
}
|
||||
|
||||
private func topicSection(with topic: String) -> some View {
|
||||
Section(header: Text(ElementL10n.roomSettingsTopic)
|
||||
.formSectionHeader()) {
|
||||
Text(topic)
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.font(.element.footnote)
|
||||
}
|
||||
Section {
|
||||
Text(topic)
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.font(.element.footnote)
|
||||
} header: {
|
||||
Text(ElementL10n.roomSettingsTopic)
|
||||
.formSectionHeader()
|
||||
}
|
||||
}
|
||||
|
||||
private var aboutSection: some View {
|
||||
Section(header: Text(ElementL10n.roomDetailsAboutSectionTitle)
|
||||
.formSectionHeader()) {
|
||||
Button {
|
||||
context.send(viewAction: .processTapPeople)
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "person")
|
||||
Section {
|
||||
Button {
|
||||
context.send(viewAction: .processTapPeople)
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "person")
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.padding(4)
|
||||
.background(Color.element.formBackground)
|
||||
.cornerRadius(8)
|
||||
.frame(width: menuIconSize, height: menuIconSize)
|
||||
|
||||
Text(ElementL10n.bottomActionPeople)
|
||||
.foregroundColor(.element.primaryContent)
|
||||
.font(.body)
|
||||
|
||||
Spacer()
|
||||
|
||||
if context.viewState.isLoadingMembers {
|
||||
ProgressView()
|
||||
} else {
|
||||
Text(String(context.viewState.members.count))
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.padding(4)
|
||||
.background(Color.element.system)
|
||||
.clipShape(RoundedCornerShape(radius: 8, corners: .allCorners))
|
||||
.frame(width: menuIconSize, height: menuIconSize)
|
||||
|
||||
Text(ElementL10n.bottomActionPeople)
|
||||
.foregroundColor(.element.primaryContent)
|
||||
.font(.body)
|
||||
|
||||
Spacer()
|
||||
|
||||
if context.viewState.isLoadingMembers {
|
||||
ProgressView()
|
||||
} else {
|
||||
Text(String(context.viewState.members.count))
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.font(.element.body)
|
||||
Image(systemName: "chevron.forward")
|
||||
.foregroundColor(.element.quaternaryContent)
|
||||
}
|
||||
.font(.element.body)
|
||||
Image(systemName: "chevron.forward")
|
||||
.foregroundColor(.element.quaternaryContent)
|
||||
}
|
||||
}
|
||||
.listRowInsets(listRowInsets)
|
||||
.foregroundColor(.element.primaryContent)
|
||||
.accessibilityIdentifier("peopleButton")
|
||||
.disabled(context.viewState.isLoadingMembers)
|
||||
}
|
||||
.listRowInsets(listRowInsets)
|
||||
.foregroundColor(.element.primaryContent)
|
||||
.accessibilityIdentifier("peopleButton")
|
||||
.disabled(context.viewState.isLoadingMembers)
|
||||
} header: {
|
||||
Text(ElementL10n.roomDetailsAboutSectionTitle)
|
||||
.formSectionHeader()
|
||||
}
|
||||
}
|
||||
|
||||
private var securitySection: some View {
|
||||
Section(header: Text(ElementL10n.roomProfileSectionSecurity)
|
||||
.formSectionHeader()) {
|
||||
HStack(alignment: .top) {
|
||||
Image(systemName: "lock.shield")
|
||||
Section {
|
||||
HStack(alignment: .top) {
|
||||
Image(systemName: "lock.shield")
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.padding(4)
|
||||
.background(Color.element.formBackground)
|
||||
.cornerRadius(8)
|
||||
.frame(width: menuIconSize, height: menuIconSize)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(ElementL10n.encryptionEnabled)
|
||||
.foregroundColor(.element.primaryContent)
|
||||
.font(.element.body)
|
||||
|
||||
Text(ElementL10n.encryptionEnabledTileDescription)
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.padding(4)
|
||||
.background(Color.element.system)
|
||||
.clipShape(RoundedCornerShape(radius: 8, corners: .allCorners))
|
||||
.frame(width: menuIconSize, height: menuIconSize)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(ElementL10n.encryptionEnabled)
|
||||
.foregroundColor(.element.primaryContent)
|
||||
.font(.element.body)
|
||||
|
||||
Text(ElementL10n.encryptionEnabledTileDescription)
|
||||
.foregroundColor(.element.secondaryContent)
|
||||
.font(.element.footnote)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "checkmark")
|
||||
.foregroundColor(.element.quaternaryContent)
|
||||
.font(.element.footnote)
|
||||
}
|
||||
.padding(.horizontal, -3)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "checkmark")
|
||||
.foregroundColor(.element.quaternaryContent)
|
||||
}
|
||||
.padding(.horizontal, -3)
|
||||
} header: {
|
||||
Text(ElementL10n.roomProfileSectionSecurity)
|
||||
.formSectionHeader()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct RoomDetails_Previews: PreviewProvider {
|
||||
static let viewModel = {
|
||||
let members: [RoomMemberProxy] = [
|
||||
.mockAlice,
|
||||
.mockBob,
|
||||
.mockCharlie
|
||||
]
|
||||
let roomProxy = MockRoomProxy(displayName: "Room A",
|
||||
topic: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
isDirect: false,
|
||||
isEncrypted: true,
|
||||
canonicalAlias: "#alias:domain.com",
|
||||
members: members)
|
||||
|
||||
return RoomDetailsViewModel(roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider())
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
Group {
|
||||
let members: [RoomMemberProxy] = [
|
||||
.mockAlice,
|
||||
.mockBob,
|
||||
.mockCharlie
|
||||
]
|
||||
let roomProxy = MockRoomProxy(displayName: "Room A",
|
||||
topic: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
isDirect: false,
|
||||
isEncrypted: true,
|
||||
canonicalAlias: "#alias:domain.com",
|
||||
members: members)
|
||||
let viewModel = RoomDetailsViewModel(roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider())
|
||||
RoomDetailsScreen(context: viewModel.context)
|
||||
}
|
||||
.tint(.element.accent)
|
||||
RoomDetailsScreen(context: viewModel.context)
|
||||
.tint(.element.accent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ struct SettingsScreen: View {
|
||||
|
||||
@ScaledMetric private var avatarSize = AvatarSize.user(on: .settings).value
|
||||
@ScaledMetric private var menuIconSize = 30.0
|
||||
|
||||
private let listRowInsets = EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16)
|
||||
|
||||
@ObservedObject var context: SettingsScreenViewModel.Context
|
||||
@@ -29,25 +30,23 @@ struct SettingsScreen: View {
|
||||
var body: some View {
|
||||
Form {
|
||||
userSection
|
||||
.listRowBackground(rowBackgroundColor)
|
||||
.listRowBackground(Color.element.formRowBackground)
|
||||
|
||||
if context.viewState.showSessionVerificationSection {
|
||||
sessionVerificationSection
|
||||
.listRowBackground(rowBackgroundColor)
|
||||
.listRowBackground(Color.element.formRowBackground)
|
||||
}
|
||||
|
||||
simplifiedSection
|
||||
.listRowBackground(rowBackgroundColor)
|
||||
.listRowBackground(Color.element.formRowBackground)
|
||||
|
||||
signOutSection
|
||||
.listRowBackground(rowBackgroundColor)
|
||||
}
|
||||
.introspectTableView { tableView in
|
||||
tableView.backgroundColor = .clear
|
||||
.listRowBackground(Color.element.formRowBackground)
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(Color.element.formBackground.ignoresSafeArea())
|
||||
.navigationTitle(ElementL10n.settings)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.background(backgroundColor.ignoresSafeArea())
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
doneButton
|
||||
@@ -59,14 +58,6 @@ struct SettingsScreen: View {
|
||||
Text(ElementL10n.settingsVersion + ": " + InfoPlistReader.main.bundleShortVersionString + " (" + InfoPlistReader.main.bundleVersion + ")")
|
||||
}
|
||||
|
||||
private var backgroundColor: Color {
|
||||
.element.system
|
||||
}
|
||||
|
||||
private var rowBackgroundColor: Color {
|
||||
colorScheme == .light ? .element.background : .element.system
|
||||
}
|
||||
|
||||
private var userSection: some View {
|
||||
Section {
|
||||
HStack(spacing: 13) {
|
||||
@@ -189,7 +180,7 @@ struct SettingsScreen_Previews: PreviewProvider {
|
||||
|
||||
NavigationView {
|
||||
SettingsScreen(context: viewModel.context)
|
||||
.previewInterfaceOrientation(.portrait)
|
||||
.tint(.element.accent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,8 +287,10 @@ class MockScreen: Identifiable {
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
let roomProxy = MockRoomProxy(id: "MockRoomIdentifier",
|
||||
displayName: "Room",
|
||||
topic: "Bacon ipsum dolor amet commodo incididunt ribeye dolore cupidatat short ribs.",
|
||||
avatarURL: URL.picturesDirectory,
|
||||
isEncrypted: true,
|
||||
canonicalAlias: "#mock:room.org",
|
||||
members: [.mockAlice, .mockBob, .mockCharlie])
|
||||
let coordinator = RoomDetailsCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator,
|
||||
roomProxy: roomProxy,
|
||||
|
||||
@@ -21,19 +21,6 @@ class SettingsUITests: XCTestCase {
|
||||
func testInitialStateComponents() {
|
||||
let app = Application.launch()
|
||||
app.goToScreenWithIdentifier(.settings)
|
||||
|
||||
XCTAssert(app.navigationBars[ElementL10n.settings].exists)
|
||||
let reportBugButton = app.buttons["reportBugButton"]
|
||||
XCTAssert(reportBugButton.exists)
|
||||
XCTAssertEqual(reportBugButton.label, ElementL10n.sendBugReport)
|
||||
|
||||
XCTAssertTrue(app.buttons["timelineStylePicker"].exists)
|
||||
XCTAssertTrue(app.staticTexts[ElementL10n.settingsTimelineStyle].exists)
|
||||
|
||||
let logoutButton = app.buttons["logoutButton"]
|
||||
XCTAssert(logoutButton.exists)
|
||||
XCTAssertEqual(logoutButton.label, ElementL10n.logout)
|
||||
|
||||
app.assertScreenshot(.settings)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:970c9b01387e5cd16dfda9a4da49d0bebaaa06dfba5bcf9e48ff575ba635a471
|
||||
size 90791
|
||||
oid sha256:9c1a4f312dabc8e0f7ca1f4555cc0fb9212845c40d54b104aaa8e6df0a1b1a1e
|
||||
size 90593
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:77a207072518aa4a87f67628ccc12a70613cfc953f7636589f9a58e30aadbdb9
|
||||
size 91154
|
||||
oid sha256:0677000cc125bb1c3aaaf02b0236939085c4ad2d1f34e653f2b81dfaafb98ab7
|
||||
size 115608
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:911e3f878cf2fb58f4618326b0efeaa9fc69b5b750ab2f9898516f01c068e404
|
||||
size 100993
|
||||
oid sha256:929b6e0abf913cc4598dedd2faef6845b73697d163480dab3339f88d90e43970
|
||||
size 101082
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3d36ef0d09153dc39c5f4b4f5b14f3e71f70e0f157d45a8ef1c451c6622716b3
|
||||
size 106670
|
||||
oid sha256:08ec2c9755ee86d41b9825cfb4ad031e480ac8aacc3591e1a145e27344c831ee
|
||||
size 106500
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b13acb165866118942b42f3defdbd9f049f4ad3f113416a5ff92684ff6ab54df
|
||||
size 107173
|
||||
oid sha256:feb2d3126893d206fe486e22b0277f8cdf3e69fc1e748c1386f0f733189595b6
|
||||
size 142603
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7356f84c44761fc41f98fc4fca6cc9146eeb55a3130f76f6bea025543fb5b730
|
||||
size 123373
|
||||
oid sha256:f39c68000391860a8260c6faeb29954456d3f10f8cacef51ed1f5850ec7b85e1
|
||||
size 126031
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:50081a6f1d88492cee859e6948f528ed1400509fa6b829f4ac30f9594d0905df
|
||||
size 86961
|
||||
oid sha256:999309a2b2227b3b5bc2c471fc60b7de0ff060bbffc60e18493651d31ccc2e2e
|
||||
size 86938
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a191f7365d3968ae8eecabd03e9518c80850ddd2e4f5d2e2882a67b5c4e2d0dc
|
||||
size 87266
|
||||
oid sha256:9892c8a4cb57e9d678204a0995f048cc9810c03bece188ee69504f0b81478e23
|
||||
size 112193
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:15c84b0229148507bfbf15711a28f2ab205fbda27ad363ac6328034454287d71
|
||||
size 101889
|
||||
oid sha256:b84b32cd357de819895541fb6ed10c562649e9f3596108151cd93e4d815977d5
|
||||
size 101777
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ff9c2153c054fe02e85266a8e428996a3c12f908d3f303ed4b93a94d96d2e157
|
||||
size 103803
|
||||
oid sha256:0065cc98273a41f0782f6f556187f8f3519db3063e0dc147edcdd37cad38dc6f
|
||||
size 103310
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bcbbe7544478c8a1086ed546da661e83666a7c748f51b5e552254652cbb4b5d7
|
||||
size 104328
|
||||
oid sha256:f9a7db7bb77d8d87d185e8ed22b4f12be4a066678b0fa0f95200eb55111c0ab9
|
||||
size 139278
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cb6a7654c6184115f0feed9cce2b78a8c464a864a69eda2fc93e2c68a68f5602
|
||||
size 123302
|
||||
oid sha256:63a0ed106d7a0cbe662657f8e55e9a8b3635e847d3c48e00fc8bb1bedb7f675d
|
||||
size 123587
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Update appearance of forms in the app. Add formBackground and formRowBackground colours.
|
||||
Reference in New Issue
Block a user