Merge lp:~vthompson/music-app/remix-remember-queue into lp:music-app/remix

Proposed by Victor Thompson
Status: Merged
Approved by: Andrew Hayzen
Approved revision: 700
Merged at revision: 705
Proposed branch: lp:~vthompson/music-app/remix-remember-queue
Merge into: lp:music-app/remix
Diff against target: 415 lines (+195/-18)
7 files modified
MusicNowPlaying.qml (+7/-2)
MusicTracks.qml (+1/-1)
Player.qml (+4/-0)
common/ListItemActions/AddToQueue.qml (+2/-0)
common/SongsPage.qml (+1/-1)
meta-database.js (+133/-1)
music-app.qml (+47/-13)
To merge this branch: bzr merge lp:~vthompson/music-app/remix-remember-queue
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Andrew Hayzen Approve
Review via email: mp+238810@code.launchpad.net

Commit message

Intial changes to remember the previous queue when restarting the app

Description of the change

Every other music app I've used persists the previous queue each time the app is launched. I think having a similar feature is pretty important for RTM, however, I know that we didn't want to have to rely on LocalStorage to do this. I think providing the functionality now would be better than waiting for the a better solution later.

To post a comment you must log in.
677. By Victor Thompson

Remove commented out code

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
678. By Victor Thompson

Small update to index values

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
679. By Victor Thompson

Improve performance slightly

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
680. By Victor Thompson

Small fix to ListItemAction

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
681. By Victor Thompson

Resolve conflicts and change tab selection detection

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
682. By Victor Thompson

Improve performance

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

1 inline comment and can it remember the previous index as well?

review: Needs Fixing
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

If you clear the queue and restart the app it remembers your queue you cleared.

Revision history for this message
Andrew Hayzen (ahayzen) wrote :

Even deleting one or many tracks from the queue causes them to be restored.

683. By Victor Thompson

Removed head actions from MusicNowPlaying and add initial recall of queue index

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
684. By Victor Thompson

Change order of setting currentIndex and source to get things working

685. By Victor Thompson

merge of remix and resolve conflict

686. By Victor Thompson

Resolve removing item and clearning queue.

687. By Victor Thompson

Update index on reorder

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

The currentIndex sometimes isn't maintained, eg select an item in the queue and the restart.

I suggest using something like the following to track the queueindex, instead of setting it in multiple places.

Connections {
   target: player
   onCurrentIndexChanged: startupSettings.queueIndex = player.currentIndex
}

review: Needs Fixing
688. By Victor Thompson

Fix for clicking on queue items

Revision history for this message
Victor Thompson (vthompson) wrote :

I made an attempt to use a similar Connections component to track changes to 'queueIndex', however, it didn't seem to work the way I wanted it to. I'll take another look into doing so shortly, but I think I now have each case covered.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
689. By Victor Thompson

merge of remix and resolve conflicts

690. By Victor Thompson

Use Player.setSource()

691. By Victor Thompson

Fix bad conflict resolution

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

This looks good assuming that this [0] mp can be approved and landed at the same time, as it has further fixes and performance tweaks. Therefore please ensure the other mp is approved before landing this and then land them together :)

0 - https://code.launchpad.net/~andrew-hayzen/music-app/remix-remember-queue-use-worker/+merge/239761

review: Approve
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

Reordering does not persist, looks like there should be a call to Library.moveQueueItem in the onReorder inside the queue

review: Needs Fixing
692. By Victor Thompson

Update change for reorder.

Revision history for this message
Andrew Hayzen (ahayzen) wrote :

Reordering now working \o/ As stated in the other comment we are waiting for the other mp [0] to be approved with this one.

0 - https://code.launchpad.net/~andrew-hayzen/music-app/remix-remember-queue-use-worker/+merge/239761

review: Approve
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
693. By Victor Thompson

Fix add to queue listitem action

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
694. By Victor Thompson

Use append method to reduce the number of places addQueueItem needs to go

695. By Victor Thompson

update fix for performance

696. By Victor Thompson

Use a clear function to minimize impacts of clearQueue()

697. By Victor Thompson

Missed one case...

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
698. By Victor Thompson

Fix remove case

699. By Victor Thompson

Fix remove index change

700. By Victor Thompson

Revert small change

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

Finally! lol LGTM :)

