Compare commits
3 Commits
c195e68216
...
70d7f5fa70
Author | SHA1 | Date |
---|---|---|
Anna Schumaker | 70d7f5fa70 | |
Anna Schumaker | 2504f4b91d | |
Anna Schumaker | 7358183fef |
|
@ -1,6 +1,7 @@
|
||||||
# Copyright 2022 (c) Anna Schumaker.
|
# Copyright 2022 (c) Anna Schumaker.
|
||||||
"""A card for displaying the list of playlists."""
|
"""A card for displaying the list of playlists."""
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
|
from gi.repository import GLib
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
from . import artist
|
from . import artist
|
||||||
from . import decade
|
from . import decade
|
||||||
|
@ -66,27 +67,37 @@ class Card(Gtk.Box):
|
||||||
if self.get_sensitive() is False:
|
if self.get_sensitive() is False:
|
||||||
if False not in {tbl.loaded for tbl in sql.playlist_tables()}:
|
if False not in {tbl.loaded for tbl in sql.playlist_tables()}:
|
||||||
self.set_sensitive(True)
|
self.set_sensitive(True)
|
||||||
self.select_playlist(sql.active_playlist)
|
self.select_playlist(sql.active_playlist, 150)
|
||||||
if len(sql.libraries) == 0:
|
if len(sql.libraries) == 0:
|
||||||
self._libraries.extra_widget.emit("clicked")
|
self._libraries.extra_widget.emit("clicked")
|
||||||
|
|
||||||
def select_playlist(self, playlist: db.playlist.Playlist) -> None:
|
def __select_playlist(self, playlist: db.playlist.Playlist) -> bool:
|
||||||
"""Set the current active playlist."""
|
|
||||||
if playlist is not None:
|
if playlist is not None:
|
||||||
match playlist.table:
|
section = self.table_section(playlist.table)
|
||||||
case self.sql.playlists:
|
if not section.active:
|
||||||
section = self._playlists
|
section.active = True
|
||||||
case self.sql.artists | self.sql.albums | self.sql.media:
|
return GLib.SOURCE_CONTINUE
|
||||||
section = self._artists
|
|
||||||
case self.sql.genres:
|
|
||||||
section = self._genres
|
|
||||||
case self.sql.decades | self.sql.years:
|
|
||||||
section = self._decades
|
|
||||||
case self.sql.libraries:
|
|
||||||
section = self._libraries
|
|
||||||
|
|
||||||
section.active = True
|
|
||||||
section.select_playlist(playlist)
|
section.select_playlist(playlist)
|
||||||
|
return GLib.SOURCE_REMOVE
|
||||||
|
|
||||||
|
def select_playlist(self, playlist: db.playlist.Playlist,
|
||||||
|
timeout: int = 0) -> None:
|
||||||
|
"""Set the current active playlist."""
|
||||||
|
GLib.timeout_add(timeout, self.__select_playlist, playlist)
|
||||||
|
|
||||||
|
def table_section(self, table: db.playlist.Table) -> section.Section:
|
||||||
|
"""Get the Section associated with a specific Playlist Table."""
|
||||||
|
match table:
|
||||||
|
case self.sql.playlists:
|
||||||
|
return self._playlists
|
||||||
|
case self.sql.artists | self.sql.albums | self.sql.media:
|
||||||
|
return self._artists
|
||||||
|
case self.sql.genres:
|
||||||
|
return self._genres
|
||||||
|
case self.sql.decades | self.sql.years:
|
||||||
|
return self._decades
|
||||||
|
case self.sql.libraries:
|
||||||
|
return self._libraries
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def accelerators(self) -> list[ActionEntry]:
|
def accelerators(self) -> list[ActionEntry]:
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
"""A sidebar Header attached to a hidden ListView for selecting playlists."""
|
"""A sidebar Header attached to a hidden ListView for selecting playlists."""
|
||||||
import typing
|
import typing
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
from gi.repository import GLib
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
from .. import db
|
from .. import db
|
||||||
from .. import factory
|
from .. import factory
|
||||||
|
@ -86,9 +85,7 @@ class Section(header.Header):
|
||||||
def select_playlist(self, playlist: db.playlist.Playlist) -> None:
|
def select_playlist(self, playlist: db.playlist.Playlist) -> None:
|
||||||
"""Select the requested playlist."""
|
"""Select the requested playlist."""
|
||||||
if (index := self.playlist_index(playlist)) is not None:
|
if (index := self.playlist_index(playlist)) is not None:
|
||||||
self._selection.select_item(index, True)
|
self._listview.scroll_to(index, Gtk.ListScrollFlags.SELECT)
|
||||||
self._listview.activate_action("list.scroll-to-item",
|
|
||||||
GLib.Variant.new_uint32(index))
|
|
||||||
|
|
||||||
@GObject.Signal(arg_types=(db.playlist.Playlist,))
|
@GObject.Signal(arg_types=(db.playlist.Playlist,))
|
||||||
def playlist_activated(self, playlist: db.playlist.Playlist):
|
def playlist_activated(self, playlist: db.playlist.Playlist):
|
||||||
|
|
|
@ -81,13 +81,9 @@ class TrackView(Gtk.ScrolledWindow):
|
||||||
|
|
||||||
def scroll_to_track(self, track: db.tracks.Track) -> None:
|
def scroll_to_track(self, track: db.tracks.Track) -> None:
|
||||||
"""Scroll to the requested Track."""
|
"""Scroll to the requested Track."""
|
||||||
# This is a workaround until the ColumnView has better scrolling
|
for i in range(self._selection.props.n_items):
|
||||||
# support, which seems to be targeted for Gtk 4.10.
|
if self._selection[i] == track:
|
||||||
adjustment = self._scrollwin.get_vadjustment()
|
self._columnview.scroll_to(i, None, Gtk.ListScrollFlags.NONE)
|
||||||
for (i, t) in enumerate(self._selection):
|
|
||||||
if t == track:
|
|
||||||
pos = max(i - 3, 0) * adjustment.get_upper()
|
|
||||||
adjustment.set_value(pos / self._selection.get_n_items())
|
|
||||||
|
|
||||||
@GObject.Property(type=Gio.ListModel)
|
@GObject.Property(type=Gio.ListModel)
|
||||||
def columns(self) -> Gio.ListModel:
|
def columns(self) -> Gio.ListModel:
|
||||||
|
|
|
@ -4,7 +4,6 @@ import emmental.db
|
||||||
import emmental.sidebar.section
|
import emmental.sidebar.section
|
||||||
import tests.util
|
import tests.util
|
||||||
import unittest.mock
|
import unittest.mock
|
||||||
from gi.repository import GLib
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,18 +104,12 @@ class TestSection(tests.util.TestCase):
|
||||||
def test_select_playlist(self):
|
def test_select_playlist(self):
|
||||||
"""Test selecting a specific playlist."""
|
"""Test selecting a specific playlist."""
|
||||||
self.section.do_get_subtitle = unittest.mock.Mock(return_value="")
|
self.section.do_get_subtitle = unittest.mock.Mock(return_value="")
|
||||||
|
|
||||||
playlist_selected = unittest.mock.Mock()
|
|
||||||
self.section.connect("playlist-selected", playlist_selected)
|
|
||||||
playlist = self.table.create("Test Playlist")
|
playlist = self.table.create("Test Playlist")
|
||||||
playlist_selected.assert_not_called()
|
|
||||||
|
|
||||||
with unittest.mock.patch.object(self.section._listview,
|
with unittest.mock.patch.object(self.section._listview,
|
||||||
"activate_action") as mock_action:
|
"scroll_to") as mock_scroll_to:
|
||||||
self.section.select_playlist(playlist)
|
self.section.select_playlist(playlist)
|
||||||
playlist_selected.assert_called_with(self.section, playlist)
|
mock_scroll_to.assert_called_with(0, Gtk.ListScrollFlags.SELECT)
|
||||||
mock_action.assert_called_with("list.scroll-to-item",
|
|
||||||
GLib.Variant.new_uint32(0))
|
|
||||||
|
|
||||||
def test_playlist_selected(self):
|
def test_playlist_selected(self):
|
||||||
"""Test selecting a playlist in the list."""
|
"""Test selecting a playlist in the list."""
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import emmental.sidebar
|
import emmental.sidebar
|
||||||
import tests.util
|
import tests.util
|
||||||
import unittest.mock
|
import unittest.mock
|
||||||
|
from gi.repository import GLib
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,10 +74,13 @@ class TestSidebar(tests.util.TestCase):
|
||||||
self.assertFalse(self.sidebar.get_sensitive())
|
self.assertFalse(self.sidebar.get_sensitive())
|
||||||
self.sidebar.select_playlist.assert_not_called()
|
self.sidebar.select_playlist.assert_not_called()
|
||||||
self.sidebar._libraries.extra_widget.emit.assert_not_called()
|
self.sidebar._libraries.extra_widget.emit.assert_not_called()
|
||||||
self.sql.emit("table-loaded", table)
|
|
||||||
|
|
||||||
self.assertTrue(self.sidebar.get_sensitive())
|
table.load(now=True)
|
||||||
self.sidebar.select_playlist.assert_called()
|
self.assertEqual(self.sidebar.get_sensitive(),
|
||||||
|
table == tables[-1])
|
||||||
|
|
||||||
|
playlist = self.sql.playlists.collection
|
||||||
|
self.sidebar.select_playlist.assert_called_with(playlist, 150)
|
||||||
self.sidebar._libraries.extra_widget.emit.assert_called_with("clicked")
|
self.sidebar._libraries.extra_widget.emit.assert_called_with("clicked")
|
||||||
|
|
||||||
self.sidebar.select_playlist.reset_mock()
|
self.sidebar.select_playlist.reset_mock()
|
||||||
|
@ -147,45 +151,48 @@ class TestSidebar(tests.util.TestCase):
|
||||||
|
|
||||||
def test_select_playlist(self):
|
def test_select_playlist(self):
|
||||||
"""Test setting the active playlist."""
|
"""Test setting the active playlist."""
|
||||||
|
self.assertEqual(self.sidebar._Card__select_playlist(None),
|
||||||
|
GLib.SOURCE_REMOVE)
|
||||||
|
|
||||||
playlist = self.sql.playlists.create("Test Playlist")
|
playlist = self.sql.playlists.create("Test Playlist")
|
||||||
self.sidebar.select_playlist(playlist)
|
with unittest.mock.patch.object(self.sidebar._playlists,
|
||||||
self.assertTrue(self.sidebar._playlists.active)
|
"select_playlist") as mock_select:
|
||||||
self.assertEqual(self.sidebar.selected_playlist, playlist)
|
self.assertEqual(self.sidebar._Card__select_playlist(playlist),
|
||||||
|
GLib.SOURCE_CONTINUE)
|
||||||
|
self.assertTrue(self.sidebar._playlists.active)
|
||||||
|
mock_select.assert_not_called()
|
||||||
|
|
||||||
artist = self.sql.artists.create("Test Artist")
|
self.assertEqual(self.sidebar._Card__select_playlist(playlist),
|
||||||
album = self.sql.albums.create("Test Album", "Test Artist", "2023")
|
GLib.SOURCE_REMOVE)
|
||||||
medium = self.sql.media.create(album, "Test Medium", number=1)
|
mock_select.assert_called_with(playlist)
|
||||||
|
|
||||||
self.sidebar._artists.select_playlist = unittest.mock.Mock()
|
with unittest.mock.patch.object(GLib, "timeout_add") as mock_to:
|
||||||
for plist in [artist, album, medium]:
|
self.sidebar.select_playlist(playlist)
|
||||||
self.sidebar._artists.select_playlist.reset_mock()
|
mock_to.assert_called_with(0, self.sidebar._Card__select_playlist,
|
||||||
self.sidebar._artists.active = False
|
playlist)
|
||||||
|
self.sidebar.select_playlist(playlist, 42)
|
||||||
|
mock_to.assert_called_with(42, self.sidebar._Card__select_playlist,
|
||||||
|
playlist)
|
||||||
|
|
||||||
self.sidebar.select_playlist(plist)
|
def test_table_section(self):
|
||||||
self.assertTrue(self.sidebar._artists.active)
|
"""Test converting a Playlist database table into a Section."""
|
||||||
self.sidebar._artists.select_playlist.assert_called_with(plist)
|
self.assertEqual(self.sidebar.table_section(self.sql.playlists),
|
||||||
|
self.sidebar._playlists)
|
||||||
genre = self.sql.genres.create("Test Genre")
|
self.assertEqual(self.sidebar.table_section(self.sql.artists),
|
||||||
self.sidebar.select_playlist(genre)
|
self.sidebar._artists)
|
||||||
self.assertTrue(self.sidebar._genres.active)
|
self.assertEqual(self.sidebar.table_section(self.sql.albums),
|
||||||
self.assertEqual(self.sidebar.selected_playlist, genre)
|
self.sidebar._artists)
|
||||||
|
self.assertEqual(self.sidebar.table_section(self.sql.media),
|
||||||
decade = self.sql.decades.create(1990)
|
self.sidebar._artists)
|
||||||
year = self.sql.years.create(1990)
|
self.assertEqual(self.sidebar.table_section(self.sql.genres),
|
||||||
|
self.sidebar._genres)
|
||||||
self.sidebar._decades.select_playlist = unittest.mock.Mock()
|
self.assertEqual(self.sidebar.table_section(self.sql.decades),
|
||||||
for plist in [decade, year]:
|
self.sidebar._decades)
|
||||||
self.sidebar._decades.select_playlist.reset_mock()
|
self.assertEqual(self.sidebar.table_section(self.sql.years),
|
||||||
self.sidebar._decades.active = False
|
self.sidebar._decades)
|
||||||
|
self.assertEqual(self.sidebar.table_section(self.sql.libraries),
|
||||||
self.sidebar.select_playlist(plist)
|
self.sidebar._libraries)
|
||||||
self.assertTrue(self.sidebar._decades.active)
|
self.assertIsNone(self.sidebar.table_section(None))
|
||||||
self.sidebar._decades.select_playlist.assert_called_with(plist)
|
|
||||||
|
|
||||||
library = self.sql.libraries.create("/a/b/c")
|
|
||||||
self.sidebar.select_playlist(library)
|
|
||||||
self.assertTrue(self.sidebar._libraries.active)
|
|
||||||
self.assertEqual(self.sidebar.selected_playlist, library)
|
|
||||||
|
|
||||||
def test_accelerators(self):
|
def test_accelerators(self):
|
||||||
"""Check that the accelerators list is set up properly."""
|
"""Check that the accelerators list is set up properly."""
|
||||||
|
|
Loading…
Reference in New Issue