nowplaying: Add a basic Now Playing widget

It doesn't have any children yet, the application will save its size
when the user resizes it.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2022-05-31 10:18:53 -04:00
parent 88e4fa4b0c
commit 51096104ce
7 changed files with 77 additions and 4 deletions

View File

@ -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

View File

@ -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")

View File

@ -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)

View File

@ -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"))

View File

@ -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)

View File

@ -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)

View File

@ -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)