Combine the Server Selection screen into the Server Confirmation screen and add autocompletion when entering an account provider. (#5949)

* Adjust login flow to exclusively use the ServerSelectionScreen

* Move async code to server selection vm

* ServerSelection supports pro picker options

* Use homeserver address for both confirmation and picker modes

* rename ServerSelectionScreenMode

* remove ServerConfirmationScreen

It's been superseded by the ServerSelectionScreen

* rename userInput

* Update strings with latest design strings

* Add server input autocompletion

* Store previous servers in AppSettings and autofill on server signin

* Audit changes for logging

* Enforce lowercase server history storage

* Update tests

* Update Xcode project

* PR review fixups

* Add HomeserverHistoryManager

* Review fixups 2

* Review fixups 3
This commit is contained in:
Michael
2026-08-10 12:38:37 -05:00
committed by GitHub
parent 42a7b6e8ee
commit 6efa8743ff
71 changed files with 977 additions and 1357 deletions
@@ -6,21 +6,71 @@
// Please see LICENSE files in the repository root for full details.
//
import Foundation
import SwiftUI
enum ServerSelectionScreenViewModelAction {
/// The homeserver selection has been updated.
case updated
/// Dismiss the view without using the entered address.
case dismiss
/// Continue the flow using the provided OAuth parameters.
case continueWithOAuth(data: OAuthAuthorizationDataProxy, window: UIWindow)
/// Continue the flow using password authentication.
case continueWithPassword
}
enum ServerSelectionScreenMode: Equatable {
/// The user is confirming the displayed account provider (or can enter their own).
case userInput
/// The user is only allowed to pick from a list of account providers.
case picker([String])
}
struct ServerSelectionScreenViewState: BindableState {
/// The message to be shown in the text field footer when no error has occurred.
private let regularFooterMessage = L10n.screenChangeServerFormNotice
/// Whether the screen is configured to confirm a single account provider or pick one from a list of many.
var mode: ServerSelectionScreenMode
/// Whether the screen is configured for registration or existing account login
var authenticationFlow: AuthenticationFlow
/// The presentation anchor used for OAuth authentication.
var window: UIWindow?
/// View state that can be bound to from SwiftUI.
var bindings: ServerSelectionScreenBindings
/// Upon introspection, this is the UITextField backing the TextField for server input
var textField: UITextField? {
get { textFieldAdapter.textField }
set { textFieldAdapter.textField = newValue }
}
/// Adapts the text field for custom functionality beyond what's available in SwiftUI
let textFieldAdapter = TextFieldAdapter()
var screenTitle: String {
switch authenticationFlow {
case .login:
L10n.screenChangeServerNavigationTitleLogin
case .register:
L10n.screenChangeServerNavigationTitleRegister
}
}
/// The header text for the screen
var screenHeader: String {
switch authenticationFlow {
case .login:
L10n.screenChangeServerTitleLogin
case .register:
L10n.screenChangeServerTitleRegister
}
}
/// The message to be shown in the text field footer when no error has occurred.
var regularFooterMessage: String {
switch authenticationFlow {
case .login:
L10n.screenChangeServerTextfieldFooterLogin
case .register:
L10n.screenChangeServerTextfieldFooterRegister
}
}
/// An error message to be shown in the text field footer.
var footerErrorMessage: String?
@@ -36,22 +86,32 @@ struct ServerSelectionScreenViewState: BindableState {
/// Whether it is possible to continue when tapping the confirmation button.
var hasValidationError: Bool {
bindings.homeserverAddress.isEmpty || isShowingFooterError
switch mode {
case .userInput:
bindings.homeserverAddress.isEmpty || isShowingFooterError
case .picker(let options):
!options.contains(bindings.homeserverAddress) || isShowingFooterError
}
}
}
struct ServerSelectionScreenBindings {
/// The homeserver address input by the user.
/// The homeserver address input or chosen by the user.
var homeserverAddress: String
/// The selection range in `homeserverAddress`
var homeserverSelection: TextSelection?
/// Information describing the currently displayed alert.
var alertInfo: AlertInfo<ServerSelectionScreenErrorType>?
}
enum ServerSelectionScreenViewAction {
/// Updates the window used as the OAuth presentation anchor.
case updateWindow(UIWindow)
/// Updates the textfield from introspection
case updateTextField(UITextField)
/// The user would like to use the homeserver at the input address.
case confirm
/// Dismiss the view without using the entered address.
case dismiss
/// Clear any errors shown in the text field footer.
case clearFooterError
}
@@ -67,4 +127,6 @@ enum ServerSelectionScreenErrorType: Hashable {
case registrationAlert
/// An alert that informs the user that Element Pro should be used for a particular server.
case elementProAlert
/// An unknown error has occurred.
case unknownError
}