mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-21 06:24:32 +00:00
windows: cfg-gate the tray badge so the Linux build has no dead code
The spend badge is a second tray icon carrying the number as its bitmap, which only the Tauri tray backend provides; Linux runs its own SNI tray and has no equivalent. The module was compiled there anyway, so every item in it - and the two tray ids in lib.rs - tripped dead_code under clippy -D warnings on the ubuntu leg. - `mod tray_badge` and TRAY_ID / BADGE_TRAY_ID are now cfg(not(linux)), so the code is absent on Linux rather than present and unused. - `set_tray_badge` reports the badge as unsupported on Linux instead of returning a success that never happened. - The frontend hides the control wherever it is unsupported, behind TRAY_BADGE_SUPPORTED in lib/platform.ts - one constant, three call sites (the settings row, the footer menu item, and the effect that would otherwise invoke the command). - AppState's `linux_tray` field is dropped: it was written and never read, which is the same lint one file over. init_tray_linux already owns the handle. Checked rather than reasoned: `cargo clippy --all-targets -- -D warnings` passes on macOS, and a scratch copy of the crate with the linux/macos cfg arms swapped (so a normal macOS clippy selects everything a Linux build would keep, and drops everything it would drop) also passes. Reinstating the ungated `mod tray_badge` in that copy reproduces the exact CI failure, so the check is real. It stubs tray_linux.rs, whose ksni and png deps do not build here - that file is still only covered by CI's ubuntu leg.
This commit is contained in:
parent
562bab65ba
commit
76c63cbfd1
6 changed files with 44 additions and 23 deletions
|
|
@ -8,6 +8,12 @@ Linux (ksni / AppIndicator) support is compiled and kept working for dev, but it
|
|||
**experimental and unreleased** - Linux users should use the GNOME extension in `../gnome/`.
|
||||
The releases this repo cuts from here are Windows only.
|
||||
|
||||
Not everything crosses over: the spend badge is a second tray icon carrying the number as its
|
||||
bitmap, which only the Windows notification area provides. `tray_badge` is compiled out on
|
||||
Linux, the `set_tray_badge` command reports it as unsupported there, and the frontend hides
|
||||
the control behind `TRAY_BADGE_SUPPORTED` in `src/lib/platform.ts`. Anything else that is
|
||||
Windows-only must be cfg-gated the same way, or the ubuntu leg of CI fails on dead code.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ mod cli;
|
|||
mod config;
|
||||
mod fx;
|
||||
mod plan;
|
||||
/// The spend-in-the-tray badge is a second tray icon, which only the Tauri tray backend
|
||||
/// provides; Linux runs its own SNI tray (`tray_linux`) and has no equivalent, so the
|
||||
/// whole module is compiled out there rather than sitting unused.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
mod tray_badge;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod tray_linux;
|
||||
|
|
@ -26,9 +30,11 @@ use crate::cli::CodeburnCli;
|
|||
use crate::config::CurrencyConfig;
|
||||
use crate::fx::FxCache;
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
const TRAY_ID: &str = "codeburn-tray";
|
||||
/// Second tray icon that carries today's spend as text, sitting next to the logo. The
|
||||
/// closest Windows and Linux panels get to the macOS menubar title.
|
||||
/// closest the Windows notification area gets to the macOS menubar title.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
const BADGE_TRAY_ID: &str = "codeburn-badge";
|
||||
const POPOVER_LABEL: &str = "popover";
|
||||
|
||||
|
|
@ -41,8 +47,6 @@ pub struct AppState {
|
|||
pub config: Mutex<CurrencyConfig>,
|
||||
pub fx: FxCache,
|
||||
pub plan: plan::PlanClient,
|
||||
#[cfg(target_os = "linux")]
|
||||
pub linux_tray: tray_linux::LinuxTrayHandle,
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
|
|
@ -51,24 +55,18 @@ pub fn run() {
|
|||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.setup(|app| {
|
||||
#[cfg(target_os = "linux")]
|
||||
let linux_tray = tray_linux::LinuxTrayHandle::empty();
|
||||
|
||||
let state = AppState {
|
||||
app.manage(AppState {
|
||||
cli: Mutex::new(CodeburnCli::resolve()),
|
||||
config: Mutex::new(CurrencyConfig::load_or_default()),
|
||||
fx: FxCache::new(),
|
||||
plan: plan::PlanClient::new(),
|
||||
#[cfg(target_os = "linux")]
|
||||
linux_tray: linux_tray.clone(),
|
||||
};
|
||||
app.manage(state);
|
||||
});
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
build_tray_tauri(app.handle())?;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
init_tray_linux(app.handle().clone(), linux_tray);
|
||||
init_tray_linux(app.handle().clone(), tray_linux::LinuxTrayHandle::empty());
|
||||
|
||||
if let Some(window) = app.get_webview_window(POPOVER_LABEL) {
|
||||
let _ = window.hide();
|
||||
|
|
@ -466,6 +464,14 @@ mod commands {
|
|||
/// `text` is a short spend string ("$87", "142", "1.2K"); `None` hides the badge icon.
|
||||
#[tauri::command]
|
||||
pub fn set_tray_badge(app: AppHandle, text: Option<String>) -> Result<(), String> {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
// Unreachable from the UI: the frontend hides the control wherever the badge is
|
||||
// unsupported (lib/platform.ts). Saying so beats reporting a success that never
|
||||
// happened.
|
||||
let _ = (app, text);
|
||||
Err("the tray spend badge needs a second tray icon, which the Linux SNI tray does not provide".to_string())
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
let Some(badge) = app.tray_by_id(super::BADGE_TRAY_ID) else {
|
||||
|
|
@ -487,12 +493,8 @@ mod commands {
|
|||
badge.set_visible(false).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let _ = (app, text);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { USD, formatCurrency, trayBadgeText } from './lib/currency'
|
|||
import { PayloadCache } from './lib/cache'
|
||||
import { relativePast } from './lib/dates'
|
||||
import { applyTheme, currentTheme, readSetting, writeSetting } from './lib/settings'
|
||||
import { TRAY_BADGE_SUPPORTED } from './lib/platform'
|
||||
import { AgentTabStrip, detectedProviders } from './components/AgentTabStrip'
|
||||
import type { Provider } from './components/AgentTabStrip'
|
||||
import { ModelsSection } from './components/ModelsSection'
|
||||
|
|
@ -65,7 +66,7 @@ export function App() {
|
|||
const [version, setVersion] = useState('')
|
||||
const [lastUpdated, setLastUpdated] = useState<Date | null>(null)
|
||||
const [theme, setTheme] = useState(() => currentTheme())
|
||||
const [trayBadge, setTrayBadge] = useState(() => readSetting('trayBadge') !== 'off')
|
||||
const [trayBadge, setTrayBadge] = useState(() => TRAY_BADGE_SUPPORTED && readSetting('trayBadge') !== 'off')
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
// The window starts hidden and is shown by a tray click, which emits `codeburn://shown`.
|
||||
const [popoverVisible, setPopoverVisible] = useState(false)
|
||||
|
|
@ -216,6 +217,7 @@ export function App() {
|
|||
}, [todayCost, currency])
|
||||
|
||||
useEffect(() => {
|
||||
if (!TRAY_BADGE_SUPPORTED) return
|
||||
const text = trayBadge && todayCost !== null ? trayBadgeText(todayCost, currency) : null
|
||||
invoke('set_tray_badge', { text }).catch(err => setError(`Tray badge: ${String(err)}`))
|
||||
}, [todayCost, currency, trayBadge])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { CurrencyState } from '../lib/currency'
|
||||
import { CURRENCY_CODES } from '../lib/currency'
|
||||
import { TRAY_BADGE_SUPPORTED } from '../lib/platform'
|
||||
import { DropMenu } from './DropMenu'
|
||||
import { CoinIcon, DownloadIcon, EllipsisIcon, RefreshIcon, TerminalIcon } from './Icons'
|
||||
|
||||
|
|
@ -64,7 +65,9 @@ export function FooterBar({
|
|||
className="dropmenu-more"
|
||||
items={[
|
||||
{ id: 'settings', label: settingsOpen ? 'Back to overview' : 'Settings…' },
|
||||
{ id: 'badge', label: "Show today's cost in tray", checked: trayBadge, separatorBefore: true },
|
||||
...(TRAY_BADGE_SUPPORTED
|
||||
? [{ id: 'badge', label: "Show today's cost in tray", checked: trayBadge, separatorBefore: true }]
|
||||
: []),
|
||||
{ id: 'theme', label: themeLabel },
|
||||
{ id: 'quit', label: 'Quit CodeBurn', separatorBefore: true },
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { invoke } from '@tauri-apps/api/core'
|
|||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import type { CurrencyState } from '../lib/currency'
|
||||
import { CURRENCY_CODES } from '../lib/currency'
|
||||
import { homePath } from '../lib/platform'
|
||||
import { homePath, TRAY_BADGE_SUPPORTED } from '../lib/platform'
|
||||
import type { CliStatus } from './SetupState'
|
||||
import { DropMenu } from './DropMenu'
|
||||
import { ChevronDown, ChevronRight } from './Icons'
|
||||
|
|
@ -70,9 +70,11 @@ export function SettingsPanel({
|
|||
<Toggle on={loginItem === true} disabled={loginItem === null} onToggle={toggleLogin} />
|
||||
</Row>
|
||||
{loginError && <div className="settings-error">{loginError}</div>}
|
||||
<Row label="Show today's cost in the tray" hint="A second tray icon carrying the number, next to the logo.">
|
||||
<Toggle on={trayBadge} onToggle={() => onTrayBadge(!trayBadge)} />
|
||||
</Row>
|
||||
{TRAY_BADGE_SUPPORTED && (
|
||||
<Row label="Show today's cost in the tray" hint="A second tray icon carrying the number, next to the logo.">
|
||||
<Toggle on={trayBadge} onToggle={() => onTrayBadge(!trayBadge)} />
|
||||
</Row>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="settings-group">
|
||||
|
|
|
|||
|
|
@ -8,3 +8,9 @@ const SEP = IS_WINDOWS ? '\\' : '/'
|
|||
export function homePath(...parts: string[]): string {
|
||||
return [HOME, ...parts].join(SEP)
|
||||
}
|
||||
|
||||
/// Today's spend in the tray is a second tray icon carrying the number as its bitmap. Only
|
||||
/// the Windows notification area gives us one; the Linux SNI tray has no equivalent, and
|
||||
/// macOS ships the Swift menubar instead. Where this is false the control is hidden and the
|
||||
/// Rust command is never called.
|
||||
export const TRAY_BADGE_SUPPORTED = IS_WINDOWS
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue