Example #1
0
    def __init__(self, name, radios_manager):
        """
            Init Popover
            @param name as string
            @param radios_manager as RadiosManager
        """
        Gtk.Popover.__init__(self)
        self.connect("map", self.__on_map)
        self.connect("unmap", self.__on_unmap)
        self.__name = name
        self.__radios_manager = radios_manager
        self.__start = 0
        self.__orig_pixbufs = {}

        self.__stack = Gtk.Stack()
        self.__stack.set_transition_duration(1000)
        self.__stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self.__stack.show()

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

        self.__view = Gtk.FlowBox()
        self.__view.set_selection_mode(Gtk.SelectionMode.NONE)
        self.__view.connect("child-activated", self.__on_activate)
        self.__view.set_max_children_per_line(100)
        self.__view.set_property("row-spacing", 10)
        self.__view.show()

        builder.get_object("viewport").add(self.__view)

        self.__name_entry = builder.get_object("name")
        self.__uri_entry = builder.get_object("uri")
        self.__btn_add_modify = builder.get_object("btn_add_modify")
        self.__spinner = builder.get_object("spinner")
        self.__stack.add_named(builder.get_object("spinner-grid"), "spinner")
        self.__stack.add_named(builder.get_object("notfound"), "notfound")
        self.__stack.add_named(builder.get_object("logo"), "logo")
        self.__stack.add_named(builder.get_object("widget"), "widget")
        self.__stack.set_visible_child_name("widget")
        self.add(self.__stack)

        track = Track()
        track.set_radio(name, "")
        rating = RatingWidget(track)
        rating.show()
        builder.get_object("widget").attach(rating, 0, 2, 2, 1)

        if self.__name == "":
            # Translators: radio context
            builder.get_object("btn_add_modify").set_label(_("Add"))
        else:
            # Translators: radio context
            builder.get_object("btn_add_modify").set_label(_("Modify"))
            builder.get_object("btn_delete").show()
            self.__name_entry.set_text(self.__name)
            url = self.__radios_manager.get_url(self.__name)
            if url:
                self.__uri_entry.set_text(url)
Example #2
0
    def __init__(self, name, radios_manager):
        """
            Init Popover
            @param name as string
            @param radios_manager as RadiosManager
        """
        Gtk.Popover.__init__(self)
        self.connect('map', self.__on_map)
        self.connect('unmap', self.__on_unmap)
        self.__name = name
        self.__radios_manager = radios_manager
        self.__start = 0
        self.__orig_pixbufs = {}

        self.__stack = Gtk.Stack()
        self.__stack.set_transition_duration(1000)
        self.__stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self.__stack.show()

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

        self.__view = Gtk.FlowBox()
        self.__view.set_selection_mode(Gtk.SelectionMode.NONE)
        self.__view.connect('child-activated', self.__on_activate)
        self.__view.set_max_children_per_line(100)
        self.__view.set_property('row-spacing', 10)
        self.__view.show()

        builder.get_object('viewport').add(self.__view)

        self.__name_entry = builder.get_object('name')
        self.__uri_entry = builder.get_object('uri')
        self.__btn_add_modify = builder.get_object('btn_add_modify')
        self.__spinner = builder.get_object('spinner')
        self.__stack.add_named(builder.get_object('spinner-grid'), 'spinner')
        self.__stack.add_named(builder.get_object('notfound'), 'notfound')
        self.__stack.add_named(builder.get_object('logo'), 'logo')
        self.__stack.add_named(builder.get_object('widget'), 'widget')
        self.__stack.set_visible_child_name('widget')
        self.add(self.__stack)

        track = Track()
        track.set_radio(name, '')
        rating = RatingWidget(track)
        rating.show()
        builder.get_object('widget').attach(rating, 0, 2, 2, 1)

        if self.__name == '':
            # Translators: radio context
            builder.get_object('btn_add_modify').set_label(_("Add"))
        else:
            # Translators: radio context
            builder.get_object('btn_add_modify').set_label(_("Modify"))
            builder.get_object('btn_delete').show()
            self.__name_entry.set_text(self.__name)
            url = self.__radios_manager.get_url(self.__name)
            if url:
                self.__uri_entry.set_text(url)
Example #3
0
    def __init__(self, name, radios_manager):
        """
            Init Popover
            @param name as string
            @param radios_manager as RadiosManager
        """
        Gtk.Popover.__init__(self)
        self.connect('map', self._on_map)
        self.connect('unmap', self._on_unmap)
        self._name = name
        self._radios_manager = radios_manager
        self._start = 0
        self._orig_pixbufs = {}

        self._stack = Gtk.Stack()
        self._stack.set_transition_duration(1000)
        self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self._stack.show()

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

        self._view = Gtk.FlowBox()
        self._view.set_selection_mode(Gtk.SelectionMode.NONE)
        self._view.connect('child-activated', self._on_activate)
        self._view.set_max_children_per_line(100)
        self._view.set_property('row-spacing', 10)
        self._view.show()

        builder.get_object('viewport').add(self._view)

        self._name_entry = builder.get_object('name')
        self._uri_entry = builder.get_object('uri')
        self._btn_add_modify = builder.get_object('btn_add_modify')
        self._spinner = builder.get_object('spinner')
        self._stack.add_named(self._spinner, 'spinner')
        self._stack.add_named(builder.get_object('notfound'), 'notfound')
        self._stack.add_named(builder.get_object('logo'), 'logo')
        self._stack.add_named(builder.get_object('widget'), 'widget')
        self._stack.set_visible_child_name('widget')
        self.add(self._stack)

        track = Track()
        track.set_radio(name, '')
        rating = RatingWidget(track)
        rating.show()
        builder.get_object('widget').attach(rating, 0, 2, 2, 1)

        if self._name == '':
            builder.get_object('btn_add_modify').set_label(_("Add"))
        else:
            builder.get_object('btn_add_modify').set_label(_("Modify"))
            builder.get_object('btn_delete').show()
            self._name_entry.set_text(self._name)
            url = self._radios_manager.get_url(self._name)
            if url:
                self._uri_entry.set_text(url)
Example #4
0
    def __init__(self, name, radios_manager):
        """
            Init Popover
            @param name as string
            @param radios_manager as RadiosManager
        """
        Gtk.Popover.__init__(self)
        self.connect("map", self._on_map)
        self.connect("unmap", self._on_unmap)
        self._name = name
        self._radios_manager = radios_manager
        self._start = 0
        self._orig_pixbufs = {}

        self._stack = Gtk.Stack()
        self._stack.set_transition_duration(1000)
        self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self._stack.show()

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

        self._view = Gtk.FlowBox()
        self._view.set_selection_mode(Gtk.SelectionMode.NONE)
        self._view.connect("child-activated", self._on_activate)
        self._view.set_max_children_per_line(100)
        self._view.set_property("row-spacing", 10)
        self._view.show()

        builder.get_object("viewport").add(self._view)

        self._name_entry = builder.get_object("name")
        self._uri_entry = builder.get_object("uri")
        self._btn_add_modify = builder.get_object("btn_add_modify")
        self._spinner = builder.get_object("spinner")
        self._stack.add_named(builder.get_object("spinner-grid"), "spinner")
        self._stack.add_named(builder.get_object("notfound"), "notfound")
        self._stack.add_named(builder.get_object("logo"), "logo")
        self._stack.add_named(builder.get_object("widget"), "widget")
        self._stack.set_visible_child_name("widget")
        self.add(self._stack)

        track = Track()
        track.set_radio(name, "")
        rating = RatingWidget(track)
        rating.show()
        builder.get_object("widget").attach(rating, 0, 2, 2, 1)

        if self._name == "":
            builder.get_object("btn_add_modify").set_label(_("Add"))
        else:
            builder.get_object("btn_add_modify").set_label(_("Modify"))
            builder.get_object("btn_delete").show()
            self._name_entry.set_text(self._name)
            url = self._radios_manager.get_url(self._name)
            if url:
                self._uri_entry.set_text(url)
Example #5
0
    def _popup_menu(self, widget, xcoordinate=None, ycoordinate=None):
        """
            Popup menu for track
            @param widget as Gtk.Button
            @param xcoordinate as int (or None)
            @param ycoordinate as int (or None)
        """
        menu = TrackMenu(self._object_id, None)
        popover = Gtk.Popover.new_from_model(widget, menu)
        if xcoordinate is not None and ycoordinate is not None:
            rect = widget.get_allocation()
            rect.x = xcoordinate
            rect.y = ycoordinate
            rect.width = 1
            rect.height = 1
            popover.set_pointing_to(rect)

        rating = RatingWidget(self._object)
        rating.set_margin_top(5)
        rating.set_margin_bottom(5)
        rating.set_property('halign', Gtk.Align.START)
        rating.set_property('hexpand', True)
        rating.show()

        loved = LovedWidget(self._object_id)
        loved.set_margin_end(5)
        loved.set_margin_top(5)
        loved.set_margin_bottom(5)
        loved.set_property('halign', Gtk.Align.END)
        loved.set_property('hexpand', True)
        loved.show()

        # Hack to add two widgets in popover
        # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable)
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, 'main')
        stack.show_all()

        menu_widget = popover.get_child()
        menu_widget.reparent(grid)

        separator = Gtk.Separator()
        separator.show()

        grid.add(separator)
        hgrid = Gtk.Grid()
        hgrid.add(rating)
        hgrid.add(loved)
        hgrid.show()
        grid.add(hgrid)

        popover.add(stack)
        popover.connect('closed', self._on_closed)
        self.get_style_context().add_class('track-menu-selected')
        popover.show()
Example #6
0
    def _popup_menu(self, widget, xcoordinate=None, ycoordinate=None):
        """
            Popup menu for track
            @param widget as Gtk.Button
            @param xcoordinate as int (or None)
            @param ycoordinate as int (or None)
        """
        menu = TrackMenu(self._object_id, None)
        popover = Gtk.Popover.new_from_model(widget, menu)
        if xcoordinate is not None and ycoordinate is not None:
            rect = widget.get_allocation()
            rect.x = xcoordinate
            rect.y = ycoordinate
            rect.width = rect.height = 1
            popover.set_pointing_to(rect)

        rating = RatingWidget(self._object)
        rating.set_margin_top(5)
        rating.set_margin_bottom(5)
        rating.set_property('halign', Gtk.Align.START)
        rating.set_property('hexpand', True)
        rating.show()

        loved = LovedWidget(self._object_id)
        loved.set_margin_end(5)
        loved.set_margin_top(5)
        loved.set_margin_bottom(5)
        loved.set_property('halign', Gtk.Align.END)
        loved.set_property('hexpand', True)
        loved.show()

        # Hack to add two widgets in popover
        # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable)
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, 'main')
        stack.show_all()

        menu_widget = popover.get_child()
        menu_widget.reparent(grid)

        separator = Gtk.Separator()
        separator.show()

        grid.add(separator)
        hgrid = Gtk.Grid()
        hgrid.add(rating)
        hgrid.add(loved)
        hgrid.show()
        grid.add(hgrid)

        popover.add(stack)
        popover.connect('closed', self._on_closed)
        self.get_style_context().add_class('track-menu-selected')
        popover.show()
Example #7
0
 def _on_infobox_clicked(self, eventbox, event):
     """
         Pop albums from current artistleft click
         Show playlist menu on right
         @param eventbox as Gtk.EventBox
         @param event as Gdk.Event
     """
     if Lp.player.current_track.id == Type.EXTERNALS:
         expopover = ExternalsPopover()
         expopover.set_relative_to(eventbox)
         expopover.populate()
         expopover.show()
     elif Lp.player.current_track.id is not None:
         if event.button == 1:
             if Lp.player.current_track.id == Type.RADIOS:
                 self._pop_tunein.populate()
                 self._pop_tunein.show()
             else:
                 self._pop_infos.show()
         elif Lp.player.current_track.id >= 0:
             menu = PopToolbarMenu(Lp.player.current_track.id, None)
             popover = Gtk.Popover.new_from_model(eventbox, menu)
             rating = RatingWidget(Lp.player.current_track)
             rating.set_margin_top(5)
             rating.set_margin_bottom(5)
             rating.set_property('halign', Gtk.Align.START)
             rating.set_property('hexpand', True)
             rating.show()
             loved = LovedWidget(Lp.player.current_track.id)
             loved.set_margin_end(5)
             loved.set_margin_top(5)
             loved.set_margin_bottom(5)
             loved.set_property('halign', Gtk.Align.END)
             loved.set_property('hexpand', True)
             loved.show()
             # Hack to add two widgets in popover
             # Use a Gtk.PopoverMenu later
             # (GTK>3.16 available on Debian stable)
             stack = Gtk.Stack()
             grid = Gtk.Grid()
             grid.set_orientation(Gtk.Orientation.VERTICAL)
             stack.add_named(grid, 'main')
             stack.show_all()
             menu_widget = popover.get_child()
             menu_widget.reparent(grid)
             separator = Gtk.Separator()
             separator.show()
             grid.add(separator)
             hgrid = Gtk.Grid()
             hgrid.add(rating)
             hgrid.add(loved)
             hgrid.show()
             grid.add(hgrid)
             popover.add(stack)
             popover.show()
         return True
Example #8
0
    def __init__(self, radio_id, radios):
        """
            Init Popover
            @param radio_id as int
            @param radios as Radios
        """
        Popover.__init__(self)
        self.connect("map", self.__on_map)
        self.__radio_id = radio_id
        self.__radios = radios
        self.__start = 0
        self.__orig_pixbufs = {}
        self.__cancellable = Gio.Cancellable()

        self.__stack = Gtk.Stack()
        self.__stack.set_transition_duration(1000)
        self.__stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self.__stack.show()

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

        self.__view = Gtk.FlowBox()
        self.__view.set_selection_mode(Gtk.SelectionMode.NONE)
        self.__view.connect("child-activated", self.__on_activate)
        self.__view.set_max_children_per_line(100)
        self.__view.set_property("row-spacing", 10)
        self.__view.show()

        builder.get_object("viewport").add(self.__view)

        self.__name_entry = builder.get_object("name")
        self.__uri_entry = builder.get_object("uri")
        self.__image_button = builder.get_object("image_button")
        self.__save_button = builder.get_object("save_button")
        self.__spinner = builder.get_object("spinner")
        self.__stack.add_named(builder.get_object("spinner-grid"), "spinner")
        self.__stack.add_named(builder.get_object("notfound"), "notfound")
        self.__stack.add_named(builder.get_object("logo"), "logo")
        self.__stack.add_named(builder.get_object("widget"), "widget")
        self.__stack.set_visible_child_name("widget")
        self.add(self.__stack)

        track = Track()
        if radio_id is not None:
            track.set_radio_id(radio_id)
            rating = RatingWidget(track)
            rating.show()
            builder.get_object("widget").attach(rating, 0, 2, 2, 1)
            builder.get_object("delete_button").show()
            self.__name_entry.set_text(radios.get_name(radio_id))
            uri = self.__radios.get_uri(radio_id)
            if uri:
                self.__uri_entry.set_text(uri)
