Beispiel #1
0
    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_title("Lollypop")
        PlaybackController.__init__(self)
        ProgressController.__init__(self)
        self.set_application(app)
        self.__timeout1 = None
        self.__timeout2 = None
        self.__signal1_id = None
        self.__signal2_id = None
        self.set_decorated(False)
        self.__parent = parent

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

        # Calculate cover size
        screen = Gdk.Screen.get_default()
        monitor = screen.get_primary_monitor()
        geometry = screen.get_monitor_geometry(monitor)
        # We want 500 and 200 in full hd
        scale = self.get_scale_factor()
        if geometry.width > geometry.height:
            artsize = int(ArtSize.FULLSCREEN * geometry.width / 1920 / scale)
        else:
            artsize = int(ArtSize.FULLSCREEN * geometry.height / 1920 / scale)
        InfosController.__init__(self, artsize)

        self._play_btn = builder.get_object('play_btn')
        self._next_btn = builder.get_object('next_btn')
        self._prev_btn = builder.get_object('prev_btn')
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object('play_image')
        self._pause_image = builder.get_object('pause_image')
        close_btn = builder.get_object('close_btn')
        close_btn.connect('clicked', self.__destroy)
        self._cover = builder.get_object('cover')
        self._title_label = builder.get_object('title')
        self._artist_label = builder.get_object('artist')
        self._album_label = builder.get_object('album')

        self._datetime = builder.get_object('datetime')

        self._progress = builder.get_object('progress_scale')
        self._timelabel = builder.get_object('playback')
        self._total_time_label = builder.get_object('duration')
        self.connect('key-release-event', self.__on_key_release_event)
        self.add(builder.get_object('widget'))
Beispiel #2
0
    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self.connect('show', self.__on_show)
        self.connect('hide', self.__on_hide)
        self.set_hexpand(True)
        self.__next_popover = NextPopover()
        self.__search = None
        self.__next_was_inhibited = False
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self.__grid_next = builder.get_object('grid-next')

        self.__shuffle_button = builder.get_object('shuffle-button')
        self.__shuffle_image = builder.get_object('shuffle-button-image')
        shuffleAction = Gio.SimpleAction.new('shuffle-button', None)
        shuffleAction.connect('activate', self.__activate_shuffle_button)
        app.add_action(shuffleAction)
        app.set_accels_for_action("app.shuffle-button", ["<Control>r"])
        Lp().settings.connect('changed::shuffle', self.__on_shuffle_changed)

        self.__party_button = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self.__activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        self.__search_button = builder.get_object('search-button')
        search_action = Gio.SimpleAction.new('search', None)
        search_action.connect('activate', self._on_search_button_clicked)
        app.add_action(search_action)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self.__settings_button = builder.get_object('settings-button')

        self.__list_button = builder.get_object('list-button')
        self.__list_button.set_property('has-tooltip', True)
        self.__list_button.connect('query-tooltip',
                                   self.__on_list_button_query_tooltip)
        list_action = Gio.SimpleAction.new('list', None)
        list_action.connect('activate', self._on_list_button_clicked)
        app.add_action(list_action)
        app.set_accels_for_action("app.list", ["<Control>i"])
        self.__list_popover = None
        Lp().player.connect('party-changed', self.__on_party_changed)
        Lp().player.connect('lock-changed', self.__on_lock_changed)
Beispiel #3
0
    def __init__(self):
        """
            Init toolbar
        """
        Gtk.Bin.__init__(self)
        self.connect('show', self.__on_show)
        self.connect('hide', self.__on_hide)
        self.set_hexpand(True)
        self.__next_popover = NextPopover()
        self.__search = None
        self.__next_was_inhibited = False
        self.__timeout_id = None
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self.__grid_next = builder.get_object('grid-next')

        self.__shuffle_button = builder.get_object('shuffle-button')
        self.__shuffle_image = builder.get_object('shuffle-button-image')
        shuffleAction = Gio.SimpleAction.new('shuffle-button', None)
        shuffleAction.connect('activate', self.__activate_shuffle_button)
        Lp().add_action(shuffleAction)
        Lp().set_accels_for_action("app.shuffle-button", ["<Control>r"])
        Lp().settings.connect('changed::shuffle', self.__on_playback_changed)
        Lp().settings.connect('changed::playback', self.__on_playback_changed)

        self.__party_button = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self.__activate_party_button)
        Lp().add_action(party_action)
        Lp().set_accels_for_action("app.party", ["<Control>p"])

        self.__search_button = builder.get_object('search-button')
        self.__helper = TouchHelper(self.__search_button, "search",
                                    "<Control>f")
        self.__helper.set_long_func(self.__on_search_long)
        self.__helper.set_short_func(self.__on_search_short)

        self.__settings_button = builder.get_object('settings-button')

        self.__list_button = builder.get_object('list-button')
        self.__list_button.set_property('has-tooltip', True)
        self.__list_button.connect('query-tooltip',
                                   self.__on_list_button_query_tooltip)
        self.__list_popover = None
        Lp().player.connect('party-changed', self.__on_party_changed)
        Lp().player.connect('lock-changed', self.__on_lock_changed)
Beispiel #4
0
    def __init__(self, app):
        Gtk.Bin.__init__(self)
        self._pop_next = NextPopover()
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._shuffle_btn = builder.get_object('shuffle-button')
        self._shuffle_btn_image = builder.get_object('shuffle-button-image')
        self._set_shuffle_icon()
        Lp.settings.connect('changed::shuffle', self._shuffle_btn_aspect)

        self._party_btn = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        search_button = builder.get_object('search-button')
        self._search = SearchWidget(self)
        self._search.set_relative_to(search_button)
        searchAction = Gio.SimpleAction.new('search', None)
        searchAction.connect('activate', self._on_search_btn_clicked)
        app.add_action(searchAction)
        app.set_accels_for_action("app.search", ["<Control>f"])

        queue_button = builder.get_object('queue-button')
        self._queue = QueueWidget()
        self._queue.set_relative_to(queue_button)

        self._settings_button = builder.get_object('settings-button')

        Lp.player.connect('party-changed', self._on_party_changed)
Beispiel #5
0
    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_application(app)
        self._timeout1 = None
        self._timeout2 = None
        self._seeking = False
        self._signal1_id = None
        self._signal2_id = None
        self.set_decorated(False)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/FullScreen.ui')
        main_widget = builder.get_object('fs')
        self.add(main_widget)
        self._prev_btn = builder.get_object('prev_btn')
        self._prev_btn.connect('clicked', self._on_prev_btn_clicked)
        self._play_btn = builder.get_object('play_btn')
        self._play_btn.connect('clicked', self._on_play_btn_clicked)
        self._next_btn = builder.get_object('next_btn')
        self._next_btn.connect('clicked', self._on_next_btn_clicked)
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object('play_image')
        self._pause_image = builder.get_object('pause_image')
        close_btn = builder.get_object('close_btn')
        close_btn.connect('clicked', self._destroy)
        self._cover = builder.get_object('cover')
        self._title = builder.get_object('title')
        self._artist = builder.get_object('artist')
        self._album = builder.get_object('album')

        self._datetime = builder.get_object('datetime')

        self._progress = builder.get_object('progress_scale')
        self._progress.connect('button-release-event',
                               self._on_progress_release_button)
        self._progress.connect('button-press-event',
                               self._on_progress_press_button)
        self._timelabel = builder.get_object('playback')
        self._total_time_label = builder.get_object('duration')
        self.connect('key-release-event', self._on_key_release_event)
Beispiel #6
0
    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_title("Lollypop")
        PlaybackController.__init__(self)
        ProgressController.__init__(self)
        self.set_application(app)
        self._timeout1 = None
        self._timeout2 = None
        self._seeking = False
        self._signal1_id = None
        self._signal2_id = None
        self.set_decorated(False)
        self._parent = parent

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

        # Calculate cover size
        screen = Gdk.Screen.get_default()
        monitor = screen.get_primary_monitor()
        geometry = screen.get_monitor_geometry(monitor)
        # We want 500 and 200 in full hd
        scale = self.get_scale_factor()
        if geometry.width > geometry.height:
            artsize = int(ArtSize.FULLSCREEN*geometry.width/1920/scale)
        else:
            artsize = int(ArtSize.FULLSCREEN*geometry.height/1920/scale)
        InfosController.__init__(self, artsize)

        self._play_btn = builder.get_object('play_btn')
        self._next_btn = builder.get_object('next_btn')
        self._prev_btn = builder.get_object('prev_btn')
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object('play_image')
        self._pause_image = builder.get_object('pause_image')
        close_btn = builder.get_object('close_btn')
        close_btn.connect('clicked', self._destroy)
        self._cover = builder.get_object('cover')
        self._title_label = builder.get_object('title')
        self._artist_label = builder.get_object('artist')
        self._album_label = builder.get_object('album')

        self._datetime = builder.get_object('datetime')

        self._progress = builder.get_object('progress_scale')
        self._timelabel = builder.get_object('playback')
        self._total_time_label = builder.get_object('duration')
        self.connect('key-release-event', self._on_key_release_event)
        self.add(builder.get_object('widget'))
Beispiel #7
0
    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self.connect('show', self._on_show)
        self.connect('hide', self._on_hide)
        self._next_popover = NextPopover()
        self._search = None
        self._next_was_inhibited = False
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._grid_next = builder.get_object('grid-next')

        self._shuffle_button = builder.get_object('shuffle-button')
        self._shuffle_image = builder.get_object('shuffle-button-image')
        shuffleAction = Gio.SimpleAction.new('shuffle-button', None)
        shuffleAction.connect('activate', self._activate_shuffle_button)
        app.add_action(shuffleAction)
        app.set_accels_for_action("app.shuffle-button", ["<Control>r"])
        Lp().settings.connect('changed::shuffle', self._on_shuffle_changed)

        self._party_button = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        self._search_button = builder.get_object('search-button')
        search_action = Gio.SimpleAction.new('search', None)
        search_action.connect('activate', self._on_search_button_clicked)
        app.add_action(search_action)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self._settings_button = builder.get_object('settings-button')

        self._list_button = builder.get_object('list-button')
        self._list_button.set_property('has-tooltip', True)
        self._list_button.connect('query-tooltip',
                                  self._on_list_button_query_tooltip)
        list_action = Gio.SimpleAction.new('list', None)
        list_action.connect('activate', self._on_list_button_clicked)
        app.add_action(list_action)
        app.set_accels_for_action("app.list", ["<Control>i"])
        self._list_popover = None
        Lp().player.connect('party-changed', self._on_party_changed)
        Lp().player.connect('state-changed', self._on_lock_changed)
Beispiel #8
0
    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self.connect('show', self._on_show)
        self.connect('hide', self._on_hide)
        self._pop_next = NextPopover()
        self._queue = None
        self._search = None
        self._timeout_id = None
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._grid_next = builder.get_object('grid-next')

        self._shuffle_button = builder.get_object('shuffle-button')
        self._shuffle_image = builder.get_object('shuffle-button-image')
        shuffleAction = Gio.SimpleAction.new('shuffle-button', None)
        shuffleAction.connect('activate', self._activate_shuffle_button)
        app.add_action(shuffleAction)
        app.set_accels_for_action("app.shuffle-button", ["<Control>r"])
        Lp().settings.connect('changed::shuffle', self._on_shuffle_changed)

        self._party_button = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        self._search_button = builder.get_object('search-button')
        searchAction = Gio.SimpleAction.new('search', None)
        searchAction.connect('activate', self._on_search_button_clicked)
        app.add_action(searchAction)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self._queue_button = builder.get_object('queue-button')
        queueAction = Gio.SimpleAction.new('queue', None)
        queueAction.connect('activate', self._on_queue_button_clicked)
        app.add_action(queueAction)
        app.set_accels_for_action("app.queue", ["<Control>l"])

        self._settings_button = builder.get_object('settings-button')

        Lp().player.connect('party-changed', self._on_party_changed)
        Lp().player.connect('queue-changed', self._on_queue_changed)
Beispiel #9
0
    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self._pop_next = NextPopover()
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._shuffle_btn = builder.get_object('shuffle-button')
        self._shuffle_btn_image = builder.get_object('shuffle-button-image')
        Lp().settings.connect('changed::shuffle', self._shuffle_btn_aspect)

        self._party_btn = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        search_button = builder.get_object('search-button')
        self._search = SearchPopover(self)
        self._search.set_relative_to(search_button)
        searchAction = Gio.SimpleAction.new('search', None)
        searchAction.connect('activate', self._on_search_btn_clicked)
        app.add_action(searchAction)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self._queue_button = builder.get_object('queue-button')

        self._settings_button = builder.get_object('settings-button')

        Lp().player.connect('party-changed', self._on_party_changed)
Beispiel #10
0
    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_application(app)
        self._timeout1 = None
        self._timeout2 = None
        self._seeking = False
        self._signal1_id = None
        self._signal2_id = None
        self.set_decorated(False)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/FullScreen.ui')
        main_widget = builder.get_object('fs')
        self.add(main_widget)
        self._prev_btn = builder.get_object('prev_btn')
        self._prev_btn.connect('clicked', self._on_prev_btn_clicked)
        self._play_btn = builder.get_object('play_btn')
        self._play_btn.connect('clicked', self._on_play_btn_clicked)
        self._next_btn = builder.get_object('next_btn')
        self._next_btn.connect('clicked', self._on_next_btn_clicked)
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object('play_image')
        self._pause_image = builder.get_object('pause_image')
        close_btn = builder.get_object('close_btn')
        close_btn.connect('clicked', self._destroy)
        self._cover = builder.get_object('cover')
        self._title = builder.get_object('title')
        self._artist = builder.get_object('artist')
        self._album = builder.get_object('album')

        self._datetime = builder.get_object('datetime')

        self._progress = builder.get_object('progress_scale')
        self._progress.connect('button-release-event',
                               self._on_progress_release_button)
        self._progress.connect('button-press-event',
                               self._on_progress_press_button)
        self._timelabel = builder.get_object('playback')
        self._total_time_label = builder.get_object('duration')
        self.connect('key-release-event', self._on_key_release_event)
