Rewrite update dialog text to plain language for WCAG readability
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use gtk::gio;
|
use gtk::gio;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use crate::config::APP_ID;
|
||||||
use crate::core::database::{AppImageRecord, Database};
|
use crate::core::database::{AppImageRecord, Database};
|
||||||
use crate::core::updater;
|
use crate::core::updater;
|
||||||
|
|
||||||
@@ -43,7 +45,6 @@ pub fn show_update_dialog(
|
|||||||
match result {
|
match result {
|
||||||
Ok((type_label, raw_info, Some(check_result))) => {
|
Ok((type_label, raw_info, Some(check_result))) => {
|
||||||
// Store update info in DB
|
// Store update info in DB
|
||||||
let now = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string();
|
|
||||||
db_ref
|
db_ref
|
||||||
.update_update_info(
|
.update_update_info(
|
||||||
record_id,
|
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();
|
db_ref.set_update_available(record_id, Some(version), check_result.download_url.as_deref()).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = format!(
|
let mut body = format!(
|
||||||
"{} -> {}\n\nA new version is available.",
|
"{} -> {}",
|
||||||
record_clone.app_version.as_deref().unwrap_or("unknown"),
|
record_clone.app_version.as_deref().unwrap_or("unknown"),
|
||||||
check_result.latest_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_heading(Some("Update Available"));
|
||||||
dialog_ref.set_body(&body);
|
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 {
|
} else {
|
||||||
dialog_ref.set_heading(Some("Up to Date"));
|
dialog_ref.set_heading(Some("Up to Date"));
|
||||||
dialog_ref.set_body(&format!(
|
dialog_ref.set_body(&format!(
|
||||||
@@ -83,8 +118,8 @@ pub fn show_update_dialog(
|
|||||||
} else {
|
} else {
|
||||||
dialog_ref.set_heading(Some("No Update Info"));
|
dialog_ref.set_heading(Some("No Update Info"));
|
||||||
dialog_ref.set_body(
|
dialog_ref.set_body(
|
||||||
"This AppImage does not contain update information. \
|
"This app does not support automatic updates. \
|
||||||
Updates must be downloaded manually.",
|
Check the developer's website for newer versions.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,6 +133,114 @@ pub fn show_update_dialog(
|
|||||||
dialog.present(Some(parent));
|
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.
|
/// Batch check all AppImages for updates. Returns count of updates found.
|
||||||
pub fn batch_check_updates(db: &Database) -> u32 {
|
pub fn batch_check_updates(db: &Database) -> u32 {
|
||||||
let records = match db.get_all_appimages() {
|
let records = match db.get_all_appimages() {
|
||||||
|
|||||||
Reference in New Issue
Block a user