This commit is contained in:
2026-01-30 16:24:08 -08:00
parent e57dcf2190
commit 20045b8de8
5 changed files with 989 additions and 79 deletions

View File

@@ -3,9 +3,9 @@ from __future__ import annotations
from typing import Any, Dict, List, Optional
from textual.app import ComposeResult
from textual.containers import Container, Horizontal, ScrollableContainer, Vertical
from textual.containers import Container, Horizontal, ScrollableContainer
from textual.screen import ModalScreen
from textual.widgets import Static, Button, Checkbox
from textual.widgets import Static, Button, Checkbox, ListView, ListItem
from textual import work
from rich.text import Text
@@ -40,13 +40,13 @@ class MatrixRoomPicker(ModalScreen[List[str]]):
margin-bottom: 1;
}
#matrix-room-checklist {
#matrix-room-list {
padding: 0;
}
.matrix-room-row {
border-bottom: solid $surface;
padding: 0.5 0;
padding: 1 0;
align: left middle;
}
@@ -91,15 +91,17 @@ class MatrixRoomPicker(ModalScreen[List[str]]):
id="matrix-room-picker-hint",
)
with ScrollableContainer(id="matrix-room-scroll"):
yield Vertical(id="matrix-room-checklist")
yield ListView(id="matrix-room-list")
with Horizontal(id="matrix-room-actions"):
yield Button("Cancel", variant="error", id="matrix-room-cancel")
yield Button("Select All", id="matrix-room-select-all")
yield Button("Clear All", id="matrix-room-clear")
yield Button("Save defaults", variant="success", id="matrix-room-save")
yield Static("Loading rooms...", id="matrix-room-status")
def on_mount(self) -> None:
self._status_widget = self.query_one("#matrix-room-status", Static)
self._checklist = self.query_one("#matrix-room-checklist", Vertical)
self._checklist = self.query_one("#matrix-room-list", ListView)
self._save_button = self.query_one("#matrix-room-save", Button)
if self._save_button:
self._save_button.disabled = True
@@ -110,10 +112,35 @@ class MatrixRoomPicker(ModalScreen[List[str]]):
self._set_status("Loading rooms...")
self._load_rooms_background()
def on_list_view_selected(self, event: ListView.Selected) -> None:
"""Intercept ListView.Selected events and prevent them from bubbling up
to parent components which may react (e.g., the main config modal).
Selecting an item should not implicitly close the picker or change the
outer editor state."""
try:
# Stop propagation so parent handlers (ConfigModal) don't react.
event.stop()
except Exception:
pass
def _set_status(self, text: str) -> None:
if self._status_widget:
self._status_widget.update(text)
def on_checkbox_changed(self, event: Checkbox.Changed) -> None:
# Enable Save only when at least one checkbox is selected
any_selected = False
for checkbox_id in self._checkbox_map.keys():
try:
cb = self.query_one(f"#{checkbox_id}", Checkbox)
if cb.value:
any_selected = True
break
except Exception:
continue
if self._save_button:
self._save_button.disabled = not any_selected
def _render_rooms(self, rooms: List[Dict[str, Any]]) -> None:
if not self._checklist:
return
@@ -130,22 +157,20 @@ class MatrixRoomPicker(ModalScreen[List[str]]):
room_id = str(room.get("room_id") or "").strip()
name = str(room.get("name") or "").strip()
checkbox_id = f"matrix-room-{idx}"
# Prefer display name; otherwise fall back to room id
label_text = name or room_id or "Matrix Room"
checkbox = Checkbox(
"",
label_text,
id=checkbox_id,
value=bool(room_id and room_id in self._existing_ids),
)
self._checkbox_map[checkbox_id] = room_id
label = Text(name or room_id or "Matrix Room")
label.stylize("bold")
label.append("\n")
label.append(room_id or "(no id)", style="dim")
list_item = ListItem(checkbox, classes="matrix-room-row")
self._checklist.mount(list_item)
row = Horizontal(classes="matrix-room-row")
self._checklist.mount(row)
row.mount(checkbox)
row.mount(Static(label, classes="matrix-room-meta"))
self._set_status("Loaded rooms. Select one or more and save.")
if self._save_button:
self._save_button.disabled = False
@@ -167,10 +192,40 @@ class MatrixRoomPicker(ModalScreen[List[str]]):
self._save_button.disabled = True
return
self._render_rooms(rooms)
# Ensure save button is enabled only if at least one checkbox is selected
any_selected = False
for cbid in self._checkbox_map.keys():
try:
cb = self.query_one(f"#{cbid}", Checkbox)
if cb.value:
any_selected = True
break
except Exception:
continue
if self._save_button:
self._save_button.disabled = not any_selected
def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "matrix-room-cancel":
self.dismiss([])
elif event.button.id == "matrix-room-select-all":
for checkbox_id in self._checkbox_map.keys():
try:
cb = self.query_one(f"#{checkbox_id}", Checkbox)
cb.value = True
except Exception:
pass
if self._save_button:
self._save_button.disabled = False
elif event.button.id == "matrix-room-clear":
for checkbox_id in self._checkbox_map.keys():
try:
cb = self.query_one(f"#{checkbox_id}", Checkbox)
cb.value = False
except Exception:
pass
if self._save_button:
self._save_button.disabled = True
elif event.button.id == "matrix-room-save":
selected: List[str] = []
for checkbox_id, room_id in self._checkbox_map.items():