Skip to content

Add menu bar timer showing how long Caffeine has been active - #15

Open
deathemperor wants to merge 3 commits into
domzilla:masterfrom
deathemperor:feature/menu-bar-timer
Open

Add menu bar timer showing how long Caffeine has been active#15
deathemperor wants to merge 3 commits into
domzilla:masterfrom
deathemperor:feature/menu-bar-timer

Conversation

@deathemperor

@deathemperor deathemperor commented Aug 27, 2026

Copy link
Copy Markdown

Why

The menu bar icon shows that Caffeine is active, but not for how long. For indefinite activations nothing was tracking it at all — displayTimer only ran when a timeout was set, and the menu's status item just read "Caffeine is active".

What

A live duration next to the status item icon, in monospaced digits so the item doesn't jitter as the time changes.

Three new preferences (Preferences window, below "Keep apps active"):

Preference Key Default
Show timer in menu bar CAShowMenuBarTimer on
Timer display: Elapsed / Remaining CATimerDisplayMode elapsed
Time format: Compact / Verbose CATimerFormat compact

Compact renders 0:42 / 5:07 / 1:23:45; verbose renders 42s / 5m / 1h 23m. Remaining mode has nothing to count down to for an indefinite activation, so it shows ∞ instead; elapsed mode still counts up.

Implementation notes:

  • CaffeineViewModel gains activationDate and a published elapsedTime. The 1-second display timer now runs whenever Caffeine is active, not only when a timeout is set, and updates both elapsedTime and timeRemaining.
  • Durations are formatted with Duration.FormatStyle, so both styles localize automatically — only the seven new preference labels needed .strings entries. They're added to all 13 localizations.
  • Verbose formatting uses fractionalPart: .hide(rounded: .towardZero); without it the default rounding renders 1:23:45 as "1h 24m" and 59:59 as "60m", so the verbose readout would run ahead of the compact one.

Behavior change worth reviewing

formattedTimeRemaining() is renamed formattedStatusText() and now honors the display-mode preference. With the default elapsed mode, the menu's status item shows elapsed time for timed activations where it previously showed remaining. Happy to flip the default to remaining if you'd rather keep the existing behavior out of the box.

Testing

  • xcodebuild -scheme Caffeine -destination "platform=macOS" build — succeeds.
  • swiftformat . — no changes.
  • All 13 Localizable.strings pass plutil -lint.
  • Formatting exercised across 0s / 7s / 42s / 60s / 5m07s / 59:59 / 1h / 1h23m45s / 10h / 99:59:59 in both styles.

The 12 non-English strings are my translations and would benefit from a native-speaker pass.

deathemperor and others added 3 commits August 28, 2026 00:19
The menu bar icon gave no indication of how long Caffeine had been
running, and for indefinite activations nothing was tracking it at all —
the display timer only ran when a timeout was set.

Track the activation date and run the display timer whenever active, then
render the duration next to the status item icon. Three preferences
control it: show/hide, elapsed vs. remaining (remaining is undefined for
indefinite activations, so those fall back to elapsed), and a compact
(1:23:45) or verbose (1h 23m) format. The menu's status item honors the
elapsed/remaining choice too.

Durations are formatted with Duration.FormatStyle so they localize
automatically; only the new preference labels needed new strings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WxSse82nGGvb6CHbDatmfC
Remaining mode fell back to counting elapsed time when no timeout was
set, which reads as a countdown that never ends. There is nothing to
count down to, so show the infinity symbol instead. Elapsed mode is
unchanged and still counts up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WxSse82nGGvb6CHbDatmfC
The ♾️ emoji renders in color and reads as a dark blob in the menu bar.
U+221E is drawn as regular text, so it picks up the menu bar tint in
both light and dark appearance.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WxSse82nGGvb6CHbDatmfC
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