Fix second audit findings and restore crash detection dialog
Address 29 issues found in comprehensive API/spec audit: - Fix .desktop Exec key path escaping per Desktop Entry spec - Fix update dialog double-dispatch with connect_response - Fix version comparison total ordering with lexicographic fallback - Use RETURNING id for reliable upsert in database - Replace tilde-based path fallbacks with proper XDG helpers - Fix backup create/restore path asymmetry for non-home paths - HTML-escape severity class in security reports - Use AppStream <custom> element instead of <metadata> - Fix has_appimage_update_tool to check .is_ok() not .success() - Use ListBoxRow instead of ActionRow::set_child in ExpanderRow - Add ELF magic validation to architecture detection - Add timeout to extract_update_info_runtime - Skip symlinks in dir_size calculation - Use Condvar instead of busy-wait in analysis thread pool - Restore crash detection to single blocking call architecture
This commit is contained in:
@@ -24,7 +24,7 @@ pub fn build_detail_page(record: &AppImageRecord, db: &Rc<Database>) -> adw::Nav
|
||||
// Toast overlay for copy actions
|
||||
let toast_overlay = adw::ToastOverlay::new();
|
||||
|
||||
// ViewStack for tabbed content with crossfade transitions.
|
||||
// ViewStack for tabbed content (transitions disabled for instant switching).
|
||||
// vhomogeneous=false so the stack sizes to the visible child only,
|
||||
// preventing shorter tabs from having excess scrollable empty space.
|
||||
let view_stack = adw::ViewStack::new();
|
||||
@@ -124,10 +124,10 @@ pub fn build_detail_page(record: &AppImageRecord, db: &Rc<Database>) -> adw::Nav
|
||||
|
||||
btn_ref.set_sensitive(true);
|
||||
match result {
|
||||
Ok(launcher::LaunchResult::Started { child, method }) => {
|
||||
let pid = child.id();
|
||||
Ok(launcher::LaunchResult::Started { pid, method }) => {
|
||||
log::info!("Launched: {} (PID: {}, method: {})", path, pid, method.as_str());
|
||||
|
||||
// App survived startup - do Wayland analysis after a delay
|
||||
let db_wayland = db_launch.clone();
|
||||
let path_clone = path.clone();
|
||||
glib::spawn_future_local(async move {
|
||||
@@ -488,12 +488,7 @@ fn build_overview_tab(record: &AppImageRecord, db: &Rc<Database>) -> gtk::Box {
|
||||
spinner_ref.set_visible(false);
|
||||
if let Ok(Some(data)) = result {
|
||||
let gbytes = glib::Bytes::from(&data);
|
||||
let stream = gio::MemoryInputStream::from_bytes(&gbytes);
|
||||
if let Ok(pixbuf) = gtk::gdk_pixbuf::Pixbuf::from_stream(
|
||||
&stream,
|
||||
None::<&gio::Cancellable>,
|
||||
) {
|
||||
let texture = gtk::gdk::Texture::for_pixbuf(&pixbuf);
|
||||
if let Ok(texture) = gtk::gdk::Texture::from_bytes(&gbytes) {
|
||||
picture_ref.set_paintable(Some(&texture));
|
||||
if let Some(slot) = textures_load.borrow_mut().get_mut(idx) {
|
||||
*slot = Some(texture);
|
||||
@@ -708,8 +703,11 @@ fn build_overview_tab(record: &AppImageRecord, db: &Rc<Database>) -> gtk::Box {
|
||||
.margin_start(12)
|
||||
.margin_end(12)
|
||||
.build();
|
||||
let label_row = adw::ActionRow::new();
|
||||
label_row.set_child(Some(&label));
|
||||
let label_row = gtk::ListBoxRow::builder()
|
||||
.activatable(false)
|
||||
.selectable(false)
|
||||
.child(&label)
|
||||
.build();
|
||||
row.add_row(&label_row);
|
||||
|
||||
release_group.add(&row);
|
||||
@@ -2080,12 +2078,7 @@ fn fetch_favicon_async(url: &str, image: >k::Image) {
|
||||
|
||||
if let Ok(Some(data)) = result {
|
||||
let gbytes = glib::Bytes::from(&data);
|
||||
let stream = gio::MemoryInputStream::from_bytes(&gbytes);
|
||||
if let Ok(pixbuf) = gtk::gdk_pixbuf::Pixbuf::from_stream(
|
||||
&stream,
|
||||
None::<&gio::Cancellable>,
|
||||
) {
|
||||
let texture = gtk::gdk::Texture::for_pixbuf(&pixbuf);
|
||||
if let Ok(texture) = gtk::gdk::Texture::from_bytes(&gbytes) {
|
||||
image_ref.set_paintable(Some(&texture));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,17 +90,15 @@ pub fn show_update_dialog(
|
||||
let db_update = db_ref.clone();
|
||||
let record_path = record_clone.path.clone();
|
||||
let new_version = check_result.latest_version.clone();
|
||||
dialog_ref.connect_response(None, move |dlg, response| {
|
||||
if response == "update" {
|
||||
start_update(
|
||||
dlg,
|
||||
&record_path,
|
||||
&download_url,
|
||||
record_id,
|
||||
new_version.as_deref(),
|
||||
&db_update,
|
||||
);
|
||||
}
|
||||
dialog_ref.connect_response(Some("update"), move |dlg, _response| {
|
||||
start_update(
|
||||
dlg,
|
||||
&record_path,
|
||||
&download_url,
|
||||
record_id,
|
||||
new_version.as_deref(),
|
||||
&db_update,
|
||||
);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -239,11 +237,9 @@ fn handle_old_version_cleanup(dialog: &adw::AlertDialog, old_path: PathBuf) {
|
||||
dialog.set_response_appearance("remove-old", adw::ResponseAppearance::Destructive);
|
||||
|
||||
let path = old_path.clone();
|
||||
dialog.connect_response(None, move |_dlg, response| {
|
||||
if response == "remove-old" {
|
||||
if path.exists() {
|
||||
std::fs::remove_file(&path).ok();
|
||||
}
|
||||
dialog.connect_response(Some("remove-old"), move |_dlg, _response| {
|
||||
if path.exists() {
|
||||
std::fs::remove_file(&path).ok();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,12 +182,10 @@ pub fn copy_button(text_to_copy: &str, toast_overlay: Option<&adw::ToastOverlay>
|
||||
let text = text_to_copy.to_string();
|
||||
let toast = toast_overlay.cloned();
|
||||
btn.connect_clicked(move |button| {
|
||||
if let Some(display) = button.display().into() {
|
||||
let clipboard = gtk::gdk::Display::clipboard(&display);
|
||||
clipboard.set_text(&text);
|
||||
if let Some(ref overlay) = toast {
|
||||
overlay.add_toast(adw::Toast::new("Copied to clipboard"));
|
||||
}
|
||||
let clipboard = button.display().clipboard();
|
||||
clipboard.set_text(&text);
|
||||
if let Some(ref overlay) = toast {
|
||||
overlay.add_toast(adw::Toast::new("Copied to clipboard"));
|
||||
}
|
||||
});
|
||||
btn
|
||||
|
||||
Reference in New Issue
Block a user