use crate::db::{self, DbPool, Folder, ImageRecord}; use crate::indexer; use serde::{Deserialize, Serialize}; use std::path::PathBuf; use tauri::{AppHandle, State}; pub type DbState = DbPool; #[derive(Serialize)] pub struct ImagesPage { pub images: Vec, pub total: i64, pub offset: i64, pub limit: i64, } #[derive(Deserialize)] pub struct GetImagesParams { pub folder_id: Option, pub search: Option, pub media_kind: Option, pub favorites_only: Option, pub sort: Option, pub offset: Option, pub limit: Option, } #[derive(Deserialize)] pub struct UpdateImageDetailsParams { pub image_id: i64, pub favorite: Option, pub rating: Option, } #[tauri::command] pub async fn add_folder( app: AppHandle, db: State<'_, DbState>, path: String, ) -> Result { let folder_path = PathBuf::from(&path); if !folder_path.exists() || !folder_path.is_dir() { return Err("Path is not a valid directory".into()); } let name = folder_path .file_name() .map(|n| n.to_string_lossy().to_string()) .unwrap_or_else(|| path.clone()); let folder_id = { let conn = db.get().map_err(|e| e.to_string())?; db::insert_folder(&conn, &path, &name).map_err(|e| e.to_string())? }; let folders = { let conn = db.get().map_err(|e| e.to_string())?; db::get_folders(&conn).map_err(|e| e.to_string())? }; let folder = folders .into_iter() .find(|f| f.id == folder_id) .ok_or("Folder not found after insert")?; indexer::index_folder(app, db.inner().clone(), folder_id, folder_path); Ok(folder) } #[tauri::command] pub async fn get_folders(db: State<'_, DbState>) -> Result, String> { let conn = db.get().map_err(|e| e.to_string())?; db::get_folders(&conn).map_err(|e| e.to_string()) } #[tauri::command] pub async fn remove_folder(db: State<'_, DbState>, folder_id: i64) -> Result<(), String> { let conn = db.get().map_err(|e| e.to_string())?; db::delete_folder(&conn, folder_id).map_err(|e| e.to_string()) } #[tauri::command] pub async fn get_images( db: State<'_, DbState>, params: GetImagesParams, ) -> Result { let conn = db.get().map_err(|e| e.to_string())?; let sort = params.sort.as_deref().unwrap_or("date_desc"); let offset = params.offset.unwrap_or(0); let limit = params.limit.unwrap_or(100); let search = params.search.as_deref(); let media_kind = params.media_kind.as_deref(); let favorites_only = params.favorites_only.unwrap_or(false); let total = db::count_images(&conn, params.folder_id, search, media_kind, favorites_only) .map_err(|e| e.to_string())?; let images = db::get_images( &conn, params.folder_id, search, media_kind, favorites_only, sort, offset, limit, ) .map_err(|e| e.to_string())?; Ok(ImagesPage { images, total, offset, limit, }) } #[tauri::command] pub async fn update_image_details( db: State<'_, DbState>, params: UpdateImageDetailsParams, ) -> Result { let conn = db.get().map_err(|e| e.to_string())?; db::update_image_details(&conn, params.image_id, params.favorite, params.rating) .map_err(|e| e.to_string()) } #[tauri::command] pub async fn reindex_folder( app: AppHandle, db: State<'_, DbState>, folder_id: i64, ) -> Result<(), String> { let folder_path = { let conn = db.get().map_err(|e| e.to_string())?; let folders = db::get_folders(&conn).map_err(|e| e.to_string())?; folders .into_iter() .find(|f| f.id == folder_id) .map(|f| PathBuf::from(f.path)) .ok_or("Folder not found")? }; indexer::index_folder(app, db.inner().clone(), folder_id, folder_path); Ok(()) }