Skip to content

Commit

Permalink
Move to approach without any breaking changes
Browse files Browse the repository at this point in the history
Read the file's value as soon as the state value is accessed for the
first time
  • Loading branch information
david-swift committed Jun 11, 2024
1 parent 7a52948 commit 15cafb8
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 24 deletions.
59 changes: 42 additions & 17 deletions Sources/Adwaita/Model/Data Flow/State.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ public struct State<Value>: StateProtocol {
/// Get and set the value without updating the views.
public var rawValue: Value {
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 {
content.storage.value = newValue
Expand All @@ -54,6 +60,8 @@ public struct State<Value>: StateProtocol {

/// The function for updating the value in the settings file.
private var writeValue: (() -> Void)?
/// The function for reading the value in the settings file.
var readValue: (() -> Value)?

/// The value with an erased type.
public var value: Any {
Expand Down Expand Up @@ -97,6 +105,8 @@ public struct State<Value>: StateProtocol {
var internalStorage: Storage?
/// The initial 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.
/// - Parameter storage: The storage.
Expand Down Expand Up @@ -159,15 +169,18 @@ public struct State<Value>: StateProtocol {

/// Get the settings directory path.
/// - Returns: The path.
private func dirPath() -> URL {
Self.userDataDir()
.appendingPathComponent(content.storage.folder ?? GTUIApp.appID, isDirectory: true)
private func dirPath() -> URL? {
guard let folder = content.storage.folder ?? GTUIApp.appID else {
return nil
}
return Self.userDataDir()
.appendingPathComponent(folder, isDirectory: true)
}

/// Get the settings file path.
/// - Returns: The path.
private func filePath() -> URL {
dirPath().appendingPathComponent("\(content.storage.key ?? "temporary").json")
private func filePath() -> URL? {
dirPath()?.appendingPathComponent("\(content.storage.key ?? "temporary").json")
}

}
Expand All @@ -187,40 +200,52 @@ extension State where Value: Codable {
self.forceUpdates = forceUpdates
content.storage.key = key
content.storage.folder = folder
checkFile()
readValue()
let value = self
self.readValue = {
value.checkFile()
return value.readActualValue() ?? wrappedValue
}
self.writeValue = writeCodableValue
}

/// Check whether the settings file exists, and, if not, create it.
private func checkFile() {
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(
at: .init(fileURLWithPath: dirPath().path),
at: .init(fileURLWithPath: dirPath.path),
withIntermediateDirectories: true,
attributes: nil
)
}
if !fileManager.fileExists(atPath: filePath().path) {
fileManager.createFile(atPath: filePath().path, contents: .init(), attributes: nil)
if !fileManager.fileExists(atPath: filePath.path) {
fileManager.createFile(atPath: filePath.path, contents: .init(), attributes: nil)
}
}

/// Update the local value with the value from the file.
private func readValue() {
let data = try? Data(contentsOf: filePath())
if let data, let value = try? JSONDecoder().decode(Value.self, from: data) {
rawValue = value
private func readActualValue() -> Value? {
if let filePath = filePath(),
let data = try? Data(contentsOf: filePath),
let value = try? JSONDecoder().decode(Value.self, from: data) {
return value
}
return nil
}

/// Update the value on the file with the local value.
private func writeCodableValue() {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try? encoder.encode(rawValue)
try? data?.write(to: filePath())
guard let filePath = filePath() else {
return
}
try? data?.write(to: filePath)
}

}
9 changes: 3 additions & 6 deletions Sources/Adwaita/Model/User Interface/App/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
public protocol App {

/// The app's application ID.
static var id: String { get }
var id: String { get }

/// The app's windows.
@SceneBuilder var scene: Scene { get }
Expand All @@ -40,12 +40,8 @@ public protocol App {

extension App {

@available(*, deprecated, message: "The 'id' property is removed. Please use the new static id instead.")
var id: String { Self.id }

/// The application's entry point.
public static func main() {
GTUIApp.appID = Self.id
let app = setupApp()
app.run()
}
Expand All @@ -55,7 +51,7 @@ extension App {
/// To run the app, call the ``GTUIApp/run(automaticSetup:manualSetup:)`` function.
public static func setupApp() -> GTUIApp {
var appInstance = self.init()
appInstance.app = GTUIApp(Self.id) { appInstance }
appInstance.app = GTUIApp(appInstance.id) { appInstance }
GTUIApp.updateHandlers.append { force in
var removeIndices: [Int] = []
for (index, window) in appInstance.app.sceneStorage.enumerated() {
Expand All @@ -69,6 +65,7 @@ extension App {
appInstance.app.sceneStorage.remove(at: index)
}
}
GTUIApp.appID = appInstance.id
return appInstance.app
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Adwaita/Model/User Interface/App/GTUIApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class GTUIApp {
/// The handlers which are called when a state changes.
static var updateHandlers: [(Bool) -> Void] = []
/// The app's id for the file name for storing the data.
static var appID: String!
static var appID: String?
/// The pointer to the application.
public var pointer: UnsafeMutablePointer<GtkApplication>?
/// Fields for additional information.
Expand Down

0 comments on commit 15cafb8

Please sign in to comment.