diff --git a/src/dnd_inventory_tracker.gleam b/src/dnd_inventory_tracker.gleam index b75d467..c2d2b08 100644 --- a/src/dnd_inventory_tracker.gleam +++ b/src/dnd_inventory_tracker.gleam @@ -38,6 +38,8 @@ type LoadedModel { type Message { StorageLoaded(storage: Storage) StorageFailedToLoad(error: storage.Error) + PersistStatusUpdated(persisted: Bool) + PersistFailed(error: storage.Error) UserSelectedInventory(name: String) @@ -75,6 +77,14 @@ fn update(model: Model, message: Message) -> #(Model, Effect(Message)) { effect.none(), ) _, StorageFailedToLoad(error:) -> #(FailedToLoad(error:), effect.none()) + _, PersistStatusUpdated(persisted: True) -> #(model, effect.none()) + _, PersistStatusUpdated(persisted: False) -> #( + FailedToLoad(error: storage.CouldNotPersist( + "Permission denied to persist storage", + )), + effect.none(), + ) + _, PersistFailed(error:) -> #(FailedToLoad(error:), effect.none()) Loaded(model), UserSelectedInventory(name:) -> #( Loaded( @@ -373,6 +383,7 @@ fn inventory_view(inventory: Inventory) -> Element(Message) { fn failed_to_load_view(error: storage.Error) -> Element(Message) { let error_message = case error { storage.CouldNotGetStorageManager -> "Could not get storage manager." + storage.CouldNotPersist(error) -> "Could not persist storage: " <> error storage.CouldNotGetRootDirectory(error) -> "Could not get root directory: " <> error storage.FileSystemError(error) -> "File system error: " <> error diff --git a/src/dnd_inventory_tracker/storage.gleam b/src/dnd_inventory_tracker/storage.gleam index d64729a..61bb1d6 100644 --- a/src/dnd_inventory_tracker/storage.gleam +++ b/src/dnd_inventory_tracker/storage.gleam @@ -13,6 +13,7 @@ pub type Storage { pub type Error { CouldNotGetStorageManager + CouldNotPersist(String) CouldNotGetRootDirectory(String) FileSystemError(String) } @@ -22,6 +23,22 @@ pub type InventoryError { CouldNotDecode(json.DecodeError) } +pub fn persist( + persist_to_message: fn(Bool) -> message, + error_to_message: fn(Error) -> message, +) -> Effect(message) { + effect.from(fn(dispatch) { + let persist_promise = persist_fs() + promise.tap(persist_promise, fn(res) { + case res { + Ok(persisted) -> dispatch(persisted |> persist_to_message) + Error(error) -> dispatch(error |> error_to_message) + } + }) + Nil + }) +} + pub fn load( storage_to_message: fn(Storage) -> message, error_to_message: fn(Error) -> message, @@ -227,6 +244,10 @@ pub fn new_could_not_get_storage_manager() -> Error { CouldNotGetStorageManager } +pub fn new_could_not_persist(desc: String) -> Error { + CouldNotPersist(desc) +} + pub fn new_could_not_get_root_directory(desc: String) -> Error { CouldNotGetRootDirectory(desc) } @@ -254,6 +275,9 @@ type FileT type File +@external(javascript, "./storage_ffi.js", "persist") +fn persist_fs() -> FsResult(Bool) + @external(javascript, "./storage_ffi.js", "get_root_directory") fn get_root_directory() -> FsResult(DirectoryHandle) diff --git a/src/dnd_inventory_tracker/storage_ffi.js b/src/dnd_inventory_tracker/storage_ffi.js index 35555bd..e65273d 100644 --- a/src/dnd_inventory_tracker/storage_ffi.js +++ b/src/dnd_inventory_tracker/storage_ffi.js @@ -2,6 +2,7 @@ import { Result$Ok, Result$Error } from "../../prelude.mjs"; import { to_list as array_to_list } from "../../gleam_javascript/gleam/javascript/array.mjs"; import { new_could_not_get_storage_manager, + new_could_not_persist, new_could_not_get_root_directory, new_file_system_error, } from "./storage.mjs"; @@ -17,6 +18,12 @@ const catchErrors = return Result$Error(ErrorConstructor(message ?? "Unknown error")); }); +export const persist = catchErrors(async () => { + if (!navigator.storage) + return Result$Error(new_could_not_get_storage_manager()); + return Result$Ok(await navigator.storage.persist()); +}, new_could_not_persist); + export const get_root_directory = catchErrors(async () => { if (!navigator.storage) return Result$Error(new_could_not_get_storage_manager());