Very basic playlist support
This commit is contained in:
parent
63518483a3
commit
77b24d58cb
6 changed files with 149 additions and 0 deletions
|
@ -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) {
|
||||
currentFilterIndex = index;
|
||||
py.call('main.set_config_value', ['ui.qml.episode_list.filter_eql', filters[currentFilterIndex].query]);
|
||||
|
|
|
@ -31,6 +31,7 @@ MediaPlayer {
|
|||
signal playerCreated()
|
||||
|
||||
property var queue: ([])
|
||||
signal queueUpdated()
|
||||
property bool isPlaying: playbackState == MediaPlayer.PlayingState
|
||||
|
||||
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) {
|
||||
if (episode == episode_id) {
|
||||
// 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 {
|
||||
// Save position every minute during playback
|
||||
interval: 60 * 1000
|
||||
|
|
|
@ -75,3 +75,13 @@ function format(s, d) {
|
|||
return (k in d) ? d[k] : m;
|
||||
});
|
||||
}
|
||||
|
||||
function atMostOnce(callback) {
|
||||
var called = false;
|
||||
return function () {
|
||||
if (!called) {
|
||||
called = true;
|
||||
callback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -57,6 +57,15 @@ Item {
|
|||
player.playbackEpisode(id);
|
||||
}
|
||||
}
|
||||
|
||||
onPressAndHold: {
|
||||
player.enqueueEpisode(id, function () {
|
||||
if (!player.isPlaying) {
|
||||
player.jumpToQueueIndex(0);
|
||||
}
|
||||
pgst.loadPage('PlayerPage.qml');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
IconMenuItem {
|
||||
|
|
|
@ -47,6 +47,20 @@ SlidePage {
|
|||
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',
|
||||
callback: function () {
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue