185 lines
6.2 KiB
Swift
185 lines
6.2 KiB
Swift
//
|
|
// 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: [String: AnyCodable]?
|
|
@State private var statusMessage = ""
|
|
@State private var isLoading = false
|
|
@State private var selectedDirectory: FileDirectory = .documents
|
|
|
|
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)
|
|
TextField("Email", text: $profileEmail)
|
|
.keyboardType(.emailAddress)
|
|
.textContentType(.emailAddress)
|
|
TextField("Age", text: $profileAge)
|
|
.keyboardType(.numberPad)
|
|
}
|
|
|
|
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") {
|
|
ForEach(Array(profile.keys.sorted()), id: \.self) { key in
|
|
LabeledContent(key.capitalized, value: String(describing: profile[key]?.value ?? "nil"))
|
|
}
|
|
}
|
|
}
|
|
|
|
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 Only")
|
|
}
|
|
}
|
|
.navigationTitle("File System")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
}
|
|
|
|
private func saveProfile() {
|
|
isLoading = true
|
|
Task {
|
|
do {
|
|
let key = StorageKeys.UserProfileFileKey()
|
|
let profile: [String: AnyCodable] = [
|
|
"name": AnyCodable(profileName),
|
|
"email": AnyCodable(profileEmail),
|
|
"age": AnyCodable(Int(profileAge) ?? 0),
|
|
"createdAt": AnyCodable(Date().ISO8601Format())
|
|
]
|
|
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()
|
|
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()
|
|
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()
|
|
}
|
|
}
|