Example #1
0
    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self)
        self.__tracks = []
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = Lp().playlists.connect('playlist-add',
                                                   self.__on_playlist_add)
        self.__signal_id2 = Lp().playlists.connect('playlist-del',
                                                   self.__on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/PlaylistView.ui')
        builder.connect_signals(self)

        builder.get_object('title').set_label(
                             ", ".join(Lp().playlists.get_names(playlist_ids)))

        self.__edit_button = builder.get_object('edit-button')
        self.__jump_button = builder.get_object('jump-button')

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] != Type.LOVED) or\
                not editable:
            self.__edit_button.hide()

        self.__playlists_widget = PlaylistsWidget(playlist_ids)
        self.__playlists_widget.show()
        self.add(builder.get_object('widget'))
        self._viewport.add(self.__playlists_widget)
        self._scrolled.set_property('expand', True)
        self.add(self._scrolled)
Example #2
0
    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self, True)
        self.__tracks = []
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = Lp().playlists.connect("playlist-add",
                                                   self.__on_playlist_add)
        self.__signal_id2 = Lp().playlists.connect("playlist-del",
                                                   self.__on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/PlaylistView.ui")
        self.__duration_label = builder.get_object("duration")
        builder.get_object("title").set_label(", ".join(
            Lp().playlists.get_names(playlist_ids)))

        self.__edit_button = builder.get_object("edit-button")
        self.__jump_button = builder.get_object("jump-button")
        split_button = builder.get_object("split-button")
        if editable:
            split_button.set_active(not Lp().settings.get_value("split-view"))
        else:
            split_button.hide()

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] not in [Type.LOVED,
                                                           Type.NOPARTY]) or\
                not editable:
            self.__edit_button.hide()

        self.__playlists_widget = PlaylistsWidget(playlist_ids)
        self.__playlists_widget.set_filter_func(self._filter_func)
        self.__playlists_widget.show()
        self.add(builder.get_object("widget"))
        self._viewport.add(self.__playlists_widget)
        self._scrolled.set_property("expand", True)
        self.add(self._scrolled)
        # Connect signals after ui init
        # "split-button" will emit a signal otherwise
        builder.connect_signals(self)
        # No duration for non user playlists
        # FIXME
        if playlist_ids[0] > 0:
            self.__set_duration()
Example #3
0
    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self)
        self._tracks = []
        self._playlist_ids = playlist_ids
        self._signal_id1 = Lp().playlists.connect('playlist-add',
                                                  self._on_playlist_add)
        self._signal_id2 = Lp().playlists.connect('playlist-del',
                                                  self._on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/PlaylistView.ui')
        builder.connect_signals(self)

        builder.get_object('title').set_label(
                             ", ".join(Lp().playlists.get_names(playlist_ids)))

        self._edit_button = builder.get_object('edit-button')
        self._jump_button = builder.get_object('jump-button')

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] != Type.LOVED) or\
                not editable:
            self._edit_button.hide()

        self._playlists_widget = PlaylistsWidget(playlist_ids)
        self._playlists_widget.show()
        self.add(builder.get_object('widget'))
        self._viewport.add(self._playlists_widget)
        self._scrolled.set_property('expand', True)
        self.add(self._scrolled)
Example #4
0
    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self, True)
        self.__tracks = []
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = Lp().playlists.connect('playlist-add',
                                                   self.__on_playlist_add)
        self.__signal_id2 = Lp().playlists.connect('playlist-del',
                                                   self.__on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/PlaylistView.ui')

        builder.get_object('title').set_label(", ".join(
            Lp().playlists.get_names(playlist_ids)))

        self.__edit_button = builder.get_object('edit-button')
        self.__jump_button = builder.get_object('jump-button')
        split_button = builder.get_object('split-button')
        if editable:
            split_button.set_active(not Lp().settings.get_value('split-view'))
        else:
            split_button.hide()

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] not in [Type.LOVED,
                                                           Type.NOPARTY]) or\
                not editable:
            self.__edit_button.hide()

        self.__playlists_widget = PlaylistsWidget(playlist_ids)
        self.__playlists_widget.set_filter_func(self._filter_func)
        self.__playlists_widget.show()
        self.add(builder.get_object('widget'))
        self._viewport.add(self.__playlists_widget)
        self._scrolled.set_property('expand', True)
        self.add(self._scrolled)
        # Connect signals after ui init
        # 'split-button' will emit a signal otherwise
        builder.connect_signals(self)
Example #5
0
    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self)
        self._tracks = []
        self._playlist_ids = playlist_ids
        self._signal_id1 = Lp().playlists.connect('playlist-add',
                                                  self._on_playlist_add)
        self._signal_id2 = Lp().playlists.connect('playlist-del',
                                                  self._on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/PlaylistView.ui')
        builder.connect_signals(self)

        name = ""
        for playlist_id in playlist_ids:
            if playlist_id == Type.POPULARS:
                name += _("Popular tracks")+", "
            elif playlist_id == Type.RECENTS:
                name += _("Recently played")+", "
            elif playlist_id == Type.NEVER:
                name += _("Never played")+", "
            elif playlist_id == Type.RANDOMS:
                name += _("Random tracks")+", "
            elif playlist_id == Type.SEARCH:
                name += _("Search")+", "
            else:
                name += Lp().playlists.get_name(playlist_id)+", "
        builder.get_object('title').set_label(name[:-2])

        self._edit_button = builder.get_object('edit-button')
        self._jump_button = builder.get_object('jump-button')

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] != Type.LOVED) or\
                not editable:
            self._edit_button.hide()
        self._title = builder.get_object('title')

        self._playlists_widget = PlaylistsWidget(playlist_ids)
        self._playlists_widget.connect('populated', self._on_populated)
        self._playlists_widget.show()
        self.add(builder.get_object('widget'))
        self._viewport.add(self._playlists_widget)
        self._scrolled.set_property('expand', True)
        self.add(self._scrolled)
Example #6
0
class PlaylistsView(View):
    """
        Show playlist tracks
    """
    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self)
        self.__tracks = []
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = Lp().playlists.connect('playlist-add',
                                                   self.__on_playlist_add)
        self.__signal_id2 = Lp().playlists.connect('playlist-del',
                                                   self.__on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/PlaylistView.ui')

        builder.get_object('title').set_label(", ".join(
            Lp().playlists.get_names(playlist_ids)))

        self.__edit_button = builder.get_object('edit-button')
        self.__jump_button = builder.get_object('jump-button')
        split_button = builder.get_object('split-button')
        if editable:
            split_button.set_active(not Lp().settings.get_value('split-view'))
        else:
            split_button.hide()

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] != Type.LOVED) or\
                not editable:
            self.__edit_button.hide()

        self.__playlists_widget = PlaylistsWidget(playlist_ids)
        self.__playlists_widget.show()
        self.add(builder.get_object('widget'))
        self._viewport.add(self.__playlists_widget)
        self._scrolled.set_property('expand', True)
        self.add(self._scrolled)
        # Connect signals after ui init
        # 'split-button' will emit a signal otherwise
        builder.connect_signals(self)

    def populate(self, tracks):
        """
            Populate view with tracks from playlist
            Thread safe
        """
        # We are looking for middle
        # Ponderate with this:
        # Tracks with cover == 2
        # Tracks without cover == 1
        prev_album_id = None
        heights = {}
        total = 0
        idx = 0
        for track_id in tracks:
            track = Track(track_id)
            if track.album_id != prev_album_id:
                heights[idx] = 2
                total += 2
            else:
                heights[idx] = 1
                total += 1
            prev_album_id = track.album_id
            idx += 1
        half = int(total / 2 + 0.5)
        mid_tracks = 1
        count = 0
        for height in heights.values():
            count += height
            if count >= half:
                break
            mid_tracks += 1
        self.__tracks = tracks
        self.__update_jump_button()
        self.__playlists_widget.populate_list_left(tracks[:mid_tracks], 1)
        self.__playlists_widget.populate_list_right(tracks[mid_tracks:],
                                                    mid_tracks + 1)

    def get_ids(self):
        """
            Return playlist ids
            @return id as [int]
        """
        return self.__playlist_ids

    def stop(self):
        """
            Stop populating
        """
        self.__playlists_widget.stop()

