Merge branch 'now-playing' into 'master'

Adaptive "Now Playing" toolbar

Closes #158

See merge request World/podcasts!131
This commit is contained in:
James Westman 2020-02-01 14:01:42 +00:00
commit 47059f3d11
9 changed files with 1257 additions and 360 deletions

View File

@ -0,0 +1,300 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<requires lib="libhandy" version="0.0"/>
<object class="HdyDialog" id="dialog">
<property name="can_focus">False</property>
<property name="type_hint">dialog</property>
<property name="modal">True</property>
<child type="titlebar">
<object class="HdyHeaderBar" id="headerbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Now Playing</property>
<child>
<object class="GtkButton" id="close">
<property name="visible">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">6</property>
<property name="margin_right">6</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage" id="cover">
<property name="width_request">256</property>
<property name="height_request">256</property>
<property name="margin">18</property>
<property name="margin-top">36</property>
<property name="margin-bottom">6</property>
<property name="valign">center</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="spacing">6</property>
<property name="orientation">vertical</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<child>
<object class="GtkLabel" id="episode_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="label">Episode Title</property>
<property name="wrap">True</property>
<property name="justify">center</property>
<style>
<class name="bold-label" />
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="show_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="label">Show Title</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<child>
<object class="GtkLabel" id="progressed">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="width_chars">5</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
<class name="small-label"/>
</style>
</object>
</child>
<child>
<object class="GtkScale" id="slider">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="draw_value">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="duration">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="width_chars">5</property>
<style>
<class name="dim-label"/>
<class name="small-label"/>
</style>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="spacing">12</property>
<child>
<object class="GtkButton" id="rewind">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_request">60</property>
<property name="height_request">60</property>
<property name="valign">center</property>
<property name="margin-end">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">skip-back-large-symbolic</property>
<property name="icon_size">5</property>
</object>
</child>
<style>
<class name="circular"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkStack" id="play_pause">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="play">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="width_request">80</property>
<property name="height_request">80</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">media-playback-start-symbolic</property>
<property name="icon_size">6</property>
</object>
</child>
<style>
<class name="circular"/>
</style>
</object>
</child>
<child>
<object class="GtkButton" id="pause">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_request">80</property>
<property name="height_request">80</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">media-playback-pause-symbolic</property>
<property name="icon_size">6</property>
</object>
</child>
<style>
<class name="circular"/>
</style>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="forward">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="width_request">60</property>
<property name="height_request">60</property>
<property name="valign">center</property>
<property name="margin-start">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">skip-forward-large-symbolic</property>
<property name="icon_size">5</property>
</object>
</child>
<style>
<class name="circular"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkBox" id="bottom">
<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="pack_type">end</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0
Copyright (C) 2017 - 2018
This file is part of GNOME Podcast.
GNOME Podcast 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 3 of the License, or
(at your option) any later version.
GNOME Podcast 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 Podcast. If not, see <http://www.gnu.org/licenses/>.
Authors:
Jordan Petridis
Tobias Bernard
-->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkMenuButton" id="rate_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Change the playback speed</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_start">6</property>
<property name="direction">up</property>
<property name="popover">rate_popover</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="rate_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">1.00×</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">pan-down-symbolic</property>
<property name="icon_size">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkPopover" id="rate_popover">
<property name="can_focus">False</property>
<property name="relative_to">rate_button</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">6</property>
<property name="margin_end">6</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="orientation">vertical</property>
<property name="spacing">3</property>
<child>
<object class="GtkRadioButton" id="rate_1_50">
<property name="label" translatable="yes">1.50×</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">1.5 speed rate</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="draw_indicator">True</property>
<property name="group">normal_rate</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="rate_1_25">
<property name="label" translatable="yes">1.25×</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">1.25 speed rate</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="draw_indicator">True</property>
<property name="group">normal_rate</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="normal_rate">
<property name="label" translatable="yes">1.00×</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Normal speed</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -54,344 +54,365 @@ Tobias Bernard
<property name="can_focus">False</property>
<property name="icon_name">skip-back-symbolic</property>
</object>
<object class="GtkActionBar" id="action_bar">
<object class="GtkBox" id="container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<property name="spacing">0</property>
<child>
<object class="GtkBox" id="buttons">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<child>
<object class="GtkButton" id="rewind_button">
<property name="width_request">42</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Rewind 10 seconds</property>
<property name="image">rewind</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="play_button">
<property name="width_request">60</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Play</property>
<property name="image">play_image</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="pause_button">
<property name="width_request">60</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Pause</property>
<property name="image">pause_image</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ff_button">
<property name="width_request">42</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Fast forward 10 seconds</property>
<property name="image">fast_forward</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<object class="GtkProgressBar" id="progress_bar">
<property name="no_show_all">True</property>
<style>
<class name="linked"/>
<class name="playback-progress"/>
</style>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="info">
<object class="GtkEventBox" id="evbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkImage" id="show_cover">
<property name="visible">True</property>
<object class="GtkActionBar" id="action_bar">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="valign">center</property>
<property name="pixel_size">34</property>
<property name="icon_name">image-x-generic-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="show_label">
<object class="HdySqueezer" id="squeezer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label">Show Title</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<property name="max_width_chars">20</property>
<style>
<class name="player-show-label"/>
</style>
<property name="transition_type">crossfade</property>
<child>
<object class="GtkBox" id="full">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<object class="GtkBox" id="buttons">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<child>
<object class="GtkButton" id="rewind_button">
<property name="width_request">42</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Rewind 10 seconds</property>
<property name="image">rewind</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="play_button">
<property name="width_request">60</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Play</property>
<property name="image">play_image</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="pause_button">
<property name="width_request">60</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Pause</property>
<property name="image">pause_image</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ff_button">
<property name="width_request">42</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Fast forward 10 seconds</property>
<property name="image">fast_forward</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="info">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="width_request">150</property>
<child>
<object class="GtkImage" id="show_cover">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="pixel_size">34</property>
<property name="icon_name">image-x-generic-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="show_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label">Show Title</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<property name="max_width_chars">20</property>
<property name="xalign">0</property>
<style>
<class name="player-show-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="episode_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label">Episode Title</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<property name="max_width_chars">20</property>
<property name="xalign">0</property>
<style>
<class name="player-episode-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkScale" id="seek">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="round_digits">1</property>
<property name="draw_value">False</property>
<property name="width_request">150</property>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="timer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="progress_time_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label">0:00</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label">/</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="total_duration_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label">0:00</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="small">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkImage" id="show_cover_small">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="pixel_size">34</property>
<property name="icon_name">image-x-generic-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="show_label_small">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label">Show Title</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<style>
<class name="player-show-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="episode_label_small">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label">Episode Title</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<style>
<class name="player-episode-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStack" id="play_pause_small">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="play_button_small">
<property name="visible">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">media-playback-start-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="pause_button_small">
<property name="visible">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">media-playback-pause-symbolic</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="episode_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label">Episode Title</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<property name="max_width_chars">20</property>
<style>
<class name="player-episode-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="player-actionbar"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkScale" id="seek">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="round_digits">1</property>
<property name="draw_value">False</property>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="timer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="progress_time_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label">0:00</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label">/</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="total_duration_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label">0:00</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="rate_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Change the playback speed</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_start">6</property>
<property name="direction">up</property>
<property name="popover">rate_popover</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="rate_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">1.00×</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-down-symbolic</property>
<property name="icon_size">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="position">4</property>
</packing>
</child>
</object>
<object class="GtkPopover" id="rate_popover">
<property name="can_focus">False</property>
<property name="relative_to">rate_button</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">6</property>
<property name="margin_end">6</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="orientation">vertical</property>
<property name="spacing">3</property>
<child>
<object class="GtkRadioButton" id="rate_1_50">
<property name="label" translatable="yes">1.50×</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">1.5 speed rate</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="draw_indicator">True</property>
<property name="group">normal_rate</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="rate_1_25">
<property name="label" translatable="yes">1.25×</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">1.25 speed rate</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="draw_indicator">True</property>
<property name="group">normal_rate</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="normal_rate">
<property name="label" translatable="yes">1.00×</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Normal speed</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>

