Tell people when a newer release is out (#1100)

At start, and at most once a day, a background thread asks GitHub for the latest stable
release (one HTTPS GET to releases/latest, nothing else sent; 15 s timeout; silent when
offline; GitHub's rate limit respected). When it is newer than this build, an Update button
appears next to Report a bug. It opens a window with the version, the release notes and
Download (the asset that fits this installation), Skip this version and Remind me later.

- Versions compare as semver; a nightly counts as the release it was built after, so it is
  offered only a newer stable release.
- The installation is detected (AppImage, Flatpak, Snap from the store or a file, deb, rpm,
  tar.gz, Windows MSI/portable/exe, macOS app); Download picks the fixed-name asset.
  Development builds and the Flatpak (no network permission) never check.
- Preferences > General > Updates: Check for updates automatically (on) and Check now.
- HTTP via ureq + rustls with the operating system's certificates (desktop app only).
- docs: Updates and privacy page.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-14 10:36:56 -04:00
1 parent 88432d226a
commit a6928abf48
21 files changed
+2969 -51

No files matched your search

+11
View File
@@ -245,6 +245,10 @@ pub struct Prefs {
pub offer_stand_up: bool,
/// What a middle-button double-click in the view does: `home`, `fit` or `off`.
pub middle_double_click: String,
/// Check for updates at start and once a day (docs/updates.md).
pub check_updates: bool,
/// When the last update check ran, and the versions skipped or put off (`update::Memo`).
pub update: crate::update::Memo,
}
/// What a middle-button double-click in the view does.
@@ -303,6 +307,8 @@ impl Default for Prefs {
up_axis: "z".into(),
offer_stand_up: true,
middle_double_click: "home".into(),
check_updates: true,
update: crate::update::Memo::default(),
}
}
}
@@ -359,7 +365,10 @@ impl Snapshot {
}
fn restore(self, app: &mut SolveApp) {
let msaa = app.preferences.msaa;
// Update bookkeeping isn't a setting: a check that finished while the dialog was open stays.
let update = std::mem::take(&mut app.preferences.update);
app.preferences = self.prefs;
app.preferences.update = update;
app.ui.dark = self.dark;
app.ui.show_grid = self.grid;
app.ui.ground_shadow = self.shadow;
@@ -392,6 +401,7 @@ fn defaults(app: &mut SolveApp, page: usize) {
p.default_units = d.default_units;
p.length_decimals = d.length_decimals;
p.angle_decimals = d.angle_decimals;
p.check_updates = d.check_updates;
app.ui.dark = true;
app.ui.agent_cursor = Default::default();
app.autosave_minutes = 5.0;
@@ -901,6 +911,7 @@ fn page(app: &mut SolveApp, ui: &mut egui::Ui, t: &Tokens) {
ui.label("");
ui.add_enabled(s.show, egui::Checkbox::new(&mut s.follow_camera, crate::i18n::tr_label("Follow the camera (Look At sketches)")));
ui.end_row();
crate::update::prefs_rows(app, ui, t);
}
1 => {
ui.label(app.tr_label("Pan, zoom, orbit"));