Rewrite update dialog text to plain language for WCAG readability
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
use adw::prelude::*;
|
||||
use gtk::gio;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use crate::config::APP_ID;
|
||||
use crate::core::database::{AppImageRecord, Database};
|
||||
use crate::core::updater;
|
||||
|
||||
@@ -43,7 +45,6 @@ pub fn show_update_dialog(
|
||||
match result {
|
||||
Ok((type_label, raw_info, Some(check_result))) => {
|
||||
// Store update info in DB
|
||||
let now = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string();
|
||||
db_ref
|
||||
.update_update_info(
|
||||
record_id,
|
||||
@@ -57,14 +58,48 @@ pub fn show_update_dialog(
|
||||
db_ref.set_update_available(record_id, Some(version), check_result.download_url.as_deref()).ok();
|
||||
}
|
||||
|
||||
let body = format!(
|
||||
"{} -> {}\n\nA new version is available.",
|
||||
let mut body = format!(
|
||||
"{} -> {}",
|
||||
record_clone.app_version.as_deref().unwrap_or("unknown"),
|
||||
check_result.latest_version.as_deref().unwrap_or("unknown"),
|
||||
);
|
||||
if let Some(size) = check_result.file_size {
|
||||
body.push_str(&format!(" ({})", humansize::format_size(size, humansize::BINARY)));
|
||||
}
|
||||
body.push_str("\n\nA new version is available.");
|
||||
if let Some(ref notes) = check_result.release_notes {
|
||||
if !notes.is_empty() {
|
||||
// Truncate long release notes for the dialog
|
||||
let truncated: String = notes.chars().take(300).collect();
|
||||
let suffix = if truncated.len() < notes.len() { "..." } else { "" };
|
||||
body.push_str(&format!("\n\n{}{}", truncated, suffix));
|
||||
}
|
||||
}
|
||||
dialog_ref.set_heading(Some("Update Available"));
|
||||
dialog_ref.set_body(&body);
|
||||
// Future: add "Update" response to trigger download
|
||||
|
||||
// Add "Update Now" button if we have a download URL
|
||||
if let Some(download_url) = check_result.download_url {
|
||||
dialog_ref.add_response("update", "Update Now");
|
||||
dialog_ref.set_response_appearance("update", adw::ResponseAppearance::Suggested);
|
||||
dialog_ref.set_default_response(Some("update"));
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
dialog_ref.set_heading(Some("Up to Date"));
|
||||
dialog_ref.set_body(&format!(
|
||||
@@ -83,8 +118,8 @@ pub fn show_update_dialog(
|
||||
} else {
|
||||
dialog_ref.set_heading(Some("No Update Info"));
|
||||
dialog_ref.set_body(
|
||||
"This AppImage does not contain update information. \
|
||||
Updates must be downloaded manually.",
|
||||
"This app does not support automatic updates. \
|
||||
Check the developer's website for newer versions.",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -98,6 +133,114 @@ pub fn show_update_dialog(
|
||||
dialog.present(Some(parent));
|
||||
}
|
||||
|
||||
/// Start the actual update download + apply process.
|
||||
fn start_update(
|
||||
dialog: &adw::AlertDialog,
|
||||
appimage_path: &str,
|
||||
download_url: &str,
|
||||
record_id: i64,
|
||||
new_version: Option<&str>,
|
||||
db: &Rc<Database>,
|
||||
) {
|
||||
dialog.set_heading(Some("Updating..."));
|
||||
dialog.set_body("Downloading update. This may take a moment.");
|
||||
dialog.set_response_enabled("update", false);
|
||||
|
||||
let path = appimage_path.to_string();
|
||||
let url = download_url.to_string();
|
||||
let version = new_version.map(|s| s.to_string());
|
||||
let db_ref = db.clone();
|
||||
let dialog_weak = dialog.downgrade();
|
||||
|
||||
glib::spawn_future_local(async move {
|
||||
let result = gio::spawn_blocking(move || {
|
||||
let p = std::path::Path::new(&path);
|
||||
// Always keep old version initially - cleanup decision happens after
|
||||
updater::perform_update(p, Some(&url), true, None)
|
||||
})
|
||||
.await;
|
||||
|
||||
let Some(dialog) = dialog_weak.upgrade() else { return };
|
||||
|
||||
match result {
|
||||
Ok(Ok(applied)) => {
|
||||
// Record the update in history using the actual new version
|
||||
let actual_version = applied.new_version.as_deref().or(version.as_deref());
|
||||
if let Some(ver) = actual_version {
|
||||
db_ref.record_update(record_id, None, Some(ver), Some("download"), None, true).ok();
|
||||
}
|
||||
db_ref.clear_update_available(record_id).ok();
|
||||
|
||||
let success_body = format!(
|
||||
"Updated to {}\nPath: {}",
|
||||
applied.new_version.as_deref().unwrap_or("latest"),
|
||||
applied.new_path.display(),
|
||||
);
|
||||
dialog.set_heading(Some("Update Complete"));
|
||||
dialog.set_body(&success_body);
|
||||
dialog.set_response_enabled("update", false);
|
||||
|
||||
// Handle old version cleanup
|
||||
if let Some(old_path) = applied.old_path_backup {
|
||||
handle_old_version_cleanup(&dialog, old_path);
|
||||
}
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
dialog.set_heading(Some("Update Failed"));
|
||||
dialog.set_body(&format!("The update could not be applied: {}", e));
|
||||
}
|
||||
Err(_) => {
|
||||
dialog.set_heading(Some("Update Failed"));
|
||||
dialog.set_body("An unexpected error occurred during the update.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// After a successful update, handle cleanup of the old version based on user preference.
|
||||
fn handle_old_version_cleanup(dialog: &adw::AlertDialog, old_path: PathBuf) {
|
||||
let settings = gio::Settings::new(APP_ID);
|
||||
let policy = settings.string("update-cleanup");
|
||||
|
||||
match policy.as_str() {
|
||||
"always" => {
|
||||
// Auto-remove without asking
|
||||
if old_path.exists() {
|
||||
if let Err(e) = std::fs::remove_file(&old_path) {
|
||||
log::warn!("Failed to remove old version {}: {}", old_path.display(), e);
|
||||
} else {
|
||||
log::info!("Auto-removed old version: {}", old_path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
"never" => {
|
||||
// Keep the backup, just inform
|
||||
dialog.set_body(&format!(
|
||||
"Update complete. The old version is saved at:\n{}",
|
||||
old_path.display()
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// "ask" - prompt the user
|
||||
dialog.set_body(&format!(
|
||||
"Update complete.\n\nRemove the old version?\n{}",
|
||||
old_path.display()
|
||||
));
|
||||
dialog.add_response("remove-old", "Remove Old Version");
|
||||
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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Batch check all AppImages for updates. Returns count of updates found.
|
||||
pub fn batch_check_updates(db: &Database) -> u32 {
|
||||
let records = match db.get_all_appimages() {
|
||||
|
||||
Reference in New Issue
Block a user