Added index listing to browse panel
This commit is contained in:
@@ -538,22 +538,18 @@ class CacheManager(metaclass=Singleton):
|
|||||||
self,
|
self,
|
||||||
before_download: Callable[[], None] = lambda: None,
|
before_download: Callable[[], None] = lambda: None,
|
||||||
force: bool = False,
|
force: bool = False,
|
||||||
) -> 'CacheManager.Result[List[Union[Artist, ArtistID3]]]':
|
) -> 'CacheManager.Result[List[ArtistID3]]':
|
||||||
# TODO: no need to id3ify I think.
|
# This will always end up being artists_id3, but do this for
|
||||||
|
# consistency.
|
||||||
cache_name = self.id3ify('artists')
|
cache_name = self.id3ify('artists')
|
||||||
|
|
||||||
if self.cache.get(cache_name) and not force:
|
if self.cache.get(cache_name) and not force:
|
||||||
return CacheManager.Result.from_data(self.cache[cache_name])
|
return CacheManager.Result.from_data(self.cache[cache_name])
|
||||||
|
|
||||||
def download_fn():
|
def download_fn() -> List[ArtistID3]:
|
||||||
raw_artists = (
|
artists: List[ArtistID3] = []
|
||||||
self.server.get_artists
|
for index in self.server.get_artists().index:
|
||||||
if self.browse_by_tags else self.server.get_indexes)()
|
|
||||||
|
|
||||||
artists: List[Union[Artist, ArtistID3]] = []
|
|
||||||
for index in raw_artists.index:
|
|
||||||
artists.extend(index.artist)
|
artists.extend(index.artist)
|
||||||
|
|
||||||
return artists
|
return artists
|
||||||
|
|
||||||
def after_download(artists):
|
def after_download(artists):
|
||||||
@@ -573,24 +569,75 @@ class CacheManager(metaclass=Singleton):
|
|||||||
before_download: Callable[[], None] = lambda: None,
|
before_download: Callable[[], None] = lambda: None,
|
||||||
force: bool = False,
|
force: bool = False,
|
||||||
) -> 'CacheManager.Result[Union[ArtistWithAlbumsID3, Child]]':
|
) -> 'CacheManager.Result[Union[ArtistWithAlbumsID3, Child]]':
|
||||||
# TODO: no need to id3ify I think.
|
# This will always end up being artist_details_id3, but do this for
|
||||||
|
# consistency.
|
||||||
cache_name = self.id3ify('artist_details')
|
cache_name = self.id3ify('artist_details')
|
||||||
|
|
||||||
if artist_id in self.cache.get(cache_name, {}) and not force:
|
if artist_id in self.cache.get(cache_name, {}) and not force:
|
||||||
return CacheManager.Result.from_data(
|
return CacheManager.Result.from_data(
|
||||||
self.cache[cache_name][artist_id])
|
self.cache[cache_name][artist_id])
|
||||||
|
|
||||||
server_fn = (
|
|
||||||
self.server.get_artist
|
|
||||||
if self.browse_by_tags else self.server.get_music_directory)
|
|
||||||
|
|
||||||
def after_download(artist):
|
def after_download(artist):
|
||||||
with self.cache_lock:
|
with self.cache_lock:
|
||||||
self.cache[cache_name][artist_id] = artist
|
self.cache[cache_name][artist_id] = artist
|
||||||
self.save_cache_info()
|
self.save_cache_info()
|
||||||
|
|
||||||
return CacheManager.Result.from_server(
|
return CacheManager.Result.from_server(
|
||||||
lambda: server_fn(artist_id),
|
lambda: self.server.get_artist(artist_id),
|
||||||
|
before_download=before_download,
|
||||||
|
after_download=after_download,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_indexes(
|
||||||
|
self,
|
||||||
|
before_download: Callable[[], None] = lambda: None,
|
||||||
|
force: bool = False,
|
||||||
|
) -> 'CacheManager.Result[List[Artist]]':
|
||||||
|
# This will always end up being artists, but do this for
|
||||||
|
# consistency.
|
||||||
|
cache_name = self.id3ify('artists')
|
||||||
|
|
||||||
|
if self.cache.get(cache_name) and not force:
|
||||||
|
return CacheManager.Result.from_data(self.cache[cache_name])
|
||||||
|
|
||||||
|
def download_fn() -> List[Artist]:
|
||||||
|
artists: List[Artist] = []
|
||||||
|
for index in self.server.get_indexes().index:
|
||||||
|
artists.extend(index.artist)
|
||||||
|
return artists
|
||||||
|
|
||||||
|
def after_download(artists):
|
||||||
|
with self.cache_lock:
|
||||||
|
self.cache[cache_name] = artists
|
||||||
|
self.save_cache_info()
|
||||||
|
|
||||||
|
return CacheManager.Result.from_server(
|
||||||
|
download_fn,
|
||||||
|
before_download=before_download,
|
||||||
|
after_download=after_download,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_music_directory(
|
||||||
|
self,
|
||||||
|
id,
|
||||||
|
before_download: Callable[[], None] = lambda: None,
|
||||||
|
force: bool = False,
|
||||||
|
) -> 'CacheManager.Result[Child]':
|
||||||
|
# This will always end up being artist_details, but do this for
|
||||||
|
# consistency.
|
||||||
|
cache_name = self.id3ify('artist_details')
|
||||||
|
|
||||||
|
if id in self.cache.get(cache_name, {}) and not force:
|
||||||
|
return CacheManager.Result.from_data(
|
||||||
|
self.cache[cache_name][id])
|
||||||
|
|
||||||
|
def after_download(artist):
|
||||||
|
with self.cache_lock:
|
||||||
|
self.cache[cache_name][id] = artist
|
||||||
|
self.save_cache_info()
|
||||||
|
|
||||||
|
return CacheManager.Result.from_server(
|
||||||
|
lambda: self.server.get_music_directory(id),
|
||||||
before_download=before_download,
|
before_download=before_download,
|
||||||
after_download=after_download,
|
after_download=after_download,
|
||||||
)
|
)
|
||||||
|
@@ -21,7 +21,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#playlist-list-spinner:checked,
|
#playlist-list-spinner:checked,
|
||||||
#artist-list-spinner:checked {
|
#artist-list-spinner:checked,
|
||||||
|
#directory-list-spinner:checked {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
@@ -3,8 +3,13 @@ import gi
|
|||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk, GObject, Pango, GLib, Gio
|
from gi.repository import Gtk, GObject, Pango, GLib, Gio
|
||||||
|
|
||||||
|
from sublime.state_manager import ApplicationState
|
||||||
|
from sublime.cache_manager import CacheManager
|
||||||
|
from sublime.ui import util
|
||||||
|
from sublime.ui.common import IconButton
|
||||||
|
|
||||||
class BrowsePanel(Gtk.Label):
|
|
||||||
|
class BrowsePanel(Gtk.ScrolledWindow):
|
||||||
"""Defines the arist panel."""
|
"""Defines the arist panel."""
|
||||||
|
|
||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
@@ -21,4 +26,151 @@ class BrowsePanel(Gtk.Label):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(label='ohea')
|
super().__init__()
|
||||||
|
|
||||||
|
self.root_directory_listing = DirectoryListAndDrilldown(is_root=True)
|
||||||
|
|
||||||
|
self.add(self.root_directory_listing)
|
||||||
|
|
||||||
|
def update(self, state: ApplicationState, force=False):
|
||||||
|
self.root_directory_listing.update(state=state, force=force)
|
||||||
|
|
||||||
|
|
||||||
|
class DirectoryListAndDrilldown(Gtk.Paned):
|
||||||
|
__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, is_root=False):
|
||||||
|
Gtk.Paned.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
|
||||||
|
|
||||||
|
self.directory_listing = DirectoryList()
|
||||||
|
self.pack1(self.directory_listing, False, False)
|
||||||
|
|
||||||
|
self.listing_drilldown_panel = Gtk.Box()
|
||||||
|
self.pack2(self.listing_drilldown_panel, True, False)
|
||||||
|
|
||||||
|
def update(self, state: ApplicationState, force=False):
|
||||||
|
print('directory list and drilldown update')
|
||||||
|
if self.is_root:
|
||||||
|
self.directory_listing.update_root(state=state, force=force)
|
||||||
|
else:
|
||||||
|
self.directory_listing.update_not_root(state=state, force=force)
|
||||||
|
|
||||||
|
|
||||||
|
class DirectoryList(Gtk.Box):
|
||||||
|
class SubelementModel(GObject.GObject):
|
||||||
|
id = GObject.Property(type=str)
|
||||||
|
name = GObject.Property(type=str)
|
||||||
|
|
||||||
|
def __init__(self, id, name):
|
||||||
|
GObject.GObject.__init__(self)
|
||||||
|
self.id = id
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
|
||||||
|
|
||||||
|
list_actions = Gtk.ActionBar()
|
||||||
|
|
||||||
|
refresh = IconButton('view-refresh-symbolic')
|
||||||
|
refresh.connect('clicked', lambda *a: self.update(force=True))
|
||||||
|
list_actions.pack_end(refresh)
|
||||||
|
|
||||||
|
self.add(list_actions)
|
||||||
|
|
||||||
|
self.loading_indicator = Gtk.ListBox()
|
||||||
|
spinner_row = Gtk.ListBoxRow()
|
||||||
|
spinner = Gtk.Spinner(
|
||||||
|
name='directory-list-spinner',
|
||||||
|
active=True,
|
||||||
|
)
|
||||||
|
spinner_row.add(spinner)
|
||||||
|
self.loading_indicator.add(spinner_row)
|
||||||
|
self.pack_start(self.loading_indicator, False, False, 0)
|
||||||
|
|
||||||
|
list_scroll_window = Gtk.ScrolledWindow(min_content_width=250)
|
||||||
|
|
||||||
|
def create_row(model: DirectoryList.SubelementModel):
|
||||||
|
return Gtk.Label(
|
||||||
|
label=f'<b>{util.esc(model.name)}</b>',
|
||||||
|
use_markup=True,
|
||||||
|
margin=8,
|
||||||
|
halign=Gtk.Align.START,
|
||||||
|
ellipsize=Pango.EllipsizeMode.END,
|
||||||
|
max_width_chars=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.directory_list_store = Gio.ListStore()
|
||||||
|
self.list = Gtk.ListBox(name='directory-list')
|
||||||
|
self.list.bind_model(self.directory_list_store, create_row)
|
||||||
|
list_scroll_window.add(self.list)
|
||||||
|
|
||||||
|
self.pack_start(list_scroll_window, True, True, 0)
|
||||||
|
|
||||||
|
@util.async_callback(
|
||||||
|
lambda *a, **k: CacheManager.get_indexes(*a, **k),
|
||||||
|
before_download=lambda self: self.loading_indicator.show_all(),
|
||||||
|
on_failure=lambda self, e: self.loading_indicator.hide(),
|
||||||
|
)
|
||||||
|
def update_root(
|
||||||
|
self,
|
||||||
|
artists,
|
||||||
|
state: ApplicationState = None,
|
||||||
|
force=False,
|
||||||
|
):
|
||||||
|
new_store = []
|
||||||
|
selected_idx = None
|
||||||
|
for i, artist in enumerate(artists):
|
||||||
|
# if state and state.selected_artist_id == artist.id:
|
||||||
|
# selected_idx = i
|
||||||
|
|
||||||
|
new_store.append(
|
||||||
|
DirectoryList.SubelementModel(artist.id, artist.name))
|
||||||
|
|
||||||
|
util.diff_model_store(self.directory_list_store, new_store)
|
||||||
|
|
||||||
|
# Preserve selection
|
||||||
|
if selected_idx is not None:
|
||||||
|
row = self.list.get_row_at_index(selected_idx)
|
||||||
|
self.list.select_row(row)
|
||||||
|
|
||||||
|
self.loading_indicator.hide()
|
||||||
|
|
||||||
|
@util.async_callback(
|
||||||
|
lambda *a, **k: CacheManager.get_music_directory(*a, **k),
|
||||||
|
before_download=lambda self: self.loading_indicator.show_all(),
|
||||||
|
on_failure=lambda self, e: self.loading_indicator.hide(),
|
||||||
|
)
|
||||||
|
def update_not_root(
|
||||||
|
self,
|
||||||
|
artists,
|
||||||
|
state: ApplicationState = None,
|
||||||
|
force=False,
|
||||||
|
):
|
||||||
|
new_store = []
|
||||||
|
selected_idx = None
|
||||||
|
for i, artist in enumerate(artists):
|
||||||
|
# if state and state.selected_artist_id == artist.id:
|
||||||
|
# selected_idx = i
|
||||||
|
|
||||||
|
new_store.append(
|
||||||
|
DirectoryList.SubelementModel(artist.id, artist.name))
|
||||||
|
|
||||||
|
util.diff_model_store(self.directory_list_store, new_store)
|
||||||
|
|
||||||
|
# Preserve selection
|
||||||
|
if selected_idx is not None:
|
||||||
|
row = self.list.get_row_at_index(selected_idx)
|
||||||
|
self.list.select_row(row)
|
||||||
|
|
||||||
|
self.loading_indicator.hide()
|
||||||
|
Reference in New Issue
Block a user