// // FileSystemDemo.swift // SecureStorgageSample // // Demonstrates file system storage with LocalData package. // import SwiftUI import LocalData struct FileSystemDemo: View { @State private var profileName = "" @State private var profileEmail = "" @State private var profileAge = "" @State private var storedProfile: UserProfile? @State private var statusMessage = "" @State private var isLoading = false @State private var selectedDirectory: FileDirectory = .documents @FocusState private var isFieldFocused: Bool var body: some View { Form { Section { Text("File system storage is great for larger data like user profiles, cached content, and structured documents.") .font(.caption) .foregroundStyle(.secondary) } Section("Profile Data") { TextField("Name", text: $profileName) .focused($isFieldFocused) TextField("Email", text: $profileEmail) .keyboardType(.emailAddress) .textContentType(.emailAddress) .focused($isFieldFocused) TextField("Age", text: $profileAge) .keyboardType(.numberPad) .focused($isFieldFocused) } Section("Storage Location") { Picker("Directory", selection: $selectedDirectory) { Text("Documents").tag(FileDirectory.documents) Text("Caches").tag(FileDirectory.caches) } .pickerStyle(.segmented) Text(selectedDirectory == .documents ? "Documents: Persisted, included in backups" : "Caches: May be cleared by system, not backed up") .font(.caption) .foregroundStyle(.secondary) } Section("Actions") { Button(action: saveProfile) { HStack { Image(systemName: "doc.fill") Text("Save to File System") } } .disabled(profileName.isEmpty || isLoading) Button(action: loadProfile) { HStack { Image(systemName: "doc.text.fill") Text("Load from File System") } } .disabled(isLoading) Button(action: deleteProfile) { HStack { Image(systemName: "trash") Text("Delete File") } } .foregroundStyle(.red) .disabled(isLoading) } if let profile = storedProfile { Section("Retrieved Profile") { LabeledContent("Name", value: profile.name) LabeledContent("Email", value: profile.email) LabeledContent("Age", value: profile.ageDescription) LabeledContent("Created", value: profile.createdAt.formatted(date: .abbreviated, time: .shortened)) } } if !statusMessage.isEmpty { Section { Text(statusMessage) .font(.caption) .foregroundStyle(statusMessage.contains("Error") ? .red : .green) } } Section("Key Configuration") { LabeledContent("Domain", value: "File System") LabeledContent("Security", value: "None") LabeledContent("Serializer", value: "JSON") LabeledContent("Platform", value: "Phone + Watch Sync") } } .navigationTitle("File System") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { isFieldFocused = false } } } } private func saveProfile() { isLoading = true Task { do { let key = StorageKeys.UserProfileFileKey(directory: selectedDirectory) let profile = UserProfile( name: profileName, email: profileEmail, age: Int(profileAge), createdAt: Date() ) try await StorageRouter.shared.set(profile, for: key) statusMessage = "✓ Saved to \(selectedDirectory == .documents ? "Documents" : "Caches")" } catch { statusMessage = "Error: \(error.localizedDescription)" } isLoading = false } } private func loadProfile() { isLoading = true Task { do { let key = StorageKeys.UserProfileFileKey(directory: selectedDirectory) storedProfile = try await StorageRouter.shared.get(key) statusMessage = "✓ Loaded from file system" } catch StorageError.notFound { storedProfile = nil statusMessage = "No profile file found" } catch { statusMessage = "Error: \(error.localizedDescription)" } isLoading = false } } private func deleteProfile() { isLoading = true Task { do { let key = StorageKeys.UserProfileFileKey(directory: selectedDirectory) try await StorageRouter.shared.remove(key) storedProfile = nil statusMessage = "✓ File deleted" } catch { statusMessage = "Error: \(error.localizedDescription)" } isLoading = false } } } extension FileDirectory: Hashable { public func hash(into hasher: inout Hasher) { switch self { case .documents: hasher.combine("documents") case .caches: hasher.combine("caches") case .custom(let url): hasher.combine(url) } } public static func == (lhs: FileDirectory, rhs: FileDirectory) -> Bool { switch (lhs, rhs) { case (.documents, .documents): return true case (.caches, .caches): return true case (.custom(let a), .custom(let b)): return a == b default: return false } } } #Preview { NavigationStack { FileSystemDemo() } }