Beispiel #11
0
    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self._pop_next = NextPopover()
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/ToolbarEnd.ui")
        builder.connect_signals(self)

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

        self._shuffle_btn = builder.get_object("shuffle-button")
        self._shuffle_btn_image = builder.get_object("shuffle-button-image")
        Lp.settings.connect("changed::shuffle", self._shuffle_btn_aspect)

        self._party_btn = builder.get_object("party-button")
        party_action = Gio.SimpleAction.new("party", None)
        party_action.connect("activate", self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        search_button = builder.get_object("search-button")
        self._search = SearchPopover(self)
        self._search.set_relative_to(search_button)
        searchAction = Gio.SimpleAction.new("search", None)
        searchAction.connect("activate", self._on_search_btn_clicked)
        app.add_action(searchAction)
        app.set_accels_for_action("app.search", ["<Control>f"])

        queue_button = builder.get_object("queue-button")
        self._queue = QueueWidget()
        self._queue.set_relative_to(queue_button)

        self._settings_button = builder.get_object("settings-button")

        Lp.player.connect("party-changed", self._on_party_changed)
Beispiel #12
0
    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_title("Lollypop")
        PlaybackController.__init__(self)
        ProgressController.__init__(self)
        self.set_application(app)
        self.__timeout1 = None
        self.__timeout2 = None
        self.__signal1_id = None
        self.__signal2_id = None
        self.set_decorated(False)
        self.__parent = parent

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

        # Calculate cover size
        screen = Gdk.Screen.get_default()
        monitor = screen.get_primary_monitor()
        geometry = screen.get_monitor_geometry(monitor)
        # We want 500 and 200 in full hd
        if geometry.width > geometry.height:
            artsize = int(ArtSize.FULLSCREEN * geometry.width / 1920)
        else:
            artsize = int(ArtSize.FULLSCREEN * geometry.height / 1920)
        InfoController.__init__(self, artsize)
        widget = builder.get_object("widget")
        self._play_btn = builder.get_object("play_btn")
        self._next_btn = builder.get_object("next_btn")
        self._prev_btn = builder.get_object("prev_btn")
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object("play_image")
        self._pause_image = builder.get_object("pause_image")
        close_btn = builder.get_object("close_btn")
        preferences = Gio.Settings.new("org.gnome.desktop.wm.preferences")
        layout = preferences.get_value("button-layout").get_string()
        if layout.split(":")[0] == "close":
            widget.attach(close_btn, 0, 0, 1, 1)
            close_btn.set_property("halign", Gtk.Align.START)
        else:
            widget.attach(close_btn, 2, 0, 1, 1)
            close_btn.set_property("halign", Gtk.Align.END)
        self._cover = builder.get_object("cover")
        self._title_label = builder.get_object("title")
        self._artist_label = builder.get_object("artist")
        self._album_label = builder.get_object("album")

        self._datetime = builder.get_object("datetime")

        self._progress = builder.get_object("progress_scale")
        self._timelabel = builder.get_object("playback")
        self._total_time_label = builder.get_object("duration")
        self.connect("key-release-event", self.__on_key_release_event)
        self.add(widget)
Beispiel #13
0
class FullScreen(Gtk.Window):
    """
        Show a fullscreen window showing current track context
    """
    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_application(app)
        self._timeout1 = None
        self._timeout2 = None
        self._seeking = False
        self._signal1_id = None
        self._signal2_id = None
        self.set_decorated(False)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/FullScreen.ui')
        main_widget = builder.get_object('fs')
        self.add(main_widget)
        self._prev_btn = builder.get_object('prev_btn')
        self._prev_btn.connect('clicked', self._on_prev_btn_clicked)
        self._play_btn = builder.get_object('play_btn')
        self._play_btn.connect('clicked', self._on_play_btn_clicked)
        self._next_btn = builder.get_object('next_btn')
        self._next_btn.connect('clicked', self._on_next_btn_clicked)
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object('play_image')
        self._pause_image = builder.get_object('pause_image')
        close_btn = builder.get_object('close_btn')
        close_btn.connect('clicked', self._destroy)
        self._cover = builder.get_object('cover')
        self._title = builder.get_object('title')
        self._artist = builder.get_object('artist')
        self._album = builder.get_object('album')

        self._datetime = builder.get_object('datetime')

        self._progress = builder.get_object('progress_scale')
        self._progress.connect('button-release-event',
                               self._on_progress_release_button)
        self._progress.connect('button-press-event',
                               self._on_progress_press_button)
        self._timelabel = builder.get_object('playback')
        self._total_time_label = builder.get_object('duration')
        self.connect('key-release-event', self._on_key_release_event)

    def do_show(self):
        """
            Init signals, set color and go party mode if nothing is playing
        """
        is_playing = Lp.player.is_playing()
        self._signal1_id = Lp.player.connect('current-changed',
                                             self._on_current_changed)
        self._signal2_id = Lp.player.connect('status-changed',
                                             self._on_status_changed)
        if is_playing:
            self._change_play_btn_status(self._pause_image, _('Pause'))
            self._on_current_changed(Lp.player)
        else:
            Lp.player.set_party(True)
        if self._timeout1 is None:
            self._timeout1 = GLib.timeout_add(1000, self._update_position)
        Gtk.Window.do_show(self)
        now = datetime.now()
        self._datetime.set_label(now.strftime('%a %d %b, %X')[:-3])
        if self._timeout2 is None:
            second = datetime.now().second
            if 60 - second > 0:
                GLib.timeout_add((60 - second) * 1000, self._update_datetime)
            else:
                self._timeout2 = GLib.timeout_add(60000, self._update_datetime)
        self._update_position()
        self.fullscreen()
        self._next_popover.set_relative_to(self._album)
        if Lp.player.next_track.id != Type.RADIOS:
            self._next_popover.show()

    def do_hide(self):
        """
            Remove signals and unset color
        """
        Gtk.Window.do_hide(self)
        if self._signal1_id is not None:
            Lp.player.disconnect(self._signal1_id)
            self._signal1_id = None
        if self._signal2_id is not None:
            Lp.player.disconnect(self._signal2_id)
            self._signal2_id = None
        if self._timeout1 is not None:
            GLib.source_remove(self._timeout1)
            self._timeout1 = None
        if self._timeout2 is not None:
            GLib.source_remove(self._timeout2)
        self._next_popover.set_relative_to(None)
        self._next_popover.hide()

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

    def _update_datetime(self):
        """
            Update datetime in headerbar
        """
        now = datetime.now()
        self._datetime.set_label(now.strftime('%a %d %b, %X')[:-3])
        if self._timeout2 is None:
            self._timeout2 = GLib.timeout_add(60000, self._update_datetime)
            return False
        return True

    def _change_play_btn_status(self, image, status):
        """
            Update play button with image and status as tooltip
            @param image as Gtk.Image
            @param status as str
        """
        self._play_btn.set_image(image)
        self._play_btn.set_tooltip_text(status)

    def _update_position(self, value=None):
        """
            Update progress bar position
            @param value as int
        """
        if not self._seeking and self._progress.is_visible():
            if value is None:
                value = Lp.player.get_position_in_track() / 1000000
            self._progress.set_value(value)
            self._timelabel.set_text(seconds_to_string(value / 60))
        return True

    def _destroy(self, widget):
        """
            Destroy self
            @param widget as Gtk.Button
        """
        self.destroy()

    def _on_current_changed(self, player):
        """
            Update View for current track
                - Cover
                - artist/title
                - reset progress bar
                - update time/total labels
            @param player as Player
        """
        if player.current_track.id is not None:
            if Lp.player.current_track.id == Type.RADIOS:
                self._timelabel.hide()
                self._total_time_label.hide()
                self._progress.hide()
                surface = Lp.art.get_radio(
                    player.current_track.artist,
                    ArtSize.MONSTER * self.get_scale_factor())
            else:
                self._timelabel.show()
                self._total_time_label.show()
                self._progress.show()
                surface = Lp.art.get_album(
                    player.current_track.album_id,
                    ArtSize.MONSTER * self.get_scale_factor())
            self._cover.set_from_surface(surface)
            del surface

            album = player.current_track.album
            if player.current_track.year != '':
                album += " (%s)" % player.current_track.year
            self._title.set_text(player.current_track.title)
            self._artist.set_text(player.current_track.artist)
            self._album.set_text(album)
            self._progress.set_value(1.0)
            self._progress.set_range(0.0, player.current_track.duration * 60)
            self._total_time_label.set_text(
                seconds_to_string(player.current_track.duration))
            self._timelabel.set_text("0:00")

            # Can add a \n in markup
            # GTK bug => https://bugzilla.gnome.org/show_bug.cgi?id=749965
            prev_artist = escape(player.prev_track.artist)
            prev_title = escape(player.prev_track.title)
            next_artist = escape(player.next_track.artist)
            next_title = escape(player.next_track.title)
            self._next_btn.set_tooltip_markup("<b>%s</b> - %s" %
                                              (next_artist, next_title))
            self._prev_btn.set_tooltip_markup("<b>%s</b> - %s" %
                                              (prev_artist, prev_title))

            # Do not show next popover non internal tracks as
            # tags will be readed on the fly
            if player.next_track.id >= 0:
                self._next_popover.update()
                self._next_popover.show()
            else:
                self._next_popover.hide()

    def _on_key_release_event(self, widget, event):
        """
            Destroy window if Esc
            @param widget as Gtk.Widget
            @param event as Gdk.event
        """
        if event.keyval == Gdk.KEY_Escape:
            self.destroy()

    def _on_prev_btn_clicked(self, widget):
        """
            Go to prev track
            @param widget as Gtk.Button
        """
        Lp.player.prev()

    def _on_play_btn_clicked(self, widget):
        """
            Play/pause
            @param widget as Gtk.Button
        """
        if Lp.player.is_playing():
            Lp.player.pause()
            widget.set_image(self._play_image)
        else:
            Lp.player.play()
            widget.set_image(self._pause_image)

    def _on_next_btn_clicked(self, widget):
        """
            Go to next track
            @param widget as Gtk.Button
        """
        Lp.player.next()

    def _on_status_changed(self, obj):
        """
            Update buttons and progress bar
            @param obj as unused
        """
        is_playing = Lp.player.is_playing()
        if Lp.player.current_track.id != Type.RADIOS:
            self._progress.set_sensitive(is_playing)
        if is_playing and not self._timeout1:
            self._timeout1 = GLib.timeout_add(1000, self._update_position)
            self._change_play_btn_status(self._pause_image, _("Pause"))
        elif not is_playing and self._timeout1:
            GLib.source_remove(self._timeout1)
            self._timeout1 = None
            self._change_play_btn_status(self._play_image, _("Play"))

    def _on_progress_press_button(self, scale, data):
        """
            On press, mark player as seeking
            @param unused
        """
        self._seeking = True

    def _on_progress_release_button(self, scale, data):
        """
            Callback for scale release button
            Seek player to scale value
            @param scale as Gtk.Scale, data as unused
        """
        value = scale.get_value()
        self._seeking = False
        self._update_position(value)
        Lp.player.seek(value / 60)
Beispiel #14
0
class ToolbarEnd(Gtk.Bin):
    """
        Toolbar end
    """

    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self._pop_next = NextPopover()
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._shuffle_btn = builder.get_object('shuffle-button')
        self._shuffle_btn_image = builder.get_object('shuffle-button-image')
        Lp().settings.connect('changed::shuffle', self._shuffle_btn_aspect)

        self._party_btn = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        search_button = builder.get_object('search-button')
        self._search = SearchPopover(self)
        self._search.set_relative_to(search_button)
        searchAction = Gio.SimpleAction.new('search', None)
        searchAction.connect('activate', self._on_search_btn_clicked)
        app.add_action(searchAction)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self._queue_button = builder.get_object('queue-button')

        self._settings_button = builder.get_object('settings-button')

        Lp().player.connect('party-changed', self._on_party_changed)

    def setup_menu_btn(self, menu):
        """
            Add an application menu to menu button
            @parma: menu as Gio.Menu
        """
        self._settings_button.show()
        self._settings_button.set_menu_model(menu)

    def on_status_changed(self, player):
        """
            Update buttons on status changed
            @param player as Player
        """
        if player.is_playing():
            # Party mode can be activated
            # via Fullscreen class, so check button state
            self._party_btn.set_active(player.is_party())

    def do_realize(self):
        """
            Show popover if needed
        """
        Gtk.Bin.do_realize(self)
        self._set_shuffle_icon()

    def on_next_changed(self, player):
        """
            Update buttons on current changed
            @param player as Player
        """
        # Do not show next popover non internal tracks as
        # tags will be readed on the fly
        if player.next_track.id is not None and\
           player.next_track.id >= 0 and\
           player.is_playing() and\
            (player.is_party() or
             Lp().settings.get_enum('shuffle') == Shuffle.TRACKS):
            self._pop_next.update()
            self._pop_next.set_relative_to(self)
            self._pop_next.show()
        else:
            self._pop_next.hide()

#######################
# PRIVATE             #
#######################
    def _set_shuffle_icon(self):
        """
            Set shuffle icon
        """
        shuffle = Lp().settings.get_enum('shuffle')
        if shuffle == Shuffle.NONE:
            self._shuffle_btn_image.get_style_context().remove_class(
                                                                    'selected')
            self._shuffle_btn_image.set_from_icon_name(
                "media-playlist-consecutive-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
        else:
            self._shuffle_btn_image.set_from_icon_name(
                "media-playlist-shuffle-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
            if shuffle in [Shuffle.TRACKS, Shuffle.TRACKS_ARTIST]:
                self._shuffle_btn_image.get_style_context().add_class(
                                                                    'selected')
            else:
                self._shuffle_btn_image.get_style_context().remove_class(
                                                                    'selected')
        if shuffle == Shuffle.TRACKS:
            if Lp().player.next_track.id is not None and\
               not self._pop_next.is_visible():
                self._pop_next.set_relative_to(self)
                self._pop_next.update()
                self._pop_next.show()
        elif Lp().player.is_playing():
            self._pop_next.set_relative_to(None)
            self._pop_next.hide()

    def _shuffle_btn_aspect(self, settings, value):
        """
            Mark shuffle button as active when shuffle active
            @param settings as Gio.Settings, value as str
        """
        self._set_shuffle_icon()

    def _activate_party_button(self, action=None, param=None):
        """
            Activate party button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self._party_btn.set_active(not self._party_btn.get_active())

    def _on_search_btn_clicked(self, obj, param=None):
        """
            Show search widget on search button clicked
            @param obj as Gtk.Button or Gtk.Action
        """
        self._search.show()

    def _on_queue_btn_clicked(self, button):
        """
            Show queue widget on queue button clicked
            @param button as Gtk.Button
        """
        queue = QueueWidget()
        queue.set_relative_to(self._queue_button)
        queue.populate()
        queue.show()

    def _on_party_btn_toggled(self, button):
        """
            Set party mode on if party button active
            @param obj as Gtk.button
        """
        active = self._party_btn.get_active()
        self._shuffle_btn.set_sensitive(not active)
        if not Lp().settings.get_value('dark-ui'):
            settings = Gtk.Settings.get_default()
            settings.set_property("gtk-application-prefer-dark-theme", active)
        is_playing = Lp().player.is_playing()
        Lp().player.set_party(active)
        if not active:
            self._pop_next.set_relative_to(None)
            self._pop_next.hide()
        elif is_playing and not self._pop_next.is_visible():
            self._pop_next.set_relative_to(self)
            self._pop_next.update()
            self._pop_next.show()

    def _on_party_changed(self, player, is_party):
        """
            On party change, sync toolbar
            @param player as Player
            @param is party as bool
        """
        if self._party_btn.get_active() != is_party:
            self._activate_party_button()
Beispiel #15
0
class ToolbarEnd(Gtk.Bin):
    """
        Toolbar end
    """

    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self.connect('show', self._on_show)
        self.connect('hide', self._on_hide)
        self._pop_next = NextPopover()
        self._queue = None
        self._search = None
        self._timeout_id = None
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._grid_next = builder.get_object('grid-next')

        self._shuffle_button = builder.get_object('shuffle-button')
        self._shuffle_image = builder.get_object('shuffle-button-image')
        shuffleAction = Gio.SimpleAction.new('shuffle-button', None)
        shuffleAction.connect('activate', self._activate_shuffle_button)
        app.add_action(shuffleAction)
        app.set_accels_for_action("app.shuffle-button", ["<Control>r"])
        Lp().settings.connect('changed::shuffle', self._on_shuffle_changed)

        self._party_button = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        self._search_button = builder.get_object('search-button')
        searchAction = Gio.SimpleAction.new('search', None)
        searchAction.connect('activate', self._on_search_button_clicked)
        app.add_action(searchAction)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self._queue_button = builder.get_object('queue-button')
        queueAction = Gio.SimpleAction.new('queue', None)
        queueAction.connect('activate', self._on_queue_button_clicked)
        app.add_action(queueAction)
        app.set_accels_for_action("app.queue", ["<Control>l"])

        self._settings_button = builder.get_object('settings-button')

        Lp().player.connect('party-changed', self._on_party_changed)
        Lp().player.connect('queue-changed', self._on_queue_changed)

    def setup_menu(self, menu):
        """
            Add an application menu to menu button
            @parma: menu as Gio.Menu
        """
        self._settings_button.show()
        self._settings_button.set_menu_model(menu)

    def on_status_changed(self, player):
        """
            Update buttons on status changed
            @param player as Player
        """
        if player.is_playing():
            # Party mode can be activated
            # via Fullscreen class, so check button state
            self._party_button.set_active(player.is_party())

    def on_next_changed(self, player, force=False):
        """
            Show next popover
            @param player as Player
            @param force to show the popover
        """
        # Do not show popover is this menu is active
        # or if we are hidden
        if self._shuffle_button.get_active() or\
           not self._grid_next.is_visible():
            return
        self._timeout_id = None
        if self._pop_next.should_be_shown() or force:
            self._pop_next.update()
            if not self._pop_next.is_visible():
                self._pop_next.set_relative_to(self._grid_next)
                self._pop_next.show()
        else:
            self._pop_next.hide()

#######################
# PRIVATE             #
#######################
    def _on_button_press(self, button, event):
        """
            Show next popover on long press
            @param widget as Gtk.Widget
            @param event as Gdk.Event
        """
        self._timeout_id = GLib.timeout_add(500, self.on_next_changed,
                                            Lp().player, True)

    def _on_button_release(self, button, event):
        """
            If next popover shown, block event
            @param widget as Gtk.Widget
            @param event as Gdk.Event
        """
        if self._timeout_id is None:
            return True
        else:
            GLib.source_remove(self._timeout_id)
            self._timeout_id = None

    def _set_shuffle_icon(self):
        """
            Set shuffle icon
        """
        shuffle = Lp().settings.get_enum('shuffle')
        if shuffle == Shuffle.NONE:
            self._shuffle_image.get_style_context().remove_class('selected')
            self._shuffle_image.set_from_icon_name(
                "media-playlist-consecutive-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
        else:
            self._shuffle_image.set_from_icon_name(
                "media-playlist-shuffle-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
            if shuffle == Shuffle.TRACKS:
                self._shuffle_image.get_style_context().add_class('selected')
            else:
                self._shuffle_image.get_style_context().remove_class(
                                                                    'selected')

    def _activate_party_button(self, action=None, param=None):
        """
            Activate party button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self._party_button.set_active(not self._party_button.get_active())
        Lp().window.responsive_design()

    def _activate_shuffle_button(self, action=None, param=None):
        """
            Activate shuffle button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self._shuffle_button.set_active(not self._shuffle_button.get_active())

    def _on_shuffle_changed(self, settings, value):
        """
            Mark shuffle button as active when shuffle active
            @param settings as Gio.Settings, value as str
        """
        self._set_shuffle_icon()
        self._pop_next.hide()

    def _on_search_button_clicked(self, obj, param=None):
        """
            Show search widget on search button clicked
            @param obj as Gtk.Button or Gtk.Action
        """
        if self._search is None:
            self._search = SearchPopover()
        self._search.set_relative_to(self._search_button)
        self._search.show()

    def _on_queue_button_clicked(self, button, param=None):
        """
            Show queue widget on queue button clicked
            @param obj as Gtk.Button or Gtk.Action
        """
        if self._queue is None:
            self._queue = QueuePopover()
        self._queue.set_relative_to(self._queue_button)
        self._queue.show()

    def _on_party_button_toggled(self, button):
        """
            Set party mode on if party button active
            @param obj as Gtk.button
        """
        active = self._party_button.get_active()
        self._shuffle_button.set_sensitive(not active)
        if not Lp().settings.get_value('dark-ui'):
            settings = Gtk.Settings.get_default()
            settings.set_property("gtk-application-prefer-dark-theme", active)
        Lp().player.set_party(active)
        self.on_next_changed(Lp().player)

    def _on_queue_changed(self, player):
        """
            On queue changed, change buttno aspect
            @param player as Player
            @param is party as bool
        """
        if player.get_queue():
            self._queue_button.get_style_context().add_class('selected')
        else:
            self._queue_button.get_style_context().remove_class('selected')

    def _on_party_changed(self, player, is_party):
        """
            On party change, sync toolbar
            @param player as Player
            @param is party as bool
        """
        if self._party_button.get_active() != is_party:
            self._activate_party_button()

    def _on_show(self, widget):
        """
            Show popover if needed
            @param widget as Gtk.Widget
        """
        self._set_shuffle_icon()

    def _on_hide(self, widget):
        """
            Hide popover
            @param widget as Gtk.Widget
        """
        self._pop_next.hide()
Beispiel #16
0
class ToolbarEnd(Gtk.Bin):
    """
        Toolbar end
    """
    def __init__(self):
        """
            Init toolbar
        """
        Gtk.Bin.__init__(self)
        self.connect('show', self.__on_show)
        self.connect('hide', self.__on_hide)
        self.set_hexpand(True)
        self.__next_popover = NextPopover()
        self.__search = None
        self.__next_was_inhibited = False
        self.__timeout_id = None
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self.__grid_next = builder.get_object('grid-next')

        self.__shuffle_button = builder.get_object('shuffle-button')
        self.__shuffle_image = builder.get_object('shuffle-button-image')
        shuffleAction = Gio.SimpleAction.new('shuffle-button', None)
        shuffleAction.connect('activate', self.__activate_shuffle_button)
        Lp().add_action(shuffleAction)
        Lp().set_accels_for_action("app.shuffle-button", ["<Control>r"])
        Lp().settings.connect('changed::shuffle', self.__on_playback_changed)
        Lp().settings.connect('changed::playback', self.__on_playback_changed)

        self.__party_button = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self.__activate_party_button)
        Lp().add_action(party_action)
        Lp().set_accels_for_action("app.party", ["<Control>p"])

        self.__search_button = builder.get_object('search-button')
        self.__helper = TouchHelper(self.__search_button, "search",
                                    "<Control>f")
        self.__helper.set_long_func(self.__on_search_long)
        self.__helper.set_short_func(self.__on_search_short)

        self.__settings_button = builder.get_object('settings-button')

        self.__list_button = builder.get_object('list-button')
        self.__list_button.set_property('has-tooltip', True)
        self.__list_button.connect('query-tooltip',
                                   self.__on_list_button_query_tooltip)
        self.__list_popover = None
        Lp().player.connect('party-changed', self.__on_party_changed)
        Lp().player.connect('lock-changed', self.__on_lock_changed)

    def setup_menu(self, menu):
        """
            Add an application menu to menu button
            @parma: menu as Gio.Menu
        """
        self.__settings_button.show()
        self.__settings_button.set_menu_model(menu)

    def on_status_changed(self, player):
        """
            Update buttons on status changed
            @param player as Player
        """
        if player.is_playing:
            # Party mode can be activated
            # via Fullscreen class, so check button state
            self.__party_button.set_active(player.is_party)

    def on_next_changed(self, player, force=False):
        """
            Show next popover
            @param player as Player
            @param force to show the popover
        """
        # Do not show popover is this menu is active
        # or if we are hidden
        if self.__shuffle_button.get_active() or\
           not self.__grid_next.is_visible():
            return
        if self.__next_popover.should_be_shown() or force:
            if self.__next_popover.is_visible():
                self.__next_popover.update()
            else:
                self.__next_popover.set_relative_to(self.__grid_next)
                self.__next_popover.show()
        else:
            self.__next_popover.hide()

    def search(self, search):
        """
            Search item
            @param search as str
        """
        self.__on_search_short([])
        self.__search.set_text(search)

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

    def _on_shuffle_button_toggled(self, button):
        """
            Hide next popover
            @param button as Gtk.Button
        """
        if button.get_active():
            self.__next_popover.hide()
            self.__next_popover.inhibit(True)
        else:
            self.__next_popover.inhibit(False)
            if self.__next_popover.should_be_shown():
                self.__next_popover.show()

    def _on_party_button_toggled(self, button):
        """
            Set party mode on if party button active
            @param obj as Gtk.button
        """
        active = self.__party_button.get_active()
        self.__shuffle_button.set_sensitive(not active)
        if not Lp().settings.get_value('dark-ui'):
            settings = Gtk.Settings.get_default()
            settings.set_property("gtk-application-prefer-dark-theme", active)
        Lp().player.set_party(active)
        self.on_next_changed(Lp().player)

    def _on_party_press_event(self, eventbox, event):
        """
            Show party popover
            @param eventbox as Gtk.EventBox
            @param event as Gdk.Event
        """
        if event.button == 3:
            popover = PartyPopover()
            popover.set_relative_to(eventbox)
            self.__next_popover.hide()
            popover.connect('closed', self.__on_popover_closed)
            self.__next_popover.inhibit(True)
            popover.show()
            return True

    def _on_list_button_clicked(self, widget, unused=None):
        """
            Show current playback context popover
            @param widget as Gtk.Widget
        """
        if self.__list_popover is not None:
            return
        self.__next_was_inhibited = self.__next_popover.inhibited
        self.__next_popover.hide()
        self.__next_popover.inhibit(True)
        if Lp().player.current_track.id == Type.EXTERNALS:
            from lollypop.pop_externals import ExternalsPopover
            self.__list_popover = ExternalsPopover()
            self.__list_popover.set_relative_to(self.__list_button)
            self.__list_popover.populate()
            self.__list_popover.show()
        elif Lp().player.get_queue():
            from lollypop.pop_queue import QueuePopover
            self.__list_popover = QueuePopover()
            self.__list_popover.set_relative_to(self.__list_button)
            self.__list_popover.show()
        elif Lp().player.get_user_playlist_ids():
            from lollypop.pop_playlists import PlaylistsPopover
            self.__list_popover = PlaylistsPopover()
            self.__list_popover.set_relative_to(self.__list_button)
            self.__list_popover.show()
        else:
            from lollypop.pop_albums import AlbumsPopover
            self.__list_popover = AlbumsPopover()
            self.__list_popover.set_relative_to(self.__list_button)
            self.__list_popover.show()
        self.__list_popover.connect('closed', self.__on_list_popover_closed)
        return True

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

    def __on_search_long(self, args):
        """
            Show current track menu
            @param args as []
        """
        if Lp().window.view is not None:
            Lp().window.view.set_search_mode()

    def __on_search_short(self, args):
        """
            Show search popover
            @param args as []
        """
        self.__next_was_inhibited = self.__next_popover.inhibited
        self.__next_popover.hide()
        self.__next_popover.inhibit(True)
        if self.__search is None:
            from lollypop.pop_search import SearchPopover
            self.__search = SearchPopover()
            self.__search.connect('closed', self.__on_popover_closed)
        self.__search.set_relative_to(self.__search_button)
        self.__search.show()

    def __set_icon(self):
        """
            Set shuffle icon
        """
        shuffle = Lp().settings.get_enum('shuffle')
        repeat = Lp().settings.get_enum('playback')
        if repeat == NextContext.REPEAT_TRACK:
            self.__shuffle_image.get_style_context().remove_class('selected')
            self.__shuffle_image.set_from_icon_name(
                "media-playlist-repeat-song-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
        elif shuffle == Shuffle.NONE:
            self.__shuffle_image.get_style_context().remove_class('selected')
            if repeat == NextContext.NONE:
                self.__shuffle_image.set_from_icon_name(
                    "media-playlist-repeat-symbolic",
                    Gtk.IconSize.SMALL_TOOLBAR)
            else:
                self.__shuffle_image.set_from_icon_name(
                    "media-playlist-consecutive-symbolic",
                    Gtk.IconSize.SMALL_TOOLBAR)
        else:
            self.__shuffle_image.set_from_icon_name(
                "media-playlist-shuffle-symbolic", Gtk.IconSize.SMALL_TOOLBAR)
            if shuffle == Shuffle.TRACKS:
                self.__shuffle_image.get_style_context().add_class('selected')
            else:
                self.__shuffle_image.get_style_context().remove_class(
                    'selected')

    def __activate_party_button(self, action=None, param=None):
        """
            Activate party button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self.__party_button.set_active(not self.__party_button.get_active())
        Lp().window.responsive_design()

    def __activate_shuffle_button(self, action=None, param=None):
        """
            Activate shuffle button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self.__shuffle_button.set_active(
            not self.__shuffle_button.get_active())

    def __on_lock_changed(self, player):
        """
            Lock toolbar
            @param player as Player
        """
        self.__party_button.set_sensitive(not player.locked)
        self.__list_button.set_sensitive(not player.locked)
        self.__shuffle_button.set_sensitive(not player.locked)

    def __on_playback_changed(self, settings, value):
        """
            Update shuffle icon
            @param settings as Gio.Settings, value as str
        """
        self.__set_icon()
        self.__next_popover.hide()

    def __on_party_changed(self, player, is_party):
        """
            On party change, sync toolbar
            @param player as Player
            @param is party as bool
        """
        if self.__party_button.get_active() != is_party:
            self.__activate_party_button()

    def __on_list_popover_closed(self, popover):
        """
            Reset variable
            @param popover as Gtk.Popover
        """
        self.__list_popover = None
        self.__on_popover_closed(popover)

    def __on_popover_closed(self, popover):
        """
            Restore next popover if needed
            @param popover as Gtk.Popover
        """
        if not self.__next_was_inhibited:
            self.__next_popover.inhibit(False)
        if self.__next_popover.should_be_shown():
            self.__next_popover.set_relative_to(self.__grid_next)
            self.__next_popover.show()

    def __on_show(self, widget):
        """
            Show popover if needed
            @param widget as Gtk.Widget
        """
        self.__set_icon()

    def __on_hide(self, widget):
        """
            Hide popover
            @param widget as Gtk.Widget
        """
        self.__next_popover.hide()

    def __on_list_button_query_tooltip(self, widget, x, y, keyboard, tooltip):
        """
            Show tooltip
            @param widget as Gtk.Widget
            @param x as int
            @param y as int
            @param keyboard as bool
            @param tooltip as Gtk.Tooltip
        """
        if Lp().player.current_track.id == Type.EXTERNALS:
            widget.set_tooltip_text(_("External tracks"))
        elif Lp().player.get_queue():
            widget.set_tooltip_text(_("Queue"))
        elif Lp().player.get_user_playlist_ids():
            widget.set_tooltip_text(_("Playing playlists"))
        else:
            widget.set_tooltip_text(_("Playing albums"))
Beispiel #17
0
class FullScreen(Gtk.Window, InfoController, PlaybackController,
                 ProgressController):
    """
        Show a fullscreen window showing current track context
    """
    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_title("Lollypop")
        PlaybackController.__init__(self)
        ProgressController.__init__(self)
        self.set_application(app)
        self.__timeout1 = None
        self.__timeout2 = None
        self.__signal1_id = None
        self.__signal2_id = None
        self.set_decorated(False)
        self.__parent = parent

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

        # Calculate cover size
        screen = Gdk.Screen.get_default()
        monitor = screen.get_primary_monitor()
        geometry = screen.get_monitor_geometry(monitor)
        # We want 500 and 200 in full hd
        if geometry.width > geometry.height:
            artsize = int(ArtSize.FULLSCREEN * geometry.width / 1920)
        else:
            artsize = int(ArtSize.FULLSCREEN * geometry.height / 1920)
        InfoController.__init__(self, artsize)

        self._play_btn = builder.get_object("play_btn")
        self._next_btn = builder.get_object("next_btn")
        self._prev_btn = builder.get_object("prev_btn")
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object("play_image")
        self._pause_image = builder.get_object("pause_image")
        close_btn = builder.get_object("close_btn")
        close_btn.connect("clicked", self.__destroy)
        self._cover = builder.get_object("cover")
        self._title_label = builder.get_object("title")
        self._artist_label = builder.get_object("artist")
        self._album_label = builder.get_object("album")

        self._datetime = builder.get_object("datetime")

        self._progress = builder.get_object("progress_scale")
        self._timelabel = builder.get_object("playback")
        self._total_time_label = builder.get_object("duration")
        self.connect("key-release-event", self.__on_key_release_event)
        self.add(builder.get_object("widget"))

    def do_show(self):
        """
            Init signals, set color and go party mode if nothing is playing
        """
        self.__signal1_id = Lp().player.connect("current-changed",
                                                self.on_current_changed)
        self.__signal2_id = Lp().player.connect("status-changed",
                                                self.on_status_changed)
        if Lp().player.current_track.id is None:
            Lp().player.set_party(True)
        else:
            self.on_status_changed(Lp().player)
            self.on_current_changed(Lp().player)
        if self.__timeout1 is None:
            self.__timeout1 = GLib.timeout_add(1000, self._update_position)
        Gtk.Window.do_show(self)
        self.__parent.set_skip_pager_hint(True)
        self.__parent.set_skip_taskbar_hint(True)
        now = datetime.now()
        self._datetime.set_label(now.strftime("%a %d %b, %X")[:-3])
        if self.__timeout2 is None:
            second = datetime.now().second
            if 60 - second > 0:
                GLib.timeout_add((60 - second) * 1000, self.__update_datetime)
            else:
                self.__timeout2 = GLib.timeout_add(60000,
                                                   self.__update_datetime)
        self._update_position(Lp().player.position / 1000000)
        self.fullscreen()
        self._next_popover.set_relative_to(self._album_label)
        if Lp().player.next_track.id != Type.RADIOS:
            self._next_popover.show()
        # Disable idle
        self.__cookie = Lp().inhibit(Lp().window,
                                     Gtk.ApplicationInhibitFlags.IDLE, None)

    def do_hide(self):
        """
            Remove signals and unset color
        """
        self.__parent.set_skip_pager_hint(False)
        self.__parent.set_skip_taskbar_hint(False)
        Gtk.Window.do_hide(self)
        if self.__signal1_id is not None:
            Lp().player.disconnect(self.__signal1_id)
            self.__signal1_id = None
        if self.__signal2_id is not None:
            Lp().player.disconnect(self.__signal2_id)
            self.__signal2_id = None
        if self.__timeout1 is not None:
            GLib.source_remove(self.__timeout1)
            self.__timeout1 = None
        if self.__timeout2 is not None:
            GLib.source_remove(self.__timeout2)
        self._next_popover.set_relative_to(None)
        self._next_popover.hide()
        Lp().uninhibit(self.__cookie)

    def show_hide_volume_control(self):
        """
            Show/Hide volume control
        """
        self._show_volume_control = not self._show_volume_control
        self._update_state()

    def on_current_changed(self, player):
        """
            Update infos and show/hide popover
            @param player as Player
        """
        InfoController.on_current_changed(self, player)
        ProgressController.on_current_changed(self, player)
        if player.current_track.id is not None:
            album_name = player.current_track.album.name
            if player.current_track.year:
                album_name += " (%s)" % player.current_track.year
            self._album_label.set_text(album_name)
        # Do not show next popover non internal tracks as
        # tags will be readed on the fly
        if player.next_track.id is not None and player.next_track.id >= 0:
            self._next_popover.update()
            self._next_popover.show()
        else:
            self._next_popover.hide()

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

    def __update_datetime(self):
        """
            Update datetime in headerbar
        """
        now = datetime.now()
        self._datetime.set_label(now.strftime("%a %d %b, %X")[:-3])
        if self.__timeout2 is None:
            self.__timeout2 = GLib.timeout_add(60000, self.__update_datetime)
            return False
        return True

    def __destroy(self, widget):
        """
            Destroy self
            @param widget as Gtk.Button
        """
        self.destroy()

    def __on_key_release_event(self, widget, event):
        """
            Destroy window if Esc
            @param widget as Gtk.Widget
            @param event as Gdk.event
        """
        if event.keyval == Gdk.KEY_Escape:
            self.destroy()
Beispiel #18
0
    def __init__(self):
        """
            Init toolbar
        """
        Gtk.Bin.__init__(self)
        self.set_hexpand(True)
        self.__search_popover = None
        self.__timeout_id = None
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/ToolbarEnd.ui")
        builder.connect_signals(self)

        self.__party_submenu = builder.get_object("party_submenu")
        self.add(builder.get_object("end"))

        # Map some settings to actions, can't use Gio.Settings.create_action()
        # because API does not support set_enabled()
        self.__shuffle_action = Gio.SimpleAction.new_stateful(
            "shuffle",
            GLib.VariantType.new("s"),
            GLib.Variant("s", "none"))
        self.__shuffle_action.set_state(App().settings.get_value("shuffle"))
        self.__shuffle_action.connect("change-state",
                                      self.__on_shuffle_change_state)
        self.__playback_action = Gio.SimpleAction.new_stateful(
            "playback",
            GLib.VariantType.new("s"),
            GLib.Variant("s", "none"))
        self.__playback_action.set_state(App().settings.get_value("playback"))
        self.__playback_action.connect("change-state",
                                       self.__on_playback_change_state)
        App().add_action(self.__shuffle_action)
        App().add_action(self.__playback_action)

        self.__shuffle_button = builder.get_object("shuffle-button")
        self.__shuffle_image = builder.get_object("shuffle-button-image")
        shuffle_button_action = Gio.SimpleAction.new("shuffle-button", None)
        shuffle_button_action.connect("activate",
                                      self.__on_shuffle_button_activate)
        App().add_action(shuffle_button_action)
        App().set_accels_for_action("app.shuffle-button", ["<Control>r"])
        App().settings.connect("changed::shuffle", self.__on_playback_changed)
        App().settings.connect("changed::playback", self.__on_playback_changed)

        party_action = Gio.SimpleAction.new_stateful(
            "party",
            None,
            GLib.Variant.new_boolean(App().player.is_party))
        party_action.connect("change-state", self.__on_party_mode_change_state)
        App().add_action(party_action)
        App().set_accels_for_action("app.party", ["<Control>p"])

        scrobbling_disabled = App().settings.get_value("disable-scrobbling")
        scrobbling_action = Gio.SimpleAction.new_stateful(
            "scrobbling",
            None,
            GLib.Variant.new_boolean(not scrobbling_disabled))
        scrobbling_action.connect("change-state",
                                  self.__on_scrobbling_mode_change_state)
        App().add_action(scrobbling_action)
        App().set_accels_for_action("app.scrobbling", ["<Control><Shift>s"])

        self.__next_popover = NextPopover()
        self.__next_popover.set_relative_to(self.__shuffle_button)

        search_action = Gio.SimpleAction.new("search", None)
        self.__search_button = builder.get_object("search-button")
        search_action.connect("activate", self.__on_search_activate)
        App().add_action(search_action)
        App().set_accels_for_action("app.search", ["<Control>f"])

        builder_menu = Gtk.Builder()
        builder_menu.add_from_resource("/org/gnome/Lollypop/Appmenu.ui")
        builder.get_object("settings-button").set_menu_model(
            builder_menu.get_object("app-menu"))

        self.__list_button = builder.get_object("list-button")
        self.__list_button.set_property("has-tooltip", True)
        self.__list_button.connect("query-tooltip",
                                   self.__on_list_button_query_tooltip)
        self.__list_popover = None
        App().player.connect("playlist-changed", self.__on_playlist_changed)
        self.__set_shuffle_icon()
Beispiel #19
0
class ToolbarEnd(Gtk.Bin):
    """
        Toolbar end
    """

    def __init__(self):
        """
            Init toolbar
        """
        Gtk.Bin.__init__(self)
        self.set_hexpand(True)
        self.__search_popover = None
        self.__timeout_id = None
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/ToolbarEnd.ui")
        builder.connect_signals(self)

        self.__party_submenu = builder.get_object("party_submenu")
        self.add(builder.get_object("end"))

        # Map some settings to actions, can't use Gio.Settings.create_action()
        # because API does not support set_enabled()
        self.__shuffle_action = Gio.SimpleAction.new_stateful(
            "shuffle",
            GLib.VariantType.new("s"),
            GLib.Variant("s", "none"))
        self.__shuffle_action.set_state(App().settings.get_value("shuffle"))
        self.__shuffle_action.connect("change-state",
                                      self.__on_shuffle_change_state)
        self.__playback_action = Gio.SimpleAction.new_stateful(
            "playback",
            GLib.VariantType.new("s"),
            GLib.Variant("s", "none"))
        self.__playback_action.set_state(App().settings.get_value("playback"))
        self.__playback_action.connect("change-state",
                                       self.__on_playback_change_state)
        App().add_action(self.__shuffle_action)
        App().add_action(self.__playback_action)

        self.__shuffle_button = builder.get_object("shuffle-button")
        self.__shuffle_image = builder.get_object("shuffle-button-image")
        shuffle_button_action = Gio.SimpleAction.new("shuffle-button", None)
        shuffle_button_action.connect("activate",
                                      self.__on_shuffle_button_activate)
        App().add_action(shuffle_button_action)
        App().set_accels_for_action("app.shuffle-button", ["<Control>r"])
        App().settings.connect("changed::shuffle", self.__on_playback_changed)
        App().settings.connect("changed::playback", self.__on_playback_changed)

        party_action = Gio.SimpleAction.new_stateful(
            "party",
            None,
            GLib.Variant.new_boolean(App().player.is_party))
        party_action.connect("change-state", self.__on_party_mode_change_state)
        App().add_action(party_action)
        App().set_accels_for_action("app.party", ["<Control>p"])

        scrobbling_disabled = App().settings.get_value("disable-scrobbling")
        scrobbling_action = Gio.SimpleAction.new_stateful(
            "scrobbling",
            None,
            GLib.Variant.new_boolean(not scrobbling_disabled))
        scrobbling_action.connect("change-state",
                                  self.__on_scrobbling_mode_change_state)
        App().add_action(scrobbling_action)
        App().set_accels_for_action("app.scrobbling", ["<Control><Shift>s"])

        self.__next_popover = NextPopover()
        self.__next_popover.set_relative_to(self.__shuffle_button)

        search_action = Gio.SimpleAction.new("search", None)
        self.__search_button = builder.get_object("search-button")
        search_action.connect("activate", self.__on_search_activate)
        App().add_action(search_action)
        App().set_accels_for_action("app.search", ["<Control>f"])

        builder_menu = Gtk.Builder()
        builder_menu.add_from_resource("/org/gnome/Lollypop/Appmenu.ui")
        builder.get_object("settings-button").set_menu_model(
            builder_menu.get_object("app-menu"))

        self.__list_button = builder.get_object("list-button")
        self.__list_button.set_property("has-tooltip", True)
        self.__list_button.connect("query-tooltip",
                                   self.__on_list_button_query_tooltip)
        self.__list_popover = None
        App().player.connect("playlist-changed", self.__on_playlist_changed)
        self.__set_shuffle_icon()

    def on_next_changed(self, player):
        """
            Show next popover
            @param player as Player
        """
        if self.__next_popover.should_be_shown():
            if self.__next_popover.is_visible():
                self.__next_popover.update()
            else:
                self.__next_popover.popup()
        else:
            self.__next_popover.hide()

    def set_mini(self, mini):
        """
            Set mini mode
            @param mini as bool
        """
        if mini:
            self.__search_button.hide()
            self.__list_button.hide()
        else:
            self.__search_button.show()
            self.__list_button.show()

    def search(self, search):
        """
            Search item
            @param search as str
        """
        self.__on_search_button_cancelled()
        self.__search_popover.set_text(search)

    @property
    def next_popover(self):
        """
            Get next popover
            @return popover
        """
        return self.__next_popover

#######################
# PROTECTED           #
#######################
    def _on_list_button_toggled(self, button):
        """
            Show current playback context popover
            @param button as Gtk.MenuButton
        """
        if not button.get_active():
            return
        self.__next_popover.hide()
        self.__next_popover.inhibit(True)
        if App().player.queue:
            from lollypop.pop_queue import QueuePopover
            popover = QueuePopover()
        elif App().player.playlist_ids:
            from lollypop.pop_playlists import PlaylistsPopover
            popover = PlaylistsPopover()
        else:
            from lollypop.pop_albums import AlbumsPopover
            popover = AlbumsPopover()
        popover.set_relative_to(button)
        popover.popup()
        popover.connect("closed", self.__on_popover_closed, button)
        return True

    def _on_search_button_toggled(self, button):
        """
            Show search popover
            @param button as Gtk.Button
        """
        if not button.get_active():
            self.__search_popover.popdown()
            return
        self.__next_popover.hide()
        self.__next_popover.inhibit(True)
        if self.__search_popover is None:
            from lollypop.pop_search import SearchPopover
            self.__search_popover = SearchPopover()
            self.__search_popover.connect("closed",
                                          self.__on_popover_closed,
                                          button)
        self.__search_popover.set_relative_to(button)
        self.__search_popover.popup()
        return True

    def _on_shuffle_button_toggled(self, button):
        """
           Create submenu
           @param button as Gtk.MenuButton
        """
        if button.get_active():
            # Create submenu "Configure party mode"
            self.__party_submenu.remove_all()
            self.__init_party_submenu()
            self.__next_popover.hide()
            self.__next_popover.inhibit(True)
        else:
            self.__next_popover.inhibit(False)
            if self.__next_popover.should_be_shown():
                self.__next_popover.popup()

    def _on_settings_button_toggled(self, button):
        """
           Create submenu
           @param button as Gtk.MenuButton
        """
        if button.get_active():
            self.__next_popover.hide()
            self.__next_popover.inhibit(True)
        else:
            self.__next_popover.inhibit(False)
            if self.__next_popover.should_be_shown():
                self.__next_popover.popup()

#######################
# PRIVATE             #
#######################
    def __init_party_submenu(self):
        """
            Init party submenu with current ids
        """
        def on_change_state(action, value, genre_id):
            action.set_state(value)
            ids = list(App().settings.get_value("party-ids"))
            genre_ids = App().genres.get_ids()
            # Select all
            if genre_id is None:
                # Update others
                for genre_id in genre_ids:
                    action = App().lookup_action("genre_%s" % genre_id)
                    if action.get_state() != value:
                        action.set_state(value)
                ids = []
            # Party id added
            elif value:
                ids.append(genre_id)
            # Party id removed
            elif ids and len(party_ids) > 1:
                ids.remove(genre_id)
            # Initial value
            else:
                genre_ids.remove(genre_id)
            App().settings.set_value("party-ids", GLib.Variant("ai", ids))
            App().player.set_party_ids()
            App().player.set_next()

        party_ids = App().settings.get_value("party-ids")
        all_ids = App().genres.get_ids()
        all_selected = len(set(all_ids) & set(party_ids)) == len(all_ids) or\
            not party_ids
        action = Gio.SimpleAction.new_stateful(
                    "all_party_ids",
                    None,
                    GLib.Variant.new_boolean(all_selected))
        action.connect("change-state", on_change_state, None)
        App().add_action(action)
        item = Gio.MenuItem.new(_("All genres"), "app.all_party_ids")
        self.__party_submenu.append_item(item)
        i = 0
        # Hack, hack, hack
        submenu_name = _("Next")
        menu = self.__party_submenu
        for (genre_id, name, sortname) in App().genres.get():
            in_party_ids = not party_ids or genre_id in party_ids
            action_name = "genre_%s" % genre_id
            action = Gio.SimpleAction.new_stateful(
                action_name,
                None,
                GLib.Variant.new_boolean(in_party_ids))
            action.connect("change-state", on_change_state, genre_id)
            App().add_action(action)
            item = Gio.MenuItem.new(name, "app.%s" % action_name)
            menu.append_item(item)
            if i > 10:
                submenu = Gio.Menu()
                item = Gio.MenuItem.new(submenu_name, None)
                submenu_name += " "
                item.set_submenu(submenu)
                menu.append_item(item)
                menu = submenu
                i = 0
            i += 1

    def __set_shuffle_icon(self):
        """
            Set shuffle icon
        """
        shuffle = App().settings.get_enum("shuffle")
        repeat = App().settings.get_enum("playback")
        if repeat == NextContext.REPEAT_TRACK:
            self.__shuffle_image.get_style_context().remove_class("selected")
            self.__shuffle_image.set_from_icon_name(
                "media-playlist-repeat-song-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
        elif shuffle == Shuffle.NONE:
            self.__shuffle_image.get_style_context().remove_class("selected")
            if repeat == NextContext.NONE:
                self.__shuffle_image.set_from_icon_name(
                    "media-playlist-repeat-symbolic",
                    Gtk.IconSize.SMALL_TOOLBAR)
            else:
                self.__shuffle_image.set_from_icon_name(
                    "media-playlist-consecutive-symbolic",
                    Gtk.IconSize.SMALL_TOOLBAR)
        else:
            self.__shuffle_image.set_from_icon_name(
                "media-playlist-shuffle-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
            if shuffle == Shuffle.TRACKS:
                self.__shuffle_image.get_style_context().add_class("selected")
            else:
                self.__shuffle_image.get_style_context().remove_class(
                    "selected")

    def __on_party_mode_change_state(self, action, value):
        """
            Activate party mode
            @param action as Gio.SimpleAction
            @param value as bool
        """
        if not App().gtk_application_prefer_dark_theme and\
                not App().settings.get_value("dark-ui"):
            settings = Gtk.Settings.get_default()
            settings.set_property("gtk-application-prefer-dark-theme", value)
        App().player.set_party(value.get_boolean())
        action.set_state(value)
        self.__shuffle_action.set_enabled(not value)
        self.__playback_action.set_enabled(not value)
        self.on_next_changed(App().player)

    def __on_scrobbling_mode_change_state(self, action, value):
        """
            Change scrobbling option
            @param action as Gio.SimpleAction
            @param value as bool
        """
        action.set_state(value)
        App().settings.set_value("disable-scrobbling",
                                 GLib.Variant("b", not value))

    def __on_shuffle_change_state(self, action, value):
        """
            Update shuffle setting
            @param action as Gio.SimpleAction
            @param value as bool
        """
        App().settings.set_value("shuffle", value)
        action.set_state(value)

    def __on_playback_change_state(self, action, value):
        """
            Update playback setting
            @param action as Gio.SimpleAction
            @param value as bool
        """
        App().settings.set_value("playback", value)
        action.set_state(value)

    def __on_shuffle_button_activate(self, action, param):
        """
            Activate shuffle button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self.__shuffle_button.set_active(
            not self.__shuffle_button.get_active())

    def __on_playback_changed(self, settings, value):
        """
            Update shuffle icon
            @param settings as Gio.Settings, value as str
        """
        self.__set_shuffle_icon()
        self.__next_popover.hide()

    def __on_popover_closed(self, popover, button):
        """
            Restore next popover if needed
            @param popover as Popover
            @param button as Gtk.Button
        """
        button.set_active(False)
        self.__next_popover.inhibit(False)
        if self.__next_popover.should_be_shown():
            self.__next_popover.popup()

    def __on_search_activate(self, action, variant):
        """
            @param action as Gio.SimpleAction
            @param variant as GLib.Variant
        """
        if self.__search_button.get_visible():
            self.__search_button.set_active(
                not self.__search_button.get_active())
        else:
            App().window.container.show_view(Type.SEARCH)

    def __on_list_button_query_tooltip(self, widget, x, y, keyboard, tooltip):
        """
            Show tooltip
            @param widget as Gtk.Widget
            @param x as int
            @param y as int
            @param keyboard as bool
            @param tooltip as Gtk.Tooltip
        """
        if App().player.queue:
            widget.set_tooltip_text(_("Queue"))
        elif App().player.playlist_ids:
            widget.set_tooltip_text(_("Playing playlists"))
        else:
            widget.set_tooltip_text(_("Playing albums"))

    def __on_playlist_changed(self, player):
        """
            Update playback button status
            @param player as Player
        """
        if player.albums or player.playlist_ids or player.queue:
            self.__list_button.set_sensitive(True)
        else:
            self.__list_button.set_sensitive(False)
Beispiel #20
0
 def _on_party_changed(self, player, is_party):
     # GTK fail to change colors on popover, so destroy it
     self._pop_next.destroy()
     self._pop_next = NextPopover()
     if self._party_btn.get_active() != is_party:
         self._activate_party_button()
Beispiel #21
0
class ToolbarEnd(Gtk.Bin):
    """
        Toolbar end
    """
    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self._pop_next = NextPopover()
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._shuffle_btn = builder.get_object('shuffle-button')
        self._shuffle_btn_image = builder.get_object('shuffle-button-image')
        Lp().settings.connect('changed::shuffle', self._shuffle_btn_aspect)

        self._party_btn = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        search_button = builder.get_object('search-button')
        self._search = SearchPopover(self)
        self._search.set_relative_to(search_button)
        searchAction = Gio.SimpleAction.new('search', None)
        searchAction.connect('activate', self._on_search_btn_clicked)
        app.add_action(searchAction)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self._queue_button = builder.get_object('queue-button')

        self._settings_button = builder.get_object('settings-button')

        Lp().player.connect('party-changed', self._on_party_changed)

    def setup_menu_btn(self, menu):
        """
            Add an application menu to menu button
            @parma: menu as Gio.Menu
        """
        self._settings_button.show()
        self._settings_button.set_menu_model(menu)

    def on_status_changed(self, player):
        """
            Update buttons on status changed
            @param player as Player
        """
        if player.is_playing():
            # Party mode can be activated
            # via Fullscreen class, so check button state
            self._party_btn.set_active(player.is_party())

    def do_realize(self):
        """
            Show popover if needed
        """
        Gtk.Bin.do_realize(self)
        self._set_shuffle_icon()

    def on_next_changed(self, player):
        """
            Update buttons on current changed
            @param player as Player
        """
        # Do not show next popover non internal tracks as
        # tags will be readed on the fly
        if player.next_track.id is not None and\
           player.next_track.id >= 0 and\
           player.is_playing() and\
            (player.is_party() or
             Lp().settings.get_enum('shuffle') == Shuffle.TRACKS):
            self._pop_next.update()
            self._pop_next.set_relative_to(self)
            self._pop_next.show()
        else:
            self._pop_next.hide()

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

    def _set_shuffle_icon(self):
        """
            Set shuffle icon
        """
        shuffle = Lp().settings.get_enum('shuffle')
        if shuffle == Shuffle.NONE:
            self._shuffle_btn_image.get_style_context().remove_class(
                'selected')
            self._shuffle_btn_image.set_from_icon_name(
                "media-playlist-consecutive-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
        else:
            self._shuffle_btn_image.set_from_icon_name(
                "media-playlist-shuffle-symbolic", Gtk.IconSize.SMALL_TOOLBAR)
            if shuffle in [Shuffle.TRACKS, Shuffle.TRACKS_ARTIST]:
                self._shuffle_btn_image.get_style_context().add_class(
                    'selected')
            else:
                self._shuffle_btn_image.get_style_context().remove_class(
                    'selected')
        if shuffle == Shuffle.TRACKS:
            if Lp().player.next_track.id is not None and\
               not self._pop_next.is_visible():
                self._pop_next.set_relative_to(self)
                self._pop_next.update()
                self._pop_next.show()
        elif Lp().player.is_playing():
            self._pop_next.set_relative_to(None)
            self._pop_next.hide()

    def _shuffle_btn_aspect(self, settings, value):
        """
            Mark shuffle button as active when shuffle active
            @param settings as Gio.Settings, value as str
        """
        self._set_shuffle_icon()

    def _activate_party_button(self, action=None, param=None):
        """
            Activate party button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self._party_btn.set_active(not self._party_btn.get_active())

    def _on_search_btn_clicked(self, obj, param=None):
        """
            Show search widget on search button clicked
            @param obj as Gtk.Button or Gtk.Action
        """
        self._search.show()

    def _on_queue_btn_clicked(self, button):
        """
            Show queue widget on queue button clicked
            @param button as Gtk.Button
        """
        queue = QueueWidget()
        queue.set_relative_to(self._queue_button)
        queue.populate()
        queue.show()

    def _on_party_btn_toggled(self, button):
        """
            Set party mode on if party button active
            @param obj as Gtk.button
        """
        active = self._party_btn.get_active()
        self._shuffle_btn.set_sensitive(not active)
        if not Lp().settings.get_value('dark-ui'):
            settings = Gtk.Settings.get_default()
            settings.set_property("gtk-application-prefer-dark-theme", active)
        is_playing = Lp().player.is_playing()
        Lp().player.set_party(active)
        if not active:
            self._pop_next.set_relative_to(None)
            self._pop_next.hide()
        elif is_playing and not self._pop_next.is_visible():
            self._pop_next.set_relative_to(self)
            self._pop_next.update()
            self._pop_next.show()

    def _on_party_changed(self, player, is_party):
        """
            On party change, sync toolbar
            @param player as Player
            @param is party as bool
        """
        if self._party_btn.get_active() != is_party:
            self._activate_party_button()
Beispiel #22
0
class FullScreen(Gtk.Window, InfoController, PlaybackController,
                 ProgressController):
    """
        Show a fullscreen window showing current track context
    """
    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_title("Lollypop")
        PlaybackController.__init__(self)
        ProgressController.__init__(self)
        self.set_application(app)
        self.__timeout1 = None
        self.__timeout2 = None
        self.__signal1_id = None
        self.__signal2_id = None
        self.set_decorated(False)
        self.__parent = parent

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

        # Calculate cover size
        screen = Gdk.Screen.get_default()
        monitor = screen.get_monitor_at_window(parent.get_window())
        geometry = screen.get_monitor_geometry(monitor)
        # We want 500 and 200 in full hd
        if geometry.width > geometry.height:
            artsize = int(ArtSize.FULLSCREEN * geometry.height / 1080)
        else:
            artsize = int(ArtSize.FULLSCREEN * geometry.width / 1920)
        InfoController.__init__(self, artsize)
        widget = builder.get_object("widget")
        self._play_btn = builder.get_object("play_btn")
        self._next_btn = builder.get_object("next_btn")
        self._prev_btn = builder.get_object("prev_btn")
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.RIGHT)
        self._play_image = builder.get_object("play_image")
        self._pause_image = builder.get_object("pause_image")
        close_btn = builder.get_object("close_btn")
        preferences = Gio.Settings.new("org.gnome.desktop.wm.preferences")
        layout = preferences.get_value("button-layout").get_string()
        if layout.split(":")[0] == "close":
            widget.attach(close_btn, 0, 0, 1, 1)
            close_btn.set_property("halign", Gtk.Align.START)
        else:
            widget.attach(close_btn, 2, 0, 1, 1)
            close_btn.set_property("halign", Gtk.Align.END)
        self._cover = builder.get_object("cover")
        self._title_label = builder.get_object("title")
        self._artist_label = builder.get_object("artist")
        self._album_label = builder.get_object("album")

        self._datetime = builder.get_object("datetime")

        self._progress = builder.get_object("progress_scale")
        self._timelabel = builder.get_object("playback")
        self._total_time_label = builder.get_object("duration")
        self.connect("key-release-event", self.__on_key_release_event)
        self.add(widget)

    def do_show(self):
        """
            Init signals, set color and go party mode if nothing is playing
        """
        self.__signal1_id = Lp().player.connect("current-changed",
                                                self.on_current_changed)
        self.__signal2_id = Lp().player.connect("status-changed",
                                                self.on_status_changed)
        if Lp().player.current_track.id is None:
            Lp().player.set_party(True)
        else:
            self.on_status_changed(Lp().player)
            self.on_current_changed(Lp().player)
        if self.__timeout1 is None:
            self.__timeout1 = GLib.timeout_add(1000, self._update_position)
        Gtk.Window.do_show(self)
        self.__parent.set_skip_pager_hint(True)
        self.__parent.set_skip_taskbar_hint(True)
        if self.__timeout2 is None:
            try:
                interface = Gio.Settings.new("org.gnome.desktop.interface")
                show_seconds = interface.get_value("clock-show-seconds")
            except:
                show_seconds = False
            self.__update_datetime(show_seconds)
            self.__timeout2 = GLib.timeout_add(1000, self.__update_datetime,
                                               show_seconds)
        self._update_position(Lp().player.position / Gst.SECOND)
        screen = Gdk.Screen.get_default()
        monitor = screen.get_monitor_at_window(self.__parent.get_window())
        self.fullscreen_on_monitor(screen, monitor)
        self._next_popover.set_relative_to(self._next_btn)
        if Lp().player.next_track.id != Type.RADIOS:
            self._next_popover.show()

        # Disable screensaver (idle)
        Lp().inhibitor.manual_inhibit(suspend=False, idle=True)

    def do_hide(self):
        """
            Remove signals and unset color
        """
        self.__parent.set_skip_pager_hint(False)
        self.__parent.set_skip_taskbar_hint(False)
        Gtk.Window.do_hide(self)
        if self.__signal1_id is not None:
            Lp().player.disconnect(self.__signal1_id)
            self.__signal1_id = None
        if self.__signal2_id is not None:
            Lp().player.disconnect(self.__signal2_id)
            self.__signal2_id = None
        if self.__timeout1 is not None:
            GLib.source_remove(self.__timeout1)
            self.__timeout1 = None
        if self.__timeout2 is not None:
            GLib.source_remove(self.__timeout2)
        self._next_popover.set_relative_to(None)
        self._next_popover.hide()
        Lp().inhibitor.manual_uninhibit()

    def show_hide_volume_control(self):
        """
            Show/Hide volume control
        """
        self._show_volume_control = not self._show_volume_control
        self._update_state()

    def on_current_changed(self, player):
        """
            Update infos and show/hide popover
            @param player as Player
        """
        InfoController.on_current_changed(self, player)
        ProgressController.on_current_changed(self, player)
        if player.current_track.id is not None:
            album_name = player.current_track.album.name
            if player.current_track.year:
                album_name += " (%s)" % player.current_track.year
            self._album_label.set_text(album_name)
        # Do not show next popover non internal tracks as
        # tags will be readed on the fly
        if player.next_track.id is not None and player.next_track.id >= 0:
            self._next_popover.update()
            self._next_popover.show()
        else:
            self._next_popover.hide()

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

    def _on_close_button_clicked(self, widget):
        """
            Destroy self
            @param widget as Gtk.Button
        """
        self.destroy()

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

    def __update_datetime(self, show_seconds=False):
        """
            Update datetime in headerbar
            @param show_seconds as bool
        """
        now = datetime.now()
        if show_seconds:
            self._datetime.set_label(now.strftime("%a %d %b, %X"))
        else:
            self._datetime.set_label(now.strftime("%a %d %b, %X")[:-3])
        if self.__timeout2 is None:
            self.__timeout2 = GLib.timeout_add(60000, self.__update_datetime)
            return False
        return True

    def __on_key_release_event(self, widget, event):
        """
            Destroy window if Esc
            @param widget as Gtk.Widget
            @param event as Gdk.event
        """
        if event.keyval == Gdk.KEY_Escape:
            self.destroy()
Beispiel #23
0
class FullScreen(Gtk.Window):
    """
        Show a fullscreen window showing current track context
    """

    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        self.set_application(app)
        self._timeout1 = None
        self._timeout2 = None
        self._seeking = False
        self._signal1_id = None
        self._signal2_id = None
        self.set_decorated(False)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/FullScreen.ui')
        builder.connect_signals(self)

        # Calculate cover size
        screen = Gdk.Screen.get_default()
        monitor = screen.get_primary_monitor()
        geometry = screen.get_monitor_geometry(monitor)
        # We want 500 and 200 in full hd
        if geometry.width > geometry.height:
            self._artsize = int(ArtSize.MONSTER*geometry.width/1920)
        else:
            self._artsize = int(ArtSize.MONSTER*geometry.height/1920)

        self._play_btn = builder.get_object('play_btn')
        self._next_btn = builder.get_object('next_btn')
        self._prev_btn = builder.get_object('prev_btn')
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object('play_image')
        self._pause_image = builder.get_object('pause_image')
        close_btn = builder.get_object('close_btn')
        close_btn.connect('clicked', self._destroy)
        self._cover = builder.get_object('cover')
        self._title = builder.get_object('title')
        self._artist = builder.get_object('artist')
        self._album = builder.get_object('album')

        self._datetime = builder.get_object('datetime')

        self._progress = builder.get_object('progress_scale')
        self._timelabel = builder.get_object('playback')
        self._total_time_label = builder.get_object('duration')
        self.connect('key-release-event', self._on_key_release_event)
        self.add(builder.get_object('widget'))

    def do_show(self):
        """
            Init signals, set color and go party mode if nothing is playing
        """
        is_playing = Lp().player.is_playing()
        self._signal1_id = Lp().player.connect('current-changed',
                                               self._on_current_changed)
        self._signal2_id = Lp().player.connect('status-changed',
                                               self._on_status_changed)
        if Lp().player.current_track is None:
            Lp().player.set_party(True)
        else:
            if is_playing:
                self._change_play_btn_status(self._pause_image, _('Pause'))
            else:
                self._on_status_changed(Lp().player)
            self._on_current_changed(Lp().player)
        if self._timeout1 is None:
            self._timeout1 = GLib.timeout_add(1000, self._update_position)
        Gtk.Window.do_show(self)
        now = datetime.now()
        self._datetime.set_label(now.strftime('%a %d %b, %X')[:-3])
        if self._timeout2 is None:
            second = datetime.now().second
            if 60 - second > 0:
                GLib.timeout_add((60-second)*1000, self._update_datetime)
            else:
                self._timeout2 = GLib.timeout_add(60000, self._update_datetime)
        self._update_position()
        self.fullscreen()
        self._next_popover.set_relative_to(self._album)
        if Lp().player.next_track.id != Type.RADIOS:
            self._next_popover.show()

    def do_hide(self):
        """
            Remove signals and unset color
        """
        Gtk.Window.do_hide(self)
        if self._signal1_id is not None:
            Lp().player.disconnect(self._signal1_id)
            self._signal1_id = None
        if self._signal2_id is not None:
            Lp().player.disconnect(self._signal2_id)
            self._signal2_id = None
        if self._timeout1 is not None:
            GLib.source_remove(self._timeout1)
            self._timeout1 = None
        if self._timeout2 is not None:
            GLib.source_remove(self._timeout2)
        self._next_popover.set_relative_to(None)
        self._next_popover.hide()

#######################
# PRIVATE             #
#######################
    def _update_datetime(self):
        """
            Update datetime in headerbar
        """
        now = datetime.now()
        self._datetime.set_label(now.strftime('%a %d %b, %X')[:-3])
        if self._timeout2 is None:
            self._timeout2 = GLib.timeout_add(60000, self._update_datetime)
            return False
        return True

    def _change_play_btn_status(self, image, status):
        """
            Update play button with image and status as tooltip
            @param image as Gtk.Image
            @param status as str
        """
        self._play_btn.set_image(image)
        self._play_btn.set_tooltip_text(status)

    def _update_position(self, value=None):
        """
            Update progress bar position
            @param value as int
        """
        if not self._seeking and self._progress.is_visible():
            if value is None and Lp().player.get_status() != Gst.State.PAUSED:
                value = Lp().player.get_position_in_track()/1000000
            if value is not None:
                self._progress.set_value(value)
                self._timelabel.set_text(seconds_to_string(value/60))
        return True

    def _destroy(self, widget):
        """
            Destroy self
            @param widget as Gtk.Button
        """
        self.destroy()

    def _on_current_changed(self, player):
        """
            Update View for current track
                - Cover
                - artist/title
                - reset progress bar
                - update time/total labels
            @param player as Player
        """
        if player.current_track.id is not None:
            if Lp().player.current_track.id == Type.RADIOS:
                self._timelabel.hide()
                self._total_time_label.hide()
                self._progress.hide()
                surface = Lp().art.get_radio_artwork(
                    player.current_track.artist,
                    self._artsize*self.get_scale_factor())
            else:
                self._timelabel.show()
                self._total_time_label.show()
                self._progress.show()
                surface = Lp().art.get_album_artwork(
                    player.current_track.album,
                    self._artsize*self.get_scale_factor())
            self._cover.set_from_surface(surface)
            del surface

            album_name = player.current_track.album.name
            if player.current_track.year != '':
                album_name += " (%s)" % player.current_track.year
            self._title.set_text(player.current_track.title)
            self._artist.set_text(player.current_track.artist)
            self._album.set_text(album_name)
            self._progress.set_value(0.0)
            self._progress.set_range(0.0, player.current_track.duration * 60)
            self._total_time_label.set_text(
                seconds_to_string(player.current_track.duration))
            self._timelabel.set_text("0:00")

            # Can add a \n in markup
            # GTK bug => https://bugzilla.gnome.org/show_bug.cgi?id=749965
            prev_artist = escape(player.prev_track.artist)
            prev_title = escape(player.prev_track.title)
            next_artist = escape(player.next_track.artist)
            next_title = escape(player.next_track.title)
            self._next_btn.set_tooltip_markup("<b>%s</b> - %s" %
                                              (next_artist,
                                               next_title))
            self._prev_btn.set_tooltip_markup("<b>%s</b> - %s" %
                                              (prev_artist,
                                               prev_title))

            # Do not show next popover non internal tracks as
            # tags will be readed on the fly
            if player.next_track.id >= 0:
                self._next_popover.update()
                self._next_popover.show()
            else:
                self._next_popover.hide()

    def _on_key_release_event(self, widget, event):
        """
            Destroy window if Esc
            @param widget as Gtk.Widget
            @param event as Gdk.event
        """
        if event.keyval == Gdk.KEY_Escape:
            self.destroy()

    def _on_prev_btn_clicked(self, widget):
        """
            Go to prev track
            @param widget as Gtk.Button
        """
        Lp().player.prev()

    def _on_play_btn_clicked(self, widget):
        """
            Play/pause
            @param widget as Gtk.Button
        """
        if Lp().player.is_playing():
            Lp().player.pause()
            widget.set_image(self._play_image)
        else:
            Lp().player.play()
            widget.set_image(self._pause_image)

    def _on_next_btn_clicked(self, widget):
        """
            Go to next track
            @param widget as Gtk.Button
        """
        Lp().player.next()

    def _on_status_changed(self, obj):
        """
            Update buttons and progress bar
            @param obj as unused
        """
        is_playing = Lp().player.is_playing()
        if Lp().player.current_track.id != Type.RADIOS:
            self._progress.set_sensitive(is_playing)
        if is_playing and not self._timeout1:
            self._timeout1 = GLib.timeout_add(1000, self._update_position)
            self._change_play_btn_status(self._pause_image, _("Pause"))
        elif not is_playing and self._timeout1:
            GLib.source_remove(self._timeout1)
            self._timeout1 = None
            self._change_play_btn_status(self._play_image, _("Play"))

    def _on_progress_press_btn(self, scale, data):
        """
            On press, mark player as seeking
            @param unused
        """
        self._seeking = True

    def _on_progress_release_btn(self, scale, data):
        """
            Callback for scale release button
            Seek player to scale value
            @param scale as Gtk.Scale, data as unused
        """
        value = scale.get_value()
        Lp().player.seek(value/60)
        self._seeking = False
        self._update_position(value)
Beispiel #24
0
class ToolbarEnd(Gtk.Bin):
    """
        Toolbar end
    """

    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self.connect('show', self._on_show)
        self.connect('hide', self._on_hide)
        self._next_popover = NextPopover()
        self._search = None
        self._next_was_inhibited = False
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._grid_next = builder.get_object('grid-next')

        self._shuffle_button = builder.get_object('shuffle-button')
        self._shuffle_image = builder.get_object('shuffle-button-image')
        shuffleAction = Gio.SimpleAction.new('shuffle-button', None)
        shuffleAction.connect('activate', self._activate_shuffle_button)
        app.add_action(shuffleAction)
        app.set_accels_for_action("app.shuffle-button", ["<Control>r"])
        Lp().settings.connect('changed::shuffle', self._on_shuffle_changed)

        self._party_button = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        self._search_button = builder.get_object('search-button')
        search_action = Gio.SimpleAction.new('search', None)
        search_action.connect('activate', self._on_search_button_clicked)
        app.add_action(search_action)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self._settings_button = builder.get_object('settings-button')

        self._list_button = builder.get_object('list-button')
        self._list_button.set_property('has-tooltip', True)
        self._list_button.connect('query-tooltip',
                                  self._on_list_button_query_tooltip)
        list_action = Gio.SimpleAction.new('list', None)
        list_action.connect('activate', self._on_list_button_clicked)
        app.add_action(list_action)
        app.set_accels_for_action("app.list", ["<Control>i"])
        self._list_popover = None
        Lp().player.connect('party-changed', self._on_party_changed)
        Lp().player.connect('state-changed', self._on_lock_changed)

    def setup_menu(self, menu):
        """
            Add an application menu to menu button
            @parma: menu as Gio.Menu
        """
        self._settings_button.show()
        self._settings_button.set_menu_model(menu)

    def on_status_changed(self, player):
        """
            Update buttons on status changed
            @param player as Player
        """
        if player.is_playing():
            # Party mode can be activated
            # via Fullscreen class, so check button state
            self._party_button.set_active(player.is_party())

    def on_next_changed(self, player, force=False):
        """
            Show next popover
            @param player as Player
            @param force to show the popover
        """
        # Do not show popover is this menu is active
        # or if we are hidden
        if self._shuffle_button.get_active() or\
           not self._grid_next.is_visible():
            return
        if self._next_popover.should_be_shown() or force:
            if self._next_popover.is_visible():
                self._next_popover.update()
            else:
                self._next_popover.set_relative_to(self._grid_next)
                self._next_popover.show()
        else:
            self._next_popover.hide()

#######################
# PRIVATE             #
#######################
    def _on_lock_changed(self, player):
        """
            Lock toolbar
            @param player as Player
        """
        self._party_button.set_sensitive(not player.locked)
        self._list_button.set_sensitive(not player.locked)
        self._shuffle_button.set_sensitive(not player.locked)

    def _on_shuffle_button_clicked(self, button):
        """
            Hide next popover
            @param button as Gtk.Button
        """
        self._next_popover.hide()

    def _set_shuffle_icon(self):
        """
            Set shuffle icon
        """
        shuffle = Lp().settings.get_enum('shuffle')
        if shuffle == Shuffle.NONE:
            self._shuffle_image.get_style_context().remove_class('selected')
            self._shuffle_image.set_from_icon_name(
                "media-playlist-consecutive-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
        else:
            self._shuffle_image.set_from_icon_name(
                "media-playlist-shuffle-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
            if shuffle == Shuffle.TRACKS:
                self._shuffle_image.get_style_context().add_class('selected')
            else:
                self._shuffle_image.get_style_context().remove_class(
                                                                    'selected')

    def _activate_party_button(self, action=None, param=None):
        """
            Activate party button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self._party_button.set_active(not self._party_button.get_active())
        Lp().window.responsive_design()

    def _activate_shuffle_button(self, action=None, param=None):
        """
            Activate shuffle button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self._shuffle_button.set_active(not self._shuffle_button.get_active())

    def _on_shuffle_changed(self, settings, value):
        """
            Mark shuffle button as active when shuffle active
            @param settings as Gio.Settings, value as str
        """
        self._set_shuffle_icon()
        self._next_popover.hide()

    def _on_search_button_clicked(self, obj, param=None):
        """
            Show search widget on search button clicked
            @param obj as Gtk.Button or Gtk.Action
        """
        self._next_was_inhibited = self._next_popover.inhibited
        self._next_popover.hide()
        self._next_popover.inhibit(True)
        if self._search is None:
            self._search = SearchPopover()
            self._search.connect('closed', self._on_popover_closed)
        self._search.set_relative_to(self._search_button)
        self._search.show()

    def _on_party_button_toggled(self, button):
        """
            Set party mode on if party button active
            @param obj as Gtk.button
        """
        active = self._party_button.get_active()
        self._shuffle_button.set_sensitive(not active)
        if not Lp().settings.get_value('dark-ui'):
            settings = Gtk.Settings.get_default()
            settings.set_property("gtk-application-prefer-dark-theme", active)
        Lp().player.set_party(active)
        self.on_next_changed(Lp().player)

    def _on_party_changed(self, player, is_party):
        """
            On party change, sync toolbar
            @param player as Player
            @param is party as bool
        """
        if self._party_button.get_active() != is_party:
            self._activate_party_button()

    def _on_list_button_clicked(self, widget, unused=None):
        """
            Show current playback context popover
            @param widget as Gtk.Widget
        """
        if self._list_popover is not None:
            return
        self._next_was_inhibited = self._next_popover.inhibited
        self._next_popover.hide()
        self._next_popover.inhibit(True)
        if Lp().player.current_track.id == Type.EXTERNALS:
            self._list_popover = ExternalsPopover()
            self._list_popover.set_relative_to(self._list_button)
            self._list_popover.populate()
            self._list_popover.show()
        elif Lp().player.get_queue():
            self._list_popover = QueuePopover()
            self._list_popover.set_relative_to(self._list_button)
            self._list_popover.show()
        elif Lp().player.get_user_playlist_ids():
            self._list_popover = PlaylistsPopover()
            self._list_popover.set_relative_to(self._list_button)
            self._list_popover.show()
        else:
            self._list_popover = AlbumsPopover()
            self._list_popover.set_relative_to(self._list_button)
            self._list_popover.show()
        self._list_popover.connect('closed', self._on_list_popover_closed)
        return True

    def _on_list_popover_closed(self, popover):
        """
            Reset variable
            @param popover as Gtk.Popover
        """
        self._list_popover = None
        self._on_popover_closed(popover)

    def _on_popover_closed(self, popover):
        """
            Restore next popover if needed
            @param popover as Gtk.Popover
        """
        if not self._next_was_inhibited:
            self._next_popover.inhibit(False)
        if self._next_popover.should_be_shown():
            self._next_popover.show()

    def _on_show(self, widget):
        """
            Show popover if needed
            @param widget as Gtk.Widget
        """
        self._set_shuffle_icon()

    def _on_hide(self, widget):
        """
            Hide popover
            @param widget as Gtk.Widget
        """
        self._next_popover.hide()

    def _on_button_press_event(self, eventbox, event):
        """
            Show party popover
            @param eventbox as Gtk.EventBox
            @param event as Gdk.Event
        """
        if event.button == 3:
            popover = PartyPopover()
            popover.set_relative_to(eventbox)
            self._next_popover.hide()
            popover.connect('closed', self._on_popover_closed)
            self._next_popover.inhibit(True)
            popover.show()
            return True

    def _on_list_button_query_tooltip(self, widget, x, y, keyboard, tooltip):
        """
            Show tooltip
            @param widget as Gtk.Widget
            @param x as int
            @param y as int
            @param keyboard as bool
            @param tooltip as Gtk.Tooltip
        """
        if Lp().player.current_track.id == Type.EXTERNALS:
            widget.set_tooltip_text(_("Externals tracks playing"))
        elif Lp().player.get_queue():
            widget.set_tooltip_text(_("Queue"))
        elif Lp().player.get_user_playlist_ids():
            widget.set_tooltip_text(_("Playing playlists"))
        else:
            widget.set_tooltip_text(_("Playing albums"))
Beispiel #25
0
class FullScreen(Gtk.Window, InfosController,
                 PlaybackController, ProgressController):
    """
        Show a fullscreen window showing current track context
    """

    def __init__(self, app, parent):
        """
            Init window and set transient for parent
            @param app as Gio.Application
            @param parent as Gtk.window
        """
        Gtk.Window.__init__(self)
        PlaybackController.__init__(self)
        ProgressController.__init__(self)
        self.set_application(app)
        self._timeout1 = None
        self._timeout2 = None
        self._seeking = False
        self._signal1_id = None
        self._signal2_id = None
        self.set_decorated(False)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/FullScreen.ui')
        builder.connect_signals(self)

        # Calculate cover size
        screen = Gdk.Screen.get_default()
        monitor = screen.get_primary_monitor()
        geometry = screen.get_monitor_geometry(monitor)
        # We want 500 and 200 in full hd
        if geometry.width > geometry.height:
            artsize = int(ArtSize.MONSTER*geometry.width/1920)
        else:
            artsize = int(ArtSize.MONSTER*geometry.height/1920)
        InfosController.__init__(self, artsize)

        self._play_btn = builder.get_object('play_btn')
        self._next_btn = builder.get_object('next_btn')
        self._prev_btn = builder.get_object('prev_btn')
        self._next_popover = NextPopover()
        self._next_popover.set_position(Gtk.PositionType.BOTTOM)
        self._play_image = builder.get_object('play_image')
        self._pause_image = builder.get_object('pause_image')
        close_btn = builder.get_object('close_btn')
        close_btn.connect('clicked', self._destroy)
        self._cover = builder.get_object('cover')
        self._cover_frame = builder.get_object('frame')
        self._title_label = builder.get_object('title')
        self._artist_label = builder.get_object('artist')
        self._album_label = builder.get_object('album')

        self._datetime = builder.get_object('datetime')

        self._progress = builder.get_object('progress_scale')
        self._timelabel = builder.get_object('playback')
        self._total_time_label = builder.get_object('duration')
        self.connect('key-release-event', self._on_key_release_event)
        self.add(builder.get_object('widget'))

    def do_show(self):
        """
            Init signals, set color and go party mode if nothing is playing
        """
        self._signal1_id = Lp().player.connect('current-changed',
                                               self.on_current_changed)
        self._signal2_id = Lp().player.connect('status-changed',
                                               self.on_status_changed)
        if Lp().player.current_track.id is None:
            Lp().player.set_party(True)
        else:
            self.on_status_changed(Lp().player)
            self.on_current_changed(Lp().player)
        if self._timeout1 is None:
            self._timeout1 = GLib.timeout_add(1000, self._update_position)
        Gtk.Window.do_show(self)
        now = datetime.now()
        self._datetime.set_label(now.strftime('%a %d %b, %X')[:-3])
        if self._timeout2 is None:
            second = datetime.now().second
            if 60 - second > 0:
                GLib.timeout_add((60-second)*1000, self._update_datetime)
            else:
                self._timeout2 = GLib.timeout_add(60000, self._update_datetime)
        self._update_position()
        self.fullscreen()
        self._next_popover.set_relative_to(self._album_label)
        if Lp().player.next_track.id != Type.RADIOS:
            self._next_popover.show()

    def do_hide(self):
        """
            Remove signals and unset color
        """
        Gtk.Window.do_hide(self)
        if self._signal1_id is not None:
            Lp().player.disconnect(self._signal1_id)
            self._signal1_id = None
        if self._signal2_id is not None:
            Lp().player.disconnect(self._signal2_id)
            self._signal2_id = None
        if self._timeout1 is not None:
            GLib.source_remove(self._timeout1)
            self._timeout1 = None
        if self._timeout2 is not None:
            GLib.source_remove(self._timeout2)
        self._next_popover.set_relative_to(None)
        self._next_popover.hide()

    def on_current_changed(self, player):
        """
            Update infos and show/hide popover
            @param player as Player
        """
        InfosController.on_current_changed(self, player)
        ProgressController.on_current_changed(self, player)
        if player.current_track.id is not None:
            album_name = player.current_track.album.name
            if player.current_track.year != '':
                album_name += " (%s)" % player.current_track.year
            self._album_label.set_text(album_name)
        # Do not show next popover non internal tracks as
        # tags will be readed on the fly
        if player.next_track.id >= 0:
            self._next_popover.update()
            self._next_popover.show()
        else:
            self._next_popover.hide()

#######################
# PRIVATE             #
#######################
    def _update_datetime(self):
        """
            Update datetime in headerbar
        """
        now = datetime.now()
        self._datetime.set_label(now.strftime('%a %d %b, %X')[:-3])
        if self._timeout2 is None:
            self._timeout2 = GLib.timeout_add(60000, self._update_datetime)
            return False
        return True

    def _destroy(self, widget):
        """
            Destroy self
            @param widget as Gtk.Button
        """
        self.destroy()

    def _on_key_release_event(self, widget, event):
        """
            Destroy window if Esc
            @param widget as Gtk.Widget
            @param event as Gdk.event
        """
        if event.keyval == Gdk.KEY_Escape:
            self.destroy()
Beispiel #26
0
class ToolbarEnd(Gtk.Bin):
    """
        Toolbar end
    """
    def __init__(self, app):
        """
            Init toolbar
            @param app as Gtk.Application
        """
        Gtk.Bin.__init__(self)
        self.connect('show', self._on_show)
        self.connect('hide', self._on_hide)
        self._next_popover = NextPopover()
        self._search = None
        self._timeout_id = None
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/ToolbarEnd.ui')
        builder.connect_signals(self)

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

        self._grid_next = builder.get_object('grid-next')

        self._shuffle_button = builder.get_object('shuffle-button')
        self._shuffle_image = builder.get_object('shuffle-button-image')
        shuffleAction = Gio.SimpleAction.new('shuffle-button', None)
        shuffleAction.connect('activate', self._activate_shuffle_button)
        app.add_action(shuffleAction)
        app.set_accels_for_action("app.shuffle-button", ["<Control>r"])
        Lp().settings.connect('changed::shuffle', self._on_shuffle_changed)

        self._party_button = builder.get_object('party-button')
        party_action = Gio.SimpleAction.new('party', None)
        party_action.connect('activate', self._activate_party_button)
        app.add_action(party_action)
        app.set_accels_for_action("app.party", ["<Control>p"])

        self._search_button = builder.get_object('search-button')
        search_action = Gio.SimpleAction.new('search', None)
        search_action.connect('activate', self._on_search_button_clicked)
        app.add_action(search_action)
        app.set_accels_for_action("app.search", ["<Control>f"])

        self._settings_button = builder.get_object('settings-button')

        self._list_button = builder.get_object('list-button')
        self._list_button.set_property('has-tooltip', True)
        self._list_button.connect('query-tooltip',
                                  self._on_list_button_query_tooltip)
        list_action = Gio.SimpleAction.new('list', None)
        list_action.connect('activate', self._on_list_button_clicked)
        app.add_action(list_action)
        app.set_accels_for_action("app.list", ["<Control>l"])
        self._list_popover = None
        Lp().player.connect('party-changed', self._on_party_changed)

    def setup_menu(self, menu):
        """
            Add an application menu to menu button
            @parma: menu as Gio.Menu
        """
        self._settings_button.show()
        self._settings_button.set_menu_model(menu)

    def on_status_changed(self, player):
        """
            Update buttons on status changed
            @param player as Player
        """
        if player.is_playing():
            # Party mode can be activated
            # via Fullscreen class, so check button state
            self._party_button.set_active(player.is_party())

    def on_next_changed(self, player, force=False):
        """
            Show next popover
            @param player as Player
            @param force to show the popover
        """
        # Do not show popover is this menu is active
        # or if we are hidden
        if self._shuffle_button.get_active() or\
           not self._grid_next.is_visible():
            return
        self._timeout_id = None
        if self._next_popover.should_be_shown() or force:
            self._next_popover.update()
            if not self._next_popover.is_visible():
                self._next_popover.set_relative_to(self._grid_next)
                self._next_popover.show()
        else:
            self._next_popover.hide()

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

    def _on_shuffle_button_clicked(self, button):
        """
            Hide next popover
            @param button as Gtk.Button
        """
        self._next_popover.hide()

    def _on_button_press(self, button, event):
        """
            Show next popover on long press
            @param button as Gtk.Button
            @param event as Gdk.Event
        """
        self._timeout_id = GLib.timeout_add(500, self.on_next_changed,
                                            Lp().player, True)

    def _on_button_release(self, button, event):
        """
            If next popover shown, block event
            @param button as Gtk.Button
            @param event as Gdk.Event
        """
        if self._timeout_id is None:
            return True
        else:
            GLib.source_remove(self._timeout_id)
            self._timeout_id = None

    def _set_shuffle_icon(self):
        """
            Set shuffle icon
        """
        shuffle = Lp().settings.get_enum('shuffle')
        if shuffle == Shuffle.NONE:
            self._shuffle_image.get_style_context().remove_class('selected')
            self._shuffle_image.set_from_icon_name(
                "media-playlist-consecutive-symbolic",
                Gtk.IconSize.SMALL_TOOLBAR)
        else:
            self._shuffle_image.set_from_icon_name(
                "media-playlist-shuffle-symbolic", Gtk.IconSize.SMALL_TOOLBAR)
            if shuffle == Shuffle.TRACKS:
                self._shuffle_image.get_style_context().add_class('selected')
            else:
                self._shuffle_image.get_style_context().remove_class(
                    'selected')

    def _activate_party_button(self, action=None, param=None):
        """
            Activate party button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self._party_button.set_active(not self._party_button.get_active())
        Lp().window.responsive_design()

    def _activate_shuffle_button(self, action=None, param=None):
        """
            Activate shuffle button
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        self._shuffle_button.set_active(not self._shuffle_button.get_active())

    def _on_shuffle_changed(self, settings, value):
        """
            Mark shuffle button as active when shuffle active
            @param settings as Gio.Settings, value as str
        """
        self._set_shuffle_icon()
        self._next_popover.hide()

    def _on_search_button_clicked(self, obj, param=None):
        """
            Show search widget on search button clicked
            @param obj as Gtk.Button or Gtk.Action
        """
        if self._search is None:
            self._search = SearchPopover()
            self._search.connect('closed', self._on_popover_closed)
        self._search.set_relative_to(self._search_button)
        self._next_popover.hide()
        self._search.show()

    def _on_party_button_toggled(self, button):
        """
            Set party mode on if party button active
            @param obj as Gtk.button
        """
        active = self._party_button.get_active()
        self._shuffle_button.set_sensitive(not active)
        if not Lp().settings.get_value('dark-ui'):
            settings = Gtk.Settings.get_default()
            settings.set_property("gtk-application-prefer-dark-theme", active)
        Lp().player.set_party(active)
        self.on_next_changed(Lp().player)

    def _on_party_changed(self, player, is_party):
        """
            On party change, sync toolbar
            @param player as Player
            @param is party as bool
        """
        if self._party_button.get_active() != is_party:
            self._activate_party_button()

    def _on_list_button_clicked(self, widget, unused=None):
        """
            Show current playback context popover
            @param widget as Gtk.Widget
        """
        if self._list_popover is not None:
            return
        self._next_popover.hide()
        if Lp().player.current_track.id == Type.EXTERNALS:
            self._list_popover = ExternalsPopover()
            self._list_popover.set_relative_to(self._list_button)
            self._list_popover.populate()
            self._list_popover.show()
        elif Lp().player.get_queue():
            self._list_popover = QueuePopover()
            self._list_popover.set_relative_to(self._list_button)
            self._list_popover.show()
        elif Lp().player.get_user_playlist_ids():
            self._list_popover = PlaylistsPopover()
            self._list_popover.set_relative_to(self._list_button)
            self._list_popover.show()
        else:
            self._list_popover = AlbumsPopover()
            self._list_popover.set_relative_to(self._list_button)
            self._list_popover.show()
        self._list_popover.connect('closed', self._on_list_popover_closed)
        return True

    def _on_list_popover_closed(self, popover):
        """
            Reset variable
            @param popover as Gtk.Popover
        """
        self._list_popover = None
        self._on_popover_closed(popover)

    def _on_popover_closed(self, popover):
        """
            Restore next popover if needed
            @param popover as Gtk.Popover
        """
        if self._next_popover.should_be_shown():
            self._next_popover.show()

    def _on_show(self, widget):
        """
            Show popover if needed
            @param widget as Gtk.Widget
        """
        self._set_shuffle_icon()

    def _on_hide(self, widget):
        """
            Hide popover
            @param widget as Gtk.Widget
        """
        self._next_popover.hide()

    def _on_list_button_query_tooltip(self, widget, x, y, keyboard, tooltip):
        """
            Show tooltip
            @param widget as Gtk.Widget
            @param x as int
            @param y as int
            @param keyboard as bool
            @param tooltip as Gtk.Tooltip
        """
        if Lp().player.current_track.id == Type.EXTERNALS:
            widget.set_tooltip_text(_("Externals tracks playing"))
        elif Lp().player.get_queue():
            widget.set_tooltip_text(_("Queue"))
        elif Lp().player.get_user_playlist_ids():
            widget.set_tooltip_text(_("Playing playlists"))
        else:
            widget.set_tooltip_text(_("Playing albums"))