Add GitHub metadata enrichment for catalog apps
Enrich catalog apps with GitHub API data (stars, version, downloads, release date) via two strategies: background drip for repo-level info and on-demand fetch when opening a detail page. - Add github_enrichment module with API calls, asset filtering, and architecture auto-detection for AppImage downloads - DB migrations v14/v15 for GitHub metadata and release asset columns - Extract github_owner/repo from feed links during catalog sync - Display colored stat cards (stars, version, downloads, released) on detail pages with on-demand enrichment - Show stars and version on browse tiles and featured carousel cards - Replace install button with SplitButton dropdown when multiple arch assets available, preferring detected architecture - Disable install button until enrichment completes to prevent stale AppImageHub URL downloads - Keep enrichment banner visible on catalog page until truly complete, showing paused state when rate-limited - Add GitHub token and auto-enrich toggle to preferences
This commit is contained in:
@@ -589,13 +589,13 @@ impl LibraryView {
|
||||
// Grid card
|
||||
let card = app_card::build_app_card(record);
|
||||
let card_menu = build_context_menu(record);
|
||||
attach_context_menu(&card, &card_menu);
|
||||
attach_context_menu(&card, &card_menu, record.id);
|
||||
self.flow_box.append(&card);
|
||||
|
||||
// List row
|
||||
let row = self.build_list_row(record);
|
||||
let row_menu = build_context_menu(record);
|
||||
attach_context_menu(&row, &row_menu);
|
||||
attach_context_menu(&row, &row_menu, record.id);
|
||||
self.list_box.append(&row);
|
||||
}
|
||||
|
||||
@@ -812,15 +812,39 @@ fn build_context_menu(record: &AppImageRecord) -> gtk::gio::Menu {
|
||||
section4.append(Some("Copy file location"), Some(&format!("win.copy-path(int64 {})", record.id)));
|
||||
menu.append_section(None, §ion4);
|
||||
|
||||
// Section 5: Destructive actions
|
||||
let section5 = gtk::gio::Menu::new();
|
||||
let uninstall_item = gtk::gio::MenuItem::new(None, Some(&format!("win.uninstall-appimage(int64 {})", record.id)));
|
||||
uninstall_item.set_attribute_value("custom", Some(&"uninstall".to_variant()));
|
||||
section5.append_item(&uninstall_item);
|
||||
menu.append_section(None, §ion5);
|
||||
|
||||
menu
|
||||
}
|
||||
|
||||
/// Attach a right-click context menu to a widget.
|
||||
fn attach_context_menu(widget: &impl gtk::prelude::IsA<gtk::Widget>, menu_model: >k::gio::Menu) {
|
||||
let popover = gtk::PopoverMenu::from_model(Some(menu_model));
|
||||
fn attach_context_menu(widget: &impl gtk::prelude::IsA<gtk::Widget>, menu_model: >k::gio::Menu, record_id: i64) {
|
||||
let popover = gtk::PopoverMenu::from_model_full(menu_model, gtk::PopoverMenuFlags::NESTED);
|
||||
popover.set_parent(widget.as_ref());
|
||||
popover.set_has_arrow(false);
|
||||
|
||||
// Add custom destructive-styled uninstall button
|
||||
let uninstall_btn = gtk::Button::builder()
|
||||
.label("Uninstall")
|
||||
.build();
|
||||
uninstall_btn.add_css_class("destructive-context-item");
|
||||
// Left-align the label to match other menu items
|
||||
if let Some(label) = uninstall_btn.child().and_then(|c| c.downcast::<gtk::Label>().ok()) {
|
||||
label.set_halign(gtk::Align::Start);
|
||||
}
|
||||
uninstall_btn.set_action_name(Some("win.uninstall-appimage"));
|
||||
uninstall_btn.set_action_target_value(Some(&record_id.to_variant()));
|
||||
let popover_ref = popover.clone();
|
||||
uninstall_btn.connect_clicked(move |_| {
|
||||
popover_ref.popdown();
|
||||
});
|
||||
popover.add_child(&uninstall_btn, "uninstall");
|
||||
|
||||
// Unparent the popover when the widget is destroyed to avoid GTK warnings
|
||||
let popover_cleanup = popover.clone();
|
||||
widget.as_ref().connect_destroy(move |_| {
|
||||
|
||||
Reference in New Issue
Block a user