Files
element-x-ios/ElementX/Sources/Services/Client/HomeserverHistoryManager.swift
Michael 6efa8743ff 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
2026-08-10 18:38:37 +01:00

75 lines
2.9 KiB
Swift

//
// Copyright 2026 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Combine
/// Manages the tracking, removal, and autocomplete matchin of previous servers in AppSettings.
/// Servers are sorted by most recently used.
class HomeserverHistoryManager {
let appSettings: AppSettings
/// cache with confirmed lowercase servers to avoid having to lowercase the entire list on every keystroke
private var cachedServers: [String] = []
var servers: [String] {
cachedServers
}
private var cancellables: Set<AnyCancellable> = []
init(appSettings: AppSettings) {
self.appSettings = appSettings
appSettings
.previousServersPublisher
.sink { [weak self] _ in
self?.updateCachedServers()
}
.store(in: &cancellables)
}
/// Tracks the given server in AppSettings's `previousServers`. The server is asserted
/// unique and placed at the beginning of the list, such that the most recent connected server is at the front.
func addServerToList(_ server: String) {
MXLog.info("Tracking server in previous servers: \(server)")
let lowercaseServer = server.lowercased()
var newList = _removeServerFromList(lowercaseServer) // don't trigger a publisher update
newList.insert(lowercaseServer, at: 0)
appSettings.previousServers = newList
}
/// Removes `server` from the tracking history of `AppSettings.previousServers`
func removeServerFromList(_ server: String) {
let lowercaseServer = server.lowercased()
appSettings.previousServers = _removeServerFromList(lowercaseServer)
}
/// Removes `lowercaseServer` from `appSettings.previousServers`
/// - Parameter lowercaseServer: the server string. It MUST be passed in with all lowercased letters.
/// - Returns: a new copy of the list without `lowercaseServer`
private func _removeServerFromList(_ lowercaseServer: String) -> [String] {
var newList = appSettings.previousServers
newList.removeAll { $0.lowercased() == lowercaseServer }
return newList
}
/// Retrieves the most recent server matching the given prefix, if any
func server(matchingPrefix prefix: String) -> String? {
let lowercasedPrefix = prefix.lowercased()
return servers.first { $0.hasPrefix(lowercasedPrefix) }
}
/// Retrieves all servers from AppSettings, previous and pre-provided and stores them in memory
/// in all lowercase. This is the list that matches are made against.
private func updateCachedServers() {
let previous = appSettings.previousServers.map { $0.lowercased() }
let defaultProviders = appSettings.accountProviders.map { $0.lowercased() }
cachedServers = previous + defaultProviders
}
}