diff --git a/Cargo.lock b/Cargo.lock index 0051af9..4458e67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6048,8 +6048,7 @@ dependencies = [ [[package]] name = "recently-used-xbel" version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "079a81183e41e5cf17fd9ec55db30d6be6cddfad7fd619862efac27f1be28c9b" +source = "git+https://github.com/pop-os/recently-used-xbel.git#eeba9e08b0446175d7dd4f526d21ea867ed37e87" dependencies = [ "chrono", "dirs 5.0.1", diff --git a/Cargo.toml b/Cargo.toml index 79e44e0..23415b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ i18n-embed = { version = "0.15", features = [ i18n-embed-fl = "0.9" rust-embed = "8" slotmap = "1.0.7" -recently-used-xbel = "1.1.0" +recently-used-xbel = { git = "https://github.com/pop-os/recently-used-xbel.git" } zip = "2.2.2" uzers = "0.12.1" md-5 = "0.10.6" diff --git a/i18n/en/cosmic_files.ftl b/i18n/en/cosmic_files.ftl index 4181a99..37b4989 100644 --- a/i18n/en/cosmic_files.ftl +++ b/i18n/en/cosmic_files.ftl @@ -245,6 +245,14 @@ permanently-deleted = Permanently deleted {$items} {$items -> [one] item *[other] items } +removing-from-recents = Removing {$items} {$items -> + [one] item + *[other] items + } from {recents} +removed-from-recents = Removed {$items} {$items -> + [one] item + *[other] items + } from {recents} renaming = Renaming "{$from}" to "{$to}" renamed = Renamed "{$from}" to "{$to}" restoring = Restoring {$items} {$items -> @@ -303,6 +311,7 @@ sort-by-name = Sort by name sort-by-modified = Sort by modified sort-by-size = Sort by size sort-by-trashed = Sort by delete time +remove-from-recents = Remove from recents ## Desktop change-wallpaper = Change wallpaper... diff --git a/src/app.rs b/src/app.rs index 5865465..8f74478 100644 --- a/src/app.rs +++ b/src/app.rs @@ -147,6 +147,7 @@ pub enum Action { PermanentlyDelete, Preview, Reload, + RemoveFromRecents, Rename, RestoreFromTrash, SearchActivate, @@ -217,6 +218,7 @@ impl Action { Action::PermanentlyDelete => Message::PermanentlyDelete(entity_opt), Action::Preview => Message::Preview(entity_opt), Action::Reload => Message::TabMessage(entity_opt, tab::Message::Reload), + Action::RemoveFromRecents => Message::RemoveFromRecents(entity_opt), Action::Rename => Message::Rename(entity_opt), Action::RestoreFromTrash => Message::RestoreFromTrash(entity_opt), Action::SearchActivate => Message::SearchActivate, @@ -360,6 +362,7 @@ pub enum Message { PermanentlyDelete(Option), Preview(Option), RescanTrash, + RemoveFromRecents(Option), Rename(Option), ReplaceResult(ReplaceResult), RestoreFromTrash(Option), @@ -1117,6 +1120,23 @@ impl App { Task::batch(commands) } + fn rescan_recents(&mut self) -> Task { + let mut needs_reload = Vec::new(); + for entity in self.tab_model.iter() { + if let Some(tab) = self.tab_model.data::(entity) { + if let Location::Recents = &tab.location { + needs_reload.push((entity, Location::Recents)); + } + } + } + + let mut commands = Vec::with_capacity(needs_reload.len()); + for (entity, location) in needs_reload { + commands.push(self.update_tab(entity, location, None)); + } + Task::batch(commands) + } + fn search_get(&self) -> Option<&str> { let entity = self.tab_model.active(); let tab = self.tab_model.data::(entity)?; @@ -3152,6 +3172,10 @@ impl Application for App { } } + if matches!(op, Operation::RemoveFromRecents { .. }) { + commands.push(self.rescan_recents()); + } + self.complete_operations.insert(id, op); } // Close progress notification if all relevant operations are finished @@ -3168,6 +3192,7 @@ impl Application for App { commands.push(self.rescan_operation_selection(op_sel)); // Manually rescan any trash tabs after any operation is completed commands.push(self.rescan_trash()); + return Task::batch(commands); } Message::PendingDismiss => { @@ -3268,6 +3293,10 @@ impl Application for App { } } } + Message::RemoveFromRecents(entity_opt) => { + let paths = self.selected_paths(entity_opt); + return self.operation(Operation::RemoveFromRecents { paths }); + } Message::RescanTrash => { // Update trash icon if empty/full let maybe_entity = self.nav_model.iter().find(|&entity| { diff --git a/src/menu.rs b/src/menu.rs index e1ee2a9..c219c61 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -239,6 +239,12 @@ pub fn context_menu<'a>( children.push(menu_item(fl!("add-to-sidebar"), Action::AddToSidebar).into()); } children.push(divider::horizontal::light().into()); + if matches!(tab.location, Location::Recents) { + children.push( + menu_item(fl!("remove-from-recents"), Action::RemoveFromRecents).into(), + ); + children.push(divider::horizontal::light().into()); + } if selected_mount_point == 0 { if modifiers.shift() && !modifiers.control() { children.push( diff --git a/src/operation/mod.rs b/src/operation/mod.rs index 06988c4..ce2ac6d 100644 --- a/src/operation/mod.rs +++ b/src/operation/mod.rs @@ -523,6 +523,9 @@ pub enum Operation { PermanentlyDelete { paths: Vec, }, + RemoveFromRecents { + paths: Vec, + }, Rename { from: PathBuf, to: PathBuf, @@ -635,6 +638,7 @@ impl Operation { Self::Rename { from, to } => { fl!("renaming", from = file_name(from), to = file_name(to)) } + Self::RemoveFromRecents { paths } => fl!("removing-from-recents", items = paths.len()), Self::Restore { items } => fl!("restoring", items = items.len(), progress = progress()), Self::SetExecutableAndLaunch { path } => { fl!("setting-executable-and-launching", name = file_name(path)) @@ -698,6 +702,7 @@ impl Operation { parent = parent_name(path) ), Self::PermanentlyDelete { paths } => fl!("permanently-deleted", items = paths.len()), + Self::RemoveFromRecents { paths } => fl!("removed-from-recents", items = paths.len()), Self::Rename { from, to } => fl!("renamed", from = file_name(from), to = file_name(to)), Self::Restore { items } => fl!("restored", items = items.len()), Self::SetExecutableAndLaunch { path } => { @@ -727,6 +732,7 @@ impl Operation { | Self::Restore { .. } => true, Self::NewFile { .. } | Self::NewFolder { .. } + | Self::RemoveFromRecents { .. } | Self::Rename { .. } | Self::SetExecutableAndLaunch { .. } | Self::SetPermissions { .. } => false, @@ -1154,6 +1160,17 @@ impl Operation { Ok(OperationSelection::default()) } + Self::RemoveFromRecents { paths } => { + tokio::task::spawn_blocking(move || { + let path_refs = paths.iter().map(|p| p.as_ref()).collect::>(); + recently_used_xbel::remove_recently_used(&path_refs) + }) + .await + .map_err(OperationError::from_str)? + .map_err(OperationError::from_str)?; + + Ok(OperationSelection::default()) + } Self::Rename { from, to } => compio::runtime::spawn(async move { controller.check().await.map_err(OperationError::from_str)?; compio::fs::rename(&from, &to)