Added buttons places

This commit is contained in:
Sumner Evans
2019-08-31 15:07:55 -06:00
parent 57f232bcb6
commit 1acea88e94
12 changed files with 242 additions and 84 deletions

View File

@@ -293,11 +293,14 @@ class LibremsonicApp(Gtk.Application):
def on_stack_change(self, stack, child):
self.update_window()
def on_song_clicked(self, win, song_id, song_queue):
def on_song_clicked(self, win, song_id, song_queue, metadata):
# Reset the play queue so that we don't ever revert back to the
# previous one.
old_play_queue = song_queue.copy()
if metadata.get('force_shuffle_state') is not None:
self.state.shuffle_on = metadata['force_shuffle_state']
# If shuffle is enabled, then shuffle the playlist.
if self.state.shuffle_on:
song_queue.remove(song_id)
@@ -449,7 +452,10 @@ class LibremsonicApp(Gtk.Application):
self.player.reset()
self.state.song_progress = 0
def on_song_download_complete(_):
def on_song_download_complete(song_id):
if self.state.current_song != song.id:
return
# Switch to the local media if the player can hotswap (MPV can,
# Chromecast cannot hotswap without lag).
if self.player.can_hotswap_source:

View File

@@ -1,5 +1,4 @@
import gi
import threading
from typing import Optional, Union
gi.require_version('Gtk', '3.0')
@@ -8,7 +7,7 @@ from gi.repository import Gtk, GObject, GLib
from libremsonic.state_manager import ApplicationState
from libremsonic.cache_manager import CacheManager
from libremsonic.ui import util
from libremsonic.ui.common import AlbumWithSongs, CoverArtGrid
from libremsonic.ui.common import AlbumWithSongs, IconButton, CoverArtGrid
from libremsonic.server.api_objects import Child, AlbumWithSongsID3
@@ -20,7 +19,7 @@ class AlbumsPanel(Gtk.Box):
'song-clicked': (
GObject.SignalFlags.RUN_FIRST,
GObject.TYPE_NONE,
(str, object),
(str, object, object),
),
}
@@ -84,7 +83,7 @@ class AlbumsPanel(Gtk.Box):
self.to_year_entry.connect('changed', self.on_year_changed)
actionbar.pack_start(self.to_year_entry)
refresh = util.button_with_icon('view-refresh')
refresh = IconButton('view-refresh')
refresh.connect('clicked', lambda *a: self.update(force=True))
actionbar.pack_end(refresh)
@@ -94,7 +93,8 @@ class AlbumsPanel(Gtk.Box):
self.grid = AlbumsGrid()
self.grid.connect(
'song-clicked',
lambda _, song, queue: self.emit('song-clicked', song, queue),
lambda _, song, queue, metadata: self.emit('song-clicked', song,
queue, metadata),
)
scrolled_window.add(self.grid)
self.add(scrolled_window)

View File

@@ -4,6 +4,16 @@
margin-bottom: 10px;
}
#icon-button-box image {
margin-left: 2px;
margin-right: 2px;
}
#icon-button-box label {
margin-left: 5px;
margin-right: 3px;
}
/* ********** Playlist ********** */
#playlist-list-listbox row {
margin: 0;
@@ -58,6 +68,10 @@
margin: -10px 0 0 10px;
}
#playlist-play-shuffle-buttons {
margin-bottom: 10px;
}
/* ********** Playback Controls ********** */
#player-controls-album-artwork {
min-height: 70px;
@@ -73,7 +87,8 @@
/* Make the play icon look centered. */
#player-controls-bar #play-button image {
margin-left: 1px;
margin-left: 5px;
margin-right: 5px;
margin-top: 1px;
}

View File

@@ -8,7 +8,7 @@ from gi.repository import Gtk, GObject, Pango
from libremsonic.state_manager import ApplicationState
from libremsonic.cache_manager import CacheManager
from libremsonic.ui import util
from libremsonic.ui.common import AlbumWithSongs, SpinnerImage
from libremsonic.ui.common import AlbumWithSongs, IconButton, SpinnerImage
from libremsonic.server.api_objects import (
AlbumID3,
@@ -25,7 +25,7 @@ class ArtistsPanel(Gtk.Paned):
'song-clicked': (
GObject.SignalFlags.RUN_FIRST,
GObject.TYPE_NONE,
(str, object),
(str, object, object),
),
}
artist_id: Optional[str] = None
@@ -45,7 +45,8 @@ class ArtistsPanel(Gtk.Paned):
self.artist_detail_panel = ArtistDetailPanel()
self.artist_detail_panel.connect(
'song-clicked',
lambda _, song, queue: self.emit('song-clicked', song, queue),
lambda _, song, queue, metadata: self.emit('song-clicked', song,
queue, metadata),
)
self.pack2(self.artist_detail_panel, True, False)
@@ -75,7 +76,7 @@ class ArtistList(Gtk.Box):
list_actions = Gtk.ActionBar()
refresh = util.button_with_icon('view-refresh')
refresh = IconButton('view-refresh')
refresh.connect('clicked', lambda *a: self.update(force=True))
list_actions.pack_end(refresh)
@@ -156,7 +157,7 @@ class ArtistDetailPanel(Gtk.Box):
'song-clicked': (
GObject.SignalFlags.RUN_FIRST,
GObject.TYPE_NONE,
(str, object),
(str, object, object),
),
}
@@ -190,12 +191,12 @@ class ArtistDetailPanel(Gtk.Box):
self.artist_action_buttons = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL)
view_refresh_button = util.button_with_icon('view-refresh-symbolic')
view_refresh_button = IconButton('view-refresh-symbolic')
view_refresh_button.connect('clicked', self.on_view_refresh_click)
self.artist_action_buttons.pack_end(view_refresh_button, False, False,
5)
download_all_btn = util.button_with_icon('folder-download-symbolic')
download_all_btn = IconButton('folder-download-symbolic')
download_all_btn.connect('clicked', self.on_download_all_click)
self.artist_action_buttons.pack_end(download_all_btn, False, False, 5)
@@ -237,7 +238,8 @@ class ArtistDetailPanel(Gtk.Box):
self.albums_list = AlbumsListWithSongs()
self.albums_list.connect(
'song-clicked',
lambda _, song, queue: self.emit('song-clicked', song, queue),
lambda _, song, queue, metadata: self.emit(
'song-clicked', song, queue, metadata),
)
artist_info_box.pack_start(self.albums_list, True, True, 0)
@@ -361,7 +363,7 @@ class AlbumsListWithSongs(Gtk.Overlay):
'song-clicked': (
GObject.SignalFlags.RUN_FIRST,
GObject.TYPE_NONE,
(str, object),
(str, object, object),
),
}
@@ -391,7 +393,8 @@ class AlbumsListWithSongs(Gtk.Overlay):
album_with_songs = AlbumWithSongs(album, show_artist_name=False)
album_with_songs.connect(
'song-clicked',
lambda _, song, queue: self.emit('song-clicked', song, queue),
lambda _, song, queue, metadata: self.emit(
'song-clicked', song, queue, metadata),
)
album_with_songs.connect('song-selected', self.on_song_selected)
album_with_songs.show_all()

View File

@@ -1,6 +1,13 @@
from .album_with_songs import AlbumWithSongs
from .cover_art_grid import CoverArtGrid
from .edit_form_dialog import EditFormDialog
from .icon_button import IconButton
from .spinner_image import SpinnerImage
__all__ = ('AlbumWithSongs', 'CoverArtGrid', 'EditFormDialog', 'SpinnerImage')
__all__ = (
'AlbumWithSongs',
'CoverArtGrid',
'EditFormDialog',
'IconButton',
'SpinnerImage',
)

View File

