Add Design, Spacing, Color, Status (+1 more)
This commit is contained in:
parent
67dbfa9e09
commit
c50c9cb60e
@ -122,8 +122,11 @@ The app demonstrates various storage configurations:
|
||||
- Global sync configuration (max file size) in app `init`
|
||||
|
||||
### Data Migration
|
||||
- **Fallback**: Automatically moves data from `LegacyMigrationSourceKey` to `ModernMigrationDestinationKey` on first access.
|
||||
- **Manual Sweep**: Explicitly triggers a "drain" of legacy keys to the Keychain using `StorageRouter.shared.migrate(for:)`.
|
||||
- **Fallback**: Automatically moves data from `LegacyMigrationSourceKey` to `ModernMigrationDestinationKey` on first access using protocol-based migration.
|
||||
- **Transforming**: Converts a legacy full-name string into a structured `ProfileName`.
|
||||
- **Aggregating**: Combines legacy notification + theme settings into `UnifiedSettings`.
|
||||
- **Conditional**: Migrates app mode only when the version rule is met.
|
||||
- **Manual Sweep**: Explicitly triggers a "drain" of legacy keys to the Keychain using `StorageRouter.shared.forceMigration(for:)`.
|
||||
- **Startup Sweep**: Automatically cleanses all registered legacy keys at app launch via `registerCatalog(..., migrateImmediately: true)`.
|
||||
|
||||
## Global Configuration
|
||||
|
||||
23
SecureStorageSample/Design/DesignConstants.swift
Normal file
23
SecureStorageSample/Design/DesignConstants.swift
Normal file
@ -0,0 +1,23 @@
|
||||
import SwiftUI
|
||||
|
||||
enum Design {
|
||||
enum Spacing {
|
||||
static let xSmall: CGFloat = 4
|
||||
static let small: CGFloat = 8
|
||||
static let medium: CGFloat = 16
|
||||
static let large: CGFloat = 24
|
||||
}
|
||||
}
|
||||
|
||||
extension Color {
|
||||
enum Status {
|
||||
static let success = Color.green
|
||||
static let info = Color.blue
|
||||
static let warning = Color.orange
|
||||
static let error = Color.red
|
||||
}
|
||||
|
||||
enum Text {
|
||||
static let secondary = Color.secondary
|
||||
}
|
||||
}
|
||||
@ -32,9 +32,13 @@ extension StorageKeys {
|
||||
let availability: PlatformAvailability = .all
|
||||
let syncPolicy: SyncPolicy = .never
|
||||
|
||||
// Define the migration path
|
||||
var migrationSources: [AnyStorageKey] {
|
||||
[AnyStorageKey(LegacyMigrationSourceKey())]
|
||||
var migration: AnyStorageMigration? {
|
||||
AnyStorageMigration(
|
||||
SimpleLegacyMigration(
|
||||
destinationKey: self,
|
||||
sourceKey: .key(LegacyMigrationSourceKey())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,12 +13,13 @@ struct MigrationDemo: View {
|
||||
Section("The Scenario") {
|
||||
Text("Imagine you have an old version of the app that stored a User ID in plain UserDefaults. Now, you want to move it to the secure Keychain automatically without the user noticing.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.foregroundStyle(Color.Text.secondary)
|
||||
}
|
||||
|
||||
Section("Step 1: Setup Legacy Data") {
|
||||
Text("First, save a value to the 'legacy' key in UserDefaults.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color.Text.secondary)
|
||||
|
||||
TextField("Legacy Value", text: $legacyValue)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
@ -30,8 +31,9 @@ struct MigrationDemo: View {
|
||||
}
|
||||
|
||||
Section("Step 2: Trigger Migration") {
|
||||
Text("Now, attempt to load from the 'modern' Keychain key. It will automatically check the legacy key, move the data, and delete the old record.")
|
||||
Text("Now, attempt to load from the 'modern' Keychain key. It will automatically check the legacy key, move the data, and delete the old record using the new migration protocol.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color.Text.secondary)
|
||||
|
||||
Button(action: loadFromModern) {
|
||||
Label("Load from Modern (Keychain)", systemImage: "sparkles")
|
||||
@ -40,17 +42,18 @@ struct MigrationDemo: View {
|
||||
|
||||
if !modernValue.isEmpty {
|
||||
LabeledContent("Migrated Value", value: modernValue)
|
||||
.foregroundStyle(.green)
|
||||
.foregroundStyle(Color.Status.success)
|
||||
.bold()
|
||||
}
|
||||
}
|
||||
|
||||
Section("Step 3: Proactive Sweep (Drain)") {
|
||||
Text("Even if the modern key already has data, you can force a 'Sweep' of legacy sources. Try saving a NEW value to Legacy, then click Drain.")
|
||||
Text("Even if the modern key already has data, you can force a sweep of legacy sources. Try saving a new value to Legacy, then click Force Migration.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color.Text.secondary)
|
||||
|
||||
Button(action: runManualMigration) {
|
||||
Label("Drain Migration Sources", systemImage: "arrow.up.circle.badge.clock")
|
||||
Label("Force Migration", systemImage: "arrow.up.circle.badge.clock")
|
||||
}
|
||||
.disabled(isLoading)
|
||||
}
|
||||
@ -58,6 +61,7 @@ struct MigrationDemo: View {
|
||||
Section("Step 4: Verify Cleanup") {
|
||||
Text("Check if the data was actually removed from UserDefaults after migration.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color.Text.secondary)
|
||||
|
||||
Button(action: checkLegacyExists) {
|
||||
Label("Check Legacy Exists?", systemImage: "magnifyingglass")
|
||||
@ -69,7 +73,7 @@ struct MigrationDemo: View {
|
||||
Section {
|
||||
Text(statusMessage)
|
||||
.font(.caption)
|
||||
.foregroundStyle(statusMessage.contains("Error") ? .red : .blue)
|
||||
.foregroundStyle(statusMessage.contains("Error") ? Color.Status.error : Color.Status.info)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,14 +117,14 @@ struct MigrationDemo: View {
|
||||
|
||||
private func runManualMigration() {
|
||||
isLoading = true
|
||||
statusMessage = "Draining migration sources..."
|
||||
statusMessage = "Running manual migration..."
|
||||
Task {
|
||||
do {
|
||||
let key = StorageKeys.ModernMigrationDestinationKey()
|
||||
try await StorageRouter.shared.migrate(for: key)
|
||||
_ = try await StorageRouter.shared.forceMigration(for: key)
|
||||
// Refresh modern value display
|
||||
modernValue = try await StorageRouter.shared.get(key)
|
||||
statusMessage = "✓ Proactive migration complete. Legacy data drained into Keychain."
|
||||
statusMessage = "✓ Manual migration complete. Legacy data drained into Keychain."
|
||||
} catch {
|
||||
statusMessage = "Error: \(error.localizedDescription)"
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user