app: debounce channel tree and cache render width
This commit is contained in:
@@ -25,6 +25,7 @@ VOLUME_STEPS = (0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0)
|
|||||||
RECONNECT_INITIAL = 2 # seconds before first retry
|
RECONNECT_INITIAL = 2 # seconds before first retry
|
||||||
RECONNECT_MAX = 30 # maximum backoff delay
|
RECONNECT_MAX = 30 # maximum backoff delay
|
||||||
RECONNECT_RETRIES = 10 # attempts before giving up
|
RECONNECT_RETRIES = 10 # attempts before giving up
|
||||||
|
TREE_DEBOUNCE = 0.1 # seconds to coalesce state changes
|
||||||
|
|
||||||
|
|
||||||
def _next_volume(current: float) -> float:
|
def _next_volume(current: float) -> float:
|
||||||
@@ -186,8 +187,7 @@ class ChannelTree(Static):
|
|||||||
for child in children:
|
for child in children:
|
||||||
self._collect_order(child.channel_id, order)
|
self._collect_order(child.channel_id, order)
|
||||||
|
|
||||||
@property
|
def _get_width(self) -> int:
|
||||||
def _available_width(self) -> int:
|
|
||||||
"""Usable character width (content area, excludes padding/border)."""
|
"""Usable character width (content area, excludes padding/border)."""
|
||||||
w = self.content_size.width
|
w = self.content_size.width
|
||||||
if w <= 0:
|
if w <= 0:
|
||||||
@@ -218,9 +218,10 @@ class ChannelTree(Static):
|
|||||||
if not self._channels:
|
if not self._channels:
|
||||||
return " Channels\n [dim]\u2514\u2500 (not connected)[/]"
|
return " Channels\n [dim]\u2514\u2500 (not connected)[/]"
|
||||||
|
|
||||||
|
w = self._get_width()
|
||||||
lines = [" [bold]Channels[/]"]
|
lines = [" [bold]Channels[/]"]
|
||||||
root_id = self._find_root()
|
root_id = self._find_root()
|
||||||
self._render_tree(root_id, lines, indent=1, is_last=True)
|
self._render_tree(root_id, lines, indent=1, is_last=True, w=w)
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
def _find_root(self) -> int:
|
def _find_root(self) -> int:
|
||||||
@@ -235,12 +236,11 @@ class ChannelTree(Static):
|
|||||||
lines: list[str],
|
lines: list[str],
|
||||||
indent: int,
|
indent: int,
|
||||||
is_last: bool,
|
is_last: bool,
|
||||||
|
w: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
ch = self._channels.get(channel_id)
|
ch = self._channels.get(channel_id)
|
||||||
if ch is None:
|
if ch is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
w = self._available_width
|
|
||||||
prefix = " " * indent
|
prefix = " " * indent
|
||||||
branch = "\u2514\u2500" if is_last else "\u251c\u2500"
|
branch = "\u2514\u2500" if is_last else "\u251c\u2500"
|
||||||
|
|
||||||
@@ -294,6 +294,7 @@ class ChannelTree(Static):
|
|||||||
lines,
|
lines,
|
||||||
indent + 2,
|
indent + 2,
|
||||||
is_last=i == len(children) - 1,
|
is_last=i == len(children) - 1,
|
||||||
|
w=w,
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_key(self, event: events.Key) -> None:
|
def on_key(self, event: events.Key) -> None:
|
||||||
@@ -412,6 +413,7 @@ class TuimbleApp(App):
|
|||||||
self._audio.input_gain = acfg.input_gain
|
self._audio.input_gain = acfg.input_gain
|
||||||
self._audio.output_gain = acfg.output_gain
|
self._audio.output_gain = acfg.output_gain
|
||||||
self._pending_reload: Config | None = None
|
self._pending_reload: Config | None = None
|
||||||
|
self._tree_refresh_timer = None
|
||||||
self._reconnecting: bool = False
|
self._reconnecting: bool = False
|
||||||
self._reconnect_attempt: int = 0
|
self._reconnect_attempt: int = 0
|
||||||
self._intentional_disconnect: bool = False
|
self._intentional_disconnect: bool = False
|
||||||
@@ -620,7 +622,11 @@ class TuimbleApp(App):
|
|||||||
chatlog.write(f"[#7aa2f7]{msg.sender}[/] {clean}")
|
chatlog.write(f"[#7aa2f7]{msg.sender}[/] {clean}")
|
||||||
|
|
||||||
def on_server_state_changed(self, _msg: ServerStateChanged) -> None:
|
def on_server_state_changed(self, _msg: ServerStateChanged) -> None:
|
||||||
self._refresh_channel_tree()
|
if self._tree_refresh_timer is not None:
|
||||||
|
self._tree_refresh_timer.stop()
|
||||||
|
self._tree_refresh_timer = self.set_timer(
|
||||||
|
TREE_DEBOUNCE, self._refresh_channel_tree,
|
||||||
|
)
|
||||||
|
|
||||||
def on_channel_selected(self, msg: ChannelSelected) -> None:
|
def on_channel_selected(self, msg: ChannelSelected) -> None:
|
||||||
if not self._client.connected:
|
if not self._client.connected:
|
||||||
|
|||||||
Reference in New Issue
Block a user