mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Show an account provider picker on the server confirmation screen when required. (#4137)
* Add a picker mode to the ServerConfirmationScreen. * Hook up the account provider picker in authentication the flow. Simplify the authentication flow coordinator, removing the restricted state. * UI/Snapshot tests.
This commit is contained in:
+90
-16
@@ -11,14 +11,38 @@ import SwiftUI
|
||||
struct ServerConfirmationScreen: View {
|
||||
@Bindable var context: ServerConfirmationScreenViewModel.Context
|
||||
|
||||
private var backgroundColor: Color {
|
||||
switch context.viewState.mode {
|
||||
case .confirmation: .compound.bgCanvasDefault
|
||||
case .picker: .compound.bgSubtleSecondaryLevel0
|
||||
}
|
||||
}
|
||||
|
||||
private var headerIcon: KeyPath<CompoundIcons, Image> {
|
||||
switch context.viewState.mode {
|
||||
case .confirmation: \.userProfileSolid
|
||||
case .picker: \.homeSolid
|
||||
}
|
||||
}
|
||||
|
||||
private var headerIconStyle: BigIcon.Style {
|
||||
switch context.viewState.mode {
|
||||
case .confirmation: .defaultSolid
|
||||
case .picker: .default
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
FullscreenDialog(topPadding: UIConstants.iconTopPaddingToNavigationBar) {
|
||||
header
|
||||
VStack(spacing: 36) {
|
||||
header
|
||||
mainContent
|
||||
}
|
||||
} bottomContent: {
|
||||
buttons
|
||||
}
|
||||
.background()
|
||||
.backgroundStyle(.compound.bgCanvasDefault)
|
||||
.backgroundStyle(backgroundColor)
|
||||
.alert(item: $context.alertInfo)
|
||||
.introspect(.window, on: .supportedVersions) { window in
|
||||
context.send(viewAction: .updateWindow(window))
|
||||
@@ -28,8 +52,7 @@ struct ServerConfirmationScreen: View {
|
||||
/// The main content of the view to be shown in a scroll view.
|
||||
var header: some View {
|
||||
VStack(spacing: 8) {
|
||||
Image(systemSymbol: .personCropCircleFill)
|
||||
.bigIcon()
|
||||
BigIcon(icon: headerIcon, style: headerIconStyle)
|
||||
.padding(.bottom, 8)
|
||||
|
||||
Text(context.viewState.title)
|
||||
@@ -38,14 +61,26 @@ struct ServerConfirmationScreen: View {
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
Text(context.viewState.message)
|
||||
.font(.compound.bodyMD)
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
if let message = context.viewState.message {
|
||||
Text(message)
|
||||
.font(.compound.bodyMD)
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var mainContent: some View {
|
||||
if case .picker(let accountProviders) = context.viewState.mode {
|
||||
FakeInlinePicker(items: accountProviders,
|
||||
icon: \.host,
|
||||
selection: $context.pickerSelection)
|
||||
.accessibilityIdentifier(A11yIdentifiers.serverConfirmationScreen.serverPicker)
|
||||
}
|
||||
}
|
||||
|
||||
/// The action buttons shown at the bottom of the view.
|
||||
var buttons: some View {
|
||||
VStack(spacing: 16) {
|
||||
@@ -55,21 +90,53 @@ struct ServerConfirmationScreen: View {
|
||||
.buttonStyle(.compound(.primary))
|
||||
.accessibilityIdentifier(A11yIdentifiers.serverConfirmationScreen.continue)
|
||||
|
||||
Button { context.send(viewAction: .changeServer) } label: {
|
||||
Text(L10n.screenServerConfirmationChangeServer)
|
||||
.font(.compound.bodyLGSemibold)
|
||||
.padding(14)
|
||||
if case .confirmation = context.viewState.mode {
|
||||
Button { context.send(viewAction: .changeServer) } label: {
|
||||
Text(L10n.screenServerConfirmationChangeServer)
|
||||
.font(.compound.bodyLGSemibold)
|
||||
.padding(14)
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.serverConfirmationScreen.changeServer)
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.serverConfirmationScreen.changeServer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is such a hack. I hate it!
|
||||
// But… We're not in a List/Form, the compound picker doesn't
|
||||
// support icons and this screen's design might change so 🤷♂️.
|
||||
private struct FakeInlinePicker: View {
|
||||
let items: [String]
|
||||
let icon: KeyPath<CompoundIcons, Image>
|
||||
@Binding var selection: String?
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
ForEach(items, id: \.self) { item in
|
||||
ListRow(label: .default(title: item, icon: icon),
|
||||
kind: .selection(isSelected: selection == item) {
|
||||
selection = item
|
||||
})
|
||||
.overlay(alignment: .bottom) {
|
||||
if item != items.last {
|
||||
Divider()
|
||||
.hidden()
|
||||
.overlay(Color.compound._borderInteractiveSecondaryAlpha)
|
||||
.padding(.leading, 54)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct ServerConfirmationScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let loginViewModel = makeViewModel(flow: .login)
|
||||
static let registerViewModel = makeViewModel(flow: .register)
|
||||
static let loginViewModel = makeViewModel(mode: .confirmation("matrix.org"), flow: .login)
|
||||
static let registerViewModel = makeViewModel(mode: .confirmation("matrix.org"), flow: .register)
|
||||
static let pickerViewModel = makeViewModel(mode: .picker(["dept1.company.com", "dept2.company.com", "dept3.company.com"]), flow: .login)
|
||||
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
@@ -83,10 +150,17 @@ struct ServerConfirmationScreen_Previews: PreviewProvider, TestablePreview {
|
||||
.toolbar(.visible, for: .navigationBar)
|
||||
}
|
||||
.previewDisplayName("Register")
|
||||
|
||||
NavigationStack {
|
||||
ServerConfirmationScreen(context: pickerViewModel.context)
|
||||
.toolbar(.visible, for: .navigationBar)
|
||||
}
|
||||
.previewDisplayName("Picker")
|
||||
}
|
||||
|
||||
static func makeViewModel(flow: AuthenticationFlow) -> ServerConfirmationScreenViewModel {
|
||||
static func makeViewModel(mode: ServerConfirmationScreenMode, flow: AuthenticationFlow) -> ServerConfirmationScreenViewModel {
|
||||
ServerConfirmationScreenViewModel(authenticationService: AuthenticationService.mock,
|
||||
mode: mode,
|
||||
authenticationFlow: flow,
|
||||
userIndicatorController: UserIndicatorControllerMock())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user