fix(ui): keep the help and catalogue menus inside the screen
This commit is contained in:
1 parent
43ddd8666b
commit
7ba2d50503
4 files changed
+151
-70
No files matched your search
@@ -5,11 +5,12 @@ from __future__ import annotations
|
||||
from rich.console import Group
|
||||
from rich.text import Text
|
||||
from textual.app import ComposeResult
|
||||
from textual.containers import VerticalScroll
|
||||
from textual.screen import ModalScreen
|
||||
from textual.widgets import Static
|
||||
|
||||
from ..providers import PROVIDERS, available_providers
|
||||
from .common import SPECTRUM_STOPS, gradient, truncate
|
||||
from .common import active_stops, gradient, truncate
|
||||
|
||||
|
||||
class ProviderScreen(ModalScreen[str | None]):
|
||||
@@ -22,12 +23,19 @@ class ProviderScreen(ModalScreen[str | None]):
|
||||
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")
|
||||
# A scroll container keeps thirteen catalogues navigable on a short
|
||||
# terminal; the body is given its exact line count so it measures.
|
||||
with VerticalScroll(id="providers"):
|
||||
yield Static(self._body(), id="providers-body")
|
||||
|
||||
def on_mount(self) -> None:
|
||||
body = self.query_one("#providers-body", Static)
|
||||
body.styles.height = len(self.slugs) + 5 # heading, blank, rows, footer
|
||||
|
||||
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("◤ ", style=f"bold {gradient(active_stops(self.app), 0.9)}")
|
||||
header.append("CATALOGUES", style=f"bold {gradient(active_stops(self.app), 0.55)}")
|
||||
header.append(" · pick a station catalogue", style="dim")
|
||||
|
||||
name_width = (
|
||||
@@ -55,26 +63,20 @@ class ProviderScreen(ModalScreen[str | None]):
|
||||
f"{truncate(provider.name, name_width - 2):<{name_width}}",
|
||||
style="bold underline" if selected else "bold",
|
||||
)
|
||||
row.append(truncate(provider.brand, 14), style="dim")
|
||||
row.append(" ")
|
||||
# marker(2) + number(5) + name + gap(2) + tagline + current dot(3)
|
||||
room = max(8, 58 - 2 - 5 - name_width - 2 - 3)
|
||||
row.append(truncate(provider.tagline, room), style="italic dim")
|
||||
if slug == self.current_id:
|
||||
row.append(" ●", style="bold green")
|
||||
rows.append(row)
|
||||
if selected:
|
||||
rows.append(
|
||||
Text(
|
||||
" " + truncate(provider.tagline, 54),
|
||||
style="italic dim",
|
||||
no_wrap=True,
|
||||
)
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
line = truncate(f"now: {current.name} — {current.station_source}", 58)
|
||||
footer.append(line + "\n", style="dim")
|
||||
footer.append(
|
||||
"↑ ↓ choose · enter switch · esc cancel",
|
||||
style="dim",
|
||||
@@ -85,7 +87,17 @@ class ProviderScreen(ModalScreen[str | None]):
|
||||
|
||||
def _move(self, delta: int) -> None:
|
||||
self.index = (self.index + delta) % len(self.slugs)
|
||||
self.query_one("#providers", Static).update(self._body())
|
||||
body = self.query_one("#providers-body", Static)
|
||||
body.update(self._body())
|
||||
|
||||
box = self.query_one("#providers", VerticalScroll)
|
||||
|
||||
def follow() -> None:
|
||||
visible = max(1, box.size.height)
|
||||
target = max(0, 2 + self.index - (visible - 3) // 2)
|
||||
box.scroll_to(y=target, animate=False)
|
||||
|
||||
box.call_after_refresh(follow)
|
||||
|
||||
def on_key(self, event) -> None:
|
||||
key = event.key
|
||||
|
||||
Reference in new issue
Block a user