feat(updater): show in-app progress during app update

Replace native update dialogs with an in-app modal that shows a live
download progress bar and installing state, so updates no longer feel
abrupt. Drives the plugin's downloadAndInstall progress events through a
zustand store.
This commit is contained in:
pj committed 2026-07-15 09:31:57 +05:30
1 parent 7ea33b5bfb
commit 866a971729
5 files changed
+254 -16

No files matched your search

+43 -16
View File
@@ -1,31 +1,58 @@
import { check } from "@tauri-apps/plugin-updater";
import { relaunch } from "@tauri-apps/plugin-process";
import { ask, message } from "@tauri-apps/plugin-dialog";
import { useUpdater } from "./store/useUpdater";
let running = false;
let checking = false;
export async function checkForUpdates(silent: boolean) {
if (running) return;
running = true;
if (checking) return;
checking = true;
const store = useUpdater.getState();
if (!silent) store.set({ phase: "checking", error: "" });
try {
const update = await check();
if (!update) {
if (!silent) await message("margin is up to date.", { title: "Check for Updates" });
store.set(silent ? { phase: "idle" } : { phase: "uptodate" });
return;
}
const notes = update.body ? `\n\n${update.body}` : "";
const install = await ask(`margin ${update.version} is available.${notes}\n\nInstall now and restart?`, {
title: "Update Available",
kind: "info",
store.set({
phase: "available",
update,
version: update.version,
notes: update.body ?? "",
downloaded: 0,
total: 0,
error: "",
});
if (!install) return;
await update.downloadAndInstall();
await relaunch();
} catch (err) {
if (!silent) {
await message(`Could not check for updates.\n\n${err}`, { title: "Update Failed", kind: "error" });
}
store.set(silent ? { phase: "idle" } : { phase: "error", error: String(err) });
} finally {
running = false;
checking = false;
}
}
export async function installUpdate() {
const { update, phase } = useUpdater.getState();
if (!update || phase === "downloading" || phase === "installing") return;
try {
useUpdater.getState().set({ phase: "downloading", downloaded: 0, total: 0 });
await update.downloadAndInstall((event) => {
const s = useUpdater.getState();
if (event.event === "Started") {
s.set({ total: event.data.contentLength ?? 0, downloaded: 0 });
} else if (event.event === "Progress") {
s.set({ downloaded: s.downloaded + event.data.chunkLength });
} else if (event.event === "Finished") {
s.set({ phase: "installing" });
}
});
useUpdater.getState().set({ phase: "installing" });
await relaunch();
} catch (err) {
useUpdater.getState().set({ phase: "error", error: String(err) });
}
}
export function dismissUpdate() {
useUpdater.getState().reset();
}