[verified] feat: auto-start next timer

This commit is contained in:
2026-07-23 00:27:05 +03:00
parent 723b4a221d
commit 6baa13dc90
9 changed files with 236 additions and 14 deletions
+12
View File
@@ -113,6 +113,18 @@ function SettingsPanel({ settings, persistenceError, onChange, onClose, onReset
/>
</label>
</div>
<label className="timer-toggle">
<input
aria-label="Automatically start next timer"
checked={settings.autoStartNext}
onChange={(event) => update('autoStartNext', event.target.checked)}
type="checkbox"
/>
<span>
<strong>Automatically start next timer</strong>
<small>Continue from focus to break, then back to focus.</small>
</span>
</label>
</section>
<section className="settings-section">
+11
View File
@@ -9,6 +9,17 @@ import {
import { IndexedDbSettingsStore } from './settings-store'
describe('application settings', () => {
it('automatically starts the next timer by default', () => {
expect(DEFAULT_SETTINGS.autoStartNext).toBe(true)
})
it('preserves an explicit auto-start opt-out during normalization', () => {
expect(normalizeSettings({
...DEFAULT_SETTINGS,
autoStartNext: false,
}).autoStartNext).toBe(false)
})
it('uses an overlay default aligned with the slider step', () => {
expect(DEFAULT_SETTINGS.overlayOpacity).toBe(0.2)
})
+6
View File
@@ -17,6 +17,7 @@ export interface AppSettings {
focusMinutes: number
shortBreakMinutes: number
longBreakMinutes: number
autoStartNext: boolean
fontId: FontId
backgroundId: BackgroundId
overlayOpacity: number
@@ -27,6 +28,7 @@ export const DEFAULT_SETTINGS: AppSettings = {
focusMinutes: 25,
shortBreakMinutes: 5,
longBreakMinutes: 15,
autoStartNext: true,
fontId: 'space',
backgroundId: 'violet',
overlayOpacity: 0.2,
@@ -53,6 +55,10 @@ export function normalizeSettings(value: unknown): AppSettings {
focusMinutes: clampInteger(candidate.focusMinutes, 1, 120, DEFAULT_SETTINGS.focusMinutes),
shortBreakMinutes: clampInteger(candidate.shortBreakMinutes, 1, 60, DEFAULT_SETTINGS.shortBreakMinutes),
longBreakMinutes: clampInteger(candidate.longBreakMinutes, 1, 90, DEFAULT_SETTINGS.longBreakMinutes),
autoStartNext:
typeof candidate.autoStartNext === 'boolean'
? candidate.autoStartNext
: DEFAULT_SETTINGS.autoStartNext,
fontId: isOneOf(candidate.fontId, FONT_IDS) ? candidate.fontId : DEFAULT_SETTINGS.fontId,
backgroundId: isOneOf(candidate.backgroundId, BACKGROUND_IDS)
? candidate.backgroundId