@@ -1,4 +1,5 @@
from typing import Union
from random import randint
import gi
@@ -7,6 +8,7 @@ from gi.repository import Gtk, GObject, Pango, GLib
from libremsonic.cache_manager import CacheManager
from libremsonic.ui import util
from .icon_button import IconButton
from .spinner_image import SpinnerImage
from libremsonic.server.api_objects import (
@@ -26,7 +28,7 @@ class AlbumWithSongs(Gtk.Box):
'song-clicked': (
GObject.SignalFlags.RUN_FIRST,
GObject.TYPE_NONE,
(str, object),
(str, object, object),
),
}
@@ -60,13 +62,39 @@ class AlbumWithSongs(Gtk.Box):
lambda f: GLib.idle_add(cover_art_future_done, f))
album_details = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
album_details.add(
album_title_and_buttons = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL)
album_title_and_buttons.add(
Gtk.Label(
label=album.get('name', album.get('title')),
name='artist-album-list-album-name',
halign=Gtk.Align.START,
))
play_btn = IconButton('media-playback-start-symbolic')
play_btn.connect('clicked', self.play_btn_clicked)
album_title_and_buttons.pack_start(play_btn, False, False, 5)
shuffle_btn_clicked = IconButton('media-playlist-shuffle-symbolic')
shuffle_btn_clicked.connect('clicked', self.shuffle_btn_clicked)
album_title_and_buttons.pack_start(shuffle_btn_clicked, False, False,
5)
play_next = IconButton('go-top-symbolic')
play_next.connect('clicked', self.play_next_clicked)
album_title_and_buttons.pack_start(play_next, False, False, 5)
add_to_queue = IconButton('go-jump-symbolic')
add_to_queue.connect('clicked', self.add_to_queue_clicked)
album_title_and_buttons.pack_start(add_to_queue, False, False, 5)
download_all_btn = IconButton('folder-download-symbolic')
download_all_btn.connect('clicked', self.on_download_all_click)
album_title_and_buttons.pack_end(download_all_btn, False, False, 5)
album_details.add(album_title_and_buttons)
stats = [
album.artist if show_artist_name else None,
album.year,
@@ -144,6 +172,8 @@ class AlbumWithSongs(Gtk.Box):
self.update_album_songs(album.id)
# Event Handlers
# =========================================================================
def on_song_selection_change(self, event):
if not self.album_songs.has_focus():
self.emit('song-selected')
@@ -152,7 +182,7 @@ class AlbumWithSongs(Gtk.Box):
# The song ID is in the last column of the model.
song_id = self.album_song_store[idx][-1]
self.emit('song-clicked', song_id,
[m[-1] for m in self.album_song_store])
[m[-1] for m in self.album_song_store], {})
def on_song_button_press(self, tree, event):
if event.button == 3: # Right click
@@ -192,6 +222,42 @@ class AlbumWithSongs(Gtk.Box):
if not allow_deselect:
return True
def on_download_all_click(self, btn):
CacheManager.batch_download_songs(
[x[-1] for x in self.album_song_store],
before_download=self.update,
on_song_download_complete=lambda x: self.update(),
)
def play_btn_clicked(self, btn):
song_ids = [x[-1] for x in self.album_song_store]
self.emit(
'song-clicked',
song_ids[0],
song_ids,
{'force_shuffle_state': False},
)
def shuffle_btn_clicked(self, btn):
rand_idx = randint(0, len(self.album_song_store))
song_ids = [x[-1] for x in self.album_song_store]
self.emit(
'song-clicked',
song_ids[rand_idx],
song_ids,
{'force_shuffle_state': True},
)
def play_next_clicked(self, btn):
# TODO
print('play next')
def add_to_queue_clicked(self, btn):
# TODO
print('add to queue')
# Helper Methods
# =========================================================================
def deselect_all(self):
self.album_songs.get_selection().unselect_all()

View File

@@ -15,7 +15,7 @@ class CoverArtGrid(Gtk.ScrolledWindow):
'song-clicked': (
GObject.SignalFlags.RUN_FIRST,
GObject.TYPE_NONE,
(str, object),
(str, object, object),
)
}
@@ -281,7 +281,8 @@ class CoverArtGrid(Gtk.ScrolledWindow):
detail_element = self.create_detail_element_from_model(model)
detail_element.connect(
'song-clicked',
lambda _, song, queue: self.emit('song-clicked', song, queue),
lambda _, song, queue, metadata: self.emit(
'song-clicked', song, queue, metadata),
)
detail_element.connect('song-selected', lambda *a: None)

View File

@@ -0,0 +1,32 @@
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gio, Gtk
class IconButton(Gtk.Button):
def __init__(
self,
icon_name,
relief=False,
icon_size=Gtk.IconSize.BUTTON,
label=None,
):
Gtk.Button.__init__(self)
self.icon_size = icon_size
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
name='icon-button-box')
self.image = Gtk.Image()
self.image.set_from_icon_name(icon_name, self.icon_size)
box.add(self.image)
if label is not None:
box.add(Gtk.Label(label=label))
if not relief:
self.props.relief = Gtk.ReliefStyle.NONE
self.add(box)
def set_icon(self, icon_name):
self.image.set_from_icon_name(icon_name, self.icon_size)

