From b288cd058174d36830c02d316ba9ecafebadeb19 Mon Sep 17 00:00:00 2001 From: ellieplayswow <164806095+ellieplayswow@users.noreply.github.com> Date: Sun, 9 Mar 2025 21:03:42 +0000 Subject: [PATCH] simplifying list generation for mime types, applying xdg-mime patch & cargo fmt --- Cargo.lock | 3 +- Cargo.toml | 3 +- src/app.rs | 123 ++++++++++++++--------------------------------- src/mime_icon.rs | 2 +- 4 files changed, 41 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b36c014..4938df5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7546,8 +7546,7 @@ dependencies = [ [[package]] name = "xdg-mime" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58d325d0ca93fb1984a56eb926f019acfc67bd2ec559b0dbf09cafcc92e81ec9" +source = "git+https://github.com/ellieplayswow/xdg-mime-rs?branch=feature/get-same-as#4f8d07ceedabbe58368a8e7f5547232490860790" dependencies = [ "dirs-next", "glob", diff --git a/Cargo.toml b/Cargo.toml index 7392f56..8733df5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ url = "2.5" walkdir = "2.5.0" wayland-client = { version = "0.31.8", optional = true } xdg = { version = "2.5.2", optional = true } -xdg-mime = "0.4" +xdg-mime = "0.4.0" # Compression bzip2 = { version = "0.5", optional = true } #TODO: replace with pure Rust crate flate2 = "1.0" @@ -96,6 +96,7 @@ tokio = { version = "1", features = ["rt", "macros"] } [patch.crates-io] # https://github.com/alexcrichton/filetime/pull/104 filetime = { git = "https://github.com/jackpot51/filetime" } +xdg-mime = { git = "https://github.com/ellieplayswow/xdg-mime-rs", branch = "feature/get-same-as" } # [patch.'https://github.com/pop-os/cosmic-text'] # cosmic-text = { path = "../cosmic-text" } diff --git a/src/app.rs b/src/app.rs index 5f02aaa..9e916b2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -14,6 +14,7 @@ use cosmic::iced::{ }; #[cfg(feature = "wayland")] use cosmic::iced_winit::commands::overlap_notify::overlap_notify; +use cosmic::widget::{Button, ListColumn}; use cosmic::{ app::{self, context_drawer, message, Core, Task}, cosmic_config, cosmic_theme, executor, @@ -40,6 +41,7 @@ use cosmic::{ }, Application, ApplicationExt, Element, }; +use mime_guess::Mime; use notify_debouncer_full::{ new_debouncer, notify::{self, RecommendedWatcher, Watcher}, @@ -57,12 +59,12 @@ use std::{ time::{self, Instant}, }; use cosmic::iced::mouse::Event::CursorMoved; -use cosmic::widget::{Button, ListColumn}; use tokio::sync::mpsc; use trash::TrashItem; #[cfg(feature = "wayland")] use wayland_client::{protocol::wl_output::WlOutput, Proxy}; +use crate::mime_app::MimeApp; use crate::operation::{OperationError, OperationErrorType}; use crate::{ clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste}, @@ -76,7 +78,6 @@ use crate::{ spawn_detached::spawn_detached, tab::{self, HeadingOptions, ItemMetadata, Location, Tab, HOVER_DURATION}, }; -use crate::mime_app::MimeApp; #[derive(Clone, Debug)] pub enum Mode { @@ -1595,6 +1596,36 @@ impl App { .into() } + fn get_programs_for_mime(&self, mime_type: &Mime) -> Vec<&MimeApp> { + let mut results = Vec::new(); + + let mut dedupe = HashSet::new(); + + // start with exact matches + for mime_app in self.mime_app_cache.get(mime_type) { + let app_id = &mime_app.id; + if !dedupe.contains(app_id) { + results.push(mime_app); + dedupe.insert(app_id); + } + } + + // grab matches based off of subclass / parent mime type + if let Some(parent_types) = mime_icon::parent_mime_types(mime_type) { + for parent_type in parent_types { + for mime_app in self.mime_app_cache.get(&parent_type) { + let app_id = &mime_app.id; + if !dedupe.contains(app_id) { + results.push(mime_app); + dedupe.insert(app_id); + } + } + } + } + + results + } + // Update favorites based on renaming or moving dirs. fn update_favorites(&mut self, path_changes: &[(PathBuf, PathBuf)]) -> bool { let mut favorites_changed = false; @@ -2215,8 +2246,9 @@ impl Application for App { selected, .. } => { - let direct_apps = self.mime_app_cache.get(&mime); - if let Some(app) = direct_apps.get(selected) { + let all_apps = self.get_programs_for_mime(&mime); + + if let Some(app) = all_apps.get(selected) { if let Some(mut command) = app.command(Some(path.clone().into())) { match spawn_detached(&mut command) { Ok(()) => { @@ -2244,46 +2276,6 @@ impl Application for App { ); } } - - let mut sub_class_index = selected - direct_apps.len(); - if let Some(sub_classes) = mime_icon::parent_mime_types(&mime) { - for sub_class in sub_classes { - let sub_class_apps = self.mime_app_cache.get(&sub_class); - if let Some(app) = sub_class_apps.get(sub_class_index) { - if let Some(mut command) = app.command(Some(path.clone().into())) { - match spawn_detached(&mut command) { - Ok(()) => { - let _ = recently_used_xbel::update_recently_used( - &path, - App::APP_ID.to_string(), - "cosmic-files".to_string(), - None, - ); - } - Err(err) => { - log::warn!( - "failed to open {:?} with {:?}: {}", - path, - app.id, - err - ) - } - } - } else { - log::warn!( - "failed to open {:?} with {:?}: failed to get command", - path, - app.id - ); - } - } - else { - sub_class_index -= sub_class_apps.len(); - } - - } - } - } DialogPage::RenameItem { from, parent, name, .. @@ -4298,8 +4290,7 @@ impl Application for App { }; let mut column = widget::list_column(); - let mut open_index = 0; - for (i, app) in self.mime_app_cache.get(mime).iter().enumerate() { + for (i, app) in self.get_programs_for_mime(&mime).iter().enumerate() { column = column.add( widget::button::custom( widget::row::with_children(vec![ @@ -4330,48 +4321,8 @@ impl Application for App { .class(theme::Button::MenuItem) .on_press(Message::OpenWithSelection(i)), ); - open_index += 1; } - if let Some(sub_classes) = mime_icon::parent_mime_types(&mime) { - for sub_class in sub_classes { - for (i, app) in self.mime_app_cache.get(&sub_class).iter().enumerate() { - column = column.add( - widget::button::custom( - widget::row::with_children(vec![ - widget::icon(app.icon.clone()).size(32).into(), - if app.is_default { - widget::text::body(fl!( - "default-app", - name = Some(app.name.as_str()) - )) - .into() - } else { - widget::text::body(app.name.to_string()).into() - }, - widget::horizontal_space().into(), - if *selected == open_index { - widget::icon::from_name("checkbox-checked-symbolic") - .size(16) - .into() - } else { - widget::Space::with_width(Length::Fixed(16.0)).into() - }, - ]) - .spacing(space_s) - .height(Length::Fixed(32.0)) - .align_y(Alignment::Center), - ) - .width(Length::Fill) - .class(theme::Button::MenuItem) - .on_press(Message::OpenWithSelection(open_index)), - ); - open_index += 1; - } - } - } - - let mut dialog = widget::dialog() .title(fl!("open-with-title", name = name)) .primary_action( diff --git a/src/mime_icon.rs b/src/mime_icon.rs index 9be98b6..c776dc8 100644 --- a/src/mime_icon.rs +++ b/src/mime_icon.rs @@ -78,4 +78,4 @@ pub fn parent_mime_types(mime: &Mime) -> Option> { let mut mime_icon_cache = MIME_ICON_CACHE.lock().unwrap(); mime_icon_cache.shared_mime_info.get_parents_aliased(mime) -} \ No newline at end of file +}