mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-17 11:45:05 +02:00
Preserve local paths for desktop saves (#5543)
# Summary - Adds desktop file tracking: local paths are preserved and save buttons now work as expcted (doing Save/Save As as appropriate) - Adds logic to track whether files are 'dirty' (they've been modified by some tool, and not saved to disk yet). - Improves file state UX (dirty vs saved) and close warnings - Web behaviour should be unaffected by these changes ## Indicators Files now have indicators in desktop mode to tell you their state. ### File up-to-date with disk <img width="318" height="393" alt="image" src="https://github.com/user-attachments/assets/06325f9a-afd7-4c2f-8a5b-6d11e3093115" /> ### File modified by a tool but not saved to disk yet <img width="357" height="385" alt="image" src="https://github.com/user-attachments/assets/1a7716d9-c6f7-4d13-be0d-c1de6493954b" /> ### File not tracked on disk <img width="312" height="379" alt="image" src="https://github.com/user-attachments/assets/9cffe300-bd9a-4e19-97c7-9b98bebefacc" /> # Limitations - It's a bit weird that we still have files stored in indexeddb in the app, which are still loadable. We might want to change this behaviour in the future - Viewer's Save doesn't persist to disk. I've left that out here because it'd need a lot of testing to make sure the logic's right with making sure you can leave the Viewer with applying the changes to the PDF _without_ saving to disk - There's no current way to do Save As on a file that has already been persisted to disk - it's only ever Save. Similarly, there's no way to duplicate a file. --------- Co-authored-by: James Brunton <[email protected]> Co-authored-by: James Brunton <[email protected]>
This commit is contained in:
co-authored by
James Brunton
James Brunton
parent
946196de43
commit
b8ce4e47c1
Generated
+45
@@ -907,6 +907,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"block2",
|
||||
"libc",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
@@ -3531,6 +3533,30 @@ dependencies = [
|
||||
"webpki-roots 1.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfd"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"dispatch2",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gtk-sys",
|
||||
"js-sys",
|
||||
"log",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation",
|
||||
"raw-window-handle",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
@@ -4229,6 +4255,7 @@ dependencies = [
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-deep-link",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-fs",
|
||||
"tauri-plugin-http",
|
||||
"tauri-plugin-log",
|
||||
@@ -4609,6 +4636,24 @@ dependencies = [
|
||||
"windows-result 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b"
|
||||
dependencies = [
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
"rfd",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-plugin-fs",
|
||||
"thiserror 2.0.18",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.4.5"
|
||||
|
||||
@@ -28,6 +28,7 @@ tauri = { version = "2.9.0", features = [ "devtools"] }
|
||||
tauri-plugin-log = "2.8.0"
|
||||
tauri-plugin-shell = "2.3.4"
|
||||
tauri-plugin-fs = "2.4.5"
|
||||
tauri-plugin-dialog = "2.4.2"
|
||||
tauri-plugin-http = { version = "2.5.6", features = ["dangerous-settings"] }
|
||||
tauri-plugin-single-instance = { version = "2.3.7", features = ["deep-link"] }
|
||||
tauri-plugin-store = "2.4.2"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"core:window:allow-destroy",
|
||||
"http:default",
|
||||
{
|
||||
"identifier": "http:allow-fetch",
|
||||
@@ -40,6 +41,18 @@
|
||||
"identifier": "fs:allow-read-file",
|
||||
"allow": [{ "path": "**" }]
|
||||
},
|
||||
{
|
||||
"identifier": "fs:allow-write-file",
|
||||
"allow": [{ "path": "**" }]
|
||||
},
|
||||
{
|
||||
"identifier": "fs:allow-remove",
|
||||
"allow": [{ "path": "**" }]
|
||||
},
|
||||
"dialog:default",
|
||||
"dialog:allow-message",
|
||||
"dialog:allow-open",
|
||||
"dialog:allow-save",
|
||||
"opener:default",
|
||||
"shell:allow-open"
|
||||
]
|
||||
|
||||
@@ -33,3 +33,12 @@ pub async fn clear_opened_files() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Command to atomically get and clear opened file paths
|
||||
#[tauri::command]
|
||||
pub async fn pop_opened_files() -> Result<Vec<String>, String> {
|
||||
let mut opened_files = OPENED_FILES.lock().unwrap();
|
||||
let all_files = opened_files.clone();
|
||||
opened_files.clear();
|
||||
add_log(format!("📂 Returning and clearing {} opened file(s)", all_files.len()));
|
||||
Ok(all_files)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ pub mod auth;
|
||||
pub mod default_app;
|
||||
|
||||
pub use backend::{cleanup_backend, get_backend_port, start_backend};
|
||||
pub use files::{add_opened_file, clear_opened_files, get_opened_files};
|
||||
pub use files::{add_opened_file, clear_opened_files, get_opened_files, pop_opened_files};
|
||||
pub use connection::{
|
||||
get_connection_config,
|
||||
is_first_launch,
|
||||
|
||||
@@ -16,6 +16,7 @@ use commands::{
|
||||
get_backend_port,
|
||||
get_connection_config,
|
||||
get_opened_files,
|
||||
pop_opened_files,
|
||||
get_refresh_token,
|
||||
get_user_info,
|
||||
is_first_launch,
|
||||
@@ -55,6 +56,7 @@ pub fn run() {
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(tauri_plugin_store::Builder::new().build())
|
||||
.plugin(tauri_plugin_deep_link::init())
|
||||
@@ -139,6 +141,7 @@ pub fn run() {
|
||||
start_backend,
|
||||
get_backend_port,
|
||||
get_opened_files,
|
||||
pop_opened_files,
|
||||
clear_opened_files,
|
||||
get_tauri_logs,
|
||||
get_connection_config,
|
||||
@@ -170,9 +173,9 @@ pub fn run() {
|
||||
app_handle.cleanup_before_exit();
|
||||
}
|
||||
RunEvent::WindowEvent { event: WindowEvent::CloseRequested {.. }, .. } => {
|
||||
add_log("🔄 Window close requested, cleaning up...".to_string());
|
||||
cleanup_backend();
|
||||
// Allow the window to close
|
||||
add_log("🔄 Window close requested (will cleanup on actual exit)...".to_string());
|
||||
// Don't cleanup here - let JavaScript handler prevent close if needed
|
||||
// Backend cleanup happens in ExitRequested when window actually closes
|
||||
}
|
||||
RunEvent::WindowEvent { event: WindowEvent::DragDrop(drag_drop_event), .. } => {
|
||||
use tauri::DragDropEvent;
|
||||
|
||||
Reference in New Issue
Block a user