From 3fd2d56999fa00a7b90f159cb686a5fc64347e7e Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 14 Oct 2026 23:40:31 -0400 Subject: [PATCH] fix(update): a Flatpak-installed launcher gets the bundle download link, not the AppImage (#370) Co-Authored-From: dylan Co-Stream: claude@craft-pilot.com --- crates/native/src/backend.rs | 9 ------ crates/ui-egui/src/dialogs.rs | 5 +++- crates/ui-egui/src/views.rs | 53 +++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/crates/native/src/backend.rs b/crates/native/src/backend.rs index 04d78f52..6b6f12de 100644 --- a/crates/native/src/backend.rs +++ b/crates/native/src/backend.rs @@ -981,15 +981,6 @@ impl Backend for NativeBackend { } } -/// The launcher's own download for this machine, for "a new launcher is available". -pub fn launcher_download(release: &Release, platform: Platform) -> Option { - let kinds: &[artcraft_launcher_core::PackageKind] = match platform.os { - Os::Linux => &[artcraft_launcher_core::PackageKind::AppImage, artcraft_launcher_core::PackageKind::Deb], - _ => platform.default_kinds(), - }; - pick_asset(release, &[LAUNCHER_ID], platform, kinds).map(|(a, _)| a.url.clone()) -} - #[cfg(test)] mod tests { use std::sync::atomic::AtomicUsize; diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 9c7f05ed..2be37d84 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -128,7 +128,10 @@ impl LauncherUi { close = true; } } else { - let url = self.platform.and_then(|p| crate::views::launcher_download(r, p)).unwrap_or_else(|| r.html_url.clone()); + let url = self + .platform + .and_then(|p| crate::views::launcher_download(r, p, crate::settings::is_flatpak_sandbox())) + .unwrap_or_else(|| r.html_url.clone()); if widgets::button(ui, tl!("Download"), Kind::Primary, 0.0).clicked() { ui.ctx().open_url(egui::OpenUrl::new_tab(url)); close = true; diff --git a/crates/ui-egui/src/views.rs b/crates/ui-egui/src/views.rs index 522f6646..a80aae14 100644 --- a/crates/ui-egui/src/views.rs +++ b/crates/ui-egui/src/views.rs @@ -184,7 +184,10 @@ impl LauncherUi { self.send(Command::UpdateLauncher); } } else { - let url = self.platform.and_then(|p| launcher_download(&r, p)).unwrap_or_else(|| r.html_url.clone()); + let url = self + .platform + .and_then(|p| launcher_download(&r, p, crate::settings::is_flatpak_sandbox())) + .unwrap_or_else(|| r.html_url.clone()); if widgets::button(ui, tl!("Download"), Kind::Primary, 0.0).clicked() { ui.ctx().open_url(egui::OpenUrl::new_tab(url)); } @@ -925,10 +928,13 @@ pub(crate) fn version_line(e: &AppEntry, status: &AppStatus) -> String { } } -/// The launcher's own download for this platform. -pub(crate) fn launcher_download(r: &artcraft_launcher_core::Release, p: artcraft_launcher_core::Platform) -> Option { +/// The launcher's own download for this platform. `flatpak` is whether this copy runs as a +/// Flatpak; such a copy's download stays the `.flatpak` bundle — offering it an AppImage (or a +/// `.deb`) would point at replacing the sandboxed install with a different one. +pub(crate) fn launcher_download(r: &artcraft_launcher_core::Release, p: artcraft_launcher_core::Platform, flatpak: bool) -> Option { use artcraft_launcher_core::PackageKind; let kinds: &[PackageKind] = match p.os { + artcraft_launcher_core::Os::Linux if flatpak => &[PackageKind::Flatpak], artcraft_launcher_core::Os::Linux => &[PackageKind::AppImage, PackageKind::Deb], _ => p.default_kinds(), }; @@ -951,3 +957,44 @@ fn lines_height(ui: &Ui, fonts: &[&FontId], gap: f32) -> f32 { let line = |font: &FontId| ui.fonts_mut(|f| f.layout_no_wrap(String::new(), font.clone(), Color32::PLACEHOLDER)).size().y; (fonts.iter().map(|font| line(font) + gap).sum::() - gap).max(0.0) } + +#[cfg(test)] +mod tests { + use super::*; + use artcraft_launcher_core::catalog::LAUNCHER_ID; + use artcraft_launcher_core::{Arch, Asset, Platform, Release}; + + fn release() -> Release { + let asset = |name: &str| Asset { name: name.into(), size: 0, url: format!("https://dl.example/{name}"), sha256: None }; + Release { + tag: "v0.4.1".into(), + version: None, + name: "ArtCraft Launcher v0.4.1".into(), + published_at: None, + html_url: "https://github.com/storytold/craft-launcher/releases/tag/v0.4.1".into(), + notes: String::new(), + prerelease: false, + assets: vec![ + asset(&format!("{LAUNCHER_ID}-0.4.1-linux-x86_64.flatpak")), + asset(&format!("{LAUNCHER_ID}-0.4.1-linux-x86_64.AppImage")), + asset(&format!("{LAUNCHER_ID}-0.4.1-linux-x86_64.deb")), + ], + } + } + + fn platform() -> Platform { + Platform { os: artcraft_launcher_core::Os::Linux, arch: Arch::X64 } + } + + #[test] + fn a_flatpak_copy_of_the_launcher_gets_the_bundle() { + let url = launcher_download(&release(), platform(), true).unwrap(); + assert_eq!(url, format!("https://dl.example/{LAUNCHER_ID}-0.4.1-linux-x86_64.flatpak")); + } + + #[test] + fn a_plain_linux_copy_still_gets_the_appimage() { + let url = launcher_download(&release(), platform(), false).unwrap(); + assert_eq!(url, format!("https://dl.example/{LAUNCHER_ID}-0.4.1-linux-x86_64.AppImage")); + } +}