Skip to content

feat: lock break exits for the opening part of a break - #1842

Open
ankitg12 wants to merge 2 commits into
hovancik:trunkfrom
ankitg12:feat/lock-exits-at-break-start
Open

ankitg12 wants to merge 2 commits into
hovancik:trunkfrom
ankitg12:feat/lock-exits-at-break-start

Conversation

@ankitg12

Copy link
Copy Markdown

Why

Skip and Postpone are currently two halves of a single predicate:

canPostpone(postpone, pp, P) => postpone && pp <= P
canSkip(strict, postpone, pp, P) => !((postpone && pp <= P) || strict)

Hiding Skip during the opening moments of a break therefore requires postponable to be true, which necessarily shows Postpone during those same moments. There is no configuration in which a break simply cannot be dismissed for its first few seconds — the only "no exit" option is strictMode, which locks the break for its whole duration.

That leaves a gap for people who want a break they cannot reflexively dismiss, but who do not want to be trapped for ten minutes. The muscle-memory click lands before the eyes have left the screen, which is the moment the break exists to interrupt.

Refs #1841, #1629.

What

Two new settings, microbreakLockedDurationPercent and breakLockedDurationPercent, both defaulting to 0.

While the break is younger than that percentage of its duration, neither Skip nor Postpone is offered and the keyboard shortcut is inert. Once it elapses, existing behaviour resumes unchanged.

At 0 the predicates are exactly as before — the new argument is optional and defaults to 0, so every existing call site and test is untouched:

function canSkip (strictMode, postpone, passedPercent, postponePercent, lockedPercent = 0) {
  return !isLocked(passedPercent, lockedPercent) &&
    !((postpone && passedPercent <= postponePercent) || strictMode)
}

The second commit adds the user-facing half: while exits are locked, Skippable in <time> appears where the buttons will be, counting down on the existing per-second tick. It is one translatable key with a {{count}} placeholder (utils.skippableIn, formatted by a new formatSkippableIn beside formatTimeRemaining) rather than a prefix concatenated onto a formatted duration — languages that place the verb differently from English can then be translated correctly. Marked aria-live="polite" so assistive technology can explain why nothing is actionable yet.

Open question for the maintainer

I expressed the lock as a percentage of break duration, reusing the existing PostponableDurationPercent plumbing and slider. #1841 asked for a delay in seconds, which is how users think about it, but that needs its own unit handling and a different control.

Happy to switch to milliseconds if you prefer — it is a small change and I would rather match your intent than my convenience.

Testing

  • standard clean.
  • vitest run — 45/45 passing, including 6 new cases covering the lock boundary, inertness at 0, and that it never overrides strictMode.
  • Packed with npm run pack and exercised on Windows 11: microbreaks remain strict throughout, a 10-minute long break offers nothing for its first 30 seconds and shows a live countdown, then Skip appears.

Not included

Translations. en.json only, since the other 53 locales are managed on Weblate.

Adds microbreakLockedDurationPercent and breakLockedDurationPercent
(default 0, no behaviour change). While the break is younger than the
configured percentage of its duration, neither Skip nor Postpone is
offered and the keyboard shortcut is inert.

Skip and Postpone were previously two halves of one predicate: hiding
Skip early required postponable to be true, which necessarily showed
Postpone. There was no configuration in which a break simply could not
be dismissed for its opening seconds.

Refs hovancik#1841, hovancik#1629
While exits are locked, show "Skippable in <time>" in place of the
buttons, counting down on the existing per-second tick.

Adds utils.formatSkippableIn alongside formatTimeRemaining and bridges
it the same way, so the whole sentence is one translatable key with a
{{count}} placeholder rather than a prefix concatenated onto a
formatted duration. Languages that do not put the verb where English
does can then be translated correctly.

Marked aria-live=polite so assistive technology explains why nothing
is actionable yet.
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