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 import pathlib
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Gtk from gi.repository import Gtk
from .. import buttons
from .. import factory from .. import factory
@ -157,3 +158,20 @@ class PathString(InscriptionRow):
def path(self, newval: pathlib.Path) -> None: def path(self, newval: pathlib.Path) -> None:
self.__path = newval self.__path = newval
self.child.set_text(str(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) model=self._selection)
self._scrollwin = Gtk.ScrolledWindow(child=self._columnview) 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("Title", "title", row.TrackString, width=300)
self.__append_column("Length", "length", row.LengthString, self.__append_column("Length", "length", row.LengthString,
xalign=1.0, numeric=True) xalign=1.0, numeric=True)
@ -51,10 +53,10 @@ class TrackView(Gtk.Frame):
def __append_column(self, title: str, property: str, row_type: type, def __append_column(self, title: str, property: str, row_type: type,
*, width: int = -1, visible: bool = True, *, width: int = -1, visible: bool = True,
**kwargs) -> None: resizable: bool = True, **kwargs) -> None:
fctry = factory.Factory(row_type=row_type, property=property, **kwargs) fctry = factory.Factory(row_type=row_type, property=property, **kwargs)
col = Gtk.ColumnViewColumn(title=title, factory=fctry, visible=visible, col = Gtk.ColumnViewColumn(title=title, factory=fctry, visible=visible,
resizable=True, fixed_width=width) resizable=resizable, fixed_width=width)
self._columnview.append_column(col) self._columnview.append_column(col)
def __runtime_changed(self, selection: Gtk.MultiSelection, 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): def test_save_tracklist_column_width(self, mock_stdout: io.StringIO):
"""Test saving tracklist column widths.""" """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.title.size"], 300)
self.assertEqual(self.settings["tracklist.length.size"], -1) self.assertEqual(self.settings["tracklist.length.size"], -1)
self.assertEqual(self.settings["tracklist.artist.size"], 250) self.assertEqual(self.settings["tracklist.artist.size"], 250)
@ -132,6 +133,7 @@ class TestSettings(unittest.TestCase):
for column in self.win.tracklist.columns: for column in self.win.tracklist.columns:
column.set_fixed_width(123) 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.title.size"], 123)
self.assertEqual(self.settings["tracklist.length.size"], 123) self.assertEqual(self.settings["tracklist.length.size"], 123)
self.assertEqual(self.settings["tracklist.artist.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): def test_save_tracklist_column_visible(self, mock_stdout: io.StringIO):
"""Test saving tracklist column visibility.""" """Test saving tracklist column visibility."""
self.assertTrue(self.settings["tracklist.fav.visible"])
self.assertTrue(self.settings["tracklist.title.visible"]) self.assertTrue(self.settings["tracklist.title.visible"])
self.assertTrue(self.settings["tracklist.length.visible"]) self.assertTrue(self.settings["tracklist.length.visible"])
self.assertTrue(self.settings["tracklist.artist.visible"]) self.assertTrue(self.settings["tracklist.artist.visible"])
@ -153,6 +156,7 @@ class TestSettings(unittest.TestCase):
for column in self.win.tracklist.columns: for column in self.win.tracklist.columns:
column.set_visible(not column.get_visible()) 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.title.visible"])
self.assertFalse(self.settings["tracklist.length.visible"]) self.assertFalse(self.settings["tracklist.length.visible"])
self.assertFalse(self.settings["tracklist.artist.visible"]) self.assertFalse(self.settings["tracklist.artist.visible"])

View File

@ -17,7 +17,7 @@ class TestTrackRowWidgets(tests.util.TestCase):
def setUp(self): def setUp(self):
"""Set up common variables.""" """Set up common variables."""
super().setUp() super().setUp()
self.sql.playlists.load() self.sql.playlists.load(now=True)
self.library = self.sql.libraries.create(pathlib.Path("/a/b")) self.library = self.sql.libraries.create(pathlib.Path("/a/b"))
self.album = self.sql.albums.create("Test Album", "Artist", "2023") self.album = self.sql.albums.create("Test Album", "Artist", "2023")
self.medium = self.sql.media.create(self.album, "", number=1) 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.track.length = 123.84
self.assertEqual(row.child.get_text(), "2:04") 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): def test_timestamp_string(self):
"""Test the TimestampString widget.""" """Test the TimestampString widget."""
row = emmental.tracklist.row.TimestampString(self.listitem, row = emmental.tracklist.row.TimestampString(self.listitem,
@ -145,3 +128,25 @@ class TestTrackRowWidgets(tests.util.TestCase):
row.bind() row.bind()
self.assertEqual(row.child.get_text(), str(pathlib.Path("/a/b/1.ogg"))) 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.columns = self.trackview.columns
self.listitem = Gtk.ListItem() 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.""" """Test the title column."""
self.assertEqual(self.columns[i].get_title(), "Title") self.assertEqual(self.columns[i].get_title(), "Title")
self.assertEqual(self.columns[i].get_fixed_width(), 300) 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.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertFalse(self.listitem.listrow.child.has_css_class("numeric")) 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.""" """Test the length column."""
self.assertEqual(self.columns[i].get_title(), "Length") self.assertEqual(self.columns[i].get_title(), "Length")
self.assertEqual(self.columns[i].get_fixed_width(), -1) 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.assertEqual(self.listitem.listrow.child.get_xalign(), 1.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric")) 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.""" """Test the artist column."""
self.assertEqual(self.columns[i].get_title(), "Artist") self.assertEqual(self.columns[i].get_title(), "Artist")
self.assertEqual(self.columns[i].get_fixed_width(), 250) 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.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertFalse(self.listitem.listrow.child.has_css_class("numeric")) 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.""" """Test the play count column."""
self.assertEqual(self.columns[i].get_title(), "Play Count") self.assertEqual(self.columns[i].get_title(), "Play Count")
self.assertEqual(self.columns[i].get_fixed_width(), 135) 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.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric")) 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.""" """Test the last started column."""
self.assertEqual(self.columns[i].get_title(), "Last Started") self.assertEqual(self.columns[i].get_title(), "Last Started")
self.assertEqual(self.columns[i].get_fixed_width(), 250) 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.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric")) 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.""" """Test the last played column."""
self.assertEqual(self.columns[i].get_title(), "Last Played") self.assertEqual(self.columns[i].get_title(), "Last Played")
self.assertEqual(self.columns[i].get_fixed_width(), 250) 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.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric")) 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.""" """Test the last played column."""
self.assertEqual(self.columns[i].get_title(), "Filepath") self.assertEqual(self.columns[i].get_title(), "Filepath")
self.assertEqual(self.columns[i].get_fixed_width(), -1) self.assertEqual(self.columns[i].get_fixed_width(), -1)