View File

@ -18,3 +18,24 @@ list, border {
.player-show-label {
font-size: smaller;
}
.small-label {
font-size: smaller;
}
.bold-label {
font-weight: bold;
}
progressbar.playback-progress trough {
border-radius: 0;
}
progressbar.playback-progress trough progress {
border-radius: 0;
border-right: none;
border-left: none;
}
actionbar.player-small revealer box {
border-top: none
}

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 8.4666665 8.4666669"
version="1.1"
id="svg2916"
sodipodi:docname="skip-back-large-symbolic.svg"
inkscape:version="0.92.4 (unknown)">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="731"
id="namedview11"
showgrid="false"
inkscape:zoom="7.375"
inkscape:cx="16"
inkscape:cy="16"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2916" />
<defs
id="defs2910" />
<metadata
id="metadata2913">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 4.2324219,1.3222656 a 0.26464845,0.26464845 0 1 0 0,0.5292969 C 5.3033196,1.8515612 6.2679165,2.4969489 6.6777344,3.4863281 7.0875525,4.4757119 6.8607584,5.6118992 6.1035156,6.3691406 5.3462755,7.1263812 4.2100855,7.3531746 3.2207031,6.9433594 2.2313192,6.5335432 1.5878886,5.5689483 1.5878906,4.4980469 a 0.2646484,0.2646484 0 1 0 -0.5292968,0 c -2.5e-6,1.28341 0.7732681,2.442454 1.9589843,2.9335937 1.1857144,0.4911386 2.5534315,0.2200067 3.4609375,-0.6875 C 7.3860249,5.836633 7.6571577,4.4689192 7.1660156,3.2832031 6.6748739,2.0974925 5.5158274,1.3222641 4.2324219,1.3222656 Z"
id="path7994"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path7996"
d="M 4.2332975,0.794 V 1.05858 2.11691 2.3815 H 3.9687142 C 3.9164802,2.38149 3.8654129,2.366 3.8219524,2.3371 l -0.79375,-0.52916 c -0.157054,-0.10475 -0.157054,-0.33554 0,-0.44028 l 0.79375,-0.52917 c 0.043461,-0.029 0.094528,-0.0444 0.1467618,-0.0444 h 0.0031 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
d="m 2.6458333,5.8208334 h 1.400175 v -0.4699 h -0.42545 V 3.6173835 h -0.327025 l -0.758825,0.4381499 0.206375,0.3937 0.3302,-0.17145 v 1.07315 h -0.42545 z"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:3.17499995px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:'Cantarell Ultra-Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.26458335"
id="path5132" />
<path
inkscape:connector-curvature="0"
d="m 5.0778791,5.8525834 c 0.5588,0 0.936625,-0.4572 0.936625,-1.146175 0,-0.6731 -0.371475,-1.1207749 -0.92075,-1.1207749 -0.561975,0 -0.9398,0.4571999 -0.9398,1.1429999 0,0.6731 0.371475,1.12395 0.923925,1.12395 z m 0.0127,-0.4699 c -0.225425,0 -0.371475,-0.269875 -0.371475,-0.6731 0,-0.3937 0.14605,-0.65405 0.36195,-0.65405 0.219075,0 0.3683,0.269875 0.3683,0.676275 0,0.390525 -0.14605,0.650875 -0.358775,0.650875 z"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:3.17499995px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:'Cantarell Ultra-Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.26458335"
id="path5134" />
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 8.4666665 8.4666669"
version="1.1"
id="svg2916"
sodipodi:docname="skip-forward-large-symbolic.svg"
inkscape:version="0.92.4 (unknown)">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="731"
id="namedview11"
showgrid="false"
inkscape:zoom="7.375"
inkscape:cx="16"
inkscape:cy="16"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2916" />
<defs
id="defs2910" />
<metadata
id="metadata2913">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<path
inkscape:connector-curvature="0"
d="m 2.6458333,5.8208334 h 1.400175 v -0.4699 h -0.42545 V 3.6173835 h -0.327025 l -0.758825,0.4381499 0.206375,0.3937 0.3302,-0.17145 v 1.07315 h -0.42545 z"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:3.17499995px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:'Cantarell Ultra-Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.26458335"
id="path5132" />
<path
inkscape:connector-curvature="0"
d="m 5.0778791,5.8525834 c 0.5588,0 0.936625,-0.4572 0.936625,-1.146175 0,-0.6731 -0.371475,-1.1207749 -0.92075,-1.1207749 -0.561975,0 -0.9398,0.4571999 -0.9398,1.1429999 0,0.6731 0.371475,1.12395 0.923925,1.12395 z m 0.0127,-0.4699 c -0.225425,0 -0.371475,-0.269875 -0.371475,-0.6731 0,-0.3937 0.14605,-0.65405 0.36195,-0.65405 0.219075,0 0.3683,0.269875 0.3683,0.676275 0,0.390525 -0.14605,0.650875 -0.358775,0.650875 z"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:3.17499995px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:'Cantarell Ultra-Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.26458335"
id="path5134" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 4.2324219,1.3222656 C 2.9490163,1.3222641 1.7899699,2.0974925 1.2988281,3.2832031 0.80768607,4.4689192 1.080772,5.836633 1.9882812,6.7441406 c 0.9075061,0.9075067 2.2732701,1.1786386 3.4589844,0.6875 1.1857163,-0.4911397 1.96094,-1.6501837 1.9609375,-2.9335937 a 0.26464845,0.26464845 0 1 0 -0.5292969,0 C 6.8789083,5.5689483 6.2354777,6.5335432 5.2460938,6.9433594 4.2567114,7.3531746 3.1185682,7.1263812 2.3613281,6.3691406 1.6040853,5.6118992 1.3792443,4.4757119 1.7890625,3.4863281 2.1988804,2.4969489 3.1615242,1.8515612 4.2324219,1.8515625 a 0.26464845,0.26464845 0 1 0 0,-0.5292969 z"
id="path5156"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 4.2327462,0.794 V 1.05858 2.11691 2.3815 h 0.2645833 c 0.052234,-1e-5 0.1033013,-0.0155 0.1467618,-0.0444 l 0.79375,-0.52916 c 0.157054,-0.10475 0.157054,-0.33554 0,-0.44028 l -0.79375,-0.52917 c -0.043461,-0.029 -0.094528,-0.0444 -0.1467618,-0.0444 h -0.0031 z"
id="path5158" />
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -11,8 +11,12 @@
<file compressed="true" preprocess="xml-stripblanks">gtk/hamburger.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtk/show_menu.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtk/player_dialog.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtk/player_rate.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtk/player_toolbar.ui</file>
<file compressed="true" preprocess="xml-stripblanks">icons/skip-back-large-symbolic.svg</file>
<file compressed="true" preprocess="xml-stripblanks">icons/skip-back-symbolic.svg</file>
<file compressed="true" preprocess="xml-stripblanks">icons/skip-forward-large-symbolic.svg</file>
<file compressed="true" preprocess="xml-stripblanks">icons/skip-forward-symbolic.svg</file>
<file compressed="true">gtk/style.css</file>
</gresource>

View File

@ -22,6 +22,10 @@ use gst::ClockTime;
use gtk;
use gtk::prelude::*;
use libhandy as hdy;
use libhandy::prelude::HeaderBarExt;
use libhandy::prelude::*;
use gio::{File, FileExt};
use glib::{SignalHandlerId, WeakRef};
@ -70,11 +74,29 @@ struct PlayerInfo {
show: gtk::Label,
episode: gtk::Label,
cover: gtk::Image,
show_small: gtk::Label,
episode_small: gtk::Label,
cover_small: gtk::Image,
mpris: Arc<MprisPlayer>,
episode_id: RefCell<Option<i32>>,
}
impl PlayerInfo {
fn create_bindings(&self) {
self.show
.bind_property("label", &self.show_small, "label")
.flags(glib::BindingFlags::SYNC_CREATE)
.build();
self.episode
.bind_property("label", &self.episode_small, "label")
.flags(glib::BindingFlags::SYNC_CREATE)
.build();
self.cover
.bind_property("pixbuf", &self.cover_small, "pixbuf")
.flags(glib::BindingFlags::SYNC_CREATE)
.build();
}
// FIXME: create a Diesel Model of the joined episode and podcast query instead
fn init(&self, episode: &EpisodeWidgetModel, podcast: &ShowCoverModel) {
self.episode_id.replace(Some(episode.rowid()));
@ -118,6 +140,7 @@ struct PlayerTimes {
separator: gtk::Label,
slider: gtk::Scale,
slider_update: Rc<SignalHandlerId>,
progress_bar: gtk::ProgressBar,
}
#[derive(Debug, Clone, Copy)]
@ -150,6 +173,8 @@ impl PlayerTimes {
self.slider.unblock_signal(&self.slider_update);
self.duration.set_text(&format_duration(seconds as u32));
self.update_progress_bar();
}
/// Update the `gtk::Scale` bar when the pipeline position is changed.
@ -161,6 +186,13 @@ impl PlayerTimes {
self.slider.unblock_signal(&self.slider_update);
self.progressed.set_text(&format_duration(seconds as u32));
self.update_progress_bar();
}
fn update_progress_bar(&self) {
let fraction = self.slider.get_value() / self.slider.get_adjustment().get_upper();
self.progress_bar.set_fraction(fraction);
}
}
@ -184,21 +216,140 @@ struct PlayerRate {
label: gtk::Label,
}
impl PlayerRate {
fn new() -> Self {
let builder = gtk::Builder::new_from_resource("/org/gnome/Podcasts/gtk/player_rate.ui");
let radio150: gtk::RadioButton = builder.get_object("rate_1_50").unwrap();
let radio125: gtk::RadioButton = builder.get_object("rate_1_25").unwrap();
let radio_normal: gtk::RadioButton = builder.get_object("normal_rate").unwrap();
let popover = builder.get_object("rate_popover").unwrap();
let btn = builder.get_object("rate_button").unwrap();
let label = builder.get_object("rate_label").unwrap();
PlayerRate {
radio150,
radio125,
radio_normal,
popover,
label,
btn,
}
}
fn set_rate(&self, rate: f64) {
self.label.set_text(&format!("{:.2}×", rate));
}
fn connect_signals(&self, widget: &Rc<PlayerWidget>) {
let weak = Rc::downgrade(widget);
self.radio_normal
.connect_toggled(clone!(weak => move |rate| {
weak.upgrade().map(|w| w.on_rate_changed(1.00));
}));
self.radio125.connect_toggled(clone!(weak => move |rate| {
weak.upgrade().map(|w| w.on_rate_changed(1.25));
}));
self.radio150.connect_toggled(clone!(weak => move |rate| {
weak.upgrade().map(|w| w.on_rate_changed(1.50));
}));
}
}
#[derive(Debug, Clone)]
struct PlayerControls {
container: gtk::Box,
play: gtk::Button,
pause: gtk::Button,
play_small: gtk::Button,
pause_small: gtk::Button,
play_pause_small: gtk::Stack,
forward: gtk::Button,
rewind: gtk::Button,
last_pause: RefCell<Option<DateTime<Local>>>,
}
#[derive(Debug, Clone)]
struct PlayerDialog {
dialog: hdy::Dialog,
close: gtk::Button,
headerbar: hdy::HeaderBar,
cover: gtk::Image,
play_pause: gtk::Stack,
play: gtk::Button,
pause: gtk::Button,
duration: gtk::Label,
progressed: gtk::Label,
slider: gtk::Scale,
forward: gtk::Button,
rewind: gtk::Button,
rate: PlayerRate,
show: gtk::Label,
episode: gtk::Label,
}
impl PlayerDialog {
fn new(rate: PlayerRate) -> Self {
let builder = gtk::Builder::new_from_resource("/org/gnome/Podcasts/gtk/player_dialog.ui");
let dialog = builder.get_object("dialog").unwrap();
let close = builder.get_object("close").unwrap();
let headerbar = builder.get_object("headerbar").unwrap();
let cover = builder.get_object("cover").unwrap();
let play_pause = builder.get_object("play_pause").unwrap();
let play = builder.get_object("play").unwrap();
let pause = builder.get_object("pause").unwrap();
let duration = builder.get_object("duration").unwrap();
let progressed = builder.get_object("progressed").unwrap();
let slider = builder.get_object("slider").unwrap();
let rewind = builder.get_object("rewind").unwrap();
let forward = builder.get_object("forward").unwrap();
let bottom: gtk::Box = builder.get_object("bottom").unwrap();
let show = builder.get_object("show_label").unwrap();
let episode = builder.get_object("episode_label").unwrap();
bottom.pack_start(&rate.btn, false, true, 0);
PlayerDialog {
dialog,
close,
headerbar,
cover,
play_pause,
play,
pause,
duration,
progressed,
slider,
forward,
rewind,
rate,
show,
episode,
}
}
fn initialize_episode(&self, episode: &EpisodeWidgetModel, show: &ShowCoverModel) {
self.episode.set_text(episode.title());
self.show.set_text(show.title());
set_image_from_path(&self.cover, show.id(), 256)
.map_err(|err| error!("Player Cover: {}", err))
.ok();
}
}
#[derive(Debug, Clone)]
pub(crate) struct PlayerWidget {
pub(crate) action_bar: gtk::ActionBar,
pub(crate) container: gtk::Box,
action_bar: gtk::ActionBar,
evbox: gtk::EventBox,
player: gst_player::Player,
controls: PlayerControls,
dialog: PlayerDialog,
full: gtk::Box,
squeezer: hdy::Squeezer,
timer: PlayerTimes,
info: PlayerInfo,
rate: PlayerRate,
@ -233,18 +384,23 @@ impl Default for PlayerWidget {
player.set_config(config).unwrap();
let builder = gtk::Builder::new_from_resource("/org/gnome/Podcasts/gtk/player_toolbar.ui");
let action_bar = builder.get_object("action_bar").unwrap();
let buttons = builder.get_object("buttons").unwrap();
let play = builder.get_object("play_button").unwrap();
let pause = builder.get_object("pause_button").unwrap();
let play_small = builder.get_object("play_button_small").unwrap();
let pause_small = builder.get_object("pause_button_small").unwrap();
let forward: gtk::Button = builder.get_object("ff_button").unwrap();
let rewind: gtk::Button = builder.get_object("rewind_button").unwrap();
let play_pause_small = builder.get_object("play_pause_small").unwrap();
let controls = PlayerControls {
container: buttons,
play,
pause,
play_small,
pause_small,
play_pause_small,
forward,
rewind,
last_pause: RefCell::new(None),
@ -258,6 +414,7 @@ impl Default for PlayerWidget {
slider.set_range(0.0, 1.0);
let player_weak = player.downgrade();
let slider_update = Rc::new(Self::connect_update_slider(&slider, player_weak));
let progress_bar = builder.get_object("progress_bar").unwrap();
let timer = PlayerTimes {
container: timer_container,
progressed,
@ -265,40 +422,50 @@ impl Default for PlayerWidget {
separator,
slider,
slider_update,
progress_bar,
};
let labels = builder.get_object("info").unwrap();
let show = builder.get_object("show_label").unwrap();
let episode = builder.get_object("episode_label").unwrap();
let cover = builder.get_object("show_cover").unwrap();
let show_small = builder.get_object("show_label_small").unwrap();
let episode_small = builder.get_object("episode_label_small").unwrap();
let cover_small = builder.get_object("show_cover_small").unwrap();
let info = PlayerInfo {
mpris,
container: labels,
show,
episode,
cover,
show_small,
episode_small,
cover_small,
episode_id: RefCell::new(None),
};
info.create_bindings();
let radio150 = builder.get_object("rate_1_50").unwrap();
let radio125 = builder.get_object("rate_1_25").unwrap();
let radio_normal = builder.get_object("normal_rate").unwrap();
let popover = builder.get_object("rate_popover").unwrap();
let btn = builder.get_object("rate_button").unwrap();
let label = builder.get_object("rate_label").unwrap();
let rate = PlayerRate {
radio150,
radio125,
radio_normal,
popover,
label,
btn,
};
let dialog_rate = PlayerRate::new();
let dialog = PlayerDialog::new(dialog_rate);
let container = builder.get_object("container").unwrap();
let action_bar: gtk::ActionBar = builder.get_object("action_bar").unwrap();
let evbox = builder.get_object("evbox").unwrap();
let full: gtk::Box = builder.get_object("full").unwrap();
let squeezer = builder.get_object("squeezer").unwrap();
let rate = PlayerRate::new();
full.pack_end(&rate.btn, false, true, 0);
PlayerWidget {
player,
container,
action_bar,
evbox,
controls,
dialog,
full,
squeezer,
timer,
info,
rate,
@ -309,7 +476,8 @@ impl Default for PlayerWidget {
impl PlayerWidget {
fn on_rate_changed(&self, rate: f64) {
self.set_playback_rate(rate);
self.rate.label.set_text(&format!("{:.2}×", rate));
self.rate.set_rate(rate);
self.dialog.rate.set_rate(rate);
}
fn reveal(&self) {
@ -320,6 +488,8 @@ impl PlayerWidget {
let ep = dbqueries::get_episode_widget_from_rowid(rowid)?;
let pd = dbqueries::get_podcast_cover_from_id(ep.show_id())?;
self.dialog.initialize_episode(&ep, &pd);
self.info.init(&ep, &pd);
// Currently that will always be the case since the play button is
// only shown if the file is downloaded
@ -331,8 +501,10 @@ impl PlayerWidget {
let uri = File::new_for_path(path).get_uri();
// play the file
self.player.set_uri(uri.as_str());
self.rate.radio_normal.set_active(true);
self.rate.set_rate(1.0);
self.dialog.rate.set_rate(1.0);
self.play();
return Ok(());
}
// TODO: log an error
@ -391,10 +563,15 @@ impl PlayerWidget {
impl PlayerExt for PlayerWidget {
fn play(&self) {
self.dialog.play_pause.set_visible_child(&self.dialog.pause);
self.reveal();
self.controls.pause.show();
self.controls.play.hide();
self.controls
.play_pause_small
.set_visible_child(&self.controls.pause_small);
self.smart_rewind();
self.player.play();
@ -402,8 +579,13 @@ impl PlayerExt for PlayerWidget {
}
fn pause(&self) {
self.dialog.play_pause.set_visible_child(&self.dialog.play);
self.controls.pause.hide();
self.controls.play.show();
self.controls
.play_pause_small
.set_visible_child(&self.controls.play_small);
self.player.pause();
self.info.mpris.set_playback_status(PlaybackStatus::Paused);
@ -413,6 +595,7 @@ impl PlayerExt for PlayerWidget {
#[cfg_attr(rustfmt, rustfmt_skip)]
fn stop(&self) {
self.controls.pause.hide();
self.controls.play.show();
@ -495,6 +678,72 @@ impl PlayerWrapper {
self.connect_rate_buttons();
self.connect_mpris_buttons(sender);
self.connect_gst_signals(sender);
self.connect_dialog();
}
fn connect_dialog(&self) {
let weak = Rc::downgrade(self);
self.squeezer
.connect_property_visible_child_notify(clone!(weak => move |_| {
weak.upgrade().map(|w| {
if let Some(child) = w.squeezer.get_visible_child() {
let full = child == w.full;
w.timer.progress_bar.set_visible(!full);
if full {
w.action_bar.get_style_context().remove_class("player-small");
} else {
w.action_bar.get_style_context().add_class("player-small");
}
}
});
}));
self.timer
.duration
.bind_property("label", &self.dialog.duration, "label")
.flags(glib::BindingFlags::SYNC_CREATE)
.build();
self.timer
.progressed
.bind_property("label", &self.dialog.progressed, "label")
.flags(glib::BindingFlags::SYNC_CREATE)
.build();
self.dialog
.slider
.set_adjustment(&self.timer.slider.get_adjustment());
self.evbox
.connect_button_press_event(clone!(weak => move |_, event| {
if event.get_button() != 1 {
return Inhibit(false);
}
if let Some(w) = weak.upgrade() {
// only open the dialog when the small toolbar is visible
if let Some(child) = w.squeezer.get_visible_child() {
if child == w.full {
return Inhibit(false);
}
}
let parent = w.container.get_toplevel().and_then(|toplevel| {
toplevel
.downcast::<gtk::Window>()
.ok()
}).unwrap();
info!("showing dialog");
w.dialog.dialog.set_transient_for(Some(&parent));
w.dialog.dialog.show();
}
Inhibit(false)
}));
self.dialog.close.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|w| w.dialog.dialog.hide());
}));
}
/// Connect the `PlayerControls` buttons to the `PlayerExt` methods.
@ -513,6 +762,20 @@ impl PlayerWrapper {
weak.upgrade().map(|p| p.pause());
}));
// Connect the play button to the gst Player.
self.controls
.play_small
.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.play());
}));
// Connect the pause button to the gst Player.
self.controls
.pause_small
.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.pause());
}));
// Connect the rewind button to the gst Player.
self.controls
.rewind
@ -526,6 +789,28 @@ impl PlayerWrapper {
.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.fast_forward());
}));
// Connect the play button to the gst Player.
self.dialog.play.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.play());
}));
// Connect the pause button to the gst Player.
self.dialog.pause.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.pause());
}));
// Connect the rewind button to the gst Player.
self.dialog.rewind.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.rewind());
}));
// Connect the fast-forward button to the gst Player.
self.dialog
.forward
.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.fast_forward());
}));
}
#[cfg_attr(rustfmt, rustfmt_skip)]
@ -567,25 +852,8 @@ impl PlayerWrapper {
#[cfg_attr(rustfmt, rustfmt_skip)]
fn connect_rate_buttons(&self) {
let weak = Rc::downgrade(self);
self.rate
.radio_normal
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.00));
}));
self.rate
.radio125
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.25));
}));
self.rate
.radio150
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.50));
}));
self.rate.connect_signals(self);
self.dialog.rate.connect_signals(self);
}
fn connect_mpris_buttons(&self, sender: &Sender<Action>) {

View File

@ -122,7 +122,7 @@ impl MainWindow {
let player = player::PlayerWrapper::new(&sender);
// Add the player to the main Box
wrap.add(&player.action_bar);
wrap.add(&player.container);
wrap.add(&header.bottom_switcher);