Merge lp:~ahayzen/music-app/bottom-edge-implementation-001 into lp:music-app/trusty

Proposed by Andrew Hayzen
Status: Rejected
Rejected by: Victor Thompson
Proposed branch: lp:~ahayzen/music-app/bottom-edge-implementation-001
Merge into: lp:music-app/trusty
Diff against target: 2815 lines (+1586/-904)
10 files modified
MusicNowPlaying.qml (+15/-4)
MusicToolbar.qml (+1026/-889)
Player.qml (+4/-1)
common/AlbumsPage.qml (+0/-1)
common/MusicPage.qml (+7/-1)
common/PageWithBottomEdge.qml (+512/-0)
common/SongsPage.qml (+1/-1)
music-app.qml (+7/-7)
tests/autopilot/music_app/__init__.py (+6/-0)
tests/autopilot/music_app/tests/test_music.py (+8/-0)
To merge this branch: bzr merge lp:~ahayzen/music-app/bottom-edge-implementation-001
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Needs Fixing
Victor Thompson Needs Fixing
Review via email: mp+230303@code.launchpad.net

Commit message

* Add bottom edge support for now playing page across all MusicPages
* Reparent the same now playing page for all bottom edges

Description of the change

* Add bottom edge support for now playing page across all MusicPages
* Reparent the same now playing page for all bottom edges

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: Needs Fixing (continuous-integration)
536. By Andrew Hayzen

* Fix for console errors
* Improvements for ap tests

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

* Fixes for ap

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

* Add wait for isReady

539. By Andrew Hayzen

* Remove unneeded property alias

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

* Sync with upstream bottom edge

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

* Fix for panel state dragging

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

One small thing I just noticed is that sometimes the toolbar can not be exposed by simply swiping from the bottom. However, when this happens you can swipe up if you manage to precisely swipe up the hidden hint for the bottom edge.

To reproduce: 1) Click a view that pops a page onto the stack (select an album), 2) try to swipe up from the bottom.

I assume this has something to do with the pagestack.

review: Needs Fixing
542. By Andrew Hayzen

* Fix for margin on stacked pages

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 :

Comments:

1. I think we should start putting upstream code in a directory other than "common". I suggest we adopt the same name as the Clock reboot, which uses "upstreamcomponents".
2. I see the following error in the logs, not sure if it was introudced here:

file:///opt/click.ubuntu.com/com.ubuntu.music/1.3.542/music-app.qml:963:9: QML M
usicNowPlaying: Cannot anchor to an item that isn't a parent or sibling.

I also added a few inline comments.

review: Needs Fixing
543. By Andrew Hayzen

* Fixes for some inline diff comments

544. By Andrew Hayzen

* Merge of trunk

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

* Merge of trunk

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

Setting this to WIP, as we have decided to wait until the 'remix' of the app and implement this feature in the new design, if appropriate.

Unmerged revisions

545. By Andrew Hayzen

* Merge of trunk

544. By Andrew Hayzen

* Merge of trunk

543. By Andrew Hayzen

* Fixes for some inline diff comments

542. By Andrew Hayzen

* Fix for margin on stacked pages

541. By Andrew Hayzen

* Fix for panel state dragging

540. By Andrew Hayzen

* Sync with upstream bottom edge

539. By Andrew Hayzen

* Remove unneeded property alias

538. By Andrew Hayzen

* Add wait for isReady

537. By Andrew Hayzen

* Fixes for ap

536. By Andrew Hayzen

