139 lines
4.9 KiB
Python
139 lines
4.9 KiB
Python
from PyQt5.QtWidgets import (
|
|
QAction,
|
|
QInputDialog,
|
|
QListWidget,
|
|
QMenu,
|
|
QMessageBox,
|
|
QTreeWidget,
|
|
QTreeWidgetItem,
|
|
)
|
|
from PyQt5.QtCore import pyqtSignal, Qt, QPoint
|
|
import DBA
|
|
from logging import debug
|
|
|
|
from components import CreatePlaylistWindow
|
|
|
|
|
|
class PlaylistWidgetItem(QTreeWidgetItem):
|
|
def __init__(self, parent, id, name):
|
|
super().__init__([name], 0)
|
|
self.id = id
|
|
|
|
|
|
# NOTE: ideas:
|
|
# auto sort list (alphabetical?)
|
|
# reorder list
|
|
# duplicate playlist
|
|
|
|
|
|
class PlaylistsPane(QTreeWidget):
|
|
playlistChoiceSignal = pyqtSignal(int)
|
|
playlistCreatedSignal = pyqtSignal()
|
|
allSongsSignal = pyqtSignal()
|
|
|
|
def __init__(self: QTreeWidget, parent=None):
|
|
super().__init__(parent)
|
|
self._library_root = QTreeWidgetItem(["Library"])
|
|
self._playlists_root: QTreeWidgetItem = QTreeWidgetItem(["Playlists"])
|
|
self.addTopLevelItem(self._library_root)
|
|
self.addTopLevelItem(self._playlists_root)
|
|
self.reload_playlists()
|
|
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
|
self.customContextMenuRequested.connect(self.showContextMenu)
|
|
self.currentItemChanged.connect(self.playlist_clicked)
|
|
self.playlist_db_id_choice: int | None = None
|
|
|
|
def reload_playlists(self):
|
|
"""
|
|
Clears and reinitializes the playlists tree
|
|
each playlist is a branch/child of root node `Playlists`
|
|
"""
|
|
# take all children away
|
|
self._playlists_root.takeChildren()
|
|
# NOTE: implement user sorting by adding a column to playlist db table for 'rank' or something
|
|
with DBA.DBAccess() as db:
|
|
playlists = db.query(
|
|
"SELECT id, name FROM playlist ORDER BY date_created DESC LIMIT 1;", ()
|
|
)
|
|
for playlist in playlists:
|
|
branch = PlaylistWidgetItem(self, playlist[0], playlist[1])
|
|
self._playlists_root.addChild(branch)
|
|
|
|
self._playlists_root.setExpanded(True)
|
|
|
|
def showContextMenu(self, position: QPoint):
|
|
"""Right-click context menu"""
|
|
menu = QMenu(self)
|
|
if self.playlist_db_id_choice is not None:
|
|
# only allow delete/rename non-root nodes
|
|
rename_action = QAction("Rename", self)
|
|
delete_action = QAction("Delete", self)
|
|
rename_action.triggered.connect(self.rename_playlist)
|
|
delete_action.triggered.connect(self.delete_playlist)
|
|
menu.addAction(rename_action)
|
|
menu.addAction(delete_action)
|
|
create_action = QAction("New playlist", self)
|
|
create_action.triggered.connect(self.create_playlist)
|
|
menu.addAction(create_action)
|
|
menu.exec_(self.mapToGlobal(position)) # Show the menu
|
|
|
|
def create_playlist(self):
|
|
"""Creates a database record for a playlist, given a name"""
|
|
window = CreatePlaylistWindow(self.playlistCreatedSignal)
|
|
window.playlistCreatedSignal.connect(self.reload_playlists) # type: ignore
|
|
window.exec_()
|
|
|
|
def rename_playlist(self, *args):
|
|
"""
|
|
Asks user for input
|
|
Renames selected playlist based on user input
|
|
"""
|
|
text, ok = QInputDialog.getText(
|
|
self, "Rename playlist", "New name: "
|
|
)
|
|
|
|
if len(text) > 64:
|
|
QMessageBox.warning(self, "WARNING", "Name must not exceed 64 characters")
|
|
return
|
|
if ok:
|
|
with DBA.DBAccess() as db:
|
|
db.execute(
|
|
"UPDATE playlist SET name = ? WHERE id = ?;",
|
|
(text, self.playlist_db_id_choice),
|
|
)
|
|
self.reload_playlists()
|
|
|
|
def delete_playlist(self, *args):
|
|
"""Deletes a playlist"""
|
|
reply = QMessageBox.question(
|
|
self,
|
|
"Confirmation",
|
|
"Really delete this playlist??",
|
|
QMessageBox.Yes | QMessageBox.No,
|
|
QMessageBox.Yes,
|
|
)
|
|
if reply == QMessageBox.Yes:
|
|
with DBA.DBAccess() as db:
|
|
db.execute(
|
|
"DELETE FROM playlist WHERE id = ?;", (self.playlist_db_id_choice,)
|
|
)
|
|
# reload
|
|
self.reload_playlists()
|
|
|
|
def playlist_clicked(self, item):
|
|
"""Specific playlist pane index was clicked"""
|
|
if item == self._playlists_root or item == self._library_root:
|
|
self.playlist_db_id_choice = None
|
|
# self.all_songs_selected()
|
|
self.allSongsSignal.emit()
|
|
elif isinstance(item, PlaylistWidgetItem):
|
|
debug(f"ID: {item.id}, name: {item.text(0)}")
|
|
self.playlist_db_id_choice = item.id
|
|
self.playlistChoiceSignal.emit(int(item.id))
|
|
|
|
# def all_songs_selected(self):
|
|
# """Emits a signal to display all songs in the library"""
|
|
# # I have no idea why this has to be in its own function, but it does
|
|
# # or else it doesn't work
|
|
# self.allSongsSignal.emit()
|