Skip to content

Commit 7576705

Browse files
refactor(tray): take a RoutingMode instead of a bare string
update_tray typed its mode as String, so the tray menu spelled out "rules"/"global"/"custom" and the webview cast the click payload back. The menu now iterates the enum and derives each id from its wire value, with an exhaustive match that fails to compile if a variant gains no label; the webview resolves the payload against the generated list.
1 parent fed29b0 commit 7576705

3 files changed

Lines changed: 23 additions & 14 deletions

File tree

frontend/src/generated/bindings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const commands = {
2525
* calls this on hydrate and whenever the active/recent profiles or language
2626
* change; clicks come back as [`TrayAction`] events (or `show`/`quit`).
2727
*/
28-
updateTray: (profiles: TrayProfile[], labels: TrayLabels, running: boolean, connected: boolean, routingMode: string) => typedError<null, string>(__TAURI_INVOKE("update_tray", { profiles, labels, running, connected, routingMode })),
28+
updateTray: (profiles: TrayProfile[], labels: TrayLabels, running: boolean, connected: boolean, routingMode: RoutingMode_Deserialize) => typedError<null, string>(__TAURI_INVOKE("update_tray", { profiles, labels, running, connected, routingMode })),
2929
/**
3030
* Update only the tray tooltip + state icon (not the menu). Called on every status
3131
* tick, so it stays cheap: the menu is rebuilt separately via [`update_tray`] only

frontend/src/lib/useTraySync.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
// ============================================================
99

1010
import { useEffect } from "react";
11-
import { commands, events, type RoutingMode_Serialize } from "../generated/bindings";
11+
import { commands, events } from "../generated/bindings";
12+
import { ROUTING_MODE_OPTS } from "../generated/defaults";
1213
import { useT } from "../i18n";
1314
import { isServiceUp } from "../lib/bridge";
1415
import { formatRate } from "../lib/format";
@@ -111,8 +112,10 @@ export function useTraySync(): void {
111112
if (action === "start" || action === "stop") void toggleService();
112113
else if (action === "restart") void restart();
113114
else if (action.startsWith("activate:")) void setActive(action.slice("activate:".length));
114-
else if (action.startsWith("routing:"))
115-
void setSetting("routingMode", action.slice("routing:".length) as RoutingMode_Serialize);
115+
else if (action.startsWith("routing:")) {
116+
const mode = ROUTING_MODE_OPTS.find((m) => m === action.slice("routing:".length));
117+
if (mode) void setSetting("routingMode", mode);
118+
}
116119
});
117120
return () => void pending.then((un) => un()).catch(() => {});
118121
}, [toggleService, restart, setActive, setSetting]);

src-tauri/src/lib.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use tauri_specta::{Builder, Event, collect_commands, collect_events};
2020
use kasumi_backend::platform::Platform;
2121
use kasumi_backend::{Command, Response, Service};
2222
use kasumi_core::contract::{PushFrame, RunState, ServiceStatus, SubAppliedEvent};
23+
use kasumi_core::enums::wire_value;
24+
use kasumi_core::state::RoutingMode;
2325

2426
pub mod defaults;
2527
pub mod desktop;
@@ -78,11 +80,11 @@ fn update_tray(
7880
labels: TrayLabels,
7981
running: bool,
8082
connected: bool,
81-
routing_mode: String,
83+
routing_mode: RoutingMode,
8284
) -> Result<(), String> {
8385
#[cfg(desktop)]
8486
{
85-
rebuild_tray_menu(&app, &profiles, &labels, running, connected, &routing_mode)
87+
rebuild_tray_menu(&app, &profiles, &labels, running, connected, routing_mode)
8688
.map_err(|e| e.to_string())?;
8789
}
8890
#[cfg(not(desktop))]
@@ -232,8 +234,9 @@ fn rebuild_tray_menu(
232234
labels: &TrayLabels,
233235
running: bool,
234236
connected: bool,
235-
routing_mode: &str,
237+
routing_mode: RoutingMode,
236238
) -> tauri::Result<()> {
239+
use strum::IntoEnumIterator;
237240
use tauri::menu::{CheckMenuItem, Menu, MenuItem, PredefinedMenuItem, Submenu};
238241

239242
let Some(tray) = app.tray_by_id("main") else {
@@ -281,18 +284,21 @@ fn rebuild_tray_menu(
281284
// Routing-mode radio: exactly the current mode is checked. Tauri has no native
282285
// radio item, so — like v2rayN's tray — we use check marks; clicks come back as
283286
// `routing:<mode>` TrayActions the webview applies to `settings.routingMode`.
287+
// Ids come from each variant's wire value, and the match below is exhaustive, so
288+
// a new RoutingMode variant fails to compile until it is given a label here.
284289
let routing = Submenu::with_id(app, "routing", &labels.routing, true)?;
285-
for (mode, label) in [
286-
("rules", &labels.routing_rules),
287-
("global", &labels.routing_global),
288-
("custom", &labels.routing_custom),
289-
] {
290+
for mode in RoutingMode::iter() {
291+
let label = match mode {
292+
RoutingMode::Rules => &labels.routing_rules,
293+
RoutingMode::Global => &labels.routing_global,
294+
RoutingMode::Custom => &labels.routing_custom,
295+
};
290296
let item = CheckMenuItem::with_id(
291297
app,
292-
format!("routing:{mode}"),
298+
format!("routing:{}", wire_value(&mode)),
293299
label,
294300
true,
295-
routing_mode == mode,
301+
mode == routing_mode,
296302
None::<&str>,
297303
)?;
298304
routing.append(&item)?;

0 commit comments

Comments
 (0)