Show all applications that handle any mime types in open with dialog, fixes #568, fixes #226, fixes #721
This commit is contained in:
parent
d9ffb5d599
commit
8ced8b0551
3 changed files with 58 additions and 11 deletions
|
|
@ -80,6 +80,8 @@ save-file = Save file
|
||||||
## Open With Dialog
|
## Open With Dialog
|
||||||
open-with-title = How do you want to open "{$name}"?
|
open-with-title = How do you want to open "{$name}"?
|
||||||
browse-store = Browse {$store}
|
browse-store = Browse {$store}
|
||||||
|
other-apps = Other applications
|
||||||
|
related-apps = Related applications
|
||||||
|
|
||||||
## Rename Dialog
|
## Rename Dialog
|
||||||
rename-file = Rename file
|
rename-file = Rename file
|
||||||
|
|
|
||||||
50
src/app.rs
50
src/app.rs
|
|
@ -505,6 +505,13 @@ pub enum DialogPage {
|
||||||
|
|
||||||
pub struct FavoriteIndex(usize);
|
pub struct FavoriteIndex(usize);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
enum MimeAppMatch {
|
||||||
|
Exact,
|
||||||
|
Related,
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MounterData(MounterKey, MounterItem);
|
pub struct MounterData(MounterKey, MounterItem);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -1710,7 +1717,7 @@ impl App {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_programs_for_mime(&self, mime_type: &Mime) -> Vec<&MimeApp> {
|
fn get_apps_for_mime(&self, mime_type: &Mime) -> Vec<(&MimeApp, MimeAppMatch)> {
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
|
||||||
let mut dedupe = HashSet::new();
|
let mut dedupe = HashSet::new();
|
||||||
|
|
@ -1719,7 +1726,7 @@ impl App {
|
||||||
for mime_app in self.mime_app_cache.get(mime_type) {
|
for mime_app in self.mime_app_cache.get(mime_type) {
|
||||||
let app_id = &mime_app.id;
|
let app_id = &mime_app.id;
|
||||||
if !dedupe.contains(app_id) {
|
if !dedupe.contains(app_id) {
|
||||||
results.push(mime_app);
|
results.push((mime_app, MimeAppMatch::Exact));
|
||||||
dedupe.insert(app_id);
|
dedupe.insert(app_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1730,13 +1737,22 @@ impl App {
|
||||||
for mime_app in self.mime_app_cache.get(&parent_type) {
|
for mime_app in self.mime_app_cache.get(&parent_type) {
|
||||||
let app_id = &mime_app.id;
|
let app_id = &mime_app.id;
|
||||||
if !dedupe.contains(app_id) {
|
if !dedupe.contains(app_id) {
|
||||||
results.push(mime_app);
|
results.push((mime_app, MimeAppMatch::Related));
|
||||||
dedupe.insert(app_id);
|
dedupe.insert(app_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add other apps
|
||||||
|
for mime_app in self.mime_app_cache.apps() {
|
||||||
|
let app_id = &mime_app.id;
|
||||||
|
if !dedupe.contains(app_id) {
|
||||||
|
results.push((mime_app, MimeAppMatch::Other));
|
||||||
|
dedupe.insert(app_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2412,9 +2428,9 @@ impl Application for App {
|
||||||
selected,
|
selected,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let all_apps = self.get_programs_for_mime(&mime);
|
let available_apps = self.get_apps_for_mime(&mime);
|
||||||
|
|
||||||
if let Some(app) = all_apps.get(selected) {
|
if let Some((app, _)) = available_apps.get(selected) {
|
||||||
if let Some(mut command) =
|
if let Some(mut command) =
|
||||||
app.command(&[&path]).and_then(|v| v.into_iter().next())
|
app.command(&[&path]).and_then(|v| v.into_iter().next())
|
||||||
{
|
{
|
||||||
|
|
@ -4555,11 +4571,23 @@ impl Application for App {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut column = widget::list_column();
|
let mut column = widget::list_column();
|
||||||
let available_programs = self.get_programs_for_mime(mime);
|
let available_apps = self.get_apps_for_mime(mime);
|
||||||
let item_height = 32.0;
|
let item_height = 32.0;
|
||||||
let mut displayed_default = false;
|
let mut displayed_default = false;
|
||||||
|
let mut last_kind = MimeAppMatch::Exact;
|
||||||
for (i, app) in available_programs.iter().enumerate() {
|
for (i, (app, kind)) in available_apps.iter().enumerate() {
|
||||||
|
if *kind != last_kind {
|
||||||
|
match kind {
|
||||||
|
MimeAppMatch::Related => {
|
||||||
|
column = column.add(widget::text::heading(fl!("related-apps")));
|
||||||
|
}
|
||||||
|
MimeAppMatch::Other => {
|
||||||
|
column = column.add(widget::text::heading(fl!("other-apps")));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
last_kind = *kind;
|
||||||
|
}
|
||||||
column = column.add(
|
column = column.add(
|
||||||
widget::button::custom(
|
widget::button::custom(
|
||||||
widget::row::with_children(vec![
|
widget::row::with_children(vec![
|
||||||
|
|
@ -4603,13 +4631,13 @@ impl Application for App {
|
||||||
)
|
)
|
||||||
.control(
|
.control(
|
||||||
widget::scrollable(column).height(if let Some(size) = self.size {
|
widget::scrollable(column).height(if let Some(size) = self.size {
|
||||||
let max_size = size.height - 256.0;
|
let max_size = (size.height - 256.0).min(480.0);
|
||||||
// (32 (item_height) + 5.0 (custom button padding)) + (space_xxs (list item spacing) * 2)
|
// (32 (item_height) + 5.0 (custom button padding)) + (space_xxs (list item spacing) * 2)
|
||||||
let scrollable_height = available_programs.len() as f32
|
let scrollable_height = available_apps.len() as f32
|
||||||
* (item_height + 5.0 + (2.0 * space_xxs as f32));
|
* (item_height + 5.0 + (2.0 * space_xxs as f32));
|
||||||
|
|
||||||
if scrollable_height > max_size {
|
if scrollable_height > max_size {
|
||||||
Length::Fill
|
Length::Fixed(max_size)
|
||||||
} else {
|
} else {
|
||||||
Length::Shrink
|
Length::Shrink
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,7 @@ fn filename_eq(path_opt: &Option<PathBuf>, filename: &str) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MimeAppCache {
|
pub struct MimeAppCache {
|
||||||
|
apps: Vec<MimeApp>,
|
||||||
cache: HashMap<Mime, Vec<MimeApp>>,
|
cache: HashMap<Mime, Vec<MimeApp>>,
|
||||||
icons: HashMap<Mime, Vec<widget::icon::Handle>>,
|
icons: HashMap<Mime, Vec<widget::icon::Handle>>,
|
||||||
terminals: Vec<MimeApp>,
|
terminals: Vec<MimeApp>,
|
||||||
|
|
@ -228,6 +229,7 @@ pub struct MimeAppCache {
|
||||||
impl MimeAppCache {
|
impl MimeAppCache {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut mime_app_cache = Self {
|
let mut mime_app_cache = Self {
|
||||||
|
apps: Vec::new(),
|
||||||
cache: HashMap::new(),
|
cache: HashMap::new(),
|
||||||
icons: HashMap::new(),
|
icons: HashMap::new(),
|
||||||
terminals: Vec::new(),
|
terminals: Vec::new(),
|
||||||
|
|
@ -246,6 +248,7 @@ impl MimeAppCache {
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
|
self.apps.clear();
|
||||||
self.cache.clear();
|
self.cache.clear();
|
||||||
self.icons.clear();
|
self.icons.clear();
|
||||||
self.terminals.clear();
|
self.terminals.clear();
|
||||||
|
|
@ -257,6 +260,10 @@ impl MimeAppCache {
|
||||||
//TODO: hashmap for all apps by id?
|
//TODO: hashmap for all apps by id?
|
||||||
let mut all_apps = desktop::load_applications(locale, false);
|
let mut all_apps = desktop::load_applications(locale, false);
|
||||||
for app in &mut all_apps {
|
for app in &mut all_apps {
|
||||||
|
//TODO: just collect apps that can be executed with a file argument?
|
||||||
|
if !app.mime_types.is_empty() {
|
||||||
|
self.apps.push(MimeApp::from(&app));
|
||||||
|
}
|
||||||
for mime in app.mime_types.iter() {
|
for mime in app.mime_types.iter() {
|
||||||
let apps = self
|
let apps = self
|
||||||
.cache
|
.cache
|
||||||
|
|
@ -387,6 +394,12 @@ impl MimeAppCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort apps by name
|
// Sort apps by name
|
||||||
|
self.apps
|
||||||
|
.sort_by(|a, b| match (a.is_default, b.is_default) {
|
||||||
|
(true, false) => Ordering::Less,
|
||||||
|
(false, true) => Ordering::Greater,
|
||||||
|
_ => LANGUAGE_SORTER.compare(&a.name, &b.name),
|
||||||
|
});
|
||||||
for apps in self.cache.values_mut() {
|
for apps in self.cache.values_mut() {
|
||||||
apps.sort_by(|a, b| match (a.is_default, b.is_default) {
|
apps.sort_by(|a, b| match (a.is_default, b.is_default) {
|
||||||
(true, false) => Ordering::Less,
|
(true, false) => Ordering::Less,
|
||||||
|
|
@ -408,6 +421,10 @@ impl MimeAppCache {
|
||||||
log::info!("loaded mime app cache in {:?}", elapsed);
|
log::info!("loaded mime app cache in {:?}", elapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn apps(&self) -> &[MimeApp] {
|
||||||
|
&self.apps
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &Mime) -> &[MimeApp] {
|
pub fn get(&self, key: &Mime) -> &[MimeApp] {
|
||||||
static EMPTY: Vec<MimeApp> = Vec::new();
|
static EMPTY: Vec<MimeApp> = Vec::new();
|
||||||
self.cache.get(key).unwrap_or(&EMPTY)
|
self.cache.get(key).unwrap_or(&EMPTY)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue