sidebar: Create a PlaylistRow
This row is configured for showing user and system playlists. This means we use a SettableIcon, and EditableTitle, and an extra button for deleting playlists. I use the big-x-symbolic icon from the gnome icon library for deleting playlists. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
0adb0d472b
commit
dcd63015b8
|
@ -56,3 +56,7 @@ image.emmental-sidebar-arrow:checked {
|
|||
transform: rotate(-180deg);
|
||||
color: @accent_color;
|
||||
}
|
||||
|
||||
button.emmental-delete>image {
|
||||
color: @destructive_color;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
from .title import PlaylistTitle
|
||||
from .title import EditableTitle
|
||||
from .icon import Icon
|
||||
from .icon import Settable
|
||||
from .. import db
|
||||
|
||||
|
||||
|
@ -45,3 +47,49 @@ class Row(BaseRow):
|
|||
digits = str(year)
|
||||
self._year = year
|
||||
self._icon.text = f"{digits[-2]} {digits[-1]}"
|
||||
|
||||
|
||||
class PlaylistRow(BaseRow):
|
||||
"""An advanced playlist row with extra actions for users."""
|
||||
|
||||
icon_name = GObject.Property(type=str)
|
||||
filepath = GObject.Property(type=GObject.TYPE_PYOBJECT)
|
||||
modifiable = GObject.Property(type=bool, default=False)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize a PlaylistRow."""
|
||||
super().__init__(**kwargs)
|
||||
self._icon = Settable()
|
||||
self._title = EditableTitle(margin_start=12, margin_end=12)
|
||||
self._delete = Gtk.Button(icon_name="big-x-symbolic",
|
||||
valign=Gtk.Align.CENTER,
|
||||
has_frame=False, visible=False)
|
||||
|
||||
self.bind_property("name", self._icon, "text")
|
||||
self.bind_property("icon-name", self._icon, "icon-name")
|
||||
self.bind_property("filepath", self._icon, "filepath",
|
||||
GObject.BindingFlags.BIDIRECTIONAL)
|
||||
self.bind_property("modifiable", self._icon, "settable")
|
||||
|
||||
self.bind_property("name", self._title, "title")
|
||||
self.bind_property("count", self._title, "count")
|
||||
self.bind_property("modifiable", self._title, "editable")
|
||||
|
||||
self.bind_property("modifiable", self._delete, "visible")
|
||||
|
||||
self._title.connect("request-rename", self.__on_rename)
|
||||
self._delete.connect("clicked", self.__on_delete)
|
||||
|
||||
self._delete.add_css_class("emmental-delete")
|
||||
|
||||
self.append(self._icon)
|
||||
self.append(self._title)
|
||||
self.append(self._delete)
|
||||
|
||||
def __on_rename(self, title: EditableTitle, new_name: str) -> None:
|
||||
if self.playlist is not None:
|
||||
self.playlist.rename(new_name)
|
||||
|
||||
def __on_delete(self, button: Gtk.Button) -> None:
|
||||
if self.playlist is not None:
|
||||
self.playlist.delete()
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 2 2 h 1 h 0.03125 c 0.253906 0.011719 0.511719 0.128906 0.6875 0.3125 l 4.28125 4.28125 l 4.3125 -4.28125 c 0.265625 -0.230469 0.445312 -0.304688 0.6875 -0.3125 h 1 v 1 c 0 0.285156 -0.035156 0.550781 -0.25 0.75 l -4.28125 4.28125 l 4.25 4.25 c 0.1875 0.1875 0.28125 0.453125 0.28125 0.71875 v 1 h -1 c -0.265625 0 -0.53125 -0.09375 -0.71875 -0.28125 l -4.28125 -4.28125 l -4.28125 4.28125 c -0.1875 0.1875 -0.453125 0.28125 -0.71875 0.28125 h -1 v -1 c 0 -0.265625 0.09375 -0.53125 0.28125 -0.71875 l 4.28125 -4.25 l -4.28125 -4.28125 c -0.210938 -0.195312 -0.304688 -0.46875 -0.28125 -0.75 z m 0 0" fill="#222222"/></svg>
|
After Width: | Height: | Size: 761 B |
|
@ -93,3 +93,87 @@ class TestRow(unittest.TestCase):
|
|||
self.assertEqual(self.row._icon.text, "8 8")
|
||||
self.row.year = 2000
|
||||
self.assertEqual(self.row._icon.text, "0 0")
|
||||
|
||||
|
||||
class TestPlaylistRow(unittest.TestCase):
|
||||
"""Test our playlist row with extra buttons."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
self.row = emmental.sidebar.row.PlaylistRow()
|
||||
self.playlist = emmental.db.playlists.Playlist(table=Gio.ListStore(),
|
||||
propertyid=12345,
|
||||
playlistid=67890,
|
||||
name="Test Playlist")
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the playlist row is configured properly."""
|
||||
self.assertIsInstance(self.row, emmental.sidebar.row.BaseRow)
|
||||
|
||||
def test_icon(self):
|
||||
"""Test the settable icon widget and properties."""
|
||||
self.assertIsInstance(self.row._icon, emmental.sidebar.icon.Settable)
|
||||
self.assertEqual(self.row.get_first_child(), self.row._icon)
|
||||
|
||||
self.row.name = "Test Playlist"
|
||||
self.row.icon_name = "image-missing"
|
||||
self.row.filepath = tests.util.COVER_JPG
|
||||
|
||||
self.assertEqual(self.row._icon.text, "Test Playlist")
|
||||
self.assertEqual(self.row._icon.icon_name, "image-missing")
|
||||
self.assertEqual(self.row._icon.filepath, tests.util.COVER_JPG)
|
||||
|
||||
self.row._icon.filepath = None
|
||||
self.assertIsNone(self.row.filepath)
|
||||
|
||||
def test_title(self):
|
||||
"""Test the editable title widget and properties."""
|
||||
self.assertIsInstance(self.row._title,
|
||||
emmental.sidebar.title.EditableTitle)
|
||||
self.assertEqual(self.row._icon.get_next_sibling(), self.row._title)
|
||||
|
||||
self.assertEqual(self.row._title.get_margin_start(), 12)
|
||||
self.assertEqual(self.row._title.get_margin_end(), 12)
|
||||
|
||||
self.row.name = "Test Playlist"
|
||||
self.row.count = 42
|
||||
self.assertEqual(self.row._title.title, "Test Playlist")
|
||||
self.assertEqual(self.row._title.count, 42)
|
||||
|
||||
def test_delete(self):
|
||||
"""Test the delete button."""
|
||||
self.assertIsInstance(self.row._delete, Gtk.Button)
|
||||
self.assertEqual(self.row._title.get_next_sibling(), self.row._delete)
|
||||
|
||||
self.assertEqual(self.row._delete.get_icon_name(), "big-x-symbolic")
|
||||
self.assertEqual(self.row._delete.get_valign(), Gtk.Align.CENTER)
|
||||
self.assertFalse(self.row._delete.get_has_frame())
|
||||
self.assertTrue(self.row._delete.has_css_class("emmental-delete"))
|
||||
|
||||
self.row._delete.emit("clicked")
|
||||
|
||||
self.playlist.delete = unittest.mock.Mock()
|
||||
self.row.playlist = self.playlist
|
||||
self.row._delete.emit("clicked")
|
||||
self.playlist.delete.assert_called()
|
||||
|
||||
def test_modifiable(self):
|
||||
"""Test the modifiable property."""
|
||||
self.assertFalse(self.row.modifiable)
|
||||
self.assertFalse(self.row._icon.settable)
|
||||
self.assertFalse(self.row._title.editable)
|
||||
self.assertFalse(self.row._delete.get_visible())
|
||||
|
||||
self.row.modifiable = True
|
||||
self.assertTrue(self.row._icon.settable)
|
||||
self.assertTrue(self.row._title.editable)
|
||||
self.assertTrue(self.row._delete.get_visible())
|
||||
|
||||
def test_rename(self):
|
||||
"""Test responding to the request-rename signal."""
|
||||
self.row._title.emit("request-rename", "No Error Expected")
|
||||
|
||||
self.playlist.rename = unittest.mock.Mock()
|
||||
self.row.playlist = self.playlist
|
||||
self.row._title.emit("request-rename", "New Name")
|
||||
self.playlist.rename.assert_called_with("New Name")
|
||||
|
|
Loading…
Reference in New Issue