diff --git a/app/models.py b/app/models.py
index e6a96ac..238e71a 100644
--- a/app/models.py
+++ b/app/models.py
@@ -233,6 +233,19 @@ class Playlists(dbtables.PlaylistsTable):
select(cls).where(cls.is_template.is_(True)).order_by(cls.name)
).all()
+ @classmethod
+ def get_favourite_templates(cls, session: Session) -> Sequence["Playlists"]:
+ """Returns a list of favourite templates ordered by name"""
+
+ return session.scalars(
+ select(cls)
+ .where(
+ cls.is_template.is_(True),
+ cls.favourite.is_(True)
+ )
+ .order_by(cls.name)
+ ).all()
+
@classmethod
def get_closed(cls, session: Session) -> Sequence["Playlists"]:
"""Returns a list of all closed playlists ordered by last use"""
@@ -287,7 +300,7 @@ class Playlists(dbtables.PlaylistsTable):
) -> None:
"""Save passed playlist as new template"""
- template = Playlists(session, template_name)
+ template = Playlists(session, template_name, template_id=0)
if not template or not template.id:
return
@@ -582,7 +595,7 @@ class PlaylistRows(dbtables.PlaylistRowsTable):
class Settings(dbtables.SettingsTable):
- def __init__(self, session: Session, name: str):
+ def __init__(self, session: Session, name: str) -> None:
self.name = name
session.add(self)
session.commit()
@@ -610,7 +623,7 @@ class Tracks(dbtables.TracksTable):
fade_at: int,
silence_at: int,
bitrate: int,
- ):
+ ) -> None:
self.path = path
self.title = title
self.artist = artist
diff --git a/app/musicmuster.py b/app/musicmuster.py
index 95f094d..bdf0cdf 100755
--- a/app/musicmuster.py
+++ b/app/musicmuster.py
@@ -601,6 +601,61 @@ class Window(QMainWindow):
self.load_last_playlists()
self.stop_autoplay = False
+ # # # # # # # # # # Overrides # # # # # # # # # #
+
+ def closeEvent(self, event: Optional[QCloseEvent]) -> None:
+ """Handle attempt to close main window"""
+
+ if not event:
+ return
+
+ # Don't allow window to close when a track is playing
+ if track_sequence.current and track_sequence.current.is_playing():
+ event.ignore()
+ helpers.show_warning(
+ self, "Track playing", "Can't close application while track is playing"
+ )
+ else:
+ with db.Session() as session:
+ # Save tab number of open playlists
+ open_playlist_ids: dict[int, int] = {}
+ for idx in range(self.playlist_section.tabPlaylist.count()):
+ open_playlist_ids[
+ self.playlist_section.tabPlaylist.widget(idx).playlist_id
+ ] = idx
+ Playlists.clear_tabs(session, list(open_playlist_ids.keys()))
+ for playlist_id, idx in open_playlist_ids.items():
+ playlist = session.get(Playlists, playlist_id)
+ if playlist:
+ log.debug(f"Set {playlist=} tab to {idx=}")
+ playlist.tab = idx
+
+ # Save window attributes
+ attributes_to_save = dict(
+ mainwindow_height=self.height(),
+ mainwindow_width=self.width(),
+ mainwindow_x=self.x(),
+ mainwindow_y=self.y(),
+ active_tab=self.playlist_section.tabPlaylist.currentIndex(),
+ )
+ for name, value in attributes_to_save.items():
+ record = Settings.get_setting(session, name)
+ record.f_int = value
+
+ session.commit()
+
+ event.accept()
+
+ # # # # # # # # # # Internal utility functions # # # # # # # # # #
+
+ def active_base_model(self) -> PlaylistModel:
+ return self.current.base_model
+
+ def active_tab(self) -> PlaylistTab:
+ return self.playlist_section.tabPlaylist.currentWidget()
+
+ # # # # # # # # # # Menu functions # # # # # # # # # #
+
def create_action(
self, text: str, handler: Callable, shortcut: Optional[str] = None
) -> QAction:
@@ -921,12 +976,6 @@ class Window(QMainWindow):
QMessageBox.StandardButton.Ok,
)
- def active_base_model(self) -> PlaylistModel:
- return self.current.base_model
-
- def active_tab(self) -> PlaylistTab:
- return self.playlist_section.tabPlaylist.currentWidget()
-
def clear_next(self) -> None:
"""
Clear next track
@@ -945,49 +994,6 @@ class Window(QMainWindow):
# Clear the search bar
self.search_playlist_clear()
- def closeEvent(self, event: Optional[QCloseEvent]) -> None:
- """Handle attempt to close main window"""
-
- if not event:
- return
-
- # Don't allow window to close when a track is playing
- if track_sequence.current and track_sequence.current.is_playing():
- event.ignore()
- helpers.show_warning(
- self, "Track playing", "Can't close application while track is playing"
- )
- else:
- with db.Session() as session:
- # Save tab number of open playlists
- open_playlist_ids: dict[int, int] = {}
- for idx in range(self.playlist_section.tabPlaylist.count()):
- open_playlist_ids[
- self.playlist_section.tabPlaylist.widget(idx).playlist_id
- ] = idx
- Playlists.clear_tabs(session, list(open_playlist_ids.keys()))
- for playlist_id, idx in open_playlist_ids.items():
- playlist = session.get(Playlists, playlist_id)
- if playlist:
- log.debug(f"Set {playlist=} tab to {idx=}")
- playlist.tab = idx
-
- # Save window attributes
- attributes_to_save = dict(
- mainwindow_height=self.height(),
- mainwindow_width=self.width(),
- mainwindow_x=self.x(),
- mainwindow_y=self.y(),
- active_tab=self.playlist_section.tabPlaylist.currentIndex(),
- )
- for name, value in attributes_to_save.items():
- record = Settings.get_setting(session, name)
- record.f_int = value
-
- session.commit()
-
- event.accept()
-
def close_playlist_tab(self) -> bool:
"""
Close active playlist tab, called by menu item
@@ -1985,54 +1991,6 @@ class Window(QMainWindow):
self.active_tab().scroll_to_top(playlist_track.row_number)
- def solicit_template_to_use(
- self, session: Session, template_prmompt: Optional[str] = None
- ) -> Optional[int]:
- """
- Have user select a template. Return the template.id, or None if they cancel.
- template_id of zero means don't use a template.
- """
-
- template_name_id_list: list[tuple[str, int]] = []
- template_name_id_list.append((Config.NO_TEMPLATE_NAME, 0))
-
- with db.Session() as session:
- for template in Playlists.get_all_templates(session):
- template_name_id_list.append((template.name, template.id))
-
- dlg = TemplateSelectorDialog(template_name_id_list, template_prmompt)
- if not dlg.exec() or dlg.selected_id is None:
- return None # User cancelled
-
- return dlg.selected_id
-
- def solicit_playlist_name(
- self, session: Session, default: str = "", prompt: str = "Playlist name:"
- ) -> Optional[str]:
- """Get name of new playlist from user"""
-
- dlg = QInputDialog(self)
- dlg.setInputMode(QInputDialog.InputMode.TextInput)
- dlg.setLabelText(prompt)
- while True:
- if default:
- dlg.setTextValue(default)
- dlg.resize(500, 100)
- ok = dlg.exec()
- if ok:
- proposed_name = dlg.textValue()
- if Playlists.name_is_available(session, proposed_name):
- return proposed_name
- else:
- helpers.show_warning(
- self,
- "Name in use",
- f"There's already a playlist called '{proposed_name}'",
- )
- continue
- else:
- return None
-
def stop(self) -> None:
"""Stop playing immediately"""
diff --git a/app/ui/main_window_playlist.ui b/app/ui/main_window_playlist.ui
index 6bcee88..4b8fb1a 100644
--- a/app/ui/main_window_playlist.ui
+++ b/app/ui/main_window_playlist.ui
@@ -7,7 +7,7 @@
0
0
1249
- 499
+ 538