Commit Graph
93 Commits
Author SHA1 Message Date
tiennm99 f2063bda4f feat: add tray icons, the native context menu, notifications and start at login
Each enabled live provider gets a tray icon with the usage badge, a four-line tooltip and the context menu; a left click toggles the widget. Menus are rebuilt from state after every click so native check marks stay right, and a bubble right-click pops the same menu.

Alerts go through the notification plugin. On Windows the app id is registered under HKCU with a name and icon first, so a portable exe without a Start-menu shortcut can show toasts.

Start at login uses the autostart plugin under the Run value name earlier releases wrote, so an existing entry is picked up as is. On Linux the tray is skipped when no AppIndicator library loads instead of aborting.
2026-10-21 13:45:59 +07:00
tiennm99 539f26019b feat: render the tray badge as straight RGBA for Tauri tray icons 2026-10-21 13:45:49 +07:00
tiennm99 a395c66248 docs: record the app runtime status and decisions 2026-10-21 13:24:58 +07:00
tiennm99 83f60d1c1c feat: run the app on a Tauri runtime with shared state and commands
run() keeps the pre-builder order: diagnostic log, the Windows WebView2 guard
(a message box with the download link, then exit 0), the --wait-pid wait
capped at 15 s, GDK_BACKEND=x11 under Wayland when Xwayland is present, and
the single-instance plugin registered first with a no-op callback.

setup() loads the settings, drops positions on missing monitors, reads the
theme, cleans up after earlier updates, starts the scheduler and polls. The
state sits behind one mutex reached only through with_state, so no Tauri call
runs under the lock. The poll worker keeps the in-flight gate, applies the
results, runs the CLI credential refresh and pushes bubble payloads from the
main thread.

Commands: get_bubble_state, get_strings, log_js and bubble_ready. Bubble
windows ignore close requests; Restart saves the settings and exits only once
the new instance spawned. The scaffold window now renders its payload as JSON.

The Win32 app module is removed.
2026-10-21 13:20:15 +07:00
tiennm99 6d84f33e59 feat: add the scheduler thread for polls, countdowns and update checks
One std thread owns the poll, countdown and update-check deadlines and is fed
over an mpsc channel. The deadline rules are a pure struct tested with
fabricated instants; the thread hands each due action to a host trait.

An update check that fires stays disarmed until the check reports back, and
only that report re-arms the full interval, so the automatic check repeats
instead of running once. Changing the interval checks at once when the last
check is older than the new interval.
2026-10-21 13:19:37 +07:00
tiennm99 607a3103d3 feat: parse the CLI flags, wait for the previous instance and clean up after updates
The argv parser accepts --diagnose, --wait-pid and --updated-to and ignores
anything else, including --apply-update, which no released version passes to
the downloaded binary. Arguments are read lossily, so a non-UTF-8 argument no
longer panics.

The wait for a parent pid polls kill(pid, 0) on Unix and waits on the process
handle on Windows, capped by the caller. The Windows platform module gains the
WebView2 runtime probe, an error message box and the theme read.

handoff::relaunch spawns the AppImage or the current executable detached with
--wait-pid and returns the spawn error to the caller. The startup cleanup of
<exe>.old.* siblings and staged updater executables moves out of the Win32
update module.
2026-10-21 13:19:15 +07:00
tiennm99 4ca4f075f3 docs: fix a duplicated phrase in the data layer proxy notes 2026-10-21 13:00:57 +07:00
tiennm99 b3afcdc04e fix: skip SOCKS environment proxies so an HTTP or system proxy applies
ureq is built without socks-proxy, so an ALL_PROXY=socks5h entry failed
every request and a socks5 entry silently connected directly, while also
suppressing the Windows system proxy. Pick the first HTTP or HTTPS proxy
from the environment ourselves, keep NO_PROXY on it, and fall back to the
system proxy when none is usable.
2026-10-21 13:00:50 +07:00
tiennm99 b8e672f750 fix: give the refresh CLI the search PATH and reject non-HTTP system proxies 2026-10-21 12:52:22 +07:00
tiennm99 91d2741028 docs: record the data layer status and decisions 2026-10-21 12:45:52 +07:00
tiennm99 9e2666ff0e feat: port the data layer to ureq with the Windows system proxy
Replace the WinHTTP client with a ureq agent that keeps the same
Client/Response surface: status errors come back as responses, gzip,
60 s connect / 30 s receive / 120 s total timeouts, rustls with the
platform verifier and a per-request User-Agent override.

