diff --git a/apps/app/package.json b/apps/app/package.json index 95d67468..540ca601 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -32,8 +32,18 @@ "vitest": "^4.0.18" }, "dependencies": { + "@codemirror/commands": "catalog:", + "@codemirror/lang-markdown": "catalog:", + "@codemirror/language": "catalog:", + "@codemirror/language-data": "catalog:", + "@codemirror/state": "catalog:", + "@codemirror/view": "catalog:", "@iconify-json/carbon": "^1.2.19", "@iconify-json/tabler": "catalog:", + "@lezer/markdown": "catalog:", + "@prosemark/core": "catalog:", + "@prosemark/paste-rich-text": "catalog:", + "@prosemark/render-html": "catalog:", "@saurl/tauri-plugin-safe-area-insets-css-api": "^0.1.0", "@tauri-apps/api": "^2.10.1", "@tauri-apps/plugin-clipboard-manager": "~2.3.2", @@ -41,28 +51,18 @@ "@tauri-apps/plugin-fs": "~2.4.5", "@tauri-apps/plugin-opener": "~2.5.3", "@tauri-apps/plugin-os": "~2.3.2", - "@tauri-apps/plugin-store": "~2.4.2", "@unocss/preset-icons": "catalog:", "@unocss/preset-mini": "^66.6.2", "@unocss/reset": "^66.6.2", "@unocss/transformer-variant-group": "^66.6.2", + "@workspace/shared-assets": "workspace:*", + "daisyui": "catalog:", + "deepmerge": "^4.3.1", "html2canvas-pro": "^2.0.2", "jspdf": "^4.2.0", "svelte-animated-details": "^1.0.2", "svelte-sonner": "^1.0.7", "tauri-plugin-android-fs-api": "^26.1.0", - "zod": "^4.3.6", - "@codemirror/commands": "catalog:", - "@codemirror/lang-markdown": "catalog:", - "@codemirror/language": "catalog:", - "@codemirror/language-data": "catalog:", - "@codemirror/state": "catalog:", - "@codemirror/view": "catalog:", - "@lezer/markdown": "catalog:", - "@prosemark/core": "catalog:", - "@prosemark/render-html": "catalog:", - "@prosemark/paste-rich-text": "catalog:", - "daisyui": "catalog:", - "@workspace/shared-assets": "workspace:*" + "zod": "^4.3.6" } } diff --git a/apps/app/src-tauri/Cargo.lock b/apps/app/src-tauri/Cargo.lock index 3f30b6a6..bf5b5904 100644 --- a/apps/app/src-tauri/Cargo.lock +++ b/apps/app/src-tauri/Cargo.lock @@ -590,6 +590,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" name = "cherit" version = "0.0.1" dependencies = [ + "chrono", "futures", "log", "natord", @@ -606,7 +607,6 @@ dependencies = [ "tauri-plugin-opener", "tauri-plugin-os", "tauri-plugin-safe-area-insets-css", - "tauri-plugin-store", "urlencoding", ] @@ -617,8 +617,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-link 0.2.1", ] @@ -4580,22 +4582,6 @@ dependencies = [ "thiserror 2.0.18", ] -[[package]] -name = "tauri-plugin-store" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a77036340a97eb5bbe1b3209c31e5f27f75e6f92a52fd9dd4b211ef08bf310" -dependencies = [ - "dunce", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.18", - "tokio", - "tracing", -] - [[package]] name = "tauri-runtime" version = "2.10.0" @@ -4845,22 +4831,10 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "socket2", - "tokio-macros", "tracing", "windows-sys 0.61.2", ] -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "tokio-util" version = "0.7.18" diff --git a/apps/app/src-tauri/Cargo.toml b/apps/app/src-tauri/Cargo.toml index 80434ed6..ebd84340 100644 --- a/apps/app/src-tauri/Cargo.toml +++ b/apps/app/src-tauri/Cargo.toml @@ -27,7 +27,6 @@ log = "0.4" tauri = { version = "2.10.2", features = [] } tauri-plugin-log = "2" tauri-plugin-fs = { version = "2", features = ['watch'] } -tauri-plugin-store = "2" tauri-plugin-dialog = "2" tauri-plugin-os = "2" urlencoding = "2" @@ -37,6 +36,7 @@ tauri-plugin-safe-area-insets-css = "0.2" tauri-plugin-clipboard-manager = "2" futures = "0.3" rayon = "1.10" +chrono = { version = "0.4.44", features = ["serde"] } [profile.dev] incremental = true # Compile your binary in smaller steps. diff --git a/apps/app/src-tauri/capabilities/default.json b/apps/app/src-tauri/capabilities/default.json index b1a1efdd..f31e4254 100644 --- a/apps/app/src-tauri/capabilities/default.json +++ b/apps/app/src-tauri/capabilities/default.json @@ -6,7 +6,6 @@ "permissions": [ "core:default", "fs:default", - "store:default", "dialog:default", "core:window:allow-start-dragging", "core:window:allow-close", @@ -24,4 +23,3 @@ "clipboard-manager:allow-write-text" ] } - diff --git a/apps/app/src-tauri/src/features/mod.rs b/apps/app/src-tauri/src/features/mod.rs index 0d994c42..d737d8a4 100644 --- a/apps/app/src-tauri/src/features/mod.rs +++ b/apps/app/src-tauri/src/features/mod.rs @@ -1,2 +1,3 @@ pub mod file_system; pub mod sync; +pub mod persistency; diff --git a/apps/app/src-tauri/src/features/persistency/commands.rs b/apps/app/src-tauri/src/features/persistency/commands.rs new file mode 100644 index 00000000..2ef1c29e --- /dev/null +++ b/apps/app/src-tauri/src/features/persistency/commands.rs @@ -0,0 +1,18 @@ +use super::structs::AppPersistentStates; +use tauri::AppHandle; + +#[tauri::command] +pub fn get_persistent_states(app: AppHandle) -> Result { + let mut temp_states = AppPersistentStates::new(); + temp_states.load_states(&app).map_err(|e| e.to_string())?; + Ok(temp_states) +} + +#[tauri::command] +pub fn save_persistent_states(app: AppHandle, states: AppPersistentStates) -> Result<(), String> { + let mut temp_states = AppPersistentStates::new(); + temp_states + .save_states(&app, &states) + .map_err(|e| e.to_string())?; + Ok(()) +} diff --git a/apps/app/src-tauri/src/features/persistency/migrations.rs b/apps/app/src-tauri/src/features/persistency/migrations.rs new file mode 100644 index 00000000..8a6fe191 --- /dev/null +++ b/apps/app/src-tauri/src/features/persistency/migrations.rs @@ -0,0 +1,2 @@ +// pub fn migrate_1_to_2() {} +// pub fn migrate_2_to_3() {} diff --git a/apps/app/src-tauri/src/features/persistency/mod.rs b/apps/app/src-tauri/src/features/persistency/mod.rs new file mode 100644 index 00000000..c4a24da7 --- /dev/null +++ b/apps/app/src-tauri/src/features/persistency/mod.rs @@ -0,0 +1,3 @@ +pub mod commands; +mod migrations; +pub mod structs; diff --git a/apps/app/src-tauri/src/features/persistency/structs.rs b/apps/app/src-tauri/src/features/persistency/structs.rs new file mode 100644 index 00000000..3c6be06d --- /dev/null +++ b/apps/app/src-tauri/src/features/persistency/structs.rs @@ -0,0 +1,131 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use std::{ + error::Error, + fs::{self, File}, + path::PathBuf, +}; +use tauri::{AppHandle, Manager}; + +const CONFIG_FILE_NAME: &str = "config.json"; +const LATEST_SCHEMA_V: u8 = 1; + +// Global Struct +#[derive(Serialize, Deserialize, Clone)] +struct GenericPath { + path: PathBuf, + document_top_tree_uri: Option, +} + +// Domain : Wokrspace +#[derive(Serialize, Deserialize, Clone)] +struct WorkspaceMetaData { + path: GenericPath, + last_accessed: DateTime, + recent_filenode_path: Option, +} + +#[derive(Serialize, Deserialize, Clone)] +struct AppConfig { + workspaces_metadata: Vec, +} + +impl AppConfig { + pub fn new() -> Self { + Self { + workspaces_metadata: vec![], + } + } +} + +#[derive(Serialize, Deserialize, Clone)] +struct AppSecureConfig { + llm_api: String, +} + +impl AppSecureConfig { + pub fn new() -> Self { + Self { + llm_api: "".to_string(), + } + } +} + +// Main Parent State +#[derive(Serialize, Deserialize, Clone)] +pub struct AppPersistentStates { + schema_version: u8, + app_config: AppConfig, + secure: AppSecureConfig, +} + +impl AppPersistentStates { + pub fn new() -> Self { + Self { + schema_version: 1, + app_config: AppConfig::new(), + secure: AppSecureConfig::new(), + } + } + pub fn save_states( + &mut self, + app: &AppHandle, + states: &AppPersistentStates, + ) -> Result<(), Box> { + self.schema_version = states.schema_version; + self.app_config = states.app_config.clone(); + self.secure = states.secure.clone(); + + let path = app.path().app_config_dir().unwrap().join(CONFIG_FILE_NAME); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + + let file = File::create(path)?; + serde_json::to_writer_pretty(&file, &self)?; + + Ok(()) + } + + pub fn load_states(&mut self, app: &AppHandle) -> Result<(), Box> { + // Setup Config Path + self.setup_config_path(app)?; + + let path = app.path().app_config_dir().unwrap().join(CONFIG_FILE_NAME); + let file = fs::File::options().read(true).open(path)?; + *self = serde_json::from_reader(&file)?; + + // Run migrations if needed + if self.schema_version == LATEST_SCHEMA_V { + return Ok(()); + } + + Err(format!( + "Current Schema version is Unsuppoirted : {}", + self.schema_version + ) + .into()) + + // Future Migration Pipeline (Uncomment when LATEST_SCHEMA_V is 2) + // while self.schema_version < LATEST_SCHEMA_V { + // match self.schema_version { + // 1 => migrate_1_to_2(&mut self), + // _ => return Err("The Schema is not Valid".into()), + // } + // } + + // Ok(()) + } + pub fn setup_config_path(&self, app: &AppHandle) -> Result<(), Box> { + let path = app.path().app_config_dir().unwrap().join(CONFIG_FILE_NAME); + // Create the file path if doesn't exists + if !path.exists() { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + let file = File::create(&path)?; + serde_json::to_writer_pretty(&file, &self)?; + } + Ok(()) + } +} diff --git a/apps/app/src-tauri/src/lib.rs b/apps/app/src-tauri/src/lib.rs index dc426d9f..a8d662a7 100644 --- a/apps/app/src-tauri/src/lib.rs +++ b/apps/app/src-tauri/src/lib.rs @@ -1,3 +1,5 @@ +use crate::features::persistency::structs::AppPersistentStates; + mod features; #[cfg(all(test, not(target_os = "android")))] @@ -10,16 +12,19 @@ pub fn run() { .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_dialog::init()) - .plugin(tauri_plugin_store::Builder::new().build()) .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_android_fs::init()) .plugin(tauri_plugin_safe_area_insets_css::init()) .invoke_handler(tauri::generate_handler![ features::file_system::build_file_tree, features::file_system::android::move_file_android, - features::file_system::android::move_directory_android + features::file_system::android::move_directory_android, + features::persistency::commands::get_persistent_states, + features::persistency::commands::save_persistent_states ]) .setup(|app| { + let app_config = AppPersistentStates::new(); + app_config.setup_config_path(app.handle())?; if cfg!(debug_assertions) { app.handle().plugin( tauri_plugin_log::Builder::default() diff --git a/apps/app/src/App.svelte b/apps/app/src/App.svelte index febfb774..b7d62a90 100644 --- a/apps/app/src/App.svelte +++ b/apps/app/src/App.svelte @@ -5,12 +5,10 @@ import { Toaster } from 'svelte-sonner'; import Main from '@/components/main_section/index.svelte'; import AppSettings from '@/components/general/app_settings/index.svelte'; - import { drawer_open } from '@/lib/states/global/index.svelte'; - import { attach_window_listeners } from './lib/operations/window_listeners'; - $effect(() => { - const detach = attach_window_listeners(); - return () => detach.then((f) => f()); // Handle the async setup/cleanup - }); + import { drawer_open } from '@/lib/states/session/global/index.svelte'; + import { onMount } from 'svelte'; + import { initialize_app } from '@/lib/operations/initialization'; + onMount(initialize_app);
= {}; let activeTab = $state(); @@ -69,6 +71,46 @@ Back to Menu {/if} + + +
{JSON.stringify(
+            persistent_states.states,
+            null,
+            '\t'
+          )}
diff --git a/apps/app/src/components/general/breadcrumb_path/index.svelte b/apps/app/src/components/general/breadcrumb_path/index.svelte index fe3e4713..8fee3aab 100644 --- a/apps/app/src/components/general/breadcrumb_path/index.svelte +++ b/apps/app/src/components/general/breadcrumb_path/index.svelte @@ -1,6 +1,6 @@ @@ -56,23 +33,24 @@
- {#if recent_workspaces.data.length} + {#if persistent_states.states?.app_config.workspaces_metadata.length}