Switch the theme live

Widgets copy their colors when they are created, so they now get role
tokens (one unique RGB value per role) instead of colors, and a wrapper
around the tcell screen replaces the tokens with the current theme's
colors in SetContent. Changing the theme in the Config view swaps that
table; the next draw recolors everything. Poster colors that equal a
token are nudged off it.

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:11:19 +02:00
co-authored by Claude Opus 5.5
parent 24f7c38a5b
commit 67f5cf6ce7
11 changed files with 171 additions and 38 deletions
+26 -1
View File
@@ -30,6 +30,8 @@ type view struct {
// App is the top-level arr-tui application.
type App struct {
app *tview.Application
theme theme // the colors in use
themed *themedScreen // draws with them; nil until Run
tabs *tview.TextView
pages *tview.Pages
status *tview.TextView
@@ -103,7 +105,7 @@ func New(cfg *config.Config) *App {
// Ask the terminal before the screen takes it over, and set the colors
// before any widget copies them.
th, themeNote := chooseTheme(cfg.UI.Theme, terminalAnswers())
th.apply()
useTokens()
a := &App{
app: tview.NewApplication(),
tabs: tview.NewTextView().SetDynamicColors(true),
@@ -140,6 +142,7 @@ func New(cfg *config.Config) *App {
if a.covers {
a.logs.add(levelInfo, coverNote)
}
a.theme = th
a.logs.add(levelInfo, themeNote)
sabClient := sabnzbd.NewClient(cfg.SABnzbd.URL, cfg.SABnzbd.APIKey)
a.sab = sabClient
@@ -394,12 +397,34 @@ func (a *App) Run() error {
a.gfx.deleteAll()
}
}()
// The screen draws through the theme (see themedScreen).
s, err := tcell.NewScreen()
if err != nil {
return err
}
a.themed = newThemedScreen(s, a.theme)
a.app.SetScreen(a.themed) // initializes it
if a.themed.initErr != nil {
return a.themed.initErr
}
a.themed.DisableMouse()
a.themed.DisablePaste()
go a.watchServices(stop)
a.setNotifyDownloads(a.notifyDone)
defer a.setNotifyDownloads(false)
return a.app.Run()
}
// setTheme switches the colors while the program runs.
func (a *App) setTheme(t theme, note string) {
a.theme = t
if a.themed != nil {
a.themed.setTheme(t)
}
a.logs.add(levelInfo, note)
}
// setNotifyDownloads starts or stops the background watch for finished downloads.
func (a *App) setNotifyDownloads(on bool) {
a.notifyDone = on