sidebar: Add keyboard shortcuts

The following shortcuts are implemented:

- <Control>? (<Shift><Control>/) to focus the "filter playlists" entry
- <Control><Alt>g to go to the current playlist
- <Shift><Control>p to open the Playlists section
- <Shift><Control>a to open the Artists section
- <Shift><Control>g to open the Genres section
- <Shift><Control>d to open the Decades section
- <Shift><Control>l to open the Libraries section

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2023-06-25 22:18:38 -04:00
parent bc92e72265
commit 0fd391a9fd
4 changed files with 65 additions and 0 deletions

View File

@ -182,6 +182,7 @@ class Application(Adw.Application):
side_bar = sidebar.Card(sql=self.db)
self.db.settings.bind_setting("sidebar.artists.show-all", side_bar,
"show-all-artists")
self.__add_accelerators(side_bar.accelerators)
return side_bar
def build_tracklist(self) -> tracklist.Card:

View File

@ -8,6 +8,7 @@ from . import genre
from . import library
from . import playlist
from . import section
from ..action import ActionEntry
from .. import db
from .. import entry
@ -86,3 +87,21 @@ class Card(Gtk.Box):
section.active = True
section.select_playlist(playlist)
@property
def accelerators(self) -> list[ActionEntry]:
"""Get a list of accelerators for the Sidebar."""
return [ActionEntry("focus-search-playlist", self._filter.grab_focus,
"<Control>question", enabled=(self, "sensitive")),
ActionEntry("goto-active-playlist", self._jump.activate,
"<Control><Alt>g", enabled=(self, "sensitive")),
ActionEntry("goto-playlists", self._playlists.activate,
"<Shift><Control>p", enabled=(self, "sensitive")),
ActionEntry("goto-artists", self._artists.activate,
"<Shift><Control>a", enabled=(self, "sensitive")),
ActionEntry("goto-genres", self._genres.activate,
"<Shift><Control>g", enabled=(self, "sensitive")),
ActionEntry("goto-decades", self._decades.activate,
"<Shift><Control>d", enabled=(self, "sensitive")),
ActionEntry("goto-libraries", self._libraries.activate,
"<Shift><Control>l", enabled=(self, "sensitive"))]

View File

@ -186,3 +186,37 @@ class TestSidebar(tests.util.TestCase):
self.sidebar.select_playlist(library)
self.assertTrue(self.sidebar._libraries.active)
self.assertEqual(self.sidebar.selected_playlist, library)
def test_accelerators(self):
"""Check that the accelerators list is set up properly."""
entries = [("focus-search-playlist", self.sidebar._filter.grab_focus,
["<Control>question"]),
("goto-active-playlist", self.sidebar._jump.activate,
["<Control><Alt>g"]),
("goto-playlists", self.sidebar._playlists.activate,
["<Shift><Control>p"]),
("goto-artists", self.sidebar._artists.activate,
["<Shift><Control>a"]),
("goto-genres", self.sidebar._genres.activate,
["<Shift><Control>g"]),
("goto-decades", self.sidebar._decades.activate,
["<Shift><Control>d"]),
("goto-libraries", self.sidebar._libraries.activate,
["<Shift><Control>l"])]
accels = self.sidebar.accelerators
self.assertIsInstance(accels, list)
for i, (name, func, accel) in enumerate(entries):
with self.subTest(action=name):
self.assertIsInstance(accels[i], emmental.action.ActionEntry)
self.assertEqual(accels[i].name, name)
self.assertEqual(accels[i].func, func)
self.assertListEqual(accels[i].accels, accel)
enabled = self.sidebar.get_sensitive()
self.assertEqual(accels[i].enabled, enabled)
self.sidebar.set_sensitive(not enabled)
self.assertEqual(accels[i].enabled, not enabled)
self.assertEqual(len(accels), i + 1)

View File

@ -205,6 +205,17 @@ class TestEmmental(unittest.TestCase):
self.application.player = emmental.audio.Player()
win = self.application.build_window()
for action, accel in [("app.focus-search-playlist",
"<Control>question"),
("app.goto-active-playlist", "<Control><Alt>g"),
("app.goto-playlists", "<Shift><Control>p"),
("app.goto-artists", "<Shift><Control>a"),
("app.goto-genres", "<Shift><Control>g"),
("app.goto-decades", "<Shift><Control>d"),
("app.goto-libraries", "<Shift><Control>l")]:
self.assertEqual(self.application.get_accels_for_action(action),
[accel])
self.assertEqual(win.sidebar.sql, self.application.db)
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)