Files
LinedanceAfspiller/linedance-app/ui/playlist_info_dialog.py
2026-04-13 16:20:19 +02:00

167 lines
6.0 KiB
Python
Raw Permalink 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,
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("")