95 lines
3.0 KiB
Swift
95 lines
3.0 KiB
Swift
import SwiftUI
|
|
|
|
struct LoginView: View {
|
|
@Environment(AppState.self) private var app
|
|
|
|
@State private var serverURL: String = ""
|
|
@State private var username: String = ""
|
|
@State private var password: String = ""
|
|
@State private var remember: Bool = true
|
|
@State private var isLoading: Bool = false
|
|
|
|
var body: some View {
|
|
VStack(spacing: 16) {
|
|
Spacer()
|
|
Image(systemName: "books.vertical.fill")
|
|
.font(.system(size: 48))
|
|
.foregroundStyle(.tint)
|
|
Text("ABS Client")
|
|
.font(.largeTitle).bold()
|
|
Text("Verbinde dich mit deinem Audiobookshelf-Server")
|
|
.foregroundStyle(.secondary)
|
|
|
|
VStack(alignment: .leading, spacing: 12) {
|
|
LabeledField(label: "Server-URL", placeholder: "https://abs.example.com") {
|
|
TextField("", text: $serverURL)
|
|
.textFieldStyle(.roundedBorder)
|
|
.disableAutocorrection(true)
|
|
}
|
|
LabeledField(label: "Benutzername", placeholder: "user") {
|
|
TextField("", text: $username)
|
|
.textFieldStyle(.roundedBorder)
|
|
.disableAutocorrection(true)
|
|
}
|
|
LabeledField(label: "Passwort", placeholder: "••••••") {
|
|
SecureField("", text: $password)
|
|
.textFieldStyle(.roundedBorder)
|
|
}
|
|
Toggle("Anmeldung merken", isOn: $remember)
|
|
.toggleStyle(.checkbox)
|
|
}
|
|
.frame(maxWidth: 380)
|
|
|
|
if let err = app.auth.errorMessage {
|
|
Text(err)
|
|
.foregroundStyle(.red)
|
|
.font(.callout)
|
|
.multilineTextAlignment(.center)
|
|
.frame(maxWidth: 380)
|
|
}
|
|
|
|
Button(action: doLogin) {
|
|
if isLoading {
|
|
ProgressView().controlSize(.small)
|
|
} else {
|
|
Text("Einloggen")
|
|
.frame(maxWidth: 200)
|
|
}
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
.controlSize(.large)
|
|
.disabled(isLoading || serverURL.isEmpty || username.isEmpty || password.isEmpty)
|
|
.keyboardShortcut(.defaultAction)
|
|
|
|
Spacer()
|
|
}
|
|
.padding(32)
|
|
}
|
|
|
|
private func doLogin() {
|
|
isLoading = true
|
|
Task {
|
|
await app.auth.login(
|
|
serverURL: serverURL,
|
|
username: username,
|
|
password: password,
|
|
remember: remember
|
|
)
|
|
isLoading = false
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct LabeledField<Content: View>: View {
|
|
let label: String
|
|
let placeholder: String
|
|
@ViewBuilder let content: Content
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
Text(label).font(.subheadline).foregroundStyle(.secondary)
|
|
content
|
|
}
|
|
}
|
|
}
|