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
@@ -20,18 +20,10 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
// Splash Screen: Tap get started button
app.buttons[A11yIdentifiers.authenticationStartScreen.signIn].tap()
// Server Confirmation: Tap change server button
app.buttons[A11yIdentifiers.serverConfirmationScreen.changeServer].tap()
// Server Selection: Clear the default, enter OAuth server and continue.
// Server Selection: Clear the default, enter a server address and submit.
// The \n triggers confirm directly, navigating to the login screen.
app.textFields[A11yIdentifiers.changeServerScreen.server].clearAndTypeText("example.com\n", app: app)
// Await for the button to be hittable, since a loader may appear
let serverConfirmationContinueButton = app.buttons[A11yIdentifiers.serverConfirmationScreen.continue]
XCTAssertTrue(serverConfirmationContinueButton.wait(for: \.isHittable, toEqual: true, timeout: 2.0))
// Server Confirmation: Tap continue button
serverConfirmationContinueButton.tap()
// Login Screen: Wait for continue button to appear
let continueButton = app.buttons[A11yIdentifiers.loginScreen.continue]
XCTAssertTrue(continueButton.waitForExistence(timeout: 2.0))
@@ -53,18 +45,10 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
// Splash Screen: Tap get started button
app.buttons[A11yIdentifiers.authenticationStartScreen.signIn].tap()
// Server Confirmation: Tap change server button
app.buttons[A11yIdentifiers.serverConfirmationScreen.changeServer].tap()
// Server Selection: Clear the default, enter OAuth server and continue.
// Server Selection: Clear the default, enter a server address and submit.
// The \n triggers confirm directly, navigating to the login screen.
app.textFields[A11yIdentifiers.changeServerScreen.server].clearAndTypeText("example.com\n", app: app)
// Await for the button to be hittable, since a loader may appear
let serverConfirmationContinueButton = app.buttons[A11yIdentifiers.serverConfirmationScreen.continue]
XCTAssertTrue(serverConfirmationContinueButton.wait(for: \.isHittable, toEqual: true, timeout: 2.0))
// Server Confirmation: Tap continue button
serverConfirmationContinueButton.tap()
// Login Screen: Wait for continue button to appear
let continueButton = app.buttons[A11yIdentifiers.loginScreen.continue]
XCTAssertTrue(continueButton.waitForExistence(timeout: 2.0))
@@ -88,18 +72,10 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
// Splash Screen: Tap get started button
app.buttons[A11yIdentifiers.authenticationStartScreen.signIn].tap()
// Server Confirmation: Tap change server button
app.buttons[A11yIdentifiers.serverConfirmationScreen.changeServer].tap()
// Server Selection: Clear the default, enter OAuth server and continue.
// Server Selection: Clear the default, enter a server address and submit.
// The \n triggers confirm directly, navigating to the login screen.
app.textFields[A11yIdentifiers.changeServerScreen.server].clearAndTypeText("example.com\n", app: app)
// Await for the button to be hittable, since a loader may appear
let serverConfirmationContinueButton = app.buttons[A11yIdentifiers.serverConfirmationScreen.continue]
XCTAssertTrue(serverConfirmationContinueButton.wait(for: \.isHittable, toEqual: true, timeout: 2.0))
// Server Confirmation: Tap continue button
serverConfirmationContinueButton.tap()
// Login Screen: Wait for continue button to appear
let continueButton = app.buttons[A11yIdentifiers.loginScreen.continue]
XCTAssertTrue(continueButton.waitForExistence(timeout: 2.0))
@@ -125,9 +101,6 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
// Splash Screen: Tap get started button
app.buttons[A11yIdentifiers.authenticationStartScreen.signIn].tap()
// Server Confirmation: Tap change server button
app.buttons[A11yIdentifiers.serverConfirmationScreen.changeServer].tap()
// Server Selection: Clear the default, enter OAuth server and continue.
app.textFields[A11yIdentifiers.changeServerScreen.server].clearAndTypeText("company.com\n", app: app)
@@ -139,8 +112,8 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
// Keep looping on the Continue button for ~5 minutes until the Authentication Session is happy.
var remainingAttempts = 30
while !wasAlertText.exists {
// Server Confirmation: Tap continue button
app.buttons[A11yIdentifiers.serverConfirmationScreen.continue].tap()
// Server Selection: Tap continue button
app.buttons[A11yIdentifiers.changeServerScreen.continue].tap()
if wasAlertText.waitForExistence(timeout: 10) {
break
@@ -223,9 +196,11 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
// Splash Screen: Tap get started button
app.buttons[A11yIdentifiers.authenticationStartScreen.signIn].tap()
// Server Confirmation: Tap the picker and confirm
app.switches.matching(identifier: A11yIdentifiers.serverConfirmationScreen.serverPicker).element(boundBy: 1).tap()
app.buttons[A11yIdentifiers.serverConfirmationScreen.continue].tap()
// Server Selection: Tap the second server in the picker and confirm.
// Use descendants(matching: .any) since ListRow used outside a List produces an ambiguous
// accessibility element type, making element-type-specific queries unreliable.
app.descendants(matching: .any).matching(identifier: "example.com").firstMatch.tap()
app.buttons[A11yIdentifiers.changeServerScreen.continue].tap()
// Login Screen: Wait for continue button to appear
let continueButton = app.buttons[A11yIdentifiers.loginScreen.continue]
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:26d4cf939e3b6dbb78652c3480a2c329f423bf4f1853e3870d282b78d9a39bf3
size 166621
oid sha256:9a1768669c060c14dc99eee7355f7c482417ed3f87040b4a6f9e6ec39de6a54b
size 171208
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cbcdaaa2d6ddb37e331027c598b5a818ff025b21068dbb0982e3b7db2e1a5171
size 170739
oid sha256:a9048c7635c8e6d54a6f9cc0641fef1a7ef8d47bffbadbcff383221292dfc7a3
size 178955
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ab299696c4358f35d57b48a3dad5d783c1776e23e81b67e915c69e1fca021dc5
size 115595
oid sha256:32ab691123f12169747b3ee8fa26ec6cea48478aa87c607b40de6f7665cd6e07
size 107836
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e4ee7497137b730cc1e62740ccf7d90756002ac9f72e53de9251f0be070af28d
size 133905
oid sha256:c30d4677ac36d40b6cf1fd654c1ee13ffdad5533a5d49dac68c62e94b951da2d
size 119739
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e59419f59671ec5fdaf2bc817e29456ef318de0e89f574b087a92b9437a15d56
size 96869
oid sha256:90df1f4842b0f49551d39016fcb33a95a910a92655f6842a116443a78d4caf61
size 101227
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:785e95a2df0dbf82654d9d10007ee211e4532f9e6f72130b8d361dcb50206876
size 105940
oid sha256:43cb650082cb249d296df4cd72dc1859eaf4a3a6d2f6ccf1e92d0984cab52191
size 109976