Example #9
0
    def __init__(self, track, menu):
        """
            Init widget
            @param track as Track
            @param menu as Gio.Menu
        """
        Popover.__init__(self)
        if menu is not None:
            self.bind_model(menu, None)

        if track.year is not None:
            year_label = Gtk.Label()
            year_label.set_text(str(track.year))
            dt = GLib.DateTime.new_from_unix_local(track.timestamp)
            year_label.set_tooltip_text(dt.format(_("%Y-%m-%d")))
            year_label.set_margin_end(5)
            year_label.get_style_context().add_class("dim-label")
            year_label.set_property("halign", Gtk.Align.END)
            year_label.set_property("hexpand", True)
            year_label.show()

        # Hack to add two widgets in popover
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, "main")
        stack.show_all()

        menu_widget = self.get_child()
        if menu_widget is not None:
            self.remove(menu_widget)
            grid.add(menu_widget)

        hgrid = Gtk.Grid()
        hgrid.get_style_context().add_class("popover-rating-loved-grid")
        rating = RatingWidget(track)
        rating.set_property("halign", Gtk.Align.START)
        rating.set_margin_end(10)
        rating.show()

        loved = LovedWidget(track)
        loved.set_property("halign", Gtk.Align.START)
        loved.set_property("hexpand", True)
        loved.show()

        hgrid.add(rating)
        hgrid.add(loved)

        if track.year is not None:
            hgrid.add(year_label)
        hgrid.show()

        grid.add(hgrid)
        self.add(stack)
Example #10
0
    def __init__(self, object, button):
        """
            Init widget
            @param object as Track/Album
            @param button as Gtk.Button
        """
        Gtk.Grid.__init__(self)
        self.__object = object
        self.__button = button

        # Check portal for tag editor
        dbus_helper = DBusHelper()
        dbus_helper.call("CanLaunchTagEditor", None,
                         self.__on_can_launch_tag_editor, None)
        self.__edit = HoverWidget("document-properties-symbolic",
                                  self.__edit_tags)
        self.__edit.set_tooltip_text(_("Modify information"))
        self.__edit.set_margin_end(10)
        self.add(self.__edit)

        playlist = HoverWidget("view-list-symbolic",
                               self.__show_playlist_manager)
        playlist.set_tooltip_text(_("Add to playlist"))
        playlist.show()
        self.add(playlist)

        if isinstance(self.__object, Album):
            if Lp().player.album_in_queue(self.__object):
                queue = HoverWidget("list-remove-symbolic",
                                    self.__add_to_queue)
                queue.set_tooltip_text(_("Remove from queue"))
            else:
                queue = HoverWidget("list-add-symbolic", self.__add_to_queue)
                queue.set_tooltip_text(_("Add to queue"))
            queue.set_margin_start(10)
            queue.show()
            self.add(queue)
        else:
            rating = RatingWidget(object)
            rating.set_margin_top(5)
            rating.set_margin_end(10)
            rating.set_margin_bottom(5)
            rating.set_property("halign", Gtk.Align.END)
            rating.set_property("hexpand", True)
            rating.show()

            loved = LovedWidget(object)
            loved.set_margin_end(5)
            loved.set_margin_top(5)
            loved.set_margin_bottom(5)
            loved.show()

            self.add(rating)
            self.add(loved)
Example #11
0
    def __init__(self, object_id, menu):
        """
            Init widget
            @param object id as int
            @param menu as Gio.Menu
        """
        Gtk.Popover.__init__(self)
        self.bind_model(menu, None)

        rating = RatingWidget(Track(object_id))
        rating.set_margin_top(5)
        rating.set_margin_bottom(5)
        rating.set_property('halign', Gtk.Align.START)
        rating.set_property('hexpand', True)
        rating.show()

        loved = LovedWidget(object_id)
        loved.set_margin_end(5)
        loved.set_margin_top(5)
        loved.set_margin_bottom(5)
        loved.set_property('halign', Gtk.Align.END)
        loved.set_property('hexpand', True)
        loved.show()

        # Hack to add two widgets in popover
        # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable)
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, 'main')
        stack.show_all()

        menu_widget = self.get_child()
        menu_widget.reparent(grid)

        separator = Gtk.Separator()
        separator.show()

        grid.add(separator)
        hgrid = Gtk.Grid()
        hgrid.add(rating)
        hgrid.add(loved)
        hgrid.show()
        grid.add(hgrid)
        self.add(stack)
Example #12
0
    def __init__(self, object_id, menu):
        """
            Init widget
            @param object id as int
            @param menu as Gio.Menu
        """
        Gtk.Popover.__init__(self)
        self.bind_model(menu, None)

        rating = RatingWidget(Track(object_id))
        rating.set_margin_top(5)
        rating.set_margin_bottom(5)
        rating.set_property('halign', Gtk.Align.START)
        rating.set_property('hexpand', True)
        rating.show()

        loved = LovedWidget(object_id)
        loved.set_margin_end(5)
        loved.set_margin_top(5)
        loved.set_margin_bottom(5)
        loved.set_property('halign', Gtk.Align.END)
        loved.set_property('hexpand', True)
        loved.show()

        # Hack to add two widgets in popover
        # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable)
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, 'main')
        stack.show_all()

        menu_widget = self.get_child()
        menu_widget.reparent(grid)

        separator = Gtk.Separator()
        separator.show()

        grid.add(separator)
        hgrid = Gtk.Grid()
        hgrid.add(rating)
        hgrid.add(loved)
        hgrid.show()
        grid.add(hgrid)
        self.add(stack)
Example #13
0
 def _on_infobox_clicked(self, eventbox, event):
     """
         Pop albums from current artistleft click
         Show playlist menu on right
         @param eventbox as Gtk.EventBox
         @param event as Gdk.Event
     """
     if Lp.player.current_track.id == Type.EXTERNALS:
         expopover = ExternalsPopover()
         expopover.set_relative_to(eventbox)
         expopover.populate()
         expopover.show()
     elif Lp.player.current_track.id is not None:
         if event.button == 1:
             if Lp.player.current_track.id == Type.RADIOS:
                 self._pop_tunein.populate()
                 self._pop_tunein.show()
             else:
                 self._pop_albums.populate()
                 self._pop_albums.show()
         elif Lp.player.current_track.id >= 0:
             menu = PopToolbarMenu(Lp.player.current_track.id, None)
             popover = Gtk.Popover.new_from_model(eventbox, menu)
             rating = RatingWidget(Lp.player.current_track)
             rating.set_property('margin_top', 5)
             rating.set_property('margin_bottom', 5)
             rating.show()
             # Hack to add two widgets in popover
             # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable)
             stack = Gtk.Stack()
             grid = Gtk.Grid()
             grid.set_orientation(Gtk.Orientation.VERTICAL)
             stack.add_named(grid, 'main')
             stack.show_all()
             menu_widget = popover.get_child()
             menu_widget.reparent(grid)
             separator = Gtk.Separator()
             separator.show()
             grid.add(separator)
             grid.add(rating)
             popover.add(stack)
             popover.show()
         return True
    def __init__(self, object, button):
        """
            Init widget
            @param object as Track/Album
            @param button as Gtk.Button
        """
        Gtk.EventBox.__init__(self)
        self.__object = object
        self.__button = button

        self.connect("button-release-event", self.__on_button_release_event)

        grid = Gtk.Grid()
        grid.show()

        if isinstance(object, Disc):
            play_button = Gtk.Button.new_from_icon_name(
                "media-playback-start-symbolic", Gtk.IconSize.BUTTON)
            play_button.connect("clicked", self.__on_play_button_clicked)
            play_button.get_style_context().add_class("dim-button")
            play_button.set_tooltip_text(_("Play"))
            play_button.set_margin_end(2)
            play_button.show()
            grid.add(play_button)
        else:
            edit_button = Gtk.Button.new_from_icon_name(
                "document-properties-symbolic", Gtk.IconSize.BUTTON)
            edit_button.connect("clicked", self.__on_edit_button_clicked)
            edit_button.get_style_context().add_class("dim-button")
            edit_button.set_tooltip_text(_("Modify information"))
            edit_button.set_margin_end(2)
            grid.add(edit_button)
            # Check portal for tag editor
            if App().art.tag_editor:
                edit_button.show()

        if isinstance(object, Track):
            add_to_queue = True
            string = _("Add to queue")
            icon = "zoom-in-symbolic"
            if App().player.track_in_queue(self.__object):
                add_to_queue = False
                string = _("Remove from queue")
                icon = "zoom-out-symbolic"
            queue_button = Gtk.Button.new_from_icon_name(
                icon, Gtk.IconSize.BUTTON)
            queue_button.connect("clicked", self.__on_queue_button_clicked,
                                 add_to_queue)
            queue_button.get_style_context().add_class("dim-button")
            queue_button.set_tooltip_text(string)
            queue_button.set_margin_end(2)
            queue_button.show()
            grid.add(queue_button)
        else:
            add = True
            string = _("Add to current playlist")
            icon = "list-add-symbolic"
            # Search album in player
            if isinstance(object, Disc):
                album = object.album
            else:
                album = object
            player_album_track_ids = []
            for _album in App().player.albums:
                if album.id == _album.id:
                    player_album_track_ids += _album.track_ids
            if len(set(player_album_track_ids) & set(object.track_ids)) == len(
                    object.track_ids):
                add = False
                string = _("Remove from current playlist")
                icon = "list-remove-symbolic"
            current_playlist_button = Gtk.Button.new_from_icon_name(
                icon, Gtk.IconSize.BUTTON)
            current_playlist_button.connect(
                "clicked", self.__on_current_playlist_button_clicked, add)
            current_playlist_button.get_style_context().add_class("dim-button")
            current_playlist_button.set_tooltip_text(string)
            current_playlist_button.set_margin_end(2)
            current_playlist_button.show()
            grid.add(current_playlist_button)

        playlist_button = Gtk.Button.new_from_icon_name(
            "view-list-symbolic", Gtk.IconSize.BUTTON)
        playlist_button.connect("clicked", self.__on_playlist_button_clicked)
        playlist_button.get_style_context().add_class("dim-button")
        playlist_button.set_tooltip_text(_("Add to playlist"))
        playlist_button.show()
        grid.add(playlist_button)

        if isinstance(self.__object, Track):
            rating = RatingWidget(object)
            rating.set_margin_end(2)
            rating.set_property("halign", Gtk.Align.END)
            rating.set_property("hexpand", True)
            rating.show()
            loved = LovedWidget(object)
            loved.set_margin_end(2)
            loved.show()
            grid.add(rating)
            grid.add(loved)
        self.add(grid)
    def __init__(self, album_id, genre_ids, artist_ids, art_size):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param lazy as LazyLoadingView
            @param art size as ArtSize
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids, artist_ids, art_size)
        self._album.set_artists(artist_ids)
        self.__width = None
        self.__context = None
        # Cover + rating + spacing
        self.__height = ArtSize.BIG + 26
        self.__orientation = None
        self.__child_height = TrackRow.get_best_height(self)
        # Header + separator + spacing + margin
        self.__requested_height = self.__child_height + 6
        # Discs to load, will be emptied
        self.__discs = self._album.discs
        self.__locked_widget_right = True
        self.set_property('height-request', self.__height)
        self.connect('size-allocate', self.__on_size_allocate)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/AlbumDetailedWidget.ui')
        builder.connect_signals(self)
        self._widget = builder.get_object('widget')
        album_info = builder.get_object('albuminfo')
        title_label = builder.get_object('title')
        title_label.set_property('has-tooltip', True)
        artist_label = builder.get_object('artist')
        artist_label.set_property('has-tooltip', True)
        year_label = builder.get_object('year')
        self.__header = builder.get_object('header')
        self.__overlay = builder.get_object('overlay')
        self.__duration_label = builder.get_object('duration')
        self.__context_button = builder.get_object('context')

        if art_size == ArtSize.NONE:
            self._cover = None
            rating = RatingWidget(self._album)
            rating.set_hexpand(True)
            rating.set_property('halign', Gtk.Align.END)
            rating.set_property('valign', Gtk.Align.CENTER)
            rating.show()
            self.__header.attach(rating, 4, 0, 1, 1)
            loved = LovedWidget(self._album)
            loved.set_property('halign', Gtk.Align.END)
            loved.set_property('valign', Gtk.Align.CENTER)
            loved.show()
            self.__header.attach(loved, 5, 0, 1, 1)

            artist_label.set_text(", ".join(self._album.artists))
            artist_label.show()
            if self._album.year:
                year_label.set_label(self._album.year)
                year_label.show()
        else:
            self.__duration_label.set_hexpand(True)
            builder = Gtk.Builder()
            builder.add_from_resource('/org/gnome/Lollypop/CoverBox.ui')
            builder.connect_signals(self)
            self._play_button = builder.get_object('play-button')
            self._action_button = builder.get_object('action-button')
            self._action_event = builder.get_object('action-event')
            self._cover = builder.get_object('cover')
            self.__coverbox = builder.get_object('coverbox')
            # 6 for 2*3px (application.css)
            self.__coverbox.set_property('width-request', art_size + 6)
            if art_size == ArtSize.BIG:
                self._cover.get_style_context().add_class('cover-frame')
                self._artwork_button = builder.get_object('artwork-button')
                if self._album.year:
                    year_label.set_label(self._album.year)
                    year_label.show()
                grid = Gtk.Grid()
                grid.set_column_spacing(10)
                grid.set_property('halign', Gtk.Align.CENTER)
                grid.show()
                rating = RatingWidget(self._album)
                loved = LovedWidget(self._album)
                rating.show()
                loved.show()
                grid.add(rating)
                grid.add(loved)
                self.__coverbox.add(grid)
                self._widget.attach(self.__coverbox, 0, 0, 1, 1)
                if Lp().window.get_view_width() < WindowSize.MEDIUM:
                    self.__coverbox.hide()
                if len(artist_ids) > 1:
                    artist_label.set_text(", ".join(self._album.artists))
                    artist_label.show()
            elif art_size == ArtSize.HEADER:
                # Here we are working around default CoverBox ui
                # Do we really need to have another ui file?
                # So just hack values on the fly
                self._cover.set_halign(Gtk.Align.CENTER)
                self._cover.get_style_context().add_class('small-cover-frame')
                self.__coverbox.set_margin_bottom(5)
                # We want a smaller button, so reload image
                self._rounded_class = "rounded-icon-small"
                self._play_button.set_from_icon_name(
                                               "media-playback-start-symbolic",
                                               Gtk.IconSize.MENU)
                overlay_grid = builder.get_object('overlay-grid')
                overlay_grid.set_margin_bottom(2)
                overlay_grid.set_margin_end(2)
                overlay_grid.set_column_spacing(0)
                self._play_button.set_margin_start(2)
                self._play_button.set_margin_bottom(2)
                play_event = builder.get_object('play-event')
                play_event.set_property('halign', Gtk.Align.START)
                play_event.set_property('valign', Gtk.Align.END)
                album_info.attach(self.__coverbox, 0, 0, 1, 1)
                artist_label.set_text(", ".join(self._album.artists))
                artist_label.show()

        self.__set_duration()

        self.__box = Gtk.Grid()
        self.__box.set_column_homogeneous(True)
        self.__box.set_property('valign', Gtk.Align.START)
        self.__box.show()
        album_info.add(self.__box)

        self._tracks_left = {}
        self._tracks_right = {}

        self.set_cover()
        self.update_state()

        title_label.set_label(self._album.name)

        for disc in self.__discs:
            self.__add_disc_container(disc.number)
            self.__set_disc_height(disc)

        self.add(self._widget)
        # We start transparent, we switch opaque at size allocation
        # This prevent artifacts
        self.set_opacity(0)

        if self._album.is_web and self._cover is not None:
            self._cover.get_style_context().add_class(
                                                'cover-frame-web')
