tracklist: Add a Footer widget
This widget displays the number of visible tracks, number of selected tracks, and runtime of the current playlist. I wire it up to these properties from the trackview. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
ee1152bcc4
commit
911aeb84a1
|
@ -9,6 +9,7 @@ from ..playlist.previous import Previous
|
|||
from .. import db
|
||||
from .. import entry
|
||||
from . import buttons
|
||||
from . import footer
|
||||
from . import trackview
|
||||
|
||||
|
||||
|
@ -35,6 +36,8 @@ class Card(Gtk.Box):
|
|||
self._loop = buttons.LoopButton()
|
||||
self._shuffle = buttons.ShuffleButton()
|
||||
self._sort = buttons.SortButton()
|
||||
self._footer = footer.Footer(margin_start=6, margin_end=6,
|
||||
margin_bottom=6)
|
||||
|
||||
self._top_left.append(self._visible_cols)
|
||||
self._top_left.append(self._unselect)
|
||||
|
@ -49,6 +52,11 @@ class Card(Gtk.Box):
|
|||
|
||||
self.append(self._top_box)
|
||||
self.append(self._trackview)
|
||||
self.append(self._footer)
|
||||
|
||||
self._trackview.bind_property("n-tracks", self._footer, "count")
|
||||
self._trackview.bind_property("n-selected", self._footer, "selected")
|
||||
self._trackview.bind_property("runtime", self._footer, "runtime")
|
||||
|
||||
self._trackview.bind_property("have-selected", self._unselect,
|
||||
"sensitive")
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# Copyright 2022 (c) Anna Schumaker.
|
||||
"""A Footer widget to display below the TrackView."""
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class Footer(Gtk.CenterBox):
|
||||
"""Footer labels for the Tracklist card."""
|
||||
|
||||
count = GObject.Property(type=int)
|
||||
selected = GObject.Property(type=int)
|
||||
runtime = GObject.Property(type=float)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize a Footer widget."""
|
||||
super().__init__(**kwargs)
|
||||
self._count = Gtk.Label(label="Showing 0 tracks", xalign=0.0)
|
||||
self._selected = Gtk.Label()
|
||||
self._runtime = Gtk.Label(label="0 seconds", xalign=1.0)
|
||||
|
||||
self.set_start_widget(self._count)
|
||||
self.set_center_widget(self._selected)
|
||||
self.set_end_widget(self._runtime)
|
||||
|
||||
self.connect("notify", self.__update_labels)
|
||||
self.add_css_class("dim-label")
|
||||
|
||||
def __update_labels(self, footer: Gtk.CenterBox, param) -> None:
|
||||
match param.name:
|
||||
case "count":
|
||||
s_count = "s" if self.count != 1 else ""
|
||||
self._count.set_text(f"Showing {self.count} track{s_count}")
|
||||
case "selected":
|
||||
match self.selected:
|
||||
case 0: text = ""
|
||||
case _:
|
||||
s_count = "s" if self.selected != 1 else ""
|
||||
text = f"{self.selected} track{s_count} selected"
|
||||
self._selected.set_text(text)
|
||||
case "runtime":
|
||||
res = []
|
||||
(min, sec) = divmod(round(self.runtime), 60)
|
||||
(hour, min) = divmod(min, 60)
|
||||
(day, hour) = divmod(hour, 24)
|
||||
(week, day) = divmod(day, 7)
|
||||
|
||||
if week > 0:
|
||||
res.append(f"{week} week{'s' if week != 1 else ''}")
|
||||
if day > 0:
|
||||
res.append(f"{day} day{'s' if day != 1 else ''}")
|
||||
if hour > 0:
|
||||
res.append(f"{hour} hour{'s' if hour != 1 else ''}")
|
||||
if min > 0:
|
||||
res.append(f"{min} minute{'s' if min != 1 else ''}")
|
||||
if sec > 0:
|
||||
res.append(f"{sec} second{'s' if sec != 1 else ''}")
|
||||
|
||||
self._runtime.set_text(", ".join(res))
|
|
@ -0,0 +1,81 @@
|
|||
# Copyright 2022 (c) Anna Schumaker.
|
||||
"""Tests our Tracklist Footer."""
|
||||
import unittest
|
||||
import emmental.tracklist.footer
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class TestFooter(unittest.TestCase):
|
||||
"""Test the Tracklist Footer."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
self.footer = emmental.tracklist.footer.Footer()
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the footer is initialized properly."""
|
||||
self.assertIsInstance(self.footer, Gtk.CenterBox)
|
||||
self.assertTrue(self.footer.has_css_class("dim-label"))
|
||||
|
||||
def test_count(self):
|
||||
"""Test the count property."""
|
||||
self.assertIsInstance(self.footer._count, Gtk.Label)
|
||||
self.assertEqual(self.footer._count.get_xalign(), 0.0)
|
||||
self.assertEqual(self.footer.get_start_widget(), self.footer._count)
|
||||
|
||||
self.assertEqual(self.footer.count, 0)
|
||||
self.assertEqual(self.footer._count.get_text(), "Showing 0 tracks")
|
||||
self.footer.count = 1
|
||||
self.assertEqual(self.footer._count.get_text(), "Showing 1 track")
|
||||
self.footer.count = 2
|
||||
self.assertEqual(self.footer._count.get_text(), "Showing 2 tracks")
|
||||
|
||||
def test_selected(self):
|
||||
"""Test the selected property."""
|
||||
self.assertIsInstance(self.footer._selected, Gtk.Label)
|
||||
self.assertEqual(self.footer._selected.get_xalign(), 0.5)
|
||||
self.assertEqual(self.footer.get_center_widget(),
|
||||
self.footer._selected)
|
||||
|
||||
self.assertEqual(self.footer.selected, 0)
|
||||
self.assertEqual(self.footer._selected.get_text(), "")
|
||||
self.footer.selected = 1
|
||||
self.assertEqual(self.footer._selected.get_text(), "1 track selected")
|
||||
self.footer.selected = 2
|
||||
self.assertEqual(self.footer._selected.get_text(), "2 tracks selected")
|
||||
self.footer.selected = 0
|
||||
self.assertEqual(self.footer._selected.get_text(), "")
|
||||
|
||||
def test_runtime(self):
|
||||
"""Test the runtime property."""
|
||||
self.assertIsInstance(self.footer._runtime, Gtk.Label)
|
||||
self.assertEqual(self.footer._runtime.get_xalign(), 1.0)
|
||||
self.assertEqual(self.footer.get_end_widget(), self.footer._runtime)
|
||||
|
||||
self.assertEqual(self.footer.runtime, 0.0)
|
||||
self.assertEqual(self.footer._runtime.get_text(),
|
||||
"0 seconds")
|
||||
|
||||
self.footer.runtime = 1.2
|
||||
self.assertEqual(self.footer._runtime.get_text(),
|
||||
"1 second")
|
||||
|
||||
self.footer.runtime = 65
|
||||
self.assertEqual(self.footer._runtime.get_text(),
|
||||
"1 minute, 5 seconds")
|
||||
|
||||
self.footer.runtime = 3720
|
||||
self.assertEqual(self.footer._runtime.get_text(),
|
||||
"1 hour, 2 minutes")
|
||||
|
||||
self.footer.runtime = 93600
|
||||
self.assertEqual(self.footer._runtime.get_text(),
|
||||
"1 day, 2 hours")
|
||||
|
||||
self.footer.runtime = 777600
|
||||
self.assertEqual(self.footer._runtime.get_text(),
|
||||
"1 week, 2 days")
|
||||
|
||||
self.footer.runtime = 1209600
|
||||
self.assertEqual(self.footer._runtime.get_text(),
|
||||
"2 weeks")
|
|
@ -169,6 +169,24 @@ class TestTracklist(tests.util.TestCase):
|
|||
self.assertEqual(self.tracklist.columns,
|
||||
self.tracklist._trackview.columns)
|
||||
|
||||
def test_footer(self):
|
||||
"""Test that the footer is wired up properly."""
|
||||
self.assertIsInstance(self.tracklist._footer,
|
||||
emmental.tracklist.footer.Footer)
|
||||
self.assertEqual(self.tracklist._footer.get_margin_start(), 6)
|
||||
self.assertEqual(self.tracklist._footer.get_margin_end(), 6)
|
||||
self.assertEqual(self.tracklist._footer.get_margin_bottom(), 6)
|
||||
self.assertEqual(self.tracklist._trackview.get_next_sibling(),
|
||||
self.tracklist._footer)
|
||||
|
||||
self.tracklist._trackview.n_tracks = 5
|
||||
self.tracklist._trackview.n_selected = 3
|
||||
self.tracklist._trackview.runtime = 12345
|
||||
|
||||
self.assertEqual(self.tracklist._footer.count, 5)
|
||||
self.assertEqual(self.tracklist._footer.selected, 3)
|
||||
self.assertEqual(self.tracklist._footer.runtime, 12345)
|
||||
|
||||
def test_playlist(self):
|
||||
"""Test the playlist property."""
|
||||
self.assertIsNone(self.tracklist.playlist)
|
||||
|
|
Loading…
Reference in New Issue