Merge lp:~ahayzen/music-app/refactor-split-now-playing-queue-full-view into lp:music-app
- refactor-split-now-playing-queue-full-view
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Victor Thompson |
Approved revision: | 843 |
Merged at revision: | 845 |
Proposed branch: | lp:~ahayzen/music-app/refactor-split-now-playing-queue-full-view |
Merge into: | lp:music-app |
Diff against target: |
1092 lines (+550/-463) 5 files modified
app/components/HeadState/MultiSelectHeadState.qml (+3/-3) app/components/NowPlayingFullView.qml (+248/-0) app/components/NowPlayingToolbar.qml (+183/-0) app/components/Queue.qml (+101/-0) app/ui/NowPlaying.qml (+15/-460) |
To merge this branch: | bzr merge lp:~ahayzen/music-app/refactor-split-now-playing-queue-full-view |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Victor Thompson | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+250014@code.launchpad.net |
Commit message
* Only async load Queue as it causes poor loading experience on low powered devices (cherry pick from lp:~music-app-dev/music-app/refactor-now-playing-as-sidebar r847)
* Split the NowPlaying page into NowPlaying, Queue and NowPlayingToolbar (cherry pick from lp:~music-app-dev/music-app/refactor-now-playing-as-sidebar r841)
Description of the change
* Only async load Queue as it causes poor loading experience on low powered devices (cherry pick from lp:~music-app-dev/music-app/refactor-now-playing-as-sidebar r847)
* Split the NowPlaying page into NowPlaying, Queue and NowPlayingToolbar (cherry pick from lp:~music-app-dev/music-app/refactor-now-playing-as-sidebar r841)
This splits the NowPlaying full view, queue and toolbar into separate components as preparation for the NowPlaying sidebar. This mp is made up of two cherry picks from lp:~music-app-dev/music-app/refactor-now-playing-as-sidebar (r841 + r847).
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:843
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
This looks good to me. Overall the strategy for splitting these components up is a good one. However, things might change if we decide to change how do the tablet/wide views. Let's move forward and change things if we need to later. Thanks!
Preview Diff
1 | === modified file 'app/components/HeadState/MultiSelectHeadState.qml' |
2 | --- app/components/HeadState/MultiSelectHeadState.qml 2015-02-05 02:51:23 +0000 |
3 | +++ app/components/HeadState/MultiSelectHeadState.qml 2015-03-06 00:29:47 +0000 |
4 | @@ -34,7 +34,7 @@ |
5 | } |
6 | }, |
7 | Action { |
8 | - enabled: listview.selectedItems.length !== 0 |
9 | + enabled: listview !== null ? listview.selectedItems.length > 0 : false |
10 | iconName: "add-to-playlist" |
11 | text: i18n.tr("Add to playlist") |
12 | onTriggered: { |
13 | @@ -51,7 +51,7 @@ |
14 | } |
15 | }, |
16 | Action { |
17 | - enabled: listview.selectedItems.length > 0 |
18 | + enabled: listview !== null ? listview.selectedItems.length > 0 : false |
19 | iconName: "add" |
20 | text: i18n.tr("Add to queue") |
21 | visible: addToQueue |
22 | @@ -69,7 +69,7 @@ |
23 | } |
24 | }, |
25 | Action { |
26 | - enabled: listview.selectedItems.length > 0 |
27 | + enabled: listview !== null ? listview.selectedItems.length > 0 : false |
28 | iconName: "delete" |
29 | text: i18n.tr("Delete") |
30 | visible: removable |
31 | |
32 | === added file 'app/components/NowPlayingFullView.qml' |
33 | --- app/components/NowPlayingFullView.qml 1970-01-01 00:00:00 +0000 |
34 | +++ app/components/NowPlayingFullView.qml 2015-03-06 00:29:47 +0000 |
35 | @@ -0,0 +1,248 @@ |
36 | +/* |
37 | + * Copyright (C) 2013, 2014, 2015 |
38 | + * Andrew Hayzen <ahayzen@gmail.com> |
39 | + * Daniel Holm <d.holmen@gmail.com> |
40 | + * Victor Thompson <victor.thompson@gmail.com> |
41 | + * |
42 | + * This program is free software; you can redistribute it and/or modify |
43 | + * it under the terms of the GNU General Public License as published by |
44 | + * the Free Software Foundation; version 3. |
45 | + * |
46 | + * This program is distributed in the hope that it will be useful, |
47 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
48 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
49 | + * GNU General Public License for more details. |
50 | + * |
51 | + * You should have received a copy of the GNU General Public License |
52 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
53 | + */ |
54 | + |
55 | +import QtQuick 2.3 |
56 | +import Ubuntu.Components 1.1 |
57 | +import Ubuntu.Thumbnailer 0.1 |
58 | +import "../components/Themes/Ambiance" |
59 | + |
60 | + |
61 | +Item { |
62 | + id: fullview |
63 | + anchors { |
64 | + fill: parent |
65 | + } |
66 | + |
67 | + BlurredBackground { |
68 | + id: blurredBackground |
69 | + anchors { |
70 | + left: parent.left |
71 | + right: parent.right |
72 | + top: parent.top |
73 | + } |
74 | + art: albumImage.firstSource |
75 | + height: parent.height - units.gu(7) |
76 | + |
77 | + Item { |
78 | + id: albumImageContainer |
79 | + anchors { |
80 | + horizontalCenter: parent.horizontalCenter |
81 | + top: parent.top |
82 | + } |
83 | + height: parent.height |
84 | + width: parent.width |
85 | + |
86 | + CoverGrid { |
87 | + id: albumImage |
88 | + anchors.centerIn: parent |
89 | + covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaAlbum}] |
90 | + size: parent.width > parent.height ? parent.height : parent.width |
91 | + } |
92 | + } |
93 | + |
94 | + Rectangle { |
95 | + id: nowPlayingWideAspectLabelsBackground |
96 | + anchors.bottom: parent.bottom |
97 | + color: styleMusic.common.black |
98 | + height: nowPlayingWideAspectTitle.lineCount === 1 ? units.gu(10) : units.gu(13) |
99 | + opacity: 0.8 |
100 | + width: parent.width |
101 | + } |
102 | + |
103 | + /* Column for labels in wideAspect */ |
104 | + Column { |
105 | + id: nowPlayingWideAspectLabels |
106 | + spacing: units.gu(1) |
107 | + anchors { |
108 | + left: parent.left |
109 | + leftMargin: units.gu(2) |
110 | + right: parent.right |
111 | + rightMargin: units.gu(2) |
112 | + top: nowPlayingWideAspectLabelsBackground.top |
113 | + topMargin: nowPlayingWideAspectTitle.lineCount === 1 ? units.gu(2) : units.gu(1.5) |
114 | + } |
115 | + |
116 | + /* Title of track */ |
117 | + Label { |
118 | + id: nowPlayingWideAspectTitle |
119 | + anchors { |
120 | + left: parent.left |
121 | + leftMargin: units.gu(1) |
122 | + right: parent.right |
123 | + rightMargin: units.gu(1) |
124 | + } |
125 | + color: styleMusic.playerControls.labelColor |
126 | + elide: Text.ElideRight |
127 | + fontSize: "x-large" |
128 | + maximumLineCount: 2 |
129 | + objectName: "playercontroltitle" |
130 | + text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle |
131 | + wrapMode: Text.WordWrap |
132 | + } |
133 | + |
134 | + /* Artist of track */ |
135 | + Label { |
136 | + id: nowPlayingWideAspectArtist |
137 | + anchors { |
138 | + left: parent.left |
139 | + leftMargin: units.gu(1) |
140 | + right: parent.right |
141 | + rightMargin: units.gu(1) |
142 | + } |
143 | + color: styleMusic.nowPlaying.labelSecondaryColor |
144 | + elide: Text.ElideRight |
145 | + fontSize: "small" |
146 | + text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist |
147 | + } |
148 | + } |
149 | + |
150 | + /* Detect cover art swipe */ |
151 | + MouseArea { |
152 | + anchors.fill: parent |
153 | + property string direction: "None" |
154 | + property real lastX: -1 |
155 | + |
156 | + onPressed: lastX = mouse.x |
157 | + |
158 | + onReleased: { |
159 | + var diff = mouse.x - lastX |
160 | + if (Math.abs(diff) < units.gu(4)) { |
161 | + return; |
162 | + } else if (diff < 0) { |
163 | + player.nextSong() |
164 | + } else if (diff > 0) { |
165 | + player.previousSong() |
166 | + } |
167 | + } |
168 | + } |
169 | + } |
170 | + |
171 | + /* Background for progress bar component */ |
172 | + Rectangle { |
173 | + id: musicToolbarFullProgressBackground |
174 | + anchors { |
175 | + bottom: parent.bottom |
176 | + left: parent.left |
177 | + right: parent.right |
178 | + top: blurredBackground.bottom |
179 | + } |
180 | + color: styleMusic.common.black |
181 | + } |
182 | + |
183 | + /* Progress bar component */ |
184 | + Item { |
185 | + id: musicToolbarFullProgressContainer |
186 | + anchors.left: parent.left |
187 | + anchors.leftMargin: units.gu(3) |
188 | + anchors.right: parent.right |
189 | + anchors.rightMargin: units.gu(3) |
190 | + anchors.top: blurredBackground.bottom |
191 | + anchors.topMargin: units.gu(1) |
192 | + height: units.gu(3) |
193 | + width: parent.width |
194 | + |
195 | + /* Position label */ |
196 | + Label { |
197 | + id: musicToolbarFullPositionLabel |
198 | + anchors.top: progressSliderMusic.bottom |
199 | + anchors.topMargin: units.gu(-2) |
200 | + anchors.left: parent.left |
201 | + color: styleMusic.nowPlaying.labelSecondaryColor |
202 | + fontSize: "small" |
203 | + height: parent.height |
204 | + horizontalAlignment: Text.AlignHCenter |
205 | + text: durationToString(player.position) |
206 | + verticalAlignment: Text.AlignVCenter |
207 | + width: units.gu(3) |
208 | + } |
209 | + |
210 | + Slider { |
211 | + id: progressSliderMusic |
212 | + anchors.left: parent.left |
213 | + anchors.right: parent.right |
214 | + maximumValue: player.duration // load value at startup |
215 | + objectName: "progressSliderShape" |
216 | + style: UbuntuBlueSliderStyle {} |
217 | + value: player.position // load value at startup |
218 | + |
219 | + function formatValue(v) { |
220 | + if (seeking) { // update position label while dragging |
221 | + musicToolbarFullPositionLabel.text = durationToString(v) |
222 | + } |
223 | + |
224 | + return durationToString(v) |
225 | + } |
226 | + |
227 | + property bool seeking: false |
228 | + property bool seeked: false |
229 | + |
230 | + onSeekingChanged: { |
231 | + if (seeking === false) { |
232 | + musicToolbarFullPositionLabel.text = durationToString(player.position) |
233 | + } |
234 | + } |
235 | + |
236 | + onPressedChanged: { |
237 | + seeking = pressed |
238 | + |
239 | + if (!pressed) { |
240 | + seeked = true |
241 | + player.seek(value) |
242 | + |
243 | + musicToolbarFullPositionLabel.text = durationToString(value) |
244 | + } |
245 | + } |
246 | + |
247 | + Connections { |
248 | + target: player |
249 | + onPositionChanged: { |
250 | + // seeked is a workaround for bug 1310706 as the first position after a seek is sometimes invalid (0) |
251 | + if (progressSliderMusic.seeking === false && !progressSliderMusic.seeked) { |
252 | + musicToolbarFullPositionLabel.text = durationToString(player.position) |
253 | + musicToolbarFullDurationLabel.text = durationToString(player.duration) |
254 | + |
255 | + progressSliderMusic.value = player.position |
256 | + progressSliderMusic.maximumValue = player.duration |
257 | + } |
258 | + |
259 | + progressSliderMusic.seeked = false; |
260 | + } |
261 | + onStopped: { |
262 | + musicToolbarFullPositionLabel.text = durationToString(0); |
263 | + musicToolbarFullDurationLabel.text = durationToString(0); |
264 | + } |
265 | + } |
266 | + } |
267 | + |
268 | + /* Duration label */ |
269 | + Label { |
270 | + id: musicToolbarFullDurationLabel |
271 | + anchors.top: progressSliderMusic.bottom |
272 | + anchors.topMargin: units.gu(-2) |
273 | + anchors.right: parent.right |
274 | + color: styleMusic.nowPlaying.labelSecondaryColor |
275 | + fontSize: "small" |
276 | + height: parent.height |
277 | + horizontalAlignment: Text.AlignHCenter |
278 | + text: durationToString(player.duration) |
279 | + verticalAlignment: Text.AlignVCenter |
280 | + width: units.gu(3) |
281 | + } |
282 | + } |
283 | +} |
284 | |
285 | === added file 'app/components/NowPlayingToolbar.qml' |
286 | --- app/components/NowPlayingToolbar.qml 1970-01-01 00:00:00 +0000 |
287 | +++ app/components/NowPlayingToolbar.qml 2015-03-06 00:29:47 +0000 |
288 | @@ -0,0 +1,183 @@ |
289 | +/* |
290 | + * Copyright (C) 2013, 2014, 2015 |
291 | + * Andrew Hayzen <ahayzen@gmail.com> |
292 | + * Daniel Holm <d.holmen@gmail.com> |
293 | + * Victor Thompson <victor.thompson@gmail.com> |
294 | + * |
295 | + * This program is free software; you can redistribute it and/or modify |
296 | + * it under the terms of the GNU General Public License as published by |
297 | + * the Free Software Foundation; version 3. |
298 | + * |
299 | + * This program is distributed in the hope that it will be useful, |
300 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
301 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
302 | + * GNU General Public License for more details. |
303 | + * |
304 | + * You should have received a copy of the GNU General Public License |
305 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
306 | + */ |
307 | + |
308 | +import QtMultimedia 5.0 |
309 | +import QtQuick 2.3 |
310 | +import Ubuntu.Components 1.1 |
311 | + |
312 | + |
313 | +/* Full toolbar */ |
314 | +Rectangle { |
315 | + id: musicToolbarFullContainer |
316 | + anchors { |
317 | + fill: parent |
318 | + } |
319 | + color: styleMusic.common.black |
320 | + |
321 | + /* Repeat button */ |
322 | + MouseArea { |
323 | + id: nowPlayingRepeatButton |
324 | + anchors.right: nowPlayingPreviousButton.left |
325 | + anchors.rightMargin: units.gu(1) |
326 | + anchors.verticalCenter: nowPlayingPlayButton.verticalCenter |
327 | + height: units.gu(6) |
328 | + opacity: player.repeat && !emptyPageLoader.noMusic ? 1 : .4 |
329 | + width: height |
330 | + onClicked: player.repeat = !player.repeat |
331 | + |
332 | + Icon { |
333 | + id: repeatIcon |
334 | + height: units.gu(3) |
335 | + width: height |
336 | + anchors.verticalCenter: parent.verticalCenter |
337 | + anchors.horizontalCenter: parent.horizontalCenter |
338 | + color: "white" |
339 | + name: "media-playlist-repeat" |
340 | + objectName: "repeatShape" |
341 | + opacity: player.repeat && !emptyPageLoader.noMusic ? 1 : .4 |
342 | + } |
343 | + } |
344 | + |
345 | + /* Previous button */ |
346 | + MouseArea { |
347 | + id: nowPlayingPreviousButton |
348 | + anchors.right: nowPlayingPlayButton.left |
349 | + anchors.rightMargin: units.gu(1) |
350 | + anchors.verticalCenter: nowPlayingPlayButton.verticalCenter |
351 | + height: units.gu(6) |
352 | + opacity: trackQueue.model.count === 0 ? .4 : 1 |
353 | + width: height |
354 | + onClicked: player.previousSong() |
355 | + |
356 | + Icon { |
357 | + id: nowPlayingPreviousIndicator |
358 | + height: units.gu(3) |
359 | + width: height |
360 | + anchors.verticalCenter: parent.verticalCenter |
361 | + anchors.horizontalCenter: parent.horizontalCenter |
362 | + color: "white" |
363 | + name: "media-skip-backward" |
364 | + objectName: "previousShape" |
365 | + opacity: 1 |
366 | + } |
367 | + } |
368 | + |
369 | + /* Play/Pause button */ |
370 | + MouseArea { |
371 | + id: nowPlayingPlayButton |
372 | + anchors.centerIn: parent |
373 | + height: units.gu(10) |
374 | + width: height |
375 | + onClicked: player.toggle() |
376 | + |
377 | + Icon { |
378 | + id: nowPlayingPlayIndicator |
379 | + height: units.gu(6) |
380 | + width: height |
381 | + anchors.verticalCenter: parent.verticalCenter |
382 | + anchors.horizontalCenter: parent.horizontalCenter |
383 | + opacity: emptyPageLoader.noMusic ? .4 : 1 |
384 | + color: "white" |
385 | + name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" |
386 | + objectName: "playShape" |
387 | + } |
388 | + } |
389 | + |
390 | + /* Next button */ |
391 | + MouseArea { |
392 | + id: nowPlayingNextButton |
393 | + anchors.left: nowPlayingPlayButton.right |
394 | + anchors.leftMargin: units.gu(1) |
395 | + anchors.verticalCenter: nowPlayingPlayButton.verticalCenter |
396 | + height: units.gu(6) |
397 | + opacity: trackQueue.model.count === 0 ? .4 : 1 |
398 | + width: height |
399 | + onClicked: player.nextSong() |
400 | + |
401 | + Icon { |
402 | + id: nowPlayingNextIndicator |
403 | + height: units.gu(3) |
404 | + width: height |
405 | + anchors.verticalCenter: parent.verticalCenter |
406 | + anchors.horizontalCenter: parent.horizontalCenter |
407 | + color: "white" |
408 | + name: "media-skip-forward" |
409 | + objectName: "forwardShape" |
410 | + opacity: 1 |
411 | + } |
412 | + } |
413 | + |
414 | + /* Shuffle button */ |
415 | + MouseArea { |
416 | + id: nowPlayingShuffleButton |
417 | + anchors.left: nowPlayingNextButton.right |
418 | + anchors.leftMargin: units.gu(1) |
419 | + anchors.verticalCenter: nowPlayingPlayButton.verticalCenter |
420 | + height: units.gu(6) |
421 | + opacity: player.shuffle && !emptyPageLoader.noMusic ? 1 : .4 |
422 | + width: height |
423 | + onClicked: player.shuffle = !player.shuffle |
424 | + |
425 | + Icon { |
426 | + id: shuffleIcon |
427 | + height: units.gu(3) |
428 | + width: height |
429 | + anchors.verticalCenter: parent.verticalCenter |
430 | + anchors.horizontalCenter: parent.horizontalCenter |
431 | + color: "white" |
432 | + name: "media-playlist-shuffle" |
433 | + objectName: "shuffleShape" |
434 | + opacity: player.shuffle && !emptyPageLoader.noMusic ? 1 : .4 |
435 | + } |
436 | + } |
437 | + |
438 | + /* Object which provides the progress bar when in the queue */ |
439 | + Rectangle { |
440 | + id: playerControlsProgressBar |
441 | + anchors { |
442 | + bottom: parent.bottom |
443 | + left: parent.left |
444 | + right: parent.right |
445 | + } |
446 | + color: styleMusic.common.black |
447 | + height: units.gu(0.25) |
448 | + visible: isListView |
449 | + |
450 | + Rectangle { |
451 | + id: playerControlsProgressBarHint |
452 | + anchors { |
453 | + left: parent.left |
454 | + bottom: parent.bottom |
455 | + } |
456 | + color: UbuntuColors.blue |
457 | + height: parent.height |
458 | + width: player.duration > 0 ? (player.position / player.duration) * playerControlsProgressBar.width : 0 |
459 | + |
460 | + Connections { |
461 | + target: player |
462 | + onPositionChanged: { |
463 | + playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width |
464 | + } |
465 | + onStopped: { |
466 | + playerControlsProgressBarHint.width = 0; |
467 | + } |
468 | + } |
469 | + } |
470 | + } |
471 | +} |
472 | |
473 | === added file 'app/components/Queue.qml' |
474 | --- app/components/Queue.qml 1970-01-01 00:00:00 +0000 |
475 | +++ app/components/Queue.qml 2015-03-06 00:29:47 +0000 |
476 | @@ -0,0 +1,101 @@ |
477 | +/* |
478 | + * Copyright (C) 2013, 2014, 2015 |
479 | + * Andrew Hayzen <ahayzen@gmail.com> |
480 | + * Daniel Holm <d.holmen@gmail.com> |
481 | + * Victor Thompson <victor.thompson@gmail.com> |
482 | + * |
483 | + * This program is free software; you can redistribute it and/or modify |
484 | + * it under the terms of the GNU General Public License as published by |
485 | + * the Free Software Foundation; version 3. |
486 | + * |
487 | + * This program is distributed in the hope that it will be useful, |
488 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
489 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
490 | + * GNU General Public License for more details. |
491 | + * |
492 | + * You should have received a copy of the GNU General Public License |
493 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
494 | + */ |
495 | + |
496 | +import QtQuick 2.3 |
497 | +import Ubuntu.Components 1.1 |
498 | +import "Delegates" |
499 | +import "Flickables" |
500 | +import "ListItemActions" |
501 | + |
502 | + |
503 | +MultiSelectListView { |
504 | + id: queueList |
505 | + anchors { |
506 | + fill: parent |
507 | + } |
508 | + footer: Item { |
509 | + height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8) |
510 | + } |
511 | + model: trackQueue.model |
512 | + objectName: "nowPlayingqueueList" |
513 | + |
514 | + property int normalHeight: units.gu(6) |
515 | + property int transitionDuration: 250 // transition length of animations |
516 | + |
517 | + onCountChanged: customdebug("Queue: Now has: " + queueList.count + " tracks") |
518 | + |
519 | + delegate: MusicListItem { |
520 | + id: queueListItem |
521 | + color: player.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor |
522 | + column: Column { |
523 | + Label { |
524 | + id: trackTitle |
525 | + color: player.currentIndex === index ? UbuntuColors.blue : styleMusic.common.music |
526 | + fontSize: "small" |
527 | + objectName: "titleLabel" |
528 | + text: model.title |
529 | + } |
530 | + |
531 | + Label { |
532 | + id: trackArtist |
533 | + color: styleMusic.common.subtitle |
534 | + fontSize: "x-small" |
535 | + objectName: "artistLabel" |
536 | + text: model.author |
537 | + } |
538 | + } |
539 | + height: queueList.normalHeight |
540 | + objectName: "nowPlayingListItem" + index |
541 | + state: "" |
542 | + leftSideAction: Remove { |
543 | + onTriggered: trackQueue.removeQueueList([index]) |
544 | + } |
545 | + multiselectable: true |
546 | + reorderable: true |
547 | + rightSideActions: [ |
548 | + AddToPlaylist{ |
549 | + |
550 | + } |
551 | + ] |
552 | + |
553 | + onItemClicked: { |
554 | + customdebug("File: " + model.filename) // debugger |
555 | + trackQueueClick(index); // toggle track state |
556 | + } |
557 | + onReorder: { |
558 | + console.debug("Move: ", from, to); |
559 | + |
560 | + trackQueue.model.move(from, to, 1); |
561 | + Library.moveQueueItem(from, to); |
562 | + |
563 | + // Maintain currentIndex with current song |
564 | + if (from === player.currentIndex) { |
565 | + player.currentIndex = to; |
566 | + } |
567 | + else if (from < player.currentIndex && to >= player.currentIndex) { |
568 | + player.currentIndex -= 1; |
569 | + } |
570 | + else if (from > player.currentIndex && to <= player.currentIndex) { |
571 | + player.currentIndex += 1; |
572 | + } |
573 | + |
574 | + queueIndex = player.currentIndex |
575 | + } |
576 | + } |
577 | +} |
578 | |
579 | === modified file 'app/ui/NowPlaying.qml' |
580 | --- app/ui/NowPlaying.qml 2015-02-16 20:27:40 +0000 |
581 | +++ app/ui/NowPlaying.qml 2015-03-06 00:29:47 +0000 |
582 | @@ -17,17 +17,11 @@ |
583 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
584 | */ |
585 | |
586 | -import QtMultimedia 5.0 |
587 | import QtQuick 2.3 |
588 | import QtQuick.LocalStorage 2.0 |
589 | import Ubuntu.Components 1.1 |
590 | -import Ubuntu.Thumbnailer 0.1 |
591 | import "../components" |
592 | -import "../components/Delegates" |
593 | -import "../components/Flickables" |
594 | import "../components/HeadState" |
595 | -import "../components/ListItemActions" |
596 | -import "../components/Themes/Ambiance" |
597 | import "../logic/meta-database.js" as Library |
598 | import "../logic/playlists.js" as Playlists |
599 | |
600 | @@ -138,477 +132,38 @@ |
601 | } |
602 | ] |
603 | |
604 | - Item { |
605 | - id: fullview |
606 | + Loader { |
607 | anchors { |
608 | + left: parent.left |
609 | + right: parent.right |
610 | top: parent.top |
611 | topMargin: mainView.header.height |
612 | } |
613 | height: parent.height - mainView.header.height - units.gu(9.5) |
614 | + source: "../components/NowPlayingFullView.qml" |
615 | visible: !isListView |
616 | - width: parent.width |
617 | - |
618 | - BlurredBackground { |
619 | - id: blurredBackground |
620 | - anchors { |
621 | - left: parent.left |
622 | - right: parent.right |
623 | - top: parent.top |
624 | - } |
625 | - art: albumImage.firstSource |
626 | - height: parent.height - units.gu(7) |
627 | - |
628 | - Item { |
629 | - id: albumImageContainer |
630 | - anchors { |
631 | - horizontalCenter: parent.horizontalCenter |
632 | - top: parent.top |
633 | - } |
634 | - height: parent.height |
635 | - width: parent.width |
636 | - |
637 | - CoverGrid { |
638 | - id: albumImage |
639 | - anchors.centerIn: parent |
640 | - covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaAlbum}] |
641 | - size: parent.width > parent.height ? parent.height : parent.width |
642 | - } |
643 | - } |
644 | - |
645 | - Rectangle { |
646 | - id: nowPlayingWideAspectLabelsBackground |
647 | - anchors.bottom: parent.bottom |
648 | - color: styleMusic.common.black |
649 | - height: nowPlayingWideAspectTitle.lineCount === 1 ? units.gu(10) : units.gu(13) |
650 | - opacity: 0.8 |
651 | - width: parent.width |
652 | - } |
653 | - |
654 | - /* Column for labels in wideAspect */ |
655 | - Column { |
656 | - id: nowPlayingWideAspectLabels |
657 | - spacing: units.gu(1) |
658 | - anchors { |
659 | - left: parent.left |
660 | - leftMargin: units.gu(2) |
661 | - right: parent.right |
662 | - rightMargin: units.gu(2) |
663 | - top: nowPlayingWideAspectLabelsBackground.top |
664 | - topMargin: nowPlayingWideAspectTitle.lineCount === 1 ? units.gu(2) : units.gu(1.5) |
665 | - } |
666 | - |
667 | - /* Title of track */ |
668 | - Label { |
669 | - id: nowPlayingWideAspectTitle |
670 | - anchors { |
671 | - left: parent.left |
672 | - leftMargin: units.gu(1) |
673 | - right: parent.right |
674 | - rightMargin: units.gu(1) |
675 | - } |
676 | - color: styleMusic.playerControls.labelColor |
677 | - elide: Text.ElideRight |
678 | - fontSize: "x-large" |
679 | - maximumLineCount: 2 |
680 | - objectName: "playercontroltitle" |
681 | - text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle |
682 | - wrapMode: Text.WordWrap |
683 | - } |
684 | - |
685 | - /* Artist of track */ |
686 | - Label { |
687 | - id: nowPlayingWideAspectArtist |
688 | - anchors { |
689 | - left: parent.left |
690 | - leftMargin: units.gu(1) |
691 | - right: parent.right |
692 | - rightMargin: units.gu(1) |
693 | - } |
694 | - color: styleMusic.nowPlaying.labelSecondaryColor |
695 | - elide: Text.ElideRight |
696 | - fontSize: "small" |
697 | - text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist |
698 | - } |
699 | - } |
700 | - |
701 | - /* Detect cover art swipe */ |
702 | - MouseArea { |
703 | - anchors.fill: parent |
704 | - property string direction: "None" |
705 | - property real lastX: -1 |
706 | - |
707 | - onPressed: lastX = mouse.x |
708 | - |
709 | - onReleased: { |
710 | - var diff = mouse.x - lastX |
711 | - if (Math.abs(diff) < units.gu(4)) { |
712 | - return; |
713 | - } else if (diff < 0) { |
714 | - player.nextSong() |
715 | - } else if (diff > 0) { |
716 | - player.previousSong() |
717 | - } |
718 | - } |
719 | - } |
720 | - } |
721 | - |
722 | - /* Background for progress bar component */ |
723 | - Rectangle { |
724 | - id: musicToolbarFullProgressBackground |
725 | - anchors { |
726 | - bottom: parent.bottom |
727 | - left: parent.left |
728 | - right: parent.right |
729 | - top: blurredBackground.bottom |
730 | - } |
731 | - color: styleMusic.common.black |
732 | - } |
733 | - |
734 | - /* Progress bar component */ |
735 | - Item { |
736 | - id: musicToolbarFullProgressContainer |
737 | - anchors.left: parent.left |
738 | - anchors.leftMargin: units.gu(3) |
739 | - anchors.right: parent.right |
740 | - anchors.rightMargin: units.gu(3) |
741 | - anchors.top: blurredBackground.bottom |
742 | - anchors.topMargin: units.gu(1) |
743 | - height: units.gu(3) |
744 | - width: parent.width |
745 | - |
746 | - /* Position label */ |
747 | - Label { |
748 | - id: musicToolbarFullPositionLabel |
749 | - anchors.top: progressSliderMusic.bottom |
750 | - anchors.topMargin: units.gu(-2) |
751 | - anchors.left: parent.left |
752 | - color: styleMusic.nowPlaying.labelSecondaryColor |
753 | - fontSize: "small" |
754 | - height: parent.height |
755 | - horizontalAlignment: Text.AlignHCenter |
756 | - text: durationToString(player.position) |
757 | - verticalAlignment: Text.AlignVCenter |
758 | - width: units.gu(3) |
759 | - } |
760 | - |
761 | - Slider { |
762 | - id: progressSliderMusic |
763 | - anchors.left: parent.left |
764 | - anchors.right: parent.right |
765 | - maximumValue: player.duration // load value at startup |
766 | - objectName: "progressSliderShape" |
767 | - style: UbuntuBlueSliderStyle {} |
768 | - value: player.position // load value at startup |
769 | - |
770 | - function formatValue(v) { |
771 | - if (seeking) { // update position label while dragging |
772 | - musicToolbarFullPositionLabel.text = durationToString(v) |
773 | - } |
774 | - |
775 | - return durationToString(v) |
776 | - } |
777 | - |
778 | - property bool seeking: false |
779 | - property bool seeked: false |
780 | - |
781 | - onSeekingChanged: { |
782 | - if (seeking === false) { |
783 | - musicToolbarFullPositionLabel.text = durationToString(player.position) |
784 | - } |
785 | - } |
786 | - |
787 | - onPressedChanged: { |
788 | - seeking = pressed |
789 | - |
790 | - if (!pressed) { |
791 | - seeked = true |
792 | - player.seek(value) |
793 | - |
794 | - musicToolbarFullPositionLabel.text = durationToString(value) |
795 | - } |
796 | - } |
797 | - |
798 | - Connections { |
799 | - target: player |
800 | - onPositionChanged: { |
801 | - // seeked is a workaround for bug 1310706 as the first position after a seek is sometimes invalid (0) |
802 | - if (progressSliderMusic.seeking === false && !progressSliderMusic.seeked) { |
803 | - musicToolbarFullPositionLabel.text = durationToString(player.position) |
804 | - musicToolbarFullDurationLabel.text = durationToString(player.duration) |
805 | - |
806 | - progressSliderMusic.value = player.position |
807 | - progressSliderMusic.maximumValue = player.duration |
808 | - } |
809 | - |
810 | - progressSliderMusic.seeked = false; |
811 | - } |
812 | - onStopped: { |
813 | - musicToolbarFullPositionLabel.text = durationToString(0); |
814 | - musicToolbarFullDurationLabel.text = durationToString(0); |
815 | - } |
816 | - } |
817 | - } |
818 | - |
819 | - /* Duration label */ |
820 | - Label { |
821 | - id: musicToolbarFullDurationLabel |
822 | - anchors.top: progressSliderMusic.bottom |
823 | - anchors.topMargin: units.gu(-2) |
824 | - anchors.right: parent.right |
825 | - color: styleMusic.nowPlaying.labelSecondaryColor |
826 | - fontSize: "small" |
827 | - height: parent.height |
828 | - horizontalAlignment: Text.AlignHCenter |
829 | - text: durationToString(player.duration) |
830 | - verticalAlignment: Text.AlignVCenter |
831 | - width: units.gu(3) |
832 | - } |
833 | - } |
834 | } |
835 | |
836 | Loader { |
837 | id: queueListLoader |
838 | anchors { |
839 | + bottomMargin: nowPlayingToolbarLoader.height + units.gu(2) |
840 | fill: parent |
841 | + topMargin: units.gu(2) |
842 | } |
843 | asynchronous: true |
844 | - sourceComponent: MultiSelectListView { |
845 | - id: queueList |
846 | - anchors { |
847 | - bottomMargin: musicToolbarFullContainer.height + units.gu(2) |
848 | - fill: parent |
849 | - topMargin: units.gu(2) |
850 | - } |
851 | - footer: Item { |
852 | - height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8) |
853 | - } |
854 | - model: trackQueue.model |
855 | - objectName: "nowPlayingqueueList" |
856 | - |
857 | - property int normalHeight: units.gu(6) |
858 | - property int transitionDuration: 250 // transition length of animations |
859 | - |
860 | - onCountChanged: customdebug("Queue: Now has: " + queueList.count + " tracks") |
861 | - |
862 | - delegate: MusicListItem { |
863 | - id: queueListItem |
864 | - color: player.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor |
865 | - column: Column { |
866 | - Label { |
867 | - id: trackTitle |
868 | - color: player.currentIndex === index ? UbuntuColors.blue : styleMusic.common.music |
869 | - fontSize: "small" |
870 | - objectName: "titleLabel" |
871 | - text: model.title |
872 | - } |
873 | - |
874 | - Label { |
875 | - id: trackArtist |
876 | - color: styleMusic.common.subtitle |
877 | - fontSize: "x-small" |
878 | - objectName: "artistLabel" |
879 | - text: model.author |
880 | - } |
881 | - } |
882 | - height: queueList.normalHeight |
883 | - objectName: "nowPlayingListItem" + index |
884 | - state: "" |
885 | - leftSideAction: Remove { |
886 | - onTriggered: trackQueue.removeQueueList([index]) |
887 | - } |
888 | - multiselectable: true |
889 | - reorderable: true |
890 | - rightSideActions: [ |
891 | - AddToPlaylist{ |
892 | - |
893 | - } |
894 | - ] |
895 | - |
896 | - onItemClicked: { |
897 | - customdebug("File: " + model.filename) // debugger |
898 | - trackQueueClick(index); // toggle track state |
899 | - } |
900 | - onReorder: { |
901 | - console.debug("Move: ", from, to); |
902 | - |
903 | - trackQueue.model.move(from, to, 1); |
904 | - Library.moveQueueItem(from, to); |
905 | - |
906 | - // Maintain currentIndex with current song |
907 | - if (from === player.currentIndex) { |
908 | - player.currentIndex = to; |
909 | - } |
910 | - else if (from < player.currentIndex && to >= player.currentIndex) { |
911 | - player.currentIndex -= 1; |
912 | - } |
913 | - else if (from > player.currentIndex && to <= player.currentIndex) { |
914 | - player.currentIndex += 1; |
915 | - } |
916 | - |
917 | - queueIndex = player.currentIndex |
918 | - } |
919 | - } |
920 | - } |
921 | + source: "../components/Queue.qml" |
922 | visible: isListView |
923 | } |
924 | |
925 | - /* Full toolbar */ |
926 | - Rectangle { |
927 | - id: musicToolbarFullContainer |
928 | - anchors.bottom: parent.bottom |
929 | - color: styleMusic.common.black |
930 | + Loader { |
931 | + id: nowPlayingToolbarLoader |
932 | + anchors { |
933 | + bottom: parent.bottom |
934 | + left: parent.left |
935 | + right: parent.right |
936 | + } |
937 | height: units.gu(10) |
938 | - width: parent.width |
939 | - |
940 | - /* Repeat button */ |
941 | - MouseArea { |
942 | - id: nowPlayingRepeatButton |
943 | - anchors.right: nowPlayingPreviousButton.left |
944 | - anchors.rightMargin: units.gu(1) |
945 | - anchors.verticalCenter: nowPlayingPlayButton.verticalCenter |
946 | - height: units.gu(6) |
947 | - opacity: player.repeat && !emptyPageLoader.noMusic ? 1 : .4 |
948 | - width: height |
949 | - onClicked: player.repeat = !player.repeat |
950 | - |
951 | - Icon { |
952 | - id: repeatIcon |
953 | - height: units.gu(3) |
954 | - width: height |
955 | - anchors.verticalCenter: parent.verticalCenter |
956 | - anchors.horizontalCenter: parent.horizontalCenter |
957 | - color: "white" |
958 | - name: "media-playlist-repeat" |
959 | - objectName: "repeatShape" |
960 | - opacity: player.repeat && !emptyPageLoader.noMusic ? 1 : .4 |
961 | - } |
962 | - } |
963 | - |
964 | - /* Previous button */ |
965 | - MouseArea { |
966 | - id: nowPlayingPreviousButton |
967 | - anchors.right: nowPlayingPlayButton.left |
968 | - anchors.rightMargin: units.gu(1) |
969 | - anchors.verticalCenter: nowPlayingPlayButton.verticalCenter |
970 | - height: units.gu(6) |
971 | - opacity: trackQueue.model.count === 0 ? .4 : 1 |
972 | - width: height |
973 | - onClicked: player.previousSong() |
974 | - |
975 | - Icon { |
976 | - id: nowPlayingPreviousIndicator |
977 | - height: units.gu(3) |
978 | - width: height |
979 | - anchors.verticalCenter: parent.verticalCenter |
980 | - anchors.horizontalCenter: parent.horizontalCenter |
981 | - color: "white" |
982 | - name: "media-skip-backward" |
983 | - objectName: "previousShape" |
984 | - opacity: 1 |
985 | - } |
986 | - } |
987 | - |
988 | - /* Play/Pause button */ |
989 | - MouseArea { |
990 | - id: nowPlayingPlayButton |
991 | - anchors.centerIn: parent |
992 | - height: units.gu(10) |
993 | - width: height |
994 | - onClicked: player.toggle() |
995 | - |
996 | - Icon { |
997 | - id: nowPlayingPlayIndicator |
998 | - height: units.gu(6) |
999 | - width: height |
1000 | - anchors.verticalCenter: parent.verticalCenter |
1001 | - anchors.horizontalCenter: parent.horizontalCenter |
1002 | - opacity: emptyPageLoader.noMusic ? .4 : 1 |
1003 | - color: "white" |
1004 | - name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" |
1005 | - objectName: "playShape" |
1006 | - } |
1007 | - } |
1008 | - |
1009 | - /* Next button */ |
1010 | - MouseArea { |
1011 | - id: nowPlayingNextButton |
1012 | - anchors.left: nowPlayingPlayButton.right |
1013 | - anchors.leftMargin: units.gu(1) |
1014 | - anchors.verticalCenter: nowPlayingPlayButton.verticalCenter |
1015 | - height: units.gu(6) |
1016 | - opacity: trackQueue.model.count === 0 ? .4 : 1 |
1017 | - width: height |
1018 | - onClicked: player.nextSong() |
1019 | - |
1020 | - Icon { |
1021 | - id: nowPlayingNextIndicator |
1022 | - height: units.gu(3) |
1023 | - width: height |
1024 | - anchors.verticalCenter: parent.verticalCenter |
1025 | - anchors.horizontalCenter: parent.horizontalCenter |
1026 | - color: "white" |
1027 | - name: "media-skip-forward" |
1028 | - objectName: "forwardShape" |
1029 | - opacity: 1 |
1030 | - } |
1031 | - } |
1032 | - |
1033 | - /* Shuffle button */ |
1034 | - MouseArea { |
1035 | - id: nowPlayingShuffleButton |
1036 | - anchors.left: nowPlayingNextButton.right |
1037 | - anchors.leftMargin: units.gu(1) |
1038 | - anchors.verticalCenter: nowPlayingPlayButton.verticalCenter |
1039 | - height: units.gu(6) |
1040 | - opacity: player.shuffle && !emptyPageLoader.noMusic ? 1 : .4 |
1041 | - width: height |
1042 | - onClicked: player.shuffle = !player.shuffle |
1043 | - |
1044 | - Icon { |
1045 | - id: shuffleIcon |
1046 | - height: units.gu(3) |
1047 | - width: height |
1048 | - anchors.verticalCenter: parent.verticalCenter |
1049 | - anchors.horizontalCenter: parent.horizontalCenter |
1050 | - color: "white" |
1051 | - name: "media-playlist-shuffle" |
1052 | - objectName: "shuffleShape" |
1053 | - opacity: player.shuffle && !emptyPageLoader.noMusic ? 1 : .4 |
1054 | - } |
1055 | - } |
1056 | - |
1057 | - /* Object which provides the progress bar when in the queue */ |
1058 | - Rectangle { |
1059 | - id: playerControlsProgressBar |
1060 | - anchors { |
1061 | - bottom: parent.bottom |
1062 | - left: parent.left |
1063 | - right: parent.right |
1064 | - } |
1065 | - color: styleMusic.common.black |
1066 | - height: units.gu(0.25) |
1067 | - visible: isListView |
1068 | - |
1069 | - Rectangle { |
1070 | - id: playerControlsProgressBarHint |
1071 | - anchors { |
1072 | - left: parent.left |
1073 | - bottom: parent.bottom |
1074 | - } |
1075 | - color: UbuntuColors.blue |
1076 | - height: parent.height |
1077 | - width: player.duration > 0 ? (player.position / player.duration) * playerControlsProgressBar.width : 0 |
1078 | - |
1079 | - Connections { |
1080 | - target: player |
1081 | - onPositionChanged: { |
1082 | - playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width |
1083 | - } |
1084 | - onStopped: { |
1085 | - playerControlsProgressBarHint.width = 0; |
1086 | - } |
1087 | - } |
1088 | - } |
1089 | - } |
1090 | + source: "../components/NowPlayingToolbar.qml" |
1091 | } |
1092 | } |
PASSED: Continuous integration, rev:842 91.189. 93.70:8080/ job/music- app-refactor- ci/41/ 91.189. 93.70:8080/ job/generic- mediumtests- vivid/1096 91.189. 93.70:8080/ job/generic- mediumtests- vivid/1096/ artifact/ work/output/ *zip*/output. zip 91.189. 93.70:8080/ job/music- app-refactor- vivid-amd64- ci/41
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/music- app-refactor- ci/41/rebuild
http://