View File

@@ -12,8 +12,8 @@ from libremsonic.state_manager import ApplicationState
class MainWindow(Gtk.ApplicationWindow):
"""Defines the main window for LibremSonic."""
__gsignals__ = {
'song-clicked':
(GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (str, object)),
'song-clicked': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
(str, object, object)),
}
def __init__(self, *args, **kwargs):
@@ -56,8 +56,8 @@ class MainWindow(Gtk.ApplicationWindow):
self.player_controls.update(state)
def on_song_clicked(self, panel, song, queue):
self.emit('song-clicked', song, queue)
def on_song_clicked(self, panel, song, queue, metadata):
self.emit('song-clicked', song, queue, metadata)
def create_stack(self, **kwargs):
stack = Gtk.Stack()

View File

@@ -7,7 +7,7 @@ from gi.repository import Gtk, Pango, GObject, Gio, GLib
from libremsonic.cache_manager import CacheManager
from libremsonic.state_manager import ApplicationState, RepeatType
from libremsonic.ui import util
from libremsonic.ui.common import SpinnerImage
from libremsonic.ui.common import IconButton, SpinnerImage
from libremsonic.ui.common.players import ChromecastPlayer
@@ -41,8 +41,7 @@ class PlayerControls(Gtk.ActionBar):
state.current_song.duration)
icon = 'pause' if state.playing else 'start'
self.play_button.get_child().set_from_icon_name(
f"media-playback-{icon}-symbolic", Gtk.IconSize.LARGE_TOOLBAR)
self.play_button.set_icon(f"media-playback-{icon}-symbolic")
has_current_song = (hasattr(state, 'current_song')
and state.current_song is not None)
@@ -118,7 +117,8 @@ class PlayerControls(Gtk.ActionBar):
else:
song_label = str(play_queue_len) + ' ' + util.pluralize(
'song', play_queue_len)
self.popover_label.set_markup(f'<b>Play Queue:</b> {song_label}')
self.popover_label.set_markup(
f'<b>Play Queue:</b> {song_label}')
# Remove everything from the play queue.
for c in self.play_queue_list.get_children():
@@ -285,35 +285,32 @@ class PlayerControls(Gtk.ActionBar):
buttons.pack_start(Gtk.Box(), True, True, 0)
# Repeat button
self.repeat_button = util.button_with_icon('media-playlist-repeat')
self.repeat_button = IconButton('media-playlist-repeat')
self.repeat_button.set_action_name('app.repeat-press')
buttons.pack_start(self.repeat_button, False, False, 5)
# Previous button
self.prev_button = util.button_with_icon(
'media-skip-backward-symbolic',
icon_size=Gtk.IconSize.LARGE_TOOLBAR)
self.prev_button = IconButton('media-skip-backward-symbolic',
icon_size=Gtk.IconSize.LARGE_TOOLBAR)
self.prev_button.set_action_name('app.prev-track')
buttons.pack_start(self.prev_button, False, False, 5)
# Play button
self.play_button = util.button_with_icon(
'media-playback-start-symbolic',
relief=True,
icon_size=Gtk.IconSize.LARGE_TOOLBAR)
self.play_button = IconButton('media-playback-start-symbolic',
relief=True,
icon_size=Gtk.IconSize.LARGE_TOOLBAR)
self.play_button.set_name('play-button')
self.play_button.set_action_name('app.play-pause')
buttons.pack_start(self.play_button, False, False, 0)
# Next button
self.next_button = util.button_with_icon(
'media-skip-forward-symbolic',
icon_size=Gtk.IconSize.LARGE_TOOLBAR)
self.next_button = IconButton('media-skip-forward-symbolic',
icon_size=Gtk.IconSize.LARGE_TOOLBAR)
self.next_button.set_action_name('app.next-track')
buttons.pack_start(self.next_button, False, False, 5)
# Shuffle button
self.shuffle_button = util.button_with_icon('media-playlist-shuffle')
self.shuffle_button = IconButton('media-playlist-shuffle')
self.shuffle_button.set_action_name('app.shuffle-press')
buttons.pack_start(self.shuffle_button, False, False, 5)
@@ -329,8 +326,8 @@ class PlayerControls(Gtk.ActionBar):
# Device button (for chromecast)
# TODO need icon
device_button = util.button_with_icon(
'view-list-symbolic', icon_size=Gtk.IconSize.LARGE_TOOLBAR)
device_button = IconButton('view-list-symbolic',
icon_size=Gtk.IconSize.LARGE_TOOLBAR)
device_button.connect('clicked', self.on_device_click)
box.pack_start(device_button, False, True, 5)
@@ -347,7 +344,7 @@ class PlayerControls(Gtk.ActionBar):
)
device_popover_header.add(self.popover_label)
refresh_devices = util.button_with_icon('view-refresh')
refresh_devices = IconButton('view-refresh')
refresh_devices.connect('clicked', self.on_device_refresh_click)
device_popover_header.pack_end(refresh_devices, False, False, 0)
@@ -376,8 +373,8 @@ class PlayerControls(Gtk.ActionBar):
self.device_popover.add(device_popover_box)
# Play Queue button
play_queue_button = util.button_with_icon(
'view-list-symbolic', icon_size=Gtk.IconSize.LARGE_TOOLBAR)
play_queue_button = IconButton('view-list-symbolic',
icon_size=Gtk.IconSize.LARGE_TOOLBAR)
play_queue_button.connect('clicked', self.on_play_queue_click)
box.pack_start(play_queue_button, False, True, 5)
@@ -412,7 +409,7 @@ class PlayerControls(Gtk.ActionBar):
self.play_queue_popover.add(play_queue_popover_box)
# Volume mute toggle
self.volume_mute_toggle = util.button_with_icon('audio-volume-high')
self.volume_mute_toggle = IconButton('audio-volume-high')
self.volume_mute_toggle.set_action_name('app.mute-toggle')
box.pack_start(self.volume_mute_toggle, False, True, 0)