Environment proxies come from ureq. On Windows, when none is set, the
static Internet Settings proxy is read from HKCU and parsed by a pure
core module (per-scheme ProxyServer, ProxyOverride globs and <local>);
bypassed hosts go through a direct agent. PAC/WPAD is not evaluated.

The usage providers and credential sources compile again on every
platform. Refresh keeps the Windows candidates and CREATE_NO_WINDOW;
Unix spawns claude/codex from PATH plus the usual per-user install
directories and reaps the child on a detached thread. An empty
CODEX_HOME now counts as unset and a float expiresAt is truncated
instead of ignored.

Fixture tests cover the OAuth usage body, rate-limit headers (including
a 429 over loopback), the ChatGPT envelope, ISO 8601 edge cases,
credential JSON and proxy strings. An ignored live_poll test polls the
real providers.
2026-10-21 12:41:08 +07:00
tiennm99 10c43d76af docs: record the portable core status and decisions 2026-10-21 12:24:08 +07:00
tiennm99 76ee0203cb feat: add the portable state, payload and menu model
Poll results, threshold crossings and the alert cooldown now return
values instead of calling the tray, so they run under unit tests. The
bubble and panel payloads carry every display string and colour from
Rust, and the context menu is a plain tree with string ids that parse
back into commands. The update-check schedule and countdown delay are
plain functions of the stored times.
2026-10-21 12:23:53 +07:00
tiennm99 bc1a098875 refactor: move settings, strings, colours and geometry into a portable core
Settings, the English strings, the colour ramp and the bubble geometry no
longer touch Win32 types, so they compile and test on every platform.
Snapping, clamping, default placement, panel placement and the monitor
probe take plain rects; settings loading is split into parsing and an
offscreen check fed with the monitor list. ProviderId now serialises as
its slug.
2026-10-21 12:23:15 +07:00
tiennm99 d8f339208d fix: list the desktop icons in bundle.icon
The bundler has no icon fallback, so an empty list breaks the AppImage
step and ships a deb without hicolor icons. Put icon.png first so it stays
the default window icon on Linux and macOS, and bundle the deb in the
Linux CI row to catch a broken list before release.
2026-10-21 12:04:54 +07:00
tiennm99 ffaa6c17a9 docs: record the Tauri scaffold status and decisions 2026-10-21 11:56:30 +07:00
tiennm99 4e70aa1d22 ci: build and check on Windows, Linux and macOS
Windows and Ubuntu 22.04 run fmt, clippy, tests, lint, the JS tests and
a no-bundle release build. The Windows row checks the exe version
resource and uploads the exe as a 7-day artifact. macOS runs cargo check
as the compile gate.
2026-10-21 11:45:20 +07:00
tiennm99 2adbeeb613 build: add the npm toolchain with ESLint, JSDoc and node --test
@tauri-apps/cli is a local devDependency. ESLint runs the recommended
and JSDoc rules, with browser globals for ui/ and node globals for tests
and scripts. npm test runs node --test over tests/js.
2026-10-21 11:45:20 +07:00
tiennm99 f64d81e6a1 build: scaffold the Tauri v2 crate
Turn the package into a lib plus thin bin on Tauri v2 with a root-level
tauri.conf.json, capabilities, generated icons (keeping the hand-tuned
icon.ico) and a placeholder bubble page. The Win32 modules leave the
module tree until each one is ported; their sources stay on disk.

