### Implement Passcode Setup with SetAccessGuard Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt SetAccessGuard provides a guided flow for users to set or redefine a passcode for a CodeAccessGuard. It can be used in settings screens and includes an optional onSuccess closure. ```swift struct SecuritySettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { NavigationStack { SetAccessGuard(.transactions) { // Called after the user successfully sets their code dismiss() } .navigationTitle("Set Transaction Passcode") } } } ``` -------------------------------- ### AccessGuards Environment Object Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt The `AccessGuards` environment object allows direct interaction with access guard states. You can inject it using `@Environment(AccessGuards.self)` to perform actions like checking lock status, verifying setup completion, locking guards, and resetting passcodes. ```APIDOC ## AccessGuards Operations ### Description Provides imperative methods for manually locking guards, checking lock state, checking setup completion, and resetting stored passcodes. ### Usage Inject the `AccessGuards` environment object into your SwiftUI views: ```swift @Environment(AccessGuards.self) private var accessGuards ``` ### Methods #### `isLocked(_:)` Checks if a specific guard is currently locked. - **Parameter**: An `AccessGuardIdentifier` specifying which guard to check. - **Returns**: `true` if the guard is locked, `false` otherwise. #### `setupComplete(for:)` Checks if the setup process for a specific guard is complete. - **Parameter**: An `AccessGuardIdentifier` specifying which guard to check. - **Returns**: `true` if the setup is complete, `false` otherwise. #### `lock(_:)` Manually locks a specific guard. - **Parameter**: An `AccessGuardIdentifier` specifying which guard to lock. #### `resetAccessCode(for:)` Resets the access code for a specific guard. - **Parameter**: An `AccessGuardIdentifier` specifying which guard to reset. - **Throws**: Potentially throws an error if the reset operation fails. ``` -------------------------------- ### Configure Code-Based Access Guard Source: https://github.com/stanfordspezi/speziaccessguard/blob/main/Sources/SpeziAccessGuard/SpeziAccessGuard.docc/SpeziAccessGuard.md Configure a CodeAccessGuard with a 4-digit numeric code, optional entry, and a 1-hour timeout. This guard is identified as 'exampleAccessGuard'. ```swift import Spezi import SpeziAccessGuard class ExampleDelegate: SpeziAppDelegate { override var configuration: Configuration { Configuration { AccessGuards { CodeAccessGuard( .exampleAccessGuard, codeFormat: .numeric(4), isOptional: true, timeout: .hours(1) ) } } } } extension AccessGuardIdentifier where AccessGuard == CodeAccessGuard { static let exampleAccessGuard: Self = .passcode("edu.stanford.spezi.exampleAccessGuard") } ``` -------------------------------- ### Configure CodeAccessGuard Initializers Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt Demonstrates different initializers for `CodeAccessGuard`: user-defined optional numeric codes, app-defined fixed codes, and custom validation logic for dynamic checks like one-time codes. Passcodes are securely stored in the Keychain. ```swift // 1. User-defined 4-digit code, optional (unlocked by default until user sets a code) CodeAccessGuard( .accountView, codeFormat: .numeric(4), isOptional: true, timeout: .hours(1) ) // 2. Fixed code (app-defined, 4-digit numeric inferred automatically) CodeAccessGuard(.hiddenFeature, fixed: "7184", timeout: .minutes(10)) // 3. Custom-validation: consumable one-time codes @MainActor final class ConsumableCodes: Sendable { private(set) var remainingCodes = ["1111", "2222", "3333"] private(set) var consumedCodes: [String] = [] func validate(_ code: String) -> CodeAccessGuard.ValidationResult { if let idx = remainingCodes.firstIndex(of: code) { remainingCodes.remove(at: idx) consumedCodes.append(code) return .valid } return consumedCodes.contains(code) ? .invalid(message: "Code Already Used") : .invalid } } // In AppDelegate: let consumableCodes = ConsumableCodes() AccessGuards { CodeAccessGuard(.transactions, format: .numeric(4)) { await consumableCodes.validate(code) } } ``` -------------------------------- ### Configure Access Guards in SpeziAppDelegate Source: https://github.com/stanfordspezi/speziaccessguard/blob/main/README.md Define and configure various access guards like numeric codes and biometrics within your SpeziAppDelegate. Ensure Spezi is set up before configuring access guards. ```swift import Spezi import SpeziAccessGuard class ExampleDelegate: SpeziAppDelegate { override var configuration: Configuration { Configuration { AccessGuards { CodeAccessGuard(.transactions) BiometricAccessGuard(.accountInfo) CodeAccessGuard(.hiddenFeature, fixed: "7184") } } } } extension AccessGuardIdentifier where AccessGuard == CodeAccessGuard { static let transactions: Self = .passcode("com.myApp.transactions") static let hiddenFeature: Self = .passcode("com.myApp.hiddenFeature") } extension AccessGuardIdentifier where AccessGuard == BiometricAccessGuard { static let accountInfo: Self = .passcode("com.myApp.accountInfo") } ``` -------------------------------- ### Register AccessGuards Module in AppDelegate Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt Register the `AccessGuards` module in your `configuration` within the `AppDelegate`. This sets up various access guards like numeric passcodes, biometric authentication, and fixed-code guards with specified timeouts. ```swift import Spezi import SpeziAccessGuard class AppDelegate: SpeziAppDelegate { override var configuration: Configuration { Configuration { AccessGuards { // 4-digit user-defined numeric passcode, locks after 5 min in background CodeAccessGuard(.transactions, codeFormat: .numeric(4), timeout: .minutes(5)) // Face ID with 6-char alphanumeric fallback BiometricAccessGuard(.accountInfo) // App-defined fixed passcode CodeAccessGuard(.hiddenFeature, fixed: "7184") } } } } // Define typed identifiers as static extensions extension AccessGuardIdentifier where AccessGuard == CodeAccessGuard { static let transactions: Self = .passcode("com.myApp.transactions") static let hiddenFeature: Self = .passcode("com.myApp.hiddenFeature") } extension AccessGuardIdentifier where AccessGuard == BiometricAccessGuard { static let accountInfo: Self = .biometric("com.myApp.accountInfo") } ``` -------------------------------- ### Define Passcode Formats Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt PasscodeFormat configures numeric or alphanumeric passcodes with exact or minimum length requirements. Used with CodeAccessGuard. ```swift // Exact-length formats PasscodeFormat.numeric(4) // exactly 4 digits PasscodeFormat.alphanumeric(6) // exactly 6 alphanumeric chars // Minimum-length formats PasscodeFormat.numeric(4...) // 4 or more digits PasscodeFormat.alphanumeric(8...) // 8 or more alphanumeric chars // Usage in CodeAccessGuard CodeAccessGuard(.settingsView, codeFormat: .numeric(6), timeout: .minutes(15)) CodeAccessGuard(.adminPanel, codeFormat: .alphanumeric(8...), timeout: .hours(2)) ``` -------------------------------- ### Create Inline AccessGuardButton Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt AccessGuardButton displays different content based on lock status. When locked, it shows a button to present an unlock sheet. Useful for protecting individual UI elements. ```swift struct PaymentRow: View { var body: some View { AccessGuardButton(.transactions) { // Shown when locked — tap to trigger unlock sheet Label("Locked – tap to view", systemImage: "lock.fill") .foregroundStyle(.secondary) } unlocked: { // Shown after successful unlock TransactionDetailView() } } } // Define identifier extension AccessGuardIdentifier where AccessGuard == CodeAccessGuard { static let transactions: Self = .passcode("com.myApp.transactions") } ``` -------------------------------- ### Control Access Guards in SwiftUI Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt Inject the AccessGuards environment object to imperatively lock guards, check their state, and reset passcodes within a SwiftUI view. ```swift struct SecurityControlView: View { @Environment(AccessGuards.self) private var accessGuards var body: some View { Form { Section("Status") { LabeledContent("Transactions locked") { Text(accessGuards.isLocked(.transactions) ? "Yes" : "No") } LabeledContent("Passcode set") { Text(accessGuards.setupComplete(for: .transactions) ? "Yes" : "No") } } Section("Actions") { Button("Lock Transactions Now") { accessGuards.lock(.transactions) } Button("Reset Passcode", role: .destructive) { try? accessGuards.resetAccessCode(for: .transactions) } } } } } ``` -------------------------------- ### Inspect Guard State with @AccessGuard Property Wrapper Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt The @AccessGuard property wrapper injects the live guard model into SwiftUI views, exposing state like isLocked and config. Use it for custom unlock UIs or reacting to lock state changes. ```swift struct ProtectedDashboard: View { @AccessGuard private var txGuard = .init(.transactions) var body: some View { VStack { if txGuard.isLocked { Label("Transactions are locked", systemImage: "lock") .foregroundStyle(.red) } else { TransactionsList() } } } } ``` -------------------------------- ### Configure Biometric Access Guard Source: https://github.com/stanfordspezi/speziaccessguard/blob/main/Sources/SpeziAccessGuard/SpeziAccessGuard.docc/SpeziAccessGuard.md Configure a BiometricAccessGuard for transactions list. Ensure NSFaceIDUsageDescription is added to your app's Info.plist. ```swift import Spezi import SpeziAccessGuard class ExampleDelegate: SpeziAppDelegate { override var configuration: Configuration { Configuration { AccessGuards { BiometricAccessGuard(.transactionsList) } } } } extension AccessGuardIdentifier where AccessGuard == BiometricAccessGuard { static let transactionsList: Self = .biometric("com.MyApp.transactionsList") } ``` -------------------------------- ### Define Typed Guard Identifiers Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt Define unique, typed identifiers for your access guards using static extensions on `AccessGuardIdentifier`. This ensures type safety and uniqueness across your `AccessGuards` configuration. ```swift // Passcode-based identifier extension AccessGuardIdentifier where AccessGuard == CodeAccessGuard { static let accountView: Self = .passcode("com.myApp.accountView") static let settingsView: Self = .passcode("com.myApp.settingsView") } // Biometric-based identifier extension AccessGuardIdentifier where AccessGuard == BiometricAccessGuard { static let paymentHistory: Self = .biometric("com.myApp.paymentHistory") } ``` -------------------------------- ### Wrap Content with AccessGuarded Source: https://context7.com/stanfordspezi/speziaccessguard/llms.txt AccessGuarded is a SwiftUI view that wraps protected content, presenting an unlock UI (passcode or biometric) when locked and the content when unlocked. It automatically manages lock state. ```swift struct MainTabView: View { var body: some View { TabView { Tab("Home", systemImage: "house") { HomeView() } Tab("Transactions", systemImage: "list.bullet.rectangle.portrait") { // Guarded with a passcode; shows EnterCodeView when locked AccessGuarded(.transactions) { TransactionsList() } } Tab("Account", systemImage: "person.circle") { // Guarded with Face ID AccessGuarded(.accountInfo) { AccountTab() } } } } } ``` -------------------------------- ### Protect SwiftUI Views with AccessGuarded Source: https://github.com/stanfordspezi/speziaccessguard/blob/main/README.md Wrap your SwiftUI views with the AccessGuarded view modifier to automatically manage the presentation and unlocking of the associated access guard. ```swift var body: some View { TabView { // ... Tab("Account", systemImage: "person.circle") { AccessGuarded(.accountInfo) { AccountTab() } } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.