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) {
|
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]);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 () {
|
||||||
|
|
|
@ -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