forked from aparoksha/adwaita-swift
Merge pull request #34 from Amzd/State-property-on-app-fix
Fixed stored @State properties on App
This commit is contained in:
commit
1723fcdf22
@ -4,3 +4,4 @@
|
|||||||
- [Greg Cotten](https://github.com/gregcotten)
|
- [Greg Cotten](https://github.com/gregcotten)
|
||||||
- [Zev Eisenberg](https://github.com/ZevEisenberg)
|
- [Zev Eisenberg](https://github.com/ZevEisenberg)
|
||||||
- [Jay Wren](https://github.com/jrwren)
|
- [Jay Wren](https://github.com/jrwren)
|
||||||
|
- [Amzd](https://github.com/amzd)
|
||||||
|
|||||||
@ -37,7 +37,13 @@ public struct State<Value>: StateProtocol {
|
|||||||
/// Get and set the value without updating the views.
|
/// Get and set the value without updating the views.
|
||||||
public var rawValue: Value {
|
public var rawValue: Value {
|
||||||
get {
|
get {
|
||||||
content.storage.value as! Value
|
if let readValue, !content.fetched {
|
||||||
|
let newValue = readValue()
|
||||||
|
content.storage.value = newValue
|
||||||
|
content.fetched = true
|
||||||
|
return newValue
|
||||||
|
}
|
||||||
|
return content.storage.value as! Value
|
||||||
}
|
}
|
||||||
nonmutating set {
|
nonmutating set {
|
||||||
content.storage.value = newValue
|
content.storage.value = newValue
|
||||||
@ -54,6 +60,8 @@ public struct State<Value>: StateProtocol {
|
|||||||
|
|
||||||
/// The function for updating the value in the settings file.
|
/// The function for updating the value in the settings file.
|
||||||
private var writeValue: (() -> Void)?
|
private var writeValue: (() -> Void)?
|
||||||
|
/// The function for reading the value in the settings file.
|
||||||
|
var readValue: (() -> Value)?
|
||||||
|
|
||||||
/// The value with an erased type.
|
/// The value with an erased type.
|
||||||
public var value: Any {
|
public var value: Any {
|
||||||
@ -97,6 +105,8 @@ public struct State<Value>: StateProtocol {
|
|||||||
var internalStorage: Storage?
|
var internalStorage: Storage?
|
||||||
/// The initial value.
|
/// The initial value.
|
||||||
private var initialValue: Value
|
private var initialValue: Value
|
||||||
|
/// Whether the value has already been fetched from the file stored on the system.
|
||||||
|
var fetched = false
|
||||||
|
|
||||||
/// Initialize the content.
|
/// Initialize the content.
|
||||||
/// - Parameter storage: The storage.
|
/// - Parameter storage: The storage.
|
||||||
@ -159,15 +169,18 @@ public struct State<Value>: StateProtocol {
|
|||||||
|
|
||||||
/// Get the settings directory path.
|
/// Get the settings directory path.
|
||||||
/// - Returns: The path.
|
/// - Returns: The path.
|
||||||
private func dirPath() -> URL {
|
private func dirPath() -> URL? {
|
||||||
Self.userDataDir()
|
guard let folder = content.storage.folder ?? GTUIApp.appID else {
|
||||||
.appendingPathComponent(content.storage.folder ?? GTUIApp.appID, isDirectory: true)
|
return nil
|
||||||
|
}
|
||||||
|
return Self.userDataDir()
|
||||||
|
.appendingPathComponent(folder, isDirectory: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the settings file path.
|
/// Get the settings file path.
|
||||||
/// - Returns: The path.
|
/// - Returns: The path.
|
||||||
private func filePath() -> URL {
|
private func filePath() -> URL? {
|
||||||
dirPath().appendingPathComponent("\(content.storage.key ?? "temporary").json")
|
dirPath()?.appendingPathComponent("\(content.storage.key ?? "temporary").json")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -187,32 +200,41 @@ extension State where Value: Codable {
|
|||||||
self.forceUpdates = forceUpdates
|
self.forceUpdates = forceUpdates
|
||||||
content.storage.key = key
|
content.storage.key = key
|
||||||
content.storage.folder = folder
|
content.storage.folder = folder
|
||||||
checkFile()
|
let value = self
|
||||||
readValue()
|
self.readValue = {
|
||||||
|
value.checkFile()
|
||||||
|
return value.readActualValue() ?? wrappedValue
|
||||||
|
}
|
||||||
self.writeValue = writeCodableValue
|
self.writeValue = writeCodableValue
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether the settings file exists, and, if not, create it.
|
/// Check whether the settings file exists, and, if not, create it.
|
||||||
private func checkFile() {
|
private func checkFile() {
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
if !fileManager.fileExists(atPath: dirPath().path) {
|
guard let dirPath = dirPath(), let filePath = filePath() else {
|
||||||
|
print("Stored state value accessed before initializing app id.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !fileManager.fileExists(atPath: dirPath.path) {
|
||||||
try? fileManager.createDirectory(
|
try? fileManager.createDirectory(
|
||||||
at: .init(fileURLWithPath: dirPath().path),
|
at: .init(fileURLWithPath: dirPath.path),
|
||||||
withIntermediateDirectories: true,
|
withIntermediateDirectories: true,
|
||||||
attributes: nil
|
attributes: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if !fileManager.fileExists(atPath: filePath().path) {
|
if !fileManager.fileExists(atPath: filePath.path) {
|
||||||
fileManager.createFile(atPath: filePath().path, contents: .init(), attributes: nil)
|
fileManager.createFile(atPath: filePath.path, contents: .init(), attributes: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the local value with the value from the file.
|
/// Update the local value with the value from the file.
|
||||||
private func readValue() {
|
private func readActualValue() -> Value? {
|
||||||
let data = try? Data(contentsOf: filePath())
|
if let filePath = filePath(),
|
||||||
if let data, let value = try? JSONDecoder().decode(Value.self, from: data) {
|
let data = try? Data(contentsOf: filePath),
|
||||||
rawValue = value
|
let value = try? JSONDecoder().decode(Value.self, from: data) {
|
||||||
|
return value
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the value on the file with the local value.
|
/// Update the value on the file with the local value.
|
||||||
@ -220,7 +242,10 @@ extension State where Value: Codable {
|
|||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
encoder.outputFormatting = .prettyPrinted
|
encoder.outputFormatting = .prettyPrinted
|
||||||
let data = try? encoder.encode(rawValue)
|
let data = try? encoder.encode(rawValue)
|
||||||
try? data?.write(to: filePath())
|
guard let filePath = filePath() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try? data?.write(to: filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ public protocol App {
|
|||||||
|
|
||||||
/// The app's application ID.
|
/// The app's application ID.
|
||||||
var id: String { get }
|
var id: String { get }
|
||||||
|
|
||||||
/// The app's windows.
|
/// The app's windows.
|
||||||
@SceneBuilder var scene: Scene { get }
|
@SceneBuilder var scene: Scene { get }
|
||||||
// swiftlint:disable implicitly_unwrapped_optional
|
// swiftlint:disable implicitly_unwrapped_optional
|
||||||
|
|||||||
@ -13,8 +13,7 @@ public class GTUIApp {
|
|||||||
/// The handlers which are called when a state changes.
|
/// The handlers which are called when a state changes.
|
||||||
static var updateHandlers: [(Bool) -> Void] = []
|
static var updateHandlers: [(Bool) -> Void] = []
|
||||||
/// The app's id for the file name for storing the data.
|
/// The app's id for the file name for storing the data.
|
||||||
static var appID = "temporary"
|
static var appID: String?
|
||||||
|
|
||||||
/// The pointer to the application.
|
/// The pointer to the application.
|
||||||
public var pointer: UnsafeMutablePointer<GtkApplication>?
|
public var pointer: UnsafeMutablePointer<GtkApplication>?
|
||||||
/// Fields for additional information.
|
/// Fields for additional information.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user