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) property = GObject.Property(type=str)
mediumid = GObject.Property(type=int) mediumid = GObject.Property(type=int)
album_binding = GObject.Property(type=GObject.Binding)
def __init__(self, listitem: Gtk.ListItem, property: str): def __init__(self, listitem: Gtk.ListItem, property: str):
"""Initialize a TrackRow.""" """Initialize a TrackRow."""
@ -26,10 +27,30 @@ class TrackRow(factory.ListRow):
self.bind_and_set(library, "online", self, "online") self.bind_and_set(library, "online", self, "online")
self.bind_active("active") 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: def bind_to_self(self, item_prop: str, child_prop: str) -> None:
"""Bind an item property directly to a TrackRow property.""" """Bind an item property directly to a TrackRow property."""
self.bind_and_set(self.item, item_prop, self, child_prop) 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) @GObject.Property(type=bool, default=False)
def active(self) -> bool: def active(self) -> bool:
"""Get the active state of this Row.""" """Get the active state of this Row."""
@ -190,6 +211,23 @@ class TracknoString(InscriptionRow):
self.bind_to_self("number", "number") 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): class FavoriteButton(TrackRow):
"""A TrackRow with an toggle to set Track favorite status.""" """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, self.__append_column("Length", "length", row.LengthString,
xalign=1.0, numeric=True) xalign=1.0, numeric=True)
self.__append_column("Artist", "artist", row.TrackString, width=250) 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, self.__append_column("Play Count", "playcount", row.PlayCountString,
width=135, numeric=True) width=135, numeric=True)
self.__append_column("Last Started", "laststarted", 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.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)
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.play-count.size"], 135)
self.assertEqual(self.settings["tracklist.last-started.size"], 250) self.assertEqual(self.settings["tracklist.last-started.size"], 250)
self.assertEqual(self.settings["tracklist.last-played.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.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)
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.play-count.size"], 123)
self.assertEqual(self.settings["tracklist.last-started.size"], 123) self.assertEqual(self.settings["tracklist.last-started.size"], 123)
self.assertEqual(self.settings["tracklist.last-played.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.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"])
self.assertFalse(self.settings["tracklist.album-artist.visible"])
self.assertTrue(self.settings["tracklist.release.visible"])
self.assertTrue(self.settings["tracklist.play-count.visible"]) self.assertTrue(self.settings["tracklist.play-count.visible"])
self.assertFalse(self.settings["tracklist.last-started.visible"]) self.assertFalse(self.settings["tracklist.last-started.visible"])
self.assertTrue(self.settings["tracklist.last-played.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.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"])
self.assertTrue(self.settings["tracklist.album-artist.visible"])
self.assertFalse(self.settings["tracklist.release.visible"])
self.assertFalse(self.settings["tracklist.play-count.visible"]) self.assertFalse(self.settings["tracklist.play-count.visible"])
self.assertTrue(self.settings["tracklist.last-started.visible"]) self.assertTrue(self.settings["tracklist.last-started.visible"])
self.assertFalse(self.settings["tracklist.last-played.visible"]) self.assertFalse(self.settings["tracklist.last-played.visible"])

View File

@ -7,6 +7,7 @@ import emmental.factory
import emmental.tracklist.row import emmental.tracklist.row
import tests.util import tests.util
import unittest.mock import unittest.mock
from gi.repository import GObject
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Adw from gi.repository import Adw
@ -37,6 +38,7 @@ class TestTrackRowWidgets(tests.util.TestCase):
"""Test the base Track Row.""" """Test the base Track Row."""
row = emmental.tracklist.row.TrackRow(self.listitem, "property") row = emmental.tracklist.row.TrackRow(self.listitem, "property")
self.assertIsInstance(row, emmental.factory.ListRow) self.assertIsInstance(row, emmental.factory.ListRow)
self.assertIsNone(row.album_binding)
self.assertEqual(row.property, "property") self.assertEqual(row.property, "property")
self.assertEqual(row.mediumid, 0) self.assertEqual(row.mediumid, 0)
@ -148,6 +150,24 @@ class TestTrackRowWidgets(tests.util.TestCase):
self.track.mediumid = medium.mediumid self.track.mediumid = medium.mediumid
self.assertEqual(row.child.get_text(), "3-03") 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): def test_favorite_button(self):
"""Test the Favorite Button widget.""" """Test the Favorite Button widget."""
row = emmental.tracklist.row.FavoriteButton(self.listitem, "favorite") 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.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 = 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.""" """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)
@ -190,7 +222,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 = 6): def test_last_started_column(self, i: int = 8):
"""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)
@ -207,7 +239,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 = 7): def test_last_played_column(self, i: int = 9):
"""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)
@ -224,7 +256,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 = 8): def test_filepath_column(self, i: int = 10):
"""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)