Skip to content

Refactor/shared appstorage#533

Merged
mltbnz merged 14 commits intomainfrom
refactor/shared-appstorage
Jan 3, 2026
Merged

Refactor/shared appstorage#533
mltbnz merged 14 commits intomainfrom
refactor/shared-appstorage

Conversation

@mltbnz
Copy link
Member

@mltbnz mltbnz commented Jan 3, 2026

πŸ“ Docs

πŸ“² What

This PR refactors the app's persistence layer by replacing the custom UserDefaultsClient dependency with TCA's native @Shared property wrapper and centralized SharedKey definitions.

Key Changes:

  • Removed the UserDefaultsClient package entirely
  • Added new SharedKeys package that defines all shared storage keys in one place
  • Migrated all features to use @Shared property wrapper instead of dependency injection
  • Consolidated storage configuration from multiple locations into a single source of truth

Migration Details:

AppStorage Keys (in-memory, fast access):

  • chatReadTimeInterval - Double value for tracking chat read timestamp
  • sessionID - Optional String for session identification
  • didShowObservationModePrompt - Boolean flag

FileStorage Keys (JSON files, structured data):

  • rideEventSettings - Event notification preferences
  • appearanceSettings - Theme and UI preferences
  • privacyZoneSettings - Location privacy configuration (includes migration from old location)

πŸ€” Why

Problems with the Old Approach:

  1. Boilerplate overhead - Required defining client methods, live implementations, and test implementations for every storage operation
  2. Scattered configuration - Storage keys were defined across multiple files (feature-specific SharedKey extensions)
  3. Testing complexity - Required mocking the entire UserDefaultsClient dependency in tests
  4. Less idiomatic - TCA now recommends @Shared for persistence over custom dependency clients

Benefits of the New Approach:

  1. Less code - Eliminated ~100 lines of client/mock/test code
  2. Centralized keys - All storage keys defined in one place (SharedKeys.swift)
  3. Simpler usage - @Shared(.chatReadTimeInterval) var value instead of userDefaultsClient.chatReadTimeInterval
  4. Better testing - @Shared automatically provides test isolation without mocking
  5. Type safety - Storage keys are type-safe at compile time
  6. Modern TCA pattern - Follows current TCA best practices from v1.9+

Code Comparison:

Before:

@Dependency(\.userDefaultsClient) var userDefaultsClient

return .run { _ in
  await userDefaultsClient.setChatReadTimeInterval(date().timeIntervalSince1970)
}

After:

@Shared(.chatReadTimeInterval) var chatReadTimeInterval
$chatReadTimeInterval.withLock { $0 = date().timeIntervalSince1970 }

πŸ‘€ See

Files Changed:

  • Removed: UserDefaultsClient package (3 files, ~100 lines)
  • Added: SharedKeys package (2 files, ~80 lines)
  • Updated: 6 feature modules to use @Shared
  • Updated: Test files simplified (removed client mocking)

Package Structure:

CriticalMapsKit/
β”œβ”€β”€ Sources/
β”‚   β”œβ”€β”€ SharedKeys/          # NEW - centralized storage keys
β”‚   β”‚   β”œβ”€β”€ SharedKeys.swift
β”‚   β”‚   └── Export.swift
β”‚   └── UserDefaultsClient/  # REMOVED
└── Tests/
    └── */                    # UPDATED - simplified mocking

Affected Features:

  • βœ… AppFeature - session management
  • βœ… ChatFeature - read timestamp tracking
  • βœ… NextRideFeature - event settings
  • βœ… SettingsFeature - appearance & privacy settings
  • βœ… IDProvider - session ID persistence

♿️ Accessibility

  • No UI changes - persistence layer refactor only
  • All existing accessibility features maintained
  • No impact on VoiceOver or Dynamic Type

πŸ§ͺ Testing

  • All tests updated and passing
  • Test mocking simplified (removed UserDefaultsClient mocks)
  • Privacy zone file migration tested
  • Backward compatibility maintained for existing data

πŸ”„ Migration Notes

This is a breaking change internally but not for end users:

  • Existing UserDefaults values automatically migrate to @Shared storage
  • Privacy zone files automatically migrate from Documents to Application Support directory
  • No data loss - all existing user preferences preserved

Net Result: -109 lines of code, simpler architecture, better testability, more idiomatic TCA πŸŽ‰
closes #528

@mltbnz mltbnz marked this pull request as ready for review January 3, 2026 17:17
@mltbnz mltbnz requested a review from a team as a code owner January 3, 2026 17:17
@mltbnz mltbnz merged commit 9469065 into main Jan 3, 2026
2 checks passed
@mltbnz mltbnz deleted the refactor/shared-appstorage branch January 3, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor UserDefaultsClient to use swift-sharing

1 participant