2025-04-06 00:38:25 +01:00

69 lines
2.3 KiB
Swift

import Foundation
import Meta
extension State where Value: Codable {
/// Initialize a property remembered between launches using a JSON file.
/// - Parameters:
/// - wrappedValue: The default value if no stored value exists.
/// - stateID: Unique key for the value.
/// - forceUpdates: Whether to force update all available views when modified.
public init(
wrappedValue: @autoclosure @escaping () -> Value,
_ stateID: String,
forceUpdates: Bool = false
) {
self.init(
wrappedValue: {
guard let data = try? Data(contentsOf: URL(fileURLWithPath: JSONDatabase.path)),
let storage = try? JSONDecoder().decode([String: Data].self, from: data),
let storedValueData = storage[stateID],
let value = try? JSONDecoder().decode(Value.self, from: storedValueData)
else {
return wrappedValue()
}
return value
},
writeValue: { value in
var storage: [String: Data] = [:]
let url = URL(fileURLWithPath: JSONDatabase.path)
if let data = try? Data(contentsOf: url),
let decoded = try? JSONDecoder().decode([String: Data].self, from: data)
{
storage = decoded
}
if let encodedValue = try? JSONEncoder().encode(value) {
storage[stateID] = encodedValue
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
if let newData = try? encoder.encode(storage) {
try? FileManager.default.createDirectory(
at: url.deletingLastPathComponent(),
withIntermediateDirectories: true
)
try? newData.write(to: url, options: .atomic)
}
}
},
forceUpdates: forceUpdates
)
}
}
public enum JSONDatabase {
/// The path to the JSON file.
static var path = "./database.json"
/// Optionally allow customization of the path.
public static func setPath(_ newPath: String) {
self.path = newPath
}
}