From 503bce2c37c457b19ff50dccbbacc5f144498040 Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Tue, 19 Mar 2024 22:40:13 -0400 Subject: [PATCH 1/5] Bump `trash`: 3.3.1 to 4.1.0 The latest version of `trash` supports a feature needed to monitor the trash. --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abd51e9..c7f16f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5074,9 +5074,9 @@ dependencies = [ [[package]] name = "trash" -version = "3.3.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c658458d46d9d5a153a3b5cdd88d8579ad50d4fb85d53961e4526c8fc7c55a57" +checksum = "6a1a7a9a17d3b004898be42be29a4c18d5a4cf008b5cdf72d69b1945dfcb158a" dependencies = [ "chrono", "libc", diff --git a/Cargo.toml b/Cargo.toml index 4d85a98..ca07272 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ paste = "1.0" serde = { version = "1", features = ["serde_derive"] } shlex = { version = "1.3" } tokio = { version = "1", features = ["sync"] } -trash = "3.2.0" +trash = "4.1.0" xdg = { version = "2.5.2", optional = true } xdg-mime = "0.3" url = "2.5" From f606a2648295aebcf6899278e86d19b9053b0552 Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Wed, 20 Mar 2024 01:50:43 -0400 Subject: [PATCH 2/5] Watch trash folders for changes --- src/app.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/app.rs b/src/app.rs index e186ffa..4423d47 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1567,6 +1567,7 @@ impl Application for App { struct ConfigSubscription; struct ThemeSubscription; struct WatcherSubscription; + struct TrashWatcherSubscription; let mut subscriptions = vec![ event::listen_with(|event, status| match event { @@ -1687,6 +1688,44 @@ impl Application for App { } }, ), + subscription::channel( + TypeId::of::(), + 25, + |mut output| async move { + let watcher_res = notify::recommended_watcher(|event_res| match event_res { + Ok(event) => { + log::info!("Trash event: {event:?}"); + } + Err(e) => log::warn!("failed watching trash bin for changes: {e:?}"), + }); + + match (watcher_res, trash::os_limited::trash_folders()) { + (Ok(mut watcher), Ok(trash_bins)) => { + for path in trash_bins { + if let Err(e) = + watcher.watch(&path, notify::RecursiveMode::Recursive) + { + log::warn!( + "failed to add trash bin `{}` to watcher: {e:?}", + path.display() + ); + } + } + + // Don't drop the watcher + std::future::pending().await + } + (Err(e), _) => { + log::warn!("failed to create new watcher for trash bin: {e:?}") + } + (_, Err(e)) => { + log::warn!("could not find any valid trash bins to watch: {e:?}") + } + } + + std::future::pending().await + }, + ), ]; for (id, (pending_operation, _)) in self.pending_operations.iter() { From 2e5911e6cc1a6b943ec525bbdd4e6985c63d74b6 Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Wed, 20 Mar 2024 20:23:00 -0400 Subject: [PATCH 3/5] Reload the trash on Created/Removed events --- src/app.rs | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/app.rs b/src/app.rs index 4423d47..61f12f5 100644 --- a/src/app.rs +++ b/src/app.rs @@ -165,6 +165,7 @@ pub enum Message { PendingComplete(u64), PendingError(u64, String), PendingProgress(u64, f32), + RescanTrash, Rename(Option), RestoreFromTrash(Option), SystemThemeModeChange(cosmic_theme::ThemeMode), @@ -1100,6 +1101,7 @@ impl Application for App { *progress = new_progress; } } + Message::RescanTrash => return self.rescan_trash(), Message::Rename(entity_opt) => { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); if let Some(tab) = self.tab_model.data_mut::(entity) { @@ -1692,13 +1694,34 @@ impl Application for App { TypeId::of::(), 25, |mut output| async move { - let watcher_res = notify::recommended_watcher(|event_res| match event_res { - Ok(event) => { - log::info!("Trash event: {event:?}"); - } - Err(e) => log::warn!("failed watching trash bin for changes: {e:?}"), - }); + let watcher_res = notify::recommended_watcher( + move |event_res: Result| match event_res { + Ok(event) + if matches!( + event.kind, + notify::EventKind::Create(_) | notify::EventKind::Remove(_) + ) => + { + if let Err(e) = futures::executor::block_on(async { + output.send(Message::RescanTrash).await + }) { + log::warn!("trash needs to be rescanned but sending message failed: {e:?}"); + } + } + Ok(_) => {} + Err(e) => { + log::warn!("failed watching trash bin for changes: {e:?}") + } + }, + ); + // TODO: Trash watching support for Windows, macOS, and other OSes + #[cfg(all( + unix, + not(target_os = "macos"), + not(target_os = "ios"), + not(target_os = "android") + ))] match (watcher_res, trash::os_limited::trash_folders()) { (Ok(mut watcher), Ok(trash_bins)) => { for path in trash_bins { From 2f5bbc5e7f9258e02ebbdbe9ea5f65c6ff519d4c Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Wed, 20 Mar 2024 23:16:15 -0400 Subject: [PATCH 4/5] Convert trash watcher to use debounced events --- src/app.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/app.rs b/src/app.rs index 61f12f5..87ebd28 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1694,23 +1694,29 @@ impl Application for App { TypeId::of::(), 25, |mut output| async move { - let watcher_res = notify::recommended_watcher( - move |event_res: Result| match event_res { - Ok(event) - if matches!( - event.kind, - notify::EventKind::Create(_) | notify::EventKind::Remove(_) - ) => - { - if let Err(e) = futures::executor::block_on(async { - output.send(Message::RescanTrash).await - }) { - log::warn!("trash needs to be rescanned but sending message failed: {e:?}"); + let watcher_res = new_debouncer( + time::Duration::from_millis(250), + Some(time::Duration::from_millis(250)), + move |event_res: notify_debouncer_full::DebounceEventResult| match event_res + { + Ok(mut events) => { + events.retain(|event| { + matches!( + event.kind, + notify::EventKind::Create(_) | notify::EventKind::Remove(_) + ) + }); + + if !events.is_empty() { + if let Err(e) = futures::executor::block_on(async { + output.send(Message::RescanTrash).await + }) { + log::warn!("trash needs to be rescanned but sending message failed: {e:?}"); + } } } - Ok(_) => {} Err(e) => { - log::warn!("failed watching trash bin for changes: {e:?}") + log::warn!("failed to watch trash bin for changes: {e:?}") } }, ); @@ -1725,8 +1731,9 @@ impl Application for App { match (watcher_res, trash::os_limited::trash_folders()) { (Ok(mut watcher), Ok(trash_bins)) => { for path in trash_bins { - if let Err(e) = - watcher.watch(&path, notify::RecursiveMode::Recursive) + if let Err(e) = watcher + .watcher() + .watch(&path, notify::RecursiveMode::Recursive) { log::warn!( "failed to add trash bin `{}` to watcher: {e:?}", From 6a5f23acec131266a6186efe82d8150220a33785 Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Thu, 21 Mar 2024 00:44:40 -0400 Subject: [PATCH 5/5] Update trash icon in nav bar on change --- src/app.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/app.rs b/src/app.rs index 87ebd28..8d11662 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1101,7 +1101,22 @@ impl Application for App { *progress = new_progress; } } - Message::RescanTrash => return self.rescan_trash(), + Message::RescanTrash => { + // Update trash icon if empty/full + let maybe_entity = self.nav_model.iter().find(|&entity| { + self.nav_model + .data::(entity) + .map(|loc| *loc == Location::Trash) + .unwrap_or_default() + }); + if let Some(entity) = maybe_entity { + self.nav_model + .icon_set(entity, widget::icon::icon(tab::trash_icon_symbolic(16))); + } + + return self.rescan_trash(); + } + Message::Rename(entity_opt) => { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); if let Some(tab) = self.tab_model.data_mut::(entity) {