Add callbacks, crescendo sound and better configs

This commit is contained in:
2026-02-04 20:55:03 +02:00
parent cdcdf2c644
commit 621815ed0f
5 changed files with 235 additions and 33 deletions

View File

@@ -24,6 +24,11 @@ const (
cfgServerPassword
cfgAPIPassword
cfgPollSeconds
cfgCrescendoEnabled
cfgCrescendoStartPct
cfgCrescendoEndPct
cfgCrescendoDurationS
cfgCallbackScript
cfgFieldCount
)
@@ -51,6 +56,15 @@ func newConfigModel(cfg db.Settings) *configModel {
c.fields[cfgServerPassword] = cfg.ServerPassword
c.fields[cfgAPIPassword] = cfg.APIPassword
c.fields[cfgPollSeconds] = strconv.Itoa(cfg.PollSeconds)
if cfg.CrescendoEnabled {
c.fields[cfgCrescendoEnabled] = "true"
} else {
c.fields[cfgCrescendoEnabled] = "false"
}
c.fields[cfgCrescendoStartPct] = strconv.Itoa(cfg.CrescendoStartPct)
c.fields[cfgCrescendoEndPct] = strconv.Itoa(cfg.CrescendoEndPct)
c.fields[cfgCrescendoDurationS] = strconv.Itoa(cfg.CrescendoDurationS)
c.fields[cfgCallbackScript] = cfg.CallbackScript
return c
}
@@ -90,11 +104,12 @@ func (c *configModel) HandleKey(msg tea.KeyMsg, m *Model) (tea.Model, tea.Cmd) {
case " ":
// Toggle boolean fields
if c.active == cfgShowSeconds {
if c.fields[cfgShowSeconds] == "true" {
c.fields[cfgShowSeconds] = "false"
if c.active == cfgShowSeconds || c.active == cfgCrescendoEnabled {
field := &c.fields[c.active]
if *field == "true" {
*field = "false"
} else {
c.fields[cfgShowSeconds] = "true"
*field = "true"
}
return *m, nil
}
@@ -106,7 +121,7 @@ func (c *configModel) HandleKey(msg tea.KeyMsg, m *Model) (tea.Model, tea.Cmd) {
default:
if len(key) == 1 {
// Don't allow free typing on boolean fields
if c.active == cfgShowSeconds {
if c.active == cfgShowSeconds || c.active == cfgCrescendoEnabled {
return *m, nil
}
c.fields[c.active] += key
@@ -159,6 +174,24 @@ func (c *configModel) save(m *Model) (tea.Model, tea.Cmd) {
return *m, nil
}
crescStartPct, err := strconv.Atoi(strings.TrimSpace(c.fields[cfgCrescendoStartPct]))
if err != nil || crescStartPct < 0 || crescStartPct > 100 {
c.err = "Crescendo start must be 0-100%"
return *m, nil
}
crescEndPct, err := strconv.Atoi(strings.TrimSpace(c.fields[cfgCrescendoEndPct]))
if err != nil || crescEndPct < 0 || crescEndPct > 150 {
c.err = "Crescendo end must be 0-150%"
return *m, nil
}
crescDuration, err := strconv.Atoi(strings.TrimSpace(c.fields[cfgCrescendoDurationS]))
if err != nil || crescDuration < 1 || crescDuration > 300 {
c.err = "Crescendo duration must be 1-300 seconds"
return *m, nil
}
cfg := db.Settings{
SnoozeMinutes: snooze,
TimeoutMinutes: timeout,
@@ -177,6 +210,12 @@ func (c *configModel) save(m *Model) (tea.Model, tea.Cmd) {
cfg.APIPassword = strings.TrimSpace(c.fields[cfgAPIPassword])
cfg.PollSeconds = pollSeconds
cfg.CrescendoEnabled = strings.TrimSpace(c.fields[cfgCrescendoEnabled]) == "true"
cfg.CrescendoStartPct = crescStartPct
cfg.CrescendoEndPct = crescEndPct
cfg.CrescendoDurationS = crescDuration
cfg.CallbackScript = strings.TrimSpace(c.fields[cfgCallbackScript])
if cfg.DefaultSound == "" {
cfg.DefaultSound = "default"
}
@@ -208,6 +247,11 @@ func (c *configModel) View() string {
"Server pass:",
"API password:",
"Poll (sec):",
"Enabled:",
"Start %:",
"End %:",
"Duration (s):",
"Script path:",
}
hints := [cfgFieldCount]string{
@@ -223,12 +267,31 @@ func (c *configModel) View() string {
"password to auth with server",
"password for incoming API requests",
"1-60, client poll frequency",
"space to toggle",
"0-100, starting volume",
"0-150, ending volume (>100 = overdrive)",
"1-300, ramp duration in seconds",
"called with: start|dismiss|snooze|timeout <name>",
}
// Section headers: field index -> section name
sections := map[cfgField]string{
cfgSnoozeMinutes: "─── Alarm ───",
cfgBlinkOnMs: "─── Display ───",
cfgServerURL: "─── Network ───",
cfgCrescendoEnabled: "─── Crescendo (pactl) ───",
cfgCallbackScript: "─── Hooks ───",
}
var lines []string
lines = append(lines, TitleStyle.Render("Settings"), "")
for i := cfgField(0); i < cfgFieldCount; i++ {
// Insert section header if this field starts a new section
if section, ok := sections[i]; ok {
lines = append(lines, "", DividerStyle.Render(section))
}
labelStr := fmt.Sprintf("%15s", labels[i])
value := c.fields[i]