ubuntu-touch-coreapps-reviewers team mailing list archive
-
ubuntu-touch-coreapps-reviewers team
-
Mailing list archive
-
Message #05587
[Merge] lp:~music-app-dev/music-app/media-hub-bg-playlists-rework into lp:music-app
Andrew Hayzen has proposed merging lp:~music-app-dev/music-app/media-hub-bg-playlists-rework into lp:music-app.
Commit message:
* Add support for media-hub background playlists
Requested reviews:
Music App Developers (music-app-dev)
Related bugs:
Bug #1251624 in Ubuntu Music App: "back button should not be random when in shuffle mode"
https://bugs.launchpad.net/music-app/+bug/1251624
Bug #1480280 in Ubuntu Music App: "Songs repeated when listening in shuffle mode"
https://bugs.launchpad.net/music-app/+bug/1480280
Bug #1500457 in Ubuntu Music App: "Pressing previous button sets duration to 0"
https://bugs.launchpad.net/music-app/+bug/1500457
For more details, see:
https://code.launchpad.net/~music-app-dev/music-app/media-hub-bg-playlists-rework/+merge/275912
* Add support for media-hub background playlists
JUST NEED THIS FOR DIFF
--
Your team Music App Developers is requested to review the proposed merge of lp:~music-app-dev/music-app/media-hub-bg-playlists-rework into lp:music-app.
=== modified file 'app/components/BlurredBackground.qml'
--- app/components/BlurredBackground.qml 2015-05-03 16:22:31 +0000
+++ app/components/BlurredBackground.qml 2015-10-27 19:27:27 +0000
@@ -25,7 +25,7 @@
Item {
width: parent.width
- property string art // : player.currentMetaFile === "" ? Qt.resolvedUrl("../graphics/music-app-cover@xxxxxx") : player.currentMetaArt
+ property string art
// dark layer
Rectangle {
=== modified file 'app/components/HeadState/MultiSelectHeadState.qml'
--- app/components/HeadState/MultiSelectHeadState.qml 2015-06-27 21:06:26 +0000
+++ app/components/HeadState/MultiSelectHeadState.qml 2015-10-27 19:27:27 +0000
@@ -41,7 +41,12 @@
var items = []
for (var i=0; i < listview.selectedItems.length; i++) {
- items.push(makeDict(listview.model.get(listview.selectedItems[i], listview.model.RoleModelData)));
+ // TODO: improve! probably take outside of the for loop or try and make playlist accept .get()
+ if (listview.model === newPlayer.mediaPlayer.playlist) {
+ items.push(makeDict(newPlayer.metaForSource(listview.model.source(listview.selectedItems[i]))));
+ } else {
+ items.push(makeDict(listview.model.get(listview.selectedItems[i], listview.model.RoleModelData)));
+ }
}
mainPageStack.push(Qt.resolvedUrl("../../ui/AddToPlaylist.qml"),
@@ -57,13 +62,13 @@
visible: addToQueue
onTriggered: {
- var items = []
+ var sources = [];
for (var i=0; i < listview.selectedItems.length; i++) {
- items.push(listview.model.get(listview.selectedItems[i], listview.model.RoleModelData));
+ sources.push(Qt.resolvedUrl(listview.model.get(listview.selectedItems[i], listview.model.RoleModelData).filename));
}
- trackQueue.appendList(items)
+ newPlayer.mediaPlayer.playlist.addSources(sources);
listview.closeSelection()
}
=== modified file 'app/components/Helpers/ContentHubHelper.qml'
--- app/components/Helpers/ContentHubHelper.qml 2015-08-18 21:08:05 +0000
+++ app/components/Helpers/ContentHubHelper.qml 2015-10-27 19:27:27 +0000
@@ -220,12 +220,12 @@
else {
stopTimer();
- trackQueue.clear();
+ newPlayer.mediaPlayer.playlist.clear();
for (i=0; i < searchPaths.length; i++) {
model = musicStore.lookup(decodeFileURI(searchPaths[i]))
- trackQueue.append(makeDict(model));
+ newPlayer.mediaPlayer.playlist.addSource(Qt.resolvedUrl(decodeURIComponent(searchPaths[i])));
}
trackQueueClick(0);
=== modified file 'app/components/Helpers/UriHandlerHelper.qml'
--- app/components/Helpers/UriHandlerHelper.qml 2015-06-28 03:06:49 +0000
+++ app/components/Helpers/UriHandlerHelper.qml 2015-10-27 19:27:27 +0000
@@ -38,14 +38,6 @@
}
function processAlbum(uri) {
- // Stop queue loading in the background
- queueLoaderWorker.canLoad = false
-
- if (queueLoaderWorker.processing > 0) {
- waitForWorker.workerStop(queueLoaderWorker, processAlbum, [uri])
- return;
- }
-
selectedAlbum = true;
var split = uri.split("/");
@@ -60,34 +52,26 @@
}
function processFile(uri, play) {
- // Stop queue loading in the background
- queueLoaderWorker.canLoad = false
-
- if (queueLoaderWorker.processing > 0) {
- waitForWorker.workerStop(queueLoaderWorker, processFile, [uri, play])
- return;
- }
-
// Lookup track in songs model
var track = musicStore.lookup(decodeFileURI(uri));
if (!track) {
console.debug("Unknown file " + uri + ", skipping")
- return;
- }
-
- if (play) {
- // clear play queue
- trackQueue.clear()
- }
-
- // enqueue
- trackQueue.append(makeDict(track));
-
- // play first URI
- if (play) {
- trackQueueClick(trackQueue.model.count - 1);
- }
+ } else {
+ if (play) {
+ // clear play queue
+ newPlayer.mediaPlayer.playlist.clear()
+ }
+
+ // enqueue
+ newPlayer.mediaPlayer.playlist.addSource(Qt.resolvedUrl(track.filename));
+
+ // play first URI
+ if (play) {
+ trackQueueClick(newPlayer.mediaPlayer.playlist.mediaCount - 1);
+ }
+ }
+
}
function process(uri, play) {
=== modified file 'app/components/Helpers/UserMetricsHelper.qml'
--- app/components/Helpers/UserMetricsHelper.qml 2015-05-03 16:22:31 +0000
+++ app/components/Helpers/UserMetricsHelper.qml 2015-10-27 19:27:27 +0000
@@ -36,17 +36,15 @@
// Connections for usermetrics
Connections {
id: userMetricPlayerConnection
- target: player
+ target: newPlayer.mediaPlayer
property bool songCounted: false
- onSourceChanged: {
- songCounted = false
- }
+ onSourceChanged: songCounted = false
onPositionChanged: {
// Increment song count on Welcome screen if song has been
// playing for over 10 seconds.
- if (player.position > 10000 && !songCounted) {
+ if (newPlayer.mediaPlayer.position > 10000 && !songCounted) {
songCounted = true
songsMetric.increment()
console.debug("Increment UserMetrics")
=== modified file 'app/components/ListItemActions/AddToQueue.qml'
--- app/components/ListItemActions/AddToQueue.qml 2015-05-03 16:22:31 +0000
+++ app/components/ListItemActions/AddToQueue.qml 2015-10-27 19:27:27 +0000
@@ -29,6 +29,6 @@
onTriggered: {
console.debug("Debug: Add track to queue: " + model)
- trackQueue.append(model)
+ newPlayer.mediaPlayer.playlist.addSource(Qt.resolvedUrl(model.filename))
}
}
=== modified file 'app/components/MusicToolbar.qml'
--- app/components/MusicToolbar.qml 2015-07-29 01:23:11 +0000
+++ app/components/MusicToolbar.qml 2015-10-27 19:27:27 +0000
@@ -42,7 +42,7 @@
anchors {
fill: parent
}
- state: trackQueue.model.count === 0 ? "disabled" : "enabled"
+ state: newPlayer.mediaPlayer.playlist.empty ? "disabled" : "enabled"
states: [
State {
name: "disabled"
@@ -104,7 +104,7 @@
}
color: "#FFF"
height: units.gu(4)
- name: player.playbackState === MediaPlayer.PlayingState ?
+ name: newPlayer.mediaPlayer.playbackState === MediaPlayer.PlayingState ?
"media-playback-pause" : "media-playback-start"
objectName: "disabledSmallPlayShape"
width: height
@@ -116,11 +116,10 @@
fill: parent
}
onClicked: {
- if (trackQueue.model.count === 0) {
+ if (newPlayer.mediaPlayer.playlist.empty) {
playRandomSong();
- }
- else {
- player.toggle();
+ } else {
+ newPlayer.mediaPlayer.toggle();
}
}
}
@@ -144,7 +143,7 @@
left: parent.left
top: parent.top
}
- covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaArt}]
+ covers: [newPlayer.currentMeta]
size: parent.height
}
@@ -170,8 +169,9 @@
elide: Text.ElideRight
fontSize: "small"
font.weight: Font.DemiBold
- text: player.currentMetaTitle === ""
- ? player.source : player.currentMetaTitle
+ text: newPlayer.currentMeta.title === ""
+ ? newPlayer.mediaPlayer.playlist.currentSource
+ : newPlayer.currentMeta.title
}
/* Artist of track */
@@ -185,7 +185,7 @@
elide: Text.ElideRight
fontSize: "small"
opacity: 0.4
- text: player.currentMetaArtist
+ text: newPlayer.currentMeta.author
}
}
@@ -199,7 +199,7 @@
}
color: "#FFF"
height: units.gu(4)
- name: player.playbackState === MediaPlayer.PlayingState ?
+ name: newPlayer.mediaPlayer.playbackState === MediaPlayer.PlayingState ?
"media-playback-pause" : "media-playback-start"
objectName: "playShape"
width: height
@@ -222,7 +222,7 @@
horizontalCenter: playerControlsPlayButton.horizontalCenter
top: parent.top
}
- onClicked: player.toggle()
+ onClicked: newPlayer.mediaPlayer.toggle()
width: units.gu(8)
Rectangle {
@@ -260,17 +260,17 @@
}
color: UbuntuColors.blue
height: parent.height
- width: player.duration > 0 ? (player.position / player.duration) * playerControlsProgressBar.width : 0
+ width: newPlayer.mediaPlayer.progress * playerControlsProgressBar.width
+
+ /*
+ FIXME: needed?
Connections {
- target: player
- onPositionChanged: {
- playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width
- }
- onStopped: {
- playerControlsProgressBarHint.width = 0;
- }
+ target: newPlayer.mediaPlayer
+ onPositionChanged: playerControlsProgressBarHint.width = (newPlayer.mediaPlayer.position / newPlayer.mediaPlayer.duration) * playerControlsProgressBar.width
+ onStopped: playerControlsProgressBarHint.width = 0;
}
+ */
}
}
}
=== added file 'app/components/NewPlayer.qml'
--- app/components/NewPlayer.qml 1970-01-01 00:00:00 +0000
+++ app/components/NewPlayer.qml 2015-10-27 19:27:27 +0000
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2015
+ * Andrew Hayzen <ahayzen@xxxxxxxxx>
+ * Victor Thompson <victor.thompson@xxxxxxxxx>
+ *
+ * This program 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; version 3.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtMultimedia 5.4
+import QtQuick 2.4
+import Qt.labs.settings 1.0
+
+import QtQuick.LocalStorage 2.0
+import "../logic/meta-database.js" as Library
+
+Item {
+ objectName: "player"
+
+ property var currentMeta: ({})
+ property alias mediaPlayer: mediaPlayer
+ property alias repeat: settings.repeat
+ property alias shuffle: settings.shuffle
+
+ function metaForSource(source) {
+ var blankMeta = {
+ album: "",
+ art: "",
+ author: "",
+ filename: "",
+ title: ""
+ };
+
+ source = source.toString();
+
+ if (source.indexOf("file://") === 0) {
+ source = source.substring(7);
+ }
+
+ return musicStore.lookup(decodeFileURI(source)) || blankMeta;
+ }
+
+ Settings {
+ id: settings
+ category: "PlayerSettings"
+
+ property bool repeat: true
+ property bool shuffle: false
+ }
+
+ // https://code.launchpad.net/~phablet-team/kubuntu-packaging/qtmultimedia-opensource-src-playlist-support/+merge/262229
+ MediaPlayer {
+ id: mediaPlayer
+ playlist: Playlist {
+ id: mediaPlayerPlaylist
+ playbackMode: { // FIXME: doesn't see to work
+ if (settings.shuffle) {
+ Playlist.Random
+ } else if (settings.repeat) {
+ Playlist.Loop
+ } else {
+ Playlist.Sequential
+ }
+ }
+
+ onCurrentSourceChanged: currentMeta = metaForSource(currentSource)
+ onMediaChanged: {
+ saveQueue()
+
+ // FIXME: shouldn't be needed? seems to be a bug where when appending currentSourceChanged is not emitted
+ //if (start === currentIndex) {
+ // currentMeta = metaForSource(currentSource)
+ //}
+ }
+ onMediaInserted: {
+ // When add to queue is done on an empty list currentIndex needs to be set
+ if (start === 0 && currentIndex === -1) {
+ currentIndex = 0;
+ }
+
+ saveQueue()
+
+ // FIXME: shouldn't be needed? seems to be a bug where when appending currentSourceChanged is not emitted
+ if (start === currentIndex) {
+ currentMeta = metaForSource(currentSource)
+ }
+ }
+ onMediaRemoved: {
+ saveQueue()
+
+ // FIXME: shouldn't be needed? seems to be a bug where when appending currentSourceChanged is not emitted
+ if (start === currentIndex) {
+ currentMeta = metaForSource(currentSource)
+ }
+ }
+
+ // TODO: AP needs queue length
+
+ function addSourcesFromModel(model) {
+ var sources = []
+
+ for (var i=0; i < model.rowCount; i++) {
+ sources.push(Qt.resolvedUrl(model.get(i, model.RoleModelData).filename));
+ }
+
+ addSources(sources);
+ }
+
+ function removeSources(items) {
+ items.sort();
+
+ for (var i=0; i < items.length; i++) {
+ removeSource(items[i] - i);
+ }
+ }
+
+ function saveQueue(start, end) {
+ // TODO: should not be hardcoded
+ // FIXME: doesn't work
+ // FIXME: disabled for now to not cause errors/slow down
+ // save("/home/phablet/.local/share/com.ubuntu.music/queue.m3u");
+
+ // FIXME: using old queueList for now, move to load()/save() long term
+ if (mainView.loadedUI) {
+ Library.clearQueue();
+
+ var sources = [];
+
+ for (var i=0; i < mediaPlayerPlaylist.mediaCount; i++) {
+ sources.push(mediaPlayerPlaylist.source(i));
+ }
+
+ Library.addQueueList(sources);
+ }
+ }
+ }
+
+ // FIXME: Bind to settings.repeat/shuffle instead of playbackMode
+ // as that doesn't emit changes
+ property bool canGoPrevious: {
+ playlist.currentIndex !== 0 ||
+ settings.repeat ||
+ settings.shuffle
+ }
+ property bool canGoNext: {
+ playlist.currentIndex !== (playlist.mediaCount - 1) ||
+ settings.repeat ||
+ settings.shuffle
+ }
+
+ property double progress: 0
+
+ onDurationChanged: _calcProgress()
+ onPositionChanged: _calcProgress()
+
+ onStatusChanged: {
+ if (status == MediaPlayer.EndOfMedia) {
+ console.debug("End of media, stopping.")
+ playlist.currentIndex = 0;
+ stop();
+
+ _calcProgress(); // ensures progress bar has reset
+ }
+ }
+
+ onStopped: { // hit when pressing next() on last track with repeat off
+ console.debug("onStopped.")
+ stop();
+ playlist.currentIndex = 0;
+ stop();
+
+ _calcProgress(); // ensures progress bar has reset
+ }
+
+ function _calcProgress() {
+ if (duration > 0) {
+ progress = position / duration;
+ } else if (position >= duration) {
+ progress = 0;
+ } else {
+ progress = 0;
+ }
+ }
+
+ function toggle() {
+ if (playbackState === MediaPlayer.PlayingState) {
+ pause();
+ } else {
+ play();
+ }
+ }
+ }
+}
=== modified file 'app/components/NowPlayingFullView.qml'
--- app/components/NowPlayingFullView.qml 2015-08-28 04:48:28 +0000
+++ app/components/NowPlayingFullView.qml 2015-10-27 19:27:27 +0000
@@ -51,7 +51,7 @@
CoverGrid {
id: albumImage
anchors.centerIn: parent
- covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaAlbum}]
+ covers: [newPlayer.currentMeta]
size: parent.height
}
}
@@ -92,7 +92,15 @@
fontSize: "x-large"
maximumLineCount: 2
objectName: "playercontroltitle"
- text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle
+ text: {
+ if (newPlayer.mediaPlayer.playlist.empty) {
+ ""
+ } else if (newPlayer.currentMeta.title === "") {
+ newPlayer.mediaPlayer.playlist.currentSource
+ } else {
+ newPlayer.currentMeta.title
+ }
+ }
wrapMode: Text.WordWrap
}
@@ -108,7 +116,7 @@
color: styleMusic.nowPlaying.labelSecondaryColor
elide: Text.ElideRight
fontSize: "small"
- text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist
+ text: newPlayer.mediaPlayer.playlist.empty ? "" : newPlayer.currentMeta.author
}
}
@@ -122,12 +130,13 @@
onReleased: {
var diff = mouse.x - lastX
+
if (Math.abs(diff) < units.gu(4)) {
return;
} else if (diff < 0) {
- player.nextSong()
+ newPlayer.mediaPlayer.playlist.next()
} else if (diff > 0) {
- player.previousSong()
+ newPlayer.mediaPlayer.playlist.previous()
}
}
}
@@ -167,7 +176,7 @@
fontSize: "small"
height: parent.height
horizontalAlignment: Text.AlignHCenter
- text: durationToString(player.position)
+ text: durationToString(newPlayer.mediaPlayer.position)
verticalAlignment: Text.AlignVCenter
width: units.gu(3)
}
@@ -176,10 +185,10 @@
id: progressSliderMusic
anchors.left: parent.left
anchors.right: parent.right
- maximumValue: player.duration // load value at startup
+ maximumValue: newPlayer.mediaPlayer.duration || 1 // fallback to 1 when 0 so that the progress bar works
objectName: "progressSliderShape"
style: UbuntuBlueSliderStyle {}
- value: player.position // load value at startup
+ value: newPlayer.mediaPlayer.position // load value at startup
function formatValue(v) {
if (seeking) { // update position label while dragging
@@ -194,7 +203,7 @@
onSeekingChanged: {
if (seeking === false) {
- musicToolbarFullPositionLabel.text = durationToString(player.position)
+ musicToolbarFullPositionLabel.text = durationToString(newPlayer.mediaPlayer.position)
}
}
@@ -203,22 +212,23 @@
if (!pressed) {
seeked = true
- player.seek(value)
+ newPlayer.mediaPlayer.seek(value)
musicToolbarFullPositionLabel.text = durationToString(value)
}
}
Connections {
- target: player
+ target: newPlayer.mediaPlayer
onPositionChanged: {
// seeked is a workaround for bug 1310706 as the first position after a seek is sometimes invalid (0)
if (progressSliderMusic.seeking === false && !progressSliderMusic.seeked) {
- musicToolbarFullPositionLabel.text = durationToString(player.position)
- musicToolbarFullDurationLabel.text = durationToString(player.duration)
+ musicToolbarFullPositionLabel.text = durationToString(newPlayer.mediaPlayer.position)
+ musicToolbarFullDurationLabel.text = durationToString(newPlayer.mediaPlayer.duration)
- progressSliderMusic.value = player.position
- progressSliderMusic.maximumValue = player.duration
+ progressSliderMusic.value = newPlayer.mediaPlayer.position
+ // fallback to 1 when 0 so that the progress bar works
+ progressSliderMusic.maximumValue = newPlayer.mediaPlayer.duration || 1
}
progressSliderMusic.seeked = false;
@@ -240,7 +250,7 @@
fontSize: "small"
height: parent.height
horizontalAlignment: Text.AlignHCenter
- text: durationToString(player.duration)
+ text: durationToString(newPlayer.mediaPlayer.duration)
verticalAlignment: Text.AlignVCenter
width: units.gu(3)
}
=== modified file 'app/components/NowPlayingToolbar.qml'
--- app/components/NowPlayingToolbar.qml 2015-07-29 01:23:11 +0000
+++ app/components/NowPlayingToolbar.qml 2015-10-27 19:27:27 +0000
@@ -37,9 +37,9 @@
anchors.rightMargin: units.gu(1)
anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
height: units.gu(6)
- opacity: player.repeat ? 1 : .4
+ opacity: newPlayer.repeat ? 1 : .4
width: height
- onClicked: player.repeat = !player.repeat
+ onClicked: newPlayer.repeat = !newPlayer.repeat
Icon {
id: repeatIcon
@@ -50,20 +50,21 @@
color: "white"
name: "media-playlist-repeat"
objectName: "repeatShape"
- opacity: player.repeat ? 1 : .4
+ opacity: newPlayer.repeat ? 1 : .4
}
}
/* Previous button */
MouseArea {
id: nowPlayingPreviousButton
+ enabled: newPlayer.mediaPlayer.canGoPrevious
anchors.right: nowPlayingPlayButton.left
anchors.rightMargin: units.gu(1)
anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
height: units.gu(6)
- opacity: trackQueue.model.count === 0 ? .4 : 1
+ opacity: newPlayer.mediaPlayer.playlist.empty ? .4 : 1
width: height
- onClicked: player.previousSong()
+ onClicked: newPlayer.mediaPlayer.playlist.previous() // FIXME:
Icon {
id: nowPlayingPreviousIndicator
@@ -74,7 +75,7 @@
color: "white"
name: "media-skip-backward"
objectName: "previousShape"
- opacity: 1
+ opacity: parent.enabled ? 1 : .4
}
}
@@ -84,7 +85,7 @@
anchors.centerIn: parent
height: units.gu(10)
width: height
- onClicked: player.toggle()
+ onClicked: newPlayer.mediaPlayer.toggle()
Icon {
id: nowPlayingPlayIndicator
@@ -93,7 +94,7 @@
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
color: "white"
- name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start"
+ name: newPlayer.mediaPlayer.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start"
objectName: "playShape"
}
}
@@ -104,10 +105,11 @@
anchors.left: nowPlayingPlayButton.right
anchors.leftMargin: units.gu(1)
anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
+ enabled: newPlayer.mediaPlayer.canGoNext
height: units.gu(6)
- opacity: trackQueue.model.count === 0 ? .4 : 1
+ opacity: newPlayer.mediaPlayer.playlist.empty ? .4 : 1
width: height
- onClicked: player.nextSong()
+ onClicked: newPlayer.mediaPlayer.playlist.next() // FIXME:
Icon {
id: nowPlayingNextIndicator
@@ -118,7 +120,7 @@
color: "white"
name: "media-skip-forward"
objectName: "forwardShape"
- opacity: 1
+ opacity: parent.enabled ? 1 : .4
}
}
@@ -129,9 +131,9 @@
anchors.leftMargin: units.gu(1)
anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
height: units.gu(6)
- opacity: player.shuffle ? 1 : .4
+ opacity: newPlayer.shuffle ? 1 : .4
width: height
- onClicked: player.shuffle = !player.shuffle
+ onClicked: newPlayer.shuffle = !newPlayer.shuffle
Icon {
id: shuffleIcon
@@ -142,7 +144,7 @@
color: "white"
name: "media-playlist-shuffle"
objectName: "shuffleShape"
- opacity: player.shuffle ? 1 : .4
+ opacity: newPlayer.shuffle ? 1 : .4
}
}
@@ -166,17 +168,7 @@
}
color: UbuntuColors.blue
height: parent.height
- width: player.duration > 0 ? (player.position / player.duration) * playerControlsProgressBar.width : 0
-
- Connections {
- target: player
- onPositionChanged: {
- playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width
- }
- onStopped: {
- playerControlsProgressBarHint.width = 0;
- }
- }
+ width: newPlayer.mediaPlayer.progress * playerControlsProgressBar.width
}
}
}
=== removed file 'app/components/Player.qml'
--- app/components/Player.qml 2015-06-28 03:06:49 +0000
+++ app/components/Player.qml 1970-01-01 00:00:00 +0000
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2013, 2014, 2015
- * Andrew Hayzen <ahayzen@xxxxxxxxx>
- * Daniel Holm <d.holmen@xxxxxxxxx>
- * Victor Thompson <victor.thompson@xxxxxxxxx>
- *
- * This program 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; version 3.
- *
- * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-import QtQuick 2.4
-import QtMultimedia 5.0
-import QtQuick.LocalStorage 2.0
-import Qt.labs.settings 1.0
-
-/*
- * This file should *only* manage the media playing and the relevant settings
- * It should therefore only access MediaPlayer, trackQueue and Settings
- * Anything else within the app should use Connections to listen for changes
- */
-
-
-Item {
- objectName: "player"
-
- property string currentMetaAlbum: ""
- property string currentMetaArt: ""
- property string currentMetaArtist: ""
- property string currentMetaFile: ""
- property string currentMetaTitle: ""
- property int currentIndex: -1
- property int duration: 1
- readonly property bool isPlaying: player.playbackState === MediaPlayer.PlayingState
- readonly property var playbackState: mediaPlayerLoader.status == Loader.Ready ? mediaPlayerLoader.item.playbackState : MediaPlayer.StoppedState
- property int position: 0
- property alias repeat: settings.repeat
- property alias shuffle: settings.shuffle
- readonly property string source: mediaPlayerLoader.status == Loader.Ready ? mediaPlayerLoader.item.source : ""
- readonly property double volume: mediaPlayerLoader.status == Loader.Ready ? mediaPlayerLoader.item.volume : 1.0
-
- signal stopped()
-
- Settings {
- id: settings
- category: "PlayerSettings"
-
- property bool repeat: true
- property bool shuffle: false
- }
-
- Connections {
- target: trackQueue.model
- onCountChanged: {
- if (trackQueue.model.count === 1 && (!queueLoaderWorker.canLoad || queueLoaderWorker.completed)) {
- player.currentIndex = 0;
- setSource(Qt.resolvedUrl(trackQueue.model.get(0).filename))
- } else if (trackQueue.model.count === 0 && (!queueLoaderWorker.canLoad || queueLoaderWorker.completed)) {
- player.currentIndex = -1
- setSource("")
- }
- }
- }
-
- function getSong(direction, startPlaying, fromControls) {
- // Seek to start if threshold reached when selecting previous
- if (direction === -1 && (player.position / 1000) > 5)
- {
- player.seek(0); // seek to start
- return;
- }
-
- if (trackQueue.model.count == 0)
- {
- customdebug("No tracks in queue.");
- return;
- }
-
- // default fromControls and startPlaying to true
- fromControls = fromControls === undefined ? true : fromControls;
- startPlaying = startPlaying === undefined ? true : startPlaying;
- var newIndex;
-
- console.log("currentIndex: " + currentIndex)
- console.log("trackQueue.count: " + trackQueue.model.count)
-
- // Do not shuffle if repeat is off and there is only one track in the queue
- if (shuffle && !(trackQueue.model.count === 1 && !repeat)) {
- var now = new Date();
- var seed = now.getSeconds();
-
- // trackQueue must be above 1 otherwise an infinite loop will occur
- do {
- newIndex = (Math.floor((trackQueue.model.count)
- * Math.random(seed)));
- } while (newIndex === currentIndex && trackQueue.model.count > 1)
- } else {
- if ((currentIndex < trackQueue.model.count - 1 && direction === 1 )
- || (currentIndex > 0 && direction === -1)) {
- newIndex = currentIndex + direction
- } else if(direction === 1 && (repeat || fromControls)) {
- newIndex = 0
- } else if(direction === -1 && (repeat || fromControls)) {
- newIndex = trackQueue.model.count - 1
- }
- else
- {
- player.stop()
- return;
- }
- }
-
- if (startPlaying) { // only start the track if told
- playSong(trackQueue.model.get(newIndex).filename, newIndex)
- }
- else {
- currentIndex = newIndex
- setSource(Qt.resolvedUrl(trackQueue.model.get(newIndex).filename))
- }
-
- // Set index into queue
- queueIndex = currentIndex
- }
-
- function nextSong(startPlaying, fromControls) {
- getSong(1, startPlaying, fromControls)
- }
-
- function pause() {
- mediaPlayerLoader.item.pause();
- }
-
- function play() {
- mediaPlayerLoader.item.play();
- }
-
- function playSong(filepath, index) {
- stop();
- currentIndex = index;
- queueIndex = index;
- setSource(filepath);
- play();
- }
-
- function previousSong(startPlaying) {
- getSong(-1, startPlaying)
- }
-
- function seek(position) {
- mediaPlayerLoader.item.seek(position);
- }
-
- function setSource(filepath) {
- mediaPlayerLoader.item.source = Qt.resolvedUrl(filepath);
- }
-
- function setVolume(volume) {
- mediaPlayerLoader.item.volume = volume
- }
-
- function stop() {
- mediaPlayerLoader.item.stop();
- }
-
- function toggle() {
- if (player.playbackState == MediaPlayer.PlayingState) {
- pause()
- }
- else {
- play()
- }
- }
-
- Loader {
- id: mediaPlayerLoader
- asynchronous: true
- sourceComponent: Component {
- MediaPlayer {
- muted: false
-
- onDurationChanged: player.duration = duration
- onPositionChanged: player.position = position
-
- onSourceChanged: {
- // Force invalid source to ""
- if (source === undefined || source === false) {
- source = ""
- return
- }
-
- if (source.toString() === "") {
- player.currentIndex = -1
- player.stop()
- }
- else {
- var obj;
-
- if (source.toString().indexOf("file://") === 0) {
- obj = musicStore.lookup(decodeFileURI(source.toString().substring(7)))
- } else {
- obj = musicStore.lookup(decodeFileURI(source.toString()))
- }
-
- // protect against null reponse from the lookup
- if (obj !== null) {
- // protect against undefined properties
- player.currentMetaAlbum = obj.album || "";
- player.currentMetaArt = obj.art || "";
- player.currentMetaArtist = obj.author || "";
- player.currentMetaFile = obj.filename || "";
- player.currentMetaTitle = obj.title || "";
- } else {
- console.debug("Mediascanner lookup resulted in null object", source.toString())
- }
- }
-
- console.log("Source: " + source.toString())
- console.log("Index: " + player.currentIndex)
- }
-
- onStatusChanged: {
- if (status == MediaPlayer.EndOfMedia) {
- nextSong(true, false) // next track
- }
- }
-
- onStopped: player.stopped()
- }
- }
- }
-}
-
=== modified file 'app/components/Queue.qml'
--- app/components/Queue.qml 2015-06-27 21:06:26 +0000
+++ app/components/Queue.qml 2015-10-27 19:27:27 +0000
@@ -34,7 +34,7 @@
footer: Item {
height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8)
}
- model: trackQueue.model
+ model: newPlayer.mediaPlayer.playlist
objectName: "nowPlayingqueueList"
property int normalHeight: units.gu(6)
@@ -44,14 +44,16 @@
delegate: MusicListItem {
id: queueListItem
- color: player.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor
+ color: newPlayer.mediaPlayer.playlist.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor
column: Column {
+ property var metaModel: newPlayer.metaForSource(model.source)
+
Label {
id: trackTitle
- color: player.currentIndex === index ? UbuntuColors.blue : styleMusic.common.music
+ color: newPlayer.mediaPlayer.playlist.currentIndex === index ? UbuntuColors.blue : styleMusic.common.music
fontSize: "small"
objectName: "titleLabel"
- text: model.title
+ text: metaModel.title
}
Label {
@@ -59,44 +61,53 @@
color: styleMusic.common.subtitle
fontSize: "x-small"
objectName: "artistLabel"
- text: model.author
+ text: metaModel.author
}
}
height: queueList.normalHeight
objectName: "nowPlayingListItem" + index
state: ""
leftSideAction: Remove {
- onTriggered: trackQueue.removeQueueList([index])
+ onTriggered: newPlayer.mediaPlayer.playlist.removeSource(index)
}
multiselectable: true
- reorderable: true
+ reorderable: true // FIXME: needs testing, sort out reordering we need moveSource(from, to);
rightSideActions: [
AddToPlaylist{
}
]
onItemClicked: {
- customdebug("File: " + model.filename) // debugger
- trackQueueClick(index); // toggle track state
+ customdebug("File: " + model.source) // debugger
+ trackQueueClick(index);
}
onReorder: {
console.debug("Move: ", from, to);
- trackQueue.model.move(from, to, 1);
- Library.moveQueueItem(from, to);
-
+ // Our custom reorder component does -1 on the 'to' if the item is moved 'down'
+ if (to > from) {
+ to += 1;
+ }
+
+ // If the item has gone 'up' then the remove index needs to be +1
+ // as a new item will be inserted before the item to be removed
+ if (to <= from) {
+ from += 1;
+ }
+
+ newPlayer.mediaPlayer.playlist.insertSource(to, model.source);
+ newPlayer.mediaPlayer.playlist.removeSource(from);
+
+ /*
// Maintain currentIndex with current song
- if (from === player.currentIndex) {
- player.currentIndex = to;
- }
- else if (from < player.currentIndex && to >= player.currentIndex) {
- player.currentIndex -= 1;
- }
- else if (from > player.currentIndex && to <= player.currentIndex) {
- player.currentIndex += 1;
- }
-
- queueIndex = player.currentIndex
+ if (from === newPlayer.mediaPlayer.playlist.currentIndex) {
+ newPlayer.mediaPlayer.playlist.currentIndex = to;
+ } else if (from < newPlayer.mediaPlayer.playlist.currentIndex && to >= newPlayer.mediaPlayer.playlist.currentIndex) {
+ newPlayer.mediaPlayer.playlist.currentIndex -= 1;
+ } else if (from > newPlayer.mediaPlayer.playlist.currentIndex && to <= newPlayer.mediaPlayer.playlist.currentIndex) {
+ newPlayer.mediaPlayer.playlist.currentIndex += 1;
+ }
+ */
}
}
}
=== modified file 'app/components/ViewButton/QueueAllButton.qml'
--- app/components/ViewButton/QueueAllButton.qml 2015-05-03 16:22:31 +0000
+++ app/components/ViewButton/QueueAllButton.qml 2015-10-27 19:27:27 +0000
@@ -28,7 +28,7 @@
property var model
- onClicked: addQueueFromModel(model)
+ onClicked: newPlayer.mediaPlayer.playlist.addSourcesFromModel(model)
Text {
anchors {
=== modified file 'app/components/ViewButton/ShuffleButton.qml'
--- app/components/ViewButton/ShuffleButton.qml 2015-05-03 16:22:31 +0000
+++ app/components/ViewButton/ShuffleButton.qml 2015-10-27 19:27:27 +0000
@@ -28,7 +28,7 @@
property var model
- onClicked: shuffleModel(model)
+ onClicked: playRandomSong(model)
Text {
anchors {
=== modified file 'app/logic/meta-database.js'
--- app/logic/meta-database.js 2015-06-20 18:01:59 +0000
+++ app/logic/meta-database.js 2015-10-27 19:27:27 +0000
@@ -70,7 +70,7 @@
var ind = getNextIndex(tx);
for (var i = 0; i < items.length; i++) {
- tx.executeSql('INSERT OR REPLACE INTO queue (ind, filename) VALUES (?,?);', [i + ind, items[i].filename]);
+ tx.executeSql('INSERT OR REPLACE INTO queue (ind, filename) VALUES (?,?);', [i + ind, items[i]]);
}
}
);
@@ -156,8 +156,15 @@
db.transaction( function(tx) {
var rs = tx.executeSql("SELECT * FROM queue ORDER BY ind ASC");
for(var i = 0; i < rs.rows.length; i++) {
- if (musicStore.lookup(decodeFileURI(rs.rows.item(i).filename)) != null) {
- res.push(makeDict(musicStore.lookup(decodeFileURI(rs.rows.item(i).filename))));
+ var filename = rs.rows.item(i).filename;
+
+ // Strip file:// from path as ms2 only accepts /home
+ if (filename.indexOf("file://") == 0) {
+ filename = filename.substr(7);
+ }
+
+ if (musicStore.lookup(decodeFileURI(filename)) != null) {
+ res.push(Qt.resolvedUrl(filename));
}
}
});
=== modified file 'app/music-app.qml'
--- app/music-app.qml 2015-09-08 08:12:31 +0000
+++ app/music-app.qml 2015-10-27 19:27:27 +0000
@@ -58,6 +58,11 @@
}
}
+ Connections {
+ target: newPlayer.mediaPlayer.playlist
+ onCurrentIndexChanged: startupSettings.queueIndex = newPlayer.mediaPlayer.playlist.currentIndex
+ }
+
// Global keyboard shortcuts
focus: true
Keys.onPressed: {
@@ -75,33 +80,35 @@
switch (event.key) {
case Qt.Key_Right: // Alt+Right Seek forward +10secs
- position = player.position + 10000 < player.duration
- ? player.position + 10000 : player.duration;
- player.seek(position);
+ position = newPlayer.mediaPlayer.position + 10000 < newPlayer.mediaPlayer.duration
+ ? newPlayer.mediaPlayer.position + 10000 : newPlayer.mediaPlayer.duration;
+ newPlayer.mediaPlayer.seek(position);
break;
case Qt.Key_Left: // Alt+Left Seek backwards -10secs
- position = player.position - 10000 > 0
- ? player.position - 10000 : 0;
- player.seek(position);
+ position = newPlayer.mediaPlayer.position - 10000 > 0
+ ? newPlayer.mediaPlayer.position - 10000 : 0;
+ newPlayer.mediaPlayer.seek(position);
break;
}
}
else if(event.modifiers === Qt.ControlModifier) {
switch (event.key) {
case Qt.Key_Left: // Ctrl+Left Previous Song
- player.previousSong(true);
+ newPlayer.mediaPlayer.playlist.previous();
break;
case Qt.Key_Right: // Ctrl+Right Next Song
- player.nextSong(true, true);
+ newPlayer.mediaPlayer.playlist.next();
break;
+ /*
case Qt.Key_Up: // Ctrl+Up Volume up
- player.volume = player.volume + .1 > 1 ? 1 : player.volume + .1
+ newPlayer.mediaPlayer.volume = newPlayer.mediaPlayer.volume + .1 > 1 ? 1 : newPlayer.mediaPlayer.volume + .1
break;
case Qt.Key_Down: // Ctrl+Down Volume down
- player.volume = player.volume - .1 < 0 ? 0 : player.volume - .1
+ newPlayer.mediaPlayer.volume = newPlayer.mediaPlayer.volume - .1 < 0 ? 0 : newPlayer.mediaPlayer.volume - .1
break;
+ */
case Qt.Key_R: // Ctrl+R Repeat toggle
- player.repeat = !player.repeat
+ newPlayer.mediaPlayer.repeat = !newPlayer.mediaPlayer.repeat
break;
case Qt.Key_F: // Ctrl+F Show Search popup
if (mainPageStack.currentMusicPage.searchable && mainPageStack.currentMusicPage.state === "default") {
@@ -118,13 +125,13 @@
tabs.pushNowPlaying()
break;
case Qt.Key_P: // Ctrl+P Toggle playing state
- player.toggle();
+ newPlayer.mediaPlayer.toggle();
break;
case Qt.Key_Q: // Ctrl+Q Quit the app
Qt.quit();
break;
case Qt.Key_U: // Ctrl+U Shuffle toggle
- player.shuffle = !player.shuffle
+ newPlayer.mediaPlayer.shuffle = !newPlayer.mediaPlayer.shuffle
break;
}
}
@@ -154,15 +161,15 @@
id: nextAction
text: i18n.tr("Next")
keywords: i18n.tr("Next Track")
- onTriggered: player.nextSong()
+ onTriggered: newPlayer.mediaPlayer.playlist.next()
}
Action {
id: playsAction
- text: player.playbackState === MediaPlayer.PlayingState ?
- i18n.tr("Pause") : i18n.tr("Play")
- keywords: player.playbackState === MediaPlayer.PlayingState ?
- i18n.tr("Pause Playback") : i18n.tr("Continue or start playback")
- onTriggered: player.toggle()
+ text: newPlayer.mediaPlayer.playbackState === MediaPlayer.PlayingState
+ ? i18n.tr("Pause") : i18n.tr("Play")
+ keywords: newPlayer.mediaPlayer.playbackState === MediaPlayer.PlayingState
+ ? i18n.tr("Pause Playback") : i18n.tr("Continue or start playback")
+ onTriggered: newPlayer.mediaPlayer.toggle()
}
Action {
id: backAction
@@ -177,16 +184,18 @@
id: prevAction
text: i18n.tr("Previous")
keywords: i18n.tr("Previous Track")
- onTriggered: player.previousSong()
+ onTriggered: newPlayer.mediaPlayer.playlist.previous()
}
+ /*
Action {
id: stopAction
text: i18n.tr("Stop")
keywords: i18n.tr("Stop Playback")
- onTriggered: player.stop()
+ onTriggered: newPlayer.mediaPlayer.stop()
}
+ */
- actions: [nextAction, playsAction, prevAction, stopAction, backAction]
+ actions: [nextAction, playsAction, prevAction, backAction]
UriHandlerHelper {
id: uriHandler
@@ -205,23 +214,6 @@
width: units.gu(100)
height: units.gu(80)
- WorkerModelLoader {
- id: queueLoaderWorker
- canLoad: false
- model: trackQueue.model
- syncFactor: 10
-
- onPreLoadCompleteChanged: {
- if (preLoadComplete) {
- player.currentIndex = queueIndex
-
- if (list[queueIndex] !== undefined) {
- player.setSource(list[queueIndex].filename)
- }
- }
- }
- }
-
WorkerWaiter {
id: waitForWorker
}
@@ -231,14 +223,27 @@
customdebug("Version "+appVersion) // print the curren version
Library.createRecent() // initialize recent
+ Library.createQueue() // create queue if it doesn't exist
// initialize playlists
Playlists.initializePlaylist()
if (!args.values.url) {
- // allow the queue loader to start
- queueLoaderWorker.canLoad = !Library.isQueueEmpty()
- queueLoaderWorker.list = Library.getQueue()
+ // load the previous queue as there are no args
+ // TODO: should not be hardcoded
+ // FIXME: doesn't work
+ //newPlayer.mediaPlayer.playlist.load("/home/phablet/.local/share/com.ubuntu.music/queue.m3u")
+
+ // use onloaded() and onLoadFailed() to confirm it is complete
+ // TODO: test if sync/async as future events may change the queue
+
+ // FIXME: using old queueList for now, move to load()/save() long term
+ if (!Library.isQueueEmpty()) {
+ newPlayer.mediaPlayer.playlist.addSources(Library.getQueue());
+
+ newPlayer.mediaPlayer.playlist.currentIndex = queueIndex;
+ newPlayer.mediaPlayer.pause();
+ }
}
// everything else
@@ -307,23 +312,6 @@
}
}
- function addQueueFromModel(model)
- {
- // TODO: remove once playlists uses U1DB
- if (model.hasOwnProperty("linkLibraryListModel")) {
- model = model.linkLibraryListModel;
- }
-
- var items = []
-
- for (var i=0; i < model.rowCount; i++) {
- items.push(model.get(i, model.RoleModelData))
- }
-
- // Add model to queue storage
- trackQueue.appendList(items)
- }
-
// Converts an duration in ms to a formated string ("minutes:seconds")
function durationToString(duration) {
var minutes = Math.floor((duration/1000) / 60);
@@ -348,14 +336,6 @@
}
function trackClicked(model, index, play, clear) {
- // Stop queue loading in the background
- queueLoaderWorker.canLoad = false
-
- if (queueLoaderWorker.processing > 0) {
- waitForWorker.workerStop(queueLoaderWorker, trackClicked, [model, index, play, clear])
- return;
- }
-
// TODO: remove once playlists uses U1DB
if (model.hasOwnProperty("linkLibraryListModel")) {
model = model.linkLibraryListModel;
@@ -364,39 +344,35 @@
var file = Qt.resolvedUrl(model.get(index, model.RoleModelData).filename);
play = play === undefined ? true : play // default play to true
- clear = clear === undefined ? false : clear // force clear and will ignore player.toggle()
+ clear = clear === undefined ? false : clear // force clear and will ignore toggle()
- if (!clear) {
+ if (!clear) { // FIXME: is this even used anymore? trackQueueClick instead?
// If same track and on Now playing page then toggle
if ((mainPageStack.currentPage.title === i18n.tr("Now playing") || mainPageStack.currentPage.title === i18n.tr("Queue"))
- && trackQueue.model.get(player.currentIndex) !== undefined
- && Qt.resolvedUrl(trackQueue.model.get(player.currentIndex).filename) === file) {
- player.toggle()
+ && Qt.resolvedUrl(newPlayer.mediaPlayer.playlist.currentSource) === file) {
+ newPlayer.mediaPlayer.toggle()
return;
}
}
- trackQueue.clear(); // clear the old model
-
- addQueueFromModel(model);
+ newPlayer.mediaPlayer.playlist.clear(); // clear the old model
+ newPlayer.mediaPlayer.playlist.addSourcesFromModel(model);
+ newPlayer.mediaPlayer.playlist.currentIndex = index;
if (play) {
- player.playSong(file, index);
+ newPlayer.mediaPlayer.play();
// Show the Now playing page and make sure the track is visible
tabs.pushNowPlaying();
}
- else {
- player.setSource(file);
- }
}
function trackQueueClick(index) {
- if (player.currentIndex === index) {
- player.toggle();
- }
- else {
- player.playSong(trackQueue.model.get(index).filename, index);
+ if (newPlayer.mediaPlayer.playlist.currentIndex === index) {
+ newPlayer.mediaPlayer.toggle();
+ } else {
+ newPlayer.mediaPlayer.playlist.currentIndex = index;
+ newPlayer.mediaPlayer.play();
}
// Show the Now playing page and make sure the track is visible
@@ -405,28 +381,17 @@
}
}
- function playRandomSong(shuffle)
- {
- trackQueue.clear();
-
- var now = new Date();
- var seed = now.getSeconds();
- var index = Math.floor(allSongsModel.rowCount * Math.random(seed));
-
- player.shuffle = shuffle === undefined ? true : shuffle;
-
- trackClicked(allSongsModel, index, true)
- }
-
- function shuffleModel(model)
- {
- var now = new Date();
- var seed = now.getSeconds();
- var index = Math.floor(model.count * Math.random(seed));
-
- player.shuffle = true;
-
- trackClicked(model, index, true)
+ function playRandomSong(model)
+ {
+ if (model === undefined) {
+ model = allSongsModel;
+ }
+
+ newPlayer.mediaPlayer.playlist.clear();
+ newPlayer.mediaPlayer.playlist.addSourcesFromModel(model);
+ newPlayer.shuffle = true;
+ newPlayer.mediaPlayer.playlist.shuffle();
+ newPlayer.mediaPlayer.play();
}
// Wrapper function around decodeURIComponent() to prevent exceptions
@@ -463,9 +428,11 @@
var i
var removed = []
+ // TODO: needs testing
+
// Find tracks from the queue that aren't in ms2 anymore
- for (i=0; i < trackQueue.model.count; i++) {
- if (musicStore.lookup(decodeFileURI(trackQueue.model.get(i).filename)) === null) {
+ for (i=0; i < newPlayer.mediaPlayer.playlist.count; i++) {
+ if (musicStore.lookup(decodeFileURI(newPlayer.mediaPlayer.playlist.source(i).filename)) === null) {
removed.push(i)
}
}
@@ -473,7 +440,7 @@
// If there are removed tracks then remove them from the queue and store
if (removed.length > 0) {
console.debug("Removed queue:", JSON.stringify(removed))
- trackQueue.removeQueueList(removed)
+ newPlayer.mediaPlayer.playlist.removeSources(removed.slice());
}
// Loop through playlists, getPlaylistTracks will remove any tracks that don't exist
@@ -559,8 +526,8 @@
}
// WHERE THE MAGIC HAPPENS
- Player {
- id: player
+ NewPlayer {
+ id: newPlayer
}
// TODO: Used by playlisttracks move to U1DB
@@ -590,105 +557,6 @@
}
}
- // list of tracks on startup. This is just during development
- LibraryListModel {
- id: trackQueue
- objectName: "trackQueue"
-
- function append(listElement)
- {
- model.append(makeDict(listElement))
- Library.addQueueItem(listElement.filename)
- }
-
- function appendList(items)
- {
- for (var i=0; i < items.length; i++) {
- model.append(makeDict(items[i]))
- }
-
- Library.addQueueList(items)
- }
-
- function clear()
- {
- Library.clearQueue()
- model.clear()
-
- queueIndex = 0 // reset otherwise when you append and play 1 track it doesn't update correctly
- }
-
- // Optimised removeQueue for removing multiple tracks from the queue
- function removeQueueList(items)
- {
- var i;
-
- // Remove from the saved queue database
- Library.removeQueueList(items)
-
- // Sort the item indexes as loops below assume *numeric* sort
- items.sort(function(a,b) { return a - b })
-
- // Remove from the listmodel
- var startCount = trackQueue.model.count
-
- for (i=0; i < items.length; i++) {
- // use diff in count as sometimes the row is removed from the model
- trackQueue.model.remove(items[i] - (startCount - trackQueue.model.count));
- }
-
- // Update the currentIndex and playing status
-
- if (trackQueue.model.count === 0) {
- // Nothing in the queue so stop and pop the queue
- player.stop()
- mainPageStack.goBack()
- } else if (items.indexOf(player.currentIndex) > -1) {
- // Current track was removed
-
- var newIndex;
-
- // Find the first index that still exists before the currentIndex
- for (i=player.currentIndex - 1; i > -1; i--) {
- if (items.indexOf(i) === -1) {
- break;
- }
- }
-
- newIndex = i;
-
- // Shuffle index down as tracks were removed before the current
- for (i=newIndex; i > -1; i--) {
- if (items.indexOf(i) !== -1) {
- newIndex--;
- }
- }
-
- // Set this as the current track
- player.currentIndex = newIndex
-
- // Play the next track
- player.nextSong(player.isPlaying);
- } else {
- // Current track not in removed list
- // Check if the index needs to be shuffled down due to removals
-
- var before = 0
-
- for (i=0; i < items.length; i++) {
- if (items[i] < player.currentIndex) {
- before++;
- }
- }
-
- // Update the index
- player.currentIndex -= before;
- }
-
- queueIndex = player.currentIndex; // ensure saved index is up to date
- }
- }
-
// TODO: list of playlists move to U1DB
// create the listmodel to use for playlists
LibraryListModel {
=== modified file 'app/ui/NowPlaying.qml'
--- app/ui/NowPlaying.qml 2015-08-19 14:03:16 +0000
+++ app/ui/NowPlaying.qml 2015-10-27 19:27:27 +0000
@@ -56,12 +56,12 @@
// Ensure that the listview has loaded before attempting to positionAt
function ensureListViewLoaded() {
- if (queueListLoader.item.count === trackQueue.model.count) {
- positionAt(player.currentIndex);
+ if (queueListLoader.item.count === newPlayer.mediaPlayer.playlist.mediaCount) {
+ positionAt(newPlayer.mediaPlayer.playlist.currentIndex);
} else {
queueListLoader.item.onCountChanged.connect(function() {
- if (queueListLoader.item.count === trackQueue.model.count) {
- positionAt(player.currentIndex);
+ if (queueListLoader.item.count === newPlayer.mediaPlayer.playlist.mediaCount) {
+ positionAt(newPlayer.mediaPlayer.playlist.currentIndex);
}
})
}
@@ -87,28 +87,30 @@
}
},
Action {
- enabled: trackQueue.model.count > 0
+ enabled: !newPlayer.mediaPlayer.playlist.empty
iconName: "add-to-playlist"
// TRANSLATORS: this action appears in the overflow drawer with limited space (around 18 characters)
text: i18n.tr("Add to playlist")
onTriggered: {
var items = []
- items.push(makeDict(trackQueue.model.get(player.currentIndex)));
+ items.push(makeDict(newPlayer.metaForSource(newPlayer.mediaPlayer.playlist.currentSource)));
mainPageStack.push(Qt.resolvedUrl("AddToPlaylist.qml"),
{"chosenElements": items})
}
},
Action {
- enabled: trackQueue.model.count > 0
+ enabled: !newPlayer.mediaPlayer.playlist.empty
iconName: "delete"
objectName: "clearQueue"
// TRANSLATORS: this action appears in the overflow drawer with limited space (around 18 characters)
text: i18n.tr("Clear queue")
onTriggered: {
mainPageStack.goBack()
- trackQueue.clear()
+ newPlayer.mediaPlayer.playlist.clear()
+
+ // FIXME: stop audio?
}
}
]
@@ -128,7 +130,9 @@
// Remove the tracks from the queue
// Use slice() to copy the list
// so that the indexes don't change as they are removed
- trackQueue.removeQueueList(selectedItems.slice())
+
+ // TODO: test!
+ newPlayer.mediaPlayer.playlist.removeSources(selectedItems.slice());
}
}
]
=== modified file 'app/ui/Songs.qml'
--- app/ui/Songs.qml 2015-06-27 21:06:26 +0000
+++ app/ui/Songs.qml 2015-10-27 19:27:27 +0000
@@ -122,8 +122,8 @@
onItemClicked: {
if (songsPage.state === "search") { // only play single track when searching
- trackQueue.clear()
- trackQueue.append(songsModelFilter.get(index))
+ newPlayer.mediaPlayer.playlist.clear();
+ newPlayer.mediaPlayer.playlist.addSource(Qt.resolvedUrl(songsModelFilter.get(index).filename));
trackQueueClick(0)
} else {
trackClicked(songsModelFilter, index) // play track
=== modified file 'debian/changelog'
--- debian/changelog 2015-09-25 08:11:22 +0000
+++ debian/changelog 2015-10-27 19:27:27 +0000
@@ -1,5 +1,8 @@
music-app (2.2ubuntu2) UNRELEASED; urgency=medium
+ [ Andrew Hayzen ]
+ * Add support for media-hub background playlists
+
[ Bartosz Kosiorek ]
* Reduce size of images (with tinypng.com) to decrease click size and improve performance
References