tracklist: Create an AlbumString TrackRow

This is an InscriptionRow that binds a Track's Album's property to the
Gtk.Inscription. I use it to display album artist and release information
in columns.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2023-01-17 11:22:37 -05:00
parent 1ffc300eda
commit b3dcd3c0b9
5 changed files with 106 additions and 4 deletions

View File

@ -14,6 +14,7 @@ class TrackRow(factory.ListRow):
property = GObject.Property(type=str)
mediumid = GObject.Property(type=int)
album_binding = GObject.Property(type=GObject.Binding)
def __init__(self, listitem: Gtk.ListItem, property: str):
"""Initialize a TrackRow."""
@ -26,10 +27,30 @@ class TrackRow(factory.ListRow):
self.bind_and_set(library, "online", self, "online")
self.bind_active("active")
def do_unbind(self) -> None:
"""Extra handling to make sure we unbind the album property."""
super().do_unbind()
if self.album_binding is not None:
self.album_binding.unbind()
self.album_binding = None
def bind_album(self, child_prop: str) -> None:
"""Bind an album property to the TrackRow child."""
album = self.item.get_medium().get_album()
self.child.set_property(child_prop, album.get_property(self.property))
self.album_binding = album.bind_property(self.property,
self.child, child_prop)
def bind_to_self(self, item_prop: str, child_prop: str) -> None:
"""Bind an item property directly to a TrackRow property."""
self.bind_and_set(self.item, item_prop, self, child_prop)
def rebind_album(self, child_prop: str) -> None:
"""Rebind an album property to the TrackRow child."""
if self.album_binding is not None:
self.album_binding.unbind()
self.bind_album(child_prop)
@GObject.Property(type=bool, default=False)
def active(self) -> bool:
"""Get the active state of this Row."""
@ -190,6 +211,23 @@ class TracknoString(InscriptionRow):
self.bind_to_self("number", "number")
class AlbumString(InscriptionRow):
"""A Track Row to display Album properties."""
def __init__(self, *args, **kwargs):
"""Initialize a AlbumString."""
super().__init__(*args, **kwargs)
self.connect("notify::mediumid", self.__update_album)
def __update_album(self, row: InscriptionRow, param) -> None:
self.rebind_album("text")
def do_bind(self) -> None:
"""Bind an album string to the AlbumString."""
super().do_bind()
self.bind_to_self("mediumid", "mediumid")
class FavoriteButton(TrackRow):
"""A TrackRow with an toggle to set Track favorite status."""

View File

