Made the playlists list work
This commit is contained in:
@@ -11,6 +11,7 @@ from .ui.main import MainWindow
|
|||||||
from .ui.configure_servers import ConfigureServersDialog
|
from .ui.configure_servers import ConfigureServersDialog
|
||||||
|
|
||||||
from .state_manager import ApplicationState
|
from .state_manager import ApplicationState
|
||||||
|
from .cache_manager import CacheManager
|
||||||
|
|
||||||
|
|
||||||
class LibremsonicApp(Gtk.Application):
|
class LibremsonicApp(Gtk.Application):
|
||||||
@@ -96,6 +97,9 @@ class LibremsonicApp(Gtk.Application):
|
|||||||
context.add_provider_for_screen(screen, css_provider,
|
context.add_provider_for_screen(screen, css_provider,
|
||||||
Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||||
|
|
||||||
|
self.window.stack.connect('notify::visible-child',
|
||||||
|
self.on_stack_change)
|
||||||
|
|
||||||
# Display the window.
|
# Display the window.
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
self.window.present()
|
self.window.present()
|
||||||
@@ -108,8 +112,10 @@ class LibremsonicApp(Gtk.Application):
|
|||||||
if self.state.config.current_server is None:
|
if self.state.config.current_server is None:
|
||||||
self.show_configure_servers_dialog()
|
self.show_configure_servers_dialog()
|
||||||
else:
|
else:
|
||||||
self.on_connected_server_changed(None,
|
self.on_connected_server_changed(
|
||||||
self.state.config.current_server)
|
None,
|
||||||
|
self.state.config.current_server,
|
||||||
|
)
|
||||||
|
|
||||||
# ########## ACTION HANDLERS ########## #
|
# ########## ACTION HANDLERS ########## #
|
||||||
def on_configure_servers(self, action, param):
|
def on_configure_servers(self, action, param):
|
||||||
@@ -141,9 +147,15 @@ class LibremsonicApp(Gtk.Application):
|
|||||||
self.state.config.current_server = current_server
|
self.state.config.current_server = current_server
|
||||||
self.state.save_config()
|
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.
|
# Update the window according to the new server configuration.
|
||||||
self.update_window()
|
self.update_window()
|
||||||
|
|
||||||
|
def on_stack_change(self, stack, child):
|
||||||
|
self.update_window()
|
||||||
|
|
||||||
# ########## HELPER METHODS ########## #
|
# ########## HELPER METHODS ########## #
|
||||||
def show_configure_servers_dialog(self):
|
def show_configure_servers_dialog(self):
|
||||||
"""Show the Connect to Server dialog."""
|
"""Show the Connect to Server dialog."""
|
||||||
|
17
libremsonic/cache_manager.py
Normal file
17
libremsonic/cache_manager.py
Normal file
@@ -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()
|
@@ -1,10 +1,12 @@
|
|||||||
from typing import List, Any
|
from typing import List, Any
|
||||||
|
|
||||||
|
from libremsonic.cache_manager import CacheManager
|
||||||
from .config import get_config, save_config, AppConfiguration
|
from .config import get_config, save_config, AppConfiguration
|
||||||
|
|
||||||
|
|
||||||
class ApplicationState:
|
class ApplicationState:
|
||||||
config: AppConfiguration = AppConfiguration.get_default_configuration()
|
config: AppConfiguration = AppConfiguration.get_default_configuration()
|
||||||
|
cache_manager: CacheManager = None
|
||||||
current_song: Any # TODO fix
|
current_song: Any # TODO fix
|
||||||
config_file: str
|
config_file: str
|
||||||
playing: bool = False
|
playing: bool = False
|
||||||
|
@@ -4,13 +4,36 @@ import sys
|
|||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gio, Gtk
|
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."""
|
"""Defines the albums panel."""
|
||||||
|
|
||||||
def __init__(self):
|
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')
|
def update(self, state: ApplicationState):
|
||||||
|
pass
|
||||||
self.add(albums)
|
|
||||||
|
@@ -1,3 +1,11 @@
|
|||||||
|
/* ********** Playback Controls ********** */
|
||||||
|
#new-playlist-button {
|
||||||
|
border-radius: 0;
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ********** Playback Controls ********** */
|
/* ********** Playback Controls ********** */
|
||||||
#player-controls-bar #play-button {
|
#player-controls-bar #play-button {
|
||||||
min-height: 45px;
|
min-height: 45px;
|
||||||
@@ -13,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#player-controls-bar #song-scrubber {
|
#player-controls-bar #song-scrubber {
|
||||||
min-width: 300px;
|
min-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#player-controls-bar #volume-slider {
|
#player-controls-bar #volume-slider {
|
||||||
|
@@ -5,6 +5,7 @@ gi.require_version('Gtk', '3.0')
|
|||||||
from gi.repository import Gio, Gtk
|
from gi.repository import Gio, Gtk
|
||||||
|
|
||||||
from .albums import AlbumsPanel
|
from .albums import AlbumsPanel
|
||||||
|
from .playlists import PlaylistsPanel
|
||||||
from .player_controls import PlayerControls
|
from .player_controls import PlayerControls
|
||||||
from libremsonic.server import Server
|
from libremsonic.server import Server
|
||||||
from libremsonic.state_manager import ApplicationState
|
from libremsonic.state_manager import ApplicationState
|
||||||
@@ -20,21 +21,21 @@ class MainWindow(Gtk.ApplicationWindow):
|
|||||||
self.panels = {
|
self.panels = {
|
||||||
'Albums': AlbumsPanel(),
|
'Albums': AlbumsPanel(),
|
||||||
'Artists': Gtk.Label('Artists'),
|
'Artists': Gtk.Label('Artists'),
|
||||||
'Playlists': Gtk.Label('Playlists'),
|
'Playlists': PlaylistsPanel(),
|
||||||
'More': Gtk.Label('More'),
|
'More': Gtk.Label('More'),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create the stack
|
# Create the stack
|
||||||
stack = self.create_stack(**self.panels)
|
self.stack = self.create_stack(**self.panels)
|
||||||
stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
|
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.set_titlebar(self.titlebar)
|
||||||
|
|
||||||
self.player_controls = PlayerControls()
|
self.player_controls = PlayerControls()
|
||||||
|
|
||||||
flowbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
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)
|
flowbox.pack_start(self.player_controls, False, True, 0)
|
||||||
self.add(flowbox)
|
self.add(flowbox)
|
||||||
|
|
||||||
@@ -49,6 +50,10 @@ class MainWindow(Gtk.ApplicationWindow):
|
|||||||
self.connected_to_label.set_markup(
|
self.connected_to_label.set_markup(
|
||||||
f'<span style="italic">Not Connected to a Server</span>')
|
f'<span style="italic">Not Connected to a Server</span>')
|
||||||
|
|
||||||
|
active_panel = self.stack.get_visible_child()
|
||||||
|
if hasattr(active_panel, 'update'):
|
||||||
|
active_panel.update(state)
|
||||||
|
|
||||||
self.player_controls.update(state)
|
self.player_controls.update(state)
|
||||||
|
|
||||||
def create_stack(self, **kwargs):
|
def create_stack(self, **kwargs):
|
||||||
|
@@ -37,19 +37,27 @@ class PlayerControls(Gtk.ActionBar):
|
|||||||
details_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
details_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||||
details_box.pack_start(Gtk.Box(), True, True, 0)
|
details_box.pack_start(Gtk.Box(), True, True, 0)
|
||||||
|
|
||||||
self.song_name = Gtk.Label('<b>Song name</b>',
|
self.song_name = Gtk.Label(
|
||||||
halign=Gtk.Align.START,
|
'<b>Song name</b>',
|
||||||
use_markup=True)
|
halign=Gtk.Align.START,
|
||||||
|
use_markup=True,
|
||||||
|
)
|
||||||
self.song_name.set_name('song-name')
|
self.song_name.set_name('song-name')
|
||||||
details_box.add(self.song_name)
|
details_box.add(self.song_name)
|
||||||
|
|
||||||
self.album_name = Gtk.Label('Album name', halign=Gtk.Align.START)
|
self.album_name = Gtk.Label(
|
||||||
|
'<i>Album name</i>',
|
||||||
|
halign=Gtk.Align.START,
|
||||||
|
use_markup=True,
|
||||||
|
)
|
||||||
self.album_name.set_name('album-name')
|
self.album_name.set_name('album-name')
|
||||||
details_box.add(self.album_name)
|
details_box.add(self.album_name)
|
||||||
|
|
||||||
self.artist_name = Gtk.Label('<i>Artist name</i>',
|
self.artist_name = Gtk.Label(
|
||||||
halign=Gtk.Align.START,
|
'Artist name',
|
||||||
use_markup=True)
|
halign=Gtk.Align.START,
|
||||||
|
use_markup=True,
|
||||||
|
)
|
||||||
self.artist_name.set_name('artist-name')
|
self.artist_name.set_name('artist-name')
|
||||||
details_box.add(self.artist_name)
|
details_box.add(self.artist_name)
|
||||||
|
|
||||||
@@ -122,6 +130,8 @@ class PlayerControls(Gtk.ActionBar):
|
|||||||
return box
|
return box
|
||||||
|
|
||||||
def create_up_next_volume(self):
|
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)
|
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
||||||
|
|
||||||
# Up Next button
|
# Up Next button
|
||||||
@@ -144,7 +154,9 @@ class PlayerControls(Gtk.ActionBar):
|
|||||||
volume_slider.set_value(100)
|
volume_slider.set_value(100)
|
||||||
box.pack_start(volume_slider, True, True, 0)
|
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,
|
def button_with_icon(self,
|
||||||
icon_name,
|
icon_name,
|
||||||
|
63
libremsonic/ui/playlists.py
Normal file
63
libremsonic/ui/playlists.py
Normal file
@@ -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'<b>{playlist.name}</b>',
|
||||||
|
halign=Gtk.Align.START,
|
||||||
|
use_markup=True,
|
||||||
|
margin=10,
|
||||||
|
)
|
Reference in New Issue
Block a user