app categories

This commit is contained in:
Aleksander
2026-01-06 20:17:34 +01:00
parent 3addd6eaa0
commit 33ad05ee39
2 changed files with 129 additions and 9 deletions

View File

@@ -70,7 +70,7 @@ struct AppList {
//data: Vec<ParserData>, //data: Vec<ParserData>,
entries_to_mount: VecDeque<DesktopEntry>, entries_to_mount: VecDeque<DesktopEntry>,
list_parent: WidgetPair, list_parent: WidgetPair,
prev_first_letter: char, prev_category_name: String,
} }
// called after the user clicks any desktop entry // called after the user clicks any desktop entry
@@ -140,12 +140,17 @@ impl<T> TabApps<T> {
.find_entries() .find_entries()
.into_values() .into_values()
.collect(); .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 { let app_list = AppList {
entries_to_mount: entries_sorted.drain(..).collect(), entries_to_mount: entries_sorted.drain(..).collect(),
list_parent: app_list_parent, list_parent: app_list_parent,
prev_first_letter: ' ', prev_category_name: String::new(),
}; };
Ok(Self { Ok(Self {
@@ -158,6 +163,115 @@ impl<T> TabApps<T> {
} }
} }
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<str>]) -> Option<&Rc<str>> {
let mut best_score: u8 = 0;
let mut best_category: Option<&Rc<str>> = 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 { impl AppList {
fn mount_entry<T>( fn mount_entry<T>(
&mut self, &mut self,
@@ -166,12 +280,11 @@ impl AppList {
doc_params: &ParseDocumentParams, doc_params: &ParseDocumentParams,
entry: &DesktopEntry, entry: &DesktopEntry,
) -> anyhow::Result<Rc<ComponentButton>> { ) -> anyhow::Result<Rc<ComponentButton>> {
if let Some(ch) = entry.app_name.chars().next() let category_name = get_category_name(entry);
&& self.prev_first_letter != ch if category_name != self.prev_category_name {
{ self.prev_category_name = String::from(category_name);
self.prev_first_letter = ch;
let mut params = HashMap::<Rc<str>, Rc<str>>::new(); let mut params = HashMap::<Rc<str>, Rc<str>>::new();
params.insert("text".into(), format!("{}", ch).into()); params.insert("text".into(), category_name.into());
parser_state.parse_template( parser_state.parse_template(
doc_params, doc_params,

View File

@@ -20,6 +20,7 @@ struct DesktopEntryOwned {
exec_args: String, exec_args: String,
app_name: String, app_name: String,
icon_path: Option<String>, icon_path: Option<String>,
categories: Vec<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -28,6 +29,7 @@ pub struct DesktopEntry {
pub exec_args: Rc<str>, pub exec_args: Rc<str>,
pub app_name: Rc<str>, pub app_name: Rc<str>,
pub icon_path: Option<Rc<str>>, pub icon_path: Option<Rc<str>>,
pub categories: Vec<Rc<str>>,
} }
impl From<DesktopEntryOwned> for DesktopEntry { impl From<DesktopEntryOwned> for DesktopEntry {
@@ -37,6 +39,7 @@ impl From<DesktopEntryOwned> for DesktopEntry {
exec_args: value.exec_args.into(), exec_args: value.exec_args.into(),
app_name: value.app_name.into(), app_name: value.app_name.into(),
icon_path: value.icon_path.map(|x| x.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 let icon_path = section
.get("Icon") .get("Icon")
.and_then(|icon_name| Self::find_icon(&params, &icon_name)) .and_then(|icon_name| Self::find_icon(&params, icon_name))
.or_else(|| Self::create_icon(&file_name).ok()); .or_else(|| Self::create_icon(&file_name).ok());
let mut vec_categories = Vec::<String>::new();
if let Some(categories) = section.get("Categories") { if let Some(categories) = section.get("Categories") {
for cat in categories.split(";") { for cat in categories.split(";") {
if CATEGORY_TYPE_BLOCKLIST.contains(&cat) { if CATEGORY_TYPE_BLOCKLIST.contains(&cat) {
continue 'entries; continue 'entries;
} }
vec_categories.push(String::from(cat));
} }
} }
@@ -240,6 +246,7 @@ impl DesktopFinder {
exec_path: String::from(exec_path), exec_path: String::from(exec_path),
exec_args: exec_args.join(" "), exec_args: exec_args.join(" "),
icon_path, icon_path,
categories: vec_categories,
}, },
); );
} }