def clear(self): """ Clear the view """ if not App().player.radio_cancellable.is_cancelled(): App().player.radio_cancellable.cancel() GLib.timeout_add(500, self.clear) else: AlbumsListView.clear(self) App().player.clear_albums()
def _on_playback_setted(self, player, albums): """ Add album @param player as Player @param albums as [Album] """ if albums: self.stop() AlbumsListView.clear(self) AlbumsListView.populate(self, albums) self.show_placeholder(False) else: self.stop() AlbumsListView.clear(self) self.show_placeholder(True)
def _on_queue_changed(self, *ignore): """ Clean view and reload if empty """ queue = App().player.queue if queue: for row in self.children: if row.revealed: for subrow in row.children: if subrow.track.id not in queue: subrow.destroy() break count = len(row.album.tracks) for track in row.album.tracks: if track.id not in queue: row.album.remove_track(track) if count == 1: row.destroy() break else: self.stop() AlbumsListView.clear(self) self.populate()
class SearchView(BaseView, Gtk.Bin): """ View for searching albums/tracks """ def __init__(self): """ Init Popover """ BaseView.__init__(self) Gtk.Bin.__init__(self) self.connect("map", self.__on_map) self.connect("unmap", self.__on_unmap) self.__timeout_id = None self.__current_search = "" self.__cancellable = Gio.Cancellable() self.__history = [] builder = Gtk.Builder() builder.add_from_resource("/org/gnome/Lollypop/SearchView.ui") builder.connect_signals(self) self.__widget = builder.get_object("widget") self.__new_button = builder.get_object("new_button") self.__play_button = builder.get_object("play_button") self.__entry = builder.get_object("entry") self.__spinner = builder.get_object("spinner") self.__header_stack = builder.get_object("header_stack") self.__stack = builder.get_object("stack") self.__placeholder = builder.get_object("placeholder") self.__view = AlbumsListView(RowListType.SEARCH) self.__view.show() self.__stack.add_named(self.__view, "view") self.__set_default_placeholder() self.add(self.__widget) def set_text(self, text): """ Set search text """ self.__entry.set_text(text) ####################### # PROTECTED # ####################### def _on_play_button_clicked(self, button): """ Play search @param button as Gtk.Button """ try: App().player.clear_albums() shuffle_setting = App().settings.get_enum("shuffle") children = self.__view.children if shuffle_setting == Shuffle.ALBUMS: shuffle(children) for child in children: App().player.add_album(child.album) App().player.load(App().player.albums[0].tracks[0]) except Exception as e: Logger.error("SearchPopover::_on_play_button_clicked(): %s", e) def _on_new_button_clicked(self, button): """ Create a new playlist based on search @param button as Gtk.Button """ button.set_sensitive(False) App().task_helper.run(self.__search_to_playlist) def _on_search_changed(self, widget): """ Timeout filtering @param widget as Gtk.TextEntry """ if self.__timeout_id: GLib.source_remove(self.__timeout_id) self.__timeout_id = None self.__cancellable.cancel() self.__view.stop() self.__current_search = widget.get_text().strip() self.__timeout_id = GLib.timeout_add(500, self.__on_search_changed_timeout) ####################### # PRIVATE # ####################### def __set_no_result_placeholder(self): """ Set placeholder for no result """ self.__placeholder.set_markup( _("<big>No results for this search</big>")) def __set_default_placeholder(self): """ Set placeholder for no result """ self.__placeholder.set_markup( _("<big>Search for artists, albums and tracks</big>")) def __populate(self): """ Populate searching items in db based on text entry current text """ self.__cancellable.reset() self.__header_stack.set_visible_child(self.__spinner) self.__spinner.start() self.__history = [] if self.__current_search: search = Search() search.get(self.__current_search, self.__cancellable, callback=(self.__on_search_get, )) else: self.__stack.set_visible_child_name("placeholder") self.__set_default_placeholder() self.__header_stack.set_visible_child(self.__new_button) GLib.idle_add(self.__spinner.stop) def __search_to_playlist(self): """ Create a new playlist based on search """ tracks = [] for child in self.__view.children: tracks += child.album.tracks if tracks: playlist_id = App().playlists.get_id(self.__current_search) if playlist_id == Type.NONE: App().playlists.add(self.__current_search) playlist_id = App().playlists.get_id(self.__current_search) App().playlists.add_tracks(playlist_id, tracks) def __on_search_get(self, result): """ Add rows for internal results @param result as [(int, Album, bool)] """ if result: albums = [] reveal_albums = [] for (score, album, in_tracks) in result: albums.append(album) if in_tracks: reveal_albums.append(album.id) self.__view.set_reveal(reveal_albums) self.__view.populate(albums) self.__stack.set_visible_child_name("view") else: self.__stack.set_visible_child_name("placeholder") self.__set_no_result_placeholder() self.__header_stack.set_visible_child(self.__new_button) GLib.idle_add(self.__spinner.stop) def __on_map(self, widget): """ Grab focus @param widget as Gtk.Widget """ GLib.idle_add(self.__entry.grab_focus) def __on_unmap(self, widget): """ Stop loading @param widget as Gtk.Widget """ self.__cancellable.cancel() self.__view.stop() self.__header_stack.set_visible_child(self.__new_button) self.__spinner.stop() def __on_search_changed_timeout(self): """ Populate widget """ if self.__view.children: self.__view.stop() self.__view.clear() return True self.__timeout_id = None self.__populate() if self.__current_search != "": self.__play_button.set_sensitive(True) self.__new_button.set_sensitive(True) else: self.__play_button.set_sensitive(False) self.__new_button.set_sensitive(False)
class SearchView(BaseView, Gtk.Bin): """ View for searching albums/tracks """ def __init__(self): """ Init Popover """ BaseView.__init__(self) Gtk.Bin.__init__(self) self.connect("map", self.__on_map) self.connect("unmap", self.__on_unmap) self.__timeout_id = None self.__new_album_signal_id = None self.__search_finished_signal_id = None self.__current_search = "" self.__cancellable = Gio.Cancellable() self.__history = [] self.__search_type_action = Gio.SimpleAction.new_stateful( "search_type", GLib.VariantType.new("s"), GLib.Variant("s", "local")) self.__search_type_action.connect("change-state", self.__on_search_action_change_state) App().add_action(self.__search_type_action) builder = Gtk.Builder() builder.add_from_resource("/org/gnome/Lollypop/SearchView.ui") self.__widget = builder.get_object("widget") self.__new_button = builder.get_object("new_button") self.__play_button = builder.get_object("play_button") self.__bottom_buttons = builder.get_object("bottom_buttons") self.__entry = builder.get_object("entry") self.__spinner = builder.get_object("spinner") self.__header_stack = builder.get_object("header_stack") self.__combo_locale = builder.get_object("combo_locale") self.__combo_locale.set_active_id( App().settings.get_value("spotify-charts-locale").get_string()) self.__button_stack = builder.get_object("button_stack") self.__stack = builder.get_object("stack") self.__placeholder = builder.get_object("placeholder") self.__view = AlbumsListView([], [], ViewType.SEARCH) self.__view.set_margin_start(MARGIN_SMALL) self.__view.show() self.__stack.add_named(self.__view, "view") self.__set_default_placeholder() self.add(self.__widget) builder.connect_signals(self) def set_search(self, search): """ Set search text @param search as str """ parsed = urlparse(search) search = search.replace("%s://" % parsed.scheme, "") if parsed.scheme == "local": self.__entry.set_text(search) GLib.idle_add(self.__search_type_action.set_state, GLib.Variant("s", "local")) elif parsed.scheme == "web": self.__entry.set_text(search) GLib.idle_add(self.__search_type_action.set_state, GLib.Variant("s", "web")) def cancel(self): """ Cancel current search and replace cancellable """ self.__cancellable.cancel() self.__cancellable = Gio.Cancellable() @property def should_destroy(self): """ User want to get search between mode """ return False ####################### # PROTECTED # ####################### def _on_play_button_clicked(self, button): """ Play search @param button as Gtk.Button """ try: App().player.clear_albums() shuffle_setting = App().settings.get_enum("shuffle") children = self.__view.children if shuffle_setting == Shuffle.ALBUMS: shuffle(children) for child in children: App().player.add_album(child.album) App().player.load(App().player.albums[0].tracks[0]) except Exception as e: Logger.error("SearchPopover::_on_play_button_clicked(): %s", e) def _on_new_button_clicked(self, button): """ Create a new playlist based on search @param button as Gtk.Button """ App().task_helper.run(self.__search_to_playlist) def _on_search_changed(self, widget): """ Timeout filtering @param widget as Gtk.TextEntry """ state = self.__search_type_action.get_state().get_string() if state == "local": timeout = 500 else: timeout = 1000 if self.__timeout_id: GLib.source_remove(self.__timeout_id) self.__timeout_id = None self.cancel() self.__view.stop() self.__current_search = widget.get_text().strip() self.__timeout_id = GLib.timeout_add(timeout, self.__on_search_changed_timeout) def _on_combo_locale_changed(self, combobox): """ Save setting @param combobox as Gtk.ComboBoxText """ App().settings.set_value("spotify-charts-locale", GLib.Variant("s", combobox.get_active_id())) self.__on_search_action_change_state(self.__search_type_action, GLib.Variant("s", "charts")) ####################### # PRIVATE # ####################### def __set_no_result_placeholder(self): """ Set placeholder for no result """ self.__placeholder.set_markup( _("<big>No results for this search</big>")) def __set_default_placeholder(self): """ Set placeholder for no result """ self.__placeholder.set_markup( _("<big>Search for artists, albums and tracks</big>")) def __populate(self): """ Populate searching items in db based on text entry current text """ self.__cancellable = Gio.Cancellable() self.__button_stack.set_visible_child(self.__spinner) self.__history = [] if len(self.__current_search) > 2: self.__spinner.start() state = self.__search_type_action.get_state().get_string() current_search = self.__current_search.lower() if state == "local": search = Search() search.get(current_search, self.__cancellable, callback=(self.__on_search_get, current_search)) elif state == "web": App().task_helper.run(App().spotify.search, current_search, self.__cancellable) else: self.__stack.set_visible_child_name("placeholder") self.__set_default_placeholder() self.__button_stack.set_visible_child(self.__new_button) GLib.idle_add(self.__spinner.stop) def __search_to_playlist(self): """ Create a new playlist based on search """ tracks = [] for child in self.__view.children: tracks += child.album.tracks if tracks: playlist_id = App().playlists.get_id(self.__current_search) if playlist_id == Type.NONE: App().playlists.add(self.__current_search) playlist_id = App().playlists.get_id(self.__current_search) App().playlists.add_tracks(playlist_id, tracks) GLib.idle_add(self.__show_playlist, playlist_id) def __show_playlist(self, playlist_id): """ Hide if in a popover and show playlist """ if App().settings.get_value("show-sidebar"): App().window.container.show_lists([Type.PLAYLISTS], [playlist_id]) else: App().window.container.show_view(Type.PLAYLISTS, [playlist_id]) popover = self.get_ancestor(Gtk.Popover) if popover is not None: popover.hide() else: self.destroy() def __on_search_get(self, result, search): """ Add rows for internal results @param result as [(int, Album, bool)] """ self.__on_search_finished(None) if result: albums = [] reveal_albums = [] for (album, in_tracks) in result: albums.append(album) if in_tracks: reveal_albums.append(album) self.__view.set_reveal(reveal_albums) self.__view.populate(albums) self.__stack.set_visible_child_name("view") def __on_map(self, widget): """ Init signals and grab focus @param widget as Gtk.Widget """ App().enable_special_shortcuts(False) if GLib.find_program_in_path("youtube-dl") is None or\ not get_network_available("SPOTIFY") or\ not get_network_available("YOUTUBE"): self.__bottom_buttons.hide() else: self.__bottom_buttons.show() if self.__new_album_signal_id is None: self.__new_album_signal_id = App().spotify.connect( "new-album", self.__on_new_spotify_album) if self.__search_finished_signal_id is None: self.__search_finished_signal_id = App().spotify.connect( "search-finished", self.__on_search_finished) GLib.idle_add(self.__entry.grab_focus) def __on_unmap(self, widget): """ Clean up @param widget as Gtk.Widget """ App().enable_special_shortcuts(True) if self.__new_album_signal_id is not None: App().spotify.disconnect(self.__new_album_signal_id) self.__new_album_signal_id = None if self.__search_finished_signal_id is not None: App().spotify.disconnect(self.__search_finished_signal_id) self.__search_finished_signal_id = None self.cancel() self.__view.stop() self.__button_stack.set_visible_child(self.__new_button) self.__spinner.stop() def __on_new_spotify_album(self, spotify, album, cover_uri): """ Add album @param spotify as SpotifyHelper @param album as Album @param cover_uri as str """ self.__view.insert_album(album, len(album.tracks) == 1, -1, cover_uri) self.__stack.set_visible_child_name("view") def __on_search_finished(self, api): """ Stop spinner @param api ignored """ self.__spinner.stop() self.__button_stack.set_visible_child(self.__new_button) if not self.__view.children: self.__stack.set_visible_child_name("placeholder") self.__set_no_result_placeholder() def __on_search_changed_timeout(self): """ Populate widget """ if self.__view.children: self.__view.stop() self.__view.clear() return True self.__timeout_id = None self.__populate() if self.__current_search != "": self.__new_button.set_sensitive(True) else: self.__new_button.set_sensitive(False) def __on_search_action_change_state(self, action, value): """ Update action value @param action as Gio.SimpleAction @param value as GLib.Variant """ self.cancel() self.__view.stop() action.set_state(value) state = value.get_string() # A new album signal may be in queue, so clear after GLib.idle_add(self.__view.clear) if state == "local": self.__new_button.show() self.__button_stack.set_visible_child(self.__new_button) else: self.__new_button.hide() if state == "charts": self.__header_stack.set_visible_child_name("locale") self.__play_button.set_sensitive(True) self.__button_stack.set_visible_child(self.__spinner) self.__history = [] self.__spinner.start() self.__stack.set_visible_child_name("view") App().task_helper.run(App().spotify.charts, self.__cancellable, self.__combo_locale.get_active_id()) else: self.__header_stack.set_visible_child_name("entry") self.__populate() GLib.idle_add(self.__entry.grab_focus)