Example #16
0
    def __init__(self, track, menu):
        """
            Init widget
            @param track as Track
            @param menu as Gio.Menu
        """
        Gtk.Popover.__init__(self)
        if menu is not None:
            self.bind_model(menu, None)

        if track.year != track.album.year:
            track_year = str(track.year)
        else:
            track_year = ""

        rating = RatingWidget(track)
        rating.set_margin_top(5)
        rating.set_margin_bottom(5)
        rating.set_property('halign', Gtk.Align.START)
        rating.set_property('hexpand', True)
        rating.show()

        loved = LovedWidget(track.id)
        loved.set_margin_end(5)
        loved.set_margin_top(5)
        loved.set_margin_bottom(5)
        if track_year == "":
            loved.set_property('halign', Gtk.Align.END)
        else:
            loved.set_property('halign', Gtk.Align.CENTER)
        loved.set_property('hexpand', True)
        loved.show()

        if track_year != "":
            year = Gtk.Label()
            year.set_text(track_year)
            year.set_margin_end(5)
            year.set_margin_top(5)
            year.set_margin_bottom(5)
            year.get_style_context().add_class('dim-label')
            year.set_property('halign', Gtk.Align.END)
            year.set_property('hexpand', True)
            year.show()

        if track.album.is_web:
            uri = Lp().tracks.get_uri(track.id)
            web = Gtk.LinkButton(uri)
            icon = Gtk.Image.new_from_icon_name('web-browser-symbolic',
                                                Gtk.IconSize.MENU)
            web.set_image(icon)
            web.get_style_context().add_class('no-padding')
            web.set_margin_end(5)
            web.set_tooltip_text(uri)
            web.show_all()
            uri = "https://www.youtube.com/results?search_query=%s" %\
                (track.artists[0] + " " + track.name,)
            search = Gtk.LinkButton(uri)
            icon = Gtk.Image.new_from_icon_name('edit-find-symbolic',
                                                Gtk.IconSize.MENU)
            search.set_image(icon)
            search.get_style_context().add_class('no-padding')
            search.set_margin_end(5)
            search.set_tooltip_text(uri)
            search.show_all()

        # Hack to add two widgets in popover
        # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable)
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, 'main')
        stack.show_all()

        menu_widget = self.get_child()
        if menu_widget is not None:
            menu_widget.reparent(grid)

        if not track.album.is_web:
            separator = Gtk.Separator()
            separator.show()
            grid.add(separator)

        hgrid = Gtk.Grid()
        hgrid.add(rating)
        hgrid.add(loved)
        if track.album.is_web:
            hgrid.add(web)
            hgrid.add(search)
        if track_year != "":
            hgrid.add(year)
        hgrid.show()
        if track.album.is_web:
            grid.set_row_spacing(2)
            uri = Lp().tracks.get_uri(track.id)
            edit = Gtk.Entry()
            edit.set_margin_start(5)
            edit.set_margin_end(5)
            edit.set_margin_bottom(5)
            edit.set_tooltip_text(_("Video address"))
            edit.set_property('hexpand', True)
            edit.set_text(uri)
            edit.connect('changed', self.__on_edit_changed, track.id)
            edit.show()
            grid.add(edit)
        grid.add(hgrid)
        self.add(stack)
Example #17
0
    def __init__(self, track):
        """
            Init widget
            @param track as Track
        """
        Gtk.Grid.__init__(self)
        self.set_margin_top(MARGIN_SMALL)
        self.set_row_spacing(MARGIN_SMALL)
        self.set_orientation(Gtk.Orientation.VERTICAL)

        if track.year is not None:
            year_label = Gtk.Label.new()
            year_label.set_text(str(track.year))
            dt = GLib.DateTime.new_from_unix_local(track.timestamp)
            year_label.set_tooltip_text(dt.format(_("%Y-%m-%d")))
            year_label.set_margin_end(5)
            year_label.get_style_context().add_class("dim-label")
            year_label.set_property("halign", Gtk.Align.START)
            year_label.set_property("hexpand", True)
            year_label.show()

        hgrid = Gtk.Grid()
        rating = RatingWidget(track)
        rating.set_property("halign", Gtk.Align.START)
        if App().window.folded:
            rating.set_icon_size(Gtk.IconSize.LARGE_TOOLBAR)
        rating.show()

        loved = LovedWidget(track)
        loved.set_property("halign", Gtk.Align.START)
        if App().window.folded:
            loved.set_icon_size(Gtk.IconSize.LARGE_TOOLBAR)
        loved.show()

        if track.year is not None:
            hgrid.add(year_label)
        hgrid.add(loved)
        hgrid.add(rating)
        hgrid.show()

        if not track.storage_type & StorageType.COLLECTION:
            try:
                escaped = GLib.uri_escape_string(track.uri, None, True)
                uri = load(open("%s/web_%s" % (CACHE_PATH, escaped), "rb"))
            except:
                uri = ""
            edit = Gtk.Entry()
            edit.set_placeholder_text(_("YouTube page address"))
            edit.set_margin_top(MARGIN_SMALL)
            edit.set_margin_start(MARGIN_SMALL)
            edit.set_margin_end(MARGIN_SMALL)
            edit.set_margin_bottom(MARGIN_SMALL)
            edit.set_property("hexpand", True)
            edit.set_text(uri)
            edit.connect("changed", self.__on_edit_changed, track)
            edit.show()
            self.add(edit)

        separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)
        separator.show()
        self.add(separator)
        self.add(hgrid)
Example #18
0
    def __init__(self, track, menu):
        """
            Init widget
            @param track as Track
            @param menu as Gio.Menu
        """
        Gtk.Popover.__init__(self)
        if menu is not None:
            self.bind_model(menu, None)
        # FIXME Does it works? => year in popover
        if track.year != track.album.year:
            track_year = str(track.year)
        else:
            track_year = ""

        if track_year != "":
            year = Gtk.Label()
            year.set_text(track_year)
            year.set_margin_end(5)
            year.get_style_context().add_class("dim-label")
            year.set_property("halign", Gtk.Align.END)
            year.set_property("hexpand", True)
            year.show()

        # Hack to add two widgets in popover
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, "main")
        stack.show_all()

        menu_widget = self.get_child()
        if menu_widget is not None:
            self.remove(menu_widget)
            grid.add(menu_widget)

        hgrid = Gtk.Grid()
        hgrid.get_style_context().add_class("popover-rating-loved-grid")
        rating = RatingWidget(track)
        rating.set_property("halign", Gtk.Align.START)
        rating.set_property("hexpand", True)
        rating.show()

        loved = LovedWidget(track)
        loved.set_margin_end(5)
        if track_year == "":
            loved.set_property("halign", Gtk.Align.END)
        else:
            loved.set_property("halign", Gtk.Align.CENTER)
        loved.set_property("hexpand", True)
        loved.show()

        hgrid.add(rating)
        hgrid.add(loved)

        if track_year != "":
            hgrid.add(year)
        hgrid.show()

        grid.add(hgrid)
        self.add(stack)