review: Approve
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'MusicNowPlaying.qml'
2--- MusicNowPlaying.qml 2014-10-26 21:39:08 +0000
3+++ MusicNowPlaying.qml 2014-10-28 00:57:21 +0000
4@@ -24,6 +24,7 @@
5 import Ubuntu.Thumbnailer 0.1
6 import "common"
7 import "common/ListItemActions"
8+import "meta-database.js" as Library
9 import "playlists.js" as Playlists
10
11 MusicPage {
12@@ -123,7 +124,7 @@
13 visible: isListView
14 onTriggered: {
15 head.backAction.trigger()
16- trackQueue.model.clear()
17+ trackQueue.clear()
18 }
19 }
20 ]
21@@ -507,10 +508,12 @@
22 }
23
24 trackQueue.model.remove(index);
25+ Library.removeQueueItem(removedIndex);
26
27 if (removedIndex < player.currentIndex) {
28 // update index as the old has been removed
29 player.currentIndex -= 1;
30+ queueIndex -= 1;
31 }
32 }
33
34@@ -598,7 +601,7 @@
35 console.debug("Move: ", from, to);
36
37 trackQueue.model.move(from, to, 1);
38-
39+ Library.moveQueueItem(from, to);
40
41 // Maintain currentIndex with current song
42 if (from === player.currentIndex) {
43@@ -610,6 +613,8 @@
44 else if (from > player.currentIndex && to <= player.currentIndex) {
45 player.currentIndex += 1;
46 }
47+
48+ queueIndex = player.currentIndex
49 }
50
51 Item {
52
53=== modified file 'MusicTracks.qml'
54--- MusicTracks.qml 2014-10-26 16:18:12 +0000
55+++ MusicTracks.qml 2014-10-28 00:57:21 +0000
56@@ -84,7 +84,7 @@
57 text: i18n.tr("Add to queue")
58 onTriggered: {
59 for (var i=0; i < tracklist.selectedItems.length; i++) {
60- trackQueue.model.append(makeDict(tracklist.model.get(tracklist.selectedItems[i], tracklist.model.RoleModelData)));
61+ trackQueue.append(makeDict(tracklist.model.get(tracklist.selectedItems[i], tracklist.model.RoleModelData)));
62 }
63
64 tracklist.closeSelection()
65
66=== modified file 'Player.qml'
67--- Player.qml 2014-10-26 16:18:12 +0000
68+++ Player.qml 2014-10-28 00:57:21 +0000
69@@ -125,6 +125,9 @@
70 currentIndex = newIndex
71 source = Qt.resolvedUrl(trackQueue.model.get(newIndex).filename)
72 }
73+
74+ // Set index into queue
75+ queueIndex = currentIndex
76 }
77
78 function nextSong(startPlaying, fromControls) {
79@@ -142,6 +145,7 @@
80 function playSong(filepath, index) {
81 stop();
82 currentIndex = index;
83+ queueIndex = index;
84 setSource(filepath);
85 play();
86 }
87
88=== modified file 'common/ListItemActions/AddToQueue.qml'
89--- common/ListItemActions/AddToQueue.qml 2014-09-20 10:50:45 +0000
90+++ common/ListItemActions/AddToQueue.qml 2014-10-28 00:57:21 +0000
91@@ -17,7 +17,9 @@
92 */
93
94 import QtQuick 2.3
95+import QtQuick.LocalStorage 2.0
96 import Ubuntu.Components 1.1
97+import "../../meta-database.js" as Library
98
99 Action {
100 iconName: "add"
101
102=== modified file 'common/SongsPage.qml'
103--- common/SongsPage.qml 2014-10-26 16:18:12 +0000
104+++ common/SongsPage.qml 2014-10-28 00:57:21 +0000
105@@ -132,7 +132,7 @@
106 text: i18n.tr("Add to queue")
107 onTriggered: {
108 for (var i=0; i < albumtrackslist.selectedItems.length; i++) {
109- trackQueue.model.append(makeDict(albumtrackslist.model.get(albumtrackslist.selectedItems[i], albumtrackslist.model.RoleModelData)));
110+ trackQueue.append(makeDict(albumtrackslist.model.get(albumtrackslist.selectedItems[i], albumtrackslist.model.RoleModelData)));
111 }
112
113 albumtrackslist.closeSelection()
114
115=== modified file 'meta-database.js'
116--- meta-database.js 2014-10-18 03:49:51 +0000
117+++ meta-database.js 2014-10-28 00:57:21 +0000
118@@ -32,7 +32,139 @@
119 tx.executeSql('DROP TABLE IF EXISTS metadata'); // TODO: drop recent as well to reset data
120
121 createRecent();
122- });
123+ createQueue();
124+ });
125+}
126+
127+function createQueue() {
128+ var db = getDatabase();
129+ db.transaction(
130+ function(tx) {
131+ tx.executeSql("CREATE TABLE IF NOT EXISTS queue(ind INTEGER NOT NULL, filename TEXT)");
132+ });
133+}
134+
135+function clearQueue() {
136+ var db = getDatabase();
137+ db.transaction(
138+ function(tx) {
139+ tx.executeSql('DROP TABLE IF EXISTS queue');
140+ tx.executeSql("CREATE TABLE IF NOT EXISTS queue(ind INTEGER NOT NULL, filename TEXT)");
141+ });
142+}
143+
144+function addQueueItem(ind,filename) {
145+ var db = getDatabase();
146+ var res="";
147+
148+ db.transaction(function(tx) {
149+ var rs = tx.executeSql('INSERT OR REPLACE INTO queue (ind, filename) VALUES (?,?);', [ind, filename]);
150+ if (rs.rowsAffected > 0) {
151+ console.log("QUEUE add OK")
152+ res = "OK";
153+ } else {
154+ console.log("QUEUE add Fail")
155+ res = "Error";
156+ }
157+ }
158+ );
159+}
160+
161+function addQueueList(model) {
162+ var db = getDatabase();
163+ var res="";
164+
165+ db.transaction(function(tx) {
166+
167+ for (var i = 0; i < model.count; i++) {
168+ var rs = tx.executeSql('INSERT OR REPLACE INTO queue (ind, filename) VALUES (?,?);', [i, model.get(i).filename]);
169+ if (rs.rowsAffected > 0) {
170+ res = "OK";
171+ } else {
172+ res = "Error";
173+ }
174+ }
175+ }
176+ );
177+}
178+
179+function moveQueueItem(from, to) {
180+ var db = getDatabase();
181+ var res="";
182+
183+ db.transaction(function(tx) {
184+
185+ // Generate new index number if records exist, otherwise use 0
186+ var rs = tx.executeSql('SELECT MAX(ind) FROM queue')
187+
188+ var nextIndex = isNaN(rs.rows.item(0)["MAX(ind)"]) ? 0 : rs.rows.item(
189+ 0)["MAX(ind)"] + 1
190+
191+ tx.executeSql('UPDATE queue SET ind=? WHERE ind=?;',
192+ [nextIndex, from])
193+
194+ if (from > to) {
195+ for (var i = from-1; i >= to; i--) {
196+ tx.executeSql('UPDATE queue SET ind=? WHERE ind=?;',
197+ [i+1, i])
198+ }
199+ } else {
200+ for (var j = from+1; j <= to; j++) {
201+ tx.executeSql('UPDATE queue SET ind=? WHERE ind=?;',
202+ [j-1, j])
203+ }
204+ }
205+
206+ tx.executeSql('UPDATE queue SET ind=? WHERE ind=?;',
207+ [to, nextIndex])
208+
209+ })
210+}
211+
212+function removeQueueItem(ind) {
213+ var db = getDatabase()
214+ var res = false
215+
216+ db.transaction(function (tx) {
217+ tx.executeSql('DELETE FROM queue WHERE ind=?;', [ind])
218+
219+ var rs = tx.executeSql('SELECT MAX(ind) FROM queue')
220+
221+ var lastIndex = isNaN(rs.rows.item(0)["MAX(ind)"]) ? 0 : rs.rows.item(
222+ 0)["MAX(ind)"]
223+ for(var i = ind+1; i <= lastIndex; i++) {
224+ tx.executeSql('UPDATE queue SET ind=? WHERE ind=?;',
225+ [i-1, i])
226+ }
227+ })
228+
229+ return res
230+}
231+
232+
233+function getQueue() {
234+ var res = [];
235+ var db = getDatabase();
236+ db.transaction( function(tx) {
237+ var rs = tx.executeSql("SELECT * FROM queue ORDER BY ind ASC");
238+ for(var i = 0; i < rs.rows.length; i++) {
239+ var dbItem = rs.rows.item(i);
240+ res.push({filename:dbItem.filename});
241+ }
242+ });
243+ return res;
244+}
245+
246+function isQueueEmpty() {
247+ var db = getDatabase();
248+ var res = 0;
249+
250+ db.transaction( function(tx) {
251+ createQueue();
252+ var rs = tx.executeSql("SELECT count(*) as value FROM queue")
253+ res = rs.rows.item(0).value === 0
254+ });
255+ return res
256 }
257
258 function createRecent() {
259
260=== modified file 'music-app.qml'
261--- music-app.qml 2014-10-26 21:39:08 +0000
262+++ music-app.qml 2014-10-28 00:57:21 +0000
263@@ -23,6 +23,7 @@
264 import Ubuntu.Components.ListItems 1.0 as ListItem
265 import Ubuntu.Content 0.1
266 import Ubuntu.MediaScanner 0.1
267+import Qt.labs.settings 1.0
268 import QtMultimedia 5.0
269 import QtQuick.LocalStorage 2.0
270 import QtGraphicalEffects 1.0
271@@ -40,6 +41,14 @@
272 backgroundColor: "#1e1e23"
273 headerColor: "#1e1e23"
274
275+ // Startup settings
276+ Settings {
277+ id: startupSettings
278+ category: "StartupSettings"
279+
280+ property int queueIndex: 0
281+ }
282+
283 // Global keyboard shortcuts
284 focus: true
285 Keys.onPressed: {
286@@ -213,7 +222,7 @@
287
288 if (play) {
289 // clear play queue
290- trackQueue.model.clear()
291+ trackQueue.clear()
292 }
293
294 // enqueue
295@@ -414,7 +423,7 @@
296 else {
297 stopTimer();
298
299- trackQueue.model.clear();
300+ trackQueue.clear();
301
302 for (i=0; i < searchPaths.length; i++) {
303 model = musicStore.lookup(searchPaths[i])
304@@ -533,6 +542,25 @@
305
306 Library.initialize();
307
308+ // Load previous queue
309+ if (!Library.isQueueEmpty()) {
310+ var queue = Library.getQueue()
311+ for (var i = 0; i < queue.length; i++) {
312+ trackQueue.model.append({
313+ album:musicStore.lookup(queue[i].filename).album,
314+ art:musicStore.lookup(queue[i].filename).art,
315+ author:musicStore.lookup(queue[i].filename).author,
316+ filename:queue[i].filename,
317+ title:musicStore.lookup(queue[i].filename).title
318+ })
319+ }
320+
321+ if (queue.length > queueIndex) {
322+ player.currentIndex = queueIndex
323+ player.setSource(queue[queueIndex].filename)
324+ }
325+ }
326+
327 // initialize playlists
328 Playlists.initializePlaylist()
329
330@@ -544,12 +572,8 @@
331
332 loadedUI = true;
333
334- // TODO: Switch tabs back and forth to get the background color in the
335- // header to work properly.
336- tabs.selectedTabIndex = 1
337-
338 // goto Recent if there are items otherwise go to Albums
339- tabs.selectedTabIndex = Library.isRecentEmpty() ? 2 : 0
340+ tabs.selectedTabIndex = Library.isRecentEmpty() ? albumsTab.index : startTab.index
341
342 // Run post load
343 tabs.ensurePopulated(tabs.selectedTab);
344@@ -564,6 +588,7 @@
345 property string appVersion: '1.2'
346 property bool toolbarShown: musicToolbar.visible
347 property bool selectedAlbum: false
348+ property alias queueIndex: startupSettings.queueIndex
349
350 signal listItemSwiping(int i)
351
352@@ -589,8 +614,11 @@
353 }
354
355 for (var i=0; i < model.rowCount; i++) {
356- trackQueue.model.append(makeDict(model.get(i, model.RoleModelData)));
357+ trackQueue.model.append(model.get(i, model.RoleModelData));
358 }
359+
360+ // Add model to queue storage
361+ Library.addQueueList(trackQueue.model);
362 }
363
364 // Converts an duration in ms to a formated string ("minutes:seconds")
365@@ -637,7 +665,7 @@
366 }
367 }
368
369- trackQueue.model.clear(); // clear the old model
370+ trackQueue.clear(); // clear the old model
371
372 addQueueFromModel(model);
373
374@@ -668,7 +696,7 @@
375
376 function playRandomSong(shuffle)
377 {
378- trackQueue.model.clear();
379+ trackQueue.clear();
380
381 var now = new Date();
382 var seed = now.getSeconds();
383@@ -766,7 +794,13 @@
384 function append(listElement)
385 {
386 model.append(makeDict(listElement))
387- console.debug(JSON.stringify(makeDict(listElement)));
388+ Library.addQueueItem(trackQueue.model.count,listElement.filename)
389+ }
390+
391+ function clear()
392+ {
393+ model.clear()
394+ Library.clearQueue()
395 }
396 }
397
398@@ -1080,7 +1114,7 @@
399 topMargin: -emptyPage.header.height
400 }
401 color: mainView.backgroundColor
402- visible: emptyPage.noPlaylists && !emptyPage.noMusic && tabs.selectedTab.index === 4
403+ visible: emptyPage.noPlaylists && !emptyPage.noMusic && playlistTab.index === tabs.selectedTab.index
404
405 Column {
406 anchors.centerIn: parent
407@@ -1110,7 +1144,7 @@
408 topMargin: -emptyPage.header.height
409 }
410 color: mainView.backgroundColor
411- visible: emptyPage.noRecent && !emptyPage.noMusic && tabs.selectedTab.index === 0
412+ visible: emptyPage.noRecent && !emptyPage.noMusic && startTab.index === tabs.selectedTab.index
413
414 Column {
415 anchors.centerIn: parent

Subscribers

People subscribed via source and target branches