@ -36,6 +36,10 @@ class TrackView(Gtk.Frame):
self.__append_column("Length", "length", row.LengthString,
xalign=1.0, numeric=True)
self.__append_column("Artist", "artist", row.TrackString, width=250)
self.__append_column("Album Artist", "artist", row.AlbumString,
width=250, visible=False)
self.__append_column("Release", "release", row.AlbumString,
width=115, numeric=True)
self.__append_column("Play Count", "playcount", row.PlayCountString,
width=135, numeric=True)
self.__append_column("Last Started", "laststarted",

View File

@ -126,6 +126,8 @@ class TestSettings(unittest.TestCase):
self.assertEqual(self.settings["tracklist.title.size"], 300)
self.assertEqual(self.settings["tracklist.length.size"], -1)
self.assertEqual(self.settings["tracklist.artist.size"], 250)
self.assertEqual(self.settings["tracklist.album-artist.size"], 250)
self.assertEqual(self.settings["tracklist.release.size"], 115)
self.assertEqual(self.settings["tracklist.play-count.size"], 135)
self.assertEqual(self.settings["tracklist.last-started.size"], 250)
self.assertEqual(self.settings["tracklist.last-played.size"], 250)
@ -139,6 +141,8 @@ class TestSettings(unittest.TestCase):
self.assertEqual(self.settings["tracklist.title.size"], 123)
self.assertEqual(self.settings["tracklist.length.size"], 123)
self.assertEqual(self.settings["tracklist.artist.size"], 123)
self.assertEqual(self.settings["tracklist.album-artist.size"], 123)
self.assertEqual(self.settings["tracklist.release.size"], 123)
self.assertEqual(self.settings["tracklist.play-count.size"], 123)
self.assertEqual(self.settings["tracklist.last-started.size"], 123)
self.assertEqual(self.settings["tracklist.last-played.size"], 123)
@ -151,6 +155,8 @@ class TestSettings(unittest.TestCase):
self.assertTrue(self.settings["tracklist.title.visible"])
self.assertTrue(self.settings["tracklist.length.visible"])
self.assertTrue(self.settings["tracklist.artist.visible"])
self.assertFalse(self.settings["tracklist.album-artist.visible"])
self.assertTrue(self.settings["tracklist.release.visible"])
self.assertTrue(self.settings["tracklist.play-count.visible"])
self.assertFalse(self.settings["tracklist.last-started.visible"])
self.assertTrue(self.settings["tracklist.last-played.visible"])
@ -164,6 +170,8 @@ class TestSettings(unittest.TestCase):
self.assertFalse(self.settings["tracklist.title.visible"])
self.assertFalse(self.settings["tracklist.length.visible"])
self.assertFalse(self.settings["tracklist.artist.visible"])
self.assertTrue(self.settings["tracklist.album-artist.visible"])
self.assertFalse(self.settings["tracklist.release.visible"])
self.assertFalse(self.settings["tracklist.play-count.visible"])
self.assertTrue(self.settings["tracklist.last-started.visible"])
self.assertFalse(self.settings["tracklist.last-played.visible"])

View File

@ -7,6 +7,7 @@ import emmental.factory
import emmental.tracklist.row
import tests.util
import unittest.mock
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import Adw
@ -37,6 +38,7 @@ class TestTrackRowWidgets(tests.util.TestCase):
"""Test the base Track Row."""
row = emmental.tracklist.row.TrackRow(self.listitem, "property")
self.assertIsInstance(row, emmental.factory.ListRow)
self.assertIsNone(row.album_binding)
self.assertEqual(row.property, "property")
self.assertEqual(row.mediumid, 0)
@ -148,6 +150,24 @@ class TestTrackRowWidgets(tests.util.TestCase):
self.track.mediumid = medium.mediumid
self.assertEqual(row.child.get_text(), "3-03")
def test_album_string(self):
"""Test the Album String widget."""
row = emmental.tracklist.row.AlbumString(self.listitem, "artist")
self.assertIsInstance(row, emmental.tracklist.row.InscriptionRow)
self.assertEqual(row.property, "artist")
row.bind()
self.assertIsInstance(row.album_binding, GObject.Binding)
self.assertEqual(row.child.get_text(), "Artist")
album = self.sql.albums.create("Other Album", "Other Artist", "2022")
medium = self.sql.media.create(album, "Other Medium", number=4)
self.track.mediumid = medium.mediumid
self.assertEqual(row.child.get_text(), "Other Artist")
row.unbind()
self.assertIsNone(row.album_binding)
def test_favorite_button(self):
"""Test the Favorite Button widget."""
row = emmental.tracklist.row.FavoriteButton(self.listitem, "favorite")

View File

@ -173,7 +173,39 @@ 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 = 5):
def test_album_artist_column(self, i: int = 5):
"""Test the album artist column."""
self.assertEqual(self.columns[i].get_title(), "Album Artist")
self.assertEqual(self.columns[i].get_fixed_width(), 250)
self.assertTrue(self.columns[i].get_resizable())
self.assertFalse(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.AlbumString)
factory.emit("setup", self.listitem)
self.assertEqual(self.listitem.listrow.property, "artist")
self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertFalse(self.listitem.listrow.child.has_css_class("numeric"))
def test_release_column(self, i: int = 6):
"""Test the release date column."""
self.assertEqual(self.columns[i].get_title(), "Release")
self.assertEqual(self.columns[i].get_fixed_width(), 115)
self.assertTrue(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.AlbumString)
factory.emit("setup", self.listitem)
self.assertEqual(self.listitem.listrow.property, "release")
self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0)
self.assertTrue(self.listitem.listrow.child.has_css_class("numeric"))
def test_playcount_column(self, i: int = 7):
"""Test the play count column."""
self.assertEqual(self.columns[i].get_title(), "Play Count")
self.assertEqual(self.columns[i].get_fixed_width(), 135)
@ -190,7 +222,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 = 6):
def test_last_started_column(self, i: int = 8):
"""Test the last started column."""
self.assertEqual(self.columns[i].get_title(), "Last Started")
self.assertEqual(self.columns[i].get_fixed_width(), 250)
@ -207,7 +239,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 = 7):
def test_last_played_column(self, i: int = 9):
"""Test the last played column."""
self.assertEqual(self.columns[i].get_title(), "Last Played")
self.assertEqual(self.columns[i].get_fixed_width(), 250)
@ -224,7 +256,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 = 8):
def test_filepath_column(self, i: int = 10):
"""Test the last played column."""
self.assertEqual(self.columns[i].get_title(), "Filepath")
self.assertEqual(self.columns[i].get_fixed_width(), -1)