diff --git a/app/helpers.py b/app/helpers.py index 6da20db..298934d 100644 --- a/app/helpers.py +++ b/app/helpers.py @@ -9,14 +9,14 @@ from tinytag import TinyTag # type: ignore from typing import Optional # from typing import Dict, Optional, Union from typing import Dict, Union -# -# -# def ask_yes_no(title: str, question: str) -> bool: -# """Ask question; return True for yes, False for no""" -# -# button_reply: bool = QMessageBox.question(None, title, question) -# -# return button_reply == QMessageBox.Yes + + +def ask_yes_no(title: str, question: str) -> bool: + """Ask question; return True for yes, False for no""" + + button_reply = QMessageBox.question(None, title, question) + + return button_reply == QMessageBox.Yes def fade_point( diff --git a/app/musicmuster.py b/app/musicmuster.py index c2d1015..8d48e70 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -6,7 +6,7 @@ import sys import threading from datetime import datetime, timedelta -from typing import List +from typing import List, Optional from PyQt5.QtCore import QDate, QEvent, Qt, QTime, QTimer from PyQt5.QtGui import QColor @@ -384,6 +384,13 @@ class Window(QMainWindow, Ui_MainWindow): self.stop_playing(fade=True) + def get_one_track(self, session: Session) -> Optional[Tracks]: + """Show dialog box to select one track and return it to caller""" + + dlg = DbDialog(self, session, get_one_track=True) + if dlg.exec(): + return dlg.ui.track + def hide_played(self): """Toggle hide played tracks""" @@ -476,7 +483,7 @@ class Window(QMainWindow, Ui_MainWindow): """Show dialog box to select and add track from database""" with Session() as session: - dlg = DbDialog(self, session) + dlg = DbDialog(self, session, get_one_track=False) dlg.exec() def load_last_playlists(self) -> None: @@ -922,11 +929,19 @@ class Window(QMainWindow, Ui_MainWindow): class DbDialog(QDialog): """Select track from database""" - def __init__(self, parent: QMainWindow, session: Session) -> None: - """Subclassed QDialog to manage track selection""" + def __init__(self, parent: QMainWindow, session: Session, + get_one_track: bool = False) -> None: + """ + Subclassed QDialog to manage track selection + + If get_one_track is True, return after first track selection + with that track in ui.track. Otherwise, allow multiple tracks + to be added to the playlist. + """ super().__init__(parent) self.session = session + self.get_one_track = get_one_track self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.btnAdd.clicked.connect(self.add_selected) @@ -936,6 +951,7 @@ class DbDialog(QDialog): self.ui.matchList.itemSelectionChanged.connect(self.selection_changed) self.ui.radioTitle.toggled.connect(self.title_artist_toggle) self.ui.searchString.textEdited.connect(self.chars_typed) + self.ui.track = None record = Settings.get_int_settings(self.session, "dbdialog_width") width = record.f_int or 800 @@ -968,11 +984,16 @@ class DbDialog(QDialog): """Handle Add and Close button""" self.add_selected() - self.close() + self.accept() def add_track(self, track: Tracks) -> None: """Add passed track to playlist on screen""" + if self.get_one_track: + self.ui.track = track + self.accept() + return + self.parent().visible_playlist_tab().insert_track(self.session, track) # Commit session to get correct row numbers if more tracks added self.session.commit() diff --git a/app/playlists.py b/app/playlists.py index 28ac3bb..7f44c13 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -30,6 +30,7 @@ from PyQt5.QtWidgets import ( from config import Config from dbconfig import Session from helpers import ( + ask_yes_no, file_is_readable, get_relative_date, ms_to_mmss, @@ -306,7 +307,8 @@ class PlaylistTab(QTableWidget): # Add track to section header (ie, make this a track # row) act_add_track = self.menu.addAction('Add track') - act_add_track.triggered.connect(self._add_track) + act_add_track.triggered.connect( + lambda: self._add_track(row_number)) if not current and not next_row: # Remove row @@ -320,7 +322,6 @@ class PlaylistTab(QTableWidget): act_move.triggered.connect(self.musicmuster.move_selected) self.menu.addSeparator() - return super(PlaylistTab, self).eventFilter(source, event) def mouseReleaseEvent(self, event): @@ -601,7 +602,7 @@ class PlaylistTab(QTableWidget): # Make empty items (row background won't be coloured without # items present). Any notes should displayed starting in # column 0 - for i in range(2, len(columns) - 1): + for i in range(2, len(columns)): self.setItem(row, i, QTableWidgetItem()) notes_item = QTableWidgetItem(row_data.note) self.setItem(row, 1, notes_item) @@ -1103,7 +1104,32 @@ class PlaylistTab(QTableWidget): def _add_track(self, row: int) -> None: """Add a track to a section header making it a normal track row""" - print("playlists._add_track() not yet implemented") + with Session() as session: + track = self.musicmuster.get_one_track(session) + if not track: + return + + # Add track to playlist row + plr = session.get(PlaylistRows, self._get_playlistrow_id(row)) + plr.track_id = track.id + session.commit() + # Update attributes of row + self.item(row, columns["userdata"].idx).setData( + self.ROW_TRACK_ID, track.id) + self.item(row, columns["start_gap"].idx).setText( + str(track.start_gap)) + self.item(row, columns["title"].idx).setText(str(track.title)) + self.item(row, columns["artist"].idx).setText(str(track.artist)) + self.item(row, columns["duration"].idx).setText( + ms_to_mmss(track.duration)) + last_playtime = Playdates.last_played(session, track.id) + last_played_str = get_relative_date(last_playtime) + self.item(row, columns['lastplayed'].idx).setText(last_played_str) + + # Reset row span + self.setSpan(row, 1, 1, 1) + + self.update_display(session) def _calculate_end_time(self, start: Optional[datetime], duration: int) -> Optional[datetime]: @@ -1181,6 +1207,14 @@ class PlaylistTab(QTableWidget): # Delete rows from database plr_ids = self.get_selected_playlistrow_ids() + + # Get confirmation + row_count = len(plr_ids) + plural = 's' if row_count > 1 else '' + if not ask_yes_no("Delete rows", + f"Really delete {row_count} row{plural}?"): + return + with Session() as session: PlaylistRows.delete_rows(session, plr_ids) @@ -1513,6 +1547,11 @@ class PlaylistTab(QTableWidget): def _remove_track(self, row: int) -> None: """Remove track from row, making it a section header""" + # Get confirmation + if not ask_yes_no("Remove music", + "Really remove the music track from this row?"): + return + # Update playlist_rows record with Session() as session: plr = session.get(PlaylistRows, self._get_playlistrow_id(row))