#######################
# PROTECTED           #
#######################

    def _get_children(self):
        """
            Return view children
        """
        return [self.__playlists_widget]

    def _on_destroy(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        View._on_destroy(self, widget)
        if self.__signal_id1:
            Lp().playlists.disconnect(self.__signal_id1)
            self.__signal_id1 = None
        if self.__signal_id2:
            Lp().playlists.disconnect(self.__signal_id2)
            self.__signal_id2 = None

    def _on_split_button_toggled(self, button):
        """
            Split/Unsplit view
        """
        Lp().settings.set_value('split-view',
                                GLib.Variant('b', not button.get_active()))
        self.__playlists_widget.update_allocation()

    def _on_jump_button_clicked(self, button):
        """
            Scroll to current track
            @param button as Gtk.Button
        """
        y = self.__playlists_widget.get_current_ordinate()
        if y is not None:
            self._scrolled.get_vadjustment().set_value(y)

    def _on_edit_button_clicked(self, button):
        """
            Edit playlist
            @param button as Gtk.Button
        """
        Lp().window.show_playlist_editor(self.__playlist_ids[0])

    def _on_current_changed(self, player):
        """
            Current song changed, update playing button
            @param player as Player
        """
        View._on_current_changed(self, player)
        self.__update_jump_button()


#######################
# PRIVATE             #
#######################

    def __update_jump_button(self):
        """
            Update jump button status
        """
        if Lp().player.current_track.id in self.__tracks:
            self.__jump_button.set_sensitive(True)
            artists = ", ".join(Lp().player.current_track.artists)
            self.__jump_button.set_tooltip_markup(
                "<b>%s</b>\n%s" %
                (GLib.markup_escape_text(artists),
                 GLib.markup_escape_text(Lp().player.current_track.name)))
        else:
            self.__jump_button.set_sensitive(False)
            self.__jump_button.set_tooltip_text('')

    def __on_playlist_add(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self.__playlist_ids:
            self.__playlists_widget.append(track_id)

    def __on_playlist_del(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self.__playlist_ids:
            self.__playlists_widget.remove(track_id)
    def __init__(self, playlist_ids, view_type):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param view_type as ViewType
        """
        LazyLoadingView.__init__(self)
        ViewController.__init__(self, ViewControllerType.ALBUM)
        self.__view_type = view_type
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = App().playlists.connect(
            "playlist-track-added", self.__on_playlist_track_added)
        self.__signal_id2 = App().playlists.connect(
            "playlist-track-removed", self.__on_playlist_track_removed)
        self.__signal_id3 = App().settings.connect(
            "changed::split-view", self.__on_split_view_changed)

        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/PlaylistView.ui")
        self.__title_label = builder.get_object("title")
        self.__duration_label = builder.get_object("duration")
        self.__play_button = builder.get_object("play_button")
        self.__shuffle_button = builder.get_object("shuffle_button")
        self.__jump_button = builder.get_object("jump_button")
        self.__menu_button = builder.get_object("menu_button")
        self.__buttons = builder.get_object("box-buttons")
        self.__widget = builder.get_object("widget")
        self.__playlists_widget = PlaylistsWidget(playlist_ids, view_type)
        self.__playlists_widget.set_filter_func(self._filter_func)
        self.__playlists_widget.connect("populated", self.__on_populated)
        self.__playlists_widget.show()
        self._viewport.add(self.__playlists_widget)
        self.__title_label.set_margin_start(MARGIN)
        self.__buttons.set_margin_end(MARGIN)
        if self.__view_type & (ViewType.POPOVER | ViewType.FULLSCREEN):
            self.__title_label.get_style_context().add_class("dim-label")
            self.__duration_label.get_style_context().add_class("dim-label")
            self.__widget.add(self.__title_label)
            self.__jump_button = Gtk.Button.new_from_icon_name(
                "go-jump-symbolic", Gtk.IconSize.BUTTON)
            self.__jump_button.connect("clicked", self._on_jump_button_clicked)
            self.__jump_button.set_relief(Gtk.ReliefStyle.NONE)
            self.__jump_button.show()
            self.__jump_button.set_margin_end(MARGIN_SMALL)
            self.__widget.add(self.__duration_label)
            self.__widget.add(self.__jump_button)
            self.__widget.set_margin_bottom(MARGIN_SMALL)
            self.add(self.__widget)
            self.add(self._scrolled)
        else:
            self.__duration_label.set_margin_start(MARGIN)
            self._overlay = Gtk.Overlay.new()
            self._overlay.add(self._scrolled)
            self._overlay.show()
            self.__widget.attach(self.__title_label, 0, 0, 1, 1)
            self.__widget.attach(self.__duration_label, 0, 1, 1, 1)
            self.__widget.attach(self.__buttons, 1, 0, 1, 2)
            self.__widget.set_vexpand(True)
            self.__title_label.set_vexpand(True)
            self.__duration_label.set_vexpand(True)
            if App().window.is_adaptive:
                self.__title_label.get_style_context().add_class(
                    "text-x-large")
                self.__duration_label.get_style_context().add_class(
                    "text-large")
            else:
                self.__title_label.get_style_context().add_class(
                    "text-xx-large")
                self.__duration_label.get_style_context().add_class(
                    "text-x-large")
            self.__title_label.set_property("valign", Gtk.Align.END)
            self.__duration_label.set_property("valign", Gtk.Align.START)
            self.__banner = PlaylistBannerWidget(playlist_ids[0])
            self.__banner.show()
            self._overlay.add_overlay(self.__banner)
            self.__banner.add_overlay(self.__widget)
            self.__playlists_widget.set_margin_top(
                self.__banner.default_height + 15)
            self.add(self._overlay)
        self.__title_label.set_label(", ".join(
            App().playlists.get_names(playlist_ids)))
        self._scrolled.set_property("expand", True)
        builder.connect_signals(self)

        if len(playlist_ids) > 1:
            self.__menu_button.hide()

        # In DB duration calculation
        if playlist_ids[0] > 0 and\
                not App().playlists.get_smart(playlist_ids[0]):
            duration = 0
            for playlist_id in self.__playlist_ids:
                duration += App().playlists.get_duration(playlist_id)
            self.__set_duration(duration)
        # Ask widget after populated
        else:
            self.__playlists_widget.connect("populated",
                                            self.__on_playlist_populated)
class PlaylistsView(LazyLoadingView, ViewController):
    """
        Show playlist tracks
    """
    def __init__(self, playlist_ids, view_type):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param view_type as ViewType
        """
        LazyLoadingView.__init__(self)
        ViewController.__init__(self, ViewControllerType.ALBUM)
        self.__view_type = view_type
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = App().playlists.connect(
            "playlist-track-added", self.__on_playlist_track_added)
        self.__signal_id2 = App().playlists.connect(
            "playlist-track-removed", self.__on_playlist_track_removed)
        self.__signal_id3 = App().settings.connect(
            "changed::split-view", self.__on_split_view_changed)

        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/PlaylistView.ui")
        self.__title_label = builder.get_object("title")
        self.__duration_label = builder.get_object("duration")
        self.__play_button = builder.get_object("play_button")
        self.__shuffle_button = builder.get_object("shuffle_button")
        self.__jump_button = builder.get_object("jump_button")
        self.__menu_button = builder.get_object("menu_button")
        self.__buttons = builder.get_object("box-buttons")
        self.__widget = builder.get_object("widget")
        self.__playlists_widget = PlaylistsWidget(playlist_ids, view_type)
        self.__playlists_widget.set_filter_func(self._filter_func)
        self.__playlists_widget.connect("populated", self.__on_populated)
        self.__playlists_widget.show()
        self._viewport.add(self.__playlists_widget)
        self.__title_label.set_margin_start(MARGIN)
        self.__buttons.set_margin_end(MARGIN)
        if self.__view_type & (ViewType.POPOVER | ViewType.FULLSCREEN):
            self.__title_label.get_style_context().add_class("dim-label")
            self.__duration_label.get_style_context().add_class("dim-label")
            self.__widget.add(self.__title_label)
            self.__jump_button = Gtk.Button.new_from_icon_name(
                "go-jump-symbolic", Gtk.IconSize.BUTTON)
            self.__jump_button.connect("clicked", self._on_jump_button_clicked)
            self.__jump_button.set_relief(Gtk.ReliefStyle.NONE)
            self.__jump_button.show()
            self.__jump_button.set_margin_end(MARGIN_SMALL)
            self.__widget.add(self.__duration_label)
            self.__widget.add(self.__jump_button)
            self.__widget.set_margin_bottom(MARGIN_SMALL)
            self.add(self.__widget)
            self.add(self._scrolled)
        else:
            self.__duration_label.set_margin_start(MARGIN)
            self._overlay = Gtk.Overlay.new()
            self._overlay.add(self._scrolled)
            self._overlay.show()
            self.__widget.attach(self.__title_label, 0, 0, 1, 1)
            self.__widget.attach(self.__duration_label, 0, 1, 1, 1)
            self.__widget.attach(self.__buttons, 1, 0, 1, 2)
            self.__widget.set_vexpand(True)
            self.__title_label.set_vexpand(True)
            self.__duration_label.set_vexpand(True)
            if App().window.is_adaptive:
                self.__title_label.get_style_context().add_class(
                    "text-x-large")
                self.__duration_label.get_style_context().add_class(
                    "text-large")
            else:
                self.__title_label.get_style_context().add_class(
                    "text-xx-large")
                self.__duration_label.get_style_context().add_class(
                    "text-x-large")
            self.__title_label.set_property("valign", Gtk.Align.END)
            self.__duration_label.set_property("valign", Gtk.Align.START)
            self.__banner = PlaylistBannerWidget(playlist_ids[0])
            self.__banner.show()
            self._overlay.add_overlay(self.__banner)
            self.__banner.add_overlay(self.__widget)
            self.__playlists_widget.set_margin_top(
                self.__banner.default_height + 15)
            self.add(self._overlay)
        self.__title_label.set_label(", ".join(
            App().playlists.get_names(playlist_ids)))
        self._scrolled.set_property("expand", True)
        builder.connect_signals(self)

        if len(playlist_ids) > 1:
            self.__menu_button.hide()

        # In DB duration calculation
        if playlist_ids[0] > 0 and\
                not App().playlists.get_smart(playlist_ids[0]):
            duration = 0
            for playlist_id in self.__playlist_ids:
                duration += App().playlists.get_duration(playlist_id)
            self.__set_duration(duration)
        # Ask widget after populated
        else:
            self.__playlists_widget.connect("populated",
                                            self.__on_playlist_populated)

    def populate(self, tracks):
        """
            Populate view with tracks from playlist
            @param tracks as [track]
        """
        self.__playlists_widget.populate(tracks)
        self.__update_jump_button()

    def stop(self):
        """
            Stop populating
        """
        self.__playlists_widget.stop()

    @property
    def playlist_ids(self):
        """
            Return playlist ids
            @return id as [int]
        """
        return self.__playlist_ids

#######################
# PROTECTED           #
#######################

    def _on_value_changed(self, adj):
        """
            Adapt widget to current scroll value
            @param adj as Gtk.Adjustment
        """
        LazyLoadingView._on_value_changed(self, adj)
        if not self.__view_type & (ViewType.POPOVER | ViewType.FULLSCREEN):
            title_style_context = self.__title_label.get_style_context()
            if adj.get_value() == adj.get_lower():
                height = self.__banner.default_height
                self.__duration_label.show()
                self.__title_label.set_property("valign", Gtk.Align.END)
                if not App().window.is_adaptive:
                    title_style_context.remove_class("text-x-large")
                    title_style_context.add_class("text-xx-large")
            else:
                self.__duration_label.hide()
                title_style_context.remove_class("text-xx-large")
                title_style_context.add_class("text-x-large")
                self.__title_label.set_property("valign", Gtk.Align.CENTER)
                height = self.__banner.default_height // 3
            # Make grid cover artwork
            # No idea why...
            self.__banner.set_height(height)
            self.__widget.set_size_request(-1, height + 1)

    def _on_current_changed(self, player):
        """
            Update children state
            @param player as Player
        """
        self.__update_jump_button()
        self.__playlists_widget.set_playing_indicator()

    def _on_search_changed(self, entry):
        """
            Update filter
            @param entry as Gtk.Entry
        """
        self._filter = entry.get_text()
        for box in self.__playlists_widget.boxes:
            box.invalidate_filter()

    def _on_destroy(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        LazyLoadingView._on_destroy(self, widget)
        if self.__signal_id1:
            App().playlists.disconnect(self.__signal_id1)
            self.__signal_id1 = None
        if self.__signal_id2:
            App().playlists.disconnect(self.__signal_id2)
            self.__signal_id2 = None

    def _on_jump_button_clicked(self, button):
        """
            Scroll to current track
            @param button as Gtk.Button
        """
        y = self.__playlists_widget.get_current_ordinate()
        if y is not None:
            self._scrolled.get_vadjustment().set_value(y)

    def _on_play_button_clicked(self, button):
        """
            Play playlist
            @param button as Gtk.Button
        """
        tracks = []
        for child in self.__playlists_widget.children:
            tracks.append(child.track)
        if tracks:
            App().player.populate_playlist_by_tracks(tracks,
                                                     self.__playlist_ids,
                                                     tracks[0])

    def _on_shuffle_button_clicked(self, button):
        """
            Play playlist shuffled
            @param button as Gtk.Button
        """
        tracks = []
        for child in self.__playlists_widget.children:
            tracks.append(child.track)
        if tracks:
            shuffle(tracks)
            App().player.populate_playlist_by_tracks(tracks,
                                                     self.__playlist_ids,
                                                     tracks[0])

    def _on_menu_button_clicked(self, button):
        """
            Show playlist menu
            @param button as Gtk.Button
        """
        from lollypop.menu_playlist import PlaylistMenu
        menu = PlaylistMenu(self.__playlist_ids[0])
        popover = Gtk.Popover.new_from_model(button, menu)
        popover.popup()

    def _on_map(self, widget):
        """
            Set active ids
        """
        sidebar_content = App().settings.get_enum("sidebar-content")
        if sidebar_content != SidebarContent.GENRES:
            App().window.emit("show-can-go-back", True)
            App().window.emit("can-go-back-changed", True)
        App().settings.set_value("state-one-ids",
                                 GLib.Variant("ai", [Type.PLAYLISTS]))
        App().settings.set_value("state-two-ids",
                                 GLib.Variant("ai", self.__playlist_ids))
        App().settings.set_value("state-three-ids", GLib.Variant("ai", []))

#######################
# PRIVATE             #
#######################

    def __set_duration(self, duration):
        """
            Set playlist duration
            @param duration as int (seconds)
        """
        self.__duration_label.set_text(get_human_duration(duration))

    def __update_jump_button(self):
        """
            Update jump button status
        """
        track_ids = [
            child.track.id for child in self.__playlists_widget.children
        ]
        if App().player.current_track.id in track_ids:
            self.__jump_button.set_sensitive(True)
        else:
            self.__jump_button.set_sensitive(False)

    def __on_populated(self, playlists_widget):
        """
            Update jump button on populated
            @param playlists_widget as PlaylistsWidget
        """
        self.__update_jump_button()

    def __on_playlist_track_added(self, playlists, playlist_id, uri, pos):
        """
            Update tracks widgets
            @param playlists as Playlists
            @param playlist_id as int
            @param uri as str
            @param pos as int
        """
        if len(self.__playlist_ids) == 1 and\
                playlist_id in self.__playlist_ids:
            track_id = App().tracks.get_id_by_uri(uri)
            self.__playlists_widget.append(track_id)

    def __on_playlist_track_removed(self, playlists, playlist_id, uri, pos):
        """
            Update tracks widgets
            @param playlists as Playlists
            @param playlist_id as int
            @param uri as str
            @param pos as int
        """
        if len(self.__playlist_ids) == 1 and\
                playlist_id in self.__playlist_ids:
            track_id = App().tracks.get_id_by_uri(uri)
            self.__playlists_widget.remove(track_id, pos)

    def __on_playlist_populated(self, widget):
        """
            Set duration on populated
            @param widget as PlaylistsWidget
        """
        self.__set_duration(widget.duration)

    def __on_split_view_changed(self, settings, value):
        """
            Split/Unsplit view
            @param settings as Gio.Settings
            @param value as GLib.Variant
        """
        self.__playlists_widget.update_allocation()
Example #9
0
    def __init__(self, playlist_ids, list_type, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param list_type as RowListType
            @param editable as bool
        """
        View.__init__(self, True)
        ViewController.__init__(self, ViewControllerType.ALBUM)
        self.__list_type = list_type
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = App().playlists.connect(
            "playlist-track-added", self.__on_playlist_track_added)
        self.__signal_id2 = App().playlists.connect(
            "playlist-track-removed", self.__on_playlist_track_removed)

        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/PlaylistView.ui")
        self.__header = builder.get_object("header")
        self.__play_button = builder.get_object("play_button")
        self.__shuffle_button = builder.get_object("shuffle_button")
        if App().player.is_locked:
            self.__play_button.set_sensitive(False)
            self.__shuffle_button.set_sensitive(False)
        self.__duration_label = builder.get_object("duration")
        builder.get_object("title").set_label(", ".join(
            App().playlists.get_names(playlist_ids)))

        self.__jump_button = builder.get_object("jump_button")
        self.__split_button = builder.get_object("split_button")
        smart_button = builder.get_object("smart_button")

        if editable:
            self.__split_button.set_active(
                not App().settings.get_value("split-view"))
        else:
            self.__jump_button.set_hexpand(True)
            self.__split_button.hide()
            self.__play_button.hide()
            self.__shuffle_button.hide()
        if not editable or len(playlist_ids) > 1 or playlist_ids[0] < 0:
            smart_button.hide()

        self.__playlists_widget = PlaylistsWidget(playlist_ids, list_type)
        self.__playlists_widget.set_filter_func(self._filter_func)
        self.__playlists_widget.connect("populated", self.__on_populated)
        self.__playlists_widget.show()
        self.add(builder.get_object("widget"))
        self._viewport.add(self.__playlists_widget)
        self._scrolled.set_property("expand", True)
        self.add(self._scrolled)
        # Connect signals after ui init
        # "split-button" will emit a signal otherwise
        builder.connect_signals(self)

        # In DB duration calculation
        if playlist_ids[0] > 0:
            duration = 0
            for playlist_id in self.__playlist_ids:
                duration += App().playlists.get_duration(playlist_id)
            self.__set_duration(duration)
        # Ask widget after populated
        else:
            self.__playlists_widget.connect("populated",
                                            self.__on_playlist_populated)
        self.__playlists_widget.connect("orientation-changed",
                                        self.__on_orientation_changed)
Example #10
0
class PlaylistsView(View, ViewController):
    """
        Show playlist tracks
    """
    def __init__(self, playlist_ids, list_type, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param list_type as RowListType
            @param editable as bool
        """
        View.__init__(self, True)
        ViewController.__init__(self, ViewControllerType.ALBUM)
        self.__list_type = list_type
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = App().playlists.connect(
            "playlist-track-added", self.__on_playlist_track_added)
        self.__signal_id2 = App().playlists.connect(
            "playlist-track-removed", self.__on_playlist_track_removed)

        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/PlaylistView.ui")
        self.__header = builder.get_object("header")
        self.__play_button = builder.get_object("play_button")
        self.__shuffle_button = builder.get_object("shuffle_button")
        if App().player.is_locked:
            self.__play_button.set_sensitive(False)
            self.__shuffle_button.set_sensitive(False)
        self.__duration_label = builder.get_object("duration")
        builder.get_object("title").set_label(", ".join(
            App().playlists.get_names(playlist_ids)))

        self.__jump_button = builder.get_object("jump_button")
        self.__split_button = builder.get_object("split_button")
        smart_button = builder.get_object("smart_button")

        if editable:
            self.__split_button.set_active(
                not App().settings.get_value("split-view"))
        else:
            self.__jump_button.set_hexpand(True)
            self.__split_button.hide()
            self.__play_button.hide()
            self.__shuffle_button.hide()
        if not editable or len(playlist_ids) > 1 or playlist_ids[0] < 0:
            smart_button.hide()

        self.__playlists_widget = PlaylistsWidget(playlist_ids, list_type)
        self.__playlists_widget.set_filter_func(self._filter_func)
        self.__playlists_widget.connect("populated", self.__on_populated)
        self.__playlists_widget.show()
        self.add(builder.get_object("widget"))
        self._viewport.add(self.__playlists_widget)
        self._scrolled.set_property("expand", True)
        self.add(self._scrolled)
        # Connect signals after ui init
        # "split-button" will emit a signal otherwise
        builder.connect_signals(self)

        # In DB duration calculation
        if playlist_ids[0] > 0:
            duration = 0
            for playlist_id in self.__playlist_ids:
                duration += App().playlists.get_duration(playlist_id)
            self.__set_duration(duration)
        # Ask widget after populated
        else:
            self.__playlists_widget.connect("populated",
                                            self.__on_playlist_populated)
        self.__playlists_widget.connect("orientation-changed",
                                        self.__on_orientation_changed)

    def populate(self, tracks):
        """
            Populate view with tracks from playlist
            @param tracks as [track]
        """
        self.__playlists_widget.populate(tracks)
        self.__update_jump_button()

    def stop(self):
        """
            Stop populating
        """
        self.__playlists_widget.stop()

    @property
    def playlist_ids(self):
        """
            Return playlist ids
            @return id as [int]
        """
        return self.__playlist_ids

#######################
# PROTECTED           #
#######################

    def _on_current_changed(self, player):
        """
            Update children state
            @param player as Player
        """
        self.__update_jump_button()
        self.__playlists_widget.set_playing_indicator()

    def _on_search_changed(self, entry):
        """
            Update filter
            @param entry as Gtk.Entry
        """
        self._filter = entry.get_text()
        for box in self.__playlists_widget.boxes:
            box.invalidate_filter()

    def _on_destroy(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        View._on_destroy(self, widget)
        if self.__signal_id1:
            App().playlists.disconnect(self.__signal_id1)
            self.__signal_id1 = None
        if self.__signal_id2:
            App().playlists.disconnect(self.__signal_id2)
            self.__signal_id2 = None

    def _on_split_button_toggled(self, button):
        """
            Split/Unsplit view
        """
        App().settings.set_value("split-view",
                                 GLib.Variant("b", not button.get_active()))
        self.__playlists_widget.update_allocation()

    def _on_jump_button_clicked(self, button):
        """
            Scroll to current track
            @param button as Gtk.Button
        """
        y = self.__playlists_widget.get_current_ordinate()
        if y is not None:
            self._scrolled.get_vadjustment().set_value(y)

    def _on_save_button_clicked(self, button):
        """
            Save playlist as file
            @param button as Gtk.Button
        """
        filechooser = Gtk.FileChooserNative.new(_("Save playlist"),
                                                App().window,
                                                Gtk.FileChooserAction.SAVE,
                                                _("Save"), _("Cancel"))
        filter = Gtk.FileFilter.new()
        filter.set_name("audio/x-mpegurl")
        filter.add_mime_type("audio/x-mpegurl")
        filechooser.add_filter(filter)
        filechooser.set_do_overwrite_confirmation(True)
        name = ", ".join(App().playlists.get_names(self.__playlist_ids))
        filechooser.set_current_name("%s.m3u" % name)
        filechooser.connect("response", self.__on_save_response)
        filechooser.run()

    def _on_play_button_clicked(self, button):
        """
            Play playlist
            @param button as Gtk.Button
        """
        tracks = []
        for child in self.__playlists_widget.children:
            tracks.append(child.track)
        if tracks:
            App().player.load(tracks[0])
            App().player.populate_playlist_by_tracks(tracks,
                                                     self.__playlist_ids)

    def _on_shuffle_button_clicked(self, button):
        """
            Play playlist shuffled
            @param button as Gtk.Button
        """
        tracks = []
        for child in self.__playlists_widget.children:
            tracks.append(child.track)
        if tracks:
            shuffle(tracks)
            App().player.load(tracks[0])
            App().player.populate_playlist_by_tracks(tracks,
                                                     self.__playlist_ids)

    def _on_smart_button_clicked(self, button):
        """
            Edit smart playlist
            @param button as Gtk.Button
        """
        App().window.container.show_smart_playlist_editor(
            self.__playlist_ids[0])

    def _on_map(self, widget):
        """
            Set active ids
        """
        App().settings.set_value("state-one-ids",
                                 GLib.Variant("ai", [Type.PLAYLISTS]))
        App().settings.set_value("state-two-ids",
                                 GLib.Variant("ai", self.__playlist_ids))

#######################
# PRIVATE             #
#######################

    def __set_duration(self, duration):
        """
            Set playlist duration
            @param duration as int (seconds)
        """
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                # Duration hour minute
                self.__duration_label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                # Duration hour minute
                self.__duration_label.set_text(_("%s h") % hours)
        else:
            # Duration hour minute
            self.__duration_label.set_text(_("%s m") % mins)

    def __update_jump_button(self):
        """
            Update jump button status
        """
        track_ids = [
            child.track.id for child in self.__playlists_widget.children
        ]
        if App().player.current_track.id in track_ids:
            self.__jump_button.set_sensitive(True)
        else:
            self.__jump_button.set_sensitive(False)

    def __on_save_response(self, dialog, response_id):
        """
            Save playlist
            @param dialog as Gtk.NativeDialog
            @param response_id as int
        """
        try:
            if response_id == Gtk.ResponseType.ACCEPT:
                uris = []
                for box in self.__playlists_widget.boxes:
                    for child in box.get_children():
                        uris.append(child.track.uri)
                stream = dialog.get_file().replace(
                    None, False, Gio.FileCreateFlags.REPLACE_DESTINATION, None)
                stream.write("#EXTM3U\n".encode("utf-8"))
                for uri in uris:
                    string = "%s\n" % uri
                    stream.write(string.encode("utf-8"))
                stream.close()
        except:
            pass

    def __on_populated(self, playlists_widget):
        """
            Update jump button on populated
            @param playlists_widget as PlaylistsWidget
        """
        self.__update_jump_button()

    def __on_playlist_track_added(self, playlists, playlist_id, uri, pos):
        """
            Update tracks widgets
            @param playlists as Playlists
            @param playlist id as int
            @param uri as str
            @param pos as int
        """
        if len(self.__playlist_ids) == 1 and\
                playlist_id in self.__playlist_ids:
            track_id = App().tracks.get_id_by_uri(uri)
            self.__playlists_widget.append(track_id)

    def __on_playlist_track_removed(self, playlists, playlist_id, uri, pos):
        """
            Update tracks widgets
            @param playlists as Playlists
            @param playlist id as int
            @param uri as str
            @param pos as int
        """
        if len(self.__playlist_ids) == 1 and\
                playlist_id in self.__playlist_ids:
            track_id = App().tracks.get_id_by_uri(uri)
            self.__playlists_widget.remove(track_id, pos)

    def __on_playlist_populated(self, widget):
        """
            Set duration on populated
            @param widget as PlaylistsWidget
        """
        self.__set_duration(widget.duration)

    def __on_orientation_changed(self, widget, orientation):
        """
            Show/Hide split button
            @param widget as Gtk.Widget
            @param orientation as Gtk.Orientation
        """
        if orientation == Gtk.Orientation.VERTICAL and (
                App().window.is_adaptive
                or self.__list_type & RowListType.POPOVER):
            self.__split_button.hide()
        else:
            self.__split_button.show()
Example #11
0
class PlaylistsView(View):
    """
        Show playlist tracks
    """
    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self, True)
        self.__tracks = []
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = Lp().playlists.connect("playlist-add",
                                                   self.__on_playlist_add)
        self.__signal_id2 = Lp().playlists.connect("playlist-del",
                                                   self.__on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/PlaylistView.ui")
        self.__duration_label = builder.get_object("duration")
        builder.get_object("title").set_label(", ".join(
            Lp().playlists.get_names(playlist_ids)))

        self.__edit_button = builder.get_object("edit-button")
        self.__jump_button = builder.get_object("jump-button")
        split_button = builder.get_object("split-button")
        if editable:
            split_button.set_active(not Lp().settings.get_value("split-view"))
        else:
            split_button.hide()

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] not in [Type.LOVED,
                                                           Type.NOPARTY]) or\
                not editable:
            self.__edit_button.hide()

        self.__playlists_widget = PlaylistsWidget(playlist_ids)
        self.__playlists_widget.set_filter_func(self._filter_func)
        self.__playlists_widget.show()
        self.add(builder.get_object("widget"))
        self._viewport.add(self.__playlists_widget)
        self._scrolled.set_property("expand", True)
        self.add(self._scrolled)
        # Connect signals after ui init
        # "split-button" will emit a signal otherwise
        builder.connect_signals(self)
        # No duration for non user playlists
        # FIXME
        if playlist_ids[0] > 0:
            self.__set_duration()

    def populate(self, tracks):
        """
            Populate view with tracks from playlist
            Thread safe
        """
        # We are looking for middle
        # Ponderate with this:
        # Tracks with cover == 2
        # Tracks without cover == 1
        prev_album_id = None
        heights = {}
        total = 0
        idx = 0
        for track_id in tracks:
            track = Track(track_id)
            if track.album_id != prev_album_id:
                heights[idx] = 2
                total += 2
            else:
                heights[idx] = 1
                total += 1
            prev_album_id = track.album_id
            idx += 1
        half = int(total / 2 + 0.5)
        mid_tracks = 1
        count = 0
        for height in heights.values():
            count += height
            if count >= half:
                break
            mid_tracks += 1
        self.__tracks = tracks
        self.__update_jump_button()
        self.__playlists_widget.populate_list_left(tracks[:mid_tracks], 1)
        self.__playlists_widget.populate_list_right(tracks[mid_tracks:],
                                                    mid_tracks + 1)

    def get_ids(self):
        """
            Return playlist ids
            @return id as [int]
        """
        return self.__playlist_ids

    def stop(self):
        """
            Stop populating
        """
        self.__playlists_widget.stop()

#######################
# PROTECTED           #
#######################

    def _get_children(self):
        """
            Return view children
        """
        return [self.__playlists_widget]

    def _on_search_changed(self, entry):
        """
            Update filter
            @param entry as Gtk.Entry
        """
        self._filter = entry.get_text()
        for box in self.__playlists_widget.boxes:
            box.invalidate_filter()

    def _on_destroy(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        View._on_destroy(self, widget)
        if self.__signal_id1:
            Lp().playlists.disconnect(self.__signal_id1)
            self.__signal_id1 = None
        if self.__signal_id2:
            Lp().playlists.disconnect(self.__signal_id2)
            self.__signal_id2 = None

    def _on_split_button_toggled(self, button):
        """
            Split/Unsplit view
        """
        Lp().settings.set_value("split-view",
                                GLib.Variant("b", not button.get_active()))
        self.__playlists_widget.update_allocation()

    def _on_jump_button_clicked(self, button):
        """
            Scroll to current track
            @param button as Gtk.Button
        """
        y = self.__playlists_widget.get_current_ordinate()
        if y is not None:
            self._scrolled.get_vadjustment().set_value(y)

    def _on_edit_button_clicked(self, button):
        """
            Edit playlist
            @param button as Gtk.Button
        """
        Lp().window.show_playlist_editor(self.__playlist_ids[0])

    def _on_current_changed(self, player):
        """
            Current song changed, update playing button
            @param player as Player
        """
        View._on_current_changed(self, player)
        self.__update_jump_button()


#######################
# PRIVATE             #
#######################

    def __set_duration(self):
        """
            Set playlist duration
        """
        duration = 0
        for playlist_id in self.__playlist_ids:
            duration += Lp().playlists.get_duration(playlist_id)

        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                self.__duration_label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                self.__duration_label.set_text(_("%s h") % hours)
        else:
            self.__duration_label.set_text(_("%s m") % mins)

    def __update_jump_button(self):
        """
            Update jump button status
        """
        if Lp().player.current_track.id in self.__tracks:
            self.__jump_button.set_sensitive(True)
            artists = ", ".join(Lp().player.current_track.artists)
            self.__jump_button.set_tooltip_markup(
                "<b>%s</b>\n%s" %
                (GLib.markup_escape_text(artists),
                 GLib.markup_escape_text(Lp().player.current_track.name)))
        else:
            self.__jump_button.set_sensitive(False)
            self.__jump_button.set_tooltip_text("")

    def __on_playlist_add(self, manager, playlist_id, track_id, pos):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self.__playlist_ids:
            self.__playlists_widget.insert(track_id, pos)

    def __on_playlist_del(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self.__playlist_ids:
            self.__playlists_widget.remove(track_id)
Example #12
0
class PlaylistsView(View):
    """
        Show playlist tracks
    """

    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self)
        self._tracks = []
        self._playlist_ids = playlist_ids
        self._signal_id1 = Lp().playlists.connect('playlist-add',
                                                  self._on_playlist_add)
        self._signal_id2 = Lp().playlists.connect('playlist-del',
                                                  self._on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/PlaylistView.ui')
        builder.connect_signals(self)

        name = ""
        for playlist_id in playlist_ids:
            if playlist_id == Type.POPULARS:
                name += _("Popular tracks")+", "
            elif playlist_id == Type.RECENTS:
                name += _("Recently played")+", "
            elif playlist_id == Type.NEVER:
                name += _("Never played")+", "
            elif playlist_id == Type.RANDOMS:
                name += _("Random tracks")+", "
            elif playlist_id == Type.SEARCH:
                name += _("Search")+", "
            else:
                name += Lp().playlists.get_name(playlist_id)+", "
        builder.get_object('title').set_label(name[:-2])

        self._edit_button = builder.get_object('edit-button')
        self._jump_button = builder.get_object('jump-button')

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] != Type.LOVED) or\
                not editable:
            self._edit_button.hide()
        self._title = builder.get_object('title')

        self._playlists_widget = PlaylistsWidget(playlist_ids)
        self._playlists_widget.connect('populated', self._on_populated)
        self._playlists_widget.show()
        self.add(builder.get_object('widget'))
        self._viewport.add(self._playlists_widget)
        self._scrolled.set_property('expand', True)
        self.add(self._scrolled)

    def populate(self, tracks):
        """
            Populate view with tracks from playlist
            Thread safe
        """
        self._tracks = tracks
        mid_tracks = int(0.5+len(tracks)/2)
        self._playlists_widget.populate_list_left(tracks[:mid_tracks],
                                                  1)
        self._playlists_widget.populate_list_right(tracks[mid_tracks:],
                                                   mid_tracks + 1)

    def get_ids(self):
        """
            Return playlist ids
            @return id as [int]
        """
        return self._playlist_ids

    def stop(self):
        """
            Stop populating
        """
        self._playlists_widget.stop()

#######################
# PRIVATE             #
#######################
    def _get_children(self):
        """
            Return view children
        """
        return [self._playlists_widget]

    def _update_jump_button(self):
        """
            Update jump button status
        """
        if Lp().player.current_track.id in self._tracks:
            self._jump_button.set_sensitive(True)
            self._jump_button.set_tooltip_markup(
             "<b>%s</b>\n%s" % (escape(Lp().player.current_track.artist_names),
                                escape(Lp().player.current_track.name)))
        else:
            self._jump_button.set_sensitive(False)
            self._jump_button.set_tooltip_text('')

    def _on_playlist_add(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self._playlist_ids:
            self._playlists_widget.append(track_id)

    def _on_playlist_del(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self._playlist_ids:
            self._playlists_widget.remove(track_id)

    def _on_populated(self, widget):
        """
            Show current track
            @param widget as Gtk.Widget
        """
        self._update_jump_button()

    def _on_destroy(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        View._on_destroy(self, widget)
        if self._signal_id1:
            Lp().playlists.disconnect(self._signal_id1)
            self._signal_id1 = None
        if self._signal_id2:
            Lp().playlists.disconnect(self._signal_id2)
            self._signal_id2 = None

    def _on_jump_button_clicked(self, button):
        """
            Scroll to current track
            @param button as Gtk.Button
        """
        y = self._playlists_widget.get_current_ordinate()
        if y is not None:
            self._scrolled.get_vadjustment().set_value(y)

    def _on_edit_button_clicked(self, button):
        """
            Edit playlist
            @param button as Gtk.Button
        """
        Lp().window.show_playlist_editor(self._playlist_ids[0])

    def _on_current_changed(self, player):
        """
            Current song changed, update playing button
            @param player as Player
        """
        View._on_current_changed(self, player)
        self._update_jump_button()
Example #13
0
class PlaylistsView(View):
    """
        Show playlist tracks
    """

    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self)
        self._tracks = []
        self._playlist_ids = playlist_ids
        self._signal_id1 = Lp().playlists.connect('playlist-add',
                                                  self._on_playlist_add)
        self._signal_id2 = Lp().playlists.connect('playlist-del',
                                                  self._on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/PlaylistView.ui')
        builder.connect_signals(self)

        builder.get_object('title').set_label(
                             ", ".join(Lp().playlists.get_names(playlist_ids)))

        self._edit_button = builder.get_object('edit-button')
        self._jump_button = builder.get_object('jump-button')

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] != Type.LOVED) or\
                not editable:
            self._edit_button.hide()

        self._playlists_widget = PlaylistsWidget(playlist_ids)
        self._playlists_widget.show()
        self.add(builder.get_object('widget'))
        self._viewport.add(self._playlists_widget)
        self._scrolled.set_property('expand', True)
        self.add(self._scrolled)

    def populate(self, tracks):
        """
            Populate view with tracks from playlist
            Thread safe
        """
        self._tracks = tracks
        self._update_jump_button()
        mid_tracks = int(0.5+len(tracks)/2)
        self._playlists_widget.populate_list_left(tracks[:mid_tracks],
                                                  1)
        self._playlists_widget.populate_list_right(tracks[mid_tracks:],
                                                   mid_tracks + 1)

    def get_ids(self):
        """
            Return playlist ids
            @return id as [int]
        """
        return self._playlist_ids

    def stop(self):
        """
            Stop populating
        """
        self._playlists_widget.stop()

#######################
# PRIVATE             #
#######################
    def _get_children(self):
        """
            Return view children
        """
        return [self._playlists_widget]

    def _update_jump_button(self):
        """
            Update jump button status
        """
        if Lp().player.current_track.id in self._tracks:
            self._jump_button.set_sensitive(True)
            self._jump_button.set_tooltip_markup(
             "<b>%s</b>\n%s" % (escape(Lp().player.current_track.artists),
                                escape(Lp().player.current_track.name)))
        else:
            self._jump_button.set_sensitive(False)
            self._jump_button.set_tooltip_text('')

    def _on_playlist_add(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self._playlist_ids:
            self._playlists_widget.append(track_id)

    def _on_playlist_del(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self._playlist_ids:
            self._playlists_widget.remove(track_id)

    def _on_populated(self, widget):
        """
            Show current track
            @param widget as LazyLoadingView
        """
        self._update_jump_button()

    def _on_destroy(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        View._on_destroy(self, widget)
        if self._signal_id1:
            Lp().playlists.disconnect(self._signal_id1)
            self._signal_id1 = None
        if self._signal_id2:
            Lp().playlists.disconnect(self._signal_id2)
            self._signal_id2 = None

    def _on_jump_button_clicked(self, button):
        """
            Scroll to current track
            @param button as Gtk.Button
        """
        y = self._playlists_widget.get_current_ordinate()
        if y is not None:
            self._scrolled.get_vadjustment().set_value(y)

    def _on_edit_button_clicked(self, button):
        """
            Edit playlist
            @param button as Gtk.Button
        """
        Lp().window.show_playlist_editor(self._playlist_ids[0])

    def _on_current_changed(self, player):
        """
            Current song changed, update playing button
            @param player as Player
        """
        View._on_current_changed(self, player)
        self._update_jump_button()
Example #14
0
class PlaylistsView(View):
    """
        Show playlist tracks
    """

    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self)
        self._tracks = []
        self._playlist_ids = playlist_ids
        self._signal_id1 = Lp().playlists.connect("playlist-add", self._on_playlist_add)
        self._signal_id2 = Lp().playlists.connect("playlist-del", self._on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/PlaylistView.ui")
        builder.connect_signals(self)

        builder.get_object("title").set_label(", ".join(Lp().playlists.get_names(playlist_ids)))

        self._edit_button = builder.get_object("edit-button")
        self._jump_button = builder.get_object("jump-button")

        if len(playlist_ids) > 1 or (playlist_ids[0] < 0 and playlist_ids[0] != Type.LOVED) or not editable:
            self._edit_button.hide()

        self._playlists_widget = PlaylistsWidget(playlist_ids)
        self._playlists_widget.show()
        self.add(builder.get_object("widget"))
        self._viewport.add(self._playlists_widget)
        self._scrolled.set_property("expand", True)
        self.add(self._scrolled)

    def populate(self, tracks):
        """
            Populate view with tracks from playlist
            Thread safe
        """
        # We are looking for middle
        # Ponderate with this:
        # Tracks with cover == 2
        # Tracks without cover == 1
        prev_album_id = None
        heights = {}
        total = 0
        idx = 0
        for track_id in tracks:
            track = Track(track_id)
            if track.album_id != prev_album_id:
                heights[idx] = 2
                total += 2
            else:
                heights[idx] = 1
                total += 1
            prev_album_id = track.album_id
            idx += 1
        half = int(total / 2 + 0.5)
        mid_tracks = 1
        count = 0
        for height in heights.values():
            count += height
            if count >= half:
                break
            mid_tracks += 1
        self._tracks = tracks
        self._update_jump_button()
        self._playlists_widget.populate_list_left(tracks[:mid_tracks], 1)
        self._playlists_widget.populate_list_right(tracks[mid_tracks:], mid_tracks + 1)

    def get_ids(self):
        """
            Return playlist ids
            @return id as [int]
        """
        return self._playlist_ids

    def stop(self):
        """
            Stop populating
        """
        self._playlists_widget.stop()

    #######################
    # PRIVATE             #
    #######################
    def _get_children(self):
        """
            Return view children
        """
        return [self._playlists_widget]

    def _update_jump_button(self):
        """
            Update jump button status
        """
        if Lp().player.current_track.id in self._tracks:
            self._jump_button.set_sensitive(True)
            artists = ", ".join(Lp().player.current_track.artists)
            self._jump_button.set_tooltip_markup(
                "<b>%s</b>\n%s" % (escape(artists), escape(Lp().player.current_track.name))
            )
        else:
            self._jump_button.set_sensitive(False)
            self._jump_button.set_tooltip_text("")

    def _on_playlist_add(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self._playlist_ids:
            self._playlists_widget.append(track_id)

    def _on_playlist_del(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self._playlist_ids:
            self._playlists_widget.remove(track_id)

    def _on_destroy(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        View._on_destroy(self, widget)
        if self._signal_id1:
            Lp().playlists.disconnect(self._signal_id1)
            self._signal_id1 = None
        if self._signal_id2:
            Lp().playlists.disconnect(self._signal_id2)
            self._signal_id2 = None

    def _on_jump_button_clicked(self, button):
        """
            Scroll to current track
            @param button as Gtk.Button
        """
        y = self._playlists_widget.get_current_ordinate()
        if y is not None:
            self._scrolled.get_vadjustment().set_value(y)

    def _on_edit_button_clicked(self, button):
        """
            Edit playlist
            @param button as Gtk.Button
        """
        Lp().window.show_playlist_editor(self._playlist_ids[0])

    def _on_current_changed(self, player):
        """
            Current song changed, update playing button
            @param player as Player
        """
        View._on_current_changed(self, player)
        self._update_jump_button()
Example #15
0
class PlaylistsView(View):
    """
        Show playlist tracks
    """

    def __init__(self, playlist_ids, editable=True):
        """
            Init PlaylistView
            @parma playlist ids as [int]
            @param editable as bool
        """
        View.__init__(self, True)
        self.__tracks = []
        self.__playlist_ids = playlist_ids
        self.__signal_id1 = Lp().playlists.connect('playlist-add',
                                                   self.__on_playlist_add)
        self.__signal_id2 = Lp().playlists.connect('playlist-del',
                                                   self.__on_playlist_del)

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/PlaylistView.ui')

        builder.get_object('title').set_label(
                             ", ".join(Lp().playlists.get_names(playlist_ids)))

        self.__edit_button = builder.get_object('edit-button')
        self.__jump_button = builder.get_object('jump-button')
        split_button = builder.get_object('split-button')
        if editable:
            split_button.set_active(not Lp().settings.get_value('split-view'))
        else:
            split_button.hide()

        if len(playlist_ids) > 1 or (
           playlist_ids[0] < 0 and playlist_ids[0] != Type.LOVED) or\
                not editable:
            self.__edit_button.hide()

        self.__playlists_widget = PlaylistsWidget(playlist_ids)
        self.__playlists_widget.set_filter_func(self._filter_func)
        self.__playlists_widget.show()
        self.add(builder.get_object('widget'))
        self._viewport.add(self.__playlists_widget)
        self._scrolled.set_property('expand', True)
        self.add(self._scrolled)
        # Connect signals after ui init
        # 'split-button' will emit a signal otherwise
        builder.connect_signals(self)

    def populate(self, tracks):
        """
            Populate view with tracks from playlist
            Thread safe
        """
        # We are looking for middle
        # Ponderate with this:
        # Tracks with cover == 2
        # Tracks without cover == 1
        prev_album_id = None
        heights = {}
        total = 0
        idx = 0
        for track_id in tracks:
            track = Track(track_id)
            if track.album_id != prev_album_id:
                heights[idx] = 2
                total += 2
            else:
                heights[idx] = 1
                total += 1
            prev_album_id = track.album_id
            idx += 1
        half = int(total / 2 + 0.5)
        mid_tracks = 1
        count = 0
        for height in heights.values():
            count += height
            if count >= half:
                break
            mid_tracks += 1
        self.__tracks = tracks
        self.__update_jump_button()
        self.__playlists_widget.populate_list_left(tracks[:mid_tracks],
                                                   1)
        self.__playlists_widget.populate_list_right(tracks[mid_tracks:],
                                                    mid_tracks + 1)

    def get_ids(self):
        """
            Return playlist ids
            @return id as [int]
        """
        return self.__playlist_ids

    def stop(self):
        """
            Stop populating
        """
        self.__playlists_widget.stop()

#######################
# PROTECTED           #
#######################
    def _get_children(self):
        """
            Return view children
        """
        return [self.__playlists_widget]

    def _on_search_changed(self, entry):
        """
            Update filter
            @param entry as Gtk.Entry
        """
        self._filter = entry.get_text()
        for box in self.__playlists_widget.boxes:
            box.invalidate_filter()

    def _on_destroy(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        View._on_destroy(self, widget)
        if self.__signal_id1:
            Lp().playlists.disconnect(self.__signal_id1)
            self.__signal_id1 = None
        if self.__signal_id2:
            Lp().playlists.disconnect(self.__signal_id2)
            self.__signal_id2 = None

    def _on_split_button_toggled(self, button):
        """
            Split/Unsplit view
        """
        Lp().settings.set_value('split-view',
                                GLib.Variant('b', not button.get_active()))
        self.__playlists_widget.update_allocation()

    def _on_jump_button_clicked(self, button):
        """
            Scroll to current track
            @param button as Gtk.Button
        """
        y = self.__playlists_widget.get_current_ordinate()
        if y is not None:
            self._scrolled.get_vadjustment().set_value(y)

    def _on_edit_button_clicked(self, button):
        """
            Edit playlist
            @param button as Gtk.Button
        """
        Lp().window.show_playlist_editor(self.__playlist_ids[0])

    def _on_current_changed(self, player):
        """
            Current song changed, update playing button
            @param player as Player
        """
        View._on_current_changed(self, player)
        self.__update_jump_button()

#######################
# PRIVATE             #
#######################
    def __update_jump_button(self):
        """
            Update jump button status
        """
        if Lp().player.current_track.id in self.__tracks:
            self.__jump_button.set_sensitive(True)
            artists = ", ".join(Lp().player.current_track.artists)
            self.__jump_button.set_tooltip_markup(
             "<b>%s</b>\n%s" % (GLib.markup_escape_text(artists),
                                GLib.markup_escape_text(
                                              Lp().player.current_track.name)))
        else:
            self.__jump_button.set_sensitive(False)
            self.__jump_button.set_tooltip_text('')

    def __on_playlist_add(self, manager, playlist_id, track_id, pos):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self.__playlist_ids:
            self.__playlists_widget.insert(track_id, pos)

    def __on_playlist_del(self, manager, playlist_id, track_id):
        """
            Update tracks widgets
            @param manager as PlaylistsManager
            @param playlist id as int
            @param track id as int
        """
        if playlist_id in self.__playlist_ids:
            self.__playlists_widget.remove(track_id)