107 lines
3.4 KiB
Python
107 lines
3.4 KiB
Python
"""Session browser dialog — lists sessions, supports load and delete."""
|
|
|
|
import json
|
|
import logging
|
|
|
|
import gi
|
|
gi.require_version("Gtk", "4.0")
|
|
gi.require_version("Adw", "1")
|
|
from gi.repository import Gtk, Adw, GObject
|
|
|
|
from cht.stream.manager import list_sessions, delete_sessions
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class SessionDialog(Adw.Window):
|
|
"""Modal dialog listing sessions. Emits 'session-selected' with session id."""
|
|
|
|
__gsignals__ = {
|
|
"session-selected": (GObject.SignalFlags.RUN_FIRST, None, (str,)),
|
|
}
|
|
|
|
def __init__(self, parent, **kwargs):
|
|
super().__init__(transient_for=parent, modal=True, **kwargs)
|
|
self.set_title("Load Session")
|
|
self.set_default_size(500, 400)
|
|
|
|
sessions = list_sessions()
|
|
|
|
toolbar = Adw.ToolbarView()
|
|
header = Adw.HeaderBar()
|
|
|
|
select_all_btn = Gtk.CheckButton(label="All")
|
|
header.pack_start(select_all_btn)
|
|
|
|
delete_btn = Gtk.Button(label="Delete")
|
|
delete_btn.add_css_class("destructive-action")
|
|
header.pack_end(delete_btn)
|
|
|
|
toolbar.add_top_bar(header)
|
|
|
|
scroll = Gtk.ScrolledWindow()
|
|
scroll.set_vexpand(True)
|
|
listbox = Gtk.ListBox()
|
|
listbox.set_selection_mode(Gtk.SelectionMode.NONE)
|
|
listbox.add_css_class("boxed-list")
|
|
|
|
checks: list[tuple[str, Gtk.CheckButton]] = []
|
|
|
|
for sid, sdir in sessions:
|
|
idx = sdir / "frames" / "index.json"
|
|
nframes = 0
|
|
try:
|
|
nframes = len(json.loads(idx.read_text()))
|
|
except Exception:
|
|
pass
|
|
nrec = len(list((sdir / "stream").glob("recording_*.mp4")))
|
|
|
|
check = Gtk.CheckButton()
|
|
checks.append((sid, check))
|
|
|
|
row = Adw.ActionRow()
|
|
row.set_title(sid)
|
|
row.set_subtitle(f"{nframes} frames, {nrec} segments")
|
|
row.set_activatable(True)
|
|
row.add_prefix(check)
|
|
|
|
def _on_row_activated(r, s=sid):
|
|
self.close()
|
|
self.emit("session-selected", s)
|
|
row.connect("activated", _on_row_activated)
|
|
listbox.append(row)
|
|
|
|
def _on_select_all(btn):
|
|
active = btn.get_active()
|
|
for _, cb in checks:
|
|
cb.set_active(active)
|
|
select_all_btn.connect("toggled", _on_select_all)
|
|
|
|
def _on_delete(btn):
|
|
to_delete = [sid for sid, cb in checks if cb.get_active()]
|
|
if not to_delete:
|
|
return
|
|
if self._current_session in to_delete:
|
|
to_delete.remove(self._current_session)
|
|
if to_delete:
|
|
delete_sessions(to_delete)
|
|
self.close()
|
|
# Re-open with updated list
|
|
new_dialog = SessionDialog(self.get_transient_for())
|
|
new_dialog._current_session = self._current_session
|
|
# Forward the signal
|
|
new_dialog.connect("session-selected",
|
|
lambda d, s: self.emit("session-selected", s))
|
|
new_dialog.present()
|
|
delete_btn.connect("clicked", _on_delete)
|
|
|
|
scroll.set_child(listbox)
|
|
toolbar.set_content(scroll)
|
|
self.set_content(toolbar)
|
|
|
|
self._current_session = None
|
|
|
|
def set_current_session(self, session_id: str | None) -> None:
|
|
"""Set the active session id so it won't be deleted."""
|
|
self._current_session = session_id
|