Example #19
0
    def __init__(self, album_id, genre_id, pop_allowed, scrolled, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre id as int
            @param parent width as int
            @param pop_allowed as bool if widget can show popovers
            @param scrolled as bool
            @param size group as Gtk.SizeGroup
        """
        AlbumWidget.__init__(self, album_id)

        self._album = Album(album_id, genre_id)

        builder = Gtk.Builder()
        if scrolled:
            builder.add_from_resource(
                '/org/gnome/Lollypop/AlbumContextWidget.ui')
        else:
            builder.add_from_resource(
                '/org/gnome/Lollypop/AlbumDetailedWidget.ui')

        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object('coverbox').add(rating)
        builder.connect_signals(self)

        if scrolled:
            builder.get_object('artist').set_text(self._album.artist_name)
            builder.get_object('artist').show()

        grid = builder.get_object('tracks')
        self._discs = Lp.albums.get_discs(album_id, genre_id)
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % disc)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
                sep = Gtk.Separator()
                sep.set_property('margin-bottom', 2)
                sep.show()
                grid.attach(sep, 0, i, 2, 1)
                i += 1
            self._tracks_left[disc] = TracksWidget(pop_allowed)
            self._tracks_right[disc] = TracksWidget(pop_allowed)
            grid.attach(self._tracks_left[disc], 0, i, 1, 1)
            grid.attach(self._tracks_right[disc], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[disc])
            size_group.add_widget(self._tracks_right[disc])

            self._tracks_left[disc].connect('activated', self._on_activated)
            self._tracks_left[disc].connect('button-press-event',
                                            self._on_button_press_event)
            self._tracks_right[disc].connect('activated', self._on_activated)
            self._tracks_right[disc].connect('button-press-event',
                                             self._on_button_press_event)

            self._tracks_left[disc].show()
            self._tracks_right[disc].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()

        self._title_label = Lp.albums.get_name(album_id)
        builder.get_object('title').set_label(self._title_label)
        builder.get_object('year').set_label(Lp.albums.get_year(album_id))
        self.add(builder.get_object('AlbumDetailedWidget'))

        if pop_allowed:
            self._menu = builder.get_object('menu')
            self._eventbox = builder.get_object('eventbox')
            self._eventbox.connect('realize', self._on_eventbox_realize)
            self._eventbox.connect("button-press-event",
                                   self._on_cover_press_event)
            self._menu.connect('clicked',
                               self._pop_menu)
            self._menu.show()
        else:
            self._eventbox = None
Example #20
0
    def __init__(self, album_id, genre_ids, artist_ids, show_cover):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param lazy as LazyLoadingView
            @param show cover as bool
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids)
        # Check if we need to limit the view to artist album
        for artist_id in self._album.artist_ids:
            if artist_id in artist_ids:
                self._album.set_artists(artist_ids)
        self._width = None
        # Cover + rating + spacing
        self._height = ArtSize.BIG + 26
        self._orientation = None
        self._stop = False
        self._child_height = TrackRow.get_best_height(self)
        # Header + separator + spacing + margin
        self._requested_height = self._child_height + 6
        # Discs to load, will be emptied
        self._discs = self._album.discs
        self._locked_widget_right = True
        self._filter_ids = artist_ids
        self.set_property('height-request', self._height)
        self.connect('size-allocate', self._on_size_allocate)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/AlbumDetailedWidget.ui')
        self._widget = builder.get_object('widget')
        self._overlay = builder.get_object('overlay')
        self._play_button = builder.get_object('play-button')
        self._play_all_button = builder.get_object('playall-button')
        self._artwork_button = builder.get_object('artwork-button')
        self._action_button = builder.get_object('action-button')
        self._action_event = builder.get_object('action-event')

        builder.connect_signals(self)
        rating = RatingWidget(self._album)
        rating.show()

        self._artist_label = builder.get_object('artist')
        if show_cover:
            self._cover = builder.get_object('cover')
            builder.get_object('duration').set_hexpand(True)
            self._cover.get_style_context().add_class('cover-frame')
            self._coverbox = builder.get_object('coverbox')
            self._coverbox.show()
            # 6 for 2*3px (application.css)
            self._coverbox.set_property('width-request', ArtSize.BIG + 6)
            self._coverbox.add(rating)
            if Lp().window.get_view_width() < WindowSize.MEDIUM:
                self._coverbox.hide()
            if len(artist_ids) > 1:
                self._artist_label.set_text(", ".join(self._album.artists))
                self._artist_label.show()
        else:
            builder.get_object('header').attach(rating, 4, 0, 1, 1)
            rating.set_hexpand(True)
            rating.set_property('halign', Gtk.Align.END)
            rating.set_property('valign', Gtk.Align.CENTER)
            self._artist_label.set_text(", ".join(self._album.artists))
            self._artist_label.show()
            self._cover = None

        label = builder.get_object('duration')
        duration = Lp().albums.get_duration(album_id, genre_ids)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)

        self._box = Gtk.Grid()
        self._box.set_column_homogeneous(True)
        self._box.set_property('valign', Gtk.Align.START)
        self._box.show()
        builder.get_object('albuminfo').add(self._box)

        self._tracks_left = {}
        self._tracks_right = {}

        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        for disc in self._discs:
            self._add_disc_container(disc.number)
            self._set_disc_height(disc)

        self.add(self._widget)
        # We start transparent, we switch opaque at size allocation
        # This prevent artifacts
        self.set_opacity(0)

        self._menu = builder.get_object('menu')
        self._menu.connect('clicked', self._pop_menu)
        # TODO Remove this later
        if Gtk.get_minor_version() > 16:
            self._menu.show()
        else:
            self.connect('map', self._on_map)
Example #21
0
    def __init__(self, object, button):
        """
            Init widget
            @param object as Track/Album
            @param button as Gtk.Button
        """
        Gtk.Grid.__init__(self)
        self.__object = object
        self.__button = button

        if self.__object.is_web:
            if Type.CHARTS in self.__object.genre_ids:
                if isinstance(self.__object, Album):
                    save = HoverWidget("document-save-symbolic",
                                       self.__save_object)
                    save.set_tooltip_text(_("Save into collection"))
                    save.set_margin_end(10)
                    save.show()
                    self.add(save)
            else:
                trash = HoverWidget("user-trash-symbolic",
                                    self.__remove_object)
                if isinstance(self.__object, Album):
                    trash.set_tooltip_text(_("Remove album"))
                else:
                    trash.set_tooltip_text(_("Remove track"))
                trash.set_margin_end(10)
                trash.show()
                self.add(trash)
        else:
            # Check portal for tag editor
            try:
                Gio.bus_get(Gio.BusType.SESSION, None, self.__on_get_bus,
                            "CanLaunchTagEditor", None,
                            self.__on_can_launch_tag_editor)
            except Exception as e:
                print("ContextWidget::__init__():", e)

            self.__edit = HoverWidget("document-properties-symbolic",
                                      self.__edit_tags)
            self.__edit.set_tooltip_text(_("Modify information"))
            self.__edit.set_margin_end(10)
            self.add(self.__edit)

        if Type.CHARTS not in self.__object.genre_ids:
            playlist = HoverWidget("view-list-symbolic",
                                   self.__show_playlist_manager)
            playlist.set_tooltip_text(_("Add to playlist"))
            playlist.show()
            self.add(playlist)

        if isinstance(self.__object, Album):
            if Lp().player.album_in_queue(self.__object):
                queue = HoverWidget("list-remove-symbolic",
                                    self.__add_to_queue)
                queue.set_tooltip_text(_("Remove from queue"))
            else:
                queue = HoverWidget("list-add-symbolic", self.__add_to_queue)
                queue.set_tooltip_text(_("Add to queue"))
            queue.set_margin_start(10)
            queue.show()
            self.add(queue)
        else:
            if self.__object.is_web:
                web = Gtk.LinkButton(self.__object.uri)
                icon = Gtk.Image.new_from_icon_name("web-browser-symbolic",
                                                    Gtk.IconSize.MENU)
                web.set_image(icon)
                web.get_style_context().add_class("no-padding")
                web.set_margin_start(5)
                web.set_tooltip_text(self.__object.uri)
                web.show_all()
                uri = "https://www.youtube.com/results?search_query=%s" %\
                    (self.__object.artists[0] + " " + self.__object.name,)
                search = Gtk.LinkButton(uri)
                icon = Gtk.Image.new_from_icon_name("edit-find-symbolic",
                                                    Gtk.IconSize.MENU)
                search.set_image(icon)
                search.get_style_context().add_class("no-padding")
                search.set_tooltip_text(uri)
                search.show_all()

                self.add(web)
                self.add(search)

            if Type.CHARTS not in self.__object.genre_ids:
                rating = RatingWidget(object)
                rating.set_margin_top(5)
                rating.set_margin_end(10)
                rating.set_margin_bottom(5)
                rating.set_property("halign", Gtk.Align.END)
                rating.set_property("hexpand", True)
                rating.show()

                loved = LovedWidget(object)
                loved.set_margin_end(5)
                loved.set_margin_top(5)
                loved.set_margin_bottom(5)
                loved.show()

                self.add(rating)
                self.add(loved)
Example #22
0
class AlbumBannerWidget(BannerWidget, SignalsHelper):
    """
        Banner for album
    """

    @signals_map
    def __init__(self, album, storage_type, view_type):
        """
            Init cover widget
            @param album
            @param storage_type as int
            @param view_type as ViewType
        """
        BannerWidget.__init__(self, view_type)
        self.__album = album
        self.__storage_type = storage_type
        self.__widget = None
        return [
                (App().window.container.widget, "notify::folded",
                 "_on_container_folded"),
                (App().art, "album-artwork-changed",
                 "_on_album_artwork_changed"),
                (App().player, "playback-added", "_on_playback_changed"),
                (App().player, "playback-updated", "_on_playback_changed"),
                (App().player, "playback-setted", "_on_playback_changed"),
                (App().player, "playback-removed", "_on_playback_changed")
        ]

    def populate(self):
        """
            Populate the view
        """
        if self.__widget is not None:
            return
        self.__widget = Gtk.Grid.new()
        self.__widget.set_margin_start(MARGIN)
        self.__widget.set_margin_end(MARGIN_MEDIUM)
        self.__widget.set_margin_top(MARGIN_SMALL)
        self.__widget.set_margin_bottom(MARGIN_SMALL)
        self.__widget.set_row_spacing(MARGIN_SMALL)
        self.__widget.set_column_spacing(MARGIN_MEDIUM)
        self.__top_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
        self.__middle_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
        self.__bottom_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
        self.__labels_box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        self.__top_box.set_vexpand(True)
        self.__middle_box.set_halign(Gtk.Align.END)
        self.__middle_box.set_valign(Gtk.Align.CENTER)
        self.__middle_box.set_hexpand(True)
        self.__bottom_box.set_vexpand(True)
        self.__year_eventbox = Gtk.EventBox.new()
        self.__year_eventbox.set_hexpand(True)
        self.__year_eventbox.set_halign(Gtk.Align.END)
        self.__year_label = Gtk.Label.new()
        self.__year_label.get_style_context().add_class("dim-label")
        self.__year_eventbox.add(self.__year_label)
        self.__year_eventbox.connect("realize", set_cursor_type)
        self.__gesture_year = GesturesHelper(
            self.__year_eventbox, primary_press_callback=self._on_year_press)
        self.__play_button = Gtk.Button.new_from_icon_name(
            "media-playback-start-symbolic", Gtk.IconSize.BUTTON)
        self.__add_button = Gtk.Button.new_from_icon_name(
            "list-add-symbolic", Gtk.IconSize.BUTTON)
        self.__menu_button = Gtk.Button.new_from_icon_name(
            "view-more-symbolic", Gtk.IconSize.BUTTON)
        self.__play_button.connect("clicked", self.__on_play_button_clicked)
        self.__add_button.connect("clicked", self.__on_add_button_clicked)
        self.__menu_button.connect("clicked", self.__on_menu_button_clicked)
        self.__title_label = Gtk.Label.new()
        self.__title_label.set_valign(Gtk.Align.END)
        self.__title_label.set_vexpand(True)
        self.__title_label.connect("query-tooltip", on_query_tooltip)
        self.__title_label.set_ellipsize(Pango.EllipsizeMode.END)
        self.__title_label.set_halign(Gtk.Align.START)
        self.__title_label.set_xalign(0)
        self.__artist_label = Gtk.Label.new()
        self.__artist_eventbox = Gtk.EventBox.new()
        self.__artist_eventbox.set_valign(Gtk.Align.START)
        self.__artist_eventbox.add(self.__artist_label)
        self.__artist_eventbox.connect("realize", set_cursor_type)
        self.__artist_label.connect("query-tooltip", on_query_tooltip)
        self.__artist_label.set_ellipsize(Pango.EllipsizeMode.END)
        self.__artist_label.set_halign(Gtk.Align.START)
        self.__artist_label.set_xalign(0)
        self.__gesture_artist = GesturesHelper(
            self.__artist_eventbox,
            primary_press_callback=self._on_artist_press)
        self.__duration_label = Gtk.Label.new()
        self.__duration_label.get_style_context().add_class("dim-label")
        self.__top_box.pack_end(self.__year_eventbox, False, True, 0)
        self.__middle_box.add(self.__play_button)
        self.__middle_box.add(self.__add_button)
        self.__middle_box.add(self.__menu_button)
        self.__middle_box.get_style_context().add_class("linked")
        self.__bottom_box.pack_end(self.__duration_label, False, True, 0)
        self.__labels_box.add(self.__title_label)
        self.__labels_box.add(self.__artist_eventbox)
        self.__widget.attach(self.__top_box, 2, 0, 1, 1)
        self.__widget.attach(self.__middle_box, 2, 1, 1, 1)
        self.__widget.attach(self.__bottom_box, 1, 2, 2, 1)
        self.__widget.attach(self.__labels_box, 1, 0, 1, 2)
        self.__widget.show_all()
        if self.view_type & ViewType.OVERLAY:
            style = "banner-button"
        else:
            style = "menu-button"
        self.__play_button.get_style_context().add_class(style)
        self.__add_button.get_style_context().add_class(style)
        self.__menu_button.get_style_context().add_class(style)
        self.__title_label.set_label(self.__album.name)
        if self.view_type & ViewType.ALBUM:
            self.__cover_widget = EditCoverWidget(self.__album, self.view_type)
            self.__artist_label.get_style_context().add_class("dim-label")
            self.__artist_label.set_label(", ".join(self.__album.artists))
        else:
            self.__artist_label.hide()
            self.__cover_widget = CoverWidget(self.__album, self.view_type)
            self.__cover_widget.set_margin_top(MARGIN_MEDIUM)
            self.__cover_widget.set_margin_bottom(MARGIN_MEDIUM)
            self.__cover_widget.connect("populated",
                                        self.__on_cover_populated)
        self.__cover_widget.show()
        if self.__album.year is not None:
            self.__year_label.set_label(str(self.__album.year))
            self.__year_label.show()
        human_duration = get_human_duration(self.__album.duration)
        self.__duration_label.set_text(human_duration)
        self.__widget.attach(self.__cover_widget, 0, 0, 1, 3)
        self.__loved_widget = LovedWidget(self.__album, Gtk.IconSize.INVALID)
        self.__loved_widget.show()
        self.__bottom_box.pack_start(self.__loved_widget, 0, False, False)
        self.__rating_widget = RatingWidget(self.__album, Gtk.IconSize.INVALID)
        self.__rating_widget.show()
        self.__bottom_box.pack_start(self.__rating_widget, 0, True, True)
        if self.view_type & ViewType.OVERLAY:
            self._overlay.add_overlay(self.__widget)
            self._overlay.set_overlay_pass_through(self.__widget, True)
        else:
            self.add(self.__widget)
        self.__update_add_button()
        self.__set_internal_size()

    def update_for_width(self, width):
        """
            Update banner internals for width, call this before showing banner
            @param width as int
        """
        BannerWidget.update_for_width(self, width)
        self.__set_artwork()

    def set_selected(self, selected):
        """
            Mark widget as selected
            @param selected as bool
        """
        if selected:
            self.__widget.set_state_flags(Gtk.StateFlags.SELECTED, True)
        else:
            self.__widget.set_state_flags(Gtk.StateFlags.NORMAL, True)

#######################
# PROTECTED           #
#######################
    def _handle_width_allocate(self, allocation):
        """
            Update artwork
            @param allocation as Gtk.Allocation
        """
        if BannerWidget._handle_width_allocate(self, allocation):
            self.__set_artwork()

    def _on_container_folded(self, leaflet, folded):
        """
            Handle libhandy folded status
            @param leaflet as Handy.Leaflet
            @param folded as Gparam
        """
        self.__set_internal_size()

    def _on_album_artwork_changed(self, art, album_id):
        """
            Update cover for album_id
            @param art as Art
            @param album_id as int
        """
        if album_id == self.__album.id:
            self.__set_artwork()

    def _on_playback_changed(self, *ignore):
        """
            Update add button
        """
        self.__update_add_button()

    def _on_year_press(self, x, y, event):
        """
            Show year view
            @param x as int
            @param y as int
            @param event as Gdk.EventButton
        """
        App().window.container.show_view([Type.YEARS], [self.__album.year])

    def _on_artist_press(self, x, y, event):
        """
            Show artist view
            @param x as int
            @param y as int
            @param event as Gdk.EventButton
        """
        App().window.container.show_view([Type.ARTISTS],
                                         self.__album.artist_ids)

#######################
# PRIVATE             #
#######################
    def __close_artwork_menu(self, action, variant):
        if App().window.folded:
            App().window.container.go_back()
        else:
            self.__artwork_popup.destroy()

    def __set_artwork(self):
        """
            Set artwork on banner
        """
        if self._artwork is not None and\
                self.view_type & ViewType.ALBUM and\
                App().animations:
            App().art_helper.set_album_artwork(
                            self.__album,
                            # +100 to prevent resize lag
                            self.width + 100,
                            self.height,
                            self._artwork.get_scale_factor(),
                            ArtBehaviour.BLUR_HARD |
                            ArtBehaviour.DARKER,
                            self._on_artwork)
        if self.width < ArtSize.BANNER * 3:
            if self.__widget.get_child_at(2, 0) == self.__top_box:
                self.__widget.remove(self.__labels_box)
                self.__widget.remove(self.__top_box)
                self.__widget.attach(self.__top_box, 1, 1, 1, 1)
                self.__widget.attach(self.__labels_box, 1, 0, 2, 1)
        elif self.__widget.get_child_at(1, 0) == self.__labels_box:
            self.__widget.remove(self.__labels_box)
            self.__widget.remove(self.__top_box)
            self.__widget.attach(self.__top_box, 2, 0, 1, 1)
            self.__widget.attach(self.__labels_box, 1, 0, 1, 2)

    def __update_add_button(self):
        """
            Set image as +/-
        """
        if self.__album.id in App().player.album_ids:
            self.__add_button.get_image().set_from_icon_name(
                "list-remove-symbolic", Gtk.IconSize.BUTTON)
        else:
            self.__add_button.get_image().set_from_icon_name(
                "list-add-symbolic", Gtk.IconSize.BUTTON)

    def __set_internal_size(self):
        """
            Set content size based on available width
        """
        classes = ["text-medium", "text-large", "text-x-large"]
        # Text size
        for label in [self.__title_label,
                      self.__artist_label,
                      self.__year_label,
                      self.__duration_label]:
            context = label.get_style_context()
            for c in classes:
                context.remove_class(c)

        if App().window.folded:
            art_size = ArtSize.MEDIUM
            icon_size = Gtk.IconSize.BUTTON
            cls_title = "text-medium"
            cls_others = "text-medium"
        elif not self.view_type & ViewType.OVERLAY:
            art_size = ArtSize.BANNER
            icon_size = Gtk.IconSize.LARGE_TOOLBAR
            cls_title = "text-large"
            cls_others = "text-large"
        else:
            art_size = ArtSize.BANNER
            icon_size = Gtk.IconSize.LARGE_TOOLBAR
            cls_title = "text-x-large"
            cls_others = "text-large"
        self.__title_label.get_style_context().add_class(cls_title)
        self.__artist_label.get_style_context().add_class(cls_title)
        self.__year_label.get_style_context().add_class(cls_others)
        self.__duration_label.get_style_context().add_class(cls_others)

        self.__rating_widget.set_icon_size(icon_size)
        self.__loved_widget.set_icon_size(icon_size)
        self.__cover_widget.set_art_size(art_size)

    def __on_cover_populated(self, widget):
        """
            Pass signal
            @param widget as Gtk.Widget
        """
        emit_signal(self, "populated")

    def __on_menu_button_clicked(self, button):
        """
            Show album menu
            @param button as Gtk.Button
        """
        from lollypop.widgets_menu import MenuBuilder
        from lollypop.menu_objects import AlbumMenu
        from lollypop.menu_artwork import AlbumArtworkMenu
        menu = AlbumMenu(self.__album,
                         self.__storage_type,
                         self.view_type)
        menu_widget = MenuBuilder(menu)
        menu_widget.show()
        if App().window.folded:
            menu_ext = AlbumArtworkMenu(self.__album, self.view_type, True)
            menu_ext.connect("hidden", self.__close_artwork_menu)
            menu_ext.show()
            menu_widget.add_widget(menu_ext, -2)
        popup_widget(menu_widget, button, None, None, button)

    def __on_play_button_clicked(self, button):
        """
            Play album
           @param button as Gtk.Button
        """
        App().player.play_album(self.__album.clone(False))

    def __on_add_button_clicked(self, button):
        """
            Add/Remove album
           @param button as Gtk.Button
        """
        if self.__album.id in App().player.album_ids:
            App().player.remove_album_by_id(self.__album.id)
        else:
            App().player.add_album(self.__album.clone(False))
Example #23
0
    def __init__(self, album_id, genre_id, pop_allowed, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre id as int
            @param parent width as int
            @param pop_allowed as bool if widget can show popovers
            @param size group as Gtk.SizeGroup
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_id=genre_id)
        self._pop_allowed = pop_allowed
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/%s.ui' %
                                  type(self).__name__)
        self._color = builder.get_object('color')
        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object('coverbox').add(rating)
        builder.connect_signals(self)

        self._artist_label = builder.get_object('artist')

        label = builder.get_object('duration')
        duration = Lp().albums.get_duration(album_id, genre_id)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)

        grid = builder.get_object('tracks')
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
            self._tracks_left[index] = TracksWidget(pop_allowed, True)
            self._tracks_right[index] = TracksWidget(pop_allowed, True)
            grid.attach(self._tracks_left[index], 0, i, 1, 1)
            grid.attach(self._tracks_right[index], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect('activated',
                                             self._on_activated)
            self._tracks_left[index].connect('button-press-event',
                                             self._on_button_press_event)
            self._tracks_right[index].connect('activated', self._on_activated)
            self._tracks_right[index].connect('button-press-event',
                                              self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        self.add(builder.get_object('widget'))

        # TODO: Remove this test later
        if pop_allowed or Gtk.get_minor_version() > 16:
            self._menu = builder.get_object('menu')
            self._menu.connect('clicked',
                               self._pop_menu)
            self._menu.show()
Example #24
0
    def __init__(self, album_id, genre_ids, artist_ids,
                 size_group, update_albums=True):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param size group as Gtk.SizeGroup
            @param update albums as bool: update albums on play
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids)
        self._width = None
        self._locked_widget_right = True
        self._artist_ids = artist_ids
        self._limit_to_current = not update_albums
        self.set_property('height-request', ArtSize.BIG)
        self.connect('size-allocate', self._on_size_allocate)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/%s.ui' %
                                  type(self).__name__)
        self._widget = builder.get_object('widget')
        self._play_button = builder.get_object('play-button')
        self._play_all_button = builder.get_object('playall-button')
        self._artwork_button = builder.get_object('artwork-button')
        self._action_button = builder.get_object('action-button')
        self._action_event = builder.get_object('action-event')
        builder.connect_signals(self)

        rating = RatingWidget(self._album)
        rating.show()
        self._coverbox = builder.get_object('coverbox')
        self._coverbox.add(rating)
        if Lp().window.get_view_width() < WindowSize.MEDIUM:
            self._coverbox.hide()

        self._artist_label = builder.get_object('artist')
        if len(artist_ids) > 1:
            self._artist_label.set_text(self._album.artist_name)
            self._artist_label.show()
        label = builder.get_object('duration')
        duration = Lp().albums.get_duration(album_id, genre_ids)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)
        self._box = Gtk.FlowBox()
        self._box.set_selection_mode(Gtk.SelectionMode.NONE)
        self._box.set_hexpand(True)
        self._box.show()
        builder.get_object('albuminfos').add(self._box)
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                label.show()
                self._box.insert(label, -1)
                sep = Gtk.Separator()
                sep.set_opacity(0.0)
                sep.show()
                self._box.insert(sep, -1)
            self._tracks_left[index] = TracksWidget(True)
            self._tracks_right[index] = TracksWidget(True)
            self._box.insert(self._tracks_left[index], -1)
            self._box.insert(self._tracks_right[index], -1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect('activated',
                                             self._on_activated)
            self._tracks_left[index].connect('button-press-event',
                                             self._on_button_press_event)
            self._tracks_right[index].connect('activated', self._on_activated)
            self._tracks_right[index].connect('button-press-event',
                                              self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()

        self._cover = builder.get_object('cover')
        self._color = builder.get_object('color')
        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        self.add(self._widget)

        self._menu = builder.get_object('menu')
        self._menu.connect('clicked', self._pop_menu)
        # TODO Remove this later
        if Gtk.get_minor_version() > 16:
            self._menu.show()
        else:
            self.connect('map', self._on_map)
Example #25
0
    def __init__(self, album_id, genre_ids, artist_ids, show_cover):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param lazy as LazyLoadingView
            @param show cover as bool
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids, artist_ids)
        self._album.set_artists(artist_ids)
        self.__width = None
        self.__context = None
        # Cover + rating + spacing
        self.__height = ArtSize.BIG + 26
        self.__orientation = None
        self.__child_height = TrackRow.get_best_height(self)
        # Header + separator + spacing + margin
        self.__requested_height = self.__child_height + 6
        # Discs to load, will be emptied
        self.__discs = self._album.discs
        self.__locked_widget_right = True
        self.set_property('height-request', self.__height)
        self.connect('size-allocate', self.__on_size_allocate)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/AlbumDetailedWidget.ui')
        self._widget = builder.get_object('widget')
        self.__header = builder.get_object('header')
        self.__overlay = builder.get_object('overlay')
        self._play_button = builder.get_object('play-button')
        self._artwork_button = builder.get_object('artwork-button')
        self._action_button = builder.get_object('action-button')
        self._action_event = builder.get_object('action-event')

        builder.connect_signals(self)
        rating = RatingWidget(self._album)
        rating.show()

        artist_label = builder.get_object('artist')
        if show_cover:
            self._cover = builder.get_object('cover')
            builder.get_object('duration').set_hexpand(True)
            self._cover.get_style_context().add_class('cover-frame')
            self.__coverbox = builder.get_object('coverbox')
            self.__coverbox.show()
            # 6 for 2*3px (application.css)
            self.__coverbox.set_property('width-request', ArtSize.BIG + 6)
            self.__coverbox.add(rating)
            if Lp().window.get_view_width() < WindowSize.MEDIUM:
                self.__coverbox.hide()
            if len(artist_ids) > 1:
                artist_label.set_text(", ".join(self._album.artists))
                artist_label.show()
        else:
            self.__header.attach(rating, 4, 0, 1, 1)
            rating.set_hexpand(True)
            rating.set_property('halign', Gtk.Align.END)
            rating.set_property('valign', Gtk.Align.CENTER)
            artist_label.set_text(", ".join(self._album.artists))
            artist_label.show()
            self._cover = None

        self.__duration_label = builder.get_object('duration')
        self.__set_duration()

        self.__box = Gtk.Grid()
        self.__box.set_column_homogeneous(True)
        self.__box.set_property('valign', Gtk.Align.START)
        self.__box.show()
        builder.get_object('albuminfo').add(self.__box)

        self._tracks_left = {}
        self._tracks_right = {}

        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        for disc in self.__discs:
            self.__add_disc_container(disc.number)
            self.__set_disc_height(disc)

        self.add(self._widget)
        # We start transparent, we switch opaque at size allocation
        # This prevent artifacts
        self.set_opacity(0)

        self.__context_button = builder.get_object('context')

        if self._album.is_web and show_cover:
            self._cover.get_style_context().add_class(
                                                'cover-frame-web')
Example #26
0
    def __init__(self, object, button):
        """
            Init widget
            @param object as Track/Album
            @param button as Gtk.Button
        """
        Gtk.Grid.__init__(self)
        self.__object = object
        self.__button = button
        self.__tag_editor = None

        if self.__object.is_web:
            if self.__object.genre_ids == [Type.CHARTS]:
                if isinstance(self.__object, Album):
                    save = HoverWidget('document-save-symbolic',
                                       self.__save_object)
                    save.set_tooltip_text(_("Save into collection"))
                    save.set_margin_end(10)
                    save.show()
            else:
                trash = HoverWidget('user-trash-symbolic',
                                    self.__remove_object)
                if isinstance(self.__object, Album):
                    trash.set_tooltip_text(_("Remove album"))
                else:
                    trash.set_tooltip_text(_("Remove track"))
                trash.set_margin_end(10)
                trash.show()
        else:
            # Search for tag editor
            favorite = Lp().settings.get_value('tag-editor').get_string()
            for editor in [favorite] + TAG_EDITORS:
                if GLib.find_program_in_path(editor) is not None:
                    self.__tag_editor = editor
            if self.__tag_editor is not None:
                edit = HoverWidget('document-properties-symbolic',
                                   self.__edit_tags)
                edit.set_tooltip_text(_("Modify information"))
                edit.set_margin_end(10)
                edit.show()

        playlist = HoverWidget('view-list-symbolic',
                               self.__show_playlist_manager)
        playlist.set_tooltip_text(_("Playlists"))
        playlist.show()

        if isinstance(self.__object, Album):
            if Lp().player.album_in_queue(self.__object):
                queue = HoverWidget('list-remove-symbolic',
                                    self.__add_to_queue)
                queue.set_tooltip_text(_("Remove from queue"))
            else:
                queue = HoverWidget('list-add-symbolic', self.__add_to_queue)
                queue.set_tooltip_text(_("Add to queue"))
            queue.set_margin_start(10)
            queue.show()
        else:
            rating = RatingWidget(object)
            rating.set_margin_top(5)
            rating.set_margin_bottom(5)
            rating.set_property('halign', Gtk.Align.END)
            rating.set_property('hexpand', True)
            rating.show()

            loved = LovedWidget(object.id)
            loved.set_margin_end(5)
            loved.set_margin_top(5)
            loved.set_margin_bottom(5)
            loved.show()

            if self.__object.is_web:
                web = Gtk.LinkButton(self.__object.uri)
                icon = Gtk.Image.new_from_icon_name('web-browser-symbolic',
                                                    Gtk.IconSize.MENU)
                web.set_image(icon)
                web.get_style_context().add_class('no-padding')
                web.set_margin_start(5)
                web.set_tooltip_text(self.__object.uri)
                web.show_all()
                uri = "https://www.youtube.com/results?search_query=%s" %\
                    (self.__object.artists[0] + " " + self.__object.name,)
                search = Gtk.LinkButton(uri)
                icon = Gtk.Image.new_from_icon_name('edit-find-symbolic',
                                                    Gtk.IconSize.MENU)
                search.set_image(icon)
                search.get_style_context().add_class('no-padding')
                search.set_tooltip_text(uri)
                search.show_all()

        if self.__object.is_web:
            if self.__object.genre_ids == [Type.CHARTS]:
                if isinstance(self.__object, Album):
                    self.add(save)
            else:
                self.add(trash)
        elif self.__tag_editor is not None:
            self.add(edit)
        self.add(playlist)
        if isinstance(self.__object, Album):
            self.add(queue)
        else:
            if self.__object.album.is_web:
                self.add(web)
                self.add(search)
            self.add(rating)
            self.add(loved)
Example #27
0
    def __init__(self, album_id, genre_id, pop_allowed, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre id as int
            @param parent width as int
            @param pop_allowed as bool if widget can show popovers
            @param size group as Gtk.SizeGroup
        """
        AlbumWidget.__init__(self, album_id, genre_id=genre_id)
        self._pop_allowed = pop_allowed

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/%s.ui' %
                                  type(self).__name__)

        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object('coverbox').add(rating)
        builder.connect_signals(self)

        self._artist_label = builder.get_object('artist')

        grid = builder.get_object('tracks')
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
                sep = Gtk.Separator()
                sep.set_property('margin-bottom', 2)
                sep.show()
                grid.attach(sep, 0, i, 2, 1)
                i += 1
            self._tracks_left[index] = TracksWidget(pop_allowed, True)
            self._tracks_right[index] = TracksWidget(pop_allowed, True)
            grid.attach(self._tracks_left[index], 0, i, 1, 1)
            grid.attach(self._tracks_right[index], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect('activated',
                                             self._on_activated)
            self._tracks_left[index].connect('button-press-event',
                                             self._on_button_press_event)
            self._tracks_right[index].connect('activated', self._on_activated)
            self._tracks_right[index].connect('button-press-event',
                                              self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        self.add(builder.get_object('widget'))

        if pop_allowed:
            self._menu = builder.get_object('menu')
            self._menu.connect('clicked',
                               self._pop_menu)
            self._menu.show()
Example #28
0
    def __init__(self, track, menu):
        """
            Init widget
            @param track as Track
            @param menu as Gio.Menu
        """
        Gtk.Popover.__init__(self)
        if menu is not None:
            self.bind_model(menu, None)

        if track.year != track.album.year:
            track_year = str(track.year)
        else:
            track_year = ""

        rating = RatingWidget(track)
        rating.set_margin_top(5)
        rating.set_margin_bottom(5)
        rating.set_property('halign', Gtk.Align.START)
        rating.set_property('hexpand', True)
        rating.show()

        loved = LovedWidget(track.id)
        loved.set_margin_end(5)
        loved.set_margin_top(5)
        loved.set_margin_bottom(5)
        if track_year == "":
            loved.set_property('halign', Gtk.Align.END)
        else:
            loved.set_property('halign', Gtk.Align.CENTER)
        loved.set_property('hexpand', True)
        loved.show()

        if track_year != "":
            year = Gtk.Label()
            year.set_text(track_year)
            year.set_margin_end(5)
            year.set_margin_top(5)
            year.set_margin_bottom(5)
            year.get_style_context().add_class('dim-label')
            year.set_property('halign', Gtk.Align.END)
            year.set_property('hexpand', True)
            year.show()

        if track.album.is_web:
            uri = Lp().tracks.get_uri(track.id)
            web = Gtk.LinkButton(uri)
            icon = Gtk.Image.new_from_icon_name('web-browser-symbolic',
                                                Gtk.IconSize.MENU)
            web.set_image(icon)
            web.get_style_context().add_class('no-padding')
            web.set_margin_end(5)
            web.set_tooltip_text(uri)
            web.show_all()
            uri = "https://www.youtube.com/results?search_query=%s" %\
                (track.artists[0] + " " + track.name,)
            search = Gtk.LinkButton(uri)
            icon = Gtk.Image.new_from_icon_name('edit-find-symbolic',
                                                Gtk.IconSize.MENU)
            search.set_image(icon)
            search.get_style_context().add_class('no-padding')
            search.set_margin_end(5)
            search.set_tooltip_text(uri)
            search.show_all()

        # Hack to add two widgets in popover
        # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable)
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, 'main')
        stack.show_all()

        menu_widget = self.get_child()
        if menu_widget is not None:
            menu_widget.reparent(grid)

        if not track.album.is_web:
            separator = Gtk.Separator()
            separator.show()
            grid.add(separator)

        hgrid = Gtk.Grid()
        hgrid.add(rating)
        hgrid.add(loved)
        if track.album.is_web:
            hgrid.add(web)
            hgrid.add(search)
        if track_year != "":
            hgrid.add(year)
        hgrid.show()
        if track.album.is_web:
            grid.set_row_spacing(2)
            uri = Lp().tracks.get_uri(track.id)
            edit = Gtk.Entry()
            edit.set_margin_start(5)
            edit.set_margin_end(5)
            edit.set_margin_bottom(5)
            edit.set_tooltip_text(_("Video address"))
            edit.set_property('hexpand', True)
            edit.set_text(uri)
            edit.connect('changed', self.__on_edit_changed, track.id)
            edit.show()
            grid.add(edit)
        grid.add(hgrid)
        self.add(stack)
Example #29
0
class AlbumBannerWidget(BannerWidget, SignalsHelper):
    """
        Banner for album
    """
    @signals_map
    def __init__(self, album, storage_type, view_type):
        """
            Init cover widget
            @param album
            @param storage_type as int
            @param view_type as ViewType
        """
        BannerWidget.__init__(self, view_type)
        self.__album = album
        self.__storage_type = storage_type
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/AlbumBannerWidget.ui")
        builder.connect_signals(self)
        self.__labels = builder.get_object("labels")
        self.__title_label = builder.get_object("title_label")
        self.__title_label.connect("query-tooltip", on_query_tooltip)
        self.__artist_label = builder.get_object("artist_label")
        self.__artist_label.connect("query-tooltip", on_query_tooltip)
        self.__year_label = builder.get_object("year_label")
        self.__duration_label = builder.get_object("duration_label")
        self.__play_button = builder.get_object("play_button")
        self.__add_button = builder.get_object("add_button")
        self.__menu_button = builder.get_object("menu_button")
        self.__widget = builder.get_object("widget")
        if view_type & ViewType.OVERLAY:
            style = "banner-button"
        else:
            style = "menu-button"
        self.__play_button.get_style_context().add_class(style)
        self.__add_button.get_style_context().add_class(style)
        self.__menu_button.get_style_context().add_class(style)
        self.__cover_widget = CoverWidget(album, view_type)
        self.__cover_widget.show()
        self.__title_label.set_label(album.name)
        if view_type & ViewType.ALBUM:
            self.__artist_label.show()
            self.__artist_label.set_label(", ".join(album.artists))
        else:
            self.__title_label.set_opacity(0.8)
            self.__year_label.set_opacity(0.7)
            self.__duration_label.set_opacity(0.6)
            self.__widget.get_style_context().add_class("album-banner")
        if album.year is not None:
            self.__year_label.set_label(str(album.year))
            self.__year_label.show()
        human_duration = get_human_duration(album.duration)
        self.__duration_label.set_text(human_duration)
        artist_eventbox = builder.get_object("artist_eventbox")
        artist_eventbox.connect("realize", set_cursor_type)
        self.__gesture1 = GesturesHelper(
            artist_eventbox, primary_press_callback=self._on_artist_press)
        year_eventbox = builder.get_object("year_eventbox")
        year_eventbox.connect("realize", set_cursor_type)
        self.__gesture2 = GesturesHelper(
            year_eventbox, primary_press_callback=self._on_year_press)
        self.__widget.attach(self.__cover_widget, 0, 0, 1, 3)
        self.__bottom_box = builder.get_object("bottom_box")
        self.__loved_widget = LovedWidget(album, Gtk.IconSize.INVALID)
        self.__loved_widget.show()
        self.__bottom_box.pack_start(self.__loved_widget, 0, False, False)
        self.__rating_widget = RatingWidget(album, Gtk.IconSize.INVALID)
        self.__rating_widget.show()
        self.__bottom_box.pack_start(self.__rating_widget, 0, True, True)
        if view_type & ViewType.OVERLAY:
            self._overlay.add_overlay(self.__widget)
            self._overlay.set_overlay_pass_through(self.__widget, True)
        else:
            self.add(self.__widget)
        self.__update_add_button()
        self.__set_internal_size()
        return [(App().window.container.widget, "notify::folded",
                 "_on_container_folded"),
                (App().art, "album-artwork-changed",
                 "_on_album_artwork_changed"),
                (App().player, "playback-added", "_on_playback_changed"),
                (App().player, "playback-updated", "_on_playback_changed"),
                (App().player, "playback-removed", "_on_playback_changed")]

    def update_for_width(self, width):
        """
            Update banner internals for width, call this before showing banner
            @param width as int
        """
        BannerWidget.update_for_width(self, width)
        self.__set_artwork()

    def set_selected(self, selected):
        """
            Mark widget as selected
            @param selected as bool
        """
        if selected:
            self.__widget.set_state_flags(Gtk.StateFlags.SELECTED, True)
        else:
            self.__widget.set_state_flags(Gtk.StateFlags.NORMAL, True)

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

    def _handle_width_allocate(self, allocation):
        """
            Update artwork
            @param allocation as Gtk.Allocation
        """
        if BannerWidget._handle_width_allocate(self, allocation):
            self.__set_artwork()

    def _on_container_folded(self, leaflet, folded):
        """
            Handle libhandy folded status
            @param leaflet as Handy.Leaflet
            @param folded as Gparam
        """
        self.__set_internal_size()

    def _on_menu_button_clicked(self, button):
        """
            Show album menu
            @param button as Gtk.Button
        """
        from lollypop.widgets_menu import MenuBuilder
        from lollypop.menu_objects import AlbumMenu
        from lollypop.menu_artwork import AlbumArtworkMenu
        menu = AlbumMenu(self.__album, self.__storage_type, self.view_type)
        menu_widget = MenuBuilder(menu)
        menu_widget.show()
        if App().window.folded:
            menu_ext = AlbumArtworkMenu(self.__album, self.view_type, True)
            menu_ext.connect("hidden", self.__close_artwork_menu)
            menu_ext.show()
            menu_widget.add_widget(menu_ext, -2)
        popup_widget(menu_widget, button, None, None, button)

    def _on_play_button_clicked(self, button):
        """
            Play album
           @param button as Gtk.Button
        """
        App().player.play_album(self.__album.clone(False))

    def _on_add_button_clicked(self, button):
        """
            Add/Remove album
           @param button as Gtk.Button
        """
        if self.__album.id in App().player.album_ids:
            App().player.remove_album_by_id(self.__album.id)
        else:
            App().player.add_album(self.__album.clone(False))

    def _on_album_artwork_changed(self, art, album_id):
        """
            Update cover for album_id
            @param art as Art
            @param album_id as int
        """
        if album_id == self.__album.id:
            self.__set_artwork()

    def _on_playback_changed(self, *ignore):
        """
            Update add button
        """
        self.__update_add_button()

    def _on_year_press(self, x, y, event):
        """
            Show year view
            @param x as int
            @param y as int
            @param event as Gdk.EventButton
        """
        App().window.container.show_view([Type.YEARS], [self.__album.year])

    def _on_artist_press(self, x, y, event):
        """
            Show artist view
            @param x as int
            @param y as int
            @param event as Gdk.EventButton
        """
        App().window.container.show_view([Type.ARTISTS],
                                         self.__album.artist_ids)

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

    def __close_artwork_menu(self, action, variant):
        if App().window.folded:
            App().window.container.go_back()
        else:
            self.__artwork_popup.destroy()

    def __set_artwork(self):
        """
            Set artwork on banner
        """
        if self._artwork is not None and\
                self.view_type & ViewType.ALBUM and\
                App().animations:
            App().art_helper.set_album_artwork(
                self.__album,
                # +100 to prevent resize lag
                self.width + 100,
                self.height,
                self._artwork.get_scale_factor(),
                ArtBehaviour.BLUR_HARD | ArtBehaviour.DARKER,
                self._on_artwork)
        if self.width < ArtSize.BANNER * 3:
            if self.__cover_widget.get_opacity() == 1:
                self.__cover_widget.set_opacity(0.1)
                self.__widget.remove(self.__labels)
                self.__widget.attach(self.__labels, 0, 0, 2, 2)
        elif self.__cover_widget.get_opacity() != 1:
            self.__cover_widget.set_opacity(1)
            self.__widget.remove(self.__labels)
            self.__widget.attach(self.__labels, 1, 0, 1, 2)

    def __update_add_button(self):
        """
            Set image as +/-
        """
        if self.__album.id in App().player.album_ids:
            self.__add_button.get_image().set_from_icon_name(
                "list-remove-symbolic", Gtk.IconSize.BUTTON)
        else:
            self.__add_button.get_image().set_from_icon_name(
                "list-add-symbolic", Gtk.IconSize.BUTTON)

    def __set_internal_size(self):
        """
            Set content size based on available width
        """
        # Text size
        for label in [
                self.__title_label, self.__artist_label, self.__year_label,
                self.__duration_label
        ]:
            context = label.get_style_context()
            for c in context.list_classes():
                context.remove_class(c)

        if App().window.folded:
            art_size = ArtSize.MEDIUM
            icon_size = Gtk.IconSize.BUTTON
            cls_title = "text-medium"
            cls_others = "text-medium"
        else:
            art_size = ArtSize.BANNER
            icon_size = Gtk.IconSize.LARGE_TOOLBAR
            cls_title = "text-x-large"
            cls_others = "text-large"
        self.__title_label.get_style_context().add_class(cls_title)
        self.__artist_label.get_style_context().add_class(cls_title)
        self.__year_label.get_style_context().add_class(cls_others)
        self.__duration_label.get_style_context().add_class(cls_others)

        self.__rating_widget.set_icon_size(icon_size)
        self.__loved_widget.set_icon_size(icon_size)
        self.__cover_widget.set_art_size(art_size)
Example #30
0
    def __init__(self, album_id, genre_ids, artist_ids, art_size):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param lazy as LazyLoadingView
            @param art size as ArtSize
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids, artist_ids, art_size)
        self._rounded_class = "rounded-icon-small"
        self.__width = None
        self.__context = None
        # Cover + rating + spacing
        self.__height = ArtSize.BIG + 26
        self.__orientation = None
        self.__child_height = TrackRow.get_best_height(self)
        # Header + separator + spacing + margin
        self.__requested_height = self.__child_height + 6
        # Discs to load, will be emptied
        self.__discs = self._album.discs
        self.__locked_widget_right = True
        self.set_property("height-request", self.__height)
        self.connect("size-allocate", self.__on_size_allocate)
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/AlbumDetailedWidget.ui")
        builder.connect_signals(self)
        self._widget = builder.get_object("widget")
        album_info = builder.get_object("albuminfo")
        title_label = builder.get_object("title")
        title_label.set_property("has-tooltip", True)
        artist_label = builder.get_object("artist")
        artist_label.set_property("has-tooltip", True)
        year_label = builder.get_object("year")
        self.__header = builder.get_object("header")
        self.__overlay = builder.get_object("overlay")
        self.__duration_label = builder.get_object("duration")
        self.__context_button = builder.get_object("context")

        if art_size == ArtSize.NONE:
            self._cover = None
            rating = RatingWidget(self._album)
            rating.set_hexpand(True)
            rating.set_property("halign", Gtk.Align.END)
            rating.set_property("valign", Gtk.Align.CENTER)
            rating.show()
            self.__header.attach(rating, 4, 0, 1, 1)
            loved = LovedWidget(self._album)
            loved.set_property("halign", Gtk.Align.END)
            loved.set_property("valign", Gtk.Align.CENTER)
            loved.show()
            self.__header.attach(loved, 5, 0, 1, 1)

            artist_label.set_text(", ".join(self._album.artists))
            artist_label.show()
            if self._album.year is not None:
                year_label.set_label(str(self._album.year))
                year_label.show()
        else:
            self.__duration_label.set_hexpand(True)
            builder = Gtk.Builder()
            builder.add_from_resource("/org/gnome/Lollypop/CoverBox.ui")
            builder.connect_signals(self)
            self._play_button = builder.get_object("play-button")
            self._action_button = builder.get_object("action-button")
            self._action_event = builder.get_object("action-event")
            self._cover = builder.get_object("cover")
            self.__coverbox = builder.get_object("coverbox")
            # 6 for 2*3px (application.css)
            self.__coverbox.set_property("width-request", art_size + 6)
            if art_size == ArtSize.BIG:
                self._cover.get_style_context().add_class("cover-frame")
                self._artwork_button = builder.get_object("artwork-button")
                if self._album.year is not None:
                    year_label.set_label(str(self._album.year))
                    year_label.show()
                grid = Gtk.Grid()
                grid.set_column_spacing(10)
                grid.set_property("halign", Gtk.Align.CENTER)
                grid.show()
                rating = RatingWidget(self._album)
                loved = LovedWidget(self._album)
                rating.show()
                loved.show()
                grid.add(rating)
                grid.add(loved)
                self.__coverbox.add(grid)
                self._widget.attach(self.__coverbox, 0, 0, 1, 1)
                if Lp().window.get_view_width() < WindowSize.MEDIUM:
                    self.__coverbox.hide()
                if len(artist_ids) > 1:
                    artist_label.set_text(", ".join(self._album.artists))
                    artist_label.show()
            elif art_size == ArtSize.HEADER:
                # Here we are working around default CoverBox ui
                # Do we really need to have another ui file?
                # So just hack values on the fly
                self._cover.get_style_context().add_class("small-cover-frame")
                overlay_grid = builder.get_object("overlay-grid")
                overlay_grid.set_margin_bottom(2)
                overlay_grid.set_margin_end(2)
                overlay_grid.set_column_spacing(0)
                play_event = builder.get_object("play-event")
                play_event.set_margin_start(2)
                play_event.set_margin_bottom(2)
                album_info.attach(self.__coverbox, 0, 0, 1, 1)
                artist_label.set_text(", ".join(self._album.artists))
                artist_label.show()

        self.__set_duration()

        self.__box = Gtk.Grid()
        self.__box.set_column_homogeneous(True)
        self.__box.set_property("valign", Gtk.Align.START)
        self.__box.show()
        album_info.add(self.__box)

        self._tracks_left = {}
        self._tracks_right = {}

        self.set_cover()
        self.update_state()

        title_label.set_label(self._album.name)

        for disc in self.__discs:
            self.__add_disc_container(disc.number)
            self.__set_disc_height(disc)

        self.add(self._widget)
        # We start transparent, we switch opaque at size allocation
        # This prevent artifacts
        self.set_opacity(0)

        self._lock_overlay = False
