diff --git a/emmental/tracklist/__init__.py b/emmental/tracklist/__init__.py index c544350..5126790 100644 --- a/emmental/tracklist/__init__.py +++ b/emmental/tracklist/__init__.py @@ -33,11 +33,13 @@ class Card(Gtk.Box): self._unselect = Gtk.Button(icon_name="edit-select-none-symbolic", has_frame=False, sensitive=False) self._loop = buttons.LoopButton() + self._shuffle = buttons.ShuffleButton() self._top_left.append(self._visible_cols) self._top_left.append(self._unselect) self._top_right.append(self._loop) + self._top_right.append(self._shuffle) self._top_box.set_start_widget(self._top_left) self._top_box.set_center_widget(self._filter) @@ -52,6 +54,7 @@ class Card(Gtk.Box): self._filter.connect("search-changed", self.__search_changed) self._unselect.connect("clicked", self.__clear_selection) self._loop.connect("notify::state", self.__update_loop_state) + self._shuffle.connect("notify::active", self.__update_shuffle_state) self.add_css_class("card") @@ -64,16 +67,24 @@ class Card(Gtk.Box): self._loop.state = playlist.loop case "playlist": self.__set_button_state() + case "shuffle": + self._shuffle.active = playlist.shuffle def __set_button_state(self) -> None: can_disable = self.playlist.playlist != self.sql.playlists.collection self._loop.can_disable = can_disable self._loop.state = self.playlist.loop + self._shuffle.active = self.playlist.shuffle def __update_loop_state(self, loop: buttons.LoopButton, param) -> None: if self.playlist.loop != loop.state: self.playlist.loop = loop.state + def __update_shuffle_state(self, shuffle: buttons.ShuffleButton, + param) -> None: + if self.playlist.shuffle != shuffle.active: + self.playlist.shuffle = shuffle.active + def __search_changed(self, filter: entry.Filter) -> None: self.sql.tracks.filter(filter.get_query()) diff --git a/emmental/tracklist/buttons.py b/emmental/tracklist/buttons.py index f988443..852e278 100644 --- a/emmental/tracklist/buttons.py +++ b/emmental/tracklist/buttons.py @@ -84,3 +84,18 @@ class LoopButton(buttons.ImageToggle): case ("Track", _): self.active = True self.icon_opacity = 1.0 + + +class ShuffleButton(buttons.ImageToggle): + """A button for setting Shuffle state of a Playlist.""" + + def __init__(self, **kwargs): + """Initialize a Shuffle Button.""" + super().__init__(active_icon_name="media-playlist-shuffle", + inactive_icon_name="media-playlist-consecutive", + icon_size=Gtk.IconSize.NORMAL, icon_opacity=0.5, + has_frame=False, **kwargs) + + def do_toggled(self): + """Adjust opacity when active state toggles.""" + self.icon_opacity = 1.0 if self.active else 0.5 diff --git a/tests/tracklist/test_buttons.py b/tests/tracklist/test_buttons.py index 6261a9d..68645cc 100644 --- a/tests/tracklist/test_buttons.py +++ b/tests/tracklist/test_buttons.py @@ -131,3 +131,29 @@ class TestLoopButton(unittest.TestCase): self.assertEqual(self.loop.state, "Track") self.loop.emit("clicked") self.assertEqual(self.loop.state, "Playlist") + + +class TestShuffleButtons(unittest.TestCase): + """Test the Shuffle button.""" + + def setUp(self): + """Set up common variables.""" + self.shuffle = emmental.tracklist.buttons.ShuffleButton() + + def test_init(self): + """Test that the shuffle button is configured correctly.""" + self.assertIsInstance(self.shuffle, emmental.buttons.ImageToggle) + self.assertEqual(self.shuffle.icon_size, Gtk.IconSize.NORMAL) + self.assertEqual(self.shuffle.active_icon_name, + "media-playlist-shuffle") + self.assertEqual(self.shuffle.inactive_icon_name, + "media-playlist-consecutive") + self.assertAlmostEqual(self.shuffle.icon_opacity, 0.5, delta=0.005) + self.assertFalse(self.shuffle.get_has_frame()) + + def test_opacity(self): + """Test adjusting the opacity based on active state.""" + self.shuffle.active = True + self.assertEqual(self.shuffle.icon_opacity, 1.0) + self.shuffle.active = False + self.assertEqual(self.shuffle.icon_opacity, 0.5) diff --git a/tests/tracklist/test_tracklist.py b/tests/tracklist/test_tracklist.py index b26cea9..f8273cf 100644 --- a/tests/tracklist/test_tracklist.py +++ b/tests/tracklist/test_tracklist.py @@ -116,6 +116,26 @@ class TestTracklist(tests.util.TestCase): self.tracklist._loop.state = "Playlist" self.assertEqual(self.playlist.loop, "Playlist") + def test_shuffle_button(self): + """Test the shuffle button.""" + self.assertIsInstance(self.tracklist._shuffle, + emmental.tracklist.buttons.ShuffleButton) + self.assertEqual(self.tracklist._loop.get_next_sibling(), + self.tracklist._shuffle) + + self.playlist.shuffle = True + self.tracklist.playlist = self.playlist + self.assertTrue(self.tracklist._shuffle.active) + + self.playlist.playlist = self.sql.playlists.collection + self.assertFalse(self.tracklist._shuffle.active) + + self.playlist.shuffle = True + self.assertTrue(self.tracklist._shuffle.active) + + self.tracklist._shuffle.active = False + self.assertFalse(self.playlist.shuffle) + def test_trackview(self): """Test the Trackview widget.""" self.assertIsInstance(self.tracklist._trackview,