Add UX enhancements: carousel, filter chips, command palette, and more
This commit is contained in:
@@ -6,6 +6,7 @@ use gtk::gio;
|
||||
|
||||
use crate::core::catalog;
|
||||
use crate::core::database::{CatalogApp, Database};
|
||||
use crate::core::fuse;
|
||||
use crate::core::github_enrichment;
|
||||
use crate::core::github_enrichment::AppImageAsset;
|
||||
use crate::i18n::i18n;
|
||||
@@ -100,14 +101,15 @@ pub fn build_catalog_detail_page(
|
||||
&& (app.latest_version.is_none() || is_enrichment_stale(app.github_enriched_at.as_deref()));
|
||||
let awaiting_github = needs_enrichment && app.github_download_url.is_none();
|
||||
|
||||
// Check if already installed
|
||||
let installed_names: std::collections::HashSet<String> = db
|
||||
// Check if already installed (map name -> record id for launching)
|
||||
let installed_map: std::collections::HashMap<String, i64> = db
|
||||
.get_all_appimages()
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.filter_map(|r| r.app_name.as_ref().map(|n| n.to_lowercase()))
|
||||
.filter_map(|r| r.app_name.as_ref().map(|n| (n.to_lowercase(), r.id)))
|
||||
.collect();
|
||||
let is_installed = installed_names.contains(&app.name.to_lowercase());
|
||||
let installed_record_id = installed_map.get(&app.name.to_lowercase()).copied();
|
||||
let is_installed = installed_record_id.is_some();
|
||||
|
||||
let install_slot = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
||||
|
||||
@@ -120,6 +122,17 @@ pub fn build_catalog_detail_page(
|
||||
let awaiting_ocs = has_ocs && !is_installed;
|
||||
|
||||
if is_installed {
|
||||
// Show Launch button for installed apps
|
||||
if let Some(record_id) = installed_record_id {
|
||||
let launch_btn = gtk::Button::builder()
|
||||
.label(&i18n("Launch"))
|
||||
.css_classes(["suggested-action", "pill"])
|
||||
.build();
|
||||
launch_btn.set_action_name(Some("win.launch-appimage"));
|
||||
launch_btn.set_action_target_value(Some(&record_id.to_variant()));
|
||||
widgets::set_pointer_cursor(&launch_btn);
|
||||
button_box.append(&launch_btn);
|
||||
}
|
||||
let installed_badge = widgets::status_badge(&i18n("Installed"), "success");
|
||||
installed_badge.set_valign(gtk::Align::Center);
|
||||
button_box.append(&installed_badge);
|
||||
@@ -166,6 +179,37 @@ pub fn build_catalog_detail_page(
|
||||
}
|
||||
|
||||
info_box.append(&button_box);
|
||||
|
||||
// "What you'll get" info and compatibility check for install
|
||||
if !is_installed {
|
||||
let size_hint = app.ocs_downloadsize.filter(|&s| s > 0)
|
||||
.map(|s| format!(" ({})", widgets::format_size(s)))
|
||||
.unwrap_or_default();
|
||||
let install_info = gtk::Label::builder()
|
||||
.label(&format!(
|
||||
"Downloads to ~/Applications and adds to your app launcher{}",
|
||||
size_hint
|
||||
))
|
||||
.css_classes(["caption", "dim-label"])
|
||||
.wrap(true)
|
||||
.xalign(0.0)
|
||||
.halign(gtk::Align::Start)
|
||||
.build();
|
||||
info_box.append(&install_info);
|
||||
|
||||
// System compatibility check
|
||||
let fuse_info = fuse::detect_system_fuse();
|
||||
let (compat_text, compat_class) = if fuse_info.status.is_functional() {
|
||||
("Works with your system", "success")
|
||||
} else {
|
||||
("May need additional setup to run", "warning")
|
||||
};
|
||||
let compat_badge = widgets::status_badge(compat_text, compat_class);
|
||||
compat_badge.set_halign(gtk::Align::Start);
|
||||
compat_badge.set_margin_top(2);
|
||||
info_box.append(&compat_badge);
|
||||
}
|
||||
|
||||
header_box.append(&info_box);
|
||||
content.append(&header_box);
|
||||
|
||||
@@ -1243,9 +1287,17 @@ fn format_ocs_file_label(file: &catalog::OcsDownloadFile) -> String {
|
||||
if !file.version.is_empty() {
|
||||
parts.push(format!("v{}", file.version));
|
||||
}
|
||||
if let Some(ref arch) = file.arch {
|
||||
parts.push(arch.clone());
|
||||
}
|
||||
if !file.filename.is_empty() {
|
||||
parts.push(file.filename.clone());
|
||||
}
|
||||
if let Some(ref pkg_type) = file.pkg_type {
|
||||
if pkg_type != "appimage" {
|
||||
parts.push(format!("[{}]", pkg_type));
|
||||
}
|
||||
}
|
||||
if let Some(size_kb) = file.size_kb {
|
||||
if size_kb > 0 {
|
||||
parts.push(format!("({})", widgets::format_size(size_kb * 1024)));
|
||||
|
||||
Reference in New Issue
Block a user