[gnome-music/wip/feborges/playback-popover] player: Introduce the Playback Popover
- From: Felipe Borges <felipeborges src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/feborges/playback-popover] player: Introduce the Playback Popover
- Date: Thu, 1 Feb 2018 11:25:55 +0000 (UTC)
commit 27db20988296969e9775f89fe3fcc9c6594a53ee
Author: Felipe Borges <felipeborges gnome org>
Date: Sun Jan 28 20:36:37 2018 +0100
player: Introduce the Playback Popover
This widget allows the user to browse through the app without
losing track of the current playlist (what's playing next).
It is based this wireframes
https://raw.githubusercontent.com/gnome-design-team/gnome-mockups/
master/music/wire-playback-buffer.png
This feature has been worked on Outreachy by Jordana Luft, but
that branch differs entirely from the current state of the code
base. Its been two years.
Fixes #14
data/PlaybackPopover.ui | 39 +++++++++++++
data/PlayerToolbar.ui | 102 +++++++++++++++++---------------
data/gnome-music.gresource.xml | 1 +
gnomemusic/player.py | 8 +++
gnomemusic/widgets/Makefile.am | 1 +
gnomemusic/widgets/playbackpopover.py | 106 ++++++++++++++++++++++++++++++++++
6 files changed, 210 insertions(+), 47 deletions(-)
---
diff --git a/data/PlaybackPopover.ui b/data/PlaybackPopover.ui
new file mode 100644
index 0000000..e16d96b
--- /dev/null
+++ b/data/PlaybackPopover.ui
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface domain="gnome-music">
+ <requires lib="gtk+" version="3.12"/>
+ <object class="GtkBox" id="playback_popover">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="width-request">480</property>
+ <property name="height-request">360</property>
+ <child>
+ <object class="GtkHeaderBar">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Now playing</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <child>
+ <object class="GtkListBox" id="playback_popover_list">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <style>
+ <class name="background"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/data/PlayerToolbar.ui b/data/PlayerToolbar.ui
index 53028c6..ce5d5c5 100644
--- a/data/PlayerToolbar.ui
+++ b/data/PlayerToolbar.ui
@@ -115,65 +115,78 @@
</object>
</child>
<child>
- <object class="GtkBox" id="nowplaying">
+ <object class="GtkToggleButton" id="nowplaying_button">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="spacing">8</property>
- <child>
- <object class="GtkImage" id="cover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
+ <style>
+ <class name="flat"/>
+ </style>
<child>
- <object class="GtkBox" id="nowplaying_labels">
+ <object class="GtkBox" id="nowplaying">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
- <property name="orientation">vertical</property>
- <property name="homogeneous">True</property>
+ <property name="spacing">8</property>
<child>
- <object class="GtkLabel" id="artist">
+ <object class="GtkImage" id="cover">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="valign">start</property>
- <property name="xalign">0</property>
- <property name="ellipsize">middle</property>
- <property name="width_chars">8</property>
- <property name="max_width_chars">42</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="0.90000000000000002"/>
- </attributes>
</object>
<packing>
<property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="title">
+ <object class="GtkBox" id="nowplaying_labels">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="valign">start</property>
- <property name="xalign">0</property>
- <property name="ellipsize">middle</property>
- <property name="width_chars">8</property>
- <property name="max_width_chars">42</property>
- <attributes>
- <attribute name="scale" value="0.90000000000000002"/>
- </attributes>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="orientation">vertical</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkLabel" id="artist">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="ellipsize">middle</property>
+ <property name="width_chars">8</property>
+ <property name="max_width_chars">42</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="scale" value="0.90000000000000002"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="ellipsize">middle</property>
+ <property name="width_chars">8</property>
+ <property name="max_width_chars">42</property>
+ <attributes>
+ <attribute name="scale" value="0.90000000000000002"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">False</property>
@@ -182,11 +195,6 @@
</packing>
</child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
</child>
@@ -290,7 +298,7 @@
<property name="icon_size">1</property>
</object>
<packing>
- <property name="expand">False</property>
+ <property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
diff --git a/data/gnome-music.gresource.xml b/data/gnome-music.gresource.xml
index d98bb47..ffcbb16 100644
--- a/data/gnome-music.gresource.xml
+++ b/data/gnome-music.gresource.xml
@@ -15,6 +15,7 @@
<file preprocess="xml-stripblanks">headerbar.ui</file>
<file preprocess="xml-stripblanks">TrackWidget.ui</file>
<file preprocess="xml-stripblanks">NoMusic.ui</file>
+ <file preprocess="xml-stripblanks">PlaybackPopover.ui</file>
<file preprocess="xml-stripblanks">PlaylistContextMenu.ui</file>
<file preprocess="xml-stripblanks">PlaylistControls.ui</file>
<file preprocess="xml-stripblanks">PlaylistDialog.ui</file>
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index e0f98e5..b6eb6f7 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -50,6 +50,7 @@ from gnomemusic.albumartcache import AlbumArtCache, DefaultIcon, ArtSize
from gnomemusic.grilo import grilo
from gnomemusic.playlists import Playlists
from gnomemusic.scrobbler import LastFmScrobbler
+from gnomemusic.widgets.playbackpopover import PlaybackPopover
import gnomemusic.utils as utils
@@ -775,6 +776,8 @@ class Player(GObject.GObject):
self.nextBtn = self._ui.get_object('next_button')
self._playImage = self._ui.get_object('play_image')
self._pauseImage = self._ui.get_object('pause_image')
+ self._nowplayingButton = self._ui.get_object('nowplaying_button')
+ self._playbackPopover = PlaybackPopover(self._nowplayingButton, self)
self.progressScale = self._ui.get_object('progress_scale')
self.songPlaybackTimeLabel = self._ui.get_object('playback')
self.songTotalTimeLabel = self._ui.get_object('duration')
@@ -792,6 +795,7 @@ class Player(GObject.GObject):
self.prevBtn.connect('clicked', self._on_prev_btn_clicked)
self.playBtn.connect('clicked', self._on_play_btn_clicked)
self.nextBtn.connect('clicked', self._on_next_btn_clicked)
+ self._playbackPopover.connect('current-changed', self._on_playback_popover_current_changed)
self.progressScale.connect('button-press-event', self._on_progress_scale_event)
self.progressScale.connect('value-changed', self._on_progress_value_changed)
self.progressScale.connect('button-release-event', self._on_progress_scale_button_released)
@@ -802,6 +806,10 @@ class Player(GObject.GObject):
self._old_progress_scale_value = 0.0
self.progressScale.set_increments(300, 600)
+ def _on_playback_popover_current_changed(self, popover, iter):
+ self.currentTrack = Gtk.TreeRowReference.new(self.playlist, self.playlist.get_path(iter))
+ self.play()
+
def _on_progress_scale_seek_finish(self, value):
"""Prevent stutters when seeking with infinitesimal amounts"""
self._seek_timeout = None
diff --git a/gnomemusic/widgets/Makefile.am b/gnomemusic/widgets/Makefile.am
index e02db58..9deffc2 100644
--- a/gnomemusic/widgets/Makefile.am
+++ b/gnomemusic/widgets/Makefile.am
@@ -6,5 +6,6 @@ app_PYTHON = \
artistalbumswidget.py \
artistalbumwidget.py \
disclistboxwidget.py \
+ playbackpopover.py \
playlistdialog.py \
starhandlerwidget.py
diff --git a/gnomemusic/widgets/playbackpopover.py b/gnomemusic/widgets/playbackpopover.py
new file mode 100644
index 0000000..a144ee8
--- /dev/null
+++ b/gnomemusic/widgets/playbackpopover.py
@@ -0,0 +1,106 @@
+# Copyright (C) 2018 Felipe Borges felipeborges gnome org
+#
+# GNOME Music is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GNOME Music is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The GNOME Music authors hereby grant permission for non-GPL compatible
+# GStreamer plugins to be used and distributed together with GStreamer
+# and GNOME Music. This permission is above and beyond the permissions
+# granted by the GPL license by which GNOME Music is covered. If you
+# modify this code, you may extend this exception to your version of the
+# code, but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version.
+
+from gi.repository import Gio, GObject, Gtk
+
+from gnomemusic.albumartcache import ArtSize
+import gnomemusic.utils as utils
+
+class PlaybackItem(GObject.Object):
+ def __init__(self, data, iter):
+ super().__init__()
+
+ self.media = data[5]
+ self.iter = iter
+ self.title = utils.get_media_title(self.media)
+ self.artist = utils.get_artist_name(self.media)
+
+
+class PlaybackEntry(Gtk.ListBoxRow):
+ def __init__(self, item, player):
+ super().__init__()
+
+ self.iter = item.iter
+
+ grid = Gtk.Grid(border_width=5, column_spacing=5, row_spacing=2)
+ self.add(grid)
+
+ self.cover = Gtk.Image()
+ artistLabel = Gtk.Label(label=item.artist, halign=Gtk.Align.START)
+ artistLabel.get_style_context().add_class('dim-label')
+
+ grid.attach(self.cover, 1, 0, 1, 2)
+ grid.attach(Gtk.Label(label=item.title, halign=Gtk.Align.START), 2, 0, 1, 1)
+ grid.attach(artistLabel, 2, 1, 1, 1)
+
+ player.cache.lookup(item.media, ArtSize.SMALL, self._on_cache_lookup, None)
+
+ self.show_all()
+
+ def _on_cache_lookup(self, surface, data=None):
+ self.cover.set_from_surface(surface)
+
+class PlaybackPopover(Gtk.Popover):
+
+ __gsignals__ = {
+ 'current-changed': (GObject.SignalFlags.RUN_FIRST, None, (Gtk.TreeIter,)),
+ }
+
+ def __repr__(self):
+ return '<PlaybackPopover>'
+
+ def __init__(self, button, player):
+ super().__init__(relative_to = button)
+
+ self._player = player
+
+ self._setup_view ()
+
+ self._player.connect('playlist-item-changed', self._update_model)
+ button.connect('toggled', self._on_button_toggled)
+
+ def _setup_view(self):
+ self._ui = Gtk.Builder()
+ self._ui.add_from_resource('/org/gnome/Music/PlaybackPopover.ui')
+
+ self.add(self._ui.get_object('playback_popover'))
+ self._trackList = self._ui.get_object('playback_popover_list')
+ self._model = Gio.ListStore()
+ def create_popover_entry(item, user_data):
+ return PlaybackEntry(item, user_data)
+ self._trackList.bind_model(self._model, create_popover_entry, self._player)
+ self._trackList.connect('row-activated', self._on_row_activated)
+
+ def _on_row_activated(self, box, row):
+ self.emit('current-changed', row.iter)
+
+ def _update_model(self, player, playlist, current_iter):
+ self._model.remove_all()
+ while current_iter != None:
+ item = PlaybackItem(playlist[current_iter], current_iter)
+ self._model.append(item)
+ current_iter = playlist.iter_next(current_iter)
+
+ def _on_button_toggled(self, button):
+ self.popup()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]