Initial commit
This commit is contained in:
127
apple-client/Sources/App/SettingsView.swift
Normal file
127
apple-client/Sources/App/SettingsView.swift
Normal 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user