From 33ad05ee39c4e14c3c2bf7fcb842bf532ed991ee Mon Sep 17 00:00:00 2001 From: Aleksander Date: Tue, 6 Jan 2026 20:17:34 +0100 Subject: [PATCH] app categories --- dash-frontend/src/tab/apps.rs | 129 +++++++++++++++++++++++++++++-- wlx-common/src/desktop_finder.rs | 9 ++- 2 files changed, 129 insertions(+), 9 deletions(-) diff --git a/dash-frontend/src/tab/apps.rs b/dash-frontend/src/tab/apps.rs index 6fd8b90..e01f49a 100644 --- a/dash-frontend/src/tab/apps.rs +++ b/dash-frontend/src/tab/apps.rs @@ -70,7 +70,7 @@ struct AppList { //data: Vec, entries_to_mount: VecDeque, list_parent: WidgetPair, - prev_first_letter: char, + prev_category_name: String, } // called after the user clicks any desktop entry @@ -140,12 +140,17 @@ impl TabApps { .find_entries() .into_values() .collect(); - entries_sorted.sort_by(|a, b| a.app_name.cmp(&b.app_name)); + + entries_sorted.sort_by(|a, b| { + let cat_name_a = get_category_name(a); + let cat_name_b = get_category_name(b); + cat_name_a.cmp(cat_name_b) + }); let app_list = AppList { entries_to_mount: entries_sorted.drain(..).collect(), list_parent: app_list_parent, - prev_first_letter: ' ', + prev_category_name: String::new(), }; Ok(Self { @@ -158,6 +163,115 @@ impl TabApps { } } +enum Scores { + Empty, + Unknown, + XFooBar, // X-something + Xfce, + Gnome, + Kde, + Gtk, + Qt, + Settings, + Application, + System, + Utility, + FileTools, + Filesystem, + FileManager, + Graphics, + Office, + Game, + VR, // best score (of course!) +} + +fn get_category_name_score(name: &str) -> u8 { + if name.starts_with("X-") { + return Scores::XFooBar as u8; + } + + match name { + "" => { + return Scores::Empty as u8; + } + "VR" => { + return Scores::VR as u8; + } + "Game" => { + return Scores::Game as u8; + } + "FileManager" => { + return Scores::FileManager as u8; + } + "Utility" => { + return Scores::Utility as u8; + } + "FileTools" => { + return Scores::FileTools as u8; + } + "Filesystem" => { + return Scores::Filesystem as u8; + } + "System" => { + return Scores::System as u8; + } + "Office" => { + return Scores::Office as u8; + } + "Settings" => { + return Scores::Settings as u8; + } + "Application" => { + return Scores::Application as u8; + } + "GTK" => { + return Scores::Gtk as u8; + } + "Qt" => { + return Scores::Qt as u8; + } + "XFCE" => { + return Scores::Xfce as u8; + } + "GNOME" => { + return Scores::Gnome as u8; + } + "KDE" => { + return Scores::Kde as u8; + } + "Graphics" => { + return Scores::Graphics as u8; + } + _ => {} + } + + Scores::Unknown as u8 +} + +fn get_best_category_name(categories: &[Rc]) -> Option<&Rc> { + let mut best_score: u8 = 0; + let mut best_category: Option<&Rc> = None; + + for cat in categories { + let score = get_category_name_score(cat); + if score > best_score { + best_category = Some(cat); + best_score = score; + } + } + + best_category +} + +fn get_category_name(entry: &DesktopEntry) -> &str { + //log::info!("{:?}", entry.categories); + + match get_best_category_name(&entry.categories) { + Some(cat) => cat, + None => "Other", + } +} + impl AppList { fn mount_entry( &mut self, @@ -166,12 +280,11 @@ impl AppList { doc_params: &ParseDocumentParams, entry: &DesktopEntry, ) -> anyhow::Result> { - if let Some(ch) = entry.app_name.chars().next() - && self.prev_first_letter != ch - { - self.prev_first_letter = ch; + let category_name = get_category_name(entry); + if category_name != self.prev_category_name { + self.prev_category_name = String::from(category_name); let mut params = HashMap::, Rc>::new(); - params.insert("text".into(), format!("{}", ch).into()); + params.insert("text".into(), category_name.into()); parser_state.parse_template( doc_params, diff --git a/wlx-common/src/desktop_finder.rs b/wlx-common/src/desktop_finder.rs index aaa9991..2f71b7b 100644 --- a/wlx-common/src/desktop_finder.rs +++ b/wlx-common/src/desktop_finder.rs @@ -20,6 +20,7 @@ struct DesktopEntryOwned { exec_args: String, app_name: String, icon_path: Option, + categories: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -28,6 +29,7 @@ pub struct DesktopEntry { pub exec_args: Rc, pub app_name: Rc, pub icon_path: Option>, + pub categories: Vec>, } impl From for DesktopEntry { @@ -37,6 +39,7 @@ impl From for DesktopEntry { exec_args: value.exec_args.into(), app_name: value.app_name.into(), icon_path: value.icon_path.map(|x| x.into()), + categories: value.categories.into_iter().map(|x| x.into()).collect(), } } } @@ -220,14 +223,17 @@ impl DesktopFinder { let icon_path = section .get("Icon") - .and_then(|icon_name| Self::find_icon(¶ms, &icon_name)) + .and_then(|icon_name| Self::find_icon(¶ms, icon_name)) .or_else(|| Self::create_icon(&file_name).ok()); + let mut vec_categories = Vec::::new(); + if let Some(categories) = section.get("Categories") { for cat in categories.split(";") { if CATEGORY_TYPE_BLOCKLIST.contains(&cat) { continue 'entries; } + vec_categories.push(String::from(cat)); } } @@ -240,6 +246,7 @@ impl DesktopFinder { exec_path: String::from(exec_path), exec_args: exec_args.join(" "), icon_path, + categories: vec_categories, }, ); }