tauri-build now embeds the icon, a VERSIONINFO from the Cargo version and
a PerMonitorV2 manifest, replacing res/icon.rc and its stale 0.1.0.
2026-10-21 11:45:14 +07:00
tiennm99 bb09765be5 docs: plan Tauri v2 cross-platform port 2026-10-21 11:28:47 +07:00
tiennm99 bfcf3b56cd chore: remove implemented plan docs 2026-06-03 09:31:46 +07:00
tiennm99 4022d3f2de feat: drop WSL and multi-language support v0.5.0 2026-06-02 16:32:21 +07:00
tiennm99 67f3b8a7ec chore: bump version to 0.4.1 v0.4.1 2026-06-02 15:52:03 +07:00
tiennm99 c46ab57f73 fix(update): use self-replace for portable updates 2026-06-02 15:50:45 +07:00
tiennm99 0ac698e2d1 chore: bump version to 0.4.0 v0.4.0 2026-06-02 15:11:26 +07:00
tiennm99 2c67dd1217 feat(providers): prepare provider terminology and metadata 2026-06-02 15:09:50 +07:00
tiennm99 38752ae5c5 chore: bump version to 0.3.13 v0.3.13 2026-06-02 11:09:35 +07:00
tiennm99 e099f0a91f fix(update): restore helper-based self-update 2026-06-02 10:27:31 +07:00
tiennm99 4e9a66cbc8 chore: bump version to 0.3.12 v0.3.12 2026-06-01 16:55:59 +07:00
tiennm99 1d9c59b43b chore: bump version to 0.3.11 v0.3.11 2026-06-01 16:10:43 +07:00
tiennm99 7039bf7e98 fix: pass updater executable path to CreateProcess 2026-06-01 16:09:28 +07:00
tiennm99 cc73c3f9b4 chore: bump version to 0.3.10 v0.3.10 2026-06-01 15:36:26 +07:00
tiennm99 a68d80415b chore: bump version to 0.3.9 v0.3.9 2026-06-01 15:05:35 +07:00
tiennm99 cce22cc3b7 fix: run self-update through detached helper 2026-06-01 15:04:16 +07:00
tiennm99 5e00009e5a chore: bump version to 0.3.8 v0.3.8 2026-06-01 14:37:26 +07:00
tiennm99 c91dc996f8 fix: tighten fullscreen auto-hide detection 2026-06-01 14:35:26 +07:00
tiennm99 b2e48cc119 chore: bump version to 0.3.7 v0.3.7 2026-05-25 11:37:34 +07:00
tiennm99 bee9f3cfa0 fix(ui): use theme-aware monochrome accent for Codex 2026-05-25 11:37:29 +07:00
tiennm99 860eb62d1b chore: bump version to 0.3.6 v0.3.6 2026-05-25 11:15:13 +07:00
tiennm99 c424b17bd7 fix(ui): reverse remaining-time direction to read like a clock
Inner ring's consumed wedge now grows clockwise from 12 o'clock (mirroring
a clock-hand countdown) and the tail remaining-time bar shrinks toward the
right edge instead of the left. Usage ring and weekly usage bar unchanged.
2026-05-25 11:15:07 +07:00
tiennm99 3b0f96f51c chore: bump version to 0.3.5 v0.3.5 2026-05-23 23:36:41 +07:00
tiennm99 5976181cb2 fix(ui): improve bubble visual hierarchy and contrast
- Lift inner time ring above WCAG 1.4.11 (track #303030 -> #404040,
  stroke floor 1 -> 2 logical, ring gap 3 -> 4).
- Breathe tail bar/text with bar_text_gap=8 (was pad=6); right inset
  12 -> 14 logical so text clears the stadium end-cap.
- Reweight typography: head percent FW_BOLD, "5H" tag and tail percent
  FW_SEMIBOLD, tail countdown stays normal but takes muted color so
  the percent reads as the headline.
