Files
driftwood/src/ui/permission_dialog.rs
lashman d11546efc6 Add UX enhancements: carousel, filter chips, command palette, and more
- Replace featured section Stack with AdwCarousel + indicator dots
- Convert category grid to horizontal scrollable filter chips
- Add grid/list view toggle for catalog with compact row layout
- Add quick launch button on library list rows
- Add stale catalog banner when data is older than 7 days
- Add command palette (Ctrl+K) for quick app search and launch
- Show specific app names in update notifications
- Add per-app auto-update toggle (skip updates switch)
- Add keyboard shortcut hints to button tooltips
- Add source trust badges (AppImageHub/Community) on catalog tiles
- Add undo-based uninstall with toast and record restoration
- Add type-to-search in library view
- Use human-readable catalog source labels
- Show Launch button for installed apps in catalog detail
- Replace external browser link with inline AppImage explainer dialog
2026-03-01 00:39:43 +02:00

98 lines
3.0 KiB
Rust

use adw::prelude::*;
use std::rc::Rc;
use crate::core::database::Database;
use crate::core::launcher;
use crate::i18n::i18n;
/// Show a first-run permission summary before launching an AppImage.
/// Returns a dialog that the caller should present. The `on_proceed` callback
/// is called if the user chooses to continue.
pub fn show_permission_dialog(
parent: &impl IsA<gtk::Widget>,
app_name: &str,
record_id: i64,
db: &Rc<Database>,
on_proceed: impl Fn() + 'static,
) {
let dialog = adw::AlertDialog::builder()
.heading(&format!("Launch {}?", app_name))
.body(&i18n(
"This AppImage will run with your full user permissions. \
It can access your files, network, and desktop.",
))
.build();
let extra = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.spacing(8)
.margin_top(12)
.build();
let access_label = gtk::Label::builder()
.label(&i18n("This app will have access to:"))
.xalign(0.0)
.build();
access_label.add_css_class("heading");
extra.append(&access_label);
let items = [
"Your files and folders",
"Internet and network access",
"Your screen and windows",
"Background system services",
];
for item in &items {
let label = gtk::Label::builder()
.label(&format!(" - {}", i18n(item)))
.xalign(0.0)
.build();
extra.append(&label);
}
// Explanation paragraph
let explain = gtk::Label::builder()
.label(&i18n(
"AppImages run like regular programs on your computer. Unlike phone apps, \
desktop apps typically have full access to your files and system. This is normal.",
))
.wrap(true)
.xalign(0.0)
.margin_top(8)
.build();
explain.add_css_class("caption");
explain.add_css_class("dim-label");
extra.append(&explain);
// Show firejail option if available
if launcher::has_firejail() {
let sandbox_note = gtk::Label::builder()
.label(&i18n(
"You can restrict this app's access later in Details > Security Restrictions.",
))
.wrap(true)
.xalign(0.0)
.margin_top(4)
.build();
sandbox_note.add_css_class("dim-label");
extra.append(&sandbox_note);
}
dialog.set_extra_child(Some(&extra));
dialog.add_response("cancel", &i18n("Cancel"));
dialog.add_response("proceed", &i18n("Launch"));
dialog.set_response_appearance("proceed", adw::ResponseAppearance::Suggested);
dialog.set_default_response(Some("proceed"));
dialog.set_close_response("cancel");
let db_ref = db.clone();
dialog.connect_response(Some("proceed"), move |_dlg, _response| {
// Mark as prompted so we don't show again
db_ref.set_first_run_prompted(record_id, true).ok();
on_proceed();
});
dialog.present(Some(parent));
}