musicmuster/app/dialogs.py
2025-04-12 11:15:21 +01:00

170 lines
4.9 KiB
Python

# Standard library imports
from typing import Optional
# PyQt imports
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (
QDialog,
QHBoxLayout,
QLabel,
QLineEdit,
QListWidget,
QListWidgetItem,
QMainWindow,
QPushButton,
QVBoxLayout,
)
# Third party imports
# App imports
from classes import ApplicationError, InsertTrack, MusicMusterSignals
from helpers import (
get_relative_date,
ms_to_mmss,
)
import ds
class TrackInsertDialog(QDialog):
def __init__(
self,
parent: QMainWindow,
playlist_id: int,
add_to_header: Optional[bool] = False,
) -> None:
"""
Subclassed QDialog to manage track selection
"""
super().__init__(parent)
self.playlist_id = playlist_id
self.add_to_header = add_to_header
self.setWindowTitle("Insert Track")
# Title input on one line
self.title_label = QLabel("Title:")
self.title_edit = QLineEdit()
self.title_edit.textChanged.connect(self.update_list)
title_layout = QHBoxLayout()
title_layout.addWidget(self.title_label)
title_layout.addWidget(self.title_edit)
# Track list
self.track_list = QListWidget()
self.track_list.itemDoubleClicked.connect(self.add_clicked)
self.track_list.itemSelectionChanged.connect(self.selection_changed)
# Note input on one line
self.note_label = QLabel("Note:")
self.note_edit = QLineEdit()
note_layout = QHBoxLayout()
note_layout.addWidget(self.note_label)
note_layout.addWidget(self.note_edit)
# Track path
self.path = QLabel()
path_layout = QHBoxLayout()
path_layout.addWidget(self.path)
# Buttons
self.add_btn = QPushButton("Add")
self.add_close_btn = QPushButton("Add and close")
self.close_btn = QPushButton("Close")
self.add_btn.clicked.connect(self.add_clicked)
self.add_close_btn.clicked.connect(self.add_and_close_clicked)
self.close_btn.clicked.connect(self.close)
btn_layout = QHBoxLayout()
btn_layout.addWidget(self.add_btn)
btn_layout.addWidget(self.add_close_btn)
btn_layout.addWidget(self.close_btn)
# Main layout
layout = QVBoxLayout()
layout.addLayout(title_layout)
layout.addWidget(self.track_list)
layout.addLayout(note_layout)
layout.addLayout(path_layout)
layout.addLayout(btn_layout)
self.setLayout(layout)
self.resize(800, 600)
width = ds.get_setting("dbdialog_width") or 800
height = ds.get_setting("dbdialog_height") or 800
self.resize(width, height)
self.signals = MusicMusterSignals()
def update_list(self, text: str) -> None:
self.track_list.clear()
if text.strip() == "":
# Do not search or populate list if input is empty
return
if text.startswith("a/") and len(text) > 2:
self.tracks = ds.tracks_by_artist(text[2:])
else:
self.tracks = ds.tracks_by_title(text)
for track in self.tracks:
duration_str = ms_to_mmss(track.duration)
last_played_str = get_relative_date(track.lastplayed)
item_str = (
f"{track.title} - {track.artist} [{duration_str}] {last_played_str}"
)
item = QListWidgetItem(item_str)
item.setData(Qt.ItemDataRole.UserRole, track.track_id)
self.track_list.addItem(item)
def get_selected_track_id(self) -> int | None:
selected_items = self.track_list.selectedItems()
if selected_items:
return selected_items[0].data(Qt.ItemDataRole.UserRole)
return None
def add_clicked(self):
track_id = self.get_selected_track_id()
note_text = self.note_edit.text()
if track_id is None and not note_text:
return
insert_track_data = InsertTrack(self.playlist_id, track_id, note_text)
self.title_edit.clear()
self.note_edit.clear()
self.track_list.clear()
self.title_edit.setFocus()
if self.add_to_header:
self.signals.signal_add_track_to_header.emit(insert_track_data)
self.accept()
else:
self.signals.signal_insert_track.emit(insert_track_data)
def add_and_close_clicked(self):
self.add_clicked()
self.accept()
def selection_changed(self) -> None:
"""Display selected track path in dialog box"""
self.path.setText("")
track_id = self.get_selected_track_id()
if track_id is None:
return
tracklist = [t for t in self.tracks if t.track_id == track_id]
if not tracklist:
return
if len(tracklist) > 1:
raise ApplicationError("More than one track returned")
track = tracklist[0]
self.path.setText(track.path)