- Tone down usage track (#3A3A3A/#D6D6D6 -> #2C2C2C/#E2E2E2) so fill
  dominates at low percentages.
- Differentiate lane mass: usage bar 9%/5..12 -> 10%/6..12, time bar
  5%/3..7 -> 4%/3..6, lane gap 5 -> 6. Time bar now reads as supporting
  context, not a competing quota.
- Min-fill guard on weekly bar: sub-cap fills floor at one cap-diameter
  so 1% renders as a recognizable dot.
- head_pad 4 -> 5; big-font ratio 26% -> 24% of head diameter (BOLD
  compensates for the size cut).
2026-05-23 23:36:34 +07:00
tiennm99 f2b31d3211 fix(ui): align tail bar text layout v0.3.4 2026-05-23 22:53:36 +07:00
tiennm99 5c2b14fc03 feat(ui): show remaining time progress v0.3.3 2026-05-23 22:31:37 +07:00
tiennm99 51889d3c39 fix(ui): scale weekly bar thickness v0.3.2 2026-05-23 21:43:11 +07:00
tiennm99 6661a7a10b chore: bump version to 0.3.1 v0.3.1 2026-05-23 21:07:05 +07:00
tiennm99 6cafffc883 fix(bubble): show 7d percent at default size and 125% DPI
v0.3.0 introduced a tail 7d% reading but the layout-collapse guard
fired at every common bubble configuration — at the default 200-logical
size on both 100% and 125% DPI, after reserving the CJK worst-case
countdown column ("999시간") and the "100%" text rect, the tail had
less than 20 logical of bar room left. The guard collapsed the % rect
to zero width and the paint code's `if rect.right > rect.left` skip
ran on every frame, so the feature was effectively dead on arrival
for the majority of users.

The 20-logical bar minimum was the pre-feature bar floor, used to
guarantee a readable bar at very small bubble sizes. It does not need
to apply when the % is shown — the % is the actual data and the bar
becomes secondary visual context. Split into two thresholds:

- `bar_min_with_pct = 8 logical` decides whether the % can fit. With
  8 logical of bar room the bar still renders as a short pill.
- `bar_min = 20 logical` only applies on the fallback (140-logical
  minimum bubble) path where the % has been dropped — preserving
  the pre-feature readable-bar behavior at the smallest size.

The bar's render floor now follows the active path (`bar_render_min`)
so a thin bar in the pct-active case does not overlap the countdown.
2026-05-23 21:06:26 +07:00
tiennm99 b58811bfe0 chore: bump version to 0.3.0 v0.3.0 2026-05-23 20:33:10 +07:00
tiennm99 e50aa3522a feat(bubble): show 5h countdown in head and 7d percent in tail
The stadium bubble previously dropped the 5h reset countdown (only the
ring + percent were visible in the head) and never showed the 7d percent
as a number (only the tail bar fill suggested it). Two more glanceable
data points now live on the bubble face without reopening the panel.

Head: the small "5h" tag is replaced by the live 5h countdown (e.g.
"2h14m"). Falls back to the literal "5h" when no countdown is available
yet (cold start) or when the localized string would overflow the rect —
DT_NOCLIP would otherwise leak wide CJK glyphs ("4시간 32분") onto the
ring stroke at the 140-logical minimum width.

Tail: a new "X%" reading sits between the "7d" label and the bar
(layout reads "7d  62%  ▰▰▰▰▰▱▱▱   6d4h"). Foreground text color —
not the bar accent — because Codex teal #10A37F on the light theme
background only hits ~3.2:1 contrast, below WCAG AA for small text;
adjacency to the bar carries the visual grouping without hue. The text
brightens in sync with the bar fill when weekly_pct >= 95%.

compute_bubble_layout reserves room for a "100%"-sized rect between
label and bar; if that would push the bar below the 20-logical
minimum, the % rect collapses to zero width and the layout falls back
to the original label→bar→countdown geometry, so the 140-logical
bubble keeps its bar.

No new graphics dependencies; tiny-skia + GDI hybrid render path
unchanged. session_text plumbing in src/app.rs was already wired but
unused in the render — now consumed.

cargo check: clean. cargo test: 2/2. cargo clippy: 13 warnings
(unchanged baseline).
2026-05-23 20:32:31 +07:00
tiennm99 a3f1323154 chore: bump version to 0.2.0 v0.2.0 2026-05-23 18:18:34 +07:00