-
Notifications
You must be signed in to change notification settings - Fork 210
/
UserSettingsClient.swift
81 lines (72 loc) · 2.34 KB
/
UserSettingsClient.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import Combine
import Dependencies
import UIKit
@dynamicMemberLookup
public struct UserSettingsClient {
public var get: @Sendable () -> UserSettings
public var set: @Sendable (UserSettings) async -> Void
public var stream: @Sendable () -> AsyncStream<UserSettings>
public subscript<Value>(dynamicMember keyPath: KeyPath<UserSettings, Value>) -> Value {
self.get()[keyPath: keyPath]
}
@_disfavoredOverload
public subscript<Value>(
dynamicMember keyPath: KeyPath<UserSettings, Value>
) -> AsyncStream<Value> {
// TODO: This should probably remove duplicates.
self.stream().map { $0[keyPath: keyPath] }.eraseToStream()
}
public func modify(_ operation: (inout UserSettings) -> Void) async {
var userSettings = self.get()
operation(&userSettings)
await self.set(userSettings)
}
}
extension UserSettingsClient: DependencyKey {
public static var liveValue: UserSettingsClient {
let initialUserSettingsData = (try? Data(contentsOf: .userSettings)) ?? Data()
let initialUserSettings =
(try? JSONDecoder().decode(UserSettings.self, from: initialUserSettingsData))
?? UserSettings()
let userSettings = LockIsolated(initialUserSettings)
let subject = PassthroughSubject<UserSettings, Never>()
return Self(
get: {
userSettings.value
},
set: { updatedUserSettings in
userSettings.withValue {
$0 = updatedUserSettings
subject.send(updatedUserSettings)
try? JSONEncoder().encode(updatedUserSettings).write(to: .userSettings)
}
},
stream: {
subject.values.eraseToStream()
}
)
}
public static let testValue = Self.mock()
public static func mock(initialUserSettings: UserSettings = UserSettings()) -> Self {
let userSettings = LockIsolated<UserSettings>(initialUserSettings)
let subject = PassthroughSubject<UserSettings, Never>()
return Self(
get: { userSettings.value },
set: { updatedUserSettings in
userSettings.withValue {
$0 = updatedUserSettings
subject.send(updatedUserSettings)
}
},
stream: {
subject.values.eraseToStream()
}
)
}
}
extension DependencyValues {
public var userSettings: UserSettingsClient {
get { self[UserSettingsClient.self] }
set { self[UserSettingsClient.self] = newValue }
}
}