diff --git a/emmental/__init__.py b/emmental/__init__.py index 024f183..f33b34a 100644 --- a/emmental/__init__.py +++ b/emmental/__init__.py @@ -5,6 +5,7 @@ from . import audio from . import db from . import header from . import mpris2 +from . import nowplaying from . import options from . import window from gi.repository import GObject @@ -50,13 +51,19 @@ class Application(Adw.Application): self.__set_replaygain() return hdr + def build_now_playing(self) -> nowplaying.Card: + """Build a new now playing card.""" + return nowplaying.Card() + def build_window(self) -> window.Window: """Build a new window instance.""" win = window.Window(VERSION_STRING, - header=self.build_header()) + header=self.build_header(), + now_playing=self.build_now_playing()) for (setting, property) in [("window.width", "default-width"), - ("window.height", "default-height")]: + ("window.height", "default-height"), + ("now-playing.size", "now-playing-size")]: self.db.settings.bind_setting(setting, win, property) return win diff --git a/emmental/nowplaying/__init__.py b/emmental/nowplaying/__init__.py new file mode 100644 index 0000000..5bb9345 --- /dev/null +++ b/emmental/nowplaying/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2022 (c) Anna Schumaker. +"""A card for displaying information about the currently playing track.""" +from gi.repository import Gtk + + +class Card(Gtk.Box): + """The Now Playing information card.""" + + def __init__(self): + """Initialize a Now Playing Card.""" + super().__init__() + self._grid = Gtk.Grid() + + self.append(self._grid) + self.add_css_class("card") diff --git a/emmental/window.py b/emmental/window.py index 9f231ec..7ae0003 100644 --- a/emmental/window.py +++ b/emmental/window.py @@ -5,12 +5,13 @@ from gi.repository import Gtk from gi.repository import Adw -def _make_pane(orientation: Gtk.Orientation, +def _make_pane(orientation: Gtk.Orientation, position: int = 0, start_child: Gtk.Widget = None, end_child: Gtk.Widget = None) -> Gtk.Paned: pane = Gtk.Paned(orientation=orientation, hexpand=True, vexpand=True, shrink_start_child=False, resize_start_child=False, - start_child=start_child, end_child=end_child) + start_child=start_child, end_child=end_child, + position=position) pane.add_css_class("emmental-pane") return pane @@ -28,6 +29,7 @@ class Window(Adw.Window): header = GObject.Property(type=Gtk.Widget) sidebar = GObject.Property(type=Gtk.Widget) now_playing = GObject.Property(type=Gtk.Widget) + now_playing_size = GObject.Property(type=int, default=250) tracklist = GObject.Property(type=Gtk.Widget) def __init__(self, version: str, **kwargs): @@ -37,6 +39,7 @@ class Window(Adw.Window): self._box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) self._header = Adw.Bin(child=self.header) self._inner_pane = _make_pane(Gtk.Orientation.VERTICAL, + position=self.now_playing_size, start_child=self.now_playing, end_child=self.tracklist) self._outer_pane = _make_pane(Gtk.Orientation.HORIZONTAL, @@ -51,6 +54,8 @@ class Window(Adw.Window): self.bind_property("header", self._header, "child") self.bind_property("sidebar", self._outer_pane, "start-child") self.bind_property("now-playing", self._inner_pane, "start-child") + self.bind_property("now-playing-size", self._inner_pane, "position", + GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("tracklist", self._inner_pane, "end-child") self._box.append(self._header) diff --git a/tests/nowplaying/test_nowplaying.py b/tests/nowplaying/test_nowplaying.py new file mode 100644 index 0000000..69221f2 --- /dev/null +++ b/tests/nowplaying/test_nowplaying.py @@ -0,0 +1,21 @@ +# Copyright 2022 (c) Anna Schumaker. +"""Tests our Now Playing card.""" +import unittest +import emmental +from gi.repository import Gtk + + +class TestNowPlaying(unittest.TestCase): + """Test case for our custom Now Playing card.""" + + def setUp(self): + """Set up common variables.""" + self.card = emmental.nowplaying.Card() + + def test_init(self): + """Test that the card has been initialized correctly.""" + self.assertIsInstance(self.card, Gtk.Box) + self.assertIsInstance(self.card._grid, Gtk.Grid) + + self.assertEqual(self.card.get_last_child(), self.card._grid) + self.assertTrue(self.card.has_css_class("card")) diff --git a/tests/test_emmental.py b/tests/test_emmental.py index 2f04c12..d7e6154 100644 --- a/tests/test_emmental.py +++ b/tests/test_emmental.py @@ -99,6 +99,8 @@ class TestEmmental(unittest.TestCase): self.assertIsInstance(win, emmental.window.Window) self.assertIsInstance(win.header, emmental.header.Header) + self.assertIsInstance(win.now_playing, emmental.nowplaying.Card) + self.assertEqual(win.header.title, emmental.VERSION_STRING) @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) diff --git a/tests/test_settings.py b/tests/test_settings.py index db117e3..4948087 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -78,3 +78,13 @@ class TestSettings(unittest.TestCase): self.assertFalse(self.settings["audio.replaygain.enabled"]) self.assertEqual(self.settings["audio.replaygain.mode"], "album") self.assertEqual(self.player.get_replaygain(), (False, None)) + + def test_save_nowplaying_size(self, mock_stdout: io.StringIO): + """Check saving and loading the nowplaying widget size.""" + self.assertEqual(self.win.now_playing_size, 250) + self.assertEqual(self.settings["now-playing.size"], 250) + + self.win.now_playing_size = 400 + self.assertEqual(self.settings["now-playing.size"], 400) + + self.assertEqual(self.app.build_window().now_playing_size, 400) diff --git a/tests/test_window.py b/tests/test_window.py index b9507d2..6799af7 100644 --- a/tests/test_window.py +++ b/tests/test_window.py @@ -93,6 +93,19 @@ class TestWindow(unittest.TestCase): self.assertEqual(window2._inner_pane.get_start_child(), window2.now_playing) + def test_now_playing_size(self): + """Check setting the size of the now playing area.""" + self.assertEqual(self.window.now_playing_size, 250) + self.assertEqual(self.window._inner_pane.get_position(), 250) + + self.window.now_playing_size = 100 + self.assertEqual(self.window.now_playing_size, 100) + self.assertEqual(self.window._inner_pane.get_position(), 100) + + self.window._inner_pane.set_position(200) + self.assertEqual(self.window.now_playing_size, 200) + self.assertEqual(self.window._inner_pane.get_position(), 200) + def test_tracklist(self): """Check setting a widget to the tracklist area.""" self.assertIsNone(self.window.tracklist)