Merge lp:~ahayzen/music-app/remix-queue-split into lp:music-app/remix
- remix-queue-split
- Merge into remix
Status: | Work in progress |
---|---|
Proposed branch: | lp:~ahayzen/music-app/remix-queue-split |
Merge into: | lp:music-app/remix |
Diff against target: |
978 lines (+449/-383) 4 files modified
MusicNowPlaying.qml (+25/-344) MusicQueue.qml (+368/-0) tests/autopilot/music_app/__init__.py (+19/-33) tests/autopilot/music_app/tests/test_music.py (+37/-6) |
To merge this branch: | bzr merge lp:~ahayzen/music-app/remix-queue-split |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Victor Thompson | Needs Fixing | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Needs Fixing | |
Review via email: mp+241884@code.launchpad.net |
Commit message
* Split the MusicQueue and MusicNowPlaying into two pages (still act like toggles though)
Description of the change
* Split the MusicQueue and MusicNowPlaying into two pages (still act like toggles though)
Note this is in prep for bottom edge development.
Please test both pages in great detail, remember things like header actions/multiselect etc :)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Victor Thompson (vthompson) wrote : | # |
When clicking on the toolbar while in Queue view the following error is produced:
file://
Victor Thompson (vthompson) wrote : | # |
This also causes the Queue to be rebuilt each time it is shown. Currently it is fairly distracting when it is doing so. Do we need to rebuild it each time?
Unmerged revisions
- 741. By Andrew Hayzen
-
* Split the MusicQueue and MusicNowPlaying into two pages (still act like toggles though)
Preview Diff
1 | === modified file 'MusicNowPlaying.qml' |
2 | --- MusicNowPlaying.qml 2014-11-07 22:51:16 +0000 |
3 | +++ MusicNowPlaying.qml 2014-11-15 22:18:22 +0000 |
4 | @@ -17,181 +17,42 @@ |
5 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
6 | */ |
7 | |
8 | -import QtMultimedia 5.0 |
9 | import QtQuick 2.3 |
10 | -import QtQuick.LocalStorage 2.0 |
11 | import Ubuntu.Components 1.1 |
12 | import Ubuntu.Thumbnailer 0.1 |
13 | import "common" |
14 | -import "common/ListItemActions" |
15 | -import "meta-database.js" as Library |
16 | -import "playlists.js" as Playlists |
17 | + |
18 | |
19 | MusicPage { |
20 | id: nowPlaying |
21 | - flickable: isListView ? queueListLoader.item : null // Ensures that the header is shown in fullview |
22 | objectName: "nowPlayingPage" |
23 | - title: isListView ? i18n.tr("Queue") : i18n.tr("Now playing") |
24 | - visible: false |
25 | - |
26 | - property bool isListView: false |
27 | - |
28 | - onIsListViewChanged: { |
29 | - if (isListView) { // When changing to the queue positionAt the currentIndex |
30 | - // ensure the loader and listview is ready |
31 | - if (queueListLoader.status === Loader.Ready) { |
32 | - ensureListViewLoaded() |
33 | - } else { |
34 | - queueListLoader.onStatusChanged.connect(function() { |
35 | - if (queueListLoader.status === Loader.Ready) { |
36 | - ensureListViewLoaded() |
37 | - } |
38 | - }) |
39 | - } |
40 | - } |
41 | - } |
42 | - |
43 | - // Ensure that the listview has loaded before attempting to positionAt |
44 | - function ensureListViewLoaded() { |
45 | - if (queueListLoader.item.count === trackQueue.model.count) { |
46 | - positionAt(player.currentIndex); |
47 | - } else { |
48 | - queueListLoader.item.onCountChanged.connect(function() { |
49 | - if (queueListLoader.item.count === trackQueue.model.count) { |
50 | - positionAt(player.currentIndex); |
51 | - } |
52 | - }) |
53 | - } |
54 | - } |
55 | - |
56 | - // Position the view at the index |
57 | - function positionAt(index) { |
58 | - queueListLoader.item.positionViewAtIndex(index, ListView.Center); |
59 | - } |
60 | - |
61 | - state: isListView && queueListLoader.item.state === "multiselectable" ? "selection" : "default" |
62 | - states: [ |
63 | - PageHeadState { |
64 | - id: defaultState |
65 | - |
66 | - name: "default" |
67 | - actions: [ |
68 | - Action { |
69 | - objectName: "toggleView" |
70 | - iconName: "media-playlist" |
71 | - onTriggered: { |
72 | - isListView = !isListView |
73 | - } |
74 | - }, |
75 | - Action { |
76 | - enabled: trackQueue.model.count > 0 |
77 | - iconName: "add-to-playlist" |
78 | - text: i18n.tr("Add to playlist") |
79 | - visible: isListView |
80 | - onTriggered: { |
81 | - var items = [] |
82 | - |
83 | - for (var i=0; i < trackQueue.model.count; i++) { |
84 | - items.push(makeDict(trackQueue.model.get(i))); |
85 | - } |
86 | - |
87 | - var comp = Qt.createComponent("MusicaddtoPlaylist.qml") |
88 | - var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": items}); |
89 | - |
90 | - if (addToPlaylist == null) { // Error Handling |
91 | - console.log("Error creating object"); |
92 | - } |
93 | - |
94 | - mainPageStack.push(addToPlaylist) |
95 | - } |
96 | - }, |
97 | - Action { |
98 | - enabled: trackQueue.model.count > 0 |
99 | - iconName: "delete" |
100 | - objectName: "clearQueue" |
101 | - text: i18n.tr("Clear queue") |
102 | - visible: isListView |
103 | - onTriggered: { |
104 | - pageStack.pop() |
105 | - trackQueue.clear() |
106 | - } |
107 | - } |
108 | - ] |
109 | - PropertyChanges { |
110 | - target: nowPlaying.head |
111 | - backAction: defaultState.backAction |
112 | - actions: defaultState.actions |
113 | - } |
114 | - }, |
115 | - PageHeadState { |
116 | - id: selectionState |
117 | - |
118 | - name: "selection" |
119 | - backAction: Action { |
120 | - text: i18n.tr("Cancel selection") |
121 | - iconName: "back" |
122 | - onTriggered: queueListLoader.item.state = "normal" |
123 | - } |
124 | - actions: [ |
125 | - Action { |
126 | - text: i18n.tr("Select All") |
127 | - iconName: "select" |
128 | - onTriggered: { |
129 | - if (queueListLoader.item.selectedItems.length === trackQueue.model.count) { |
130 | - queueListLoader.item.clearSelection() |
131 | - } else { |
132 | - queueListLoader.item.selectAll() |
133 | - } |
134 | - } |
135 | - }, |
136 | - Action { |
137 | - enabled: queueListLoader.item.selectedItems.length > 0 |
138 | - iconName: "add-to-playlist" |
139 | - text: i18n.tr("Add to playlist") |
140 | - onTriggered: { |
141 | - var items = [] |
142 | - |
143 | - for (var i=0; i < queueListLoader.item.selectedItems.length; i++) { |
144 | - items.push(makeDict(trackQueue.model.get(queueListLoader.item.selectedItems[i]))); |
145 | - } |
146 | - |
147 | - var comp = Qt.createComponent("MusicaddtoPlaylist.qml") |
148 | - var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": items}); |
149 | - |
150 | - if (addToPlaylist == null) { // Error Handling |
151 | - console.log("Error creating object"); |
152 | - } |
153 | - |
154 | - mainPageStack.push(addToPlaylist) |
155 | - |
156 | - queueListLoader.item.closeSelection() |
157 | - } |
158 | - }, |
159 | - Action { |
160 | - enabled: queueListLoader.item.selectedItems.length > 0 |
161 | - iconName: "delete" |
162 | - text: i18n.tr("Delete") |
163 | - onTriggered: { |
164 | - for (var i=0; i < queueListLoader.item.selectedItems.length; i++) { |
165 | - removeQueue(queueListLoader.item.selectedItems[i]) |
166 | - } |
167 | - |
168 | - queueListLoader.item.closeSelection() |
169 | - } |
170 | - } |
171 | - ] |
172 | - PropertyChanges { |
173 | - target: nowPlaying.head |
174 | - backAction: selectionState.backAction |
175 | - actions: selectionState.actions |
176 | - } |
177 | - } |
178 | - ] |
179 | + title: i18n.tr("Now playing") |
180 | + |
181 | + head { |
182 | + actions: [ |
183 | + Action { |
184 | + objectName: "toggleView" |
185 | + iconName: "media-playlist" |
186 | + onTriggered: { |
187 | + var comp = Qt.createComponent("MusicQueue.qml") |
188 | + var queue = comp.createObject(mainPageStack, {}); |
189 | + |
190 | + if (queue == null) { // Error Handling |
191 | + console.log("Error creating object"); |
192 | + } |
193 | + |
194 | + mainPageStack.pop(); |
195 | + mainPageStack.push(queue); |
196 | + |
197 | + queue.positionAtWhenReady(); // runs positionAt once queue is loaded |
198 | + } |
199 | + } |
200 | + ] |
201 | + } |
202 | |
203 | Item { |
204 | id: fullview |
205 | anchors.fill: parent |
206 | - visible: !isListView |
207 | |
208 | BlurredBackground { |
209 | id: blurredBackground |
210 | @@ -430,7 +291,7 @@ |
211 | anchors.horizontalCenter: parent.horizontalCenter |
212 | opacity: emptyPage.noMusic ? .4 : 1 |
213 | color: "white" |
214 | - name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" |
215 | + name: player.isPlaying ? "media-playback-pause" : "media-playback-start" |
216 | objectName: "playShape" |
217 | } |
218 | } |
219 | @@ -484,184 +345,4 @@ |
220 | } |
221 | } |
222 | } |
223 | - |
224 | - function removeQueue(index) |
225 | - { |
226 | - var removedIndex = index |
227 | - |
228 | - if (trackQueue.model.count === 1) { |
229 | - player.stop() |
230 | - musicToolbar.goBack() |
231 | - } else if (index === player.currentIndex) { |
232 | - player.nextSong(player.isPlaying); |
233 | - } |
234 | - |
235 | - trackQueue.model.remove(index); |
236 | - Library.removeQueueItem(removedIndex); |
237 | - |
238 | - if (removedIndex < player.currentIndex) { |
239 | - // update index as the old has been removed |
240 | - player.currentIndex -= 1; |
241 | - queueIndex -= 1; |
242 | - } |
243 | - } |
244 | - |
245 | - Loader { |
246 | - id: queueListLoader |
247 | - anchors { |
248 | - fill: parent |
249 | - } |
250 | - asynchronous: true |
251 | - sourceComponent: ListView { |
252 | - id: queueList |
253 | - anchors { |
254 | - bottomMargin: units.gu(2) |
255 | - fill: parent |
256 | - topMargin: units.gu(2) |
257 | - } |
258 | - delegate: queueDelegate |
259 | - footer: Item { |
260 | - height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8) |
261 | - } |
262 | - model: trackQueue.model |
263 | - objectName: "nowPlayingqueueList" |
264 | - |
265 | - property int normalHeight: units.gu(6) |
266 | - property int transitionDuration: 250 // transition length of animations |
267 | - |
268 | - onCountChanged: { |
269 | - customdebug("Queue: Now has: " + queueList.count + " tracks") |
270 | - } |
271 | - |
272 | - // Requirements for ListItemWithActions |
273 | - property var selectedItems: [] |
274 | - |
275 | - signal clearSelection() |
276 | - signal closeSelection() |
277 | - signal selectAll() |
278 | - |
279 | - onClearSelection: selectedItems = [] |
280 | - onCloseSelection: { |
281 | - clearSelection() |
282 | - state = "normal" |
283 | - } |
284 | - onSelectAll: { |
285 | - var tmp = selectedItems |
286 | - |
287 | - for (var i=0; i < model.count; i++) { |
288 | - if (tmp.indexOf(i) === -1) { |
289 | - tmp.push(i) |
290 | - } |
291 | - } |
292 | - |
293 | - selectedItems = tmp |
294 | - } |
295 | - onVisibleChanged: { |
296 | - if (!visible) { |
297 | - clearSelection(true) |
298 | - } |
299 | - } |
300 | - |
301 | - Component.onCompleted: { |
302 | - // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition |
303 | - // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration |
304 | - var scaleFactor = units.gridUnit / 8; |
305 | - maximumFlickVelocity = maximumFlickVelocity * scaleFactor; |
306 | - flickDeceleration = flickDeceleration * scaleFactor; |
307 | - } |
308 | - |
309 | - Component { |
310 | - id: queueDelegate |
311 | - ListItemWithActions { |
312 | - id: queueListItem |
313 | - color: player.currentIndex === index ? "#2c2c34" : "transparent" |
314 | - height: queueList.normalHeight |
315 | - objectName: "nowPlayingListItem" + index |
316 | - state: "" |
317 | - |
318 | - leftSideAction: Remove { |
319 | - onTriggered: removeQueue(index) |
320 | - } |
321 | - multiselectable: true |
322 | - reorderable: true |
323 | - rightSideActions: [ |
324 | - AddToPlaylist{ |
325 | - |
326 | - } |
327 | - ] |
328 | - |
329 | - onItemClicked: { |
330 | - customdebug("File: " + model.filename) // debugger |
331 | - trackQueueClick(index); // toggle track state |
332 | - } |
333 | - onReorder: { |
334 | - console.debug("Move: ", from, to); |
335 | - |
336 | - trackQueue.model.move(from, to, 1); |
337 | - Library.moveQueueItem(from, to); |
338 | - |
339 | - // Maintain currentIndex with current song |
340 | - if (from === player.currentIndex) { |
341 | - player.currentIndex = to; |
342 | - } |
343 | - else if (from < player.currentIndex && to >= player.currentIndex) { |
344 | - player.currentIndex -= 1; |
345 | - } |
346 | - else if (from > player.currentIndex && to <= player.currentIndex) { |
347 | - player.currentIndex += 1; |
348 | - } |
349 | - |
350 | - queueIndex = player.currentIndex |
351 | - } |
352 | - |
353 | - Item { |
354 | - id: trackContainer; |
355 | - anchors { |
356 | - fill: parent |
357 | - } |
358 | - |
359 | - NumberAnimation { |
360 | - id: trackContainerReorderAnimation |
361 | - target: trackContainer; |
362 | - property: "anchors.leftMargin"; |
363 | - duration: queueList.transitionDuration; |
364 | - to: units.gu(2) |
365 | - } |
366 | - |
367 | - NumberAnimation { |
368 | - id: trackContainerResetAnimation |
369 | - target: trackContainer; |
370 | - property: "anchors.leftMargin"; |
371 | - duration: queueList.transitionDuration; |
372 | - to: units.gu(0.5) |
373 | - } |
374 | - |
375 | - MusicRow { |
376 | - id: musicRow |
377 | - height: parent.height |
378 | - column: Column { |
379 | - Label { |
380 | - id: trackTitle |
381 | - color: player.currentIndex === index ? UbuntuColors.blue |
382 | - : styleMusic.common.music |
383 | - fontSize: "small" |
384 | - objectName: "titleLabel" |
385 | - text: model.title |
386 | - } |
387 | - |
388 | - Label { |
389 | - id: trackArtist |
390 | - color: styleMusic.common.subtitle |
391 | - fontSize: "x-small" |
392 | - objectName: "artistLabel" |
393 | - text: model.author |
394 | - } |
395 | - } |
396 | - } |
397 | - } |
398 | - } |
399 | - } |
400 | - } |
401 | - visible: isListView |
402 | - } |
403 | } |
404 | |
405 | === added file 'MusicQueue.qml' |
406 | --- MusicQueue.qml 1970-01-01 00:00:00 +0000 |
407 | +++ MusicQueue.qml 2014-11-15 22:18:22 +0000 |
408 | @@ -0,0 +1,368 @@ |
409 | +/* |
410 | + * Copyright (C) 2013, 2014 |
411 | + * Andrew Hayzen <ahayzen@gmail.com> |
412 | + * Daniel Holm <d.holmen@gmail.com> |
413 | + * Victor Thompson <victor.thompson@gmail.com> |
414 | + * |
415 | + * This program is free software; you can redistribute it and/or modify |
416 | + * it under the terms of the GNU General Public License as published by |
417 | + * the Free Software Foundation; version 3. |
418 | + * |
419 | + * This program is distributed in the hope that it will be useful, |
420 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
421 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
422 | + * GNU General Public License for more details. |
423 | + * |
424 | + * You should have received a copy of the GNU General Public License |
425 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
426 | + */ |
427 | + |
428 | +import QtQuick 2.3 |
429 | +import Ubuntu.Components 1.1 |
430 | +import "common" |
431 | +import "common/ListItemActions" |
432 | +import "meta-database.js" as Library |
433 | +import "playlists.js" as Playlists |
434 | + |
435 | + |
436 | +MusicPage { |
437 | + id: queuePage |
438 | + flickable: queueListLoader.item |
439 | + objectName: "queuePage" |
440 | + title: i18n.tr("Queue") |
441 | + state: queueListLoader.item.state === "multiselectable" ? "selection" : "default" |
442 | + states: [ |
443 | + PageHeadState { |
444 | + id: defaultState |
445 | + |
446 | + name: "default" |
447 | + actions: [ |
448 | + Action { |
449 | + objectName: "toggleView" |
450 | + iconName: "media-playlist" |
451 | + onTriggered: { |
452 | + var comp = Qt.createComponent("MusicNowPlaying.qml") |
453 | + var nowPlaying = comp.createObject(mainPageStack, {}); |
454 | + |
455 | + if (nowPlaying == null) { // Error Handling |
456 | + console.log("Error creating object"); |
457 | + } |
458 | + |
459 | + mainPageStack.pop(); |
460 | + mainPageStack.push(nowPlaying); |
461 | + } |
462 | + }, |
463 | + Action { |
464 | + enabled: trackQueue.model.count > 0 |
465 | + iconName: "add-to-playlist" |
466 | + text: i18n.tr("Add to playlist") |
467 | + onTriggered: { |
468 | + var items = [] |
469 | + |
470 | + for (var i=0; i < trackQueue.model.count; i++) { |
471 | + items.push(makeDict(trackQueue.model.get(i))); |
472 | + } |
473 | + |
474 | + var comp = Qt.createComponent("MusicaddtoPlaylist.qml") |
475 | + var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": items}); |
476 | + |
477 | + if (addToPlaylist == null) { // Error Handling |
478 | + console.log("Error creating object"); |
479 | + } |
480 | + |
481 | + mainPageStack.push(addToPlaylist) |
482 | + } |
483 | + }, |
484 | + Action { |
485 | + enabled: trackQueue.model.count > 0 |
486 | + iconName: "delete" |
487 | + objectName: "clearQueue" |
488 | + text: i18n.tr("Clear queue") |
489 | + onTriggered: { |
490 | + pageStack.pop() |
491 | + trackQueue.clear() |
492 | + } |
493 | + } |
494 | + ] |
495 | + PropertyChanges { |
496 | + target: queuePage.head |
497 | + backAction: defaultState.backAction |
498 | + actions: defaultState.actions |
499 | + } |
500 | + }, |
501 | + PageHeadState { |
502 | + id: selectionState |
503 | + |
504 | + name: "selection" |
505 | + backAction: Action { |
506 | + text: i18n.tr("Cancel selection") |
507 | + iconName: "back" |
508 | + onTriggered: queueListLoader.item.state = "normal" |
509 | + } |
510 | + actions: [ |
511 | + Action { |
512 | + text: i18n.tr("Select All") |
513 | + iconName: "select" |
514 | + onTriggered: { |
515 | + if (queueListLoader.item.selectedItems.length === trackQueue.model.count) { |
516 | + queueListLoader.item.clearSelection() |
517 | + } else { |
518 | + queueListLoader.item.selectAll() |
519 | + } |
520 | + } |
521 | + }, |
522 | + Action { |
523 | + enabled: queueListLoader.item.selectedItems.length > 0 |
524 | + iconName: "add-to-playlist" |
525 | + text: i18n.tr("Add to playlist") |
526 | + onTriggered: { |
527 | + var items = [] |
528 | + |
529 | + for (var i=0; i < queueListLoader.item.selectedItems.length; i++) { |
530 | + items.push(makeDict(trackQueue.model.get(queueListLoader.item.selectedItems[i]))); |
531 | + } |
532 | + |
533 | + var comp = Qt.createComponent("MusicaddtoPlaylist.qml") |
534 | + var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": items}); |
535 | + |
536 | + if (addToPlaylist == null) { // Error Handling |
537 | + console.log("Error creating object"); |
538 | + } |
539 | + |
540 | + mainPageStack.push(addToPlaylist) |
541 | + |
542 | + queueListLoader.item.closeSelection() |
543 | + } |
544 | + }, |
545 | + Action { |
546 | + enabled: queueListLoader.item.selectedItems.length > 0 |
547 | + iconName: "delete" |
548 | + text: i18n.tr("Delete") |
549 | + onTriggered: { |
550 | + for (var i=0; i < queueListLoader.item.selectedItems.length; i++) { |
551 | + removeQueue(queueListLoader.item.selectedItems[i]) |
552 | + } |
553 | + |
554 | + queueListLoader.item.closeSelection() |
555 | + } |
556 | + } |
557 | + ] |
558 | + PropertyChanges { |
559 | + target: queuePage.head |
560 | + backAction: selectionState.backAction |
561 | + actions: selectionState.actions |
562 | + } |
563 | + } |
564 | + ] |
565 | + |
566 | + // Ensure that the listview has loaded before attempting to positionAt |
567 | + function ensureListViewLoaded() { |
568 | + if (queueListLoader.item.count === trackQueue.model.count) { |
569 | + positionAt(player.currentIndex); |
570 | + } else { |
571 | + queueListLoader.item.onCountChanged.connect(function() { |
572 | + if (queueListLoader.item.count === trackQueue.model.count) { |
573 | + positionAt(player.currentIndex); |
574 | + } |
575 | + }) |
576 | + } |
577 | + } |
578 | + |
579 | + function removeQueue(index) |
580 | + { |
581 | + var removedIndex = index |
582 | + |
583 | + if (trackQueue.model.count === 1) { |
584 | + player.stop() |
585 | + musicToolbar.goBack() |
586 | + } else if (index === player.currentIndex) { |
587 | + player.nextSong(player.isPlaying); |
588 | + } |
589 | + |
590 | + trackQueue.model.remove(index); |
591 | + Library.removeQueueItem(removedIndex); |
592 | + |
593 | + if (removedIndex < player.currentIndex) { |
594 | + // update index as the old has been removed |
595 | + player.currentIndex -= 1; |
596 | + queueIndex -= 1; |
597 | + } |
598 | + } |
599 | + |
600 | + // Position the view at the index |
601 | + function positionAt(index) { |
602 | + queueListLoader.item.positionViewAtIndex(index, ListView.Center); |
603 | + } |
604 | + |
605 | + // Ensure the loader is ready and the list is ready before positioning at |
606 | + function positionAtWhenReady() { |
607 | + // ensure the loader and listview is ready |
608 | + if (queueListLoader.status === Loader.Ready) { |
609 | + ensureListViewLoaded() |
610 | + } else { |
611 | + queueListLoader.onStatusChanged.connect(function() { |
612 | + if (queueListLoader.status === Loader.Ready) { |
613 | + ensureListViewLoaded() |
614 | + } |
615 | + }) |
616 | + } |
617 | + } |
618 | + |
619 | + Loader { |
620 | + id: queueListLoader |
621 | + anchors { |
622 | + fill: parent |
623 | + } |
624 | + asynchronous: true |
625 | + sourceComponent: ListView { |
626 | + id: queueList |
627 | + anchors { |
628 | + bottomMargin: units.gu(2) |
629 | + fill: parent |
630 | + topMargin: units.gu(2) |
631 | + } |
632 | + delegate: queueDelegate |
633 | + footer: Item { |
634 | + height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8) |
635 | + } |
636 | + model: trackQueue.model |
637 | + objectName: "queueListView" |
638 | + |
639 | + property int normalHeight: units.gu(6) |
640 | + property int transitionDuration: 250 // transition length of animations |
641 | + |
642 | + onCountChanged: { |
643 | + customdebug("Queue: Now has: " + queueList.count + " tracks") |
644 | + } |
645 | + |
646 | + // Requirements for ListItemWithActions |
647 | + property var selectedItems: [] |
648 | + |
649 | + signal clearSelection() |
650 | + signal closeSelection() |
651 | + signal selectAll() |
652 | + |
653 | + onClearSelection: selectedItems = [] |
654 | + onCloseSelection: { |
655 | + clearSelection() |
656 | + state = "normal" |
657 | + } |
658 | + onSelectAll: { |
659 | + var tmp = selectedItems |
660 | + |
661 | + for (var i=0; i < model.count; i++) { |
662 | + if (tmp.indexOf(i) === -1) { |
663 | + tmp.push(i) |
664 | + } |
665 | + } |
666 | + |
667 | + selectedItems = tmp |
668 | + } |
669 | + onVisibleChanged: { |
670 | + if (!visible) { |
671 | + clearSelection(true) |
672 | + } |
673 | + } |
674 | + |
675 | + Component.onCompleted: { |
676 | + // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition |
677 | + // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration |
678 | + var scaleFactor = units.gridUnit / 8; |
679 | + maximumFlickVelocity = maximumFlickVelocity * scaleFactor; |
680 | + flickDeceleration = flickDeceleration * scaleFactor; |
681 | + } |
682 | + |
683 | + Component { |
684 | + id: queueDelegate |
685 | + ListItemWithActions { |
686 | + id: queueListItem |
687 | + color: player.currentIndex === index ? "#2c2c34" : "transparent" |
688 | + height: queueList.normalHeight |
689 | + objectName: "queueListItem" + index |
690 | + state: "" |
691 | + |
692 | + leftSideAction: Remove { |
693 | + onTriggered: removeQueue(index) |
694 | + } |
695 | + multiselectable: true |
696 | + reorderable: true |
697 | + rightSideActions: [ |
698 | + AddToPlaylist{ |
699 | + |
700 | + } |
701 | + ] |
702 | + |
703 | + onItemClicked: { |
704 | + customdebug("File: " + model.filename) // debugger |
705 | + trackQueueClick(index); // toggle track state |
706 | + } |
707 | + onReorder: { |
708 | + console.debug("Move: ", from, to); |
709 | + |
710 | + trackQueue.model.move(from, to, 1); |
711 | + Library.moveQueueItem(from, to); |
712 | + |
713 | + // Maintain currentIndex with current song |
714 | + if (from === player.currentIndex) { |
715 | + player.currentIndex = to; |
716 | + } |
717 | + else if (from < player.currentIndex && to >= player.currentIndex) { |
718 | + player.currentIndex -= 1; |
719 | + } |
720 | + else if (from > player.currentIndex && to <= player.currentIndex) { |
721 | + player.currentIndex += 1; |
722 | + } |
723 | + |
724 | + queueIndex = player.currentIndex |
725 | + } |
726 | + |
727 | + Item { |
728 | + id: trackContainer; |
729 | + anchors { |
730 | + fill: parent |
731 | + } |
732 | + |
733 | + NumberAnimation { |
734 | + id: trackContainerReorderAnimation |
735 | + target: trackContainer; |
736 | + property: "anchors.leftMargin"; |
737 | + duration: queueList.transitionDuration; |
738 | + to: units.gu(2) |
739 | + } |
740 | + |
741 | + NumberAnimation { |
742 | + id: trackContainerResetAnimation |
743 | + target: trackContainer; |
744 | + property: "anchors.leftMargin"; |
745 | + duration: queueList.transitionDuration; |
746 | + to: units.gu(0.5) |
747 | + } |
748 | + |
749 | + MusicRow { |
750 | + id: musicRow |
751 | + height: parent.height |
752 | + column: Column { |
753 | + Label { |
754 | + id: trackTitle |
755 | + color: player.currentIndex === index ? UbuntuColors.blue |
756 | + : styleMusic.common.music |
757 | + fontSize: "small" |
758 | + objectName: "titleLabel" |
759 | + text: model.title |
760 | + } |
761 | + |
762 | + Label { |
763 | + id: trackArtist |
764 | + color: styleMusic.common.subtitle |
765 | + fontSize: "x-small" |
766 | + objectName: "artistLabel" |
767 | + text: model.author |
768 | + } |
769 | + } |
770 | + } |
771 | + } |
772 | + } |
773 | + } |
774 | + } |
775 | + } |
776 | +} |
777 | |
778 | === modified file 'tests/autopilot/music_app/__init__.py' |
779 | --- tests/autopilot/music_app/__init__.py 2014-11-07 22:54:20 +0000 |
780 | +++ tests/autopilot/music_app/__init__.py 2014-11-15 22:18:22 +0000 |
781 | @@ -21,28 +21,6 @@ |
782 | return func_wrapper |
783 | |
784 | |
785 | -def ensure_now_playing_full(func): |
786 | - """Wrapper which ensures the now playing is full before clicking""" |
787 | - def func_wrapper(self, *args, **kwargs): |
788 | - if self.isListView: |
789 | - self.click_toggle_view() |
790 | - |
791 | - return func(self, *args, **kwargs) |
792 | - |
793 | - return func_wrapper |
794 | - |
795 | - |
796 | -def ensure_now_playing_list(func): |
797 | - """Wrapper which ensures the now playing is list before clicking""" |
798 | - def func_wrapper(self, *args, **kwargs): |
799 | - if not self.isListView: |
800 | - self.click_toggle_view() |
801 | - |
802 | - return func(self, *args, **kwargs) |
803 | - |
804 | - return func_wrapper |
805 | - |
806 | - |
807 | class MusicApp(object): |
808 | """Autopilot helper object for the Music application.""" |
809 | |
810 | @@ -89,6 +67,10 @@ |
811 | return self.main_view.select_single("LibraryListModel", |
812 | objectName="trackQueue").count |
813 | |
814 | + def get_queue_page(self): |
815 | + return self.app.wait_select_single(MusicQueue, |
816 | + objectName="queuePage") |
817 | + |
818 | def get_songs_page(self): |
819 | return self.app.wait_select_single(SongsPage, objectName="songsPage") |
820 | |
821 | @@ -242,27 +224,22 @@ |
822 | |
823 | self.visible.wait_for(True) |
824 | |
825 | - @ensure_now_playing_full |
826 | @click_object |
827 | def click_forward_button(self): |
828 | return self.wait_select_single("*", objectName="forwardShape") |
829 | |
830 | - @ensure_now_playing_full |
831 | @click_object |
832 | def click_play_button(self): |
833 | return self.wait_select_single("*", objectName="playShape") |
834 | |
835 | - @ensure_now_playing_full |
836 | @click_object |
837 | def click_previous_button(self): |
838 | return self.wait_select_single("*", objectName="previousShape") |
839 | |
840 | - @ensure_now_playing_full |
841 | @click_object |
842 | def click_repeat_button(self): |
843 | return self.wait_select_single("*", objectName="repeatShape") |
844 | |
845 | - @ensure_now_playing_full |
846 | @click_object |
847 | def click_shuffle_button(self): |
848 | return self.wait_select_single("*", objectName="shuffleShape") |
849 | @@ -270,12 +247,6 @@ |
850 | def click_toggle_view(self): |
851 | self.main_view.get_header().click_action_button("toggleView") |
852 | |
853 | - @ensure_now_playing_list |
854 | - def get_track(self, i): |
855 | - return (self.wait_select_single(ListItemWithActions, |
856 | - objectName="nowPlayingListItem" + str(i))) |
857 | - |
858 | - @ensure_now_playing_full |
859 | def seek_to(self, percentage): |
860 | progress_bar = self.wait_select_single( |
861 | "*", objectName="progressSliderShape") |
862 | @@ -300,6 +271,21 @@ |
863 | self.player.shuffle.wait_for(state) |
864 | |
865 | |
866 | +class MusicQueue(MusicPage): |
867 | + """ Autopilot helper for queue page """ |
868 | + def __init__(self, *args): |
869 | + super(MusicPage, self).__init__(*args) |
870 | + |
871 | + self.visible.wait_for(True) |
872 | + |
873 | + def click_toggle_view(self): |
874 | + self.main_view.get_header().click_action_button("toggleView") |
875 | + |
876 | + def get_track(self, i): |
877 | + return (self.wait_select_single(ListItemWithActions, |
878 | + objectName="queueListItem" + str(i))) |
879 | + |
880 | + |
881 | class AlbumsPage(MusicPage): |
882 | """ Autopilot helper for the albums page """ |
883 | def __init__(self, *args): |
884 | |
885 | === modified file 'tests/autopilot/music_app/tests/test_music.py' |
886 | --- tests/autopilot/music_app/tests/test_music.py 2014-11-07 23:08:29 +0000 |
887 | +++ tests/autopilot/music_app/tests/test_music.py 2014-11-15 22:18:22 +0000 |
888 | @@ -95,8 +95,13 @@ |
889 | # Re get now playing page as it has changed |
890 | now_playing_page = self.app.get_now_playing_page() |
891 | |
892 | + # Switch to the queue |
893 | + now_playing_page.click_toggle_view() |
894 | + |
895 | # verify song's metadata matches the item added to the Now Playing view |
896 | - current_track = now_playing_page.get_track(self.player.currentIndex) |
897 | + queue_page = self.app.get_queue_page() |
898 | + |
899 | + current_track = queue_page.get_track(self.player.currentIndex) |
900 | |
901 | self.assertThat(current_track.get_label_text("artistLabel"), |
902 | Equals(self.tracks[0]["artist"])) |
903 | @@ -350,8 +355,13 @@ |
904 | # Re get now playing page as it has changed |
905 | now_playing_page = self.app.get_now_playing_page() |
906 | |
907 | + # Switch to the queue |
908 | + now_playing_page.click_toggle_view() |
909 | + |
910 | # verify song's metadata matches the item added to the Now Playing view |
911 | - current_track = now_playing_page.get_track(self.player.currentIndex) |
912 | + queue_page = self.app.get_queue_page() |
913 | + |
914 | + current_track = queue_page.get_track(self.player.currentIndex) |
915 | |
916 | self.assertThat(current_track.get_label_text("artistLabel"), |
917 | Equals(tracks[0]["artist"])) |
918 | @@ -385,8 +395,13 @@ |
919 | Eventually(NotEquals(self.app.get_queue_count()))) |
920 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
921 | |
922 | + # Switch to the queue |
923 | + now_playing_page.click_toggle_view() |
924 | + |
925 | # verify song's metadata matches the item added to the Now Playing view |
926 | - current_track = now_playing_page.get_track(self.player.currentIndex) |
927 | + queue_page = self.app.get_queue_page() |
928 | + |
929 | + current_track = queue_page.get_track(self.player.currentIndex) |
930 | |
931 | self.assertThat(current_track.get_label_text("artistLabel"), |
932 | Equals(self.tracks[0]["artist"])) |
933 | @@ -425,8 +440,13 @@ |
934 | # Re get now playing page as it has changed |
935 | now_playing_page = self.app.get_now_playing_page() |
936 | |
937 | + # Switch to the queue |
938 | + now_playing_page.click_toggle_view() |
939 | + |
940 | # verify song's metadata matches the item added to the Now Playing view |
941 | - current_track = now_playing_page.get_track(self.player.currentIndex) |
942 | + queue_page = self.app.get_queue_page() |
943 | + |
944 | + current_track = queue_page.get_track(self.player.currentIndex) |
945 | |
946 | self.assertThat(current_track.get_label_text("artistLabel"), |
947 | Equals(self.tracks[0]["artist"])) |
948 | @@ -527,8 +547,13 @@ |
949 | Eventually(NotEquals(self.app.get_queue_count()))) |
950 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
951 | |
952 | + # Switch to the queue |
953 | + now_playing_page.click_toggle_view() |
954 | + |
955 | # verify song's metadata matches the item added to the Now Playing view |
956 | - current_track = now_playing_page.get_track(self.player.currentIndex) |
957 | + queue_page = self.app.get_queue_page() |
958 | + |
959 | + current_track = queue_page.get_track(self.player.currentIndex) |
960 | |
961 | self.assertThat(current_track.get_label_text("artistLabel"), |
962 | Equals(tracks[0]["artist"])) |
963 | @@ -546,8 +571,14 @@ |
964 | # get initial queue count |
965 | initial_queue_count = self.app.get_queue_count() |
966 | |
967 | + # Switch to the queue |
968 | + now_playing_page.click_toggle_view() |
969 | + |
970 | + # verify song's metadata matches the item added to the Now Playing view |
971 | + queue_page = self.app.get_queue_page() |
972 | + |
973 | # get track row and swipe to reveal swipe to delete |
974 | - track = now_playing_page.get_track(0) |
975 | + track = queue_page.get_track(0) |
976 | track.swipe_to_delete() |
977 | |
978 | track.confirm_removal() # confirm delete |
FAILED: Continuous integration, rev:741 91.189. 93.70:8080/ job/music- app-ci/ 1154/ 91.189. 93.70:8080/ job/generic- mediumtests- vivid/235 91.189. 93.70:8080/ job/generic- mediumtests- vivid/235/ artifact/ work/output/ *zip*/output. zip 91.189. 93.70:8080/ job/music- app-vivid- amd64-ci/ 6
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/music- app-ci/ 1154/rebuild
http://