feat: initial gosleep-timer implementation

Go TUI sleep timer with modular architecture.
- Config: YAML-based, profile inheritance, auto WM detection
- Engine: timer, executor, stage pipeline (pre→timer→post)
- Modules: workspace (niri/hyprland/kde), media, lock, kill,
  notify, sound, brightness, mute, custom, script
- TUI: bubbletea app with profiles, module toggles, progress bar
- CLI: run, list-profiles, export, import, history, stats
- History: JSONL log with statistics
- QR: config export as ASCII QR
This commit is contained in:
2026-07-03 01:43:22 +02:00
commit 8501fd074c
34 changed files with 3401 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
package profiles
import (
"fmt"
"sort"
"github.com/forust/gosleep-timer/config"
)
type Manager struct {
cfg *config.Config
}
func NewManager(cfg *config.Config) *Manager {
return &Manager{cfg: cfg}
}
func (m *Manager) List() []string {
// Return sorted list of profile names
names := make([]string, 0, len(m.cfg.Profiles))
for name := range m.cfg.Profiles {
names = append(names, name)
}
sort.Strings(names)
return names
}
func (m *Manager) Get(name string) (*config.Profile, error) {
p, ok := m.cfg.Profiles[name]
if !ok {
return nil, fmt.Errorf("profile %q not found", name)
}
return &p, nil
}
func (m *Manager) Info(name string) (*Info, error) {
p, err := m.Get(name)
if err != nil {
return nil, err
}
info := &Info{Name: name}
if p.Modules != nil {
m := p.Modules
if m.Workspace != nil && m.Workspace.Enabled {
info.Modules = append(info.Modules, "workspace")
}
if m.Media != nil && m.Media.Enabled {
info.Modules = append(info.Modules, "media")
}
if m.Lock != nil && m.Lock.Enabled {
info.Modules = append(info.Modules, "lock")
}
if m.Kill != nil && m.Kill.Enabled {
info.Modules = append(info.Modules, "kill")
}
if m.Notify != nil && m.Notify.Enabled {
info.Modules = append(info.Modules, "notify")
}
if m.Sound != nil && m.Sound.Enabled {
info.Modules = append(info.Modules, "sound")
}
if m.Brightness != nil && m.Brightness.Enabled {
info.Modules = append(info.Modules, "brightness")
}
if m.Mute != nil && m.Mute.Enabled {
info.Modules = append(info.Modules, "mute")
}
if m.Custom != nil && m.Custom.Enabled {
info.Modules = append(info.Modules, "custom")
}
if m.Script != nil && m.Script.Enabled {
info.Modules = append(info.Modules, "script")
}
}
return info, nil
}