From af3d0247127785d74cbcd3f26e1f7f5e0cb1e436 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 22 Jun 2019 14:45:38 -0600 Subject: [PATCH] Made the playlists list work --- libremsonic/app.py | 16 +++++++- libremsonic/cache_manager.py | 17 +++++++++ libremsonic/state_manager.py | 2 + libremsonic/ui/albums.py | 33 +++++++++++++--- libremsonic/ui/app_styles.css | 10 ++++- libremsonic/ui/main.py | 15 +++++--- libremsonic/ui/player_controls.py | 28 ++++++++++---- libremsonic/ui/playlists.py | 63 +++++++++++++++++++++++++++++++ 8 files changed, 163 insertions(+), 21 deletions(-) create mode 100644 libremsonic/cache_manager.py create mode 100644 libremsonic/ui/playlists.py diff --git a/libremsonic/app.py b/libremsonic/app.py index c1ad72b..68af6e2 100644 --- a/libremsonic/app.py +++ b/libremsonic/app.py @@ -11,6 +11,7 @@ from .ui.main import MainWindow from .ui.configure_servers import ConfigureServersDialog from .state_manager import ApplicationState +from .cache_manager import CacheManager class LibremsonicApp(Gtk.Application): @@ -96,6 +97,9 @@ class LibremsonicApp(Gtk.Application): context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER) + self.window.stack.connect('notify::visible-child', + self.on_stack_change) + # Display the window. self.window.show_all() self.window.present() @@ -108,8 +112,10 @@ class LibremsonicApp(Gtk.Application): if self.state.config.current_server is None: self.show_configure_servers_dialog() else: - self.on_connected_server_changed(None, - self.state.config.current_server) + self.on_connected_server_changed( + None, + self.state.config.current_server, + ) # ########## ACTION HANDLERS ########## # def on_configure_servers(self, action, param): @@ -141,9 +147,15 @@ class LibremsonicApp(Gtk.Application): self.state.config.current_server = current_server self.state.save_config() + self.state.cache_manager = CacheManager( + self.state.config.servers[self.state.config.current_server]) + # Update the window according to the new server configuration. self.update_window() + def on_stack_change(self, stack, child): + self.update_window() + # ########## HELPER METHODS ########## # def show_configure_servers_dialog(self): """Show the Connect to Server dialog.""" diff --git a/libremsonic/cache_manager.py b/libremsonic/cache_manager.py new file mode 100644 index 0000000..9581859 --- /dev/null +++ b/libremsonic/cache_manager.py @@ -0,0 +1,17 @@ +from libremsonic.config import ServerConfiguration +from libremsonic.server import Server + + +class CacheManager: + server: Server + + def __init__(self, server_config: ServerConfiguration): + self.server = Server( + name=server_config.name, + hostname=server_config.server_address, + username=server_config.username, + password=server_config.password, + ) + + def get_playlists(self): + return self.server.get_playlists() diff --git a/libremsonic/state_manager.py b/libremsonic/state_manager.py index 8b6a2eb..0631e35 100644 --- a/libremsonic/state_manager.py +++ b/libremsonic/state_manager.py @@ -1,10 +1,12 @@ from typing import List, Any +from libremsonic.cache_manager import CacheManager from .config import get_config, save_config, AppConfiguration class ApplicationState: config: AppConfiguration = AppConfiguration.get_default_configuration() + cache_manager: CacheManager = None current_song: Any # TODO fix config_file: str playing: bool = False diff --git a/libremsonic/ui/albums.py b/libremsonic/ui/albums.py index a6257c7..356ce44 100644 --- a/libremsonic/ui/albums.py +++ b/libremsonic/ui/albums.py @@ -4,13 +4,36 @@ import sys gi.require_version('Gtk', '3.0') from gi.repository import Gio, Gtk +from libremsonic.state_manager import ApplicationState -class AlbumsPanel(Gtk.Box): + +class AlbumsPanel(Gtk.ScrolledWindow): + def __init__(self): + Gtk.ScrolledWindow.__init__(self) + self.child = AlbumsGrid() + self.add(self.child) + + def update(self, state: ApplicationState): + self.child.update(state) + + +class AlbumsGrid(Gtk.FlowBox): """Defines the albums panel.""" def __init__(self): - Gtk.Box.__init__(self) + Gtk.FlowBox.__init__( + self, + vexpand=True, + hexpand=True, + row_spacing=12, + column_spacing=12, + margin_top=12, + margin_bottom=12, + homogeneous=True, + valign=Gtk.Align.START, + halign=Gtk.Align.CENTER, + selection_mode=Gtk.SelectionMode.NONE, + ) - albums = Gtk.Label('Albums') - - self.add(albums) + def update(self, state: ApplicationState): + pass diff --git a/libremsonic/ui/app_styles.css b/libremsonic/ui/app_styles.css index 9ce63a4..a67fb25 100644 --- a/libremsonic/ui/app_styles.css +++ b/libremsonic/ui/app_styles.css @@ -1,3 +1,11 @@ +/* ********** Playback Controls ********** */ +#new-playlist-button { + border-radius: 0; + border-left: none; + border-right: none; + border-bottom: none; +} + /* ********** Playback Controls ********** */ #player-controls-bar #play-button { min-height: 45px; @@ -13,7 +21,7 @@ } #player-controls-bar #song-scrubber { - min-width: 300px; + min-width: 400px; } #player-controls-bar #volume-slider { diff --git a/libremsonic/ui/main.py b/libremsonic/ui/main.py index 8a0f3bc..f1b7597 100644 --- a/libremsonic/ui/main.py +++ b/libremsonic/ui/main.py @@ -5,6 +5,7 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gio, Gtk from .albums import AlbumsPanel +from .playlists import PlaylistsPanel from .player_controls import PlayerControls from libremsonic.server import Server from libremsonic.state_manager import ApplicationState @@ -20,21 +21,21 @@ class MainWindow(Gtk.ApplicationWindow): self.panels = { 'Albums': AlbumsPanel(), 'Artists': Gtk.Label('Artists'), - 'Playlists': Gtk.Label('Playlists'), + 'Playlists': PlaylistsPanel(), 'More': Gtk.Label('More'), } # Create the stack - stack = self.create_stack(**self.panels) - stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) + self.stack = self.create_stack(**self.panels) + self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) - self.titlebar = self.create_headerbar(stack) + self.titlebar = self.create_headerbar(self.stack) self.set_titlebar(self.titlebar) self.player_controls = PlayerControls() flowbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - flowbox.pack_start(stack, True, True, 0) + flowbox.pack_start(self.stack, True, True, 0) flowbox.pack_start(self.player_controls, False, True, 0) self.add(flowbox) @@ -49,6 +50,10 @@ class MainWindow(Gtk.ApplicationWindow): self.connected_to_label.set_markup( f'Not Connected to a Server') + active_panel = self.stack.get_visible_child() + if hasattr(active_panel, 'update'): + active_panel.update(state) + self.player_controls.update(state) def create_stack(self, **kwargs): diff --git a/libremsonic/ui/player_controls.py b/libremsonic/ui/player_controls.py index 8bd630d..2b0ca84 100644 --- a/libremsonic/ui/player_controls.py +++ b/libremsonic/ui/player_controls.py @@ -37,19 +37,27 @@ class PlayerControls(Gtk.ActionBar): details_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) details_box.pack_start(Gtk.Box(), True, True, 0) - self.song_name = Gtk.Label('Song name', - halign=Gtk.Align.START, - use_markup=True) + self.song_name = Gtk.Label( + 'Song name', + halign=Gtk.Align.START, + use_markup=True, + ) self.song_name.set_name('song-name') details_box.add(self.song_name) - self.album_name = Gtk.Label('Album name', halign=Gtk.Align.START) + self.album_name = Gtk.Label( + 'Album name', + halign=Gtk.Align.START, + use_markup=True, + ) self.album_name.set_name('album-name') details_box.add(self.album_name) - self.artist_name = Gtk.Label('Artist name', - halign=Gtk.Align.START, - use_markup=True) + self.artist_name = Gtk.Label( + 'Artist name', + halign=Gtk.Align.START, + use_markup=True, + ) self.artist_name.set_name('artist-name') details_box.add(self.artist_name) @@ -122,6 +130,8 @@ class PlayerControls(Gtk.ActionBar): return box def create_up_next_volume(self): + vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + vbox.pack_start(Gtk.Box(), True, True, 0) box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) # Up Next button @@ -144,7 +154,9 @@ class PlayerControls(Gtk.ActionBar): volume_slider.set_value(100) box.pack_start(volume_slider, True, True, 0) - return box + vbox.pack_start(box, False, True, 0) + vbox.pack_start(Gtk.Box(), True, True, 0) + return vbox def button_with_icon(self, icon_name, diff --git a/libremsonic/ui/playlists.py b/libremsonic/ui/playlists.py new file mode 100644 index 0000000..188fcc1 --- /dev/null +++ b/libremsonic/ui/playlists.py @@ -0,0 +1,63 @@ +import gi +import sys + +gi.require_version('Gtk', '3.0') +from gi.repository import Gio, Gtk + +from libremsonic.server.api_objects import Playlist +from libremsonic.state_manager import ApplicationState + + +class PlaylistsPanel(Gtk.Paned): + """Defines the playlists panel.""" + + def __init__(self): + Gtk.FlowBox.__init__( + self, + orientation=Gtk.Orientation.HORIZONTAL, + ) + + # The playlist list on the left side + # ===================================================================== + playlist_list_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + + list_scroll_window = Gtk.ScrolledWindow(min_content_width=200) + self.playlist_list = Gtk.ListBox() + list_scroll_window.add(self.playlist_list) + playlist_list_vbox.pack_start(list_scroll_window, True, True, 0) + + # Add playlist button + box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + add_icon = Gio.ThemedIcon(name='list-add') + image = Gtk.Image.new_from_gicon(add_icon, Gtk.IconSize.LARGE_TOOLBAR) + box.add(image) + box.add(Gtk.Label('New Playlist', margin=10)) + + self.new_playlist = Gtk.Button(name='new-playlist-button') + self.new_playlist.add(box) + playlist_list_vbox.pack_start(self.new_playlist, False, False, 0) + self.pack1(playlist_list_vbox, False, False) + + # The playlist view on the right side + # ===================================================================== + self.playlist_view = Gtk.ListBox() + self.pack2(self.playlist_view, True, False) + + def update(self, state: ApplicationState): + playlists = state.cache_manager.get_playlists() + + for c in self.playlist_list.get_children(): + self.playlist_list.remove(c) + + for playlist in playlists.playlist: + self.playlist_list.add(self.create_playlist_label(playlist)) + + self.playlist_list.show_all() + + def create_playlist_label(self, playlist: Playlist): + return Gtk.Label( + f'{playlist.name}', + halign=Gtk.Align.START, + use_markup=True, + margin=10, + )