feat: refine native iOS chat experience

This commit is contained in:
snowspeeder committed 2026-10-03 18:55:28 -04:00
1 parent 9c5e9bce5b
commit 7bd893ae5c
14 files changed
+415 -93

No files matched your search

+26 -7
View File
@@ -7,6 +7,8 @@ struct LoginView: View {
@State private var password = ""
@State private var server = ""
@State private var serverError: String?
@State private var savedServer: String?
@State private var passwordVisible = false
@Environment(\.dynamicTypeSize) private var typeSize
var body: some View {
NavigationStack {
@@ -29,11 +31,21 @@ struct LoginView: View {
Section("Account") {
TextField("Username", text: $username).textContentType(.username)
.textInputAutocapitalization(.never).autocorrectionDisabled()
SecureField("Password", text: $password).textContentType(.password)
HStack {
Group {
if passwordVisible { TextField("Password", text: $password) }
else { SecureField("Password", text: $password) }
}
.textContentType(.password)
Button(passwordVisible ? "Hide" : "Show") { passwordVisible.toggle() }
.accessibilityLabel(passwordVisible ? "Hide password" : "Show password")
}
Button("Sign in") {
let suppliedPassword = password
password = ""
Task { await auth.login(username: username, password: suppliedPassword) }
Task {
await auth.login(username: username, password: suppliedPassword)
if auth.user != nil { password = "" }
}
}
.font(NearlightFont.control(typeSize))
.buttonStyle(.borderedProminent)
@@ -54,13 +66,19 @@ struct LoginView: View {
.textInputAutocapitalization(.never).autocorrectionDisabled()
Button("Save server address") {
switch ServerConfig.parse(server) {
case .success(let config): settings.serverURL = config.baseURL.absoluteString
case .failure(let error): serverError = error.localizedDescription
case .success(let config):
server = config.baseURL.absoluteString
settings.serverURL = config.baseURL.absoluteString
serverError = nil
savedServer = config.baseURL.absoluteString
case .failure(let error): serverError = error.localizedDescription; savedServer = nil
}
}.disabled(auth.isBusy)
}.disabled(auth.isBusy || server.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || server == settings.serverURL)
if let serverError {
Text(serverError).foregroundStyle(Nearlight.alert)
Label(serverError, systemImage: "exclamationmark.circle").foregroundStyle(Nearlight.alert)
.fixedSize(horizontal: false, vertical: true)
} else if savedServer != nil {
Label("Server address saved. Sign in uses this server.", systemImage: "checkmark.circle").font(.footnote).foregroundStyle(Nearlight.quiet)
}
Text("Connections use HTTPS and secure WebSockets. A private server certificate must be trusted by this iPhone for conversations.")
.font(.footnote).foregroundStyle(Nearlight.quiet)
@@ -81,6 +99,7 @@ struct LoginView: View {
.navigationTitle("Hope")
.toolbarBackground(Nearlight.ground, for: .navigationBar)
.onAppear { server = settings.serverURL }
.onChange(of: server) { _, _ in serverError = nil; savedServer = nil }
}
}
}