Skip to main content

max / balanced_breakfast

2.8 KB · 92 lines History Blame Raw
1 //! Theme loading commands — thin Tauri wrappers over `theme_common`.
2
3 use std::path::PathBuf;
4 use tauri::{AppHandle, Manager};
5 use tracing::instrument;
6
7 use super::error::ApiError;
8
9 pub use theme_common::{ThemeColors, ThemeMeta};
10
11 /// Returns theme directories in priority order (later overrides earlier by ID).
12 /// Each entry is `(path, is_custom)`.
13 fn theme_dirs(app: &AppHandle) -> Vec<(PathBuf, bool)> {
14 let mut dirs = Vec::new();
15
16 // 1. Bundled themes (production)
17 if let Ok(resource_dir) = app.path().resource_dir() {
18 let bundled = resource_dir.join("themes");
19 if bundled.is_dir() {
20 dirs.push((bundled, false));
21 }
22 }
23
24 // 2. Dev fallback: CARGO_MANIFEST_DIR → 3 parents up → Git/themes/
25 if let Some(dev_path) = theme_common::dev_themes_dir(env!("CARGO_MANIFEST_DIR").as_ref(), 3) {
26 dirs.push((dev_path, false));
27 }
28
29 // 3. User custom themes (highest priority)
30 if let Ok(config_dir) = app.path().app_config_dir() {
31 let custom = config_dir.join("themes");
32 if custom.is_dir() {
33 dirs.push((custom, true));
34 }
35 }
36
37 dirs
38 }
39
40 #[tauri::command]
41 #[instrument(skip_all)]
42 pub fn list_themes(app: AppHandle) -> Result<Vec<ThemeMeta>, ApiError> {
43 let dirs = theme_dirs(&app);
44 Ok(theme_common::list_themes_from_dirs(&dirs))
45 }
46
47 #[tauri::command]
48 #[instrument(skip_all)]
49 pub fn get_theme(app: AppHandle, id: String) -> Result<ThemeColors, ApiError> {
50 let dirs = theme_dirs(&app);
51 theme_common::load_theme(&dirs, &id).map_err(ApiError::internal)
52 }
53
54 #[tauri::command]
55 #[instrument(skip_all)]
56 pub fn get_custom_themes_dir(app: AppHandle) -> Result<String, ApiError> {
57 let dir = app
58 .path()
59 .app_config_dir()
60 .map_err(|e| ApiError::internal(e.to_string()))?
61 .join("themes");
62 std::fs::create_dir_all(&dir)
63 .map_err(|e| ApiError::internal(format!("Failed to create themes dir: {}", e)))?;
64 Ok(dir.to_string_lossy().to_string())
65 }
66
67 #[tauri::command]
68 #[instrument(skip_all)]
69 pub fn import_theme(app: AppHandle, path: String) -> Result<ThemeMeta, ApiError> {
70 let custom_dir = app
71 .path()
72 .app_config_dir()
73 .map_err(|e| ApiError::internal(e.to_string()))?
74 .join("themes");
75 theme_common::import_theme(std::path::Path::new(&path), &custom_dir)
76 .map_err(ApiError::internal)
77 }
78
79 #[tauri::command]
80 #[instrument(skip_all)]
81 pub fn export_theme(app: AppHandle, id: String, path: String) -> Result<(), ApiError> {
82 let dirs = theme_dirs(&app);
83 theme_common::export_theme(&dirs, &id, std::path::Path::new(&path))
84 .map_err(ApiError::internal)
85 }
86
87 #[cfg(test)]
88 mod tests {
89 // Core theme logic tests live in theme-common crate.
90 // App-specific tests here only if needed for theme_dirs behavior.
91 }
92