feat(04-01): add Notifier interface and FocusTimer

- Notifier interface with ExecNotifier (notify-send) and NullNotifier
- FocusTimer thread-safe with Set/IsActive/Remaining
- shortName helper for session display names
- Full test coverage for all components
This commit is contained in:
Pierre Martin
2026-03-23 21:23:57 +01:00
parent 421bff8f73
commit b96c6d05be
4 changed files with 181 additions and 0 deletions

38
focus.go Normal file
View File

@@ -0,0 +1,38 @@
package main
import (
"sync"
"time"
)
// FocusTimer suppresses notifications for a configurable duration.
// Thread-safe via mutex.
type FocusTimer struct {
mu sync.Mutex
expires time.Time
}
// Set activates focus mode for duration d.
func (f *FocusTimer) Set(d time.Duration) {
f.mu.Lock()
defer f.mu.Unlock()
f.expires = time.Now().Add(d)
}
// IsActive returns true if focus mode has not expired.
func (f *FocusTimer) IsActive() bool {
f.mu.Lock()
defer f.mu.Unlock()
return time.Now().Before(f.expires)
}
// Remaining returns how much focus time is left. Returns 0 if expired.
func (f *FocusTimer) Remaining() time.Duration {
f.mu.Lock()
defer f.mu.Unlock()
rem := time.Until(f.expires)
if rem < 0 {
return 0
}
return rem
}