diff --git a/package-lock.json b/package-lock.json index 0cdd7de..c5428af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@tauri-apps/api": "^2.5.0", "@tauri-apps/plugin-autostart": "^2.3.0", "@tauri-apps/plugin-dialog": "^2.7.1", + "@tauri-apps/plugin-fs": "^2.5.1", "@tauri-apps/plugin-global-shortcut": "^2.2.0", "@tauri-apps/plugin-opener": "^2.2.0", "@tauri-apps/plugin-process": "^2.3.1", @@ -1218,6 +1219,15 @@ "@tauri-apps/api": "^2.11.0" } }, + "node_modules/@tauri-apps/plugin-fs": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-fs/-/plugin-fs-2.5.1.tgz", + "integrity": "sha512-9Lz+Jopp6QyeEWhlpkMx4R/+P9HgR+AVAI4vOZhlT8Xaymtz8iVI/Ov984/XTqgJz/5gz5NretqPB/XEMS3NhQ==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0" + } + }, "node_modules/@tauri-apps/plugin-global-shortcut": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-global-shortcut/-/plugin-global-shortcut-2.3.2.tgz", diff --git a/package.json b/package.json index 4df5651..239414a 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@tauri-apps/api": "^2.5.0", "@tauri-apps/plugin-autostart": "^2.3.0", "@tauri-apps/plugin-dialog": "^2.7.1", + "@tauri-apps/plugin-fs": "^2.5.1", "@tauri-apps/plugin-global-shortcut": "^2.2.0", "@tauri-apps/plugin-opener": "^2.2.0", "@tauri-apps/plugin-process": "^2.3.1", diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 4fd3982..d57ce83 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -38,20 +38,41 @@ fn safe_name(name: &str) -> bool { } #[tauri::command] -fn write_text_file(path: String, contents: String) -> Result<(), String> { - write_atomic(std::path::Path::new(&path), &contents) +async fn save_text_file_dialog(app: tauri::AppHandle, contents: String, is_sum: bool) -> Result { + use tauri_plugin_dialog::DialogExt; + let dialog = app.dialog().file(); + let dialog = if is_sum { + dialog.add_filter("Summarum Sheet", &["sum"]) + } else { + dialog.add_filter("Text file", &["txt"]) + }; + + if let Some(path) = dialog.blocking_save_file() { + let path = path.into_path().map_err(|_| "invalid path".to_string())?; + write_atomic(&path, &contents)?; + Ok(true) + } else { + Ok(false) + } } #[tauri::command] -fn write_image_file(path: String, data_base64: String) -> Result<(), String> { +async fn save_image_file_dialog(app: tauri::AppHandle, data_base64: String) -> Result { + use tauri_plugin_dialog::DialogExt; use std::io::Write; - let bytes = base64_decode(&data_base64)?; - let p = std::path::Path::new(&path); - let tmp = p.with_extension("tmp"); - std::fs::File::create(&tmp) - .and_then(|mut f| f.write_all(&bytes)) - .map_err(|e| e.to_string())?; - fs::rename(&tmp, p).map_err(|e| e.to_string()) + + if let Some(path) = app.dialog().file().add_filter("PNG Image", &["png"]).blocking_save_file() { + let path = path.into_path().map_err(|_| "invalid path".to_string())?; + let bytes = base64_decode(&data_base64)?; + let tmp = path.with_extension("tmp"); + std::fs::File::create(&tmp) + .and_then(|mut f| f.write_all(&bytes)) + .map_err(|e| e.to_string())?; + fs::rename(&tmp, &path).map_err(|e| e.to_string())?; + Ok(true) + } else { + Ok(false) + } } fn base64_decode(s: &str) -> Result, String> { @@ -712,8 +733,8 @@ fn main() { read_text_file, exit_app, is_hidden_launch, - write_text_file, - write_image_file + save_text_file_dialog, + save_image_file_dialog ]) .setup(|app| { let handle = app.handle().clone(); diff --git a/src/main.ts b/src/main.ts index a0d754b..7798d1a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -907,17 +907,11 @@ async function boot(): Promise { } else if (action === "print") { window.print(); } else if (isTauri()) { - const { save } = await import("@tauri-apps/plugin-dialog"); const { invoke } = await import("@tauri-apps/api/core"); const isSum = action === "save-sum"; - const path = await save({ - filters: isSum - ? [{ name: "Summarum Sheet", extensions: ["sum"] }] - : [{ name: "Text file", extensions: ["txt"] }], - }); - if (path) { - const content = isSum ? editor.getText() : editor.getSheetWithResults(); - await invoke("write_text_file", { path, contents: content }); + const content = isSum ? editor.getText() : editor.getSheetWithResults(); + const saved = await invoke("save_text_file_dialog", { contents: content, isSum }); + if (saved) { toast(t("saved")); } } diff --git a/src/storage.ts b/src/storage.ts index ce99608..70ef897 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -234,9 +234,9 @@ export async function fetchHistoricalRates(date: string): Promise { - if (!isTauri()) return; - await invoke("write_image_file", { path, dataBase64 }); +export async function writeImageFile(dataBase64: string): Promise { + if (!isTauri()) return false; + return await invoke("save_image_file_dialog", { dataBase64 }); } // ---------- market data diff --git a/src/ui/export.ts b/src/ui/export.ts index b94e6ab..7b2b456 100644 --- a/src/ui/export.ts +++ b/src/ui/export.ts @@ -58,14 +58,10 @@ export async function exportSheetImage(deps: ExportImageDeps): Promise { } catch { // clipboard API failed — save to file try { - const { save } = await import("@tauri-apps/plugin-dialog"); - const path = await save({ filters: [{ name: "PNG Image", extensions: ["png"] }] }); - if (path) { - const buf = await blob.arrayBuffer(); - const b64 = bytesToBase64(new Uint8Array(buf)); - await writeImageFile(path, b64); - toast(t("saved")); - } + const buf = await blob.arrayBuffer(); + const b64 = bytesToBase64(new Uint8Array(buf)); + const saved = await writeImageFile(b64); + if (saved) toast(t("saved")); } catch { toast(t("imageFailed")); }