Fixed dark and light themes, ui.theme auto/dark/light

Colors no longer come from the terminal's palette, whose color 0 many
color themes set to a grey that is not their background. A theme sets
tview's default styles and the color names used in texts, all chosen from
entries 16-255 of the 256-color table so terminals without 24-bit color
show them exactly. "auto" picks light or dark from the background color
the terminal reports. Settable in the Config view, applied at the next
start (widgets copy their colors when created). Replaces using the
terminal's own background and text colors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019reK4DUGYqDUjniWYJvwUW
This commit is contained in:
2026-10-21 12:05:00 +02:00
co-authored by Claude Opus 5.5
parent 08d3417b05
commit 820b17842b
20 changed files with 254 additions and 169 deletions
+8
View File
@@ -48,6 +48,9 @@ type UI struct {
// known to support it, else cells in macOS Terminal, sextant on terminals known to draw them or when
// fontconfig finds a font with the glyphs, else quadrant). The block styles are also the fallback for "kitty".
CoverStyle string `json:"cover_style,omitempty"`
// Theme selects the colors: "dark", "light" or "auto" (default: light when
// the terminal reports a light background, else dark).
Theme string `json:"theme,omitempty"`
}
// ShouldNotifyDownloads reports whether finished downloads are announced.
@@ -270,5 +273,10 @@ func (c *Config) Validate() error {
default:
errs = append(errs, fmt.Errorf(`ui.cover_style: %q must be "auto", "kitty", "sextant", "quadrant" or "cells"`, c.UI.CoverStyle))
}
switch c.UI.Theme {
case "", "auto", "dark", "light":
default:
errs = append(errs, fmt.Errorf(`ui.theme: %q must be "auto", "dark" or "light"`, c.UI.Theme))
}
return errors.Join(errs...)
}
+12
View File
@@ -110,6 +110,18 @@ func TestCoverStyleValidation(t *testing.T) {
}
}
func TestThemeValidation(t *testing.T) {
base := `{"radarr":{"url":"http://r","apikey":"k"},"sonarr":{"url":"http://s","apikey":"k"},"sabnzbd":{"url":"http://a","apikey":"k"},"ui":{"theme":`
for _, ok := range []string{`"auto"`, `"dark"`, `"light"`, `""`} {
if _, err := Parse([]byte(base + ok + `}}`)); err != nil {
t.Errorf("%s rejected: %v", ok, err)
}
}
if _, err := Parse([]byte(base + `"solarized"}}`)); err == nil {
t.Error("unknown theme accepted")
}
}
func TestSaveRoundTripAndPermissions(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "config.json")