Go to artist working
This commit is contained in:
@@ -67,9 +67,11 @@ class LibremsonicApp(Gtk.Application):
|
||||
def do_startup(self):
|
||||
Gtk.Application.do_startup(self)
|
||||
|
||||
def add_action(name: str, fn):
|
||||
def add_action(name: str, fn, parameter_type=None):
|
||||
"""Registers an action with the application."""
|
||||
action = Gio.SimpleAction.new(name, None)
|
||||
if type(parameter_type) == str:
|
||||
parameter_type = GLib.VariantType(parameter_type)
|
||||
action = Gio.SimpleAction.new(name, parameter_type)
|
||||
action.connect('activate', fn)
|
||||
self.add_action(action)
|
||||
|
||||
@@ -84,6 +86,12 @@ class LibremsonicApp(Gtk.Application):
|
||||
add_action('repeat-press', self.on_repeat_press)
|
||||
add_action('shuffle-press', self.on_shuffle_press)
|
||||
|
||||
# Navigation actions.
|
||||
add_action('play-next', self.on_play_next, parameter_type='as')
|
||||
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('mute-toggle', self.on_mute_toggle)
|
||||
add_action(
|
||||
'update-play-queue-from-server',
|
||||
@@ -208,6 +216,9 @@ class LibremsonicApp(Gtk.Application):
|
||||
dialog.destroy()
|
||||
|
||||
def on_play_pause(self, *args):
|
||||
if self.state.current_song is None:
|
||||
return
|
||||
|
||||
if self.player.song_loaded:
|
||||
self.player.toggle_play()
|
||||
self.save_play_queue()
|
||||
@@ -270,6 +281,24 @@ class LibremsonicApp(Gtk.Application):
|
||||
self.state.shuffle_on = not self.state.shuffle_on
|
||||
self.update_window()
|
||||
|
||||
def on_play_next(self, action, song_ids):
|
||||
# TODO
|
||||
print(song_ids)
|
||||
|
||||
def on_add_to_queue(self, action, song_ids):
|
||||
# TODO
|
||||
print(song_ids)
|
||||
|
||||
def on_go_to_album(self, action, album_id):
|
||||
# TODO
|
||||
self.state.current_tab = 'albums'
|
||||
self.update_window()
|
||||
|
||||
def on_go_to_artist(self, action, artist_id):
|
||||
self.state.current_tab = 'artists'
|
||||
self.state.selected_artist_id = artist_id.get_string()
|
||||
self.update_window()
|
||||
|
||||
def on_server_list_changed(self, action, servers):
|
||||
self.state.config.servers = servers
|
||||
self.state.save()
|
||||
@@ -292,6 +321,7 @@ class LibremsonicApp(Gtk.Application):
|
||||
self.update_window()
|
||||
|
||||
def on_stack_change(self, stack, child):
|
||||
self.state.current_tab = stack.get_visible_child_name()
|
||||
self.update_window()
|
||||
|
||||
def on_song_clicked(self, win, song_id, song_queue, metadata):
|
||||
@@ -514,6 +544,9 @@ class LibremsonicApp(Gtk.Application):
|
||||
lambda f: GLib.idle_add(do_play_song, f.result()), )
|
||||
|
||||
def save_play_queue(self):
|
||||
if len(self.state.play_queue) == 0:
|
||||
return
|
||||
|
||||
position = self.state.song_progress
|
||||
self.last_play_queue_update = position
|
||||
|
||||
|
@@ -39,17 +39,19 @@ class ApplicationState:
|
||||
loads.
|
||||
"""
|
||||
config: AppConfiguration = AppConfiguration()
|
||||
current_song: Child
|
||||
config_file: str
|
||||
current_song: Child = None
|
||||
config_file: str = None
|
||||
playing: bool = False
|
||||
play_queue: List[str]
|
||||
old_play_queue: List[str]
|
||||
play_queue: List[str] = []
|
||||
old_play_queue: List[str] = []
|
||||
volume: int = 100
|
||||
old_volume: int = 100
|
||||
repeat_type: RepeatType = RepeatType.NO_REPEAT
|
||||
shuffle_on: bool = False
|
||||
song_progress: float = 0
|
||||
current_device: str = 'this device'
|
||||
current_tab: str = 'albums'
|
||||
selected_artist_id: str = None
|
||||
|
||||
def to_json(self):
|
||||
current_song = (self.current_song.id if
|
||||
@@ -65,6 +67,8 @@ class ApplicationState:
|
||||
'shuffle_on': getattr(self, 'shuffle_on', None),
|
||||
'song_progress': getattr(self, 'song_progress', None),
|
||||
'current_device': getattr(self, 'current_device', 'this device'),
|
||||
'current_tab': getattr(self, 'current_tab', 'albums'),
|
||||
'selected_artist_id': getattr(self, 'selected_artist_id', None),
|
||||
}
|
||||
|
||||
def load_from_json(self, json_object):
|
||||
@@ -83,6 +87,8 @@ class ApplicationState:
|
||||
self.shuffle_on = json_object.get('shuffle_on', False)
|
||||
self.song_progress = json_object.get('song_progress', 0.0)
|
||||
self.current_device = json_object.get('current_device', 'this device')
|
||||
self.current_tab = json_object.get('current_tab', 'albums')
|
||||
self.selected_artist_id = json_object.get('selected_artist_id', None)
|
||||
|
||||
def load(self):
|
||||
self.config = self.get_config(self.config_file)
|
||||
|
@@ -3,7 +3,7 @@ from typing import List, Union, Optional
|
||||
import gi
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, GObject, Pango
|
||||
from gi.repository import Gtk, GObject, Pango, GLib
|
||||
|
||||
from libremsonic.state_manager import ApplicationState
|
||||
from libremsonic.cache_manager import CacheManager
|
||||
@@ -33,13 +33,7 @@ class ArtistsPanel(Gtk.Paned):
|
||||
def __init__(self, *args, **kwargs):
|
||||
Gtk.Paned.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
self.selected_artist = None
|
||||
|
||||
self.artist_list = ArtistList()
|
||||
self.artist_list.connect(
|
||||
'selection-changed',
|
||||
self.on_list_selection_changed,
|
||||
)
|
||||
self.pack1(self.artist_list, False, False)
|
||||
|
||||
self.artist_detail_panel = ArtistDetailPanel()
|
||||
@@ -52,28 +46,14 @@ class ArtistsPanel(Gtk.Paned):
|
||||
|
||||
def update(self, state: ApplicationState):
|
||||
self.artist_list.update(state)
|
||||
if self.artist_id:
|
||||
self.artist_detail_panel.update(self.artist_id)
|
||||
|
||||
def on_list_selection_changed(self, artist_list, artist):
|
||||
self.artist_id = artist.id
|
||||
self.artist_detail_panel.update(self.artist_id)
|
||||
if state.selected_artist_id:
|
||||
self.artist_detail_panel.update(state.selected_artist_id)
|
||||
|
||||
|
||||
class ArtistList(Gtk.Box):
|
||||
__gsignals__ = {
|
||||
'selection-changed': (
|
||||
GObject.SignalFlags.RUN_FIRST,
|
||||
GObject.TYPE_NONE,
|
||||
(object, ),
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
|
||||
|
||||
self.artist_map = {}
|
||||
|
||||
list_actions = Gtk.ActionBar()
|
||||
|
||||
refresh = IconButton('view-refresh')
|
||||
@@ -93,24 +73,19 @@ class ArtistList(Gtk.Box):
|
||||
self.loading_indicator.add(loading_spinner)
|
||||
self.list.add(self.loading_indicator)
|
||||
|
||||
self.list.connect('row-activated', self.on_row_activated)
|
||||
list_scroll_window.add(self.list)
|
||||
self.pack_start(list_scroll_window, True, True, 0)
|
||||
|
||||
def update(self, state=None, force=False):
|
||||
self.update_list(force=force)
|
||||
self.update_list(force=force, state=state)
|
||||
|
||||
@util.async_callback(
|
||||
lambda *a, **k: CacheManager.get_artists(*a, **k),
|
||||
before_download=lambda self: self.loading_indicator.show(),
|
||||
on_failure=lambda self, e: self.loading_indicator.hide(),
|
||||
)
|
||||
def update_list(self, artists):
|
||||
selected_row = self.list.get_selected_row()
|
||||
selected_artist = None
|
||||
if selected_row:
|
||||
selected_artist = self.artist_map.get(selected_row.get_index())
|
||||
|
||||
def update_list(self, artists, state: ApplicationState):
|
||||
# TODO use a diff here
|
||||
# Remove everything
|
||||
for row in self.list.get_children()[1:]:
|
||||
self.list.remove(row)
|
||||
@@ -119,9 +94,9 @@ class ArtistList(Gtk.Box):
|
||||
|
||||
for i, artist in enumerate(artists):
|
||||
# Use i + 1 because of the loading indicator in index 0.
|
||||
if selected_artist and artist.id == selected_artist.id:
|
||||
if (state.selected_artist_id
|
||||
and artist.id == (state.selected_artist_id or -1)):
|
||||
selected_idx = i + 1
|
||||
self.artist_map[i + 1] = artist
|
||||
|
||||
label_text = [f'<b>{util.esc(artist.name)}</b>']
|
||||
|
||||
@@ -130,7 +105,11 @@ class ArtistList(Gtk.Box):
|
||||
label_text.append('{} {}'.format(
|
||||
album_count, util.pluralize('album', album_count)))
|
||||
|
||||
self.list.add(
|
||||
row = Gtk.ListBoxRow(
|
||||
action_name='app.go-to-artist',
|
||||
action_target=GLib.Variant('s', artist.id),
|
||||
)
|
||||
row.add(
|
||||
Gtk.Label(
|
||||
label='\n'.join(label_text),
|
||||
use_markup=True,
|
||||
@@ -139,16 +118,16 @@ class ArtistList(Gtk.Box):
|
||||
ellipsize=Pango.EllipsizeMode.END,
|
||||
max_width_chars=30,
|
||||
))
|
||||
self.list.add(row)
|
||||
|
||||
if selected_idx:
|
||||
row = self.list.get_row_at_index(selected_idx)
|
||||
# TODO scroll to the row
|
||||
self.list.select_row(row)
|
||||
|
||||
self.list.show_all()
|
||||
self.loading_indicator.hide()
|
||||
|
||||
def on_row_activated(self, listbox, row):
|
||||
self.emit('selection-changed', self.artist_map[row.get_index()])
|
||||
|
||||
|
||||
class ArtistDetailPanel(Gtk.Box):
|
||||
"""Defines the artists list."""
|
||||
@@ -238,15 +217,15 @@ class ArtistDetailPanel(Gtk.Box):
|
||||
self.albums_list = AlbumsListWithSongs()
|
||||
self.albums_list.connect(
|
||||
'song-clicked',
|
||||
lambda _, song, queue, metadata: self.emit(
|
||||
'song-clicked', song, queue, metadata),
|
||||
lambda _, song, queue, metadata: self.emit('song-clicked', song,
|
||||
queue, metadata),
|
||||
)
|
||||
artist_info_box.pack_start(self.albums_list, True, True, 0)
|
||||
|
||||
self.add(artist_info_box)
|
||||
|
||||
def update(self, album_id):
|
||||
self.update_artist_view(album_id)
|
||||
def update(self, artist_id):
|
||||
self.update_artist_view(artist_id)
|
||||
|
||||
def get_model_list_future(self, before_download):
|
||||
def do_get_model_list() -> List[Child]:
|
||||
@@ -261,7 +240,11 @@ class ArtistDetailPanel(Gtk.Box):
|
||||
before_download=lambda self: self.artist_artwork.set_loading(True),
|
||||
on_failure=lambda self, e: print('fail a', e),
|
||||
)
|
||||
def update_artist_view(self, artist: ArtistWithAlbumsID3):
|
||||
def update_artist_view(
|
||||
self,
|
||||
artist: ArtistWithAlbumsID3,
|
||||
state: ApplicationState,
|
||||
):
|
||||
self.artist_id = artist.id
|
||||
self.artist_indicator.set_text('ARTIST')
|
||||
self.artist_name.set_markup(util.esc(f'<b>{artist.name}</b>'))
|
||||
@@ -276,7 +259,11 @@ class ArtistDetailPanel(Gtk.Box):
|
||||
@util.async_callback(
|
||||
lambda *a, **k: CacheManager.get_artist_info(*a, **k),
|
||||
)
|
||||
def update_artist_info(self, artist_info: ArtistInfo2):
|
||||
def update_artist_info(
|
||||
self,
|
||||
artist_info: ArtistInfo2,
|
||||
state: ApplicationState,
|
||||
):
|
||||
self.artist_bio.set_markup(util.esc(''.join(artist_info.biography)))
|
||||
|
||||
if len(artist_info.similarArtist or []) > 0:
|
||||
@@ -287,9 +274,10 @@ class ArtistDetailPanel(Gtk.Box):
|
||||
for artist in artist_info.similarArtist[:5]:
|
||||
self.similar_artists_button_box.add(
|
||||
Gtk.LinkButton(
|
||||
uri=f'artist://{artist.id}',
|
||||
label=artist.name,
|
||||
name='similar-artist-button',
|
||||
action_name='app.go-to-artist',
|
||||
action_target=GLib.Variant('s', artist.id),
|
||||
))
|
||||
self.similar_artists_box.show_all()
|
||||
else:
|
||||
@@ -300,7 +288,11 @@ class ArtistDetailPanel(Gtk.Box):
|
||||
before_download=lambda self: self.artist_artwork.set_loading(True),
|
||||
on_failure=lambda self, e: self.artist_artwork.set_loading(False),
|
||||
)
|
||||
def update_artist_artwork(self, cover_art_filename):
|
||||
def update_artist_artwork(
|
||||
self,
|
||||
cover_art_filename,
|
||||
state: ApplicationState,
|
||||
):
|
||||
self.artist_artwork.set_from_file(cover_art_filename)
|
||||
self.artist_artwork.set_loading(False)
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, GObject, Pango, GLib
|
||||
|
||||
from libremsonic.state_manager import ApplicationState
|
||||
from libremsonic.cache_manager import CacheManager
|
||||
from libremsonic.ui import util
|
||||
from .icon_button import IconButton
|
||||
@@ -65,6 +66,7 @@ class AlbumWithSongs(Gtk.Box):
|
||||
album_title_and_buttons = Gtk.Box(
|
||||
orientation=Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
# TODO: deal with super long-ass titles
|
||||
album_title_and_buttons.add(
|
||||
Gtk.Label(
|
||||
label=album.get('name', album.get('title')),
|
||||
@@ -239,7 +241,7 @@ class AlbumWithSongs(Gtk.Box):
|
||||
)
|
||||
|
||||
def shuffle_btn_clicked(self, btn):
|
||||
rand_idx = randint(0, len(self.album_song_store))
|
||||
rand_idx = randint(0, len(self.album_song_store) - 1)
|
||||
song_ids = [x[-1] for x in self.album_song_store]
|
||||
self.emit(
|
||||
'song-clicked',
|
||||
@@ -272,6 +274,7 @@ class AlbumWithSongs(Gtk.Box):
|
||||
def update_album_songs(
|
||||
self,
|
||||
album: Union[AlbumWithSongsID3, Child, Directory],
|
||||
state: ApplicationState,
|
||||
):
|
||||
new_store = [[
|
||||
util.get_cached_status_icon(CacheManager.get_cached_status(song)),
|
||||
|
@@ -50,6 +50,8 @@ 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)
|
||||
|
@@ -151,7 +151,7 @@ class PlayerControls(Gtk.ActionBar):
|
||||
before_download=lambda self: self.album_art.set_loading(True),
|
||||
on_failure=lambda self, e: self.album_art.set_loading(False),
|
||||
)
|
||||
def update_cover_art(self, cover_art_filename):
|
||||
def update_cover_art(self, cover_art_filename, state):
|
||||
self.album_art.set_from_file(cover_art_filename)
|
||||
self.album_art.set_loading(False)
|
||||
|
||||
|
@@ -59,7 +59,6 @@ class PlaylistsPanel(Gtk.Paned):
|
||||
playlist_list_actions = Gtk.ActionBar()
|
||||
|
||||
self.new_playlist = IconButton(
|
||||
relief=Gtk.ReliefStyle.NONE,
|
||||
icon_name='list-add',
|
||||
label='New Playlist',
|
||||
)
|
||||
@@ -380,7 +379,7 @@ class PlaylistsPanel(Gtk.Paned):
|
||||
{'force_shuffle_state': False})
|
||||
|
||||
def on_shuffle_all_button(self, btn):
|
||||
rand_idx = randint(0, len(self.playlist_song_store))
|
||||
rand_idx = randint(0, len(self.playlist_song_store) - 1)
|
||||
self.emit(
|
||||
'song-clicked',
|
||||
self.playlist_song_store[rand_idx][-1],
|
||||
@@ -531,7 +530,11 @@ class PlaylistsPanel(Gtk.Paned):
|
||||
before_download=lambda self: self.set_playlist_list_loading(True),
|
||||
on_failure=lambda self, e: self.set_playlist_list_loading(False),
|
||||
)
|
||||
def update_playlist_list(self, playlists: List[PlaylistWithSongs]):
|
||||
def update_playlist_list(
|
||||
self,
|
||||
playlists: List[PlaylistWithSongs],
|
||||
state: ApplicationState,
|
||||
):
|
||||
selected_row = self.playlist_list.get_selected_row()
|
||||
selected_playlist = None
|
||||
if selected_row:
|
||||
@@ -564,7 +567,7 @@ class PlaylistsPanel(Gtk.Paned):
|
||||
on_failure=lambda self, e: (self.set_playlist_view_loading(False) or
|
||||
self.playlist_artwork.set_loading(False)),
|
||||
)
|
||||
def update_playlist_view(self, playlist):
|
||||
def update_playlist_view(self, playlist, state: ApplicationState):
|
||||
# Update the Playlist Info panel
|
||||
self.update_playlist_artwork(playlist.coverArt)
|
||||
self.playlist_indicator.set_markup('PLAYLIST')
|
||||
@@ -583,7 +586,7 @@ class PlaylistsPanel(Gtk.Paned):
|
||||
@util.async_callback(
|
||||
lambda *a, **k: CacheManager.get_playlist(*a, **k),
|
||||
)
|
||||
def update_playlist_song_list(self, playlist):
|
||||
def update_playlist_song_list(self, playlist, state: ApplicationState):
|
||||
# Update the song list model. This requires some fancy diffing to
|
||||
# update the list.
|
||||
self.editing_playlist_song_list = True
|
||||
@@ -607,7 +610,11 @@ class PlaylistsPanel(Gtk.Paned):
|
||||
before_download=lambda self: self.playlist_artwork.set_loading(True),
|
||||
on_failure=lambda self, e: self.playlist_artwork.set_loading(False),
|
||||
)
|
||||
def update_playlist_artwork(self, cover_art_filename):
|
||||
def update_playlist_artwork(
|
||||
self,
|
||||
cover_art_filename,
|
||||
state: ApplicationState,
|
||||
):
|
||||
self.playlist_artwork.set_from_file(cover_art_filename)
|
||||
self.playlist_artwork.set_loading(False)
|
||||
|
||||
@@ -615,7 +622,7 @@ class PlaylistsPanel(Gtk.Paned):
|
||||
lambda *a, **k: CacheManager.get_playlist(*a, **k),
|
||||
# TODO make loading here
|
||||
)
|
||||
def update_playlist_order(self, playlist):
|
||||
def update_playlist_order(self, playlist, state: ApplicationState):
|
||||
CacheManager.update_playlist(
|
||||
playlist_id=playlist.id,
|
||||
song_index_to_remove=list(range(playlist.songCount)),
|
||||
|
@@ -103,22 +103,6 @@ def show_song_popover(
|
||||
show_remove_from_playlist_button: bool = False,
|
||||
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):
|
||||
CacheManager.batch_download_songs(
|
||||
song_ids,
|
||||
@@ -147,9 +131,13 @@ def show_song_popover(
|
||||
|
||||
# Determine if we should enable the download button.
|
||||
download_sensitive, remove_download_sensitive = False, False
|
||||
albums, artists = 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)
|
||||
|
||||
if download_sensitive or status == SongCacheStatus.NOT_CACHED:
|
||||
download_sensitive = True
|
||||
|
||||
@@ -159,18 +147,32 @@ def show_song_popover(
|
||||
remove_download_sensitive = True
|
||||
|
||||
menu_items = [
|
||||
(Gtk.ModelButton(text='Play next'), on_play_next_click),
|
||||
(Gtk.ModelButton(text='Add to queue'), on_add_to_queue_click),
|
||||
(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), None),
|
||||
(
|
||||
Gtk.ModelButton(text='Go to album', sensitive=len(song_ids) == 1),
|
||||
on_go_to_album_click,
|
||||
Gtk.ModelButton(
|
||||
text='Play next',
|
||||
action_name='app.play-next',
|
||||
action_target=GLib.Variant('as', song_ids),
|
||||
),
|
||||
(
|
||||
Gtk.ModelButton(text='Go to artist', sensitive=len(song_ids) == 1),
|
||||
on_go_to_artist_click,
|
||||
Gtk.ModelButton(
|
||||
text='Add to queue',
|
||||
action_name='app.add-to-queue',
|
||||
action_target=GLib.Variant('as', song_ids),
|
||||
),
|
||||
(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), None),
|
||||
Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
|
||||
Gtk.ModelButton(
|
||||
text='Go to album',
|
||||
action_name='app.go-to-album',
|
||||
action_target=GLib.Variant('s',
|
||||
list(albums)[0]),
|
||||
sensitive=len(albums) == 1,
|
||||
),
|
||||
Gtk.ModelButton(
|
||||
text='Go to artist',
|
||||
action_name='app.go-to-artist',
|
||||
action_target=GLib.Variant('s',
|
||||
list(artists)[0]),
|
||||
sensitive=len(artists) == 1,
|
||||
),
|
||||
Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
|
||||
(
|
||||
Gtk.ModelButton(
|
||||
text=f"Download {pluralize('song', song_count)}",
|
||||
@@ -185,23 +187,23 @@ def show_song_popover(
|
||||
),
|
||||
on_remove_downloads_click,
|
||||
),
|
||||
(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), None),
|
||||
(
|
||||
Gtk.ModelButton(
|
||||
text=f"Add {pluralize('song', song_count)} to playlist",
|
||||
menu_name='add-to-playlist',
|
||||
),
|
||||
None,
|
||||
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, action in menu_items:
|
||||
if action:
|
||||
item.connect('clicked', action)
|
||||
if type(item) == Gtk.ModelButton:
|
||||
for item in menu_items:
|
||||
if type(item) == tuple:
|
||||
el, fn = item
|
||||
el.connect('clicked', fn)
|
||||
el.get_style_context().add_class('menu-button')
|
||||
vbox.pack_start(item[0], False, True, 0)
|
||||
else:
|
||||
item.get_style_context().add_class('menu-button')
|
||||
vbox.pack_start(item, False, True, 0)
|
||||
vbox.pack_start(item, False, True, 0)
|
||||
|
||||
popover.add(vbox)
|
||||
|
||||
@@ -237,7 +239,11 @@ def show_song_popover(
|
||||
popover.show_all()
|
||||
|
||||
|
||||
def async_callback(future_fn, before_download=None, on_failure=None):
|
||||
def async_callback(
|
||||
future_fn,
|
||||
before_download=None,
|
||||
on_failure=None,
|
||||
):
|
||||
"""
|
||||
Defines the ``async_callback`` decorator.
|
||||
|
||||
@@ -251,7 +257,7 @@ def async_callback(future_fn, before_download=None, on_failure=None):
|
||||
"""
|
||||
def decorator(callback_fn):
|
||||
@functools.wraps(callback_fn)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
def wrapper(self, *args, state=None, **kwargs):
|
||||
if before_download:
|
||||
on_before_download = (
|
||||
lambda: GLib.idle_add(before_download, self))
|
||||
@@ -266,7 +272,7 @@ def async_callback(future_fn, before_download=None, on_failure=None):
|
||||
on_failure(self, e)
|
||||
return
|
||||
|
||||
return GLib.idle_add(callback_fn, self, result)
|
||||
return GLib.idle_add(callback_fn, self, result, state)
|
||||
|
||||
future: Future = future_fn(
|
||||
*args,
|
||||
|
Reference in New Issue
Block a user