SecureStorageSample/SecureStorgageSample/Views/FileSystemDemo.swift

177 lines
6.1 KiB
Swift

//
// FileSystemDemo.swift
// SecureStorgageSample
//
// Demonstrates file system storage with LocalData package.
//
import SwiftUI
import LocalData
import SharedKit
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
}
}
}
#Preview {
NavigationStack {
FileSystemDemo()
}
}