84 lines
2.5 KiB
Rust
84 lines
2.5 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 home directory and files",
|
|
"Network and internet access",
|
|
"Display server (Wayland/X11)",
|
|
"System D-Bus and services",
|
|
];
|
|
for item in &items {
|
|
let label = gtk::Label::builder()
|
|
.label(&format!(" - {}", i18n(item)))
|
|
.xalign(0.0)
|
|
.build();
|
|
extra.append(&label);
|
|
}
|
|
|
|
// Show firejail option if available
|
|
if launcher::has_firejail() {
|
|
let sandbox_note = gtk::Label::builder()
|
|
.label(&i18n(
|
|
"Firejail is available on your system. You can configure sandboxing in the app's system tab.",
|
|
))
|
|
.wrap(true)
|
|
.xalign(0.0)
|
|
.margin_top(8)
|
|
.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));
|
|
}
|