91 lines
3.1 KiB
Python
91 lines
3.1 KiB
Python
"""One-line status / key hint bar."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, cast
|
|
|
|
from rich.cells import cell_len
|
|
from rich.console import RenderableType
|
|
from rich.text import Text
|
|
from textual.widget import Widget
|
|
|
|
from .common import compact_count, state_glyph, truncate
|
|
|
|
if TYPE_CHECKING:
|
|
from ..app import SomaFMApp
|
|
|
|
HINTS_LONG = (
|
|
"SPACE pause ↑↓ station ENTER tune +/- vol f ★ / filter "
|
|
"v visual r refresh ? help q quit"
|
|
)
|
|
HINTS_MEDIUM = (
|
|
"space pause · ↑↓ station · enter tune · +/- vol · f ★ · / filter · ? help · q quit"
|
|
)
|
|
HINTS_SHORT = "↑↓ station · space play · ? help · q quit"
|
|
|
|
|
|
class StatusBar(Widget):
|
|
can_focus = False
|
|
|
|
def render(self) -> RenderableType:
|
|
app = cast("SomaFMApp", self.app)
|
|
width = max(20, self.size.width)
|
|
glyph, colour = state_glyph(app.playing_state)
|
|
frame = app.spectrum.snapshot()
|
|
mpris = app.mpris.status_label
|
|
backend = app.player.backend or "no audio"
|
|
analyser = frame.label
|
|
|
|
listeners = ""
|
|
if app.current is not None and app.current.listeners:
|
|
listeners = f"♪ {compact_count(app.current.listeners)} "
|
|
state = app.playing_state
|
|
volume = f"vol {app.volume:>3}%"
|
|
|
|
# From most to least informative; pick the first combination that fits.
|
|
right_variants = (
|
|
f"{state} {listeners}{volume} {backend} mpris {mpris} {analyser}",
|
|
f"{state} {volume} {analyser}",
|
|
f"{state} {volume}",
|
|
volume,
|
|
)
|
|
options = (
|
|
(HINTS_LONG, right_variants[0]),
|
|
(HINTS_LONG, right_variants[1]),
|
|
(HINTS_MEDIUM, right_variants[0]),
|
|
(HINTS_MEDIUM, right_variants[1]),
|
|
(HINTS_SHORT, right_variants[1]),
|
|
(HINTS_SHORT, right_variants[2]),
|
|
(HINTS_SHORT, right_variants[3]),
|
|
)
|
|
|
|
chosen: tuple[int, str, str] | None = None
|
|
for hint, right_text in options:
|
|
right_width = cell_len(glyph) + 1 + cell_len(right_text)
|
|
if cell_len(hint) + right_width + 2 <= width:
|
|
chosen = (right_width, right_text, hint)
|
|
break
|
|
|
|
if chosen is None:
|
|
right_text = right_variants[-1]
|
|
right_width = cell_len(glyph) + 1 + cell_len(right_text)
|
|
if width <= right_width + 2:
|
|
line = Text(no_wrap=True)
|
|
line.append(
|
|
truncate(f"{glyph} {right_text}", width), style="dim"
|
|
)
|
|
return line
|
|
chosen = (right_width, right_text, "")
|
|
|
|
right_width, right_text, hint = chosen
|
|
left_width = max(0, width - right_width - 2)
|
|
left = app.notice or hint
|
|
left_style = "italic yellow" if app.notice else "dim"
|
|
|
|
line = Text(no_wrap=True)
|
|
line.append(truncate(left, left_width), style=left_style)
|
|
line.append(" " * max(0, width - left_width - right_width))
|
|
line.append(f"{glyph} ", style=f"bold {colour}")
|
|
line.append(right_text, style="dim")
|
|
return line
|