Skip to content
This repository was archived by the owner on Apr 28, 2026. It is now read-only.

Commit 161550b

Browse files
Add manual app update checks
Add a Check for Updates menu item to the macOS app menu and route manual checks through the existing updater flow with explicit no-update and error feedback.
1 parent 3062c0a commit 161550b

2 files changed

Lines changed: 57 additions & 4 deletions

File tree

src-tauri/src/lib.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use speech_models::{
3030
};
3131
use tauri::{
3232
menu::{AboutMetadata, Menu, MenuItem, PredefinedMenuItem, Submenu},
33-
Manager, RunEvent, State, WebviewUrl, WebviewWindowBuilder,
33+
Emitter, Manager, RunEvent, State, WebviewUrl, WebviewWindowBuilder,
3434
};
3535
use tracing::{error, info, warn};
3636

@@ -40,6 +40,8 @@ const SETTINGS_CONFIG_FILE: &str = "settings.json";
4040
const LEGACY_GENERAL_SETTINGS_FILE: &str = "general-settings.json";
4141
const LEGACY_MODEL_SETTINGS_FILE: &str = "model-settings.json";
4242
const LEGACY_DIARIZATION_SETTINGS_FILE: &str = "diarization-settings.json";
43+
const CHECK_FOR_UPDATES_MENU_ID: &str = "check-for-updates";
44+
const CHECK_FOR_UPDATES_EVENT: &str = "check-for-updates";
4345
const OPEN_SETTINGS_MENU_ID: &str = "open-settings";
4446
const SETTINGS_WINDOW_LABEL: &str = "settings";
4547
const CHAR_WEBSITE_URL: &str = "https://char.com";
@@ -1072,6 +1074,14 @@ fn build_app_menu<R: tauri::Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result
10721074
true,
10731075
Some("CmdOrCtrl+,"),
10741076
)?;
1077+
let check_for_updates_item =
1078+
MenuItem::with_id(
1079+
app,
1080+
CHECK_FOR_UPDATES_MENU_ID,
1081+
"Check for Updates...",
1082+
true,
1083+
None::<&str>,
1084+
)?;
10751085

10761086
let edit_menu = Submenu::with_items(
10771087
app,
@@ -1118,6 +1128,7 @@ fn build_app_menu<R: tauri::Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result
11181128
true,
11191129
&[
11201130
&PredefinedMenuItem::about(app, Some(&about_label), Some(about_metadata))?,
1131+
&check_for_updates_item,
11211132
&PredefinedMenuItem::separator(app)?,
11221133
&settings_item,
11231134
&PredefinedMenuItem::separator(app)?,
@@ -2480,6 +2491,8 @@ pub fn run() {
24802491
.on_menu_event(|app, event| {
24812492
if event.id() == OPEN_SETTINGS_MENU_ID {
24822493
let _ = show_settings_window(app, None);
2494+
} else if event.id() == CHECK_FOR_UPDATES_MENU_ID {
2495+
let _ = app.emit(CHECK_FOR_UPDATES_EVENT, ());
24832496
}
24842497
})
24852498
.invoke_handler(tauri::generate_handler![

src/updates.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import { listen } from "@tauri-apps/api/event";
12
import { check } from "@tauri-apps/plugin-updater";
23
import { relaunch } from "@tauri-apps/plugin-process";
34

5+
const CHECK_FOR_UPDATES_EVENT = "check-for-updates";
6+
47
let updaterStarted = false;
8+
let updateCheckInFlight = false;
59

610
function formatUpdateMessage(version: string, notes?: string | null) {
711
const normalizedNotes = notes?.trim();
@@ -13,17 +17,33 @@ function formatUpdateMessage(version: string, notes?: string | null) {
1317
return `unsigned {char} ${version} is available.\n\n${normalizedNotes}\n\nInstall it now?`;
1418
}
1519

16-
export async function startUpdater() {
17-
if (updaterStarted || import.meta.env.DEV || typeof window === "undefined") {
20+
async function runUpdateCheck(options: { userInitiated: boolean }) {
21+
if (import.meta.env.DEV || typeof window === "undefined") {
22+
if (options.userInitiated) {
23+
window.alert("Update checks are unavailable in development builds.");
24+
}
25+
1826
return;
1927
}
2028

21-
updaterStarted = true;
29+
if (updateCheckInFlight) {
30+
if (options.userInitiated) {
31+
window.alert("An update check is already in progress.");
32+
}
33+
34+
return;
35+
}
36+
37+
updateCheckInFlight = true;
2238

2339
try {
2440
const update = await check();
2541

2642
if (!update) {
43+
if (options.userInitiated) {
44+
window.alert("unsigned {char} is up to date.");
45+
}
46+
2747
return;
2848
}
2949

@@ -44,5 +64,25 @@ export async function startUpdater() {
4464
}
4565
} catch (error) {
4666
console.warn("Updater check failed", error);
67+
68+
if (options.userInitiated) {
69+
window.alert("Unable to check for updates right now.");
70+
}
71+
} finally {
72+
updateCheckInFlight = false;
4773
}
4874
}
75+
76+
export async function startUpdater() {
77+
if (updaterStarted || typeof window === "undefined") {
78+
return;
79+
}
80+
81+
updaterStarted = true;
82+
83+
await listen(CHECK_FOR_UPDATES_EVENT, () => {
84+
void runUpdateCheck({ userInitiated: true });
85+
});
86+
87+
void runUpdateCheck({ userInitiated: false });
88+
}

0 commit comments

Comments
 (0)