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 } }