Merge lp:~ahayzen/music-app/refactor-split-now-playing-queue-full-view into lp:music-app

Proposed by Andrew Hayzen
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
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).

To post a comment you must log in.
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
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!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 }

Subscribers

People subscribed via source and target branches