app: add volume key bindings and status display

This commit is contained in:
Username
2026-02-24 14:17:02 +01:00
parent 5e44ee9e38
commit e9726da401

View File

@@ -20,6 +20,16 @@ from tuimble.ptt import KittyPtt, TogglePtt, detect_backend
log = logging.getLogger(__name__)
VOLUME_STEPS = (0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0)
def _next_volume(current: float) -> float:
"""Cycle through VOLUME_STEPS, wrapping to 0.0 after max."""
for step in VOLUME_STEPS:
if step > current + 0.01:
return step
return VOLUME_STEPS[0]
# -- custom messages (pymumble thread -> Textual) ----------------------------
@@ -63,6 +73,14 @@ class StatusBar(Static):
connected = reactive(False)
self_deaf = reactive(False)
server_info = reactive("")
output_vol = reactive(100)
input_vol = reactive(100)
@staticmethod
def _vol_bar(pct: int) -> str:
"""Compact 4-char volume indicator using block chars."""
filled = round(pct / 25)
return "\u2588" * filled + "\u2591" * (4 - filled)
def render(self) -> str:
w = self.content_size.width if self.content_size.width > 0 else 80
@@ -88,8 +106,14 @@ class StatusBar(Static):
return f" {conn_sym} {deaf_sym}{ptt_sym}"
if w < 60:
return f" {conn_full} {deaf_full}{' ' if deaf_full else ''}{ptt_full}"
vol = (
f" [dim]out[/]{self._vol_bar(self.output_vol)}"
f" [dim]in[/]{self._vol_bar(self.input_vol)}"
)
info = f" [dim]{self.server_info}[/]" if self.server_info else ""
return f" {conn_full} {deaf_full}{' ' if deaf_full else ''}{ptt_full}{info}"
deaf = f"{deaf_full} " if deaf_full else ""
return f" {conn_full} {deaf}{ptt_full}{vol}{info}"
class ChannelTree(Static):
@@ -345,6 +369,8 @@ class TuimbleApp(App):
BINDINGS = [
("f1", "toggle_deaf", "Deafen"),
("f2", "cycle_output_volume", "Vol Out"),
("f3", "cycle_input_volume", "Vol In"),
("q", "quit", "Quit"),
("ctrl+c", "quit", "Quit"),
]
@@ -388,6 +414,10 @@ class TuimbleApp(App):
yield Footer()
def on_mount(self) -> None:
status = self.query_one("#status", StatusBar)
status.output_vol = int(self._audio.output_gain * 100)
status.input_vol = int(self._audio.input_gain * 100)
chatlog = self.query_one("#chatlog", ChatLog)
chatlog.write("[dim]tuimble v0.1.0[/dim]")
srv = self._config.server
@@ -550,6 +580,28 @@ class TuimbleApp(App):
else:
chatlog.write("[#9ece6a]\u2713 undeafened[/]")
# -- volume ---------------------------------------------------------------
def action_cycle_output_volume(self) -> None:
"""Cycle output volume through preset steps."""
vol = _next_volume(self._audio.output_gain)
self._audio.output_gain = vol
pct = int(vol * 100)
status = self.query_one("#status", StatusBar)
status.output_vol = pct
chatlog = self.query_one("#chatlog", ChatLog)
chatlog.write(f"[dim]output volume {pct}%[/dim]")
def action_cycle_input_volume(self) -> None:
"""Cycle input volume through preset steps."""
vol = _next_volume(self._audio.input_gain)
self._audio.input_gain = vol
pct = int(vol * 100)
status = self.query_one("#status", StatusBar)
status.input_vol = pct
chatlog = self.query_one("#chatlog", ChatLog)
chatlog.write(f"[dim]input volume {pct}%[/dim]")
# -- PTT -----------------------------------------------------------------
def on_key(self, event: events.Key) -> None: