Very basic playlist support

This commit is contained in:
Thomas Perl 2014-12-17 22:40:06 +01:00
parent 63518483a3
commit 77b24d58cb
6 changed files with 149 additions and 0 deletions

View file

@ -62,6 +62,13 @@ ListModel {
}); });
} }
function forEachEpisode(callback) {
// Go from bottom up (= chronological order)
for (var i=count-1; i>=0; i--) {
callback(get(i));
}
}
function setQueryIndex(index) { function setQueryIndex(index) {
currentFilterIndex = index; currentFilterIndex = index;
py.call('main.set_config_value', ['ui.qml.episode_list.filter_eql', filters[currentFilterIndex].query]); py.call('main.set_config_value', ['ui.qml.episode_list.filter_eql', filters[currentFilterIndex].query]);

View file

@ -31,6 +31,7 @@ MediaPlayer {
signal playerCreated() signal playerCreated()
property var queue: ([]) property var queue: ([])
signal queueUpdated()
property bool isPlaying: playbackState == MediaPlayer.PlayingState property bool isPlaying: playbackState == MediaPlayer.PlayingState
property bool inhibitPositionEvents: false property bool inhibitPositionEvents: false
@ -58,6 +59,24 @@ MediaPlayer {
} }
} }
function enqueueEpisode(episode_id, callback) {
py.call('main.show_episode', [episode_id], function (episode) {
if (episode_id != player.episode && !queue.some(function (queued) {
return queued.episode_id === episode_id;
})) {
queue.push({
episode_id: episode_id,
title: episode.title,
});
queueUpdated();
}
if (callback !== undefined) {
callback();
}
});
}
function playbackEpisode(episode_id) { function playbackEpisode(episode_id) {
if (episode == episode_id) { if (episode == episode_id) {
// If the episode is already loaded, just start playing // If the episode is already loaded, just start playing
@ -157,6 +176,35 @@ MediaPlayer {
} }
} }
property var nextInQueueTimer: Timer {
interval: 500
repeat: false
onTriggered: {
if (queue.length > 0) {
playbackEpisode(queue.shift().episode_id);
player.queueUpdated();
}
}
}
function jumpToQueueIndex(index) {
playbackEpisode(removeQueueIndex(index).episode_id);
}
function removeQueueIndex(index) {
var result = queue.splice(index, 1)[0];
player.queueUpdated();
return result;
}
onStatusChanged: {
if (status === MediaPlayer.EndOfMedia) {
nextInQueueTimer.start();
}
}
property var savePlaybackPositionTimer: Timer { property var savePlaybackPositionTimer: Timer {
// Save position every minute during playback // Save position every minute during playback
interval: 60 * 1000 interval: 60 * 1000

View file

@ -75,3 +75,13 @@ function format(s, d) {
return (k in d) ? d[k] : m; return (k in d) ? d[k] : m;
}); });
} }
function atMostOnce(callback) {
var called = false;
return function () {
if (!called) {
called = true;
callback();
}
};
}

View file

@ -57,6 +57,15 @@ Item {
player.playbackEpisode(id); player.playbackEpisode(id);
} }
} }
onPressAndHold: {
player.enqueueEpisode(id, function () {
if (!player.isPlaying) {
player.jumpToQueueIndex(0);
}
pgst.loadPage('PlayerPage.qml');
});
}
} }
IconMenuItem { IconMenuItem {

View file

@ -47,6 +47,20 @@ SlidePage {
py.call('main.mark_episodes_as_old', [page.podcast_id]); py.call('main.mark_episodes_as_old', [page.podcast_id]);
}, },
}, },
{
label: 'Enqueue episodes in player',
callback: function () {
var startPlayback = Util.atMostOnce(function () {
if (!player.isPlaying) {
player.jumpToQueueIndex(0);
}
});
episodeList.model.forEachEpisode(function (episode) {
player.enqueueEpisode(episode.id, startPlayback);
});
},
},
{ {
label: 'Podcast details', label: 'Podcast details',
callback: function () { callback: function () {

View file

@ -190,6 +190,67 @@ SlidePage {
} }
} }
} }
SectionHeader {
text: 'Play queue'
visible: playQueueRepeater.count > 0
width: parent.width
}
Repeater {
id: playQueueRepeater
model: player.queue
property var queueConnections: Connections {
target: player
onQueueUpdated: {
playQueueRepeater.model = player.queue;
}
}
ButtonArea {
height: Constants.layout.item.height * pgst.scalef
width: parent.width
transparent: true
PLabel {
anchors {
left: parent.left
right: parent.right
margins: Constants.layout.padding * pgst.scalef
verticalCenter: parent.verticalCenter
}
text: modelData.title
elide: Text.ElideRight
}
onClicked: {
player.jumpToQueueIndex(index);
}
onPressAndHold: {
pgst.showSelection([
{
label: 'Shownotes',
callback: function () {
pgst.loadPage('EpisodeDetail.qml', {
episode_id: modelData.episode_id,
title: modelData.title
});
},
},
{
label: 'Remove from queue',
callback: function () {
player.removeQueueIndex(index);
},
},
]);
}
}
}
} }
} }