tracklist: Create a FavoriteButton TrackRow

This button shows an ImageToggle button connected to the "favorite"
property of the Track.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2023-01-13 11:48:53 -05:00
parent 915a59a46b
commit bed518cd77
5 changed files with 71 additions and 27 deletions

View File

@ -5,6 +5,7 @@ import dateutil.tz
import pathlib
from gi.repository import GObject
from gi.repository import Gtk
from .. import buttons
from .. import factory
@ -157,3 +158,20 @@ class PathString(InscriptionRow):
def path(self, newval: pathlib.Path) -> None:
self.__path = newval
self.child.set_text(str(newval))
class FavoriteButton(TrackRow):
"""A TrackRow with an toggle to set Track favorite status."""
def __init__(self, listitem: Gtk.ListItem, property: str) -> None:
"""Initialize a Favorite Button."""
super().__init__(listitem, property=property)
self.child = buttons.ImageToggle("heart-filled", "heart-outline-thick",
icon_size=Gtk.IconSize.NORMAL,
valign=Gtk.Align.CENTER,
has_frame=False)
def do_bind(self):
"""Bind a track property to the Toggle Button."""
super().do_bind()
self.bind_and_set_property(self.property, "active", bidirectional=True)

View File

@ -28,6 +28,8 @@ class TrackView(Gtk.Frame):
model=self._selection)
self._scrollwin = Gtk.ScrolledWindow(child=self._columnview)
self.__append_column("Fav", "favorite", row.FavoriteButton,
resizable=False)
self.__append_column("Title", "title", row.TrackString, width=300)
self.__append_column("Length", "length", row.LengthString,
xalign=1.0, numeric=True)
@ -51,10 +53,10 @@ class TrackView(Gtk.Frame):
def __append_column(self, title: str, property: str, row_type: type,
*, width: int = -1, visible: bool = True,
**kwargs) -> None:
resizable: bool = True, **kwargs) -> None:
fctry = factory.Factory(row_type=row_type, property=property, **kwargs)
col = Gtk.ColumnViewColumn(title=title, factory=fctry, visible=visible,
resizable=True, fixed_width=width)
resizable=resizable, fixed_width=width)
self._columnview.append_column(col)
def __runtime_changed(self, selection: Gtk.MultiSelection,

View File

@ -121,6 +121,7 @@ class TestSettings(unittest.TestCase):
def test_save_tracklist_column_width(self, mock_stdout: io.StringIO):
"""Test saving tracklist column widths."""
self.assertEqual(self.settings["tracklist.fav.size"], -1)
self.assertEqual(self.settings["tracklist.title.size"], 300)
self.assertEqual(self.settings["tracklist.length.size"], -1)
self.assertEqual(self.settings["tracklist.artist.size"], 250)
@ -132,6 +133,7 @@ class TestSettings(unittest.TestCase):
for column in self.win.tracklist.columns:
column.set_fixed_width(123)
self.assertEqual(self.settings["tracklist.fav.size"], 123)
self.assertEqual(self.settings["tracklist.title.size"], 123)
self.assertEqual(self.settings["tracklist.length.size"], 123)
self.assertEqual(self.settings["tracklist.artist.size"], 123)
@ -142,6 +144,7 @@ class TestSettings(unittest.TestCase):
def test_save_tracklist_column_visible(self, mock_stdout: io.StringIO):
"""Test saving tracklist column visibility."""
self.assertTrue(self.settings["tracklist.fav.visible"])
self.assertTrue(self.settings["tracklist.title.visible"])
self.assertTrue(self.settings["tracklist.length.visible"])
self.assertTrue(self.settings["tracklist.artist.visible"])
@ -153,6 +156,7 @@ class TestSettings(unittest.TestCase):
for column in self.win.tracklist.columns:
column.set_visible(not column.get_visible())
self.assertFalse(self.settings["tracklist.fav.visible"])
self.assertFalse(self.settings["tracklist.title.visible"])
self.assertFalse(self.settings["tracklist.length.visible"])
self.assertFalse(self.settings["tracklist.artist.visible"])

View File

@ -17,7 +17,7 @@ class TestTrackRowWidgets(tests.util.TestCase):
def setUp(self):
"""Set up common variables."""
super().setUp()
self.sql.playlists.load()
self.sql.playlists.load(now=True)
self.library = self.sql.libraries.create(pathlib.Path("/a/b"))
self.album = self.sql.albums.create("Test Album", "Artist", "2023")
self.medium = self.sql.media.create(self.album, "", number=1)
@ -102,23 +102,6 @@ class TestTrackRowWidgets(tests.util.TestCase):
self.track.length = 123.84
self.assertEqual(row.child.get_text(), "2:04")
def test_playcount_string(self):
"""Test the PlayCountString widget."""
row = emmental.tracklist.row.PlayCountString(self.listitem,
"playcount")
self.assertIsInstance(row, emmental.tracklist.row.InscriptionRow)
self.assertEqual(row.property, "playcount")
self.assertEqual(row.playcount, 0)
row.bind()
self.assertEqual(row.child.get_text(), "Unplayed")
self.track.playcount = 1
self.assertEqual(row.child.get_text(), "Played 1 time")
self.track.playcount = 2
self.assertEqual(row.child.get_text(), "Played 2 times")
self.track.playcount = 3
self.assertEqual(row.child.get_text(), "Played 3 times")
def test_timestamp_string(self):
"""Test the TimestampString widget."""
row = emmental.tracklist.row.TimestampString(self.listitem,
@ -145,3 +128,25 @@ class TestTrackRowWidgets(tests.util.TestCase):
row.bind()
self.assertEqual(row.child.get_text(), str(pathlib.Path("/a/b/1.ogg")))
def test_favorite_button(self):
"""Test the Favorite Button widget."""
row = emmental.tracklist.row.FavoriteButton(self.listitem, "favorite")
self.assertIsInstance(row, emmental.tracklist.row.TrackRow)
self.assertIsInstance(row.child, emmental.buttons.ImageToggle)
self.assertEqual(row.property, "favorite")
self.assertEqual(row.child.active_icon_name, "heart-filled")
self.assertEqual(row.child.inactive_icon_name, "heart-outline-thick")
self.assertEqual(row.child.icon_size, Gtk.IconSize.NORMAL)
self.assertEqual(row.child.get_valign(), Gtk.Align.CENTER)
self.assertFalse(row.child.get_has_frame())
self.track.favorite = True
row.bind()
self.assertTrue(row.child.active)
self.track.favorite = False
self.assertFalse(row.child.active)
row.child.active = True
self.assertTrue(self.track.favorite)

View File

@ -93,7 +93,22 @@ class TestTrackViewColumns(tests.util.TestCase):
self.columns = self.trackview.columns
self.listitem = Gtk.ListItem()
def test_title_column(self, i: int = 0):
def test_favorite_column(self, i: int = 0):
"""Test the favorite column."""
self.assertEqual(self.columns[i].get_title(), "Fav")
self.assertEqual(self.columns[i].get_fixed_width(), -1)
self.assertFalse(self.columns[i].get_resizable())
self.assertTrue(self.columns[i].get_visible())
factory = self.columns[i].get_factory()
self.assertIsInstance(factory, emmental.factory.Factory)
self.assertEqual(factory.row_type,
emmental.tracklist.row.FavoriteButton)
factory.emit("setup", self.listitem)
self.assertEqual(self.listitem.listrow.property, "favorite")
def test_title_column(self, i: int = 1):
"""Test the title column."""
self.assertEqual(self.columns[i].get_title(), "Title")
self.assertEqual(self.columns[i].get_fixed_width(), 300)
@ -109,7 +124,7 @@ class TestTrackViewColumns(tests.util.TestCase):
self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertFalse(self.listitem.listrow.child.has_css_class("numeric"))
def test_length_column(self, i: int = 1):
def test_length_column(self, i: int = 2):
"""Test the length column."""
self.assertEqual(self.columns[i].get_title(), "Length")
self.assertEqual(self.columns[i].get_fixed_width(), -1)
@ -125,7 +140,7 @@ class TestTrackViewColumns(tests.util.TestCase):
self.assertEqual(self.listitem.listrow.child.get_xalign(), 1.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric"))
def test_artist_column(self, i: int = 2):
def test_artist_column(self, i: int = 3):
"""Test the artist column."""
self.assertEqual(self.columns[i].get_title(), "Artist")
self.assertEqual(self.columns[i].get_fixed_width(), 250)
@ -141,7 +156,7 @@ class TestTrackViewColumns(tests.util.TestCase):
self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertFalse(self.listitem.listrow.child.has_css_class("numeric"))
def test_playcount_column(self, i: int = 3):
def test_playcount_column(self, i: int = 4):
"""Test the play count column."""
self.assertEqual(self.columns[i].get_title(), "Play Count")
self.assertEqual(self.columns[i].get_fixed_width(), 135)
@ -158,7 +173,7 @@ class TestTrackViewColumns(tests.util.TestCase):
self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric"))
def test_last_started_column(self, i: int = 4):
def test_last_started_column(self, i: int = 5):
"""Test the last started column."""
self.assertEqual(self.columns[i].get_title(), "Last Started")
self.assertEqual(self.columns[i].get_fixed_width(), 250)
@ -175,7 +190,7 @@ class TestTrackViewColumns(tests.util.TestCase):
self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric"))
def test_last_played_column(self, i: int = 5):
def test_last_played_column(self, i: int = 6):
"""Test the last played column."""
self.assertEqual(self.columns[i].get_title(), "Last Played")
self.assertEqual(self.columns[i].get_fixed_width(), 250)
@ -192,7 +207,7 @@ class TestTrackViewColumns(tests.util.TestCase):
self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric"))
def test_filepath_column(self, i: int = 6):
def test_filepath_column(self, i: int = 7):
"""Test the last played column."""
self.assertEqual(self.columns[i].get_title(), "Filepath")
self.assertEqual(self.columns[i].get_fixed_width(), -1)