Example #31
0
    def __init__(self, album_id, genre_id, pop_allowed, scrolled, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre id as int
            @param parent width as int
            @param pop_allowed as bool if widget can show popovers
            @param scrolled as bool
            @param size group as Gtk.SizeGroup
        """
        AlbumWidget.__init__(self, album_id, genre_id=genre_id)

        builder = Gtk.Builder()
        if scrolled:
            builder.add_from_resource(
                '/org/gnome/Lollypop/AlbumContextWidget.ui')
        else:
            builder.add_from_resource(
                '/org/gnome/Lollypop/AlbumDetailedWidget.ui')

        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object('coverbox').add(rating)
        builder.connect_signals(self)

        if scrolled:
            builder.get_object('artist').set_text(self._album.artist_name)
            builder.get_object('artist').show()

        grid = builder.get_object('tracks')
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
                sep = Gtk.Separator()
                sep.set_property('margin-bottom', 2)
                sep.show()
                grid.attach(sep, 0, i, 2, 1)
                i += 1
            self._tracks_left[index] = TracksWidget(pop_allowed)
            self._tracks_right[index] = TracksWidget(pop_allowed)
            grid.attach(self._tracks_left[index], 0, i, 1, 1)
            grid.attach(self._tracks_right[index], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect('activated', self._on_activated)
            self._tracks_left[index].connect('button-press-event',
                                             self._on_button_press_event)
            self._tracks_right[index].connect('activated', self._on_activated)
            self._tracks_right[index].connect('button-press-event',
                                              self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()

        builder.get_object('title').set_label(self._album.name)
        builder.get_object('year').set_label(self._album.year)
        self.add(builder.get_object('AlbumDetailedWidget'))

        if pop_allowed:
            self._menu = builder.get_object('menu')
            self._eventbox = builder.get_object('eventbox')
            self._eventbox.connect('realize', self._on_eventbox_realize)
            self._eventbox.connect("button-press-event",
                                   self._on_cover_press_event)
            self._menu.connect('clicked', self._pop_menu)
            self._menu.show()
        else:
            self._eventbox = None
Example #32
0
    def __init__(self, album_id, genre_ids, artist_ids, popover, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param popover as bool
            @param size group as Gtk.SizeGroup
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids)
        self._artist_ids = artist_ids
        self._pop_allowed = not popover or Gtk.get_minor_version() > 16
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/%s.ui" % type(self).__name__)
        self._color = builder.get_object("color")
        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object("coverbox").add(rating)
        builder.connect_signals(self)

        self._artist_label = builder.get_object("artist")
        if len(artist_ids) > 1:
            self._artist_label.set_text(self._album.artist_name)
            self._artist_label.show()
        label = builder.get_object("duration")
        duration = Lp().albums.get_duration(album_id, genre_ids)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)

        grid = builder.get_object("tracks")
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property("halign", Gtk.Align.START)
                label.get_style_context().add_class("dim-label")
                if i:
                    label.set_property("margin-top", 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
            self._tracks_left[index] = TracksWidget(self._pop_allowed, True)
            self._tracks_right[index] = TracksWidget(self._pop_allowed, True)
            grid.attach(self._tracks_left[index], 0, i, 1, 1)
            grid.attach(self._tracks_right[index], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect("activated", self._on_activated)
            self._tracks_left[index].connect("button-press-event", self._on_button_press_event)
            self._tracks_right[index].connect("activated", self._on_activated)
            self._tracks_right[index].connect("button-press-event", self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()
            i += 1

        self._cover = builder.get_object("cover")
        self.set_cover()
        self.update_state()

        builder.get_object("title").set_label(self._album.name)
        if self._album.year:
            year = builder.get_object("year")
            year.set_label(self._album.year)
            year.show()

        self.add(builder.get_object("widget"))

        # TODO: Remove this test later
        if self._pop_allowed:
            self._menu = builder.get_object("menu")
            self._menu.connect("clicked", self._pop_menu)
            self._menu.show()
    def __init__(self, object, button):
        """
            Init widget
            @param object as Track/Album
            @param button as Gtk.Button
        """
        Gtk.Grid.__init__(self)
        self.__object = object
        self.__button = button

        can_launch = False

        if self.__object.is_web:
            if self.__object.genre_ids == [Type.CHARTS]:
                if isinstance(self.__object, Album):
                    save = HoverWidget('document-save-symbolic',
                                       self.__save_object)
                    save.set_tooltip_text(_("Save into collection"))
                    save.set_margin_end(10)
                    save.show()
            else:
                trash = HoverWidget('user-trash-symbolic',
                                    self.__remove_object)
                if isinstance(self.__object, Album):
                    trash.set_tooltip_text(_("Remove album"))
                else:
                    trash.set_tooltip_text(_("Remove track"))
                trash.set_margin_end(10)
                trash.show()
        else:
            # Check portal for tag editor
            try:
                bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
                proxy = Gio.DBusProxy.new_sync(
                                            bus, Gio.DBusProxyFlags.NONE, None,
                                            'org.gnome.Lollypop.Portal',
                                            '/org/gnome/LollypopPortal',
                                            'org.gnome.Lollypop.Portal', None)
                can_launch = proxy.call_sync('CanLaunchTagEditor', None,
                                             Gio.DBusCallFlags.NO_AUTO_START,
                                             500, None)[0]
            except Exception as e:
                print("ContextWidget::__init__():", e)
            if can_launch:
                edit = HoverWidget('document-properties-symbolic',
                                   self.__edit_tags)
                edit.set_tooltip_text(_("Modify information"))
                edit.set_margin_end(10)
                edit.show()

        playlist = HoverWidget('view-list-symbolic',
                               self.__show_playlist_manager)
        playlist.set_tooltip_text(_("Playlists"))
        playlist.show()

        if isinstance(self.__object, Album):
            if Lp().player.album_in_queue(self.__object):
                queue = HoverWidget('list-remove-symbolic',
                                    self.__add_to_queue)
                queue.set_tooltip_text(_("Remove from queue"))
            else:
                queue = HoverWidget('list-add-symbolic', self.__add_to_queue)
                queue.set_tooltip_text(_("Add to queue"))
            queue.set_margin_start(10)
            queue.show()
        else:
            rating = RatingWidget(object)
            rating.set_margin_top(5)
            rating.set_margin_bottom(5)
            rating.set_property('halign', Gtk.Align.END)
            rating.set_property('hexpand', True)
            rating.show()

            loved = LovedWidget(object.id)
            loved.set_margin_end(5)
            loved.set_margin_top(5)
            loved.set_margin_bottom(5)
            loved.show()

            if self.__object.is_web:
                web = Gtk.LinkButton(self.__object.uri)
                icon = Gtk.Image.new_from_icon_name('web-browser-symbolic',
                                                    Gtk.IconSize.MENU)
                web.set_image(icon)
                web.get_style_context().add_class('no-padding')
                web.set_margin_start(5)
                web.set_tooltip_text(self.__object.uri)
                web.show_all()
                uri = "https://www.youtube.com/results?search_query=%s" %\
                    (self.__object.artists[0] + " " + self.__object.name,)
                search = Gtk.LinkButton(uri)
                icon = Gtk.Image.new_from_icon_name('edit-find-symbolic',
                                                    Gtk.IconSize.MENU)
                search.set_image(icon)
                search.get_style_context().add_class('no-padding')
                search.set_tooltip_text(uri)
                search.show_all()

        if self.__object.is_web:
            if self.__object.genre_ids == [Type.CHARTS]:
                if isinstance(self.__object, Album):
                    self.add(save)
            else:
                self.add(trash)
        elif can_launch:
            self.add(edit)
        self.add(playlist)
        if isinstance(self.__object, Album):
            self.add(queue)
        else:
            if self.__object.album.is_web:
                self.add(web)
                self.add(search)
            self.add(rating)
            self.add(loved)
Example #34
0
    def __init__(self, album_id, genre_ids, artist_ids, update_albums=True):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param lazy as LazyLoadingView
            @param update albums as bool: update albums on play
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids)
        # Check if we need to limit the view to artist album
        for artist_id in self._album.artist_ids:
            if artist_id in artist_ids:
                self._album.set_artists(artist_ids)
        self._width = None
        self._orientation = None
        self._stop = False
        self._child_height = TrackRow.get_best_height(self)
        # Discs to load, will be emptied
        self._discs = self._album.discs
        self._locked_widget_right = True
        self._artist_ids = artist_ids
        self._limit_to_current = not update_albums
        self.set_property('height-request',
                          ArtSize.BIG * self.get_scale_factor())
        self.connect('size-allocate', self._on_size_allocate)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/%s.ui' %
                                  type(self).__name__)
        self._widget = builder.get_object('widget')
        self._play_button = builder.get_object('play-button')
        self._play_all_button = builder.get_object('playall-button')
        self._artwork_button = builder.get_object('artwork-button')
        self._action_button = builder.get_object('action-button')
        self._action_event = builder.get_object('action-event')
        builder.connect_signals(self)

        rating = RatingWidget(self._album)
        rating.show()
        self._coverbox = builder.get_object('coverbox')
        # 6 for 2*3px (application.css)
        self._coverbox.set_property('width-request',
                                    ArtSize.BIG * self.get_scale_factor() + 6)
        self._coverbox.add(rating)
        if Lp().window.get_view_width() < WindowSize.MEDIUM:
            self._coverbox.hide()

        self._artist_label = builder.get_object('artist')
        if len(artist_ids) > 1:
            self._artist_label.set_text(", ".join(self._album.artists))
            self._artist_label.show()
        label = builder.get_object('duration')
        duration = Lp().albums.get_duration(album_id, genre_ids)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)

        self._box = Gtk.Grid()
        self._box.set_column_homogeneous(True)
        self._box.set_property('valign', Gtk.Align.START)
        self._box.show()
        builder.get_object('albuminfo').add(self._box)

        self._tracks_left = {}
        self._tracks_right = {}

        self._cover = builder.get_object('cover')
        self._cover.get_style_context().add_class('cover-frame')
        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        for disc in self._discs:
            self._add_disc_container(disc.number)
            self._set_disc_height(disc)

        self.add(self._widget)
        # We start transparent, we switch opaque at size allocation
        # This prevent artifacts
        self.set_opacity(0)

        self._menu = builder.get_object('menu')
        self._menu.connect('clicked', self._pop_menu)
        # TODO Remove this later
        if Gtk.get_minor_version() > 16:
            self._menu.show()
        else:
            self.connect('map', self._on_map)
Example #35
0
    def __init__(self, object, button):
        """
            Init widget
            @param object as Track/Album
            @param button as Gtk.Button
        """
        Gtk.Grid.__init__(self)
        self.__object = object
        self.__button = button

        can_launch = False

        if self.__object.is_web:
            if self.__object.genre_ids == [Type.CHARTS]:
                if isinstance(self.__object, Album):
                    save = HoverWidget('document-save-symbolic',
                                       self.__save_object)
                    save.set_tooltip_text(_("Save into collection"))
                    save.set_margin_end(10)
                    save.show()
            else:
                trash = HoverWidget('user-trash-symbolic',
                                    self.__remove_object)
                if isinstance(self.__object, Album):
                    trash.set_tooltip_text(_("Remove album"))
                else:
                    trash.set_tooltip_text(_("Remove track"))
                trash.set_margin_end(10)
                trash.show()
        else:
            # Check portal for tag editor
            try:
                bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
                proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE,
                                               None,
                                               'org.gnome.Lollypop.Portal',
                                               '/org/gnome/LollypopPortal',
                                               'org.gnome.Lollypop.Portal',
                                               None)
                can_launch = proxy.call_sync('CanLaunchTagEditor', None,
                                             Gio.DBusCallFlags.NO_AUTO_START,
                                             500, None)[0]
            except:
                print("You are missing lollypop-portal: "
                      "https://github.com/gnumdk/lollypop-portal")
            if can_launch:
                edit = HoverWidget('document-properties-symbolic',
                                   self.__edit_tags)
                edit.set_tooltip_text(_("Modify information"))
                edit.set_margin_end(10)
                edit.show()

        playlist = HoverWidget('view-list-symbolic',
                               self.__show_playlist_manager)
        playlist.set_tooltip_text(_("Playlists"))
        playlist.show()

        if isinstance(self.__object, Album):
            if Lp().player.album_in_queue(self.__object):
                queue = HoverWidget('list-remove-symbolic',
                                    self.__add_to_queue)
                queue.set_tooltip_text(_("Remove from queue"))
            else:
                queue = HoverWidget('list-add-symbolic', self.__add_to_queue)
                queue.set_tooltip_text(_("Add to queue"))
            queue.set_margin_start(10)
            queue.show()
        else:
            rating = RatingWidget(object)
            rating.set_margin_top(5)
            rating.set_margin_end(10)
            rating.set_margin_bottom(5)
            rating.set_property('halign', Gtk.Align.END)
            rating.set_property('hexpand', True)
            rating.show()

            loved = LovedWidget(object)
            loved.set_margin_end(5)
            loved.set_margin_top(5)
            loved.set_margin_bottom(5)
            loved.show()

            if self.__object.is_web:
                web = Gtk.LinkButton(self.__object.uri)
                icon = Gtk.Image.new_from_icon_name('web-browser-symbolic',
                                                    Gtk.IconSize.MENU)
                web.set_image(icon)
                web.get_style_context().add_class('no-padding')
                web.set_margin_start(5)
                web.set_tooltip_text(self.__object.uri)
                web.show_all()
                uri = "https://www.youtube.com/results?search_query=%s" %\
                    (self.__object.artists[0] + " " + self.__object.name,)
                search = Gtk.LinkButton(uri)
                icon = Gtk.Image.new_from_icon_name('edit-find-symbolic',
                                                    Gtk.IconSize.MENU)
                search.set_image(icon)
                search.get_style_context().add_class('no-padding')
                search.set_tooltip_text(uri)
                search.show_all()

        if self.__object.is_web:
            if self.__object.genre_ids == [Type.CHARTS]:
                if isinstance(self.__object, Album):
                    self.add(save)
            else:
                self.add(trash)
        elif can_launch:
            self.add(edit)
        self.add(playlist)
        if isinstance(self.__object, Album):
            self.add(queue)
        else:
            if self.__object.album.is_web:
                self.add(web)
                self.add(search)
            self.add(rating)
            self.add(loved)
Example #36
0
    def populate(self):
        """
            Populate widget content
        """
        if self._widget is None:
            OverlayAlbumHelper.__init__(self)
            self.__context = None
            grid = Gtk.Grid()
            grid.set_margin_start(5)
            grid.set_margin_end(5)
            grid.set_row_spacing(1)
            grid.set_vexpand(True)
            grid.show()
            self.__title_label = Gtk.Label()
            self.__title_label.set_margin_end(10)
            self.__title_label.set_ellipsize(Pango.EllipsizeMode.END)
            self.__title_label.get_style_context().add_class("dim-label")
            self.__title_label.set_property("has-tooltip", True)
            self.__title_label.connect("query-tooltip",
                                       self.__on_query_tooltip)
            self.__title_label.show()
            self.__artist_label = Gtk.Label()
            self.__artist_label.set_margin_end(10)
            self.__artist_label.set_ellipsize(Pango.EllipsizeMode.END)
            self.__artist_label.set_property("has-tooltip", True)
            self.__artist_label.connect("query-tooltip",
                                        self.__on_query_tooltip)
            self.__artist_label.show()
            self.__year_label = Gtk.Label()
            self.__year_label.set_margin_end(10)
            self.__year_label.get_style_context().add_class("dim-label")
            self.__year_label.show()
            self.__duration_label = Gtk.Label()
            self.__duration_label.get_style_context().add_class("dim-label")
            self.__duration_label.show()
            self.__context_button = Gtk.Button.new_from_icon_name(
                "go-next-symbolic", Gtk.IconSize.BUTTON)
            self.__context_button.set_relief(Gtk.ReliefStyle.NONE)
            self.__context_button.connect("clicked", self.__on_context_clicked)
            self.__context_button.get_style_context().add_class("menu-button")
            self.__context_button.get_style_context().add_class(
                                                          "album-menu-button")
            self.__context_button.show()
            self._widget = Gtk.Grid()
            self._widget.set_orientation(Gtk.Orientation.VERTICAL)
            self._widget.set_row_spacing(2)
            self._widget.show()
            self.__header = Gtk.Grid()
            self.__header.add(self.__artist_label)
            self.__header.add(self.__title_label)
            self.__header.add(self.__year_label)
            self.__header.add(self.__context_button)
            self.__header.show()
            self._widget.add(self.__header)
            separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)
            separator.show()
            self._widget.add(separator)

            loved = LovedWidget(self._album)
            loved.set_property("valign", Gtk.Align.CENTER)
            loved.set_margin_end(10)
            loved.show()

            rating = RatingWidget(self._album)
            rating.set_property("valign", Gtk.Align.CENTER)
            rating.set_property("halign", Gtk.Align.END)
            rating.set_margin_end(10)
            rating.show()

            if self.__show_cover:
                self.__header.add(self.__duration_label)
                self.__duration_label.set_hexpand(True)
                self.__duration_label.set_property("halign", Gtk.Align.END)
                eventbox = Gtk.EventBox()
                eventbox.connect("enter-notify-event", self._on_enter_notify)
                eventbox.connect("leave-notify-event", self._on_leave_notify)
                eventbox.connect("button-press-event", self._on_button_press)
                eventbox.show()
                self.set_property("valign", Gtk.Align.CENTER)
                self._artwork = App().art_helper.get_image(ArtSize.BIG,
                                                           ArtSize.BIG,
                                                           "cover-frame")
                self._artwork.show()
                eventbox.add(self._artwork)
                self.__duration_label.set_hexpand(True)
                self._overlay = Gtk.Overlay.new()
                self._overlay.add(eventbox)
                self._overlay.show()
                self.__coverbox = Gtk.Grid()
                self.__coverbox.set_row_spacing(2)
                self.__coverbox.set_margin_end(10)
                self.__coverbox.set_orientation(Gtk.Orientation.VERTICAL)
                self.__coverbox.show()
                self.__coverbox.attach(self._overlay, 0, 0, 2, 1)
                loved.set_property("halign", Gtk.Align.START)
                self.__coverbox.attach(rating, 0, 1, 1, 1)
                self.__coverbox.attach_next_to(loved,
                                               rating,
                                               Gtk.PositionType.RIGHT,
                                               1,
                                               1)
                if App().window.container.stack.get_allocation().width <\
                        Sizing.MEDIUM:
                    self.__coverbox.hide()
                if len(self._artist_ids) > 1:
                    self.__artist_label.set_text(
                        ", ".join(self._album.artists))
                    self.__artist_label.show()
            else:
                self._artwork = None
                loved.set_property("halign", Gtk.Align.END)
                self.__header.add(rating)
                self.__header.add(loved)
                rating.set_hexpand(True)
                self.__header.add(self.__duration_label)
                self.__artist_label.set_text(", ".join(self._album.artists))
                self.__artist_label.show()
            self.__set_duration()
            album_name = GLib.markup_escape_text(self._album.name)
            artist_name = GLib.markup_escape_text(
                ", ".join(self._album.artists))
            self.__title_label.set_markup("<b>%s</b>" % album_name)
            self.__artist_label.set_markup("<b>%s</b>" % artist_name)
            if self._album.year is not None:
                self.__year_label.set_label(str(self._album.year))
                self.__year_label.show()
            self.set_selection()
            if self._artwork is None:
                TracksView.populate(self)
                self._widget.add(self._responsive_widget)
                self._responsive_widget.show()
            else:
                grid.add(self.__coverbox)
                self.set_artwork()
            grid.add(self._widget)
            self.add(grid)
        else:
            TracksView.populate(self)
Example #37
0
    def __init__(self, album_id, genre_ids, artist_ids, popover, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param popover as bool
            @param size group as Gtk.SizeGroup
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids)
        self._artist_ids = artist_ids
        self._pop_allowed = not popover or Gtk.get_minor_version() > 16
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/%s.ui' %
                                  type(self).__name__)
        self._color = builder.get_object('color')
        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object('coverbox').add(rating)
        builder.connect_signals(self)

        self._artist_label = builder.get_object('artist')
        if len(artist_ids) > 1:
            self._artist_label.set_text(self._album.artist_name)
            self._artist_label.show()
        label = builder.get_object('duration')
        duration = Lp().albums.get_duration(album_id, genre_ids)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)

        grid = builder.get_object('tracks')
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
            self._tracks_left[index] = TracksWidget(self._pop_allowed, True)
            self._tracks_right[index] = TracksWidget(self._pop_allowed, True)
            grid.attach(self._tracks_left[index], 0, i, 1, 1)
            grid.attach(self._tracks_right[index], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect('activated', self._on_activated)
            self._tracks_left[index].connect('button-press-event',
                                             self._on_button_press_event)
            self._tracks_right[index].connect('activated', self._on_activated)
            self._tracks_right[index].connect('button-press-event',
                                              self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        self.add(builder.get_object('widget'))

        # TODO: Remove this test later
        if self._pop_allowed:
            self._menu = builder.get_object('menu')
            self._menu.connect('clicked', self._pop_menu)
            self._menu.show()
Example #38
0
    def __init__(self, track, menu):
        """
            Init widget
            @param track as Track
            @param menu as Gio.Menu
        """
        Gtk.Popover.__init__(self)
        self.bind_model(menu, None)

        if track.year != track.album.year:
            track_year = str(track.year)
        else:
            track_year = ""

        rating = RatingWidget(track)
        rating.set_margin_top(5)
        rating.set_margin_bottom(5)
        rating.set_property('halign', Gtk.Align.START)
        rating.set_property('hexpand', True)
        rating.show()

        loved = LovedWidget(track.id)
        loved.set_margin_end(5)
        loved.set_margin_top(5)
        loved.set_margin_bottom(5)
        if track_year == "":
            loved.set_property('halign', Gtk.Align.END)
        else:
            loved.set_property('halign', Gtk.Align.CENTER)
        loved.set_property('hexpand', True)
        loved.show()

        if track_year != "":
            year = Gtk.Label()
            year.set_text(track_year)
            year.set_margin_end(5)
            year.set_margin_top(5)
            year.set_margin_bottom(5)
            year.get_style_context().add_class('dim-label')
            year.set_property('halign', Gtk.Align.END)
            year.set_property('hexpand', True)
            year.show()

        # Hack to add two widgets in popover
        # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable)
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)

        stack = Gtk.Stack()
        stack.add_named(grid, 'main')
        stack.show_all()

        menu_widget = self.get_child()
        menu_widget.reparent(grid)

        separator = Gtk.Separator()
        separator.show()

        grid.add(separator)
        hgrid = Gtk.Grid()
        hgrid.add(rating)
        hgrid.add(loved)
        if track_year != "":
            hgrid.add(year)
        hgrid.show()
        grid.add(hgrid)
        self.add(stack)
class AlbumBannerWidget(Gtk.Bin):
    """
        Banner for album
    """

    def __init__(self, album, view_type=ViewType.DEFAULT):
        """
            Init cover widget
            @param album
            @param view_type as ViewType
        """
        Gtk.Bin.__init__(self)
        self.__view_type = view_type
        self.__height = None
        self.__width = 0
        self.__cloud_image = None
        self.__allocation_timeout_id = None
        self.__album = album
        self.set_property("valign", Gtk.Align.START)
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/AlbumBannerWidget.ui")
        builder.connect_signals(self)
        self.__title_label = builder.get_object("name_label")
        self.__title_label.connect("query-tooltip", on_query_tooltip)
        self.__year_label = builder.get_object("year_label")
        self.__duration_label = builder.get_object("duration_label")
        self.__menu_button = builder.get_object("menu_button")
        self.__cover_widget = CoverWidget(album, view_type)
        self.__cover_widget.set_vexpand(True)
        self.__cover_widget.show()
        album_name = GLib.markup_escape_text(album.name)
        markup = "<b>%s</b>" % album_name
        if view_type & ViewType.ALBUM:
            artist_name = GLib.markup_escape_text(", ".join(album.artists))
            if view_type & ViewType.SMALL:
                markup += "\n<span alpha='40000'>%s</span>" % artist_name
            else:
                markup += "\n<span size='x-small' alpha='40000'>%s</span>" %\
                                                                  artist_name
        self.__title_label.set_markup(markup)
        if album.year is not None:
            self.__year_label.set_text(str(album.year))
        else:
            self.__year_label.hide()
        year_eventbox = builder.get_object("year_eventbox")
        year_eventbox.connect("realize", on_realize)
        year_eventbox.connect("button-release-event",
                              self.__on_year_button_release_event)
        duration = App().albums.get_duration(self.__album.id,
                                             self.__album.genre_ids)
        self.__duration_label.set_text(get_human_duration(duration))
        self.__artwork = builder.get_object("artwork")
        self.__grid = builder.get_object("grid")
        self.__widget = builder.get_object("widget")
        if view_type & ViewType.ALBUM:
            self.__menu_button.get_style_context().add_class(
                "black-transparent")
            self.get_style_context().add_class("black")
            self.__artwork.get_style_context().add_class("black")
            self.connect("size-allocate", self.__on_size_allocate)
            self.connect("destroy", self.__on_destroy)
            self.__art_signal_id = App().art.connect(
                                               "album-artwork-changed",
                                               self.__on_album_artwork_changed)
        else:
            self.__grid.get_style_context().add_class("banner-frame")
        self.__grid.attach(self.__cover_widget, 0, 0, 1, 3)
        self.__rating_grid = builder.get_object("rating_grid")
        if album.mtime <= 0:
            self.__cloud_image = Gtk.Image.new()
            self.__cloud_image.show()
            self.__cloud_image.set_margin_start(MARGIN)
            self.__rating_grid.attach(self.__cloud_image, 1, 0, 1, 1)
        self.__rating_widget = RatingWidget(album, Gtk.IconSize.INVALID)
        self.__rating_widget.set_property("halign", Gtk.Align.START)
        self.__rating_widget.set_property("valign", Gtk.Align.CENTER)
        self.__rating_widget.show()
        self.__rating_grid.attach(self.__rating_widget, 2, 0, 1, 1)
        self.__loved_widget = LovedWidget(album, Gtk.IconSize.INVALID)
        self.__loved_widget.set_margin_start(10)
        self.__loved_widget.set_property("halign", Gtk.Align.START)
        self.__loved_widget.set_property("valign", Gtk.Align.CENTER)
        self.__loved_widget.show()
        self.__rating_grid.attach(self.__loved_widget, 3, 0, 1, 1)
        self.add(self.__widget)
        self.__cover_widget.set_margin_start(MARGIN)
        self.__year_label.set_margin_end(MARGIN)
        self.__duration_label.set_margin_start(MARGIN)
        self.__rating_grid.set_margin_end(MARGIN)
        self.set_view_type(view_type)

    def set_view_type(self, view_type):
        """
            Update widget internals for view_type
            @param view_type as ViewType
        """
        self.__view_type = view_type
        art_size = 0
        if view_type & ViewType.SMALL:
            art_size = ArtSize.LARGE
            style = "menu-button"
            icon_size = Gtk.IconSize.BUTTON
            self.__title_label.get_style_context().add_class(
                "text-large")
            self.__year_label.get_style_context().add_class(
                "text-large")
        elif view_type & ViewType.MEDIUM:
            art_size = ArtSize.BANNER
            style = "menu-button-48"
            icon_size = Gtk.IconSize.LARGE_TOOLBAR
            self.__title_label.get_style_context().add_class(
                "text-x-large")
            self.__year_label.get_style_context().add_class(
                "text-large")
        else:
            art_size = ArtSize.BANNER
            style = "menu-button-48"
            icon_size = Gtk.IconSize.LARGE_TOOLBAR
            self.__title_label.get_style_context().add_class(
                "text-xx-large")
            self.__year_label.get_style_context().add_class(
                "text-x-large")
        self.__rating_widget.set_icon_size(icon_size)
        self.__loved_widget.set_icon_size(icon_size)
        if self.__cloud_image is not None:
            self.__cloud_image.set_from_icon_name("goa-panel-symbolic",
                                                  icon_size)
        self.__cover_widget.set_artwork(art_size)
        menu_button_style_context = self.__menu_button.get_style_context()
        menu_button_style_context.remove_class("menu-button-48")
        menu_button_style_context.remove_class("menu-button")
        menu_button_style_context.add_class(style)
        self.__menu_button.get_image().set_from_icon_name(
                                                   "view-more-symbolic",
                                                   icon_size)
        self.set_height(self.height)

    def set_height(self, height):
        """
            Set height
            @param height as int
        """
        if height < self.default_height:
            self.__height = height
            # Make grid cover artwork
            # No idea why...
            self.__grid.set_size_request(-1, height + 1)
            self.__cover_widget.hide()
            self.__duration_label.hide()
            self.__rating_grid.hide()
            self.__year_label.set_vexpand(True)
            self.__set_text_height(True)
        else:
            self.__height = None
            # Make grid cover artwork
            # No idea why...
            self.__grid.set_size_request(-1, height + 1)
            self.__cover_widget.show()
            self.__duration_label.show()
            self.__rating_grid.show()
            self.__year_label.set_vexpand(False)
            self.__set_text_height(False)

    def do_get_preferred_width(self):
        """
            Force preferred width
        """
        return (0, 0)

    def do_get_preferred_height(self):
        """
            Force preferred height
        """
        return (self.height, self.height)

    def set_selected(self, selected):
        """
            Mark widget as selected
            @param selected as bool
        """
        if selected:
            self.__grid.set_state_flags(Gtk.StateFlags.SELECTED, True)
        else:
            self.__grid.set_state_flags(Gtk.StateFlags.NORMAL, True)

    @property
    def height(self):
        """
            Get height
            @return int
        """
        return self.__height if self.__height is not None\
            else self.default_height

    @property
    def default_height(self):
        """
            Get default height
        """
        if self.__view_type & ViewType.SMALL:
            return ArtSize.LARGE + 40
        elif self.__view_type & ViewType.MEDIUM:
            return ArtSize.BANNER + 40
        else:
            return ArtSize.BANNER + 40

#######################
# PROTECTED           #
#######################
    def _on_menu_button_clicked(self, button):
        """
            Show album menu
            @param button as Gtk.Button
        """
        from lollypop.menu_objects import AlbumMenu
        menu = AlbumMenu(self.__album, self.__view_type)
        popover = Gtk.Popover.new_from_model(button, menu)
        popover.popup()

#######################
# PRIVATE             #
#######################
    def __set_text_height(self, collapsed):
        """
            Set text height
            @param collapsed as bool
        """
        title_context = self.__title_label.get_style_context()
        year_context = self.__year_label.get_style_context()
        for c in title_context.list_classes():
            title_context.remove_class(c)
        for c in year_context.list_classes():
            title_context.remove_class(c)
        if self.__view_type & ViewType.SMALL:
            if not collapsed:
                self.__title_label.get_style_context().add_class("text-large")
        # Collapsed not implemented for MEDIUM
        elif self.__view_type & ViewType.MEDIUM:
            self.__title_label.get_style_context().add_class(
                "text-x-large")
            self.__year_label.get_style_context().add_class(
                "text-large")
        elif collapsed:
            self.__title_label.get_style_context().add_class(
                "text-x-large")
            self.__year_label.get_style_context().add_class(
                "text-large")
        else:
            self.__title_label.get_style_context().add_class(
                "text-xx-large")
            self.__year_label.get_style_context().add_class(
                "text-x-large")

    def __handle_size_allocate(self, allocation):
        """
            Change box max/min children
            @param allocation as Gtk.Allocation
        """
        self.__allocation_timeout_id = None
        if allocation.width == 1 or self.__width == allocation.width:
            return
        self.__width = allocation.width
        App().art_helper.set_album_artwork(
                self.__album,
                # +100 to prevent resize lag
                allocation.width + 100,
                self.default_height,
                self.__artwork.get_scale_factor(),
                ArtBehaviour.BLUR_HARD |
                ArtBehaviour.DARKER,
                self.__on_album_artwork)

    def __on_destroy(self, widget):
        """
            Disconnect signal
            @param widget as Gtk.Widget
        """
        if self.__art_signal_id is not None:
            App().art.disconnect(self.__art_signal_id)

    def __on_album_artwork_changed(self, art, album_id):
        """
            Update cover for album_id
            @param art as Art
            @param album_id as int
        """
        if album_id == self.__album.id:
            App().art_helper.set_album_artwork(
                            self.__album,
                            # +100 to prevent resize lag
                            self.get_allocated_width() + 100,
                            self.default_height,
                            self.__artwork.get_scale_factor(),
                            ArtBehaviour.BLUR_HARD |
                            ArtBehaviour.DARKER,
                            self.__on_album_artwork)

    def __on_album_artwork(self, surface):
        """
            Set album artwork
            @param surface as str
        """
        if surface is not None:
            self.__artwork.set_from_surface(surface)

    def __on_year_button_release_event(self, widget, event):
        """
            Show year view
            @param widget as Gtk.Widget
            @param event as Gdk.event
        """
        App().window.emit("can-go-back-changed", True)
        App().window.emit("show-can-go-back", True)
        App().window.container.show_view([Type.YEARS], [self.__album.year])

    def __on_size_allocate(self, widget, allocation):
        """
            Delayed handling
            @param widget as Gtk.Widget
            @param allocation as Gtk.Allocation
        """
        if self.__allocation_timeout_id is not None:
            GLib.source_remove(self.__allocation_timeout_id)
        self.__allocation_timeout_id = GLib.idle_add(
            self.__handle_size_allocate, allocation)