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 <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2023-04-22 22:33:14 -04:00
parent cf056d6ec5
commit 6bbc423193
2 changed files with 107 additions and 2 deletions

View File

@ -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:

View File

@ -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())