From e8fdb28a24ab11f249a9a39b1ea04bb245924466 Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Thu, 11 Jun 2026 18:45:49 +0200 Subject: [PATCH] feat(mime_app): show related apps in open with dropdown in preview --- src/app.rs | 4 ++-- src/mime_app.rs | 47 +++++++++++++++++++++++++++++++++-------------- src/tab.rs | 38 ++++++++++++++++++++------------------ 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/app.rs b/src/app.rs index 58ac81f..ac0996a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3180,7 +3180,7 @@ impl Application for App { selected, .. } => { - let available_apps = self.mime_app_cache.get_apps_for_mime(&mime); + let available_apps = self.mime_app_cache.get_apps_for_mime(&mime, true); if let Some((app, _)) = available_apps.get(selected) { if let Some(mut command) = @@ -5918,7 +5918,7 @@ impl Application for App { }; let mut column = widget::list_column(); - let available_apps = self.mime_app_cache.get_apps_for_mime(mime); + let available_apps = self.mime_app_cache.get_apps_for_mime(mime, true); let item_height = 32.0; let mut displayed_default = false; let mut last_kind = MimeAppMatch::Exact; diff --git a/src/mime_app.rs b/src/mime_app.rs index bb84f80..5a3b421 100644 --- a/src/mime_app.rs +++ b/src/mime_app.rs @@ -252,7 +252,11 @@ impl MimeAppCache { mime_app_cache } - pub fn get_apps_for_mime(&self, mime_type: &Mime) -> Vec<(&Arc, MimeAppMatch)> { + pub fn get_apps_for_mime( + &self, + mime_type: &Mime, + include_other: bool, + ) -> Vec<(&Arc, MimeAppMatch)> { let mut results = Vec::new(); let mut dedupe = FxHashSet::default(); @@ -291,19 +295,21 @@ impl MimeAppCache { } } - results.extend({ - let mut apps = self - .apps() - .iter() - .filter(|mime_app| !mime_app.no_display()) - .filter(|&mime_app| dedupe.insert(&mime_app.id)) - .map(|mime_app| (mime_app, MimeAppMatch::Other)) - .collect::>(); - apps.sort_by(|(a, _), (b, _)| { - crate::localize::LANGUAGE_SORTER.compare(&a.name, &b.name) + if include_other { + results.extend({ + let mut apps = self + .apps() + .iter() + .filter(|mime_app| !mime_app.no_display()) + .filter(|&mime_app| dedupe.insert(&mime_app.id)) + .map(|mime_app| (mime_app, MimeAppMatch::Other)) + .collect::>(); + apps.sort_by(|(a, _), (b, _)| { + crate::localize::LANGUAGE_SORTER.compare(&a.name, &b.name) + }); + apps }); - apps - }); + } results } @@ -411,15 +417,28 @@ impl MimeAppCache { // Sort cached apps for this mime by default precedence. for default in defaults.into_iter().flatten() { let default = default.strip_suffix(".desktop").unwrap_or(default.as_ref()); + let mut found_any = false; apps.retain(|app| { let found = app.id.as_str() == default; if found { - app.is_default.write().unwrap().insert(default.into()); + app.is_default + .write() + .unwrap() + .insert(mime.essence_str().into()); cache.push(app.clone()); + found_any = true; } !found }); + + if !found_any && let Some(app) = self.apps.iter().find(|app| app.id == default) { + app.is_default + .write() + .unwrap() + .insert(mime.essence_str().into()); + cache.push(app.clone()); + } } // Sort remaining apps by name diff --git a/src/tab.rs b/src/tab.rs index d5deaaf..6afcfce 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -2368,23 +2368,24 @@ impl Item { ))); let mut settings = Vec::new(); if let Some(mime_app_cache) = mime_app_cache_opt { - let mime_apps = mime_app_cache.get(&self.mime); + let mime_apps = mime_app_cache.get_apps_for_mime(&self.mime, false); if !mime_apps.is_empty() { + let (names, icons) = mime_apps + .iter() + .map(|(app, _)| (Cow::Owned(app.name.clone()), app.icon())) + .collect::<(Vec<_>, Vec<_>)>(); settings.push( widget::settings::item::builder(fl!("open-with")).control( Element::from( widget::dropdown( - mime_apps - .iter() - .map(|app| Cow::Owned(app.name.clone())) - .collect::>>(), - mime_apps.iter().position(|x| x.is_default(&self.mime)), + names, + mime_apps.iter().position(|(x, _)| x.is_default(&self.mime)), move |index| index, ) - .icons(Cow::Owned(mime_app_cache.icons(&self.mime))), + .icons(Cow::Owned(icons)), ) - .map(|index| { - let mime_app = &mime_apps[index]; + .map(move |index| { + let mime_app = &mime_apps[index].0; Message::SetOpenWith(self.mime.clone(), mime_app.id.clone()) }), ), @@ -6451,24 +6452,25 @@ impl Tab { .and_then(|(mime, _)| mime.parse::().ok()) && let Some(mime_app_cache) = mime_app_cache_opt { - let mime_apps = mime_app_cache.get(&mime); + let mime_apps = mime_app_cache.get_apps_for_mime(&mime, false); if !mime_apps.is_empty() { let mime_closure = mime.clone(); + let (names, icons) = mime_apps + .iter() + .map(|(app, _)| (Cow::Owned(app.name.clone()), app.icon())) + .collect::<(Vec<_>, Vec<_>)>(); settings.push( widget::settings::item::builder(fl!("open-with")).control( Element::from( widget::dropdown( - mime_apps - .iter() - .map(|app| Cow::Owned(app.name.clone())) - .collect::>>(), - mime_apps.iter().position(|x| x.is_default(&mime)), + names, + mime_apps.iter().position(|(x, _)| x.is_default(&mime)), move |index| (index, mime_closure.clone()), ) - .icons(Cow::Owned(mime_app_cache.icons(&mime))), + .icons(Cow::Owned(icons)), ) - .map(|(index, mime)| { - let mime_app = &mime_apps[index]; + .map(move |(index, mime)| { + let mime_app = &mime_apps[index].0; Message::SetOpenWith(mime, mime_app.id.clone()) }), ),