From d4d0344a12ed9c1fab070e09c5c2552451cf37fc Mon Sep 17 00:00:00 2001 From: Gene Johnson Date: Mon, 16 Mar 2026 02:58:18 -0700 Subject: [PATCH] feat: add pick_color_theme() UI and integration --- engine/app.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/engine/app.py b/engine/app.py index 6c22f25..1382692 100644 --- a/engine/app.py +++ b/engine/app.py @@ -10,7 +10,7 @@ import termios import time import tty -from engine import config, render +from engine import config, render, themes from engine.fetch import fetch_all, fetch_poetry, load_cache, save_cache from engine.mic import MicMonitor from engine.ntfy import NtfyPoller @@ -65,6 +65,28 @@ def _read_picker_key(): return None +def _draw_color_picker(themes_list, selected): + """Draw the color theme picker menu. + + Args: + themes_list: List of (theme_id, Theme) tuples from THEME_REGISTRY.items() + selected: Index of currently selected theme (0-2) + """ + print(CLR, end="") + print() + + print(f" {G_HI}▼ COLOR THEME{RST} {W_GHOST}─ ↑/↓ or j/k to move, Enter/q to select{RST}") + print(f" {W_GHOST}{'─' * (tw() - 4)}{RST}\n") + + for i, (theme_id, theme) in enumerate(themes_list): + prefix = " ▶ " if i == selected else " " + color = G_HI if i == selected else "" + reset = "" if i == selected else W_GHOST + print(f"{prefix}{color}{theme.name}{reset}") + + print() + + def _normalize_preview_rows(rows): """Trim shared left padding and trailing spaces for stable on-screen previews.""" non_empty = [r for r in rows if r.strip()] @@ -131,6 +153,50 @@ def _draw_font_picker(faces, selected): print(f" {shown}") +def pick_color_theme(): + """Interactive color theme picker. Defaults to 'green' if not TTY. + + Displays a menu of available themes and lets user select with arrow keys. + Non-interactive environments (piped stdin, CI) silently default to green. + """ + # Non-interactive fallback + if not sys.stdin.isatty(): + config.set_active_theme("green") + return + + # Interactive picker + themes_list = list(themes.THEME_REGISTRY.items()) + selected = 0 + + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setcbreak(fd) + while True: + _draw_color_picker(themes_list, selected) + key = _read_picker_key() + if key == "up": + selected = max(0, selected - 1) + elif key == "down": + selected = min(len(themes_list) - 1, selected + 1) + elif key == "enter": + break + elif key == "interrupt": + raise KeyboardInterrupt + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + + selected_theme_id = themes_list[selected][0] + config.set_active_theme(selected_theme_id) + + theme_name = themes_list[selected][1].name + print(f" {G_DIM}> using {theme_name}{RST}") + time.sleep(0.8) + print(CLR, end="") + print(CURSOR_OFF, end="") + print() + + def pick_font_face(): """Interactive startup picker for selecting a face from repo OTF files.""" if not config.FONT_PICKER: @@ -262,6 +328,7 @@ def main(): w = tw() print(CLR, end="") print(CURSOR_OFF, end="") + pick_color_theme() pick_font_face() w = tw() print()