Added Browse tab and implemented logic to change stack state
This commit is contained in:
@@ -96,6 +96,8 @@ class SublimeMusicApp(Gtk.Application):
|
||||
add_action('add-to-queue', self.on_add_to_queue, parameter_type='as')
|
||||
add_action('go-to-album', self.on_go_to_album, parameter_type='s')
|
||||
add_action('go-to-artist', self.on_go_to_artist, parameter_type='s')
|
||||
add_action(
|
||||
'browse-to-song', self.on_browse_to_song, parameter_type='s')
|
||||
add_action(
|
||||
'go-to-playlist', self.on_go_to_playlist, parameter_type='s')
|
||||
|
||||
@@ -581,6 +583,11 @@ class SublimeMusicApp(Gtk.Application):
|
||||
self.state.selected_artist_id = artist_id.get_string()
|
||||
self.update_window()
|
||||
|
||||
def on_browse_to_song(self, action, song_id):
|
||||
# Really, we want to browse to the song's parent.
|
||||
self.state.current_tab = 'browse'
|
||||
self.update_window()
|
||||
|
||||
def on_go_to_playlist(self, action, playlist_id):
|
||||
self.state.current_tab = 'playlists'
|
||||
self.state.selected_playlist_id = playlist_id.get_string()
|
||||
|
@@ -214,6 +214,12 @@ class CacheManager(metaclass=Singleton):
|
||||
def ready():
|
||||
return CacheManager._instance is not None
|
||||
|
||||
@staticmethod
|
||||
def browse_by_tags():
|
||||
return (
|
||||
CacheManager._instance is not None
|
||||
and CacheManager._instance.browse_by_tags)
|
||||
|
||||
@staticmethod
|
||||
def shutdown():
|
||||
CacheManager.should_exit = True
|
||||
@@ -523,6 +529,7 @@ class CacheManager(metaclass=Singleton):
|
||||
before_download: Callable[[], None] = lambda: None,
|
||||
force: bool = False,
|
||||
) -> 'CacheManager.Result[List[Union[Artist, ArtistID3]]]':
|
||||
# TODO: no need to id3ify I think.
|
||||
cache_name = self.id3ify('artists')
|
||||
|
||||
if self.cache.get(cache_name) and not force:
|
||||
@@ -556,6 +563,7 @@ class CacheManager(metaclass=Singleton):
|
||||
before_download: Callable[[], None] = lambda: None,
|
||||
force: bool = False,
|
||||
) -> 'CacheManager.Result[Union[ArtistWithAlbumsID3, Child]]':
|
||||
# TODO: no need to id3ify I think.
|
||||
cache_name = self.id3ify('artist_details')
|
||||
|
||||
if artist_id in self.cache.get(cache_name, {}) and not force:
|
||||
@@ -583,6 +591,7 @@ class CacheManager(metaclass=Singleton):
|
||||
before_download: Callable[[], None] = lambda: None,
|
||||
force: bool = False,
|
||||
) -> 'CacheManager.Result[Union[ArtistInfo, ArtistInfo2]]':
|
||||
# TODO: no need to id3ify I think.
|
||||
cache_name = self.id3ify('artist_infos')
|
||||
|
||||
if artist_id in self.cache.get(cache_name, {}) and not force:
|
||||
@@ -663,6 +672,7 @@ class CacheManager(metaclass=Singleton):
|
||||
# Look at documentation for get_album_list in server.py:
|
||||
**params,
|
||||
) -> 'CacheManager.Result[List[Union[Child, AlbumWithSongsID3]]]':
|
||||
# TODO: no need to id3ify I think.
|
||||
cache_name = self.id3ify('albums')
|
||||
|
||||
if (len(self.cache.get(cache_name, {}).get(type_, [])) > 0
|
||||
|
24
sublime/ui/browse.py
Normal file
24
sublime/ui/browse.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import gi
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, GObject, Pango, GLib, Gio
|
||||
|
||||
|
||||
class BrowsePanel(Gtk.Label):
|
||||
"""Defines the arist panel."""
|
||||
|
||||
__gsignals__ = {
|
||||
'song-clicked': (
|
||||
GObject.SignalFlags.RUN_FIRST,
|
||||
GObject.TYPE_NONE,
|
||||
(int, object, object),
|
||||
),
|
||||
'refresh-window': (
|
||||
GObject.SignalFlags.RUN_FIRST,
|
||||
GObject.TYPE_NONE,
|
||||
(object, bool),
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(label='ohea')
|
@@ -1,15 +1,10 @@
|
||||
import concurrent
|
||||
|
||||
from concurrent.futures import Future
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gio, Gtk, GObject, Gdk, GLib, Pango
|
||||
from fuzzywuzzy import fuzz
|
||||
|
||||
from . import albums, artists, playlists, player_controls
|
||||
from . import albums, artists, browse, playlists, player_controls
|
||||
from sublime.state_manager import ApplicationState
|
||||
from sublime.cache_manager import CacheManager, SearchResult
|
||||
from sublime.cache_manager import CacheManager
|
||||
from sublime.server.api_objects import Child
|
||||
from sublime.ui import util
|
||||
from sublime.ui.common import SpinnerImage
|
||||
@@ -47,9 +42,13 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self.set_default_size(1150, 768)
|
||||
|
||||
# Create the stack
|
||||
self.albums_panel = albums.AlbumsPanel()
|
||||
self.artists_panel = artists.ArtistsPanel()
|
||||
self.browse_panel = browse.BrowsePanel()
|
||||
self.stack = self.create_stack(
|
||||
Albums=albums.AlbumsPanel(),
|
||||
Artists=artists.ArtistsPanel(),
|
||||
Albums=self.albums_panel,
|
||||
Browse=self.browse_panel,
|
||||
Artists=self.artists_panel,
|
||||
Playlists=playlists.PlaylistsPanel(),
|
||||
)
|
||||
self.stack.set_transition_type(
|
||||
@@ -76,7 +75,19 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self.connect('button-release-event', self.on_button_release)
|
||||
|
||||
def update(self, state: ApplicationState, force=False):
|
||||
# Have to do this before hiding/showing the panels to avoid issues with
|
||||
# the current_tab being overridden.
|
||||
self.stack.set_visible_child_name(state.current_tab)
|
||||
|
||||
self.browse_by_tags = state.config.server.browse_by_tags
|
||||
if self.browse_by_tags:
|
||||
self.browse_panel.hide()
|
||||
self.albums_panel.show()
|
||||
self.artists_panel.show()
|
||||
else:
|
||||
self.browse_panel.show()
|
||||
self.albums_panel.hide()
|
||||
self.artists_panel.hide()
|
||||
|
||||
# Update the Connected to label on the popup menu.
|
||||
if state.config.current_server >= 0:
|
||||
@@ -88,8 +99,6 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self.connected_to_label.set_markup(
|
||||
f'<span style="italic">Not Connected to a Server</span>')
|
||||
|
||||
self.stack.set_visible_child_name(state.current_tab)
|
||||
|
||||
active_panel = self.stack.get_visible_child()
|
||||
if hasattr(active_panel, 'update'):
|
||||
active_panel.update(state, force=force)
|
||||
@@ -339,7 +348,12 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
widget.remove(c)
|
||||
|
||||
def create_search_result_row(
|
||||
self, text, action_name, value, artwork_future):
|
||||
self,
|
||||
text,
|
||||
action_name,
|
||||
value,
|
||||
artwork_future,
|
||||
):
|
||||
row = Gtk.Button(relief=Gtk.ReliefStyle.NONE)
|
||||
row.connect(
|
||||
'button-press-event',
|
||||
|
@@ -154,12 +154,13 @@ def show_song_popover(
|
||||
|
||||
# Determine if we should enable the download button.
|
||||
download_sensitive, remove_download_sensitive = False, False
|
||||
albums, artists = set(), set()
|
||||
albums, artists, parents = set(), set(), set()
|
||||
for song_id in song_ids:
|
||||
details = CacheManager.get_song_details(song_id).result()
|
||||
status = CacheManager.get_cached_status(details)
|
||||
albums.add(details.albumId)
|
||||
artists.add(details.artistId)
|
||||
parents.add(details.parent)
|
||||
|
||||
if download_sensitive or status == SongCacheStatus.NOT_CACHED:
|
||||
download_sensitive = True
|
||||
@@ -181,6 +182,14 @@ def show_song_popover(
|
||||
artist_value = GLib.Variant('s', list(artists)[0])
|
||||
go_to_artist_button.set_action_target_value(artist_value)
|
||||
|
||||
browse_to_song = Gtk.ModelButton(
|
||||
text=f"Browse to {pluralize('song', song_count)}",
|
||||
action_name='app.browse-to-song',
|
||||
)
|
||||
if len(parents) == 1 and list(parents)[0] is not None:
|
||||
parent_value = GLib.Variant('s', list(parents)[0])
|
||||
browse_to_song.set_action_target_value(parent_value)
|
||||
|
||||
menu_items = [
|
||||
Gtk.ModelButton(
|
||||
text='Play next',
|
||||
@@ -193,31 +202,38 @@ def show_song_popover(
|
||||
action_target=GLib.Variant('as', song_ids),
|
||||
),
|
||||
Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
|
||||
go_to_album_button,
|
||||
go_to_artist_button,
|
||||
Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
|
||||
(
|
||||
Gtk.ModelButton(
|
||||
text=f"Download {pluralize('song', song_count)}",
|
||||
sensitive=download_sensitive,
|
||||
),
|
||||
on_download_songs_click,
|
||||
),
|
||||
(
|
||||
Gtk.ModelButton(
|
||||
text=f"Remove {pluralize('download', song_count)}",
|
||||
sensitive=remove_download_sensitive,
|
||||
),
|
||||
on_remove_downloads_click,
|
||||
),
|
||||
Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
|
||||
Gtk.ModelButton(
|
||||
text=f"Add {pluralize('song', song_count)} to playlist",
|
||||
menu_name='add-to-playlist',
|
||||
),
|
||||
*extra_menu_items,
|
||||
]
|
||||
|
||||
if CacheManager.browse_by_tags():
|
||||
menu_items.extend([go_to_album_button, go_to_artist_button])
|
||||
else:
|
||||
menu_items.extend([browse_to_song])
|
||||
|
||||
menu_items.extend(
|
||||
[
|
||||
Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
|
||||
(
|
||||
Gtk.ModelButton(
|
||||
text=f"Download {pluralize('song', song_count)}",
|
||||
sensitive=download_sensitive,
|
||||
),
|
||||
on_download_songs_click,
|
||||
),
|
||||
(
|
||||
Gtk.ModelButton(
|
||||
text=f"Remove {pluralize('download', song_count)}",
|
||||
sensitive=remove_download_sensitive,
|
||||
),
|
||||
on_remove_downloads_click,
|
||||
),
|
||||
Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
|
||||
Gtk.ModelButton(
|
||||
text=f"Add {pluralize('song', song_count)} to playlist",
|
||||
menu_name='add-to-playlist',
|
||||
),
|
||||
*extra_menu_items,
|
||||
])
|
||||
|
||||
for item in menu_items:
|
||||
if type(item) == tuple:
|
||||
el, fn = item
|
||||
|
Reference in New Issue
Block a user