Initial commit

This commit is contained in:
2026-03-09 19:35:08 +01:00
commit f6b790a515
64 changed files with 18778 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
import SwiftUI
struct SettingsView: View {
@Bindable var settings: SettingsStore
var body: some View {
Form {
Section("Backend") {
TextField("Backend URL", text: $settings.backendURLString)
.onSubmit {
settings.saveBackendURL()
}
.platformCredentialField()
Button("Apply Backend URL") {
settings.saveBackendURL()
}
}
Section("Session") {
if let user = settings.currentUser {
LabeledContent("Signed in as", value: user.displayName)
LabeledContent("Username", value: user.username)
Button("Sign out", role: .destructive) {
Task {
await settings.signOut()
}
}
} else {
Picker("Mode", selection: $settings.authMode) {
ForEach(SettingsStore.AuthMode.allCases) { mode in
Text(mode == .login ? "Log in" : "Register").tag(mode)
}
}
.pickerStyle(.segmented)
if settings.authMode == .register {
TextField("Display name", text: $settings.displayName)
}
TextField("Username", text: $settings.username)
.platformCredentialField()
SecureField("Password", text: $settings.password)
Button(settings.authMode == .login ? "Authenticate" : "Create account") {
Task {
await settings.authenticate()
}
}
.disabled(settings.isBusy)
Button("Use access key") {
Task {
await settings.signInWithAccessKey()
}
}
.disabled(settings.isBusy)
}
}
Section("Access Keys") {
if settings.currentUser == nil {
Text("Sign in before registering or listing access keys.")
.foregroundStyle(.secondary)
} else {
TextField("New access key label", text: $settings.accessKeyLabel)
Button("Register access key") {
Task {
await settings.registerAccessKey()
}
}
.disabled(settings.isBusy)
if settings.accessKeys.isEmpty {
Text("No access keys registered yet.")
.foregroundStyle(.secondary)
} else {
ForEach(settings.accessKeys) { key in
VStack(alignment: .leading, spacing: 4) {
Text(key.label)
.font(.headline)
Text("Device: \(key.deviceType)\(key.backedUp ? " / backed up" : "")")
.font(.subheadline)
.foregroundStyle(.secondary)
Text("Transports: \(key.transports.isEmpty ? "unspecified" : key.transports.joined(separator: ", "))")
.font(.footnote)
.foregroundStyle(.secondary)
}
.padding(.vertical, 4)
}
}
}
}
if let infoMessage = settings.infoMessage {
Section("Status") {
Text(infoMessage)
.foregroundStyle(.secondary)
}
}
if let errorMessage = settings.errorMessage {
Section("Error") {
Text(errorMessage)
.foregroundStyle(.red)
}
}
}
.formStyle(.grouped)
.padding()
.frame(minWidth: 420, minHeight: 520)
}
}
private extension View {
@ViewBuilder
func platformCredentialField() -> some View {
#if os(iOS)
textInputAutocapitalization(.never)
.autocorrectionDisabled()
#else
self
#endif
}
}