Windows
This commit is contained in:
@@ -104,26 +104,25 @@ pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
[], # ← onedir: ingen binaries/datas her
|
||||
exclude_binaries=True, # ← onedir: binaries samles i COLLECT
|
||||
name='LineDancePlayer',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[
|
||||
'vcruntime140.dll',
|
||||
'msvcp140.dll',
|
||||
'python3*.dll',
|
||||
'Qt6*.dll',
|
||||
],
|
||||
upx_exclude=['Qt6*.dll', 'python3*.dll', 'vcruntime140.dll'],
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=None,
|
||||
onefile=True,
|
||||
)
|
||||
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=['Qt6*.dll', 'python3*.dll', 'vcruntime140.dll'],
|
||||
name='LineDancePlayer',
|
||||
)
|
||||
|
||||
@@ -138,11 +138,20 @@ class LibraryPanel(QWidget):
|
||||
header.addWidget(btn_manage)
|
||||
layout.addLayout(header)
|
||||
|
||||
# Søgefelt
|
||||
# Søgefelt + checkbox
|
||||
search_row = QHBoxLayout()
|
||||
search_row.setSpacing(6)
|
||||
self._search = QLineEdit()
|
||||
self._search.setPlaceholderText("Søg i titel, artist, album, dans...")
|
||||
self._search.textChanged.connect(self._on_search_changed)
|
||||
layout.addWidget(self._search)
|
||||
search_row.addWidget(self._search)
|
||||
from PyQt6.QtWidgets import QCheckBox
|
||||
self._chk_alt = QCheckBox("Inkl. alt.")
|
||||
self._chk_alt.setToolTip("Søg også i alternativ-danse")
|
||||
self._chk_alt.setChecked(False)
|
||||
self._chk_alt.toggled.connect(self._on_search_changed)
|
||||
search_row.addWidget(self._chk_alt)
|
||||
layout.addLayout(search_row)
|
||||
|
||||
# Resultat-tæller + drag-hint
|
||||
hint_row = QHBoxLayout()
|
||||
@@ -190,7 +199,10 @@ class LibraryPanel(QWidget):
|
||||
|
||||
def _do_search(self):
|
||||
q = self._search.text().strip().lower()
|
||||
self._filtered = [s for s in self._all_songs if self._matches(s, q)] if q else list(self._all_songs)
|
||||
incl_alt = self._chk_alt.isChecked()
|
||||
self._filtered = [
|
||||
s for s in self._all_songs if self._matches(s, q, incl_alt)
|
||||
] if q else list(self._all_songs)
|
||||
total = len(self._all_songs)
|
||||
found = len(self._filtered)
|
||||
q_text = self._search.text().strip()
|
||||
@@ -200,25 +212,14 @@ class LibraryPanel(QWidget):
|
||||
)
|
||||
self._render()
|
||||
|
||||
def _matches(self, song: dict, q: str) -> bool:
|
||||
return any(q in f.lower() for f in [
|
||||
def _matches(self, song: dict, q: str, incl_alt: bool = False) -> bool:
|
||||
fields = [
|
||||
song.get("title", ""), song.get("artist", ""),
|
||||
song.get("album", ""), song.get("file_format", ""),
|
||||
] + song.get("dances", []))
|
||||
|
||||
def _render(self):
|
||||
self._list.clear()
|
||||
q = self._search.text().strip().lower()
|
||||
for song in self._filtered:
|
||||
dances = song.get("dances", [])
|
||||
dance_levels = song.get("dance_levels", [])
|
||||
missing = song.get("file_missing", False)
|
||||
|
||||
dance_parts = []
|
||||
for i, d in enumerate(dances):
|
||||
lvl = dance_levels[i] if i < len(dance_levels) else ""
|
||||
dance_parts.append(f"{d} / {lvl}" if lvl else d)
|
||||
dance_str = " · " + " | ".join(dance_parts) if dance_parts else ""
|
||||
] + song.get("dances", [])
|
||||
if incl_alt:
|
||||
fields += song.get("alt_dances", [])
|
||||
return any(q in f.lower() for f in fields)
|
||||
|
||||
def _render(self):
|
||||
self._list.clear()
|
||||
|
||||
@@ -287,10 +287,10 @@ class MainWindow(QMainWindow):
|
||||
b.setCheckable(True)
|
||||
return b
|
||||
|
||||
self._btn_prev = btn("⏮", size=52)
|
||||
self._btn_prev = btn("|◀◀", size=52)
|
||||
self._btn_play = btn("▶", "btn_play", size=72)
|
||||
self._btn_stop = btn("⏹", "btn_stop", size=52)
|
||||
self._btn_next = btn("⏭", size=52)
|
||||
self._btn_stop = btn("■", "btn_stop", size=52)
|
||||
self._btn_next = btn("▶▶|", size=52)
|
||||
self._btn_demo = btn(f"▶\n{self._demo_seconds} SEK", "btn_demo", size=64, checkable=True)
|
||||
|
||||
self._btn_prev.clicked.connect(self._prev_song)
|
||||
@@ -453,12 +453,15 @@ class MainWindow(QMainWindow):
|
||||
SELECT s.id, s.title, s.artist, s.album, s.bpm,
|
||||
s.duration_sec, s.local_path, s.file_format,
|
||||
s.file_missing,
|
||||
GROUP_CONCAT(d.name, '||') AS dance_names,
|
||||
GROUP_CONCAT(COALESCE(dl.name,''), '||') AS dance_levels
|
||||
GROUP_CONCAT(DISTINCT d.name) AS dance_names,
|
||||
GROUP_CONCAT(DISTINCT COALESCE(dl.name,'')) AS dance_levels,
|
||||
GROUP_CONCAT(DISTINCT ad.name) AS alt_dance_names
|
||||
FROM songs s
|
||||
LEFT JOIN song_dances sd ON sd.song_id = s.id
|
||||
LEFT JOIN dances d ON d.id = sd.dance_id
|
||||
LEFT JOIN dance_levels dl ON dl.id = d.level_id
|
||||
LEFT JOIN song_dances sd ON sd.song_id = s.id
|
||||
LEFT JOIN dances d ON d.id = sd.dance_id
|
||||
LEFT JOIN dance_levels dl ON dl.id = d.level_id
|
||||
LEFT JOIN song_alt_dances sad ON sad.song_id = s.id
|
||||
LEFT JOIN dances ad ON ad.id = sad.dance_id
|
||||
WHERE s.file_missing = 0
|
||||
GROUP BY s.id
|
||||
ORDER BY s.artist, s.title
|
||||
@@ -467,8 +470,9 @@ class MainWindow(QMainWindow):
|
||||
|
||||
songs = []
|
||||
for row in rows:
|
||||
dances = row["dance_names"].split("||") if row["dance_names"] else []
|
||||
levels = row["dance_levels"].split("||") if row["dance_levels"] else []
|
||||
dances = row["dance_names"].split(",") if row["dance_names"] else []
|
||||
levels = row["dance_levels"].split(",") if row["dance_levels"] else []
|
||||
alt_dances = row["alt_dance_names"].split(",") if row["alt_dance_names"] else []
|
||||
songs.append({
|
||||
"id": row["id"],
|
||||
"title": row["title"],
|
||||
@@ -481,6 +485,7 @@ class MainWindow(QMainWindow):
|
||||
"file_missing": bool(row["file_missing"]),
|
||||
"dances": dances,
|
||||
"dance_levels": levels,
|
||||
"alt_dances": alt_dances,
|
||||
})
|
||||
self._library_loaded.emit(songs)
|
||||
except Exception:
|
||||
|
||||
@@ -29,6 +29,16 @@ class DanceLineEdit(QLineEdit):
|
||||
|
||||
|
||||
class TagEditorDialog(QDialog):
|
||||
def keyPressEvent(self, event):
|
||||
"""Forhindre Enter i at lukke dialogen — bruges til at tilføje danse."""
|
||||
from PyQt6.QtCore import Qt as _Qt
|
||||
if event.key() in (_Qt.Key.Key_Return, _Qt.Key.Key_Enter):
|
||||
# Send Enter videre til det fokuserede widget i stedet for at lukke
|
||||
focused = self.focusWidget()
|
||||
if focused and focused is not self:
|
||||
focused.event(event)
|
||||
return
|
||||
super().keyPressEvent(event)
|
||||
def __init__(self, song: dict, parent=None):
|
||||
super().__init__(parent)
|
||||
self._song = song
|
||||
@@ -134,6 +144,7 @@ class TagEditorDialog(QDialog):
|
||||
# Forslags-liste
|
||||
self._dance_suggestions = QListWidget()
|
||||
self._dance_suggestions.setMaximumHeight(120)
|
||||
self._dance_suggestions.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||
self._dance_suggestions.itemClicked.connect(
|
||||
lambda item: self._add_from_suggestion(item, "dance")
|
||||
)
|
||||
@@ -152,7 +163,11 @@ class TagEditorDialog(QDialog):
|
||||
return grp
|
||||
|
||||
def _add_dance_row(self, name="", level_id=None):
|
||||
from translations import _
|
||||
try:
|
||||
from translations import _, translate_level
|
||||
except Exception:
|
||||
def _(key, **kw): return key.split(".")[-1]
|
||||
def translate_level(n): return n
|
||||
row_widget = QWidget()
|
||||
row_layout = QHBoxLayout(row_widget)
|
||||
row_layout.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -166,7 +181,6 @@ class TagEditorDialog(QDialog):
|
||||
level_cb = QComboBox()
|
||||
level_cb.addItem(_("tags.no_level"), None)
|
||||
for lvl in self._levels:
|
||||
from translations import translate_level
|
||||
level_cb.addItem(translate_level(lvl["name"]), lvl["id"])
|
||||
# Sæt til det rigtige niveau
|
||||
if level_id is not None:
|
||||
@@ -221,16 +235,18 @@ class TagEditorDialog(QDialog):
|
||||
pass
|
||||
|
||||
def _add_from_suggestion(self, item, panel: str):
|
||||
"""Tilføj dans fra forslags-listen ved dobbeltklik."""
|
||||
"""Tilføj dans fra forslags-listen ved klik."""
|
||||
name = item.data(Qt.ItemDataRole.UserRole + 1) or item.text().split(" / ")[0]
|
||||
level_id = item.data(Qt.ItemDataRole.UserRole)
|
||||
if panel == "dance":
|
||||
self._add_dance_row(name, level_id)
|
||||
self._new_dance.clear()
|
||||
self._new_dance.setFocus()
|
||||
self._load_dance_suggestions("", self._dance_suggestions)
|
||||
else:
|
||||
self._add_alt_row(name, level_id)
|
||||
self._new_alt.clear()
|
||||
self._new_alt.setFocus()
|
||||
self._load_dance_suggestions("", self._alt_suggestions)
|
||||
|
||||
def _on_add_dance(self):
|
||||
@@ -278,6 +294,7 @@ class TagEditorDialog(QDialog):
|
||||
|
||||
self._alt_suggestions = QListWidget()
|
||||
self._alt_suggestions.setMaximumHeight(120)
|
||||
self._alt_suggestions.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||
self._alt_suggestions.itemClicked.connect(
|
||||
lambda item: self._add_from_suggestion(item, "alt")
|
||||
)
|
||||
@@ -295,7 +312,11 @@ class TagEditorDialog(QDialog):
|
||||
return grp
|
||||
|
||||
def _add_alt_row(self, name="", level_id=None, note=""):
|
||||
from translations import _
|
||||
try:
|
||||
from translations import _, translate_level
|
||||
except Exception:
|
||||
def _(key, **kw): return key.split(".")[-1]
|
||||
def translate_level(n): return n
|
||||
row_widget = QWidget()
|
||||
row_layout = QHBoxLayout(row_widget)
|
||||
row_layout.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -313,7 +334,6 @@ class TagEditorDialog(QDialog):
|
||||
level_cb = QComboBox()
|
||||
level_cb.addItem(_("tags.no_level"), None)
|
||||
for lvl in self._levels:
|
||||
from translations import translate_level
|
||||
level_cb.addItem(translate_level(lvl["name"]), lvl["id"])
|
||||
if level_id is not None:
|
||||
for i in range(level_cb.count()):
|
||||
|
||||
Reference in New Issue
Block a user