sidebar: Create a basic Sidebar widget
It only contains a FilterEntry for filtering future playlists. The application will save its size when resized. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
5545cb106d
commit
40c463da81
|
@ -9,6 +9,7 @@ from . import header
|
|||
from . import mpris2
|
||||
from . import nowplaying
|
||||
from . import options
|
||||
from . import sidebar
|
||||
from . import window
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GLib
|
||||
|
@ -92,18 +93,23 @@ class Application(Adw.Application):
|
|||
playing.connect("play", self.player.play)
|
||||
playing.connect("pause", self.player.pause)
|
||||
playing.connect("seek", self.__on_seek)
|
||||
|
||||
return playing
|
||||
|
||||
def build_sidebar(self) -> sidebar.Card:
|
||||
"""Build a new sidebar card."""
|
||||
return sidebar.Card(sql=self.db)
|
||||
|
||||
def build_window(self) -> window.Window:
|
||||
"""Build a new window instance."""
|
||||
win = window.Window(VERSION_STRING,
|
||||
header=self.build_header(),
|
||||
now_playing=self.build_now_playing())
|
||||
now_playing=self.build_now_playing(),
|
||||
sidebar=self.build_sidebar())
|
||||
|
||||
for (setting, property) in [("window.width", "default-width"),
|
||||
("window.height", "default-height"),
|
||||
("now-playing.size", "now-playing-size")]:
|
||||
("now-playing.size", "now-playing-size"),
|
||||
("sidebar.size", "sidebar-size")]:
|
||||
self.db.settings.bind_setting(setting, win, property)
|
||||
|
||||
return win
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright 2022 (c) Anna Schumaker.
|
||||
"""A card for displaying the list of playlists."""
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
from .. import db
|
||||
from .. import entry
|
||||
|
||||
|
||||
class Card(Gtk.Box):
|
||||
"""Our playlist Sidebar."""
|
||||
|
||||
sql = GObject.Property(type=db.Connection)
|
||||
|
||||
def __init__(self, sql: db.Connection, **kwargs):
|
||||
"""Set up the Sidebar widget."""
|
||||
super().__init__(sql=sql, orientation=Gtk.Orientation.VERTICAL,
|
||||
sensitive=False, **kwargs)
|
||||
self._filter = entry.Filter("playlists")
|
||||
|
||||
self.append(self._filter)
|
||||
|
||||
self._filter.connect("search-changed", self.__search_changed)
|
||||
self.sql.connect("table-loaded", self.__table_loaded)
|
||||
|
||||
self.add_css_class("background")
|
||||
self.add_css_class("linked")
|
||||
self.add_css_class("card")
|
||||
|
||||
def __search_changed(self, entry: entry.Filter) -> None:
|
||||
self.sql.filter(entry.get_query())
|
||||
|
||||
def __table_loaded(self, sql: db.Connection, table: db.table.Table):
|
||||
loaded = {tbl.loaded for tbl in sql.playlist_tables()}
|
||||
self.set_sensitive(False not in loaded)
|
|
@ -28,6 +28,7 @@ class Window(Adw.Window):
|
|||
|
||||
header = GObject.Property(type=Gtk.Widget)
|
||||
sidebar = GObject.Property(type=Gtk.Widget)
|
||||
sidebar_size = GObject.Property(type=int, default=300)
|
||||
now_playing = GObject.Property(type=Gtk.Widget)
|
||||
now_playing_size = GObject.Property(type=int, default=250)
|
||||
tracklist = GObject.Property(type=Gtk.Widget)
|
||||
|
@ -43,6 +44,7 @@ class Window(Adw.Window):
|
|||
start_child=self.now_playing,
|
||||
end_child=self.tracklist)
|
||||
self._outer_pane = _make_pane(Gtk.Orientation.HORIZONTAL,
|
||||
position=self.sidebar_size,
|
||||
start_child=self.sidebar,
|
||||
end_child=self._inner_pane)
|
||||
self._toast = Adw.ToastOverlay(child=self._outer_pane)
|
||||
|
@ -53,6 +55,8 @@ class Window(Adw.Window):
|
|||
|
||||
self.bind_property("header", self._header, "child")
|
||||
self.bind_property("sidebar", self._outer_pane, "start-child")
|
||||
self.bind_property("sidebar-size", self._outer_pane, "position",
|
||||
GObject.BindingFlags.BIDIRECTIONAL)
|
||||
self.bind_property("now-playing", self._inner_pane, "start-child")
|
||||
self.bind_property("now-playing-size", self._inner_pane, "position",
|
||||
GObject.BindingFlags.BIDIRECTIONAL)
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# Copyright 2022 (c) Anna Schumaker.
|
||||
"""Tests our playlist Sidebar card."""
|
||||
import emmental.sidebar
|
||||
import tests.util
|
||||
import unittest.mock
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class TestSidebar(tests.util.TestCase):
|
||||
"""Tests the Sidebar card."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
super().setUp()
|
||||
self.sidebar = emmental.sidebar.Card(sql=self.sql)
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the Sidebar has been set up correctly."""
|
||||
self.assertIsInstance(self.sidebar, Gtk.Box)
|
||||
|
||||
self.assertEqual(self.sidebar.sql, self.sql)
|
||||
self.assertEqual(self.sidebar.get_orientation(),
|
||||
Gtk.Orientation.VERTICAL)
|
||||
|
||||
self.assertTrue(self.sidebar.has_css_class("background"))
|
||||
self.assertTrue(self.sidebar.has_css_class("linked"))
|
||||
self.assertTrue(self.sidebar.has_css_class("card"))
|
||||
|
||||
def test_filter(self):
|
||||
"""Test the Sidebar filter entry."""
|
||||
self.assertIsInstance(self.sidebar._filter, emmental.entry.Filter)
|
||||
|
||||
self.assertEqual(self.sidebar.get_first_child(), self.sidebar._filter)
|
||||
self.assertEqual(self.sidebar._filter.get_placeholder_text(),
|
||||
"type to filter playlists")
|
||||
|
||||
with unittest.mock.patch.object(self.sql, "filter") as mock_filter:
|
||||
self.sidebar._filter.set_text("test text")
|
||||
self.sidebar._filter.emit("search-changed")
|
||||
mock_filter.assert_called_with("*test text*")
|
||||
|
||||
def test_sensitivity(self):
|
||||
"""Test setting the sidebar sensitivity when all tables have loaded."""
|
||||
tables = [t for t in self.sql.playlist_tables()]
|
||||
self.assertFalse(self.sidebar.get_sensitive())
|
||||
|
||||
for table in tables:
|
||||
self.sql.emit("table-loaded", table)
|
||||
self.assertEqual(self.sidebar.get_sensitive(), table == tables[-1])
|
|
@ -103,6 +103,7 @@ 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.assertIsInstance(win.sidebar, emmental.sidebar.Card)
|
||||
|
||||
self.assertEqual(win.header.title, emmental.VERSION_STRING)
|
||||
|
||||
|
@ -141,6 +142,15 @@ class TestEmmental(unittest.TestCase):
|
|||
self.application.autopause = 2
|
||||
self.assertEqual(win.now_playing.autopause, 2)
|
||||
|
||||
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_sidebar(self, mock_stdout: io.StringIO):
|
||||
"""Check that the sidebar widget is wired up properly."""
|
||||
self.application.db = emmental.db.Connection()
|
||||
self.application.player = emmental.audio.Player()
|
||||
win = self.application.build_window()
|
||||
|
||||
self.assertEqual(win.sidebar.sql, self.application.db)
|
||||
|
||||
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_replaygain(self, mock_stdout: io.StringIO):
|
||||
"""Test setting replaygain modes."""
|
||||
|
|
|
@ -98,3 +98,13 @@ class TestSettings(unittest.TestCase):
|
|||
self.assertFalse(self.settings["now-playing.prefer-artist"])
|
||||
|
||||
self.assertFalse(self.app.build_window().now_playing.prefer_artist)
|
||||
|
||||
def test_save_sidebar_size(self, mock_stdout: io.StringIO):
|
||||
"""Check saving and loading the sidebar widget size."""
|
||||
self.assertEqual(self.win.sidebar_size, 300)
|
||||
self.assertEqual(self.settings["sidebar.size"], 300)
|
||||
|
||||
self.win.sidebar_size = 400
|
||||
self.assertEqual(self.settings["sidebar.size"], 400)
|
||||
|
||||
self.assertEqual(self.app.build_window().sidebar_size, 400)
|
||||
|
|
|
@ -80,6 +80,19 @@ class TestWindow(unittest.TestCase):
|
|||
self.assertEqual(window2._outer_pane.get_start_child(),
|
||||
window2.sidebar)
|
||||
|
||||
def test_sidebar_size(self):
|
||||
"""Check setting the size of the sidebar area."""
|
||||
self.assertEqual(self.window.sidebar_size, 300)
|
||||
self.assertEqual(self.window._outer_pane.get_position(), 300)
|
||||
|
||||
self.window.sidebar_size = 100
|
||||
self.assertEqual(self.window.sidebar_size, 100)
|
||||
self.assertEqual(self.window._outer_pane.get_position(), 100)
|
||||
|
||||
self.window._outer_pane.set_position(200)
|
||||
self.assertEqual(self.window.sidebar_size, 200)
|
||||
self.assertEqual(self.window._outer_pane.get_position(), 200)
|
||||
|
||||
def test_now_playing(self):
|
||||
"""Check setting a widget to the now_playing area."""
|
||||
self.assertIsNone(self.window.now_playing)
|
||||
|
|
Loading…
Reference in New Issue