Skip to content

Commit

Permalink
Leif/app state improvements (#97)
Browse files Browse the repository at this point in the history
* Update State to work with all tpyes of state

* Update states to work for AppState

* Add comments and update State
  • Loading branch information
0xLeif authored Mar 6, 2024
1 parent 79a1087 commit eeab0d2
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 24 deletions.
13 changes: 4 additions & 9 deletions Sources/AppState/Application/Application+public.swift
Original file line number Diff line number Diff line change
Expand Up @@ -302,22 +302,17 @@ public extension Application {
- Parameter keyPath: KeyPath of the state value to be fetched
- Returns: The requested state of type `Value`.
*/
static func state<Value>(
_ keyPath: KeyPath<Application, State<Value>>,
static func state<Value, ApplicationState: MutableApplicationState>(
_ keyPath: KeyPath<Application, ApplicationState>,
_ fileID: StaticString = #fileID,
_ function: StaticString = #function,
_ line: Int = #line,
_ column: Int = #column
) -> State<Value> {
) -> ApplicationState where ApplicationState.Value == Value {
let appState = shared.value(keyPath: keyPath)
#if !os(Linux) && !os(Windows)
let debugEmoji = "🔄"
#else
let debugEmoji = "📦"
#endif

log(
debug: "\(debugEmoji) Getting State \(String(describing: keyPath)) -> \(appState.value)",
debug: "\(ApplicationState.emoji) Getting State \(String(describing: keyPath)) -> \(appState.value)",
fileID: fileID,
function: function,
line: line,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ This protocol defines a type, `Value`, and a mutable property, `value`, of that
public protocol MutableApplicationState {
associatedtype Value

/// An emoji to use when logging about this state.
static var emoji: Character { get }

/// The actual value that this state holds. It can be both retrieved and modified.
var value: Value { get set }
}

extension MutableApplicationState {
static var emoji: Character { "" }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ extension Application {

/// `FileState` encapsulates the value within the application's scope and allows any changes to be propagated throughout the scoped area. State is stored using `FileManager`.
public struct FileState<Value: Codable>: MutableApplicationState {
public static var emoji: Character { "🗄️" }

@AppDependency(\.fileManager) private var fileManager: FileManager

/// The initial value of the state.
Expand All @@ -30,7 +32,7 @@ extension Application {
} catch {
log(
error: error,
message: "🗄️ FileState Fetching",
message: "\(FileState.emoji) FileState Fetching",
fileID: #fileID,
function: #function,
line: #line,
Expand All @@ -51,7 +53,7 @@ extension Application {
} catch {
log(
error: error,
message: "🗄️ FileState Deleting",
message: "\(FileState.emoji) FileState Deleting",
fileID: #fileID,
function: #function,
line: #line,
Expand All @@ -78,7 +80,7 @@ extension Application {
} catch {
log(
error: error,
message: "🗄️ FileState Saving",
message: "\(FileState.emoji) FileState Saving",
fileID: #fileID,
function: #function,
line: #line,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ extension Application {
}

/// The SecureState structure provides secure and persistent key-value string storage backed by the Keychain that can be used across the application.
public struct SecureState {
public struct SecureState: MutableApplicationState {
public static var emoji: Character { "🔑" }

@AppDependency(\.keychain) private var keychain: Keychain

/// The initial value of the state.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@ import Foundation
extension Application {
/// `State` encapsulates the value within the application's scope and allows any changes to be propagated throughout the scoped area.
public struct State<Value>: MutableApplicationState, CustomStringConvertible {
/// Values that are available in the cache.
enum StateType {
case state
case stored
case sync
case file
}

public static var emoji: Character {
#if !os(Linux) && !os(Windows)
return "🔄"
#else
return "📦"
#endif
}

private let type: StateType

/// A private backing storage for the value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ extension Application {

/// `StoredState` encapsulates the value within the application's scope and allows any changes to be propagated throughout the scoped area. State is stored using `UserDefaults`.
public struct StoredState<Value: Codable>: MutableApplicationState {
public static var emoji: Character { "💾" }

@AppDependency(\.userDefaults) private var userDefaults: UserDefaults

/// The initial value of the state.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ extension Application {
- Warning: Avoid using this class for data that is essential to your app’s behavior when offline; instead, store such data directly into the local user defaults database.
*/
public struct SyncState<Value: Codable>: MutableApplicationState {
public static var emoji: Character { "☁️" }

@AppDependency(\.icloudStore) private var icloudStore: NSUbiquitousKeyValueStore

/// The initial value of the state.
Expand Down Expand Up @@ -76,7 +78,7 @@ extension Application {
} catch {
Application.log(
error: error,
message: "☁️ SyncState failed to encode: \(newValue)",
message: "\(SyncState.emoji) SyncState failed to encode: \(newValue)",
fileID: #fileID,
function: #function,
line: #line,
Expand Down
14 changes: 4 additions & 10 deletions Sources/AppState/PropertyWrappers/State/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SwiftUI
#endif

/// `AppState` is a property wrapper allowing SwiftUI views to subscribe to Application's state changes in a reactive way. Works similar to `State` and `Published`.
@propertyWrapper public struct AppState<Value> {
@propertyWrapper public struct AppState<Value, ApplicationState: MutableApplicationState> where ApplicationState.Value == Value {
#if !os(Linux) && !os(Windows)
/// Holds the singleton instance of `Application`.
@ObservedObject private var app: Application = Application.shared
Expand All @@ -14,7 +14,7 @@ import SwiftUI
#endif

/// Path for accessing `State` from Application.
private let keyPath: KeyPath<Application, Application.State<Value>>
private let keyPath: KeyPath<Application, ApplicationState>

private let fileID: StaticString
private let function: StaticString
Expand All @@ -33,14 +33,8 @@ import SwiftUI
).value
}
nonmutating set {
#if !os(Linux) && !os(Windows)
let debugEmoji = "🔄"
#else
let debugEmoji = "📦"
#endif

Application.log(
debug: "\(debugEmoji) Setting State \(String(describing: keyPath)) = \(newValue)",
debug: "\(ApplicationState.emoji) Setting State \(String(describing: keyPath)) = \(newValue)",
fileID: fileID,
function: function,
line: line,
Expand Down Expand Up @@ -68,7 +62,7 @@ import SwiftUI
- Parameter keyPath: The `KeyPath` for accessing `State` in Application.
*/
public init(
_ keyPath: KeyPath<Application, Application.State<Value>>,
_ keyPath: KeyPath<Application, ApplicationState>,
_ fileID: StaticString = #fileID,
_ function: StaticString = #function,
_ line: Int = #line,
Expand Down

0 comments on commit eeab0d2

Please sign in to comment.