""" playlist_info_dialog.py — Flydende danseliste-info vindue med dynamisk opdatering. """ from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QFrame, QGridLayout, ) from PyQt6.QtCore import Qt, pyqtSignal from datetime import datetime, timedelta def fmt_time(seconds: int) -> str: if seconds < 0: seconds = 0 h = seconds // 3600 m = (seconds % 3600) // 60 s = seconds % 60 if h > 0: return f"{h}:{m:02d}:{s:02d}" return f"{m}:{s:02d}" class PlaylistInfoWindow(QWidget): def __init__(self, playlist_panel, parent=None): super().__init__(parent, Qt.WindowType.Tool | Qt.WindowType.WindowStaysOnTopHint ) self._panel = playlist_panel self._pause_seconds = getattr(playlist_panel, "_pause_seconds", 60) self._workshop_seconds = getattr(playlist_panel, "_workshop_seconds", 600) self.setWindowTitle("Danseliste-info") self.setMinimumWidth(380) self.setFixedWidth(440) self._build_ui() self._update() playlist_panel.playlist_changed.connect(self._update) playlist_panel.status_changed.connect(lambda *_: self._update()) def moveEvent(self, event): from PyQt6.QtCore import QSettings QSettings("LineDance", "Player").setValue("window/info_pos", self.pos()) super().moveEvent(event) def _build_ui(self): layout = QVBoxLayout(self) layout.setContentsMargins(12, 12, 12, 12) layout.setSpacing(8) # Stats stats = QFrame() stats.setObjectName("track_display") grid = QGridLayout(stats) grid.setContentsMargins(12, 10, 12, 10) grid.setSpacing(5) grid.setColumnStretch(1, 1) def row(r, label, attr): l = QLabel(label) l.setObjectName("track_meta") grid.addWidget(l, r, 0) v = QLabel("—") v.setAlignment(Qt.AlignmentFlag.AlignRight) grid.addWidget(v, r, 1) setattr(self, attr, v) row(0, "Antal sange:", "_lbl_count") row(1, "Afspillet:", "_lbl_played") row(2, "Workshop:", "_lbl_ws") row(3, "Sprunget over:", "_lbl_skipped") row(4, "Tilbage:", "_lbl_remaining") sep = QFrame() sep.setFrameShape(QFrame.Shape.HLine) grid.addWidget(sep, 5, 0, 1, 2) row(6, "Musik-tid total:", "_lbl_music_total") row(7, "Musik-tid tilbage:", "_lbl_music_remain") row(8, "Pause-tid total:", "_lbl_pause_total") row(9, "Workshop-tid total:", "_lbl_ws_total") row(10, "Samlet tid total:", "_lbl_total") row(11, "Samlet tid tilbage:", "_lbl_total_remain") layout.addWidget(stats) # Fremgang og ETA eta_frame = QFrame() eta_frame.setObjectName("track_display") eta_layout = QVBoxLayout(eta_frame) eta_layout.setContentsMargins(12, 8, 12, 8) eta_layout.setSpacing(4) self._lbl_eta = QLabel("") self._lbl_eta.setWordWrap(True) self._lbl_eta.setAlignment(Qt.AlignmentFlag.AlignCenter) self._lbl_eta.setObjectName("track_title") eta_layout.addWidget(self._lbl_eta) self._lbl_finish = QLabel("") self._lbl_finish.setWordWrap(True) self._lbl_finish.setAlignment(Qt.AlignmentFlag.AlignCenter) self._lbl_finish.setObjectName("track_title") eta_layout.addWidget(self._lbl_finish) layout.addWidget(eta_frame) def _update(self): songs = self._panel.get_songs() statuses = self._panel.get_statuses() total = len(songs) played = statuses.count("played") skipped = statuses.count("skipped") done = played + skipped # samlet "overstået" remaining = total - done ws_total = sum(1 for s in songs if s.get("is_workshop")) ws_remain = sum(1 for s, st in zip(songs, statuses) if s.get("is_workshop") and st == "pending") music_total = sum(s.get("duration_sec", 0) for s in songs) music_remain = sum( s.get("duration_sec", 0) for s, st in zip(songs, statuses) if st == "pending" ) p = self._pause_seconds w = self._workshop_seconds pause_total = max(0, total - 1) * p pause_remain = max(0, remaining - 1) * p ws_time_total = ws_total * w ws_time_remain = ws_remain * w total_time = music_total + pause_total + ws_time_total remain_time = music_remain + pause_remain + ws_time_remain self._lbl_count.setText(str(total)) self._lbl_played.setText(str(played)) self._lbl_ws.setText(f"{ws_total} ({fmt_time(ws_time_total)})") self._lbl_skipped.setText(str(skipped)) self._lbl_remaining.setText(str(remaining)) self._lbl_music_total.setText(fmt_time(music_total)) self._lbl_music_remain.setText(fmt_time(music_remain)) self._lbl_pause_total.setText(f"{fmt_time(pause_total)} ({max(0,total-1)} × {p}s)") self._lbl_ws_total.setText(f"{fmt_time(ws_time_total)} ({ws_total} × {w//60}min)") self._lbl_total.setText(fmt_time(total_time)) self._lbl_total_remain.setText(fmt_time(remain_time)) # ETA if remaining == 0 and total > 0: self._lbl_eta.setText("✓ Danselisten er afsluttet!") self._lbl_finish.setText("") elif total > 0: pct = int(done / total * 100) if total > 0 else 0 self._lbl_eta.setText( f"{pct}% færdig · {fmt_time(remain_time)} tilbage" if done > 0 else f"Samlet varighed: {fmt_time(total_time)}" ) finish = datetime.now() + timedelta(seconds=remain_time) self._lbl_finish.setText(f"Estimeret sluttid: {finish.strftime('%H:%M')}") else: self._lbl_eta.setText("Ingen sange i listen") self._lbl_finish.setText("")