import SwiftUI import OnyxDesign /// Was auf dem Sperrbildschirm steht: Uhr, Zustand, Passwortfeld. struct LockScreenView: View { let controller: LockController @State private var password = "" @FocusState private var isTyping: Bool var body: some View { ZStack { // Schwarz und kein Hintergrundbild: was hier zu sehen ist, soll // nichts über den Rechner verraten, der darunter liegt. Color.black.ignoresSafeArea() VStack(spacing: Onyx.Space.xxl) { Spacer() clock statusLine field Spacer() disclaimer } .padding(Onyx.Space.xxl) } } private var clock: some View { TimelineView(.everyMinute) { context in VStack(spacing: Onyx.Space.sm) { Text(context.date, format: .dateTime.hour().minute()) .font(.system(size: 84, weight: .thin)) .monospacedDigit() Text(context.date, format: .dateTime.weekday(.wide).day().month(.wide)) .font(Onyx.Font.headline) .foregroundStyle(.white.opacity(0.6)) } .foregroundStyle(.white) } } @ViewBuilder private var statusLine: some View { switch controller.status { case .looking: label("lock.looking", symbol: "faceid", tint: .white.opacity(0.7)) case .recognised: label("lock.recognised", symbol: "checkmark.circle.fill", tint: Onyx.Color.positive) case .lockedOut: label("lock.lockedOut", symbol: "exclamationmark.triangle.fill", tint: Onyx.Color.warning) case .wrongPassword: label("lock.wrongPassword", symbol: "xmark.circle.fill", tint: Onyx.Color.critical) case .passwordOnly, .idle: label("lock.password", symbol: "lock.fill", tint: .white.opacity(0.7)) } } private func label(_ key: LocalizedStringKey, symbol: String, tint: Color) -> some View { HStack(spacing: Onyx.Space.sm) { Image(systemName: symbol) Text(key, bundle: .module) } .font(Onyx.Font.body) .foregroundStyle(tint) } private var field: some View { SecureField("", text: $password, prompt: Text("lock.passwordPrompt", bundle: .module)) .textFieldStyle(.plain) .font(Onyx.Font.headline) .foregroundStyle(.white) .multilineTextAlignment(.center) .frame(width: 260) .padding(.vertical, Onyx.Space.row) .background(.white.opacity(0.10), in: .capsule) .focused($isTyping) .onSubmit { controller.submit(password: password) password = "" } .onAppear { isTyping = true } } /// Die Einschränkung steht auf dem Bildschirm selbst. /// /// Nicht im Kleingedruckten einer Einstellung, die man einmal gesehen hat: /// wer sich darauf verlässt, tut es hier. private var disclaimer: some View { Text("lock.disclaimer", bundle: .module) .font(Onyx.Font.caption) .foregroundStyle(.white.opacity(0.35)) .multilineTextAlignment(.center) .frame(maxWidth: 420) } }