Add support for chapters in episodes

This commit is contained in:
Thomas Perl 2014-04-30 18:49:37 +02:00
parent bb20181a77
commit 69c803ab5c
7 changed files with 160 additions and 0 deletions

View file

@ -26,6 +26,7 @@ MediaPlayer {
property int episode: 0
property string episode_title: ''
property var episode_chapters: ([])
property string podcast_title: ''
signal playerCreated()
@ -62,6 +63,7 @@ MediaPlayer {
var old_episode = player.episode;
player.episode = episode_id;
player.episode_title = episode.title;
player.episode_chapters = episode.chapters;
player.podcast_title = episode.podcast_title;
player.source = episode.source;
player.seekTargetSeconds = episode.position;

View file

@ -327,6 +327,7 @@ class gPotherSide:
'position': episode.current_position,
'total': episode.total_time,
'video': episode.file_type() == 'video',
'chapters': getattr(episode, 'chapters', []),
}
def report_playback_event(self, episode_id, position_from, position_to, duration):
@ -345,6 +346,7 @@ class gPotherSide:
'description': util.remove_html_tags(episode.description),
'metadata': ' | '.join(self._format_metadata(episode)),
'link': episode.link if episode.link != episode.url else '',
'chapters': getattr(episode, 'chapters', []),
}
def _format_metadata(self, episode):

View file

@ -21,6 +21,7 @@
import QtQuick 2.0
import 'common/constants.js' as Constants
import 'common/util.js' as Util
import 'icons/icons.js' as Icons
SlidePage {
@ -30,6 +31,7 @@ SlidePage {
property string title
property string link
property bool ready: false
property var chapters: ([])
hasMenuButton: detailPage.link != ''
menuButtonIcon: Icons.link
@ -47,6 +49,7 @@ SlidePage {
metadataLabel.text = episode.metadata;
detailPage.link = episode.link;
detailPage.ready = true;
detailPage.chapters = episode.chapters;
});
}
@ -87,6 +90,45 @@ SlidePage {
color: Constants.colors.placeholder
}
PExpander {
visible: detailPage.chapters.length > 0
width: parent.width
expandedHeight: chaptersColumn.childrenRect.height
Column {
id: chaptersColumn
width: parent.width
PLabel {
text: 'Chapters'
color: Constants.colors.secondaryHighlight
}
Repeater {
model: detailPage.chapters
delegate: Column {
width: parent.width
PLabel {
width: parent.width
text: Util.formatDuration(modelData.start)
font.pixelSize: 20 * pgst.scalef
color: Constants.colors.secondaryHighlight
}
PLabel {
width: parent.width
text: modelData.title
font.pixelSize: 20 * pgst.scalef
color: Constants.colors.placeholder
}
}
}
}
}
PLabel {
id: descriptionLabel
width: parent.width

88
touch/PExpander.qml Normal file
View file

@ -0,0 +1,88 @@
/**
*
* gPodder QML UI Reference Implementation
* Copyright (c) 2014, Thomas Perl <m@thp.io>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
*/
import QtQuick 2.0
import 'common/constants.js' as Constants
import 'common/util.js' as Util
Item {
id: expander
property bool expanded: false
property bool canExpand: expandedHeight > contractedHeight
property real contractedHeight: 100 * pgst.scalef
property real expandedHeight: childrenRect.height
property color backgroundColor: Constants.colors.page
height: expanded ? expandedHeight : contractedHeight
clip: true
Behavior on height { PropertyAnimation { } }
MouseArea {
anchors.fill: parent
onClicked: {
if (expander.canExpand) {
expander.expanded = !expander.expanded
}
}
}
Rectangle {
z: 100
opacity: chapterExpander.opacity
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: expander.contractedHeight * 0.6
gradient: Gradient {
GradientStop { position: 0; color: '#00000000' }
GradientStop { position: 1; color: expander.backgroundColor }
}
}
PLabel {
id: chapterExpander
z: 200
anchors {
right: parent.right
bottom: parent.bottom
}
text: '...'
font.pixelSize: 60 * pgst.scalef
color: Constants.colors.highlight
opacity: !expander.expanded
Behavior on opacity { PropertyAnimation { } }
}
}

View file

@ -135,6 +135,29 @@ Dialog {
icon: Icons.last
onClicked: player.seekAndSync(player.position + 60 * 1000);
}
IconMenuItem {
text: 'Chapters'
color: Constants.colors.playback
icon: Icons.tag_fill
visible: player.episode_chapters.length > 0
onClicked: {
var items = [];
for (var i in player.episode_chapters) {
(function (items, chapter) {
items.push({
label: chapter.title + ' (' + Util.formatDuration(chapter.start) + ')',
callback: function () {
player.seekAndSync(chapter.start * 1000);
}
});
})(items, player.episode_chapters[i]);
}
pgst.showSelection(items, 'Chapters');
}
}
}
}
}

View file

@ -67,6 +67,7 @@ Dialog {
PLabel {
anchors {
left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter
margins: 20 * pgst.scalef
}
@ -74,6 +75,7 @@ Dialog {
text: modelData
color: (index == selectionDialog.selectedIndex || buttonArea.pressed) ? Constants.colors.dialogHighlight : Constants.colors.dialogText
font.pixelSize: 30 * pgst.scalef
elide: Text.ElideRight
}
onClicked: {

View file

@ -21,3 +21,4 @@ var cog = '\u2699';
var link = '\ue077';
var vellipsis = '\u22ee';
var paperclip = '\ue08a';
var tag_fill = '\ue02b';