Skip to content

feat: add an estimated time to depletion (ETD) indicator#38

Open
carlosresu wants to merge 12 commits into
CodeZeno:mainfrom
carlosresu:feat/etd
Open

feat: add an estimated time to depletion (ETD) indicator#38
carlosresu wants to merge 12 commits into
CodeZeno:mainfrom
carlosresu:feat/etd

Conversation

@carlosresu

Copy link
Copy Markdown

Summary

Adds an opt-in Estimated Time to Depletion (ETD) indicator that tells you how long until a quota runs out at your current pace, so you can see at a glance whether you are about to hit the limit before the window resets. Inspired by issue #21.

When a usage bar is on pace to deplete before its window resets, the cell appends the estimate after the remaining time:

  • The remaining countdown gains a rem label and the estimate follows as … ETD, e.g. 90% · 1d rem · 13h ETD — about a day until the weekly window resets, but at the current burn rate you would run out in ~13h.
  • The estimate is derived from each section's resets_at timestamp and the fixed window length (5h / 7d): etd = (100 - used%) / (used% / elapsed). It is shown only when the projected depletion lands before the reset — i.e. exactly when you are over pace. Cells pacing safely show nothing extra.
  • Applies to all four cells: Claude/Codex × session/weekly.

The indicator is off by default. State persists to settings.json via a #[serde(default)] show_etd field, so existing settings files migrate cleanly.

Screenshots

Same usage data with Show ETD enabled — the 5h session is pacing safely (no suffix), while the 7d weekly is over pace and shows the estimate.

ETD

Settings control

A single right-click Settings → Show ETD checkbox toggles it. The checkmark reflects the current state; toggling repaints live and persists immediately.

Layout

When ETD is on, the text column widens (TEXT_WIDTH 62ETD_TEXT_WIDTH 160) so the worst-case 100% · 59m rem · 59m ETD is never clipped. The width is threaded through both the layout calc and the draw clip rect so they stay in agreement; when ETD is off the widget renders exactly as before.

Localization

Show ETD, the ETD label, and the rem label are present in all 10 supported locales (a missing field is a compile error).

Tests

This change adds the repository's first unit tests (#[cfg(test)] in poller.rs and window.rs), 9 in total:

  • ETD projection math: safe-pace, at-risk, boundary cases, and a ~3,000-case property sweep asserting the at-risk invariant (Some iff used% > 100·elapsed/window).
  • etd_suffix formatting: present when at-risk, absent when safe, absent without a reset timestamp.
  • Width: the ETD column is wider than the base, and the widget grows by exactly the column delta per active model (so layout and draw never disagree).

Commits

  • feat: add ETD projection math with unit tests
  • feat: add ETD localization strings
  • feat: add ETD suffix formatter
  • feat: persist show_etd setting
  • feat: add Show ETD toggle and wire ETD into usage cells
  • fix: widen usage cells when ETD is shown so the suffix is not clipped
  • feat: label remaining time with 'rem' in ETD mode and widen column to fit
  • docs: document the ETD indicator

Test plan

  • cargo test — 9/9 passing, output pristine
  • cargo build clean, no warnings
  • Right-click → Settings → Show ETD; confirm the item exists and is off by default
  • Toggle on; confirm an over-pace cell gains · <rem> rem · <etd> ETD and a safe cell stays bare
  • Confirm the suffix is not clipped and rows stay aligned (widget widens while on)
  • Toggle off; confirm cells render exactly as before and the widget returns to its original width
  • Restart; confirm the setting persists via settings.json

Revert shared window.rs draw/width signatures to base; read show_etd via a
state-lock accessor and share a lock-free text-width slot mechanism with the
detailed-remaining feature (identical block, distinct per-feature wiring).
Place ETD's struct fields, menu ID, and Settings menu item at anchors that are
non-adjacent to the other display features so any merge subset is conflict-free.
Keeps poller's format_countdown_from_secs at its base 2-arg signature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant