From 6bbc42319343e216fe3dc47296b31b542411f82e Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Sat, 22 Apr 2023 22:33:14 -0400 Subject: [PATCH] playlist: Give the Factory a next_track() function It takes an additional user= parameter to indicate if the user is asking for the next track or if it is coming from the audio player (such as an EOS / about-to-finish signal). This lets us handle the next_track() call slightly differently for the user case. Signed-off-by: Anna Schumaker --- emmental/playlist/__init__.py | 39 ++++++++++++++++++- tests/playlist/test_factory.py | 70 ++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) diff --git a/emmental/playlist/__init__.py b/emmental/playlist/__init__.py index 5f207c5..eeece53 100644 --- a/emmental/playlist/__init__.py +++ b/emmental/playlist/__init__.py @@ -19,6 +19,7 @@ class Factory(GObject.GObject): previous_playlist = GObject.Property(type=previous.Previous) visible_playlist = GObject.Property(type=playlist.Playlist) + can_go_next = GObject.Property(type=bool, default=False) can_go_previous = GObject.Property(type=bool, default=False) def __init__(self, sql: db.Connection): @@ -26,6 +27,8 @@ class Factory(GObject.GObject): super().__init__(sql=sql) self.sql.bind_property("active-playlist", self, "db-active") self.connect("notify", self.__notify_db_playlists) + self.sql.playlists.connect("notify::have-collection-tracks", + self.__update_can_go_next) def __get_playlists(self) -> list[playlist.Playlist]: plists = [self.active_playlist, self.previous_playlist, @@ -42,6 +45,14 @@ class Factory(GObject.GObject): if self.get_property(f"can-go-{which}") != newval: self.set_property(f"can-go-{which}", newval) + def __update_can_go_next(self, *args) -> None: + prev = self.previous_playlist + active = self.active_playlist + self.__update_can_go("next", + self.sql.playlists.have_collection_tracks or + (active is not None and active.can_go_next) or + (prev is not None and prev.can_go_forward)) + def __update_can_go_prev(self, *args) -> None: self.__update_can_go("previous", self.previous_playlist.can_go_next) @@ -50,13 +61,17 @@ class Factory(GObject.GObject): if db_plist == self.sql.playlists.previous: res = previous.Previous(self.sql, db_plist) res.connect("notify::can-go-next", self.__update_can_go_prev) - return res - return playlist.Playlist(self.sql, db_plist) + res.connect("notify::can-go-forward", self.__update_can_go_next) + else: + res = playlist.Playlist(self.sql, db_plist) + res.connect("notify::can-go-next", self.__update_can_go_next) + return res def __free_playlist(self, plist: playlist.Playlist) -> None: plist.playlist = None if isinstance(plist, previous.Previous): plist.disconnect_by_func(self.__update_can_go_prev) + plist.disconnect_by_func(self.__update_can_go_next) def __run_factory(self, label: str) -> None: db_plist = self.get_property(f"db-{label}") @@ -91,6 +106,26 @@ class Factory(GObject.GObject): case "db-visible": self.__run_factory("visible") + def next_track(self, *, user: bool = False) \ + -> tuple[db.tracks.Track | None, str, bool]: + """Get the next track.""" + track = None + restart = False + + if user is True: + track = self.previous_playlist.previous_track() + restart = track is not None + if track is None and self.active_playlist is not None: + track = self.active_playlist.next_track() + if track is None: + self.sql.set_active_playlist(self.sql.playlists.collection) + track = self.active_playlist.next_track() + + album = isinstance(self.db_active, db.albums.Album) or \ + isinstance(self.db_active, db.media.Medium) + rg_auto = "album" if album else "track" + return (track, rg_auto, restart) + def previous_track(self) -> tuple[db.tracks.Track | None, bool]: """Get the previous Track.""" if self.previous_playlist is None: diff --git a/tests/playlist/test_factory.py b/tests/playlist/test_factory.py index 354bca0..f7c5f3e 100644 --- a/tests/playlist/test_factory.py +++ b/tests/playlist/test_factory.py @@ -257,6 +257,27 @@ class TestFactoryNextPreviousTrack(tests.util.TestCase): self.medium, self.year, number=i) for i in range(1, 4)] + def test_can_go_next(self, mock_stdout: io.StringIO): + """Test the can-go-next property.""" + self.assertFalse(self.factory.can_go_next) + + self.sql.playlists.have_collection_tracks = True + self.assertTrue(self.factory.can_go_next) + self.sql.playlists.have_collection_tracks = False + self.assertFalse(self.factory.can_go_next) + + self.factory.db_active = self.user_plist + self.factory.active_playlist.can_go_next = True + self.assertTrue(self.factory.can_go_next) + self.factory.active_playlist.can_go_next = False + self.assertFalse(self.factory.can_go_next) + + self.factory.db_previous = self.sql.playlists.previous + self.factory.previous_playlist.can_go_forward = True + self.assertTrue(self.factory.can_go_next) + self.factory.previous_playlist.can_go_forward = False + self.assertFalse(self.factory.can_go_next) + def test_can_go_previous(self, mock_stdout: io.StringIO): """Test the can-go-previous property.""" self.assertFalse(self.factory.can_go_previous) @@ -273,6 +294,55 @@ class TestFactoryNextPreviousTrack(tests.util.TestCase): self.tracks[2].start() self.assertFalse(self.factory.can_go_previous) + def test_next_track(self, mock_stdout: io.StringIO): + """Test the next_track() function.""" + self.sql.set_active_playlist(None) + self.assertTupleEqual(self.factory.next_track(), + (None, "track", False)) + self.assertEqual(self.sql.active_playlist, + self.sql.playlists.collection) + + self.sql.set_active_playlist(self.user_plist) + self.user_plist.add_track(self.tracks[0]) + self.user_plist.add_track(self.tracks[1]) + self.assertTupleEqual(self.factory.next_track(), + (self.tracks[0], "track", False)) + self.assertTupleEqual(self.factory.next_track(), + (self.tracks[1], "track", False)) + + self.sql.playlists.collection.add_track(self.tracks[0]) + self.assertTupleEqual(self.factory.next_track(), + (self.tracks[0], "track", False)) + self.assertEqual(self.factory.db_active, + self.sql.playlists.collection) + self.assertEqual(self.sql.active_playlist, + self.sql.playlists.collection) + + self.album.add_track(self.tracks[2]) + self.factory.db_active = self.album + self.assertTupleEqual(self.factory.next_track(), + (self.tracks[2], "album", False)) + + self.medium.add_track(self.tracks[2]) + self.factory.db_active = self.medium + self.assertTupleEqual(self.factory.next_track(), + (self.tracks[2], "album", False)) + + def test_next_track_user(self, mock_stdout: io.StringIO): + """Test calling next_track() with user=True.""" + self.factory.db_active = self.user_plist + self.factory.db_previous = self.sql.playlists.previous + + self.user_plist.add_track(self.tracks[2]) + self.tracks[0].start() + self.tracks[1].start() + self.factory.previous_track() + + self.assertEqual(self.factory.next_track(user=True), + (self.tracks[1], "track", True)) + self.assertEqual(self.factory.next_track(user=True), + (self.tracks[2], "track", False)) + def test_previous_track(self, mock_stdout: io.StringIO): """Test the previous_track() function.""" self.assertIsNone(self.factory.previous_track())