* Fix for console errors
* Improvements for ap tests

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'MusicNowPlaying.qml'
--- MusicNowPlaying.qml 2014-08-17 23:58:29 +0000
+++ MusicNowPlaying.qml 2014-08-21 20:46:47 +0000
@@ -31,9 +31,12 @@
31 id: nowPlaying31 id: nowPlaying
32 objectName: "nowplayingpage"32 objectName: "nowplayingpage"
33 title: i18n.tr("Now Playing")33 title: i18n.tr("Now Playing")
34 visible: false34 visible: true
3535
36 property int ensureVisibleIndex: 0 // ensure first index is visible at startup36 property int ensureVisibleIndex: 0 // ensure first index is visible at startup
37 property var parentCache // cache of parent for reparent()
38
39 bottomEdgeEnabled: false
3740
38 Rectangle {41 Rectangle {
39 anchors.fill: parent42 anchors.fill: parent
@@ -80,6 +83,14 @@
80 queuelist.contentY -= header.height;83 queuelist.contentY -= header.height;
81 }84 }
8285
86 function reparent(newParent) {
87 if (parentCache !== newParent) {
88 nowPlaying.parent = newParent
89 nowPlaying.anchors.fill = newParent
90 parentCache = newParent
91 }
92 }
93
83 ListView {94 ListView {
84 id: queuelist95 id: queuelist
85 objectName: "queuelist"96 objectName: "queuelist"
@@ -348,10 +359,10 @@
348 }359 }
349360
350 onRunningChanged: {361 onRunningChanged: {
351 if (running === false && ensureVisibleIndex != -1)362 if (running === false && nowPlaying.ensureVisibleIndex != -1)
352 {363 {
353 queuelist.positionViewAtIndex(ensureVisibleIndex, ListView.Beginning);364 queuelist.positionViewAtIndex(nowPlaying.ensureVisibleIndex, ListView.Beginning);
354 ensureVisibleIndex = -1;365 nowPlaying.ensureVisibleIndex = -1;
355 }366 }
356 }367 }
357 }368 }
358369
=== modified file 'MusicToolbar.qml'
--- MusicToolbar.qml 2014-08-18 00:02:37 +0000
+++ MusicToolbar.qml 2014-08-21 20:46:47 +0000
@@ -24,12 +24,15 @@
24import Ubuntu.Components.Popups 0.124import Ubuntu.Components.Popups 0.1
25import "settings.js" as Settings25import "settings.js" as Settings
2626
27Item {27Panel {
28 anchors {28 id: musicToolbarPanel
29 bottom: parent.bottom29 align: Qt.AlignCenter
30 left: parent.left30 height: currentMode === "full" ? fullHeight : expandedHeight
31 right: parent.right31 locked: true
32 }32 width: parent.width
33 x: 0
34 y: currentPage === null ? 0 : currentPage.height
35 z: 200
3336
34 // Properties storing the current page info37 // Properties storing the current page info
35 property var currentPage: null38 property var currentPage: null
@@ -43,13 +46,63 @@
43 property int transitionDuration: 10046 property int transitionDuration: 100
4447
45 property alias currentHeight: musicToolbarPanel.height48 property alias currentHeight: musicToolbarPanel.height
46 property alias minimizedHeight: musicToolbarPanel.minimizedHeight
47 property alias expandedHeight: musicToolbarPanel.expandedHeight
48 property alias fullHeight: musicToolbarPanel.fullHeight
49 property alias mouseAreaOffset: musicToolbarPanel.hintSize49 property alias mouseAreaOffset: musicToolbarPanel.hintSize
5050
51 property alias animating: musicToolbarPanel.animating51 // The current mode of the controls
52 property alias opened: musicToolbarPanel.opened52 property string currentMode: wideAspect || isNowPlaying(currentPage)
53 ? "full" : "expanded"
54
55 // Properties for the different heights
56 property int minimizedHeight: units.gu(0.5)
57 property int expandedHeight: units.gu(8)
58 property int fullHeight: units.gu(11)
59
60 onCurrentModeChanged: {
61 musicToolbarFullProgressMouseArea.enabled = currentMode === "full"
62 }
63
64 onHeightChanged: {
65 if (currentPage !== null && !currentPage.floating) {
66 if (shown) {
67 y = currentPage.height - height
68 } else {
69 y = currentPage.height
70 }
71 }
72 }
73
74 onOpenedChanged: {
75 onToolbarShownChanged(opened, currentPage, currentTab);
76
77 if (opened) {
78 startAutoHideTimer();
79 }
80 }
81
82 onShownChanged: {
83 onToolbarShownChanged(shown, currentPage, currentTab);
84
85 if (shown) {
86 startAutoHideTimer();
87 }
88 }
89
90 onYChanged: {
91 if (currentPage !== null) {
92 if (y <= currentPage.height - height) {
93 shown = true
94 } else {
95 shown = false
96 }
97 }
98 }
99
100 Behavior on y {
101 // don't animate if the bottomedge is being dragged
102 enabled: !currentPage.floating
103 UbuntuNumberAnimation {
104 }
105 }
53106
54 Connections {107 Connections {
55 id: pageStackConn108 id: pageStackConn
@@ -59,14 +112,27 @@
59 previousPage = currentPage;112 previousPage = currentPage;
60113
61 // If going back from nowPlaying jump back to tabs114 // If going back from nowPlaying jump back to tabs
62 if (previousPage === nowPlaying && mainPageStack.currentPage !== nowPlaying) {115 if (isNowPlaying(previousPage) && !isNowPlaying(mainPageStack.currentPage)) {
116 tabs.selectedTab.page.forceExpandedStateNoAnimation() // ensure main tab bottom edge state will animate
117
63 while (mainPageStack.depth > 1) {118 while (mainPageStack.depth > 1) {
64 mainPageStack.pop(mainPageStack.currentPage)119 mainPageStack.currentPage.bottomEdgeState = "collapsed" // ensure bottom edge state is reset
120 mainPageStack.pop()
65 }121 }
66 }122 }
67 }123 }
68 }124 }
69125
126 Connections {
127 target: mainView
128 onWideAspectChanged: {
129 // Force toolbar to show if in wideAspect
130 if (wideAspect && !shown) {
131 showToolbar();
132 }
133 }
134 }
135
70 /* Helper functions */136 /* Helper functions */
71137
72 // Disable the toolbar for this page/view (eg a dialog)138 // Disable the toolbar for this page/view (eg a dialog)
@@ -103,10 +169,15 @@
103 function hideToolbar()169 function hideToolbar()
104 {170 {
105 if (!wideAspect) {171 if (!wideAspect) {
106 musicToolbarPanel.close();172 y = currentPage.height
107 }173 }
108174
109 toolbarAutoHideTimer.stop(); // cancel any autohide175 stopAutoHideTimer(); // cancel any autohide
176 }
177
178 // Return true if the page is now playing
179 function isNowPlaying(page) {
180 return page === nowPlaying
110 }181 }
111182
112 // Remove sheet as it has been closed183 // Remove sheet as it has been closed
@@ -135,161 +206,132 @@
135 // Show the toolbar206 // Show the toolbar
136 function showToolbar()207 function showToolbar()
137 {208 {
138 startAutohideTimer(); // always attempt to autohide toolbar209 startAutoHideTimer(); // always attempt to autohide toolbar
139210
140 if (!musicToolbarPanel.opened) {211 y = currentPage.height - height
141 musicToolbarPanel.open();
142 }
143 }212 }
144213
145 // Start the autohidetimer214 // Start the autohidetimer
146 function startAutohideTimer()215 function startAutoHideTimer()
147 {216 {
148 toolbarAutoHideTimer.restart();217 toolbarAutoHideTimer.restart();
149 }218 }
150219
151 Connections {220 function stopAutoHideTimer()
152 target: mainView221 {
153 onWideAspectChanged: {222 toolbarAutoHideTimer.stop()
154 // Force toolbar to show if in wideAspect
155 if (wideAspect && !opened) {
156 showToolbar();
157 }
158 }
159 }223 }
160224
161 Panel {225 /* Full toolbar */
162 id: musicToolbarPanel226 Rectangle {
227 id: musicToolbarFullContainer
163 anchors {228 anchors {
164 left: parent.left229 fill: parent
165 right: parent.right230 }
166 bottom: parent.bottom231 color: styleMusic.toolbar.fullBackgroundColor
167 }232 visible: musicToolbarPanel.currentMode === "full"
168 height: currentMode === "full" ? fullHeight : expandedHeight233
169 locked: wideAspect234 /* Buttons component */
170
171 __closeOnContentsClicks: false // TODO: fix bug 1295720
172
173 // The current mode of the controls
174 property string currentMode: wideAspect || (currentPage === nowPlaying)
175 ? "full" : "expanded"
176
177 // Properties for the different heights
178 property int minimizedHeight: units.gu(0.5)
179 property int expandedHeight: units.gu(8)
180 property int fullHeight: units.gu(11)
181
182 onCurrentModeChanged: {
183 musicToolbarFullProgressMouseArea.enabled = currentMode === "full"
184 }
185
186 onOpenedChanged: {
187 onToolbarShownChanged(opened, currentPage, currentTab);
188
189 if (opened) {
190 startAutohideTimer();
191 }
192 }
193
194 /* Full toolbar */
195 Rectangle {235 Rectangle {
196 id: musicToolbarFullContainer236 id: musicToolbarFullButtonsContainer
197 anchors {237 anchors.left: parent.left
198 fill: parent238 anchors.top: musicToolbarFullProgressContainer.bottom
199 }239 color: "transparent"
200 color: styleMusic.toolbar.fullBackgroundColor240 height: parent.height - musicToolbarFullProgressContainer.height
201 visible: musicToolbarPanel.currentMode === "full"241 width: parent.width
202242
203 /* Buttons component */243 /* Column for labels in wideAspect */
204 Rectangle {244 Column {
205 id: musicToolbarFullButtonsContainer245 id: nowPlayingWideAspectLabels
206 anchors.left: parent.left246 anchors {
207 anchors.top: musicToolbarFullProgressContainer.bottom247 left: parent.left
208 color: "transparent"248 leftMargin: units.gu(1)
209 height: parent.height - musicToolbarFullProgressContainer.height249 right: nowPlayingRepeatButton.left
210 width: parent.width250 rightMargin: units.gu(1)
211251 }
212 /* Column for labels in wideAspect */252 visible: wideAspect
213 Column {253
214 id: nowPlayingWideAspectLabels254 /* Title of track */
215 anchors {255 Label {
216 left: parent.left256 id: nowPlayingWideAspectTitle
217 leftMargin: units.gu(1)257 anchors {
218 right: nowPlayingRepeatButton.left258 left: parent.left
219 rightMargin: units.gu(1)259 leftMargin: units.gu(1)
220 verticalCenter: parent.verticalCenter260 right: parent.right
221 }261 rightMargin: units.gu(1)
222 visible: wideAspect262 }
223263 color: styleMusic.playerControls.labelColor
224 /* Clicking in the area shows the queue */264 elide: Text.ElideRight
225 function trigger() {265 fontSize: "medium"
226 if (trackQueue.model.count !== 0 && currentPage !== nowPlaying) {266 objectName: "playercontroltitle"
227 tabs.pushNowPlaying();267 text: player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle
228 }268 }
229 else if (currentPage === nowPlaying) {269
230 musicToolbar.goBack();270 /* Artist of track */
231 }271 Label {
232 }272 id: nowPlayingWideAspectArtist
233273 anchors {
234 /* Title of track */274 left: parent.left
235 Label {275 leftMargin: units.gu(1)
236 id: nowPlayingWideAspectTitle276 right: parent.right
237 anchors {277 rightMargin: units.gu(1)
238 left: parent.left278 }
239 leftMargin: units.gu(1)279 color: styleMusic.playerControls.labelColor
240 right: parent.right280 elide: Text.ElideRight
241 rightMargin: units.gu(1)281 fontSize: "small"
242 }282 text: player.currentMetaArtist
243 color: styleMusic.playerControls.labelColor283 }
244 elide: Text.ElideRight284
245 fontSize: "medium"285 /* Album of track */
246 objectName: "playercontroltitle"286 Label {
247 text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle287 id: nowPlayingWideAspectAlbum
248 }288 anchors {
249289 left: parent.left
250 /* Artist of track */290 leftMargin: units.gu(1)
251 Label {291 right: parent.right
252 id: nowPlayingWideAspectArtist292 rightMargin: units.gu(1)
253 anchors {293 }
254 left: parent.left294 color: styleMusic.playerControls.labelColor
255 leftMargin: units.gu(1)295 elide: Text.ElideRight
256 right: parent.right296 fontSize: "small"
257 rightMargin: units.gu(1)297 text: player.currentMetaAlbum
258 }298 }
259 color: styleMusic.playerControls.labelColor299 }
260 elide: Text.ElideRight300
261 fontSize: "small"301 /* Clicking in the area shows the queue */
262 text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist302 MouseArea {
263 }303 anchors {
264304 bottom: parent.bottom
265 /* Album of track */305 left: parent.left
266 Label {306 right: nowPlayingRepeatButton.left
267 id: nowPlayingWideAspectAlbum307 top: parent.top
268 anchors {308 }
269 left: parent.left309 onClicked: {
270 leftMargin: units.gu(1)310 if (trackQueue.model.count !== 0 && currentPage !== nowPlaying) {
271 right: parent.right311 tabs.pushNowPlaying();
272 rightMargin: units.gu(1)312 }
273 }313 else if (currentPage === nowPlaying) {
274 color: styleMusic.playerControls.labelColor314 musicToolbar.goBack();
275 elide: Text.ElideRight315 }
276 fontSize: "small"316 }
277 text: trackQueue.model.count === 0 ? "" : player.currentMetaAlbum317 }
278 }318
279 }319 /* Repeat button */
280320 Item {
281 /* Repeat button */321 id: nowPlayingRepeatButton
282 Item {322 objectName: "repeatShape"
283 id: nowPlayingRepeatButton323 anchors.right: nowPlayingPreviousButton.left
284 objectName: "repeatShape"324 anchors.rightMargin: units.gu(1)
285 anchors.right: nowPlayingPreviousButton.left325 anchors.verticalCenter: parent.verticalCenter
286 anchors.rightMargin: units.gu(1)326 height: units.gu(6)
287 anchors.verticalCenter: parent.verticalCenter327 opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
288 height: units.gu(6)328 width: height
289 opacity: player.repeat && !emptyPage.noMusic ? 1 : .4329
290 width: height330 MouseArea {
291331 anchors {
292 function trigger() {332 fill: parent
333 }
334 onClicked: {
293 if (emptyPage.noMusic) {335 if (emptyPage.noMusic) {
294 return;336 return;
295 }337 }
@@ -297,114 +339,124 @@
297 // Invert repeat settings339 // Invert repeat settings
298 player.repeat = !player.repeat340 player.repeat = !player.repeat
299 }341 }
300
301 Image {
302 id: repeatIcon
303 height: units.gu(3)
304 width: height
305 anchors.verticalCenter: parent.verticalCenter
306 anchors.horizontalCenter: parent.horizontalCenter
307 source: Qt.resolvedUrl("images/media-playlist-repeat.svg")
308 verticalAlignment: Text.AlignVCenter
309 opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
310 }
311 }342 }
312343
313 /* Previous button */344 Image {
314 Item {345 id: repeatIcon
315 id: nowPlayingPreviousButton346 height: units.gu(3)
316 anchors.right: nowPlayingPlayButton.left347 width: height
317 anchors.rightMargin: units.gu(1)
318 anchors.verticalCenter: parent.verticalCenter348 anchors.verticalCenter: parent.verticalCenter
319 height: units.gu(6)349 anchors.horizontalCenter: parent.horizontalCenter
320 objectName: "previousshape"350 source: Qt.resolvedUrl("images/media-playlist-repeat.svg")
321 opacity: trackQueue.model.count === 0 ? .4 : 1351 verticalAlignment: Text.AlignVCenter
322 width: height352 opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
323353 }
324 function trigger() {354 }
355
356 /* Previous button */
357 Item {
358 id: nowPlayingPreviousButton
359 anchors.right: nowPlayingPlayButton.left
360 anchors.rightMargin: units.gu(1)
361 anchors.verticalCenter: parent.verticalCenter
362 height: units.gu(6)
363 objectName: "previousshape"
364 opacity: trackQueue.model.count === 0 ? .4 : 1
365 width: height
366
367 MouseArea {
368 anchors {
369 fill: parent
370 }
371 onClicked: {
325 if (trackQueue.model.count === 0) {372 if (trackQueue.model.count === 0) {
326 return;373 return;
327 }374 }
328375
329 player.previousSong()376 player.previousSong()
330 }377 }
331
332 Image {
333 id: nowPlayingPreviousIndicator
334 height: units.gu(3)
335 width: height
336 anchors.horizontalCenter: parent.horizontalCenter
337 anchors.verticalCenter: parent.verticalCenter
338 source: Qt.resolvedUrl("images/media-skip-backward.svg")
339 opacity: 1
340 }
341 }378 }
342379
343 /* Play/Pause button */380 Image {
344 Rectangle {381 id: nowPlayingPreviousIndicator
345 id: nowPlayingPlayButton382 height: units.gu(3)
383 width: height
346 anchors.horizontalCenter: parent.horizontalCenter384 anchors.horizontalCenter: parent.horizontalCenter
347 anchors.verticalCenter: parent.verticalCenter385 anchors.verticalCenter: parent.verticalCenter
386 source: Qt.resolvedUrl("images/media-skip-backward.svg")
387 opacity: 1
388 }
389 }
390
391 /* Play/Pause button */
392 Rectangle {
393 id: nowPlayingPlayButton
394 anchors.horizontalCenter: parent.horizontalCenter
395 anchors.verticalCenter: parent.verticalCenter
396 antialiasing: true
397 color: styleMusic.toolbar.fullOuterPlayCircleColor
398 height: units.gu(12)
399 radius: height / 2
400 width: height
401
402 // draws the outter shadow/highlight
403 Rectangle {
404 id: sourceOutterFull
405 anchors { fill: parent; margins: -units.gu(0.1) }
406 radius: (width / 2)
348 antialiasing: true407 antialiasing: true
349 color: styleMusic.toolbar.fullOuterPlayCircleColor408 gradient: Gradient {
350 height: units.gu(12)409 GradientStop { position: 0.0; color: "black" }
351 radius: height / 2410 GradientStop { position: 0.5; color: "transparent" }
352 width: height411 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
412 }
353413
354 // draws the outter shadow/highlight
355 Rectangle {414 Rectangle {
356 id: sourceOutterFull415 anchors.horizontalCenter: parent.horizontalCenter
357 anchors { fill: parent; margins: -units.gu(0.1) }416 anchors.verticalCenter: parent.verticalCenter
358 radius: (width / 2)
359 antialiasing: true417 antialiasing: true
360 gradient: Gradient {418 color: styleMusic.toolbar.fullOuterPlayCircleColor
361 GradientStop { position: 0.0; color: "black" }419 height: nowPlayingPlayButton.height - units.gu(.1)
362 GradientStop { position: 0.5; color: "transparent" }420 radius: height / 2
363 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }421 width: height
364 }
365422
366 Rectangle {423 Rectangle {
424 id: nowPlayingPlayButtonInner
367 anchors.horizontalCenter: parent.horizontalCenter425 anchors.horizontalCenter: parent.horizontalCenter
368 anchors.verticalCenter: parent.verticalCenter426 anchors.verticalCenter: parent.verticalCenter
369 antialiasing: true427 antialiasing: true
370 color: styleMusic.toolbar.fullOuterPlayCircleColor428 color: styleMusic.toolbar.fullInnerPlayCircleColor
371 height: nowPlayingPlayButton.height - units.gu(.1)429 height: units.gu(7)
372 radius: height / 2430 radius: height / 2
373 width: height431 width: height
374432
433 // draws the inner shadow/highlight
375 Rectangle {434 Rectangle {
376 id: nowPlayingPlayButtonInner435 id: sourceInnerFull
377 anchors.horizontalCenter: parent.horizontalCenter436 anchors { fill: parent; margins: -units.gu(0.1) }
378 anchors.verticalCenter: parent.verticalCenter437 radius: (width / 2)
379 antialiasing: true438 antialiasing: true
380 color: styleMusic.toolbar.fullInnerPlayCircleColor439 gradient: Gradient {
381 height: units.gu(7)440 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
382 radius: height / 2441 GradientStop { position: 0.5; color: "transparent" }
383 width: height442 GradientStop { position: 1.0; color: "black" }
443 }
384444
385 // draws the inner shadow/highlight
386 Rectangle {445 Rectangle {
387 id: sourceInnerFull446 anchors.horizontalCenter: parent.horizontalCenter
388 anchors { fill: parent; margins: -units.gu(0.1) }447 anchors.verticalCenter: parent.verticalCenter
389 radius: (width / 2)
390 antialiasing: true448 antialiasing: true
391 gradient: Gradient {449 color: styleMusic.toolbar.fullInnerPlayCircleColor
392 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }450 height: nowPlayingPlayButtonInner.height - units.gu(.1)
393 GradientStop { position: 0.5; color: "transparent" }451 objectName: "nowPlayingPlayShape"
394 GradientStop { position: 1.0; color: "black" }452 radius: height / 2
395 }453 width: height
396454
397 Rectangle {455 MouseArea {
398 anchors.horizontalCenter: parent.horizontalCenter456 anchors {
399 anchors.verticalCenter: parent.verticalCenter457 fill: parent
400 antialiasing: true458 }
401 color: styleMusic.toolbar.fullInnerPlayCircleColor459 onClicked: {
402 height: nowPlayingPlayButtonInner.height - units.gu(.1)
403 objectName: "nowPlayingPlayShape"
404 radius: height / 2
405 width: height
406
407 function trigger() {
408 if (emptyPage.noMusic) {460 if (emptyPage.noMusic) {
409 return;461 return;
410 }462 }
@@ -416,66 +468,76 @@
416 player.toggle();468 player.toggle();
417 }469 }
418 }470 }
471 }
419472
420 Image {473 Image {
421 id: nowPlayingPlayIndicator474 id: nowPlayingPlayIndicator
422 height: units.gu(6)475 height: units.gu(6)
423 width: height476 width: height
424 anchors.horizontalCenter: parent.horizontalCenter477 anchors.horizontalCenter: parent.horizontalCenter
425 anchors.verticalCenter: parent.verticalCenter478 anchors.verticalCenter: parent.verticalCenter
426 opacity: emptyPage.noMusic ? .4 : 1479 opacity: emptyPage.noMusic ? .4 : 1
427 source: player.playbackState === MediaPlayer.PlayingState ?480 source: player.playbackState === MediaPlayer.PlayingState ?
428 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")481 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
429 }
430 }482 }
431 }483 }
432 }484 }
433 }485 }
434 }486 }
435 }487 }
436488 }
437 /* Next button */489
438 Item {490 /* Next button */
439 id: nowPlayingNextButton491 Item {
440 anchors.left: nowPlayingPlayButton.right492 id: nowPlayingNextButton
441 anchors.leftMargin: units.gu(1)493 anchors.left: nowPlayingPlayButton.right
442 anchors.verticalCenter: parent.verticalCenter494 anchors.leftMargin: units.gu(1)
443 height: units.gu(6)495 anchors.verticalCenter: parent.verticalCenter
444 objectName: "forwardshape"496 height: units.gu(6)
445 opacity: trackQueue.model.count === 0 ? .4 : 1497 objectName: "forwardshape"
446 width: height498 opacity: trackQueue.model.count === 0 ? .4 : 1
447499 width: height
448 function trigger() {500
501 MouseArea {
502 anchors {
503 fill: parent
504 }
505 onClicked: {
449 if (trackQueue.model.count === 0 || emptyPage.noMusic) {506 if (trackQueue.model.count === 0 || emptyPage.noMusic) {
450 return;507 return;
451 }508 }
452509
453 player.nextSong()510 player.nextSong()
454 }511 }
455
456 Image {
457 id: nowPlayingNextIndicator
458 height: units.gu(3)
459 width: height
460 anchors.horizontalCenter: parent.horizontalCenter
461 anchors.verticalCenter: parent.verticalCenter
462 source: Qt.resolvedUrl("images/media-skip-forward.svg")
463 opacity: 1
464 }
465 }512 }
466513
467 /* Shuffle button */514 Image {
468 Item {515 id: nowPlayingNextIndicator
469 id: nowPlayingShuffleButton516 height: units.gu(3)
470 objectName: "shuffleShape"517 width: height
471 anchors.left: nowPlayingNextButton.right518 anchors.horizontalCenter: parent.horizontalCenter
472 anchors.leftMargin: units.gu(1)
473 anchors.verticalCenter: parent.verticalCenter519 anchors.verticalCenter: parent.verticalCenter
474 height: units.gu(6)520 source: Qt.resolvedUrl("images/media-skip-forward.svg")
475 opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4521 opacity: 1
476 width: height522 }
477523 }
478 function trigger() {524
525 /* Shuffle button */
526 Item {
527 id: nowPlayingShuffleButton
528 objectName: "shuffleShape"
529 anchors.left: nowPlayingNextButton.right
530 anchors.leftMargin: units.gu(1)
531 anchors.verticalCenter: parent.verticalCenter
532 height: units.gu(6)
533 opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
534 width: height
535
536 MouseArea {
537 anchors {
538 fill: parent
539 }
540 onClicked: {
479 if (emptyPage.noMusic) {541 if (emptyPage.noMusic) {
480 return;542 return;
481 }543 }
@@ -483,33 +545,38 @@
483 // Invert shuffle settings545 // Invert shuffle settings
484 player.shuffle = !player.shuffle546 player.shuffle = !player.shuffle
485 }547 }
486548 }
487 Image {549
488 id: shuffleIcon550 Image {
489 height: units.gu(3)551 id: shuffleIcon
490 width: height552 height: units.gu(3)
491 anchors.verticalCenter: parent.verticalCenter553 width: height
492 anchors.horizontalCenter: parent.horizontalCenter554 anchors.verticalCenter: parent.verticalCenter
493 source: Qt.resolvedUrl("images/media-playlist-shuffle.svg")555 anchors.horizontalCenter: parent.horizontalCenter
494 opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4556 source: Qt.resolvedUrl("images/media-playlist-shuffle.svg")
495 }557 opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
496 }558 }
497559 }
498 /* Search button in wideAspect */560
499 Item {561 /* Search button in wideAspect */
500 id: nowPlayingSearchButton562 Item {
501 objectName: "searchShape"563 id: nowPlayingSearchButton
564 objectName: "searchShape"
565 anchors {
566 right: parent.right
567 rightMargin: units.gu(1)
568 verticalCenter: parent.verticalCenter
569 }
570 height: units.gu(6)
571 opacity: !emptyPage.noMusic ? 1 : .4
572 width: height
573 visible: wideAspect
574
575 MouseArea {
502 anchors {576 anchors {
503 right: parent.right577 fill: parent
504 rightMargin: units.gu(1)
505 verticalCenter: parent.verticalCenter
506 }578 }
507 height: units.gu(6)579 onClicked: {
508 opacity: !emptyPage.noMusic ? 1 : .4
509 width: height
510 visible: wideAspect
511
512 function trigger() {
513 if (emptyPage.noMusic) {580 if (emptyPage.noMusic) {
514 return;581 return;
515 }582 }
@@ -519,620 +586,690 @@
519 mainView, { title: i18n.tr("Search")} )586 mainView, { title: i18n.tr("Search")} )
520 }587 }
521 }588 }
589 }
522590
523 Image {591 Image {
524 id: searchIcon592 id: searchIcon
525 anchors {593 anchors {
526 horizontalCenter: parent.horizontalCenter594 horizontalCenter: parent.horizontalCenter
527 verticalCenter: parent.verticalCenter595 verticalCenter: parent.verticalCenter
528 }
529 height: units.gu(3)
530 opacity: !emptyPage.noMusic ? 1 : .4
531 source: Qt.resolvedUrl("images/search.svg")
532 width: height
533 }596 }
597 height: units.gu(3)
598 opacity: !emptyPage.noMusic ? 1 : .4
599 source: Qt.resolvedUrl("images/search.svg")
600 width: height
534 }601 }
535 }602 }
536603 }
537 /* Progress bar component */604
538 Rectangle {605 /* Progress bar component */
539 id: musicToolbarFullProgressContainer606 Rectangle {
607 id: musicToolbarFullProgressContainer
608 anchors.left: parent.left
609 anchors.top: parent.top
610 color: styleMusic.toolbar.fullBackgroundColor
611 height: units.gu(3)
612 width: parent.width
613
614 /* Position label */
615 Label {
616 id: musicToolbarFullPositionLabel
540 anchors.left: parent.left617 anchors.left: parent.left
618 anchors.leftMargin: units.gu(2)
541 anchors.top: parent.top619 anchors.top: parent.top
542 color: styleMusic.toolbar.fullBackgroundColor620 color: styleMusic.nowPlaying.labelColor
543 height: units.gu(3)621 fontSize: "x-small"
544 width: parent.width622 height: parent.height
545623 horizontalAlignment: Text.AlignHCenter
546 /* Position label */624 text: durationToString(player.position)
547 Label {625 verticalAlignment: Text.AlignVCenter
548 id: musicToolbarFullPositionLabel626 width: units.gu(3)
549 anchors.left: parent.left627 }
550 anchors.leftMargin: units.gu(2)628
551 anchors.top: parent.top629 /* Progress bar */
552 color: styleMusic.nowPlaying.labelColor
553 fontSize: "x-small"
554 height: parent.height
555 horizontalAlignment: Text.AlignHCenter
556 text: durationToString(player.position)
557 verticalAlignment: Text.AlignVCenter
558 width: units.gu(3)
559 }
560
561 /* Progress bar */
562 Rectangle {
563 id: musicToolbarFullProgressBarContainer
564 objectName: "progressBarShape"
565 anchors.left: musicToolbarFullPositionLabel.right
566 anchors.leftMargin: units.gu(2)
567 anchors.right: musicToolbarFullDurationLabel.left
568 anchors.rightMargin: units.gu(2)
569 anchors.verticalCenter: parent.verticalCenter
570 color: "transparent"
571 height: units.gu(1);
572 state: trackQueue.model.count === 0 ? "disabled" : "enabled"
573
574 states: [
575 State {
576 name: "disabled"
577 PropertyChanges {
578 target: musicToolbarFullProgressMouseArea
579 enabled: false
580 }
581 PropertyChanges {
582 target: musicToolbarFullProgressTrough
583 visible: false
584 }
585 PropertyChanges {
586 target: musicToolbarFullProgressHandle
587 visible: false
588 }
589 },
590 State {
591 name: "enabled"
592 PropertyChanges {
593 target: musicToolbarFullProgressMouseArea
594 enabled: true
595 }
596 PropertyChanges {
597 target: musicToolbarFullProgressTrough
598 visible: true
599 }
600 PropertyChanges {
601 target: musicToolbarFullProgressHandle
602 visible: true
603 }
604 }
605 ]
606
607 property bool seeking: false
608
609 onSeekingChanged: {
610 if (seeking === false) {
611 musicToolbarFullPositionLabel.text = durationToString(player.position)
612 }
613 }
614
615 Connections {
616 target: player
617 onDurationChanged: {
618 console.debug("Duration changed: " + player.duration)
619 musicToolbarFullDurationLabel.text = durationToString(player.duration)
620 }
621 onPositionChanged: {
622 if (musicToolbarFullProgressBarContainer.seeking === false)
623 {
624 musicToolbarFullPositionLabel.text = durationToString(player.position)
625 musicToolbarFullDurationLabel.text = durationToString(player.duration)
626 musicToolbarFullProgressHandle.x = (player.position / player.duration) * musicToolbarFullProgressBarContainer.width
627 - musicToolbarFullProgressHandle.width / 2;
628 }
629 }
630 onStopped: {
631 musicToolbarFullProgressHandle.x = -musicToolbarFullProgressHandle.width / 2;
632
633 musicToolbarFullPositionLabel.text = durationToString(0);
634 musicToolbarFullDurationLabel.text = durationToString(0);
635 }
636 }
637
638 // Black background behind the progress bar
639 Rectangle {
640 id: musicToolbarFullProgressBackground
641 anchors.verticalCenter: parent.verticalCenter;
642 color: styleMusic.toolbar.fullProgressBackgroundColor;
643 height: parent.height;
644 radius: units.gu(0.5)
645 width: parent.width;
646 }
647
648 // The orange fill of the progress bar
649 Rectangle {
650 id: musicToolbarFullProgressTrough
651 anchors.verticalCenter: parent.verticalCenter;
652 antialiasing: true
653 color: styleMusic.toolbar.fullProgressTroughColor;
654 height: parent.height;
655 radius: units.gu(0.5)
656 width: musicToolbarFullProgressHandle.x + (height / 2); // +radius
657 }
658
659 // The current position (handle) of the progress bar
660 Rectangle {
661 id: musicToolbarFullProgressHandle
662 anchors.verticalCenter: musicToolbarFullProgressBackground.verticalCenter
663 antialiasing: true
664 color: styleMusic.nowPlaying.progressHandleColor
665 height: units.gu(1.5)
666 radius: height / 2
667 width: height
668
669 // On X change update the position string
670 onXChanged: {
671 if (musicToolbarFullProgressBarContainer.seeking) {
672 var fraction = (x + (width / 2)) / parent.width;
673 musicToolbarFullPositionLabel.text = durationToString(fraction * player.duration)
674 }
675 }
676 }
677 }
678
679 /* Duration label */
680 Label {
681 id: musicToolbarFullDurationLabel
682 anchors.right: parent.right
683 anchors.rightMargin: units.gu(2)
684 anchors.top: parent.top
685 color: styleMusic.nowPlaying.labelColor
686 fontSize: "x-small"
687 height: parent.height
688 horizontalAlignment: Text.AlignHCenter
689 text: durationToString(player.duration)
690 verticalAlignment: Text.AlignVCenter
691 width: units.gu(3)
692 }
693
694 /* Border at the bottom */
695 Rectangle {
696 anchors.bottom: parent.bottom
697 anchors.left: parent.left
698 anchors.right: parent.right
699 color: styleMusic.common.white
700 height: units.gu(0.1)
701 opacity: 0.1
702 }
703 }
704 }
705
706 /* Expanded toolbar */
707 Rectangle {
708 id: musicToolbarExpandedContainer
709 anchors {
710 fill: parent
711 }
712 color: "transparent"
713 visible: musicToolbarPanel.currentMode === "expanded"
714
715 Rectangle {630 Rectangle {
716 id: musicToolbarPlayerControls631 id: musicToolbarFullProgressBarContainer
717 anchors.fill: parent632 objectName: "progressBarShape"
718 color: styleMusic.playerControls.backgroundColor633 anchors.left: musicToolbarFullPositionLabel.right
634 anchors.leftMargin: units.gu(2)
635 anchors.right: musicToolbarFullDurationLabel.left
636 anchors.rightMargin: units.gu(2)
637 anchors.verticalCenter: parent.verticalCenter
638 color: "transparent"
639 height: units.gu(1);
719 state: trackQueue.model.count === 0 ? "disabled" : "enabled"640 state: trackQueue.model.count === 0 ? "disabled" : "enabled"
641
720 states: [642 states: [
721 State {643 State {
722 name: "disabled"644 name: "disabled"
723 PropertyChanges {645 PropertyChanges {
724 target: disabledPlayerControlsGroup646 target: musicToolbarFullProgressMouseArea
725 visible: true647 enabled: false
726 }648 }
727 PropertyChanges {649 PropertyChanges {
728 target: enabledPlayerControlsGroup650 target: musicToolbarFullProgressTrough
651 visible: false
652 }
653 PropertyChanges {
654 target: musicToolbarFullProgressHandle
729 visible: false655 visible: false
730 }656 }
731 },657 },
732 State {658 State {
733 name: "enabled"659 name: "enabled"
734 PropertyChanges {660 PropertyChanges {
735 target: disabledPlayerControlsGroup661 target: musicToolbarFullProgressMouseArea
736 visible: false662 enabled: true
737 }663 }
738 PropertyChanges {664 PropertyChanges {
739 target: enabledPlayerControlsGroup665 target: musicToolbarFullProgressTrough
666 visible: true
667 }
668 PropertyChanges {
669 target: musicToolbarFullProgressHandle
740 visible: true670 visible: true
741 }671 }
742 }672 }
743 ]673 ]
744674
745 Rectangle {675 property bool seeking: false
746 id: disabledPlayerControlsGroup676
747 anchors.fill: parent677 onSeekingChanged: {
748 color: "transparent"678 if (seeking === false) {
749 visible: trackQueue.model.count === 0679 musicToolbarFullPositionLabel.text = durationToString(player.position)
750680 }
751 Label {681 }
752 id: noSongsInQueueLabel
753 anchors {
754 left: parent.left
755 right: disabledPlayerControlsPlayButton.left
756 margins: units.gu(1)
757 top: parent.top
758 }
759 color: styleMusic.playerControls.labelColor
760 text: i18n.tr("Tap play to shuffle music")
761 fontSize: "large"
762 wrapMode: Text.WordWrap
763 maximumLineCount: 2
764 }
765
766 Rectangle {
767 id: disabledPlayerControlsPlayButton
768 anchors.right: parent.right
769 anchors.rightMargin: units.gu(1)
770 anchors.verticalCenter: parent.verticalCenter
771 antialiasing: true
772 color: "#444"
773 height: units.gu(7)
774 radius: height / 2
775 width: height
776
777 function trigger() {
778 if (emptyPage.noMusic) {
779 return;
780 }
781
782 if (trackQueue.model.count === 0) {
783 playRandomSong();
784 }
785 else {
786 player.toggle();
787 }
788 }
789
790 // draws the outer shadow/highlight
791 Rectangle {
792 id: disabledSourceOutter
793 anchors { fill: parent; margins: -units.gu(0.1) }
794 radius: (width / 2)
795 antialiasing: true
796 gradient: Gradient {
797 GradientStop { position: 0.0; color: "black" }
798 GradientStop { position: 0.5; color: "transparent" }
799 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
800 }
801
802 Rectangle {
803 anchors.verticalCenter: parent.verticalCenter
804 anchors.horizontalCenter: parent.horizontalCenter
805 antialiasing: true
806 color: "#444"
807 height: playerControlsPlayButton.height - units.gu(.1)
808 radius: height / 2
809 width: height
810
811 Rectangle {
812 id: disabledPlayerControlsPlayInnerCircle
813 anchors.horizontalCenter: parent.horizontalCenter
814 anchors.verticalCenter: parent.verticalCenter
815 antialiasing: true
816 height: units.gu(4.5)
817 radius: height / 2
818 width: height
819 color: styleMusic.toolbar.fullInnerPlayCircleColor
820
821 // draws the inner shadow/highlight
822 Rectangle {
823 id: disabledSourceInner
824 anchors { fill: parent; margins: -units.gu(0.1) }
825 radius: (width / 2)
826 antialiasing: true
827 gradient: Gradient {
828 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
829 GradientStop { position: 0.5; color: "transparent" }
830 GradientStop { position: 1.0; color: "black" }
831 }
832
833 Rectangle {
834 anchors.verticalCenter: parent.verticalCenter
835 anchors.horizontalCenter: parent.horizontalCenter
836 antialiasing: true
837 height: playerControlsPlayInnerCircle.height - units.gu(.1)
838 radius: height / 2
839 width: height
840 color: styleMusic.toolbar.fullInnerPlayCircleColor
841
842 Image {
843 id: disabledPlayIndicator
844 height: units.gu(4)
845 width: height
846 anchors.horizontalCenter: parent.horizontalCenter
847 anchors.verticalCenter: parent.verticalCenter
848 opacity: emptyPage.noMusic ? .4 : 1
849 source: player.playbackState === MediaPlayer.PlayingState ?
850 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
851 }
852 }
853 }
854 }
855 }
856 }
857 }
858 }
859
860 Rectangle {
861 id: enabledPlayerControlsGroup
862 anchors.fill: parent
863 color: "transparent"
864 visible: trackQueue.model.count !== 0
865
866 /* Settings button */
867 // TODO: Enable settings when it is practical
868 /* Rectangle {
869 id: playerControlsSettings
870 anchors.right: parent.right
871 anchors.verticalCenter: parent.verticalCenter
872 width: units.gu(6)
873 height: width
874 color: "transparent"
875
876 Image {
877 anchors.horizontalCenter: parent.horizontalCenter
878 anchors.verticalCenter: parent.verticalCenter
879 height: units.gu(3)
880 source: Qt.resolvedUrl("images/settings.png")
881 width: height
882 }
883
884 MouseArea {
885 anchors.fill: parent
886 onClicked: {
887 console.debug('Debug: Show settings')
888 PopupUtils.open(Qt.resolvedUrl("MusicSettings.qml"), mainView,
889 {
890 title: i18n.tr("Settings")
891 } )
892 }
893 }
894 } */
895
896 /* Play/Pause button TODO: image and colours needs updating */
897 Rectangle {
898 id: playerControlsPlayButton
899 anchors.right: parent.right
900 anchors.rightMargin: units.gu(1)
901 anchors.verticalCenter: parent.verticalCenter
902 antialiasing: true
903 color: "#444"
904 height: units.gu(7)
905 objectName: "playshape"
906 radius: height / 2
907 width: height
908
909 function trigger() {
910 if (emptyPage.noMusic) {
911 return;
912 }
913
914 if (trackQueue.model.count === 0) {
915 playRandomSong();
916 }
917 else {
918 player.toggle();
919 }
920 }
921
922 // draws the outer shadow/highlight
923 Rectangle {
924 id: sourceOutter
925 anchors { fill: parent; margins: -units.gu(0.1) }
926 radius: (width / 2)
927 antialiasing: true
928 gradient: Gradient {
929 GradientStop { position: 0.0; color: "black" }
930 GradientStop { position: 0.5; color: "transparent" }
931 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
932 }
933
934 Rectangle {
935 anchors.verticalCenter: parent.verticalCenter
936 anchors.horizontalCenter: parent.horizontalCenter
937 antialiasing: true
938 color: "#444"
939 height: playerControlsPlayButton.height - units.gu(.1)
940 radius: height / 2
941 width: height
942
943 Rectangle {
944 id: playerControlsPlayInnerCircle
945 anchors.horizontalCenter: parent.horizontalCenter
946 anchors.verticalCenter: parent.verticalCenter
947 antialiasing: true
948 height: units.gu(4.5)
949 radius: height / 2
950 width: height
951 color: styleMusic.toolbar.fullInnerPlayCircleColor
952
953 // draws the inner shadow/highlight
954 Rectangle {
955 id: sourceInner
956 anchors { fill: parent; margins: -units.gu(0.1) }
957 radius: (width / 2)
958 antialiasing: true
959 gradient: Gradient {
960 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
961 GradientStop { position: 0.5; color: "transparent" }
962 GradientStop { position: 1.0; color: "black" }
963 }
964
965 Rectangle {
966 anchors.verticalCenter: parent.verticalCenter
967 anchors.horizontalCenter: parent.horizontalCenter
968 antialiasing: true
969 height: playerControlsPlayInnerCircle.height - units.gu(.1)
970 radius: height / 2
971 width: height
972 color: styleMusic.toolbar.fullInnerPlayCircleColor
973
974 Image {
975 id: playindicator
976 height: units.gu(4)
977 width: height
978 anchors.horizontalCenter: parent.horizontalCenter
979 anchors.verticalCenter: parent.verticalCenter
980 opacity: emptyPage.noMusic ? .4 : 1
981 source: player.playbackState === MediaPlayer.PlayingState ?
982 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
983 }
984 }
985 }
986 }
987 }
988 }
989 }
990
991 /* Container holding the labels for the toolbar */
992 Rectangle {
993 id: playerControlLabelContainer
994 anchors.bottom: parent.bottom
995 anchors.left: parent.left
996 anchors.right: playerControlsPlayButton.left
997 anchors.top: parent.top
998 color: "transparent"
999
1000 /* Title of track */
1001 Label {
1002 id: playerControlsTitle
1003 anchors.left: parent.left
1004 anchors.leftMargin: units.gu(1)
1005 anchors.right: parent.right
1006 anchors.rightMargin: units.gu(1)
1007 anchors.top: parent.top
1008 anchors.topMargin: units.gu(1)
1009 color: styleMusic.playerControls.labelColor
1010 elide: Text.ElideRight
1011 fontSize: "medium"
1012 objectName: "playercontroltitle"
1013 text: player.currentMetaTitle === ""
1014 ? player.source : player.currentMetaTitle
1015 }
1016
1017 /* Artist of track */
1018 Label {
1019 id: playerControlsArtist
1020 anchors.left: parent.left
1021 anchors.leftMargin: units.gu(1)
1022 anchors.right: parent.right
1023 anchors.rightMargin: units.gu(1)
1024 anchors.top: playerControlsTitle.bottom
1025 color: styleMusic.playerControls.labelColor
1026 elide: Text.ElideRight
1027 fontSize: "small"
1028 text: player.currentMetaArtist
1029 }
1030
1031 /* Album of track */
1032 Label {
1033 id: playerControlsAlbum
1034 anchors.left: parent.left
1035 anchors.leftMargin: units.gu(1)
1036 anchors.right: parent.right
1037 anchors.rightMargin: units.gu(1)
1038 anchors.top: playerControlsArtist.bottom
1039 color: styleMusic.playerControls.labelColor
1040 elide: Text.ElideRight
1041 fontSize: "small"
1042 text: player.currentMetaAlbum
1043 }
1044 }
1045
1046 Rectangle {
1047 anchors.fill: playerControlLabelContainer
1048 color: "transparent"
1049 function trigger() {
1050 tabs.pushNowPlaying();
1051 }
1052 }
1053 }
1054 }
1055 }
1056
1057 /* Object which provides the progress bar when toolbar is minimized */
1058 Rectangle {
1059 id: musicToolbarSmallProgressBackground
1060 anchors {
1061 bottom: parent.top
1062 left: parent.left
1063 right: parent.right
1064 }
1065 color: styleMusic.common.black
1066 height: musicToolbarPanel.minimizedHeight
1067 visible: (!musicToolbarPanel.animating &&
1068 !musicToolbarPanel.opened)
1069 || musicToolbarPanel.currentMode == "expanded"
1070
1071 Rectangle {
1072 id: musicToolbarSmallProgressHint
1073 anchors.left: parent.left
1074 anchors.top: parent.top
1075 color: styleMusic.nowPlaying.progressForegroundColor
1076 height: parent.height
1077 width: 0
1078682
1079 Connections {683 Connections {
1080 target: player684 target: player
685 onDurationChanged: {
686 console.debug("Duration changed: " + player.duration)
687 musicToolbarFullDurationLabel.text = durationToString(player.duration)
688 }
1081 onPositionChanged: {689 onPositionChanged: {
1082 musicToolbarSmallProgressHint.width = (player.position / player.duration) * musicToolbarSmallProgressBackground.width690 if (musicToolbarFullProgressBarContainer.seeking === false)
691 {
692 musicToolbarFullPositionLabel.text = durationToString(player.position)
693 musicToolbarFullDurationLabel.text = durationToString(player.duration)
694 musicToolbarFullProgressHandle.x = (player.position / player.duration) * musicToolbarFullProgressBarContainer.width
695 - musicToolbarFullProgressHandle.width / 2;
696 }
1083 }697 }
1084 onStopped: {698 onStopped: {
1085 musicToolbarSmallProgressHint.width = 0;699 musicToolbarFullProgressHandle.x = -musicToolbarFullProgressHandle.width / 2;
1086 }700
1087 }701 musicToolbarFullPositionLabel.text = durationToString(0);
1088 }702 musicToolbarFullDurationLabel.text = durationToString(0);
1089 }703 }
1090704 }
1091 /* Mouse events for the progress bar705
1092 is after musicToolbarMouseArea so that it captures mouse events for dragging */706 // Black background behind the progress bar
1093 MouseArea {707 Rectangle {
1094 id: musicToolbarFullProgressMouseArea708 id: musicToolbarFullProgressBackground
1095 height: units.gu(2)709 anchors.verticalCenter: parent.verticalCenter;
1096 width: musicToolbarFullProgressBarContainer.width710 color: styleMusic.toolbar.fullProgressBackgroundColor;
1097 x: musicToolbarFullProgressBarContainer.x711 height: parent.height;
1098 y: musicToolbarFullProgressBarContainer.y712 radius: units.gu(0.5)
1099713 width: parent.width;
1100 drag.axis: Drag.XAxis714 }
1101 drag.minimumX: -(musicToolbarFullProgressHandle.width / 2)715
1102 drag.maximumX: musicToolbarFullProgressBarContainer.width - (musicToolbarFullProgressHandle.width / 2)716 // The orange fill of the progress bar
1103 drag.target: musicToolbarFullProgressHandle717 Rectangle {
1104718 id: musicToolbarFullProgressTrough
1105 onPressed: {719 anchors.verticalCenter: parent.verticalCenter;
1106 musicToolbarFullProgressBarContainer.seeking = true;720 antialiasing: true
1107721 color: styleMusic.toolbar.fullProgressTroughColor;
1108 // Jump the handle to the current mouse position722 height: parent.height;
1109 musicToolbarFullProgressHandle.x = mouse.x - (musicToolbarFullProgressHandle.width / 2);723 radius: units.gu(0.5)
1110 }724 width: musicToolbarFullProgressHandle.x + (height / 2); // +radius
1111725 }
1112 onReleased: {726
1113 var fraction = mouse.x / musicToolbarFullProgressBarContainer.width;727 // The current position (handle) of the progress bar
1114728 Rectangle {
1115 // Limit the bounds of the fraction729 id: musicToolbarFullProgressHandle
1116 fraction = fraction < 0 ? 0 : fraction730 anchors.verticalCenter: musicToolbarFullProgressBackground.verticalCenter
1117 fraction = fraction > 1 ? 1 : fraction731 antialiasing: true
1118732 color: styleMusic.nowPlaying.progressHandleColor
1119 player.seek((fraction) * player.duration);733 height: units.gu(1.5)
1120 musicToolbarFullProgressBarContainer.seeking = false;734 radius: height / 2
1121 }735 width: height
1122 }736
1123737 // On X change update the position string
1124 // Timer for autohide738 onXChanged: {
1125 Timer {739 if (musicToolbarFullProgressBarContainer.seeking) {
1126 id: toolbarAutoHideTimer740 var fraction = (x + (width / 2)) / parent.width;
1127 interval: 5000741 musicToolbarFullPositionLabel.text = durationToString(fraction * player.duration)
1128 repeat: false742 }
1129 running: false743 }
1130 onTriggered: {744 }
1131 if (currentPage !== nowPlaying) { // don't autohide on now playing745 }
1132 hideToolbar();746
1133 }747 /* Duration label */
748 Label {
749 id: musicToolbarFullDurationLabel
750 anchors.right: parent.right
751 anchors.rightMargin: units.gu(2)
752 anchors.top: parent.top
753 color: styleMusic.nowPlaying.labelColor
754 fontSize: "x-small"
755 height: parent.height
756 horizontalAlignment: Text.AlignHCenter
757 text: durationToString(player.duration)
758 verticalAlignment: Text.AlignVCenter
759 width: units.gu(3)
760 }
761
762 /* Border at the bottom */
763 Rectangle {
764 anchors.bottom: parent.bottom
765 anchors.left: parent.left
766 anchors.right: parent.right
767 color: styleMusic.common.white
768 height: units.gu(0.1)
769 opacity: 0.1
770 }
771 }
772 }
773
774 /* Expanded toolbar */
775 Rectangle {
776 id: musicToolbarExpandedContainer
777 anchors {
778 fill: parent
779 }
780 color: "transparent"
781 visible: musicToolbarPanel.currentMode === "expanded"
782
783 Rectangle {
784 id: musicToolbarPlayerControls
785 anchors.fill: parent
786 color: styleMusic.playerControls.backgroundColor
787 state: trackQueue.model.count === 0 ? "disabled" : "enabled"
788 states: [
789 State {
790 name: "disabled"
791 PropertyChanges {
792 target: disabledPlayerControlsGroup
793 visible: true
794 }
795 PropertyChanges {
796 target: enabledPlayerControlsGroup
797 visible: false
798 }
799 },
800 State {
801 name: "enabled"
802 PropertyChanges {
803 target: disabledPlayerControlsGroup
804 visible: false
805 }
806 PropertyChanges {
807 target: enabledPlayerControlsGroup
808 visible: true
809 }
810 }
811 ]
812
813 Rectangle {
814 id: disabledPlayerControlsGroup
815 anchors.fill: parent
816 color: "transparent"
817 visible: trackQueue.model.count === 0
818
819 Label {
820 id: noSongsInQueueLabel
821 anchors {
822 left: parent.left
823 right: disabledPlayerControlsPlayButton.left
824 margins: units.gu(1)
825 top: parent.top
826 }
827 color: styleMusic.playerControls.labelColor
828 text: i18n.tr("Tap play to shuffle music")
829 fontSize: "large"
830 wrapMode: Text.WordWrap
831 maximumLineCount: 2
832 }
833
834 Rectangle {
835 id: disabledPlayerControlsPlayButton
836 anchors.right: parent.right
837 anchors.rightMargin: units.gu(1)
838 anchors.verticalCenter: parent.verticalCenter
839 antialiasing: true
840 color: "#444"
841 height: units.gu(7)
842 radius: height / 2
843 width: height
844
845 MouseArea {
846 anchors {
847 fill: parent
848 }
849 onClicked: {
850 if (emptyPage.noMusic) {
851 return;
852 }
853
854 if (trackQueue.model.count === 0) {
855 playRandomSong();
856 }
857 else {
858 player.toggle();
859 }
860 }
861 }
862
863 // draws the outer shadow/highlight
864 Rectangle {
865 id: disabledSourceOutter
866 anchors { fill: parent; margins: -units.gu(0.1) }
867 radius: (width / 2)
868 antialiasing: true
869 gradient: Gradient {
870 GradientStop { position: 0.0; color: "black" }
871 GradientStop { position: 0.5; color: "transparent" }
872 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
873 }
874
875 Rectangle {
876 anchors.verticalCenter: parent.verticalCenter
877 anchors.horizontalCenter: parent.horizontalCenter
878 antialiasing: true
879 color: "#444"
880 height: playerControlsPlayButton.height - units.gu(.1)
881 radius: height / 2
882 width: height
883
884 Rectangle {
885 id: disabledPlayerControlsPlayInnerCircle
886 anchors.horizontalCenter: parent.horizontalCenter
887 anchors.verticalCenter: parent.verticalCenter
888 antialiasing: true
889 height: units.gu(4.5)
890 radius: height / 2
891 width: height
892 color: styleMusic.toolbar.fullInnerPlayCircleColor
893
894 // draws the inner shadow/highlight
895 Rectangle {
896 id: disabledSourceInner
897 anchors { fill: parent; margins: -units.gu(0.1) }
898 radius: (width / 2)
899 antialiasing: true
900 gradient: Gradient {
901 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
902 GradientStop { position: 0.5; color: "transparent" }
903 GradientStop { position: 1.0; color: "black" }
904 }
905
906 Rectangle {
907 anchors.verticalCenter: parent.verticalCenter
908 anchors.horizontalCenter: parent.horizontalCenter
909 antialiasing: true
910 height: playerControlsPlayInnerCircle.height - units.gu(.1)
911 radius: height / 2
912 width: height
913 color: styleMusic.toolbar.fullInnerPlayCircleColor
914
915 Image {
916 id: disabledPlayIndicator
917 height: units.gu(4)
918 width: height
919 anchors.horizontalCenter: parent.horizontalCenter
920 anchors.verticalCenter: parent.verticalCenter
921 opacity: emptyPage.noMusic ? .4 : 1
922 source: player.playbackState === MediaPlayer.PlayingState ?
923 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
924 }
925 }
926 }
927 }
928 }
929 }
930 }
931 }
932
933 Rectangle {
934 id: enabledPlayerControlsGroup
935 anchors.fill: parent
936 color: "transparent"
937 visible: trackQueue.model.count !== 0
938
939 /* Settings button */
940 // TODO: Enable settings when it is practical
941 /* Rectangle {
942 id: playerControlsSettings
943 anchors.right: parent.right
944 anchors.verticalCenter: parent.verticalCenter
945 width: units.gu(6)
946 height: width
947 color: "transparent"
948
949 Image {
950 anchors.horizontalCenter: parent.horizontalCenter
951 anchors.verticalCenter: parent.verticalCenter
952 height: units.gu(3)
953 source: Qt.resolvedUrl("images/settings.png")
954 width: height
955 }
956
957 MouseArea {
958 anchors.fill: parent
959 onClicked: {
960 console.debug('Debug: Show settings')
961 PopupUtils.open(Qt.resolvedUrl("MusicSettings.qml"), mainView,
962 {
963 title: i18n.tr("Settings")
964 } )
965 }
966 }
967 } */
968
969 /* Play/Pause button TODO: image and colours needs updating */
970 Rectangle {
971 id: playerControlsPlayButton
972 anchors.right: parent.right
973 anchors.rightMargin: units.gu(1)
974 anchors.verticalCenter: parent.verticalCenter
975 antialiasing: true
976 color: "#444"
977 height: units.gu(7)
978 objectName: "playshape"
979 radius: height / 2
980 width: height
981
982 MouseArea {
983 anchors {
984 fill: parent
985 }
986 onClicked: {
987 if (emptyPage.noMusic) {
988 return;
989 }
990
991 if (trackQueue.model.count === 0) {
992 playRandomSong();
993 }
994 else {
995 player.toggle();
996 }
997 }
998 }
999
1000 // draws the outer shadow/highlight
1001 Rectangle {
1002 id: sourceOutter
1003 anchors { fill: parent; margins: -units.gu(0.1) }
1004 radius: (width / 2)
1005 antialiasing: true
1006 gradient: Gradient {
1007 GradientStop { position: 0.0; color: "black" }
1008 GradientStop { position: 0.5; color: "transparent" }
1009 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
1010 }
1011
1012 Rectangle {
1013 anchors.verticalCenter: parent.verticalCenter
1014 anchors.horizontalCenter: parent.horizontalCenter
1015 antialiasing: true
1016 color: "#444"
1017 height: playerControlsPlayButton.height - units.gu(.1)
1018 radius: height / 2
1019 width: height
1020
1021 Rectangle {
1022 id: playerControlsPlayInnerCircle
1023 anchors.horizontalCenter: parent.horizontalCenter
1024 anchors.verticalCenter: parent.verticalCenter
1025 antialiasing: true
1026 height: units.gu(4.5)
1027 radius: height / 2
1028 width: height
1029 color: styleMusic.toolbar.fullInnerPlayCircleColor
1030
1031 // draws the inner shadow/highlight
1032 Rectangle {
1033 id: sourceInner
1034 anchors { fill: parent; margins: -units.gu(0.1) }
1035 radius: (width / 2)
1036 antialiasing: true
1037 gradient: Gradient {
1038 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
1039 GradientStop { position: 0.5; color: "transparent" }
1040 GradientStop { position: 1.0; color: "black" }
1041 }
1042
1043 Rectangle {
1044 anchors.verticalCenter: parent.verticalCenter
1045 anchors.horizontalCenter: parent.horizontalCenter
1046 antialiasing: true
1047 height: playerControlsPlayInnerCircle.height - units.gu(.1)
1048 radius: height / 2
1049 width: height
1050 color: styleMusic.toolbar.fullInnerPlayCircleColor
1051
1052 Image {
1053 id: playindicator
1054 height: units.gu(4)
1055 width: height
1056 anchors.horizontalCenter: parent.horizontalCenter
1057 anchors.verticalCenter: parent.verticalCenter
1058 opacity: emptyPage.noMusic ? .4 : 1
1059 source: player.playbackState === MediaPlayer.PlayingState ?
1060 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
1061 }
1062 }
1063 }
1064 }
1065 }
1066 }
1067 }
1068
1069 /* Container holding the labels for the toolbar */
1070 Rectangle {
1071 id: playerControlLabelContainer
1072 anchors.bottom: parent.bottom
1073 anchors.left: parent.left
1074 anchors.right: playerControlsPlayButton.left
1075 anchors.top: parent.top
1076 color: "transparent"
1077
1078 /* Title of track */
1079 Label {
1080 id: playerControlsTitle
1081 anchors.left: parent.left
1082 anchors.leftMargin: units.gu(1)
1083 anchors.right: parent.right
1084 anchors.rightMargin: units.gu(1)
1085 anchors.top: parent.top
1086 anchors.topMargin: units.gu(1)
1087 color: styleMusic.playerControls.labelColor
1088 elide: Text.ElideRight
1089 fontSize: "medium"
1090 objectName: "playercontroltitle"
1091 text: player.currentMetaTitle === ""
1092 ? player.source : player.currentMetaTitle
1093 }
1094
1095 /* Artist of track */
1096 Label {
1097 id: playerControlsArtist
1098 anchors.left: parent.left
1099 anchors.leftMargin: units.gu(1)
1100 anchors.right: parent.right
1101 anchors.rightMargin: units.gu(1)
1102 anchors.top: playerControlsTitle.bottom
1103 color: styleMusic.playerControls.labelColor
1104 elide: Text.ElideRight
1105 fontSize: "small"
1106 text: player.currentMetaArtist
1107 }
1108
1109 /* Album of track */
1110 Label {
1111 id: playerControlsAlbum
1112 anchors.left: parent.left
1113 anchors.leftMargin: units.gu(1)
1114 anchors.right: parent.right
1115 anchors.rightMargin: units.gu(1)
1116 anchors.top: playerControlsArtist.bottom
1117 color: styleMusic.playerControls.labelColor
1118 elide: Text.ElideRight
1119 fontSize: "small"
1120 text: player.currentMetaAlbum
1121 }
1122 }
1123
1124 Rectangle {
1125 anchors.fill: playerControlLabelContainer
1126 color: "transparent"
1127
1128 MouseArea {
1129 anchors {
1130 fill: parent
1131 }
1132 onClicked: tabs.pushNowPlaying();
1133 }
1134 }
1135 }
1136 }
1137 }
1138
1139 /* Object which provides the progress bar when toolbar is minimized */
1140 Rectangle {
1141 id: musicToolbarSmallProgressBackground
1142 anchors {
1143 bottom: parent.top
1144 left: parent.left
1145 right: parent.right
1146 }
1147 color: styleMusic.common.black
1148 height: musicToolbarPanel.minimizedHeight
1149 visible: (!musicToolbarPanel.animating &&
1150 !musicToolbarPanel.shown)
1151 || musicToolbarPanel.currentMode === "expanded"
1152
1153 Rectangle {
1154 id: musicToolbarSmallProgressHint
1155 anchors.left: parent.left
1156 anchors.top: parent.top
1157 color: styleMusic.nowPlaying.progressForegroundColor
1158 height: parent.height
1159 width: 0
1160
1161 Connections {
1162 target: player
1163 onPositionChanged: {
1164 musicToolbarSmallProgressHint.width = (player.position / player.duration) * musicToolbarSmallProgressBackground.width
1165 }
1166 onStopped: {
1167 musicToolbarSmallProgressHint.width = 0;
1168 }
1169 }
1170 }
1171 }
1172
1173 /* Mouse events for dragging the toolbar down */
1174 MouseArea {
1175 anchors {
1176 fill: parent
1177 }
1178 drag {
1179 axis: Drag.YAxis
1180 minimumY: currentPage === null ? -musicToolbarPanel.height : currentPage.height - musicToolbarPanel.height
1181 maximumY: currentPage === null ? 0 : currentPage.height
1182 target: musicToolbarPanel
1183 }
1184 enabled: !wideAspect
1185 propagateComposedEvents: true
1186
1187 property bool changed: false
1188
1189 onClicked: mouse.accepted = changed
1190 onMouseYChanged: {
1191 mouse.accepted = true
1192 changed = true
1193 }
1194 onPressed: mouse.accepted = false
1195 onReleased: {
1196 mouse.accepted = changed
1197 changed = false
1198
1199 if (musicToolbarPanel.y < currentPage.height - (musicToolbarPanel.height / 2)) {
1200 showToolbar()
1201 } else {
1202 hideToolbar()
1203 }
1204 }
1205 }
1206
1207 /* Mouse events for showing the toolbar when hidden and bottom edge is expanded */
1208 MouseArea {
1209 enabled: isNowPlaying(currentPage) && !wideAspect
1210 height: units.gu(2)
1211 width: parent.width
1212 x: 0
1213 y: currentPage === null ? 0 : -height
1214 drag {
1215 axis: Drag.YAxis
1216 minimumY: currentPage === null ? -musicToolbarPanel.height : currentPage.height - musicToolbarPanel.height
1217 maximumY: currentPage === null ? 0 : currentPage.height
1218 target: musicToolbarPanel
1219 }
1220
1221 onReleased: {
1222 if (musicToolbarPanel.y < currentPage.height - (musicToolbarPanel.height / 2)) {
1223 showToolbar()
1224 } else {
1225 hideToolbar()
1226 }
1227 }
1228 }
1229
1230 /* Mouse events for the progress bar
1231 is after musicToolbarMouseArea so that it captures mouse events for dragging */
1232 MouseArea {
1233 id: musicToolbarFullProgressMouseArea
1234 height: units.gu(2)
1235 width: musicToolbarFullProgressBarContainer.width
1236 x: musicToolbarFullProgressBarContainer.x
1237 y: musicToolbarFullProgressBarContainer.y
1238
1239 drag.axis: Drag.XAxis
1240 drag.minimumX: -(musicToolbarFullProgressHandle.width / 2)
1241 drag.maximumX: musicToolbarFullProgressBarContainer.width - (musicToolbarFullProgressHandle.width / 2)
1242 drag.target: musicToolbarFullProgressHandle
1243
1244 onPressed: {
1245 musicToolbarFullProgressBarContainer.seeking = true;
1246
1247 // Jump the handle to the current mouse position
1248 musicToolbarFullProgressHandle.x = mouse.x - (musicToolbarFullProgressHandle.width / 2);
1249 }
1250
1251 onReleased: {
1252 var fraction = mouse.x / musicToolbarFullProgressBarContainer.width;
1253
1254 // Limit the bounds of the fraction
1255 fraction = fraction < 0 ? 0 : fraction
1256 fraction = fraction > 1 ? 1 : fraction
1257
1258 player.seek((fraction) * player.duration);
1259 musicToolbarFullProgressBarContainer.seeking = false;
1260 }
1261 }
1262
1263 // Timer for autohide
1264 Timer {
1265 id: toolbarAutoHideTimer
1266 interval: 5000
1267 repeat: false
1268 running: false
1269 onTriggered: {
1270 if (!isNowPlaying(currentPage) && !currentPage.floating) { // don't autohide on now playing
1271 hideToolbar();
1134 }1272 }
1135 }1273 }
1136 }1274 }
1137}1275}
1138
11391276
=== modified file 'Player.qml'
--- Player.qml 2014-08-13 23:57:39 +0000
+++ Player.qml 2014-08-21 20:46:47 +0000
@@ -65,7 +65,10 @@
65 player.currentIndex = 0;65 player.currentIndex = 0;
66 player.source = Qt.resolvedUrl(trackQueue.model.get(0).filename)66 player.source = Qt.resolvedUrl(trackQueue.model.get(0).filename)
67 } else if (trackQueue.model.count === 0) {67 } else if (trackQueue.model.count === 0) {
68 currentMetaFile = ""68 currentMetaAlbum = "";
69 currentMetaArtist = "";
70 currentMetaFile = "";
71 currentMetaTitle = "";
69 }72 }
70 }73 }
71 }74 }
7275
=== modified file 'common/AlbumsPage.qml'
--- common/AlbumsPage.qml 2014-08-21 17:28:54 +0000
+++ common/AlbumsPage.qml 2014-08-21 20:46:47 +0000
@@ -28,7 +28,6 @@
2828
29MusicPage {29MusicPage {
30 id: albumStackPage30 id: albumStackPage
31 anchors.bottomMargin: units.gu(.5)
32 visible: false31 visible: false
3332
34 property string artist: ""33 property string artist: ""
3534
=== modified file 'common/MusicPage.qml'
--- common/MusicPage.qml 2014-07-02 12:27:30 +0000
+++ common/MusicPage.qml 2014-08-21 20:46:47 +0000
@@ -17,13 +17,19 @@
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */18 */
1919
20import QtQuick 2.0
20import Ubuntu.Components 0.121import Ubuntu.Components 0.1
2122
2223
23// generic page for music, could be useful for bottomedge implementation24// generic page for music, could be useful for bottomedge implementation
24Page {25PageWithBottomEdge {
25 id: thisPage26 id: thisPage
2627
28 bottomEdgeEnabled: true
29 //bottomEdgePageComponent: nowPlayingComponent
30 bottomEdgeTitle: i18n.tr("Now Playing") + " (" + trackQueue.model.count.toString() + ")"
31 reloadBottomEdgePage: false
32
27 onVisibleChanged: {33 onVisibleChanged: {
28 if (visible) {34 if (visible) {
29 musicToolbar.setPage(thisPage);35 musicToolbar.setPage(thisPage);
3036
=== added file 'common/PageWithBottomEdge.qml'
--- common/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000
+++ common/PageWithBottomEdge.qml 2014-08-21 20:46:47 +0000
@@ -0,0 +1,512 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17/*
18 Example:
19
20 MainView {
21 objectName: "mainView"
22
23 applicationName: "com.ubuntu.developer.boiko.bottomedge"
24
25 width: units.gu(100)
26 height: units.gu(75)
27
28 Component {
29 id: pageComponent
30
31 PageWithBottomEdge {
32 id: mainPage
33 title: i18n.tr("Main Page")
34
35 Rectangle {
36 anchors.fill: parent
37 color: "white"
38 }
39
40 bottomEdgePageComponent: Page {
41 title: "Contents"
42 anchors.fill: parent
43 //anchors.topMargin: contentsPage.flickable.contentY
44
45 ListView {
46 anchors.fill: parent
47 model: 50
48 delegate: ListItems.Standard {
49 text: "One Content Item: " + index
50 }
51 }
52 }
53 bottomEdgeTitle: i18n.tr("Bottom edge action")
54 }
55 }
56
57 PageStack {
58 id: stack
59 Component.onCompleted: stack.push(pageComponent)
60 }
61 }
62
63*/
64
65import QtQuick 2.0
66import Ubuntu.Components 0.1
67
68Page {
69 id: page
70
71 property alias bottomEdgePageComponent: edgeLoader.sourceComponent
72 property alias bottomEdgePageSource: edgeLoader.source
73 property alias bottomEdgeTitle: tipLabel.text
74 property alias bottomEdgeEnabled: bottomEdge.visible
75 property int bottomEdgeExpandThreshold: page.height * 0.2
76 property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded
77 property bool reloadBottomEdgePage: true
78
79 readonly property alias bottomEdgePage: edgeLoader.item
80 readonly property bool isReady: (bottomEdge.y === 0) // CUSTOM, no edgeLoader && bottomEdgePageLoaded && edgeLoader.item.active)
81 readonly property bool isCollapsed: (bottomEdge.y === page.height)
82 readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready)
83
84 property bool _showEdgePageWhenReady: false
85 property int _areaWhenExpanded: 0
86
87 property bool floating: bottomEdge.state === "floating" // CUSTOM
88 property alias bottomEdgeState: bottomEdge.state // CUSTOM expose state for toolbar and pushNowPlaying()
89
90 signal bottomEdgeReleased()
91 signal bottomEdgeDismissed()
92
93
94 function showBottomEdgePage(source, properties)
95 {
96 edgeLoader.setSource(source, properties)
97 _showEdgePageWhenReady = true
98 }
99
100 function setBottomEdgePage(source, properties)
101 {
102 edgeLoader.setSource(source, properties)
103 }
104
105 function _pushPage()
106 {
107 /* CUSTOM
108 if (edgeLoader.status === Loader.Ready) {
109 edgeLoader.item.active = true
110 page.pageStack.push(edgeLoader.item)
111 if (edgeLoader.item.flickable) {
112 edgeLoader.item.flickable.contentY = -page.header.height
113 edgeLoader.item.flickable.returnToBounds()
114 }
115 if (edgeLoader.item.ready)
116 edgeLoader.item.ready()
117 }
118 */
119
120 nowPlaying.reparent(mainPageStack) // CUSTOM
121 mainPageStack.push(nowPlaying) // CUSTOM
122 }
123
124
125 function forceExpandedStateNoAnimation() // CUSTOM, used by toolbar to restore state
126 {
127 bottomEdge.forceStateNoAnimation = true
128 bottomEdge.state = "expanded"
129 bottomEdge.forceStateNoAnimation = false
130 }
131
132
133 Component.onCompleted: {
134 // avoid a binding on the expanded height value
135 var expandedHeight = height;
136 _areaWhenExpanded = expandedHeight;
137 }
138
139 onActiveChanged: {
140 if (active) {
141 bottomEdge.state = "collapsed"
142 }
143 }
144
145 onBottomEdgePageLoadedChanged: {
146 if (_showEdgePageWhenReady && bottomEdgePageLoaded) {
147 bottomEdge.state = "expanded"
148 _showEdgePageWhenReady = false
149 }
150 }
151
152 onVisibleChanged: { // CUSTOM, reparent now playing to this page
153 if (visible) {
154 nowPlaying.reparent(customLoader)
155 }
156 }
157
158 Rectangle {
159 id: bgVisual
160
161 color: "black"
162 anchors.fill: page
163 opacity: 0.7 * ((page.height - bottomEdge.y) / page.height)
164 z: 1
165 }
166
167 Timer {
168 id: hideIndicator
169
170 interval: 3000
171 running: true
172 repeat: false
173 onTriggered: tip.hidden = true
174 }
175
176
177 Rectangle {
178 id: bottomEdge
179 objectName: "bottomEdge"
180
181 readonly property int tipHeight: units.gu(4) // CUSTOM increase tip height due to progress bar overlay units.gu(3)
182 readonly property int pageStartY: 0
183
184 property bool forceStateNoAnimation: false // CUSTOM, used to force the state without animation
185
186 z: 1
187 color: Theme.palette.normal.background // FIXME: causes non transparent bg
188 parent: page
189 anchors {
190 left: parent.left
191 right: parent.right
192 }
193 height: page.height
194 y: height
195
196 Connections { // custom
197 target: musicToolbar
198
199 onYChanged: {
200 // Lock the bottom edge y to the toolbar y if not in expanded mode
201 if (!floating && bottomEdge.state === "panel") {
202 bottomEdge.y = musicToolbar.y
203 }
204 }
205 }
206
207
208 UbuntuShape {
209 id: tip
210 objectName: "bottomEdgeTip"
211
212 property bool hidden: false
213
214 //readonly property double visiblePosition: (page.height - bottomEdge.y) < units.gu(1) ? -bottomEdge.tipHeight + (page.height - bottomEdge.y) : 0
215 //readonly property double invisiblePosition: (page.height - bottomEdge.y) < units.gu(1) ? -units.gu(1) : 0
216 // CUSTOM, due to panel state position needs to be different
217 readonly property double visiblePosition: bottomEdge.y < page.height - musicToolbar.height - units.gu(1) ? 0 : -bottomEdge.tipHeight
218 readonly property double invisiblePosition: bottomEdge.state === "panel" || bottomEdge.state === "collapsed" ? -units.gu(1) : 0
219
220 z: -1
221 anchors.horizontalCenter: parent.horizontalCenter
222 y: hidden ? invisiblePosition : visiblePosition
223
224 width: tipLabel.paintedWidth + units.gu(6)
225 height: bottomEdge.tipHeight + units.gu(1)
226 color: Theme.palette.normal.overlay
227 Label {
228 id: tipLabel
229
230 anchors {
231 top: parent.top
232 left: parent.left
233 right: parent.right
234 }
235 color: styleMusic.common.black // CUSTOM use black text so it is readable
236 height: bottomEdge.tipHeight
237 verticalAlignment: Text.AlignVCenter
238 horizontalAlignment: Text.AlignHCenter
239 opacity: tip.hidden ? 0.0 : 1.0
240 Behavior on opacity {
241 UbuntuNumberAnimation {
242 duration: UbuntuAnimation.SnapDuration
243 }
244 }
245 }
246 Behavior on y {
247 UbuntuNumberAnimation {
248 duration: UbuntuAnimation.SnapDuration
249 }
250 }
251 }
252
253
254 Rectangle {
255 id: shadow
256
257 anchors {
258 left: parent.left
259 right: parent.right
260 }
261 height: units.gu(1)
262 y: -height
263 z: -2
264 opacity: 0.0
265 gradient: Gradient {
266 GradientStop { position: 0.0; color: "transparent" }
267 GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
268 }
269 }
270
271 MouseArea {
272 id: mouseArea
273
274 preventStealing: true
275 drag {
276 axis: Drag.YAxis
277 target: bottomEdge
278 minimumY: bottomEdge.pageStartY
279 maximumY: page.height
280 threshold: 100
281 }
282
283 anchors {
284 left: parent.left
285 right: parent.right
286 }
287 height: bottomEdge.tipHeight
288 y: -height
289
290 onReleased: {
291 page.bottomEdgeReleased()
292 if (bottomEdge.y < (page.height - bottomEdgeExpandThreshold * 2 - bottomEdge.tipHeight)) {
293 bottomEdge.state = "expanded"
294 }
295 // Release case for panel state
296 else if (bottomEdge.y < (page.height - musicToolbar.height * 0.5)) {
297 bottomEdge.state = "panel" // CUSTOM, custom panel state
298 }
299 else {
300 bottomEdge.state = "collapsed"
301 bottomEdge.y = bottomEdge.height
302 }
303 }
304
305 onClicked: {
306 tip.hidden = false
307 hideIndicator.restart()
308 }
309
310 // custom
311 // update the Y position of the musicToolbar as the bottom edge is dragged
312 // do not move the toolbar 'higher' than its height
313 onMouseYChanged: musicToolbar.y = bottomEdge.y < page.height - musicToolbar.height ? page.height - musicToolbar.height : bottomEdge.y
314 }
315
316 state: "collapsed"
317 states: [
318 State {
319 name: "collapsed"
320 PropertyChanges {
321 target: bottomEdge
322 y: bottomEdge.height - (wideAspect ? musicToolbar.height : 0) // custom, in wideAspect toolbar does not hide
323 }
324 PropertyChanges {
325 target: tip
326 opacity: 1.0
327 }
328 PropertyChanges {
329 target: hideIndicator
330 running: true
331 }
332 PropertyChanges { // custom
333 // Set the music toolbar to be offscreen unless in wideaspect
334 target: musicToolbar
335 y: bottomEdge.height - (wideAspect ? musicToolbar.height : 0) // in wideAspect toolbar does not hide
336 }
337 },
338 State { // custom
339 name: "panel" // state for when Panel is shown
340 PropertyChanges {
341 target: bottomEdge
342 y: bottomEdge.height - musicToolbar.height
343 }
344 PropertyChanges {
345 target: hideIndicator
346 running: true
347 }
348 PropertyChanges {
349 target: tip
350 hidden: false
351 }
352 PropertyChanges {
353 target: musicToolbar
354 y: bottomEdge.height - musicToolbar.height
355 }
356 },
357 State {
358 name: "expanded"
359 PropertyChanges {
360 target: bottomEdge
361 y: bottomEdge.pageStartY
362 }
363 PropertyChanges {
364 target: hideIndicator
365 running: false
366 }
367 PropertyChanges { // custom
368 // Ensure that the musicToolbar is shown as the bottom edge is shown
369 target: musicToolbar
370 y: bottomEdge.height - musicToolbar.height
371 }
372 },
373 State {
374 name: "floating"
375 when: mouseArea.drag.active
376 PropertyChanges { // CUSTOM, otherwise if drag starts from panel Y gets reset
377 target: bottomEdge
378 y: bottomEdge.y
379 }
380 PropertyChanges {
381 target: shadow
382 opacity: 1.0
383 }
384 PropertyChanges {
385 target: hideIndicator
386 running: false
387 }
388 PropertyChanges {
389 target: tip
390 hidden: false
391 }
392 }
393 ]
394
395 transitions: [
396 Transition {
397 to: "expanded"
398 enabled: !bottomEdge.forceStateNoAnimation // CUSTOM, only animate if required
399 SequentialAnimation {
400 UbuntuNumberAnimation {
401 targets: bottomEdge
402 properties: "y"
403 duration: UbuntuAnimation.SlowDuration
404 }
405 ScriptAction {
406 script: page._pushPage()
407 }
408 }
409 },
410 Transition {
411 from: "expanded"
412 to: "collapsed"
413 SequentialAnimation {
414 ScriptAction {
415 script: {
416 nowPlaying.reparent(customLoader) // CUSTOM, rebind the now playing to the bottom edge
417
418 /* CUSTOM.
419 Qt.inputMethod.hide()
420 edgeLoader.item.parent = edgeLoader
421 edgeLoader.item.anchors.fill = edgeLoader
422 edgeLoader.item.active = false
423 */
424 }
425 }
426 UbuntuNumberAnimation {
427 targets: bottomEdge
428 properties: "y"
429 duration: UbuntuAnimation.SlowDuration
430 }
431 ScriptAction {
432 script: {
433 // destroy current bottom page
434 if (page.reloadBottomEdgePage) {
435 edgeLoader.active = false
436 }
437
438 // notify
439 page.bottomEdgeDismissed()
440
441 edgeLoader.active = true
442 tip.hidden = false
443 hideIndicator.restart()
444
445 // CUSTOM, collapse toolbar when going to collapsed mode
446 musicToolbar.hideToolbar()
447 }
448 }
449 }
450 },
451 Transition {
452 from: "floating"
453 to: "collapsed"
454 UbuntuNumberAnimation {
455 targets: bottomEdge
456 properties: "y"
457 }
458 },
459 Transition { // custom
460 to: "panel"
461 ScriptAction {
462 // Start autohide timer when going to panel
463 script: musicToolbar.startAutoHideTimer()
464 }
465 },
466 Transition { // custom
467 from: "panel"
468 ScriptAction {
469 // Stop any autohide timers when moving away from panel
470 script: musicToolbar.stopAutoHideTimer()
471 }
472 }
473 ]
474
475
476 Item {
477 anchors.fill: parent
478 clip: true
479
480 Item { // CUSTOM, item which will contain the bottom edge component
481 id: customLoader
482 anchors {
483 fill: parent
484 }
485 z: 1
486 }
487
488 Loader {
489 id: edgeLoader
490
491 z: 1
492 active: true
493 asynchronous: true
494 anchors.fill: parent
495
496 //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging
497 Binding {
498 target: edgeLoader.status === Loader.Ready ? edgeLoader : null
499 property: "anchors.topMargin"
500 value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
501 when: !page.isReady
502 }
503
504 onLoaded: {
505 if (page.isReady && edgeLoader.item.active !== true) {
506 page._pushPage()
507 }
508 }
509 }
510 }
511 }
512}
0513
=== modified file 'common/SongsPage.qml'
--- common/SongsPage.qml 2014-08-16 13:38:36 +0000
+++ common/SongsPage.qml 2014-08-21 20:46:47 +0000
@@ -29,7 +29,7 @@
2929
30MusicPage {30MusicPage {
31 id: songStackPage31 id: songStackPage
32 anchors.bottomMargin: units.gu(.5)32 objectName: "songStackPage"
33 visible: false33 visible: false
3434
35 property string line1: ""35 property string line1: ""
3636
=== modified file 'music-app.qml'
--- music-app.qml 2014-08-21 18:54:06 +0000
+++ music-app.qml 2014-08-21 20:46:47 +0000
@@ -35,7 +35,6 @@
35import "scrobble.js" as Scrobble35import "scrobble.js" as Scrobble
36import "playlists.js" as Playlists36import "playlists.js" as Playlists
37import "common"37import "common"
38
39MainView {38MainView {
40 objectName: "music"39 objectName: "music"
41 applicationName: "com.ubuntu.music"40 applicationName: "com.ubuntu.music"
@@ -598,7 +597,7 @@
598 // Show toolbar and start timer if there is music597 // Show toolbar and start timer if there is music
599 if (!emptyPage.noMusic) {598 if (!emptyPage.noMusic) {
600 musicToolbar.showToolbar();599 musicToolbar.showToolbar();
601 musicToolbar.startAutohideTimer();600 musicToolbar.startAutoHideTimer();
602 }601 }
603 }602 }
604603
@@ -990,7 +989,6 @@
990 MusicToolbar {989 MusicToolbar {
991 id: musicToolbar990 id: musicToolbar
992 objectName: "musicToolbarObject"991 objectName: "musicToolbarObject"
993 z: 200 // put on top of everything else
994 }992 }
995993
996 PageStack {994 PageStack {
@@ -999,7 +997,7 @@
999 Tabs {997 Tabs {
1000 id: tabs998 id: tabs
1001 anchors {999 anchors {
1002 bottomMargin: wideAspect ? musicToolbar.fullHeight : undefined1000 //bottomMargin: wideAspect ? musicToolbar.fullHeight : undefined
1003 fill: parent1001 fill: parent
1004 }1002 }
10051003
@@ -1123,8 +1121,9 @@
1123 function pushNowPlaying()1121 function pushNowPlaying()
1124 {1122 {
1125 // only push if on a different page1123 // only push if on a different page
1126 if (mainPageStack.currentPage !== nowPlaying) {1124 if (!musicToolbar.isNowPlaying(musicToolbar.currentPage)) {
1127 mainPageStack.push(nowPlaying);1125 // Emulate dragging the bottom edge up
1126 musicToolbar.currentPage.bottomEdgeState = "expanded"
1128 }1127 }
1129 }1128 }
11301129
@@ -1161,8 +1160,9 @@
1161 }1160 }
1162 }1161 }
11631162
1164 Page {1163 MusicPage {
1165 id: emptyPage1164 id: emptyPage
1165 bottomEdgeEnabled: false
1166 title: i18n.tr("Music")1166 title: i18n.tr("Music")
1167 visible: noMusic1167 visible: noMusic
11681168
11691169
=== modified file 'tests/autopilot/music_app/__init__.py'
--- tests/autopilot/music_app/__init__.py 2014-08-21 17:59:15 +0000
+++ tests/autopilot/music_app/__init__.py 2014-08-21 20:46:47 +0000
@@ -257,6 +257,12 @@
257 if item.text == trackTitle:257 if item.text == trackTitle:
258 return item258 return item
259259
260 def get_song_stack_page(self):
261 return self.select_single("*", objectName="songStackPage")
262
263 def get_tracks_page(self):
264 return self.select_single("*", objectName="tracksPage")
265
260 def get_songs_page_listview_tracktitle(self, trackTitle):266 def get_songs_page_listview_tracktitle(self, trackTitle):
261 tracktitles = self.select_many_retry(267 tracktitles = self.select_many_retry(
262 "Label", objectName="songspage-tracktitle")268 "Label", objectName="songspage-tracktitle")
263269
=== modified file 'tests/autopilot/music_app/tests/test_music.py'
--- tests/autopilot/music_app/tests/test_music.py 2014-08-19 23:30:26 +0000
+++ tests/autopilot/music_app/tests/test_music.py 2014-08-21 20:46:47 +0000
@@ -41,6 +41,10 @@
41 def pointing_device(self):41 def pointing_device(self):
42 return self.app.app.pointing_device42 return self.app.app.pointing_device
4343
44 # wait for animations to complete
45 page = self.main_view.get_tracks_page()
46 page.isReady.wait_for(True)
47
44 def turn_shuffle_off(self):48 def turn_shuffle_off(self):
45 if self.player.shuffle:49 if self.player.shuffle:
46 shufflebutton = self.main_view.get_shuffle_button()50 shufflebutton = self.main_view.get_shuffle_button()
@@ -527,6 +531,10 @@
527 self.trackTitle)531 self.trackTitle)
528 self.pointing_device.click_object(track)532 self.pointing_device.click_object(track)
529533
534 # wait for animations to complete
535 page = self.main_view.get_song_stack_page()
536 page.isReady.wait_for(True)
537
530 # verify track queue has added all songs to initial value538 # verify track queue has added all songs to initial value
531 endtracksCount = self.main_view.get_queue_track_count()539 endtracksCount = self.main_view.get_queue_track_count()
532 self.assertThat(endtracksCount, Equals(initialtracksCount + 2))540 self.assertThat(endtracksCount, Equals(initialtracksCount + 2))

Subscribers

People subscribed via source and target branches

to status/vote changes: