"""Catalogue picker: switch between SomaFM, tilderadio and whatever comes next.""" from __future__ import annotations from rich.console import Group from rich.text import Text from textual.app import ComposeResult from textual.screen import ModalScreen from textual.widgets import Static from ..providers import PROVIDERS, available_providers from .common import SPECTRUM_STOPS, gradient, truncate class ProviderScreen(ModalScreen[str | None]): """A list of catalogues; enter selects, esc leaves everything as it was.""" def __init__(self, current_id: str = "") -> None: super().__init__() self.slugs: tuple[str, ...] = available_providers() self.current_id = current_id self.index = self.slugs.index(current_id) if current_id in self.slugs else 0 def compose(self) -> ComposeResult: yield Static(self._body(), id="providers") def _body(self) -> Group: header = Text() header.append("◤ ", style=f"bold {gradient(SPECTRUM_STOPS, 0.9)}") header.append("CATALOGUES", style=f"bold {gradient(SPECTRUM_STOPS, 0.55)}") header.append(" pick a station catalogue", style="dim") rows: list[Text] = [] for index, slug in enumerate(self.slugs): provider = PROVIDERS[slug] selected = index == self.index row = Text(no_wrap=True) row.append("▶ " if selected else " ", style="bold magenta" if selected else "") row.append(f"{index + 1} ", style="dim") name_style = "bold underline" if selected else "bold" row.append(f"{provider.name:<12}", style=name_style) row.append(f" {provider.brand}", style="dim") if slug == self.current_id: row.append(" ●", style="bold green") rows.append(row) detail = Text(no_wrap=True) detail.append(" ", style="") detail.append(truncate(provider.tagline, 54), style="italic dim") rows.append(detail) current = PROVIDERS.get(self.current_id) footer = Text() footer.append("\n") if current is not None: footer.append( f"now: {current.name} — {current.station_source}\n", style="dim" ) footer.append( "↑ ↓ choose · 1–9 jump · enter switch · esc cancel", style="dim", ) return Group(header, Text(""), *rows, footer) # -- interaction ----------------------------------------------------- # def _move(self, delta: int) -> None: self.index = (self.index + delta) % len(self.slugs) self.query_one("#providers", Static).update(self._body()) def on_key(self, event) -> None: key = event.key if key in ("up", "k", "shift+tab"): self._move(-1) elif key in ("down", "j", "tab"): self._move(1) elif key in ("enter", "space"): self.dismiss(self.slugs[self.index]) elif key == "escape" or key == "q": self.dismiss(None) elif key.isdigit() and key != "0": choice = int(key) - 1 if 0 <= choice < len(self.slugs): self.dismiss(self.slugs[choice]) else: return event.stop()