use std::fs; use std::path::PathBuf; use tauri::{AppHandle, Manager}; pub fn app_file_path(app: &AppHandle, name: &str) -> Result { let dir = app.path().app_data_dir().map_err(|e| e.to_string())?.join("musealpha"); fs::create_dir_all(&dir).map_err(|e| e.to_string())?; Ok(dir.join(name)) } pub fn save_json(app: &AppHandle, name: &str, value: &T) -> Result<(), String> { let path = app_file_path(app, name)?; let json = serde_json::to_string_pretty(value).map_err(|e| e.to_string())?; fs::write(path, json).map_err(|e| e.to_string()) } pub fn load_json(app: &AppHandle, name: &str) -> Result { let path = app_file_path(app, name)?; if !path.exists() { return Ok(T::default()); } let json = fs::read_to_string(path).map_err(|e| e.to_string())?; serde_json::from_str(&json).map_err(|e| e.to_string()) } /// Storage info for the settings panel #[derive(serde::Serialize)] pub struct StorageInfo { pub data_path: String, pub total_size_bytes: u64, pub file_count: usize, pub project_count: usize, pub library_count: usize, pub library_size_bytes: u64, pub projects_size_bytes: u64, } #[tauri::command] pub fn storage_info(app: AppHandle) -> Result { let dir = app.path().app_data_dir().map_err(|e| e.to_string())?.join("musealpha"); let data_path = dir.to_string_lossy().to_string(); if !dir.exists() { return Ok(StorageInfo { data_path, total_size_bytes: 0, file_count: 0, project_count: 0, library_count: 0, library_size_bytes: 0, projects_size_bytes: 0 }); } let mut total_size: u64 = 0; let mut file_count: usize = 0; let mut projects_size: u64 = 0; let mut project_count: usize = 0; let mut library_size: u64 = 0; if let Ok(entries) = fs::read_dir(&dir) { for entry in entries.flatten() { if let Ok(meta) = entry.metadata() { if meta.is_file() { let size = meta.len(); total_size += size; file_count += 1; let name = entry.file_name().to_string_lossy().to_string(); if name.starts_with("project_") && name.ends_with(".json") { projects_size += size; project_count += 1; } if name == "library.json" { library_size = size; } } } } } // Count library items let library_count = load_json::>(&app, "library.json").map(|v| v.len()).unwrap_or(0); Ok(StorageInfo { data_path, total_size_bytes: total_size, file_count, project_count, library_count, library_size_bytes: library_size, projects_size_bytes: projects_size }) } /// Clear all library data #[tauri::command] pub fn storage_clear_library(app: AppHandle) -> Result<(), String> { let path = app_file_path(&app, "library.json")?; if path.exists() { fs::write(&path, "[]").map_err(|e| e.to_string())?; } // Also clear in-memory state let state = app.state::(); let mut items = state.items.lock().map_err(|_| "lock")?; items.clear(); Ok(()) } /// Delete all project files and reset index #[tauri::command] pub fn storage_clear_projects(app: AppHandle) -> Result<(), String> { let dir = app.path().app_data_dir().map_err(|e| e.to_string())?.join("musealpha"); if let Ok(entries) = fs::read_dir(&dir) { for entry in entries.flatten() { let name = entry.file_name().to_string_lossy().to_string(); if name.starts_with("project_") && name.ends_with(".json") { let _ = fs::remove_file(entry.path()); } } } // Reset index save_json(&app, "projects_index.json", &serde_json::json!({"projects": [], "active_id": null}))?; Ok(()) } /// Reveal app data folder in OS file manager #[tauri::command] pub fn storage_reveal_folder(app: AppHandle) -> Result<(), String> { let dir = app.path().app_data_dir().map_err(|e| e.to_string())?.join("musealpha"); fs::create_dir_all(&dir).map_err(|e| e.to_string())?; opener::open(dir.to_string_lossy().as_ref()).map_err(|e| format!("Could not open folder: {e}")) }