View File

@@ -1,4 +1,5 @@
from functools import lru_cache
from random import randint
from typing import List, OrderedDict
from fuzzywuzzy import process
@@ -11,7 +12,7 @@ from libremsonic.server.api_objects import PlaylistWithSongs
from libremsonic.state_manager import ApplicationState
from libremsonic.cache_manager import CacheManager
from libremsonic.ui import util
from libremsonic.ui.common import EditFormDialog, SpinnerImage
from libremsonic.ui.common import EditFormDialog, IconButton, SpinnerImage
class EditPlaylistDialog(EditFormDialog):
@@ -38,8 +39,8 @@ class EditPlaylistDialog(EditFormDialog):
class PlaylistsPanel(Gtk.Paned):
"""Defines the playlists panel."""
__gsignals__ = {
'song-clicked':
(GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (str, object)),
'song-clicked': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
(str, object, object)),
}
playlist_map: OrderedDict[int, PlaylistWithSongs] = {}
@@ -57,17 +58,15 @@ class PlaylistsPanel(Gtk.Paned):
playlist_list_actions = Gtk.ActionBar()
self.new_playlist = Gtk.Button(relief=Gtk.ReliefStyle.NONE)
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(label='New Playlist', margin=5))
self.new_playlist.add(box)
self.new_playlist = IconButton(
relief=Gtk.ReliefStyle.NONE,
icon_name='list-add',
label='New Playlist',
)
self.new_playlist.connect('clicked', self.on_new_playlist_clicked)
playlist_list_actions.pack_start(self.new_playlist)
list_refresh_button = util.button_with_icon('view-refresh')
list_refresh_button = IconButton('view-refresh')
list_refresh_button.connect('clicked', self.on_list_refresh_click)
playlist_list_actions.pack_end(list_refresh_button)
@@ -150,18 +149,18 @@ class PlaylistsPanel(Gtk.Paned):
self.playlist_action_buttons = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL)
view_refresh_button = util.button_with_icon('view-refresh-symbolic')
view_refresh_button = IconButton('view-refresh-symbolic')
view_refresh_button.connect('clicked', self.on_view_refresh_click)
self.playlist_action_buttons.pack_end(view_refresh_button, False,
False, 5)
playlist_edit_button = util.button_with_icon('document-edit-symbolic')
playlist_edit_button = IconButton('document-edit-symbolic')
playlist_edit_button.connect('clicked',
self.on_playlist_edit_button_click)
self.playlist_action_buttons.pack_end(playlist_edit_button, False,
False, 5)
download_all_button = util.button_with_icon('folder-download-symbolic')
download_all_button = IconButton('folder-download-symbolic')
download_all_button.connect(
'clicked', self.on_playlist_list_download_all_button_click)
self.playlist_action_buttons.pack_end(download_all_button, False,
@@ -184,6 +183,29 @@ class PlaylistsPanel(Gtk.Paned):
self.playlist_stats = self.make_label(name='playlist-stats')
playlist_details_box.add(self.playlist_stats)
self.play_shuffle_buttons = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL,
name='playlist-play-shuffle-buttons',
)
play_button = IconButton(
'media-playback-start-symbolic',
label='Play All',
relief=True,
)
play_button.connect('clicked', self.on_play_all_clicked)
self.play_shuffle_buttons.pack_start(play_button, False, False, 0)
shuffle_button = IconButton(
'media-playlist-shuffle-symbolic',
label='Shuffle All',
relief=True,
)
shuffle_button.connect('clicked', self.on_shuffle_all_button)
self.play_shuffle_buttons.pack_start(shuffle_button, False, False, 5)
playlist_details_box.add(self.play_shuffle_buttons)
self.big_info_panel.pack_start(playlist_details_box, True, True, 10)
playlist_box.pack_start(self.big_info_panel, False, True, 0)
@@ -351,11 +373,29 @@ class PlaylistsPanel(Gtk.Paned):
self.playlist_list.get_selected_row().get_index()]
self.update_playlist_view(playlist.id, force=True)
def on_play_all_clicked(self, btn):
song_id = self.playlist_song_store[0][-1]
self.emit('song-clicked', song_id,
[m[-1] for m in self.playlist_song_store],
{'force_shuffle_state': False})
def on_shuffle_all_button(self, btn):
rand_idx = randint(0, len(self.playlist_song_store))
self.emit(
'song-clicked',
self.playlist_song_store[rand_idx][-1],
[m[-1] for m in self.playlist_song_store],
{'force_shuffle_state': True},
)
def on_song_activated(self, treeview, idx, column):
# The song ID is in the last column of the model.
song_id = self.playlist_song_store[idx][-1]
self.emit('song-clicked', song_id,
[m[-1] for m in self.playlist_song_store])
self.emit(
'song-clicked',
self.playlist_song_store[idx][-1],
[m[-1] for m in self.playlist_song_store],
{},
)
def on_song_button_press(self, tree, event):
if event.button == 3: # Right click
@@ -456,8 +496,10 @@ class PlaylistsPanel(Gtk.Paned):
playlist_id = self.playlist_map[selected.get_index()].id
self.update_playlist_view(playlist_id)
self.playlist_action_buttons.show()
self.play_shuffle_buttons.show()
else:
self.playlist_action_buttons.hide()
self.play_shuffle_buttons.hide()
self.playlist_songs.set_headers_visible(state.config.show_headers)
@@ -536,6 +578,7 @@ class PlaylistsPanel(Gtk.Paned):
self.update_playlist_song_list(playlist.id)
self.playlist_action_buttons.show()
self.play_shuffle_buttons.show()
@util.async_callback(
lambda *a, **k: CacheManager.get_playlist(*a, **k),

View File

@@ -8,27 +8,11 @@ from deepdiff import DeepDiff
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gio, Gtk, GLib, Gdk
from gi.repository import Gtk, GLib, Gdk
from libremsonic.cache_manager import CacheManager, SongCacheStatus
def button_with_icon(
icon_name,
relief=False,
icon_size=Gtk.IconSize.BUTTON,
) -> Gtk.Button:
button = Gtk.Button()
icon = Gio.ThemedIcon(name=icon_name)
image = Gtk.Image.new_from_gicon(icon, icon_size)
button.add(image)
if not relief:
button.props.relief = Gtk.ReliefStyle.NONE
return button
def format_song_duration(duration_secs) -> str:
return f'{duration_secs // 60}:{duration_secs % 60:02}'
@@ -120,15 +104,19 @@ def show_song_popover(
extra_menu_items: List[Tuple[Gtk.ModelButton, Any]] = [],
):
def on_play_next_click(button):
# TODO
print('play next click')
def on_add_to_queue_click(button):
# TODO
print('add to queue click')
def on_go_to_album_click(button):
# TODO
print('go to album click')
def on_go_to_artist_click(button):
# TODO
print('go to artist click')
def on_download_songs_click(button):