Files
LinedanceAfspiller/linedance-app/ui/playlist_info_dialog.py
2026-04-12 10:25:41 +02:00

202 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
playlist_info_dialog.py — Flydende danseliste-info vindue med dynamisk opdatering.
"""
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSpinBox,
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):
pause_changed = pyqtSignal(int)
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 _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)
# Indstillinger
cfg = QFrame()
cfg.setObjectName("track_display")
cfg_layout = QGridLayout(cfg)
cfg_layout.setContentsMargins(12, 8, 12, 8)
cfg_layout.setSpacing(6)
cfg_layout.addWidget(QLabel("Tid mellem musikstykker:"), 0, 0)
self._spin_pause = QSpinBox()
self._spin_pause.setRange(0, 600)
self._spin_pause.setValue(self._pause_seconds)
self._spin_pause.setSuffix(" sek")
self._spin_pause.setFixedWidth(90)
self._spin_pause.valueChanged.connect(self._on_pause_changed)
cfg_layout.addWidget(self._spin_pause, 0, 1)
cfg_layout.addWidget(QLabel("Tid per workshop:"), 1, 0)
self._spin_ws = QSpinBox()
self._spin_ws.setRange(0, 120)
self._spin_ws.setValue(self._workshop_seconds // 60)
self._spin_ws.setSuffix(" min")
self._spin_ws.setFixedWidth(90)
self._spin_ws.valueChanged.connect(self._on_ws_changed)
cfg_layout.addWidget(self._spin_ws, 1, 1)
layout.addWidget(cfg)
# 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 _on_pause_changed(self, value: int):
self._pause_seconds = value
if hasattr(self._panel, "_pause_seconds"):
self._panel._pause_seconds = value
self.pause_changed.emit(value)
self._update()
def _on_ws_changed(self, minutes: int):
self._workshop_seconds = minutes * 60
if hasattr(self._panel, "_workshop_seconds"):
self._panel._workshop_seconds = self._workshop_seconds
self._update()
def _update(self):
songs = self._panel.get_songs()
statuses = self._panel.get_statuses()
total = len(songs)
played = statuses.count("played")
skipped = statuses.count("skipped")
remaining = total - played - skipped
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(played / total * 100) if total > 0 else 0
self._lbl_eta.setText(
f"{pct}% færdig · {fmt_time(remain_time)} tilbage"
if played > 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("")