Merge lp:~ahayzen/music-app/remix-recent-card-view into lp:music-app/trusty

Proposed by Andrew Hayzen
Status: Superseded
Proposed branch: lp:~ahayzen/music-app/remix-recent-card-view
Merge into: lp:music-app/trusty
Diff against target: 6131 lines (+1937/-2660) (has conflicts)
28 files modified
MusicAlbums.qml (+21/-123)
MusicArtists.qml (+37/-87)
MusicNowPlaying.qml (+381/-219)
MusicPlaylists.qml (+25/-142)
MusicSettings.qml (+0/-11)
MusicStart.qml (+37/-474)
MusicToolbar.qml (+169/-951)
MusicTracks.qml (+14/-15)
MusicaddtoPlaylist.qml (+0/-1)
Player.qml (+5/-1)
Style.qml (+2/-2)
com.ubuntu.music_music.desktop.in.in (+3/-0)
common/AlbumsPage.qml (+0/-3)
common/BlurredBackground.qml (+11/-9)
common/Card.qml (+151/-0)
common/CardView.qml (+43/-0)
common/ColumnFlow.qml (+160/-0)
common/CoverGrid.qml (+71/-0)
common/ListItemActions/DeletePlaylist.qml (+0/-29)
common/ListItemActions/EditPlaylist.qml (+0/-35)
common/MusicPage.qml (+4/-0)
common/MusicRow.qml (+34/-5)
common/SongsPage.qml (+268/-122)
music-app.qml (+27/-36)
po/com.ubuntu.music.pot (+145/-131)
po/pt_BR.po (+167/-134)
tests/autopilot/music_app/__init__.py (+102/-84)
tests/autopilot/music_app/tests/test_music.py (+60/-46)
Text conflict in po/pt_BR.po
To merge this branch: bzr merge lp:~ahayzen/music-app/remix-recent-card-view
Reviewer Review Type Date Requested Status
Music App Developers Pending
Review via email: mp+238635@code.launchpad.net

Commit message

* Use CardView in Recent Tab
* Use Recent as default if >0 recent items otherwise use Albums Tab

Description of the change

* Use CardView in Recent Tab
* Use Recent as default if >0 recent items otherwise use Albums Tab

Note we still need designs for an empty recent item state.

To post a comment you must log in.
673. By Andrew Hayzen

* Merge of trunk

674. By Andrew Hayzen

* Rebuild of .pot

675. By Andrew Hayzen

* Removal of old hasRecent

676. By Andrew Hayzen

* Switch to using delete icon

Unmerged revisions

676. By Andrew Hayzen

* Switch to using delete icon

675. By Andrew Hayzen

* Removal of old hasRecent

674. By Andrew Hayzen

* Rebuild of .pot

673. By Andrew Hayzen

* Merge of trunk

672. By Andrew Hayzen

* Use CardView in Recent Tab
* Use Recent as default if >0 recent items otherwise use Albums Tab

671. By Launchpad Translations on behalf of music-app-dev

Launchpad automatic translations update.

670. By Andrew Hayzen

* Use CardView in MusicPlaylists.qml
* Use header actions for edit and delete of playlists.

Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.

669. By Andrew Hayzen

* Make SongsPage use CoverGrid.

Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.

668. By Andrew Hayzen

* Add CoverGrid.qml component
* Use CoverGrid in Card.qml
.

Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.

667. By Victor Thompson

Initial Artists view with CardView.

Approved by Andrew Hayzen, Ubuntu Phone Apps Jenkins Bot.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'MusicAlbums.qml'
2--- MusicAlbums.qml 2014-09-20 15:41:33 +0000
3+++ MusicAlbums.qml 2014-10-16 23:15:23 +0000
4@@ -19,37 +19,17 @@
5
6 import QtQuick 2.3
7 import Ubuntu.Components 1.1
8-import Ubuntu.Components.Popups 1.0
9 import Ubuntu.MediaScanner 0.1
10-import Ubuntu.Thumbnailer 0.1
11-import QtMultimedia 5.0
12-import QtQuick.LocalStorage 2.0
13-import QtGraphicalEffects 1.0
14-import "settings.js" as Settings
15-import "playlists.js" as Playlists
16 import "common"
17
18+
19 MusicPage {
20- id: mainpage
21+ id: albumsPage
22 objectName: "albumsPage"
23 title: i18n.tr("Albums")
24
25- // TODO: This ListView is empty and causes the header to get painted with the desired background color because the
26- // page is now vertically flickable.
27- ListView {
28- anchors.fill: parent
29- anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
30- }
31-
32- GridView {
33- id: albumlist
34- anchors.fill: parent
35- anchors.leftMargin: units.gu(1)
36- anchors.top: parent.top
37- anchors.topMargin: mainView.header.height + units.gu(1)
38- anchors.bottomMargin: units.gu(1)
39- cellHeight: height/3
40- cellWidth: height/3
41+ CardView {
42+ id: albumCardView
43 model: SortFilterModel {
44 id: albumsModelFilter
45 property alias rowCount: albumsModel.rowCount
46@@ -60,106 +40,24 @@
47 sort.property: "title"
48 sort.order: Qt.AscendingOrder
49 }
50-
51- delegate: albumDelegate
52- flow: GridView.TopToBottom
53-
54- Component {
55- id: albumDelegate
56- Item {
57- property string artist: model.artist
58- property string album: model.title
59- property var covers: [{art: model.art}]
60-
61- id: albumItem
62- height: albumlist.cellHeight - units.gu(1)
63- objectName: "albumsPageGridItem" + index
64- width: albumlist.cellHeight - units.gu(1)
65- anchors.margins: units.gu(1)
66-
67- CoverRow {
68- id: albumShape
69- anchors {
70- top: parent.top
71- left: parent.left
72- verticalCenter: parent.verticalCenter
73- }
74- count: albumItem.covers.length
75- size: albumItem.width
76- covers: albumItem.covers
77- spacing: units.gu(2)
78- }
79- Item { // Background so can see text in current state
80- id: albumBg
81- anchors {
82- bottom: parent.bottom
83- left: parent.left
84- right: parent.right
85- }
86- height: units.gu(6)
87- clip: true
88- UbuntuShape{
89- anchors {
90- bottom: parent.bottom
91- left: parent.left
92- right: parent.right
93- }
94- height: albumShape.height
95- radius: "medium"
96- color: styleMusic.common.black
97- opacity: 0.6
98- }
99- }
100- Label {
101- id: albumArtist
102- objectName: "albums-albumartist"
103- anchors.bottom: parent.bottom
104- anchors.bottomMargin: units.gu(1)
105- anchors.left: parent.left
106- anchors.leftMargin: units.gu(1)
107- anchors.right: parent.right
108- anchors.rightMargin: units.gu(1)
109- color: styleMusic.common.white
110- elide: Text.ElideRight
111- text: model.artist
112- fontSize: "x-small"
113- }
114- Label {
115- id: albumLabel
116- anchors.bottom: parent.bottom
117- anchors.bottomMargin: units.gu(3)
118- anchors.left: parent.left
119- anchors.leftMargin: units.gu(1)
120- anchors.right: parent.right
121- anchors.rightMargin: units.gu(1)
122- color: styleMusic.common.white
123- elide: Text.ElideRight
124- text: model.title
125- fontSize: "small"
126- font.weight: Font.DemiBold
127- }
128-
129-
130- MouseArea {
131- anchors.fill: parent
132- onClicked: {
133- songsPage.album = model.title;
134- songsPage.covers = [{art: model.art}]
135- songsPage.genre = undefined
136- songsPage.isAlbum = true
137- songsPage.line1 = model.artist
138- songsPage.line2 = model.title
139- songsPage.title = i18n.tr("Album")
140-
141- mainPageStack.push(songsPage)
142- }
143-
144- // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
145- onPressedChanged: albumShape.pressed = pressed
146- }
147+ delegate: Card {
148+ id: albumCard
149+ coverSources: [{art: model.art}]
150+ objectName: "albumsPageGridItem" + index
151+ primaryText: model.title
152+ secondaryText: model.artist
153+
154+ onClicked: {
155+ songsPage.album = model.title;
156+ songsPage.covers = [{art: model.art}]
157+ songsPage.genre = undefined
158+ songsPage.isAlbum = true
159+ songsPage.line1 = model.artist
160+ songsPage.line2 = model.title
161+ songsPage.title = i18n.tr("Album")
162+
163+ mainPageStack.push(songsPage)
164 }
165 }
166 }
167 }
168-
169-
170
171=== modified file 'MusicArtists.qml'
172--- MusicArtists.qml 2014-09-20 15:41:33 +0000
173+++ MusicArtists.qml 2014-10-16 23:15:23 +0000
174@@ -36,98 +36,48 @@
175 objectName: "artistsPage"
176 title: i18n.tr("Artists")
177
178- ListView {
179- id: artistlist
180- anchors.fill: parent
181- anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
182+ CardView {
183+ id: artistCardView
184+ itemWidth: units.gu(12)
185 model: ArtistsModel {
186 id: artistsModel
187 albumArtists: true
188 store: musicStore
189 }
190-
191- delegate: artistDelegate
192-
193- Component {
194- id: artistDelegate
195-
196- ListItem.Standard {
197- id: track
198- objectName: "artistsPageListItem" + index
199- height: styleMusic.common.itemHeight
200-
201- AlbumsModel {
202- id: albumArtistModel
203- albumArtist: model.artist
204- store: musicStore
205- }
206-
207- Repeater {
208- id: albumArtistModelRepeater
209- model: albumArtistModel
210- delegate: Item {
211- property string art: model.art
212- }
213- property var covers: []
214- signal finished()
215-
216- onFinished: {
217- musicRow.covers = covers
218- }
219- onItemAdded: {
220- covers.push({art: item.art});
221-
222- if (index === count - 1) {
223- finished();
224- }
225- }
226- }
227-
228- SongsModel {
229- id: songArtistModel
230- albumArtist: model.artist
231- store: musicStore
232- }
233-
234- MusicRow {
235- id: musicRow
236- column: Column {
237- spacing: units.gu(1)
238- Label {
239- id: trackArtistAlbum
240- color: styleMusic.common.music
241- fontSize: "medium"
242- objectName: "artists-artist"
243- text: model.artist
244- }
245- Label {
246- id: trackArtistAlbums
247- color: styleMusic.common.subtitle
248- fontSize: "x-small"
249- text: i18n.tr("%1 album", "%1 albums", albumArtistModel.rowCount).arg(albumArtistModel.rowCount)
250- }
251- Label {
252- id: trackArtistAlbumTracks
253- color: styleMusic.common.subtitle
254- fontSize: "x-small"
255- text: i18n.tr("%1 song", "%1 songs", songArtistModel.rowCount).arg(songArtistModel.rowCount)
256- }
257- }
258- }
259-
260- MouseArea {
261- anchors.fill: parent
262- onClicked: {
263- albumsPage.artist = model.artist
264- albumsPage.covers = musicRow.covers
265- albumsPage.title = i18n.tr("Artist")
266-
267- mainPageStack.push(albumsPage)
268- }
269-
270- // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
271- onPressedChanged: musicRow.pressed = pressed
272- }
273+ delegate: Card {
274+ id: artistCard
275+ coverSources: [{art: "image://artistart/artist=" + model.artist + "&album=" + artistCard.album}]
276+ objectName: "artistsPageGridItem" + index
277+ primaryText: model.artist
278+ secondaryTextVisible: false
279+
280+ property string album: ""
281+
282+ AlbumsModel {
283+ id: albumArtistModel
284+ albumArtist: model.artist
285+ store: musicStore
286+ }
287+
288+ Repeater {
289+ id: albumArtistModelRepeater
290+ model: albumArtistModel
291+ delegate: Item {
292+ property string album: model.title
293+ }
294+
295+ onItemAdded: {
296+ artistCard.album = item.album
297+ }
298+ }
299+
300+
301+ onClicked: {
302+ albumsPage.artist = model.artist;
303+ albumsPage.covers = [{art: artistCard.imageSource}]
304+ albumsPage.title = i18n.tr("Artist")
305+
306+ mainPageStack.push(albumsPage)
307 }
308 }
309 }
310
311=== modified file 'MusicNowPlaying.qml'
312--- MusicNowPlaying.qml 2014-09-20 15:41:33 +0000
313+++ MusicNowPlaying.qml 2014-10-16 23:15:23 +0000
314@@ -17,7 +17,6 @@
315 * along with this program. If not, see <http://www.gnu.org/licenses/>.
316 */
317
318-
319 import QtMultimedia 5.0
320 import QtQuick 2.3
321 import QtQuick.LocalStorage 2.0
322@@ -29,65 +28,367 @@
323
324 MusicPage {
325 id: nowPlaying
326+ flickable: isListView ? queuelist : null // Ensures that the header is shown in fullview
327 objectName: "nowPlayingPage"
328- title: i18n.tr("Now Playing")
329+ title: isListView ? i18n.tr("Queue") : i18n.tr("Now playing")
330 visible: false
331
332- property int ensureVisibleIndex: 0 // ensure first index is visible at startup
333+ property bool isListView: false
334+
335+ onIsListViewChanged: {
336+ if (isListView) {
337+ positionAt(player.currentIndex);
338+ }
339+ }
340+
341+ head.backAction: Action {
342+ iconName: "back";
343+ objectName: "backButton"
344+ onTriggered: {
345+ mainPageStack.pop();
346+
347+ while (mainPageStack.depth > 1) { // jump back to the tab layer if via SongsPage
348+ mainPageStack.pop();
349+ }
350+ }
351+ }
352+
353+ head {
354+ actions: [
355+ Action {
356+ objectName: "clearQueue"
357+ iconName: "delete"
358+ visible: isListView
359+ onTriggered: {
360+ head.backAction.trigger()
361+ trackQueue.model.clear()
362+ }
363+ },
364+ Action {
365+ objectName: "toggleView"
366+ iconName: "media-playlist"
367+ onTriggered: {
368+ isListView = !isListView
369+ }
370+ }
371+ ]
372+ }
373+
374+ function positionAt(index) {
375+ queuelist.positionViewAtIndex(index, ListView.Center);
376+ }
377
378 Rectangle {
379+ id: fullview
380 anchors.fill: parent
381- color: styleMusic.nowPlaying.backgroundColor
382- opacity: 0.75 // change later
383- MouseArea { // Block events to lower layers
384- anchors.fill: parent
385- }
386- }
387-
388- Component.onCompleted: {
389- onToolbarShownChanged.connect(jumpToCurrent)
390- }
391-
392- Connections {
393- target: player
394- onCurrentIndexChanged: {
395- if (player.source === "") {
396- return;
397- }
398-
399- queuelist.currentIndex = player.currentIndex;
400-
401- customdebug("MusicQueue update currentIndex: " + player.source);
402-
403- // Always jump to current track
404- nowPlaying.jumpToCurrent(musicToolbar.opened, nowPlaying, musicToolbar.currentTab)
405-
406- }
407- }
408-
409- function jumpToCurrent(shown, currentPage, currentTab)
410- {
411- // If the toolbar is shown, the page is now playing and snaptrack is enabled
412- if (shown && currentPage === nowPlaying && Settings.getSetting("snaptrack") === "1")
413- {
414- // Then position the view at the current index
415- queuelist.positionViewAtIndex(queuelist.currentIndex, ListView.Beginning);
416- }
417- }
418-
419- function positionAt(index) {
420- queuelist.positionViewAtIndex(index, ListView.Beginning);
421- queuelist.contentY -= header.height;
422+ color: "transparent"
423+ visible: !isListView
424+
425+ BlurredBackground {
426+ id: blurredBackground
427+ anchors.top: parent.top
428+ anchors.topMargin: mainView.header.height
429+ height: units.gu(27)
430+ art: albumImage.source
431+
432+ Image {
433+ id: albumImage
434+ anchors.centerIn: parent
435+ width: units.gu(18)
436+ height: width
437+ smooth: true
438+ source: player.currentMetaArt === "" ?
439+ decodeURIComponent("image://albumart/artist=" +
440+ player.currentMetaArtist +
441+ "&album=" + player.currentMetaAlbum)
442+ : player.currentMetaArt
443+ }
444+ }
445+
446+ /* Full toolbar */
447+ Item {
448+ id: musicToolbarFullContainer
449+ anchors.top: blurredBackground.bottom
450+ anchors.topMargin: units.gu(4)
451+ width: blurredBackground.width
452+
453+ /* Column for labels in wideAspect */
454+ Column {
455+ id: nowPlayingWideAspectLabels
456+ spacing: units.gu(1)
457+ anchors {
458+ left: parent.left
459+ leftMargin: units.gu(2)
460+ right: parent.right
461+ rightMargin: units.gu(2)
462+ }
463+
464+ /* Title of track */
465+ Label {
466+ id: nowPlayingWideAspectTitle
467+ anchors {
468+ left: parent.left
469+ leftMargin: units.gu(1)
470+ right: parent.right
471+ rightMargin: units.gu(1)
472+ }
473+ color: styleMusic.playerControls.labelColor
474+ elide: Text.ElideRight
475+ fontSize: "x-large"
476+ objectName: "playercontroltitle"
477+ text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle
478+ }
479+
480+ /* Artist of track */
481+ Label {
482+ id: nowPlayingWideAspectArtist
483+ anchors {
484+ left: parent.left
485+ leftMargin: units.gu(1)
486+ right: parent.right
487+ rightMargin: units.gu(1)
488+ }
489+ color: styleMusic.nowPlaying.labelSecondaryColor
490+ elide: Text.ElideRight
491+ fontSize: "small"
492+ text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist
493+ }
494+ }
495+
496+ /* Progress bar component */
497+ MouseArea {
498+ id: musicToolbarFullProgressContainer
499+ anchors.left: parent.left
500+ anchors.leftMargin: units.gu(3)
501+ anchors.right: parent.right
502+ anchors.rightMargin: units.gu(3)
503+ anchors.top: nowPlayingWideAspectLabels.bottom
504+ anchors.topMargin: units.gu(3)
505+ height: units.gu(3)
506+ width: parent.width
507+
508+ /* Position label */
509+ Label {
510+ id: musicToolbarFullPositionLabel
511+ anchors.top: progressSliderMusic.bottom
512+ anchors.topMargin: units.gu(-2)
513+ anchors.left: parent.left
514+ color: styleMusic.nowPlaying.labelSecondaryColor
515+ fontSize: "small"
516+ height: parent.height
517+ horizontalAlignment: Text.AlignHCenter
518+ text: durationToString(player.position)
519+ verticalAlignment: Text.AlignVCenter
520+ width: units.gu(3)
521+ }
522+
523+ Slider {
524+ id: progressSliderMusic
525+ anchors.left: parent.left
526+ anchors.right: parent.right
527+ objectName: "progressSliderShape"
528+
529+ function formatValue(v) {
530+ if (seeking) { // update position label while dragging
531+ musicToolbarFullPositionLabel.text = durationToString(v)
532+ }
533+
534+ return durationToString(v)
535+ }
536+
537+ property bool seeking: false
538+ property bool seeked: false
539+
540+ onSeekingChanged: {
541+ if (seeking === false) {
542+ musicToolbarFullPositionLabel.text = durationToString(player.position)
543+ }
544+ }
545+
546+ Component.onCompleted: {
547+ Theme.palette.selected.foreground = UbuntuColors.blue
548+ }
549+
550+ onPressedChanged: {
551+ seeking = pressed
552+ if (!pressed) {
553+ seeked = true
554+ player.seek(value)
555+ }
556+ }
557+
558+ Connections {
559+ target: player
560+ onDurationChanged: {
561+ musicToolbarFullDurationLabel.text = durationToString(player.duration)
562+ progressSliderMusic.maximumValue = player.duration
563+ }
564+ onPositionChanged: {
565+ // seeked is a workaround for bug 1310706 as the first position after a seek is sometimes invalid (0)
566+ if (progressSliderMusic.seeking === false && !progressSliderMusic.seeked) {
567+ progressSliderMusic.value = player.position
568+ musicToolbarFullPositionLabel.text = durationToString(player.position)
569+ musicToolbarFullDurationLabel.text = durationToString(player.duration)
570+ }
571+
572+ progressSliderMusic.seeked = false;
573+ }
574+ onStopped: {
575+ musicToolbarFullPositionLabel.text = durationToString(0);
576+ musicToolbarFullDurationLabel.text = durationToString(0);
577+ }
578+ }
579+ }
580+
581+ /* Duration label */
582+ Label {
583+ id: musicToolbarFullDurationLabel
584+ anchors.top: progressSliderMusic.bottom
585+ anchors.topMargin: units.gu(-2)
586+ anchors.right: parent.right
587+ color: styleMusic.nowPlaying.labelSecondaryColor
588+ fontSize: "small"
589+ height: parent.height
590+ horizontalAlignment: Text.AlignHCenter
591+ text: durationToString(player.duration)
592+ verticalAlignment: Text.AlignVCenter
593+ width: units.gu(3)
594+ }
595+ }
596+
597+ /* Repeat button */
598+ MouseArea {
599+ id: nowPlayingRepeatButton
600+ anchors.right: nowPlayingPreviousButton.left
601+ anchors.rightMargin: units.gu(1)
602+ anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
603+ height: units.gu(6)
604+ opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
605+ width: height
606+ onClicked: player.repeat = !player.repeat
607+
608+ Icon {
609+ id: repeatIcon
610+ height: units.gu(3)
611+ width: height
612+ anchors.verticalCenter: parent.verticalCenter
613+ anchors.horizontalCenter: parent.horizontalCenter
614+ color: "white"
615+ name: "media-playlist-repeat"
616+ objectName: "repeatShape"
617+ opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
618+ }
619+ }
620+
621+ /* Previous button */
622+ MouseArea {
623+ id: nowPlayingPreviousButton
624+ anchors.right: nowPlayingPlayButton.left
625+ anchors.rightMargin: units.gu(1)
626+ anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
627+ height: units.gu(6)
628+ opacity: trackQueue.model.count === 0 ? .4 : 1
629+ width: height
630+ onClicked: player.previousSong()
631+
632+ Icon {
633+ id: nowPlayingPreviousIndicator
634+ height: units.gu(3)
635+ width: height
636+ anchors.verticalCenter: parent.verticalCenter
637+ anchors.horizontalCenter: parent.horizontalCenter
638+ color: "white"
639+ name: "media-skip-backward"
640+ objectName: "previousShape"
641+ opacity: 1
642+ }
643+ }
644+
645+ /* Play/Pause button */
646+ MouseArea {
647+ id: nowPlayingPlayButton
648+ anchors.horizontalCenter: parent.horizontalCenter
649+ anchors.top: musicToolbarFullProgressContainer.bottom
650+ anchors.topMargin: units.gu(2)
651+ height: units.gu(12)
652+ width: height
653+ onClicked: player.toggle()
654+
655+ Icon {
656+ id: nowPlayingPlayIndicator
657+ height: units.gu(6)
658+ width: height
659+ anchors.verticalCenter: parent.verticalCenter
660+ anchors.horizontalCenter: parent.horizontalCenter
661+ opacity: emptyPage.noMusic ? .4 : 1
662+ color: "white"
663+ name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start"
664+ objectName: "playShape"
665+ }
666+ }
667+
668+ /* Next button */
669+ MouseArea {
670+ id: nowPlayingNextButton
671+ anchors.left: nowPlayingPlayButton.right
672+ anchors.leftMargin: units.gu(1)
673+ anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
674+ height: units.gu(6)
675+ opacity: trackQueue.model.count === 0 ? .4 : 1
676+ width: height
677+ onClicked: player.nextSong()
678+
679+ Icon {
680+ id: nowPlayingNextIndicator
681+ height: units.gu(3)
682+ width: height
683+ anchors.verticalCenter: parent.verticalCenter
684+ anchors.horizontalCenter: parent.horizontalCenter
685+ color: "white"
686+ name: "media-skip-forward"
687+ objectName: "forwardShape"
688+ opacity: 1
689+ }
690+ }
691+
692+ /* Shuffle button */
693+ MouseArea {
694+ id: nowPlayingShuffleButton
695+ anchors.left: nowPlayingNextButton.right
696+ anchors.leftMargin: units.gu(1)
697+ anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
698+ height: units.gu(6)
699+ opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
700+ width: height
701+ onClicked: player.shuffle = !player.shuffle
702+
703+ Icon {
704+ id: shuffleIcon
705+ height: units.gu(3)
706+ width: height
707+ anchors.verticalCenter: parent.verticalCenter
708+ anchors.horizontalCenter: parent.horizontalCenter
709+ color: "white"
710+ name: "media-playlist-shuffle"
711+ objectName: "shuffleShape"
712+ opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
713+ }
714+ }
715+ }
716 }
717
718 ListView {
719 id: queuelist
720- objectName: "nowPlayingQueueList"
721- anchors.fill: parent
722- anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
723+ anchors {
724+ fill: parent
725+ topMargin: units.gu(2)
726+ }
727 delegate: queueDelegate
728+ footer: Item {
729+ height: mainView.height - (styleMusic.common.expandHeight + queuelist.currentHeight) + units.gu(8)
730+ }
731 model: trackQueue.model
732- highlightFollowsCurrentItem: false
733+ objectName: "nowPlayingQueueList"
734 state: "normal"
735 states: [
736 State {
737@@ -105,33 +406,29 @@
738 }
739 }
740 ]
741- footer: Item {
742- height: mainView.height - (styleMusic.common.expandHeight + queuelist.currentHeight) + units.gu(8)
743- }
744+ visible: isListView
745
746- property int normalHeight: units.gu(12)
747- property int currentHeight: units.gu(40)
748+ property int normalHeight: units.gu(6)
749 property int transitionDuration: 250 // transition length of animations
750
751 onCountChanged: {
752 customdebug("Queue: Now has: " + queuelist.count + " tracks")
753 }
754
755- onMovementStarted: {
756- musicToolbar.hideToolbar();
757- }
758-
759 Component {
760 id: queueDelegate
761 ListItemWithActions {
762 id: queueListItem
763- color: "transparent"
764+ color: player.currentIndex === index ? "#2c2c34" : "transparent"
765 height: queuelist.normalHeight
766 objectName: "nowPlayingListItem" + index
767- state: queuelist.currentIndex == index && !reordering ? "current" : ""
768+ showDivider: false
769+ state: ""
770
771 leftSideAction: Remove {
772 onTriggered: {
773+ var removedIndex = index
774+
775 if (queuelist.count === 1) {
776 player.stop()
777 musicToolbar.goBack()
778@@ -139,12 +436,12 @@
779 player.nextSong(player.isPlaying);
780 }
781
782- if (index < player.currentIndex) {
783+ queuelist.model.remove(index);
784+
785+ if (removedIndex < player.currentIndex) {
786 // update index as the old has been removed
787 player.currentIndex -= 1;
788 }
789-
790- queuelist.model.remove(index);
791 }
792 }
793 reorderable: true
794@@ -177,14 +474,10 @@
795 }
796 }
797
798- // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
799- onPressedChanged: trackImage.pressed = pressed
800-
801 Rectangle {
802 id: trackContainer;
803 anchors {
804 fill: parent
805- margins: units.gu(1)
806 }
807 color: "transparent"
808
809@@ -204,159 +497,28 @@
810 to: units.gu(0.5)
811 }
812
813- CoverRow {
814- id: trackImage
815-
816- anchors {
817- top: parent.top
818- left: parent.left
819- leftMargin: units.gu(1.5)
820- }
821- count: 1
822- size: (queueListItem.state === "current"
823- ? (mainView.wideAspect
824- ? queuelist.currentHeight
825- : mainView.width - (trackImage.anchors.leftMargin * 2))
826- : queuelist.normalHeight) - units.gu(2)
827- covers: [{art: model.art}]
828-
829- spacing: units.gu(2)
830-
831- Item { // Background so can see text in current state
832- id: albumBg
833- visible: false
834- anchors {
835- bottom: parent.bottom
836- left: parent.left
837- right: parent.right
838- }
839- height: units.gu(9)
840- clip: true
841- UbuntuShape{
842- anchors {
843- bottom: parent.bottom
844- left: parent.left
845- right: parent.right
846- }
847- height: trackImage.height
848- radius: "medium"
849- color: styleMusic.common.black
850- opacity: 0.6
851- }
852- }
853-
854- function calcAnchors() {
855- if (trackImage.height > queuelist.normalHeight && mainView.wideAspect) {
856- trackImage.anchors.left = undefined
857- trackImage.anchors.horizontalCenter = trackImage.parent.horizontalCenter
858- } else {
859- trackImage.anchors.left = trackImage.parent.left
860- trackImage.anchors.horizontalCenter = undefined
861- }
862-
863- trackImage.width = trackImage.height; // force width to match height
864- }
865-
866- Connections {
867- target: mainView
868- onWideAspectChanged: trackImage.calcAnchors()
869- }
870-
871- onHeightChanged: {
872- calcAnchors()
873- }
874- Behavior on height {
875- NumberAnimation {
876- target: trackImage;
877- property: "height";
878- duration: queuelist.transitionDuration;
879- }
880- }
881- }
882- Label {
883- id: nowPlayingArtist
884- objectName: "artistLabel"
885- color: styleMusic.nowPlaying.labelSecondaryColor
886- elide: Text.ElideRight
887- height: units.gu(1)
888- text: model.author
889- fontSize: 'small'
890- width: parent.width - trackImage.width - units.gu(3.5)
891- x: trackImage.x + trackImage.width + units.gu(1)
892- y: trackImage.y + units.gu(1)
893- }
894- Label {
895- id: nowPlayingTitle
896- objectName: "titleLabel"
897- color: styleMusic.common.white
898- elide: Text.ElideRight
899- height: units.gu(1)
900- text: model.title
901- fontSize: 'medium'
902- width: parent.width - trackImage.width - units.gu(3.5)
903- x: trackImage.x + trackImage.width + units.gu(1)
904- y: nowPlayingArtist.y + nowPlayingArtist.height + units.gu(1.25)
905- }
906- Label {
907- id: nowPlayingAlbum
908- objectName: "albumLabel"
909- color: styleMusic.nowPlaying.labelSecondaryColor
910- elide: Text.ElideRight
911- height: units.gu(1)
912- text: model.album
913- fontSize: 'x-small'
914- width: parent.width - trackImage.width - units.gu(3.5)
915- x: trackImage.x + trackImage.width + units.gu(1)
916- y: nowPlayingTitle.y + nowPlayingTitle.height + units.gu(1.25)
917- }
918- }
919-
920- states: State {
921- name: "current"
922- PropertyChanges {
923- target: queueListItem
924- height: trackImage.size + (trackContainer.anchors.margins * 2)
925- }
926- PropertyChanges {
927- target: nowPlayingArtist
928- width: trackImage.width - units.gu(4)
929- x: trackImage.x + units.gu(2)
930- y: trackImage.y + trackImage.height - albumBg.height + units.gu(1)
931- color: styleMusic.common.white
932- }
933- PropertyChanges {
934- target: nowPlayingTitle
935- width: trackImage.width - units.gu(4)
936- x: trackImage.x + units.gu(2)
937- y: nowPlayingArtist.y + nowPlayingArtist.height + units.gu(1.25)
938- color: styleMusic.common.white
939- font.weight: Font.DemiBold
940- }
941- PropertyChanges {
942- target: nowPlayingAlbum
943- width: trackImage.width - units.gu(4)
944- x: trackImage.x + units.gu(2)
945- y: nowPlayingTitle.y + nowPlayingTitle.height + units.gu(1.25)
946- color: styleMusic.common.white
947- }
948- PropertyChanges {
949- target: albumBg
950- visible: true
951- }
952- }
953- transitions: Transition {
954- from: ",current"
955- to: "current,"
956- NumberAnimation {
957- duration: queuelist.transitionDuration
958- properties: "height,opacity,width,x,y"
959- }
960-
961- onRunningChanged: {
962- if (running === false && ensureVisibleIndex != -1)
963- {
964- queuelist.positionViewAtIndex(ensureVisibleIndex, ListView.Beginning);
965- ensureVisibleIndex = -1;
966+ MusicRow {
967+ id: musicRow
968+ covers: [{art: model.art, album: model.album, author: model.author}]
969+ showCovers: false
970+ coverSize: units.gu(6)
971+ column: Column {
972+ Label {
973+ id: trackTitle
974+ color: player.currentIndex === index ? UbuntuColors.blue
975+ : styleMusic.common.music
976+ fontSize: "small"
977+ objectName: "titleLabel"
978+ text: model.title
979+ }
980+
981+ Label {
982+ id: trackArtist
983+ color: styleMusic.common.subtitle
984+ fontSize: "x-small"
985+ objectName: "artistLabel"
986+ text: model.author
987+ }
988 }
989 }
990 }
991
992=== modified file 'MusicPlaylists.qml'
993--- MusicPlaylists.qml 2014-09-20 10:50:45 +0000
994+++ MusicPlaylists.qml 2014-10-16 23:15:23 +0000
995@@ -23,170 +23,53 @@
996 import Ubuntu.Components.Popups 1.0
997 import QtMultimedia 5.0
998 import QtQuick.LocalStorage 2.0
999-import "settings.js" as Settings
1000-import "scrobble.js" as Scrobble
1001 import "playlists.js" as Playlists
1002 import "common"
1003-import "common/ListItemActions"
1004
1005 // page for the playlists
1006 MusicPage {
1007- id: listspage
1008+ id: playlistsPage
1009 objectName: "playlistsPage"
1010 // TRANSLATORS: this is the name of the playlists page shown in the tab header.
1011 // Remember to keep the translation short to fit the screen width
1012 title: i18n.tr("Playlists")
1013
1014 property string playlistTracks: ""
1015- property string oldPlaylistName: ""
1016 property string inPlaylist: ""
1017
1018- tools: ToolbarItems {
1019- ToolbarButton {
1020- action: Action {
1021+ head {
1022+ actions: [
1023+ Action {
1024 objectName: "newplaylistButton"
1025- text: i18n.tr("New playlist")
1026 iconName: "add"
1027 onTriggered: {
1028 customdebug("New playlist.")
1029 PopupUtils.open(newPlaylistDialog, mainView)
1030 }
1031 }
1032- }
1033- }
1034-
1035- // Edit name of playlist dialog
1036- Component {
1037- id: editPlaylistDialog
1038- Dialog {
1039- id: dialogEditPlaylist
1040- // TRANSLATORS: this is a title of a dialog with a prompt to rename a playlist
1041- title: i18n.tr("Change name")
1042- text: i18n.tr("Enter the new name of the playlist.")
1043- TextField {
1044- id: playlistName
1045- placeholderText: oldPlaylistName
1046- inputMethodHints: Qt.ImhNoPredictiveText
1047- }
1048- Label {
1049- id: editplaylistoutput
1050- color: "red"
1051- visible: false
1052- }
1053-
1054- Button {
1055- text: i18n.tr("Change")
1056- color: styleMusic.dialog.confirmButtonColor
1057- onClicked: {
1058- editplaylistoutput.visible = true
1059-
1060- if (playlistName.text.length > 0) { // make sure something is acually inputed
1061- console.debug("Debug: User changed name from "+oldPlaylistName+" to "+playlistName.text)
1062-
1063- if (Playlists.renamePlaylist(oldPlaylistName, playlistName.text) === true) {
1064- playlistModel.filterPlaylists()
1065-
1066- PopupUtils.close(dialogEditPlaylist)
1067-
1068- if (inPlaylist) {
1069- playlistInfoLabel.text = playlistName.text
1070- }
1071- }
1072- else {
1073- editplaylistoutput.text = i18n.tr("Playlist already exists")
1074- }
1075- }
1076- else {
1077- editplaylistoutput.text = i18n.tr("Please type in a name.")
1078- }
1079- }
1080- }
1081- Button {
1082- text: i18n.tr("Cancel")
1083- color: styleMusic.dialog.cancelButtonColor
1084- onClicked: PopupUtils.close(dialogEditPlaylist)
1085- }
1086- }
1087- }
1088-
1089- MusicSettings {
1090- id: musicSettings
1091- }
1092-
1093- ListView {
1094+ ]
1095+ }
1096+
1097+ CardView {
1098 id: playlistslist
1099- objectName: "playlistsListView"
1100- anchors.fill: parent
1101- anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
1102 model: playlistModel.model
1103- delegate: playlistDelegate
1104- onCountChanged: {
1105- customdebug("onCountChanged: " + playlistslist.count)
1106- }
1107- onCurrentIndexChanged: {
1108- customdebug("tracklist.currentIndex = " + playlistslist.currentIndex)
1109- }
1110-
1111- Component {
1112- id: playlistDelegate
1113- ListItemWithActions {
1114- id: playlist
1115- property string name: model.name
1116- property string count: model.count
1117- property var covers: Playlists.getPlaylistCovers(name)
1118-
1119- color: "transparent"
1120- height: styleMusic.common.itemHeight
1121- width: parent.width
1122-
1123- leftSideAction: DeletePlaylist {
1124- onTriggered: {
1125- Playlists.removePlaylist(model.name)
1126-
1127- playlistModel.filterPlaylists();
1128- }
1129- }
1130-
1131- rightSideActions: [
1132- EditPlaylist {
1133- }
1134- ]
1135- triggerActionOnMouseRelease: true
1136-
1137- onItemClicked: {
1138- albumTracksModel.filterPlaylistTracks(name)
1139- songsPage.isAlbum = false
1140- songsPage.line1 = i18n.tr("Playlist")
1141- songsPage.line2 = model.name
1142- songsPage.covers = playlist.covers
1143- songsPage.genre = undefined
1144- songsPage.title = i18n.tr("Playlist")
1145-
1146- mainPageStack.push(songsPage)
1147- }
1148-
1149- // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
1150- onPressedChanged: musicRow.pressed = pressed
1151-
1152- MusicRow {
1153- id: musicRow
1154- covers: playlist.covers
1155- column: Column {
1156- spacing: units.gu(1)
1157- Label {
1158- id: playlistCount
1159- color: styleMusic.common.subtitle
1160- fontSize: "x-small"
1161- text: i18n.tr("%1 song", "%1 songs", playlist.count).arg(playlist.count)
1162- }
1163- Label {
1164- id: playlistName
1165- color: styleMusic.common.music
1166- fontSize: "medium"
1167- text: playlist.name
1168- }
1169- }
1170- }
1171+ objectName: "playlistsCardView"
1172+ delegate: Card {
1173+ id: playlistCard
1174+ coverSources: Playlists.getPlaylistCovers(name)
1175+ primaryText: name
1176+ secondaryText: i18n.tr("%1 song", "%1 songs", count).arg(count)
1177+
1178+ onClicked: {
1179+ albumTracksModel.filterPlaylistTracks(name)
1180+ songsPage.isAlbum = false
1181+ songsPage.line1 = i18n.tr("Playlist")
1182+ songsPage.line2 = model.name
1183+ songsPage.covers = coverSources
1184+ songsPage.genre = undefined
1185+ songsPage.title = i18n.tr("Playlist")
1186+
1187+ mainPageStack.push(songsPage)
1188 }
1189 }
1190 }
1191
1192=== modified file 'MusicSettings.qml'
1193--- MusicSettings.qml 2014-09-20 10:50:45 +0000
1194+++ MusicSettings.qml 2014-10-16 23:15:23 +0000
1195@@ -30,17 +30,6 @@
1196 title: i18n.tr("Settings")
1197 contentsHeight: parent.height;
1198
1199- onVisibleChanged: {
1200- if (visible === true)
1201- {
1202- musicToolbar.disableToolbar()
1203- }
1204- else
1205- {
1206- musicToolbar.enableToolbar()
1207- }
1208- }
1209-
1210 onCancelClicked: PopupUtils.close(musicSettings)
1211 onConfirmClicked: {
1212 PopupUtils.close(musicSettings)
1213
1214=== modified file 'MusicStart.qml'
1215--- MusicStart.qml 2014-09-20 15:41:33 +0000
1216+++ MusicStart.qml 2014-10-16 23:15:23 +0000
1217@@ -32,482 +32,45 @@
1218
1219 MusicPage {
1220 id: mainpage
1221- title: i18n.tr("Music")
1222+ title: i18n.tr("Recent")
1223
1224- /* Dev button for search.
1225- Button {
1226- id: searchButton
1227- text: i18n.tr("Search")
1228- anchors.top: parent.top
1229- anchors.topMargin: units.gu(2)
1230- anchors.bottom: recentlyPlayed.top
1231- anchors.bottomMargin: units.gu(1)
1232- height: units.gu(4)
1233- onClicked: {
1234- PopupUtils.open(Qt.resolvedUrl("MusicSearch.qml"), mainView,
1235- {
1236- title: i18n.tr("Search")
1237- } )
1238- }
1239+ head {
1240+ actions: [
1241+ Action {
1242+ iconName: "edit-clear"
1243+ onTriggered: {
1244+ Library.clearRecentHistory()
1245+ recentModel.filterRecent()
1246+ }
1247+ }
1248+ ]
1249 }
1250- */
1251- Flickable{
1252- id: musicFlickable
1253- anchors.fill: parent
1254-
1255- width: mainpage.width
1256- height: mainpage.height
1257-
1258- contentHeight: mainView.hasRecent ? recentlyPlayed.height + recentlist.height + genres.height + genrelist.height + albums.height + albumlist.height + units.gu(4)
1259- : genres.height + genrelist.height + albums.height + albumlist.height + units.gu(3)
1260- contentWidth: width
1261-
1262- focus: true
1263-
1264- ListItem.Standard {
1265- id: recentlyPlayed
1266- Label {
1267- anchors {
1268- verticalCenter: parent.verticalCenter
1269- left: parent.left
1270- leftMargin: units.gu(2)
1271- }
1272- text: i18n.tr("Recent")
1273- color: styleMusic.common.music
1274- }
1275- visible: mainView.hasRecent
1276- }
1277-
1278- ListView {
1279- id: recentlist
1280- anchors.top: recentlyPlayed.bottom
1281- anchors.topMargin: units.gu(1)
1282- width: parent.width
1283- spacing: units.gu(1)
1284- height: units.gu(18)
1285- // TODO: Update when view counts are collected
1286- model: recentModel.model
1287- delegate: recentDelegate
1288- header: Item {
1289- id: recentSpacer
1290- width: units.gu(1)
1291- }
1292- footer: Item {
1293- id: clearRecent
1294- width: recentlist.height - units.gu(2)
1295- height: width
1296- visible: mainView.hasRecent && !loading.visible
1297- Button {
1298- id: clearRecentButton
1299- anchors.centerIn: parent
1300- text: i18n.tr("Clear History")
1301- onClicked: {
1302- Library.clearRecentHistory()
1303- mainView.hasRecent = false
1304- recentModel.filterRecent()
1305- }
1306- }
1307- }
1308- orientation: ListView.Horizontal
1309- visible: mainView.hasRecent
1310-
1311- Component {
1312- id: recentDelegate
1313- Item {
1314- property string title: model.title
1315- property string title2: model.title2 !== "Playlist" ? model.title2 : i18n.tr("Playlist")
1316- property var covers: type === "playlist" ? Playlists.getPlaylistCovers(title) : (model.art !== undefined ? [{art: model.art}] : [{author: model.title2, album: model.title}])
1317- property string type: model.type
1318- property string time: model.time
1319- property string key: model.key
1320- id: recentItem
1321- height: recentlist.height - units.gu(1)
1322- width: height
1323- CoverRow {
1324- id: recentShape
1325- anchors {
1326- top: parent.top
1327- left: parent.left
1328- verticalCenter: parent.verticalCenter
1329- }
1330- count: recentItem.covers.length
1331- size: recentItem.width
1332- covers: recentItem.covers
1333- spacing: units.gu(2)
1334- }
1335- Item { // Background so can see text in current state
1336- id: albumBg
1337- anchors {
1338- bottom: parent.bottom
1339- left: parent.left
1340- right: parent.right
1341- }
1342- height: units.gu(6)
1343- clip: true
1344- UbuntuShape{
1345- anchors {
1346- bottom: parent.bottom
1347- left: parent.left
1348- right: parent.right
1349- }
1350- height: recentShape.height
1351- radius: "medium"
1352- color: styleMusic.common.black
1353- opacity: 0.6
1354- }
1355- }
1356- Label {
1357- id: albumArtist
1358- anchors.bottom: parent.bottom
1359- anchors.bottomMargin: units.gu(3)
1360- anchors.left: parent.left
1361- anchors.leftMargin: units.gu(1)
1362- anchors.right: parent.right
1363- anchors.rightMargin: units.gu(1)
1364- color: styleMusic.common.white
1365- elide: Text.ElideRight
1366- text: title
1367- fontSize: "small"
1368- font.weight: Font.DemiBold
1369- }
1370- Label {
1371- id: albumLabel
1372- anchors.left: parent.left
1373- anchors.leftMargin: units.gu(1)
1374- anchors.bottom: parent.bottom
1375- anchors.bottomMargin: units.gu(1)
1376- anchors.right: parent.right
1377- anchors.rightMargin: units.gu(1)
1378- color: styleMusic.common.white
1379- elide: Text.ElideRight
1380- text: title2
1381- fontSize: "x-small"
1382- }
1383- MouseArea {
1384- anchors.fill: parent
1385- onClicked: {
1386- if (type === "playlist") {
1387- albumTracksModel.filterPlaylistTracks(key)
1388- } else {
1389- songsPage.album = title;
1390- }
1391- songsPage.genre = undefined;
1392-
1393- songsPage.line1 = title2
1394- songsPage.line2 = title
1395- songsPage.covers = recentItem.covers
1396- songsPage.isAlbum = (type === "album")
1397- songsPage.title = songsPage.isAlbum ? i18n.tr("Album") : i18n.tr("Playlist")
1398-
1399- mainPageStack.push(songsPage)
1400- }
1401-
1402- // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
1403- onPressedChanged: recentShape.pressed = pressed
1404- }
1405- }
1406- }
1407- }
1408-
1409- ListItem.ThinDivider {
1410- id: genreDivider
1411- anchors.top: mainView.hasRecent ? recentlist.bottom : parent.top
1412- visible: genrelist.count > 1
1413- }
1414- ListItem.Standard {
1415- id: genres
1416- anchors.top: genreDivider.bottom
1417- visible: genrelist.count > 1
1418- Label {
1419- anchors {
1420- verticalCenter: parent.verticalCenter
1421- left: parent.left
1422- leftMargin: units.gu(2)
1423- }
1424- text: i18n.tr("Genres")
1425- color: styleMusic.common.music
1426- }
1427- }
1428- // TODO: add music genres. frequency of play? most tracks?
1429- ListView {
1430- id: genrelist
1431- width: parent.width
1432- anchors.top: genres.bottom
1433- anchors.topMargin: units.gu(1)
1434- spacing: units.gu(1)
1435- height: units.gu(18)
1436- visible: genrelist.count > 1
1437- model: SortFilterModel {
1438- id: genresModelFilter
1439- model: GenresModel {
1440- id: genresModel
1441- store: musicStore
1442- }
1443- filter.property: "genre"
1444- filter.pattern: /\S+/
1445- }
1446-
1447- delegate: genreDelegate
1448- header: Item {
1449- id: genreSpacer
1450- width: units.gu(1)
1451- }
1452- orientation: ListView.Horizontal
1453-
1454- Component {
1455- id: genreDelegate
1456- Item {
1457- id: genreItem
1458- objectName: "genreItemObject"
1459- height: genrelist.height - units.gu(1)
1460- width: height
1461-
1462- Repeater {
1463- id: albumGenreModelRepeater
1464- model: AlbumsModel {
1465- genre: model.genre
1466- store: musicStore
1467- }
1468-
1469- delegate: Item {
1470- property string art: model.art
1471- }
1472- property var covers: []
1473- signal finished()
1474-
1475- onFinished: {
1476- genreShape.count = count
1477- genreShape.covers = covers
1478- }
1479- onItemAdded: {
1480- covers.push({art: item.art});
1481-
1482- if (index === count - 1) {
1483- finished();
1484- }
1485- }
1486- }
1487-
1488- SongsModel {
1489- id: songGenreModel
1490- genre: model.genre
1491- store: musicStore
1492- }
1493-
1494- CoverRow {
1495- id: genreShape
1496- anchors {
1497- top: parent.top
1498- left: parent.left
1499- verticalCenter: parent.verticalCenter
1500- }
1501- count: 0
1502- size: genreItem.width
1503- covers: []
1504- spacing: units.gu(2)
1505- }
1506- MouseArea {
1507- anchors.fill: parent
1508- onClicked: {
1509- songsPage.album = undefined
1510- songsPage.covers = genreShape.covers
1511- songsPage.genre = model.genre
1512- songsPage.isAlbum = true
1513- songsPage.line1 = i18n.tr("Genre")
1514- songsPage.line2 = model.genre
1515- songsPage.title = i18n.tr("Genre")
1516-
1517- mainPageStack.push(songsPage)
1518- }
1519-
1520- // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
1521- onPressedChanged: genreShape.pressed = pressed
1522- }
1523- Item { // Background so can see text in current state
1524- id: genreBg
1525- anchors {
1526- bottom: parent.bottom
1527- left: parent.left
1528- right: parent.right
1529- }
1530- height: units.gu(5.5)
1531- clip: true
1532- UbuntuShape{
1533- anchors {
1534- bottom: parent.bottom
1535- left: parent.left
1536- right: parent.right
1537- }
1538- height: genreShape.height
1539- radius: "medium"
1540- color: styleMusic.common.black
1541- opacity: 0.6
1542- }
1543- }
1544- Label {
1545- id: genreLabel
1546- anchors.bottom: parent.bottom
1547- anchors.bottomMargin: units.gu(1)
1548- anchors.left: parent.left
1549- anchors.leftMargin: units.gu(1)
1550- anchors.right: parent.right
1551- anchors.rightMargin: units.gu(1)
1552- color: styleMusic.common.white
1553- elide: Text.ElideRight
1554- text: model.genre
1555- fontSize: "small"
1556- font.weight: Font.DemiBold
1557- }
1558- Label {
1559- id: genreTotal
1560- anchors.bottom: parent.bottom
1561- anchors.bottomMargin: units.gu(3)
1562- anchors.left: parent.left
1563- anchors.leftMargin: units.gu(1)
1564- anchors.right: parent.right
1565- anchors.rightMargin: units.gu(1)
1566- color: styleMusic.common.white
1567- elide: Text.ElideRight
1568- text: i18n.tr("%1 song", "%1 songs", songGenreModel.rowCount).arg(songGenreModel.rowCount)
1569- fontSize: "x-small"
1570- }
1571- }
1572- }
1573- }
1574-
1575- ListItem.ThinDivider {
1576- id: albumsDivider
1577- anchors.top: genrelist.visible
1578- ? genrelist.bottom
1579- : (mainView.hasRecent ? recentlist.bottom : parent.top)
1580- }
1581- ListItem.Standard {
1582- id: albums
1583- Label {
1584- anchors {
1585- verticalCenter: parent.verticalCenter
1586- left: parent.left
1587- leftMargin: units.gu(2)
1588- }
1589- text: i18n.tr("Albums")
1590- color: styleMusic.common.music
1591- }
1592- anchors.top: albumsDivider.bottom
1593- }
1594-
1595- ListView {
1596- id: albumlist
1597- width: parent.width
1598- anchors.top: albums.bottom
1599- anchors.topMargin: units.gu(1)
1600- spacing: units.gu(1)
1601- height: units.gu(18)
1602- model: SortFilterModel {
1603- id: albumsModelFilter
1604- property alias rowCount: albumsModel.rowCount
1605- model: AlbumsModel {
1606- id: albumsModel
1607- store: musicStore
1608- }
1609- sort.property: "title"
1610- sort.order: Qt.AscendingOrder
1611- }
1612- delegate: albumDelegate
1613- header: Item {
1614- id: albumSpacer
1615- width: units.gu(1)
1616- }
1617- orientation: ListView.Horizontal
1618-
1619- Component {
1620- id: albumDelegate
1621- Item {
1622- property string artist: model.artist
1623- property string album: model.title
1624- property var covers: [{art: model.art}]
1625-
1626- id: albumItem
1627- objectName: "albumItemObject"
1628- height: albumlist.height - units.gu(1)
1629- width: height
1630- CoverRow {
1631- id: albumShape
1632- anchors {
1633- top: parent.top
1634- left: parent.left
1635- verticalCenter: parent.verticalCenter
1636- }
1637- count: albumItem.covers.length
1638- size: albumItem.width
1639- covers: albumItem.covers
1640- spacing: units.gu(2)
1641- }
1642- MouseArea {
1643- anchors.fill: parent
1644- onClicked: {
1645- songsPage.album = album
1646- songsPage.covers = covers
1647- songsPage.genre = undefined
1648- songsPage.isAlbum = true
1649- songsPage.line1 = artist
1650- songsPage.line2 = album
1651- songsPage.title = i18n.tr("Album")
1652-
1653- mainPageStack.push(songsPage)
1654- }
1655-
1656- // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
1657- onPressedChanged: albumShape.pressed = pressed
1658- }
1659- Item { // Background so can see text in current state
1660- id: albumBg
1661- anchors {
1662- bottom: parent.bottom
1663- left: parent.left
1664- right: parent.right
1665- }
1666- height: units.gu(6)
1667- clip: true
1668- UbuntuShape{
1669- anchors {
1670- bottom: parent.bottom
1671- left: parent.left
1672- right: parent.right
1673- }
1674- height: albumShape.height
1675- radius: "medium"
1676- color: styleMusic.common.black
1677- opacity: 0.6
1678- }
1679- }
1680- Label {
1681- id: albumLabel
1682- anchors.bottom: parent.bottom
1683- anchors.bottomMargin: units.gu(1)
1684- anchors.left: parent.left
1685- anchors.leftMargin: units.gu(1)
1686- anchors.right: parent.right
1687- anchors.rightMargin: units.gu(1)
1688- color: styleMusic.common.white
1689- elide: Text.ElideRight
1690- text: artist
1691- fontSize: "x-small"
1692- }
1693- Label {
1694- id: albumLabel2
1695- anchors.bottom: parent.bottom
1696- anchors.bottomMargin: units.gu(3)
1697- anchors.left: parent.left
1698- anchors.leftMargin: units.gu(1)
1699- anchors.right: parent.right
1700- anchors.rightMargin: units.gu(1)
1701- color: styleMusic.common.white
1702- elide: Text.ElideRight
1703- text: album
1704- fontSize: "small"
1705- font.weight: Font.DemiBold
1706- }
1707- }
1708+
1709+ CardView {
1710+ id: recentCardView
1711+ model: recentModel.model
1712+ delegate: Card {
1713+ id: albumCard
1714+ coverSources: model.type === "playlist" ? Playlists.getPlaylistCovers(title) : (model.art !== undefined ? [{art: model.art}] : [{author: model.title2, album: model.title}])
1715+ objectName: "albumsPageGridItem" + index
1716+ primaryText: model.title
1717+ secondaryText: model.title2 !== "Playlist" ? model.title2 : i18n.tr("Playlist")
1718+
1719+ onClicked: {
1720+ if (type === "playlist") {
1721+ albumTracksModel.filterPlaylistTracks(model.key)
1722+ } else {
1723+ songsPage.album = title;
1724+ }
1725+ songsPage.genre = undefined;
1726+
1727+ songsPage.line1 = secondaryText
1728+ songsPage.line2 = primaryText
1729+ songsPage.covers = coverSources
1730+ songsPage.isAlbum = (type === "album")
1731+ songsPage.title = songsPage.isAlbum ? i18n.tr("Album") : i18n.tr("Playlist")
1732+
1733+ mainPageStack.push(songsPage)
1734 }
1735 }
1736 }
1737
1738=== modified file 'MusicToolbar.qml'
1739--- MusicToolbar.qml 2014-09-23 20:45:41 +0000
1740+++ MusicToolbar.qml 2014-10-16 23:15:23 +0000
1741@@ -35,59 +35,13 @@
1742 property var currentPage: null
1743 property var currentSheet: []
1744 property var currentTab: null
1745- property var previousPage: null
1746
1747 // Properties and signals for the toolbar
1748- property var cachedStates: []
1749- property bool shown: false
1750- property int transitionDuration: 100
1751-
1752 property alias currentHeight: musicToolbarPanel.height
1753- property alias minimizedHeight: musicToolbarPanel.minimizedHeight
1754- property alias expandedHeight: musicToolbarPanel.expandedHeight
1755- property alias fullHeight: musicToolbarPanel.fullHeight
1756- property alias mouseAreaOffset: musicToolbarPanel.hintSize
1757-
1758- property alias animating: musicToolbarPanel.animating
1759 property alias opened: musicToolbarPanel.opened
1760
1761- // Alias for autopilot
1762- property alias currentMode: musicToolbarPanel.currentMode
1763-
1764- Connections {
1765- id: pageStackConn
1766- target: mainPageStack
1767-
1768- onCurrentPageChanged: {
1769- previousPage = currentPage;
1770-
1771- // If going back from nowPlaying jump back to tabs
1772- if (previousPage === nowPlaying && mainPageStack.currentPage !== nowPlaying) {
1773- while (mainPageStack.depth > 1) {
1774- mainPageStack.pop(mainPageStack.currentPage)
1775- }
1776- }
1777- }
1778- }
1779-
1780 /* Helper functions */
1781
1782- // Disable the toolbar for this page/view (eg a dialog)
1783- function disableToolbar()
1784- {
1785- cachedStates.push(state);
1786- musicToolbarPanel.state = "hidden";
1787- }
1788-
1789- // Enable the toolbar (run when closing a page that disabled it)
1790- function enableToolbar()
1791- {
1792- if (cachedStates.length > 0)
1793- {
1794- musicToolbarPanel.state = cachedStates.pop();
1795- }
1796- }
1797-
1798 // Back button has been pressed, jump up pageStack or back to parent page
1799 function goBack()
1800 {
1801@@ -98,18 +52,6 @@
1802 else if (mainPageStack !== null && mainPageStack.depth > 1) {
1803 mainPageStack.pop(currentPage)
1804 }
1805-
1806- startAutohideTimer()
1807- }
1808-
1809- // Hide the toolbar
1810- function hideToolbar()
1811- {
1812- if (!wideAspect) {
1813- musicToolbarPanel.close();
1814- }
1815-
1816- toolbarAutoHideTimer.stop(); // cancel any autohide
1817 }
1818
1819 // Remove sheet as it has been closed
1820@@ -126,8 +68,6 @@
1821 function setPage(childPage)
1822 {
1823 currentPage = childPage;
1824- // note: If pageStack tracking is needed readd here
1825- //currentPageStack = pageStack === undefined ? null : pageStack;
1826 }
1827
1828 // Set the current sheet (overrides page)
1829@@ -135,32 +75,6 @@
1830 currentSheet.push(sheet)
1831 }
1832
1833- // Show the toolbar
1834- function showToolbar()
1835- {
1836- startAutohideTimer(); // always attempt to autohide toolbar
1837-
1838- if (!musicToolbarPanel.opened) {
1839- musicToolbarPanel.open();
1840- }
1841- }
1842-
1843- // Start the autohidetimer
1844- function startAutohideTimer()
1845- {
1846- toolbarAutoHideTimer.restart();
1847- }
1848-
1849- Connections {
1850- target: mainView
1851- onWideAspectChanged: {
1852- // Force toolbar to show if in wideAspect
1853- if (wideAspect && !opened) {
1854- showToolbar();
1855- }
1856- }
1857- }
1858-
1859 Panel {
1860 id: musicToolbarPanel
1861 anchors {
1862@@ -168,543 +82,9 @@
1863 right: parent.right
1864 bottom: parent.bottom
1865 }
1866- height: currentMode === "full" ? fullHeight : expandedHeight
1867- locked: wideAspect
1868-
1869- __closeOnContentsClicks: false // TODO: fix bug 1295720
1870-
1871- // The current mode of the controls
1872- property string currentMode: wideAspect || (currentPage === nowPlaying)
1873- ? "full" : "expanded"
1874-
1875- // Properties for the different heights
1876- property int minimizedHeight: units.gu(0.5)
1877- property int expandedHeight: units.gu(8)
1878- property int fullHeight: units.gu(11)
1879-
1880- onCurrentModeChanged: {
1881- musicToolbarFullProgressMouseArea.enabled = currentMode === "full"
1882- }
1883-
1884- onOpenedChanged: {
1885- onToolbarShownChanged(opened, currentPage, currentTab);
1886-
1887- if (opened) {
1888- startAutohideTimer();
1889- }
1890- }
1891-
1892- /* Full toolbar */
1893- Rectangle {
1894- id: musicToolbarFullContainer
1895- anchors {
1896- fill: parent
1897- }
1898- color: styleMusic.toolbar.fullBackgroundColor
1899- visible: musicToolbarPanel.currentMode === "full"
1900-
1901- /* Buttons component */
1902- Rectangle {
1903- id: musicToolbarFullButtonsContainer
1904- anchors.left: parent.left
1905- anchors.top: musicToolbarFullProgressContainer.bottom
1906- color: "transparent"
1907- height: parent.height - musicToolbarFullProgressContainer.height
1908- width: parent.width
1909-
1910- /* Column for labels in wideAspect */
1911- Column {
1912- id: nowPlayingWideAspectLabels
1913- anchors {
1914- left: parent.left
1915- leftMargin: units.gu(1)
1916- right: nowPlayingRepeatButton.left
1917- rightMargin: units.gu(1)
1918- verticalCenter: parent.verticalCenter
1919- }
1920- visible: wideAspect
1921-
1922- /* Clicking in the area shows the queue */
1923- function trigger() {
1924- if (trackQueue.model.count !== 0 && currentPage !== nowPlaying) {
1925- tabs.pushNowPlaying();
1926- }
1927- else if (currentPage === nowPlaying) {
1928- musicToolbar.goBack();
1929- }
1930- }
1931-
1932- /* Title of track */
1933- Label {
1934- id: nowPlayingWideAspectTitle
1935- anchors {
1936- left: parent.left
1937- leftMargin: units.gu(1)
1938- right: parent.right
1939- rightMargin: units.gu(1)
1940- }
1941- color: styleMusic.playerControls.labelColor
1942- elide: Text.ElideRight
1943- fontSize: "medium"
1944- objectName: "playercontroltitle"
1945- text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle
1946- }
1947-
1948- /* Artist of track */
1949- Label {
1950- id: nowPlayingWideAspectArtist
1951- anchors {
1952- left: parent.left
1953- leftMargin: units.gu(1)
1954- right: parent.right
1955- rightMargin: units.gu(1)
1956- }
1957- color: styleMusic.playerControls.labelColor
1958- elide: Text.ElideRight
1959- fontSize: "small"
1960- text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist
1961- }
1962-
1963- /* Album of track */
1964- Label {
1965- id: nowPlayingWideAspectAlbum
1966- anchors {
1967- left: parent.left
1968- leftMargin: units.gu(1)
1969- right: parent.right
1970- rightMargin: units.gu(1)
1971- }
1972- color: styleMusic.playerControls.labelColor
1973- elide: Text.ElideRight
1974- fontSize: "small"
1975- text: trackQueue.model.count === 0 ? "" : player.currentMetaAlbum
1976- }
1977- }
1978-
1979- /* Repeat button */
1980- Item {
1981- id: nowPlayingRepeatButton
1982- objectName: "repeatShape"
1983- anchors.right: nowPlayingPreviousButton.left
1984- anchors.rightMargin: units.gu(1)
1985- anchors.verticalCenter: parent.verticalCenter
1986- height: units.gu(6)
1987- opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
1988- width: height
1989-
1990- function trigger() {
1991- if (emptyPage.noMusic) {
1992- return;
1993- }
1994-
1995- // Invert repeat settings
1996- player.repeat = !player.repeat
1997- }
1998-
1999- Image {
2000- id: repeatIcon
2001- height: units.gu(3)
2002- width: height
2003- anchors.verticalCenter: parent.verticalCenter
2004- anchors.horizontalCenter: parent.horizontalCenter
2005- source: Qt.resolvedUrl("images/media-playlist-repeat.svg")
2006- verticalAlignment: Text.AlignVCenter
2007- opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
2008- }
2009- }
2010-
2011- /* Previous button */
2012- Item {
2013- id: nowPlayingPreviousButton
2014- anchors.right: nowPlayingPlayButton.left
2015- anchors.rightMargin: units.gu(1)
2016- anchors.verticalCenter: parent.verticalCenter
2017- height: units.gu(6)
2018- objectName: "previousShape"
2019- opacity: trackQueue.model.count === 0 ? .4 : 1
2020- width: height
2021-
2022- function trigger() {
2023- if (trackQueue.model.count === 0) {
2024- return;
2025- }
2026-
2027- player.previousSong()
2028- }
2029-
2030- Image {
2031- id: nowPlayingPreviousIndicator
2032- height: units.gu(3)
2033- width: height
2034- anchors.horizontalCenter: parent.horizontalCenter
2035- anchors.verticalCenter: parent.verticalCenter
2036- source: Qt.resolvedUrl("images/media-skip-backward.svg")
2037- opacity: 1
2038- }
2039- }
2040-
2041- /* Play/Pause button */
2042- Rectangle {
2043- id: nowPlayingPlayButton
2044- anchors.horizontalCenter: parent.horizontalCenter
2045- anchors.verticalCenter: parent.verticalCenter
2046- antialiasing: true
2047- color: styleMusic.toolbar.fullOuterPlayCircleColor
2048- height: units.gu(12)
2049- radius: height / 2
2050- width: height
2051-
2052- // draws the outter shadow/highlight
2053- Rectangle {
2054- id: sourceOutterFull
2055- anchors { fill: parent; margins: -units.gu(0.1) }
2056- radius: (width / 2)
2057- antialiasing: true
2058- gradient: Gradient {
2059- GradientStop { position: 0.0; color: "black" }
2060- GradientStop { position: 0.5; color: "transparent" }
2061- GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
2062- }
2063-
2064- Rectangle {
2065- anchors.horizontalCenter: parent.horizontalCenter
2066- anchors.verticalCenter: parent.verticalCenter
2067- antialiasing: true
2068- color: styleMusic.toolbar.fullOuterPlayCircleColor
2069- height: nowPlayingPlayButton.height - units.gu(.1)
2070- radius: height / 2
2071- width: height
2072-
2073- Rectangle {
2074- id: nowPlayingPlayButtonInner
2075- anchors.horizontalCenter: parent.horizontalCenter
2076- anchors.verticalCenter: parent.verticalCenter
2077- antialiasing: true
2078- color: styleMusic.toolbar.fullInnerPlayCircleColor
2079- height: units.gu(7)
2080- radius: height / 2
2081- width: height
2082-
2083- // draws the inner shadow/highlight
2084- Rectangle {
2085- id: sourceInnerFull
2086- anchors { fill: parent; margins: -units.gu(0.1) }
2087- radius: (width / 2)
2088- antialiasing: true
2089- gradient: Gradient {
2090- GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
2091- GradientStop { position: 0.5; color: "transparent" }
2092- GradientStop { position: 1.0; color: "black" }
2093- }
2094-
2095- Rectangle {
2096- anchors.horizontalCenter: parent.horizontalCenter
2097- anchors.verticalCenter: parent.verticalCenter
2098- antialiasing: true
2099- color: styleMusic.toolbar.fullInnerPlayCircleColor
2100- height: nowPlayingPlayButtonInner.height - units.gu(.1)
2101- objectName: "playShape"
2102- radius: height / 2
2103- width: height
2104-
2105- function trigger() {
2106- if (emptyPage.noMusic) {
2107- return;
2108- }
2109-
2110- if (trackQueue.model.count === 0) {
2111- playRandomSong();
2112- }
2113- else {
2114- player.toggle();
2115- }
2116- }
2117-
2118- Image {
2119- id: nowPlayingPlayIndicator
2120- height: units.gu(6)
2121- width: height
2122- anchors.horizontalCenter: parent.horizontalCenter
2123- anchors.verticalCenter: parent.verticalCenter
2124- opacity: emptyPage.noMusic ? .4 : 1
2125- source: player.playbackState === MediaPlayer.PlayingState ?
2126- Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
2127- }
2128- }
2129- }
2130- }
2131- }
2132- }
2133- }
2134-
2135- /* Next button */
2136- Item {
2137- id: nowPlayingNextButton
2138- anchors.left: nowPlayingPlayButton.right
2139- anchors.leftMargin: units.gu(1)
2140- anchors.verticalCenter: parent.verticalCenter
2141- height: units.gu(6)
2142- objectName: "forwardShape"
2143- opacity: trackQueue.model.count === 0 ? .4 : 1
2144- width: height
2145-
2146- function trigger() {
2147- if (trackQueue.model.count === 0 || emptyPage.noMusic) {
2148- return;
2149- }
2150-
2151- player.nextSong()
2152- }
2153-
2154- Image {
2155- id: nowPlayingNextIndicator
2156- height: units.gu(3)
2157- width: height
2158- anchors.horizontalCenter: parent.horizontalCenter
2159- anchors.verticalCenter: parent.verticalCenter
2160- source: Qt.resolvedUrl("images/media-skip-forward.svg")
2161- opacity: 1
2162- }
2163- }
2164-
2165- /* Shuffle button */
2166- Item {
2167- id: nowPlayingShuffleButton
2168- objectName: "shuffleShape"
2169- anchors.left: nowPlayingNextButton.right
2170- anchors.leftMargin: units.gu(1)
2171- anchors.verticalCenter: parent.verticalCenter
2172- height: units.gu(6)
2173- opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
2174- width: height
2175-
2176- function trigger() {
2177- if (emptyPage.noMusic) {
2178- return;
2179- }
2180-
2181- // Invert shuffle settings
2182- player.shuffle = !player.shuffle
2183- }
2184-
2185- Image {
2186- id: shuffleIcon
2187- height: units.gu(3)
2188- width: height
2189- anchors.verticalCenter: parent.verticalCenter
2190- anchors.horizontalCenter: parent.horizontalCenter
2191- source: Qt.resolvedUrl("images/media-playlist-shuffle.svg")
2192- opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
2193- }
2194- }
2195-
2196- /* Search button in wideAspect */
2197- Item {
2198- id: nowPlayingSearchButton
2199- objectName: "searchShape"
2200- anchors {
2201- right: parent.right
2202- rightMargin: units.gu(1)
2203- verticalCenter: parent.verticalCenter
2204- }
2205- height: units.gu(6)
2206- opacity: !emptyPage.noMusic ? 1 : .4
2207- width: height
2208- visible: wideAspect
2209-
2210- function trigger() {
2211- if (emptyPage.noMusic) {
2212- return;
2213- }
2214-
2215- if (!searchSheet.sheetVisible) {
2216- PopupUtils.open(searchSheet.sheet,
2217- mainView, { title: i18n.tr("Search")} )
2218- }
2219- }
2220-
2221- Image {
2222- id: searchIcon
2223- anchors {
2224- horizontalCenter: parent.horizontalCenter
2225- verticalCenter: parent.verticalCenter
2226- }
2227- height: units.gu(3)
2228- opacity: !emptyPage.noMusic ? 1 : .4
2229- source: Qt.resolvedUrl("images/search.svg")
2230- width: height
2231- }
2232- }
2233- }
2234-
2235- /* Progress bar component */
2236- Rectangle {
2237- id: musicToolbarFullProgressContainer
2238- anchors.left: parent.left
2239- anchors.top: parent.top
2240- color: styleMusic.toolbar.fullBackgroundColor
2241- height: units.gu(3)
2242- width: parent.width
2243-
2244- /* Position label */
2245- Label {
2246- id: musicToolbarFullPositionLabel
2247- anchors.left: parent.left
2248- anchors.leftMargin: units.gu(2)
2249- anchors.top: parent.top
2250- color: styleMusic.nowPlaying.labelColor
2251- fontSize: "x-small"
2252- height: parent.height
2253- horizontalAlignment: Text.AlignHCenter
2254- text: durationToString(player.position)
2255- verticalAlignment: Text.AlignVCenter
2256- width: units.gu(3)
2257- }
2258-
2259- /* Progress bar */
2260- Rectangle {
2261- id: musicToolbarFullProgressBarContainer
2262- objectName: "progressBarShape"
2263- anchors.left: musicToolbarFullPositionLabel.right
2264- anchors.leftMargin: units.gu(2)
2265- anchors.right: musicToolbarFullDurationLabel.left
2266- anchors.rightMargin: units.gu(2)
2267- anchors.verticalCenter: parent.verticalCenter
2268- color: "transparent"
2269- height: units.gu(1);
2270- state: trackQueue.model.count === 0 ? "disabled" : "enabled"
2271-
2272- states: [
2273- State {
2274- name: "disabled"
2275- PropertyChanges {
2276- target: musicToolbarFullProgressMouseArea
2277- enabled: false
2278- }
2279- PropertyChanges {
2280- target: musicToolbarFullProgressTrough
2281- visible: false
2282- }
2283- PropertyChanges {
2284- target: musicToolbarFullProgressHandle
2285- visible: false
2286- }
2287- },
2288- State {
2289- name: "enabled"
2290- PropertyChanges {
2291- target: musicToolbarFullProgressMouseArea
2292- enabled: true
2293- }
2294- PropertyChanges {
2295- target: musicToolbarFullProgressTrough
2296- visible: true
2297- }
2298- PropertyChanges {
2299- target: musicToolbarFullProgressHandle
2300- visible: true
2301- }
2302- }
2303- ]
2304-
2305- property bool seeking: false
2306-
2307- onSeekingChanged: {
2308- if (seeking === false) {
2309- musicToolbarFullPositionLabel.text = durationToString(player.position)
2310- }
2311- }
2312-
2313- Connections {
2314- target: player
2315- onDurationChanged: {
2316- console.debug("Duration changed: " + player.duration)
2317- musicToolbarFullDurationLabel.text = durationToString(player.duration)
2318- }
2319- onPositionChanged: {
2320- if (musicToolbarFullProgressBarContainer.seeking === false)
2321- {
2322- musicToolbarFullPositionLabel.text = durationToString(player.position)
2323- musicToolbarFullDurationLabel.text = durationToString(player.duration)
2324- musicToolbarFullProgressHandle.x = (player.position / player.duration) * musicToolbarFullProgressBarContainer.width
2325- - musicToolbarFullProgressHandle.width / 2;
2326- }
2327- }
2328- onStopped: {
2329- musicToolbarFullProgressHandle.x = -musicToolbarFullProgressHandle.width / 2;
2330-
2331- musicToolbarFullPositionLabel.text = durationToString(0);
2332- musicToolbarFullDurationLabel.text = durationToString(0);
2333- }
2334- }
2335-
2336- // Black background behind the progress bar
2337- Rectangle {
2338- id: musicToolbarFullProgressBackground
2339- anchors.verticalCenter: parent.verticalCenter;
2340- color: styleMusic.toolbar.fullProgressBackgroundColor;
2341- height: parent.height;
2342- radius: units.gu(0.5)
2343- width: parent.width;
2344- }
2345-
2346- // The orange fill of the progress bar
2347- Rectangle {
2348- id: musicToolbarFullProgressTrough
2349- anchors.verticalCenter: parent.verticalCenter;
2350- antialiasing: true
2351- color: styleMusic.toolbar.fullProgressTroughColor;
2352- height: parent.height;
2353- radius: units.gu(0.5)
2354- width: musicToolbarFullProgressHandle.x + (height / 2); // +radius
2355- }
2356-
2357- // The current position (handle) of the progress bar
2358- Rectangle {
2359- id: musicToolbarFullProgressHandle
2360- anchors.verticalCenter: musicToolbarFullProgressBackground.verticalCenter
2361- antialiasing: true
2362- color: styleMusic.nowPlaying.progressHandleColor
2363- height: units.gu(1.5)
2364- radius: height / 2
2365- width: height
2366-
2367- // On X change update the position string
2368- onXChanged: {
2369- if (musicToolbarFullProgressBarContainer.seeking) {
2370- var fraction = (x + (width / 2)) / parent.width;
2371- musicToolbarFullPositionLabel.text = durationToString(fraction * player.duration)
2372- }
2373- }
2374- }
2375- }
2376-
2377- /* Duration label */
2378- Label {
2379- id: musicToolbarFullDurationLabel
2380- anchors.right: parent.right
2381- anchors.rightMargin: units.gu(2)
2382- anchors.top: parent.top
2383- color: styleMusic.nowPlaying.labelColor
2384- fontSize: "x-small"
2385- height: parent.height
2386- horizontalAlignment: Text.AlignHCenter
2387- text: durationToString(player.duration)
2388- verticalAlignment: Text.AlignVCenter
2389- width: units.gu(3)
2390- }
2391-
2392- /* Border at the bottom */
2393- Rectangle {
2394- anchors.bottom: parent.bottom
2395- anchors.left: parent.left
2396- anchors.right: parent.right
2397- color: styleMusic.common.white
2398- height: units.gu(0.1)
2399- opacity: 0.1
2400- }
2401- }
2402- }
2403+ height: units.gu(7.25)
2404+ locked: true
2405+ opened: true
2406
2407 /* Expanded toolbar */
2408 Rectangle {
2409@@ -713,12 +93,13 @@
2410 fill: parent
2411 }
2412 color: "transparent"
2413- visible: musicToolbarPanel.currentMode === "expanded"
2414
2415 Rectangle {
2416 id: musicToolbarPlayerControls
2417- anchors.fill: parent
2418- color: styleMusic.playerControls.backgroundColor
2419+ anchors {
2420+ fill: parent
2421+ }
2422+ color: "#000"
2423 state: trackQueue.model.count === 0 ? "disabled" : "enabled"
2424 states: [
2425 State {
2426@@ -745,39 +126,55 @@
2427 }
2428 ]
2429
2430+ /* Disabled (empty state) controls */
2431 Rectangle {
2432 id: disabledPlayerControlsGroup
2433- anchors.fill: parent
2434+ anchors {
2435+ bottom: playerControlsProgressBar.top
2436+ left: parent.left
2437+ right: parent.right
2438+ top: parent.top
2439+ }
2440 color: "transparent"
2441- visible: trackQueue.model.count === 0
2442
2443 Label {
2444 id: noSongsInQueueLabel
2445 anchors {
2446 left: parent.left
2447+ leftMargin: units.gu(2)
2448 right: disabledPlayerControlsPlayButton.left
2449- margins: units.gu(1)
2450- top: parent.top
2451+ rightMargin: units.gu(2)
2452+ verticalCenter: parent.verticalCenter
2453 }
2454 color: styleMusic.playerControls.labelColor
2455- text: i18n.tr("Tap play to shuffle music")
2456+ text: i18n.tr("Tap to shuffle music")
2457 fontSize: "large"
2458 wrapMode: Text.WordWrap
2459 maximumLineCount: 2
2460 }
2461
2462- Rectangle {
2463+ /* Play/Pause button */
2464+ Icon {
2465 id: disabledPlayerControlsPlayButton
2466- anchors.right: parent.right
2467- anchors.rightMargin: units.gu(1)
2468- anchors.verticalCenter: parent.verticalCenter
2469- antialiasing: true
2470- color: "#444"
2471- height: units.gu(7)
2472- radius: height / 2
2473+ anchors {
2474+ right: parent.right
2475+ rightMargin: units.gu(3)
2476+ verticalCenter: parent.verticalCenter
2477+ }
2478+ color: "#FFF"
2479+ height: units.gu(2.5)
2480+ name: player.playbackState === MediaPlayer.PlayingState ?
2481+ "media-playback-pause" : "media-playback-start"
2482+ objectName: "disabledSmallPlayShape"
2483 width: height
2484+ }
2485
2486- function trigger() {
2487+ /* Click to shuffle music */
2488+ MouseArea {
2489+ anchors {
2490+ fill: parent
2491+ }
2492+ onClicked: {
2493 if (emptyPage.noMusic) {
2494 return;
2495 }
2496@@ -789,230 +186,65 @@
2497 player.toggle();
2498 }
2499 }
2500-
2501- // draws the outer shadow/highlight
2502- Rectangle {
2503- id: disabledSourceOutter
2504- anchors { fill: parent; margins: -units.gu(0.1) }
2505- radius: (width / 2)
2506- antialiasing: true
2507- gradient: Gradient {
2508- GradientStop { position: 0.0; color: "black" }
2509- GradientStop { position: 0.5; color: "transparent" }
2510- GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
2511- }
2512-
2513- Rectangle {
2514- anchors.verticalCenter: parent.verticalCenter
2515- anchors.horizontalCenter: parent.horizontalCenter
2516- antialiasing: true
2517- color: "#444"
2518- height: playerControlsPlayButton.height - units.gu(.1)
2519- radius: height / 2
2520- width: height
2521-
2522- Rectangle {
2523- id: disabledPlayerControlsPlayInnerCircle
2524- anchors.horizontalCenter: parent.horizontalCenter
2525- anchors.verticalCenter: parent.verticalCenter
2526- antialiasing: true
2527- height: units.gu(4.5)
2528- radius: height / 2
2529- width: height
2530- color: styleMusic.toolbar.fullInnerPlayCircleColor
2531-
2532- // draws the inner shadow/highlight
2533- Rectangle {
2534- id: disabledSourceInner
2535- anchors { fill: parent; margins: -units.gu(0.1) }
2536- radius: (width / 2)
2537- antialiasing: true
2538- gradient: Gradient {
2539- GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
2540- GradientStop { position: 0.5; color: "transparent" }
2541- GradientStop { position: 1.0; color: "black" }
2542- }
2543-
2544- Rectangle {
2545- anchors.verticalCenter: parent.verticalCenter
2546- anchors.horizontalCenter: parent.horizontalCenter
2547- antialiasing: true
2548- height: playerControlsPlayInnerCircle.height - units.gu(.1)
2549- radius: height / 2
2550- width: height
2551- color: styleMusic.toolbar.fullInnerPlayCircleColor
2552-
2553- Image {
2554- id: disabledPlayIndicator
2555- height: units.gu(4)
2556- width: height
2557- anchors.horizontalCenter: parent.horizontalCenter
2558- anchors.verticalCenter: parent.verticalCenter
2559- opacity: emptyPage.noMusic ? .4 : 1
2560- source: player.playbackState === MediaPlayer.PlayingState ?
2561- Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
2562- }
2563- }
2564- }
2565- }
2566- }
2567- }
2568 }
2569 }
2570
2571+ /* Enabled (queue > 0) controls */
2572 Rectangle {
2573 id: enabledPlayerControlsGroup
2574- anchors.fill: parent
2575+ anchors {
2576+ bottom: playerControlsProgressBar.top
2577+ left: parent.left
2578+ right: parent.right
2579+ top: parent.top
2580+ }
2581 color: "transparent"
2582- visible: trackQueue.model.count !== 0
2583-
2584- /* Settings button */
2585- // TODO: Enable settings when it is practical
2586- /* Rectangle {
2587- id: playerControlsSettings
2588- anchors.right: parent.right
2589- anchors.verticalCenter: parent.verticalCenter
2590- width: units.gu(6)
2591- height: width
2592- color: "transparent"
2593-
2594- Image {
2595- anchors.horizontalCenter: parent.horizontalCenter
2596- anchors.verticalCenter: parent.verticalCenter
2597- height: units.gu(3)
2598- source: Qt.resolvedUrl("images/settings.png")
2599- width: height
2600- }
2601-
2602- MouseArea {
2603- anchors.fill: parent
2604- onClicked: {
2605- console.debug('Debug: Show settings')
2606- PopupUtils.open(Qt.resolvedUrl("MusicSettings.qml"), mainView,
2607- {
2608- title: i18n.tr("Settings")
2609- } )
2610- }
2611- }
2612- } */
2613-
2614- /* Play/Pause button TODO: image and colours needs updating */
2615- Rectangle {
2616- id: playerControlsPlayButton
2617- anchors.right: parent.right
2618- anchors.rightMargin: units.gu(1)
2619- anchors.verticalCenter: parent.verticalCenter
2620- antialiasing: true
2621- color: "#444"
2622- height: units.gu(7)
2623- objectName: "smallPlayShape"
2624- radius: height / 2
2625- width: height
2626-
2627- function trigger() {
2628- if (emptyPage.noMusic) {
2629- return;
2630- }
2631-
2632- if (trackQueue.model.count === 0) {
2633- playRandomSong();
2634- }
2635- else {
2636- player.toggle();
2637- }
2638- }
2639-
2640- // draws the outer shadow/highlight
2641- Rectangle {
2642- id: sourceOutter
2643- anchors { fill: parent; margins: -units.gu(0.1) }
2644- radius: (width / 2)
2645- antialiasing: true
2646- gradient: Gradient {
2647- GradientStop { position: 0.0; color: "black" }
2648- GradientStop { position: 0.5; color: "transparent" }
2649- GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
2650- }
2651-
2652- Rectangle {
2653- anchors.verticalCenter: parent.verticalCenter
2654- anchors.horizontalCenter: parent.horizontalCenter
2655- antialiasing: true
2656- color: "#444"
2657- height: playerControlsPlayButton.height - units.gu(.1)
2658- radius: height / 2
2659- width: height
2660-
2661- Rectangle {
2662- id: playerControlsPlayInnerCircle
2663- anchors.horizontalCenter: parent.horizontalCenter
2664- anchors.verticalCenter: parent.verticalCenter
2665- antialiasing: true
2666- height: units.gu(4.5)
2667- radius: height / 2
2668- width: height
2669- color: styleMusic.toolbar.fullInnerPlayCircleColor
2670-
2671- // draws the inner shadow/highlight
2672- Rectangle {
2673- id: sourceInner
2674- anchors { fill: parent; margins: -units.gu(0.1) }
2675- radius: (width / 2)
2676- antialiasing: true
2677- gradient: Gradient {
2678- GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
2679- GradientStop { position: 0.5; color: "transparent" }
2680- GradientStop { position: 1.0; color: "black" }
2681- }
2682-
2683- Rectangle {
2684- anchors.verticalCenter: parent.verticalCenter
2685- anchors.horizontalCenter: parent.horizontalCenter
2686- antialiasing: true
2687- height: playerControlsPlayInnerCircle.height - units.gu(.1)
2688- radius: height / 2
2689- width: height
2690- color: styleMusic.toolbar.fullInnerPlayCircleColor
2691-
2692- Image {
2693- id: playindicator
2694- height: units.gu(4)
2695- width: height
2696- anchors.horizontalCenter: parent.horizontalCenter
2697- anchors.verticalCenter: parent.verticalCenter
2698- opacity: emptyPage.noMusic ? .4 : 1
2699- source: player.playbackState === MediaPlayer.PlayingState ?
2700- Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
2701- }
2702- }
2703- }
2704- }
2705+
2706+ /* Album art in player controls */
2707+ Image {
2708+ id: playerControlsImage
2709+ anchors {
2710+ bottom: parent.bottom
2711+ left: parent.left
2712+ top: parent.top
2713+ }
2714+ smooth: true
2715+ source: player.currentMetaArt === "" ?
2716+ decodeURIComponent("image://albumart/artist=" +
2717+ player.currentMetaArtist +
2718+ "&album=" + player.currentMetaAlbum)
2719+ : player.currentMetaArt
2720+ width: parent.height
2721+
2722+ onStatusChanged: {
2723+ if (status === Image.Error) {
2724+ source = Qt.resolvedUrl("../images/music-app-cover@30.png")
2725 }
2726 }
2727 }
2728
2729- /* Container holding the labels for the toolbar */
2730- Rectangle {
2731- id: playerControlLabelContainer
2732- anchors.bottom: parent.bottom
2733- anchors.left: parent.left
2734- anchors.right: playerControlsPlayButton.left
2735- anchors.top: parent.top
2736- color: "transparent"
2737+ /* Column of meta labels */
2738+ Column {
2739+ id: playerControlsLabels
2740+ anchors {
2741+ left: playerControlsImage.right
2742+ leftMargin: units.gu(1.5)
2743+ right: playerControlsPlayButton.left
2744+ rightMargin: units.gu(1)
2745+ verticalCenter: parent.verticalCenter
2746+ }
2747
2748 /* Title of track */
2749 Label {
2750 id: playerControlsTitle
2751- anchors.left: parent.left
2752- anchors.leftMargin: units.gu(1)
2753- anchors.right: parent.right
2754- anchors.rightMargin: units.gu(1)
2755- anchors.top: parent.top
2756- anchors.topMargin: units.gu(1)
2757- color: styleMusic.playerControls.labelColor
2758+ anchors {
2759+ left: parent.left
2760+ right: parent.right
2761+ }
2762+ color: "#FFF"
2763 elide: Text.ElideRight
2764- fontSize: "medium"
2765- objectName: "playercontroltitle"
2766+ fontSize: "small"
2767+ font.weight: Font.DemiBold
2768 text: player.currentMetaTitle === ""
2769 ? player.source : player.currentMetaTitle
2770 }
2771@@ -1020,119 +252,105 @@
2772 /* Artist of track */
2773 Label {
2774 id: playerControlsArtist
2775- anchors.left: parent.left
2776- anchors.leftMargin: units.gu(1)
2777- anchors.right: parent.right
2778- anchors.rightMargin: units.gu(1)
2779- anchors.top: playerControlsTitle.bottom
2780- color: styleMusic.playerControls.labelColor
2781+ anchors {
2782+ left: parent.left
2783+ right: parent.right
2784+ }
2785+ color: "#FFF"
2786 elide: Text.ElideRight
2787 fontSize: "small"
2788+ opacity: 0.4
2789 text: player.currentMetaArtist
2790 }
2791-
2792- /* Album of track */
2793- Label {
2794- id: playerControlsAlbum
2795- anchors.left: parent.left
2796- anchors.leftMargin: units.gu(1)
2797- anchors.right: parent.right
2798- anchors.rightMargin: units.gu(1)
2799- anchors.top: playerControlsArtist.bottom
2800- color: styleMusic.playerControls.labelColor
2801- elide: Text.ElideRight
2802- fontSize: "small"
2803- text: player.currentMetaAlbum
2804- }
2805- }
2806-
2807+ }
2808+
2809+ /* Play/Pause button */
2810+ Icon {
2811+ id: playerControlsPlayButton
2812+ anchors {
2813+ right: parent.right
2814+ rightMargin: units.gu(3)
2815+ verticalCenter: parent.verticalCenter
2816+ }
2817+ color: "#FFF"
2818+ height: units.gu(2.5)
2819+ name: player.playbackState === MediaPlayer.PlayingState ?
2820+ "media-playback-pause" : "media-playback-start"
2821+ objectName: "playShape"
2822+ width: height
2823+ }
2824+
2825+ MouseArea {
2826+ anchors {
2827+ bottom: parent.bottom
2828+ horizontalCenter: playerControlsPlayButton.horizontalCenter
2829+ top: parent.top
2830+ }
2831+ onClicked: player.toggle()
2832+ width: units.gu(8)
2833+
2834+ Rectangle {
2835+ anchors {
2836+ fill: parent
2837+ }
2838+ color: "#FFF"
2839+ opacity: parent.pressed ? 0.1 : 0
2840+
2841+ Behavior on opacity {
2842+ UbuntuNumberAnimation {
2843+ duration: UbuntuAnimation.FastDuration
2844+ }
2845+ }
2846+ }
2847+ }
2848+
2849+ /* Mouse area to jump to now playing */
2850 Rectangle {
2851- anchors.fill: playerControlLabelContainer
2852+ anchors {
2853+ bottom: parent.bottom
2854+ left: parent.left
2855+ right: playerControlsLabels.right
2856+ top: parent.top
2857+ }
2858 color: "transparent"
2859+ objectName: "jumpNowPlaying"
2860 function trigger() {
2861 tabs.pushNowPlaying();
2862 }
2863 }
2864 }
2865- }
2866- }
2867-
2868- /* Object which provides the progress bar when toolbar is minimized */
2869- Rectangle {
2870- id: musicToolbarSmallProgressBackground
2871- anchors {
2872- bottom: parent.top
2873- left: parent.left
2874- right: parent.right
2875- }
2876- color: styleMusic.common.black
2877- height: musicToolbarPanel.minimizedHeight
2878- visible: (!musicToolbarPanel.animating &&
2879- !musicToolbarPanel.opened)
2880- || musicToolbarPanel.currentMode == "expanded"
2881-
2882- Rectangle {
2883- id: musicToolbarSmallProgressHint
2884- anchors.left: parent.left
2885- anchors.top: parent.top
2886- color: styleMusic.nowPlaying.progressForegroundColor
2887- height: parent.height
2888- width: 0
2889-
2890- Connections {
2891- target: player
2892- onPositionChanged: {
2893- musicToolbarSmallProgressHint.width = (player.position / player.duration) * musicToolbarSmallProgressBackground.width
2894- }
2895- onStopped: {
2896- musicToolbarSmallProgressHint.width = 0;
2897- }
2898- }
2899- }
2900- }
2901-
2902- /* Mouse events for the progress bar
2903- is after musicToolbarMouseArea so that it captures mouse events for dragging */
2904- MouseArea {
2905- id: musicToolbarFullProgressMouseArea
2906- height: units.gu(2)
2907- width: musicToolbarFullProgressBarContainer.width
2908- x: musicToolbarFullProgressBarContainer.x
2909- y: musicToolbarFullProgressBarContainer.y
2910-
2911- drag.axis: Drag.XAxis
2912- drag.minimumX: -(musicToolbarFullProgressHandle.width / 2)
2913- drag.maximumX: musicToolbarFullProgressBarContainer.width - (musicToolbarFullProgressHandle.width / 2)
2914- drag.target: musicToolbarFullProgressHandle
2915-
2916- onPressed: {
2917- musicToolbarFullProgressBarContainer.seeking = true;
2918-
2919- // Jump the handle to the current mouse position
2920- musicToolbarFullProgressHandle.x = mouse.x - (musicToolbarFullProgressHandle.width / 2);
2921- }
2922-
2923- onReleased: {
2924- var fraction = mouse.x / musicToolbarFullProgressBarContainer.width;
2925-
2926- // Limit the bounds of the fraction
2927- fraction = fraction < 0 ? 0 : fraction
2928- fraction = fraction > 1 ? 1 : fraction
2929-
2930- player.seek((fraction) * player.duration);
2931- musicToolbarFullProgressBarContainer.seeking = false;
2932- }
2933- }
2934-
2935- // Timer for autohide
2936- Timer {
2937- id: toolbarAutoHideTimer
2938- interval: 5000
2939- repeat: false
2940- running: false
2941- onTriggered: {
2942- if (currentPage !== nowPlaying) { // don't autohide on now playing
2943- hideToolbar();
2944+
2945+ /* Object which provides the progress bar when toolbar is minimized */
2946+ Rectangle {
2947+ id: playerControlsProgressBar
2948+ anchors {
2949+ bottom: parent.bottom
2950+ left: parent.left
2951+ right: parent.right
2952+ }
2953+ color: styleMusic.common.black
2954+ height: units.gu(0.25)
2955+
2956+ Rectangle {
2957+ id: playerControlsProgressBarHint
2958+ anchors {
2959+ left: parent.left
2960+ top: parent.top
2961+ }
2962+ color: UbuntuColors.blue
2963+ height: parent.height
2964+ width: 0
2965+
2966+ Connections {
2967+ target: player
2968+ onPositionChanged: {
2969+ playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width
2970+ }
2971+ onStopped: {
2972+ playerControlsProgressBarHint.width = 0;
2973+ }
2974+ }
2975+ }
2976 }
2977 }
2978 }
2979
2980=== modified file 'MusicTracks.qml'
2981--- MusicTracks.qml 2014-09-20 15:41:33 +0000
2982+++ MusicTracks.qml 2014-10-16 23:15:23 +0000
2983@@ -36,8 +36,10 @@
2984
2985 ListView {
2986 id: tracklist
2987- anchors.fill: parent
2988- anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
2989+ anchors {
2990+ fill: parent
2991+ topMargin: units.gu(2)
2992+ }
2993 highlightFollowsCurrentItem: false
2994 objectName: "trackstab-listview"
2995 model: SortFilterModel {
2996@@ -59,7 +61,8 @@
2997 color: "transparent"
2998 objectName: "tracksPageListItem" + index
2999 width: parent.width
3000- height: styleMusic.common.itemHeight
3001+ height: units.gu(7)
3002+ showDivider: false
3003
3004 rightSideActions: [
3005 AddToQueue {
3006@@ -77,29 +80,25 @@
3007
3008 MusicRow {
3009 id: musicRow
3010+ anchors.verticalCenter: parent.verticalCenter
3011 covers: [{art: model.art}]
3012+ isSquare: true
3013+ coverSize: units.gu(6)
3014+ spacing: units.gu(2)
3015 column: Column {
3016- spacing: units.gu(1)
3017- Label {
3018- id: trackArtist
3019- color: styleMusic.common.subtitle
3020- fontSize: "x-small"
3021- text: model.author
3022- }
3023-
3024 Label {
3025 id: trackTitle
3026 color: styleMusic.common.music
3027- fontSize: "medium"
3028+ fontSize: "small"
3029 objectName: "tracktitle"
3030 text: model.title
3031 }
3032
3033 Label {
3034- id: trackAlbum
3035+ id: trackArtist
3036 color: styleMusic.common.subtitle
3037- fontSize: "xx-small"
3038- text: model.album
3039+ fontSize: "x-small"
3040+ text: model.author
3041 }
3042 }
3043 }
3044
3045=== modified file 'MusicaddtoPlaylist.qml'
3046--- MusicaddtoPlaylist.qml 2014-09-20 10:50:45 +0000
3047+++ MusicaddtoPlaylist.qml 2014-10-16 23:15:23 +0000
3048@@ -65,7 +65,6 @@
3049 ListView {
3050 id: addtoPlaylistView
3051 anchors {
3052- bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
3053 fill: parent
3054 }
3055 clip: true
3056
3057=== modified file 'Player.qml'
3058--- Player.qml 2014-09-20 15:41:33 +0000
3059+++ Player.qml 2014-10-16 23:15:23 +0000
3060@@ -187,7 +187,11 @@
3061 else {
3062 var obj = trackQueue.model.get(player.currentIndex);
3063 currentMetaAlbum = obj.album;
3064- currentMetaArt = obj.art;
3065+
3066+ if (obj.art !== undefined) { // FIXME: protect against not art property in playlists
3067+ currentMetaArt = obj.art;
3068+ }
3069+
3070 currentMetaArtist = obj.author;
3071 currentMetaFile = obj.filename;
3072 currentMetaTitle = obj.title;
3073
3074=== modified file 'Style.qml'
3075--- Style.qml 2014-09-20 10:50:45 +0000
3076+++ Style.qml 2014-10-16 23:15:23 +0000
3077@@ -34,8 +34,8 @@
3078 property QtObject common: QtObject {
3079 property color black: "#000000";
3080 property color white: "#FFFFFF";
3081- property color music: "#333333";
3082- property color subtitle: "#666666";
3083+ property color music: "#FFFFFF";
3084+ property color subtitle: "#999999";
3085 property color expandedColor: "#000000";
3086 property int albumSize: units.gu(10);
3087 property int itemHeight: units.gu(12);
3088
3089=== modified file 'com.ubuntu.music_music.desktop.in.in'
3090--- com.ubuntu.music_music.desktop.in.in 2014-07-21 14:49:14 +0000
3091+++ com.ubuntu.music_music.desktop.in.in 2014-10-16 23:15:23 +0000
3092@@ -9,4 +9,7 @@
3093 StartupNotify=true
3094 X-Ubuntu-Touch=true
3095 X-Ubuntu-Single-Instance=true
3096+X-Ubuntu-Splash-Show-Header=true
3097+_X-Ubuntu-Splash-Title=Music
3098+X-Ubuntu-Splash-Color=#1e1e23
3099 X-Ubuntu-Default-Department-ID=sound-video
3100
3101=== modified file 'common/AlbumsPage.qml'
3102--- common/AlbumsPage.qml 2014-10-07 02:15:06 +0000
3103+++ common/AlbumsPage.qml 2014-10-16 23:15:23 +0000
3104@@ -28,7 +28,6 @@
3105
3106 MusicPage {
3107 id: albumStackPage
3108- anchors.bottomMargin: units.gu(.5)
3109 objectName: "albumsArtistPage"
3110 visible: false
3111
3112@@ -38,7 +37,6 @@
3113 ListView {
3114 id: albumtrackslist
3115 anchors {
3116- bottomMargin: wideAspect ? musicToolbar.fullHeight : musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
3117 fill: parent
3118 }
3119 delegate: albumTracksDelegate
3120@@ -365,7 +363,6 @@
3121 anchors.fill: parent
3122 onClicked: {
3123 Library.addRecent(model.title, artist, "", model.title, "album")
3124- mainView.hasRecent = true
3125 recentModel.filterRecent()
3126 trackClicked(songAlbumArtistModel, 0, true)
3127 }
3128
3129=== modified file 'common/BlurredBackground.qml'
3130--- common/BlurredBackground.qml 2014-09-20 15:41:33 +0000
3131+++ common/BlurredBackground.qml 2014-10-16 23:15:23 +0000
3132@@ -23,8 +23,14 @@
3133
3134 // Blurred background
3135 Rectangle {
3136- anchors.fill: parent
3137- property string art: player.currentMetaFile === "" ? Qt.resolvedUrl("../images/music-app-cover@30.png") : player.currentMetaArt
3138+ width: parent.width
3139+ property string art // : player.currentMetaFile === "" ? Qt.resolvedUrl("../images/music-app-cover@30.png") : player.currentMetaArt
3140+
3141+ // dark layer
3142+ Rectangle {
3143+ anchors.fill: parent
3144+ color: "black"
3145+ }
3146
3147 // the album art
3148 Image {
3149@@ -32,7 +38,8 @@
3150 anchors.horizontalCenter: parent.horizontalCenter
3151 anchors.verticalCenter: parent.verticalCenter
3152 source: art // this has to be fixed for the default cover art to work - cant find in this dir
3153- height: Math.max(parent.height, parent.width)
3154+ fillMode: Image.PreserveAspectCrop
3155+ height: parent.height
3156 width: Math.max(parent.height, parent.width)
3157 visible: false
3158 onStatusChanged: {
3159@@ -47,12 +54,7 @@
3160 anchors.fill: backgroundImage
3161 source: backgroundImage
3162 radius: units.dp(42)
3163- }
3164- // transparent white layer
3165- Rectangle {
3166- anchors.fill: parent
3167- color: "white"
3168- opacity: 0.7
3169+ opacity: 0.2
3170 }
3171 onArtChanged: {
3172 // TODO: This is a work around for LP:1261078 and LP:1306845. Ideally,
3173
3174=== added file 'common/Card.qml'
3175--- common/Card.qml 1970-01-01 00:00:00 +0000
3176+++ common/Card.qml 2014-10-16 23:15:23 +0000
3177@@ -0,0 +1,151 @@
3178+/*
3179+ * Copyright (C) 2014
3180+ * Andrew Hayzen <ahayzen@gmail.com>
3181+ *
3182+ * This program is free software; you can redistribute it and/or modify
3183+ * it under the terms of the GNU General Public License as published by
3184+ * the Free Software Foundation; version 3.
3185+ *
3186+ * This program is distributed in the hope that it will be useful,
3187+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3188+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3189+ * GNU General Public License for more details.
3190+ *
3191+ * You should have received a copy of the GNU General Public License
3192+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3193+ */
3194+
3195+import QtQuick 2.3
3196+import Ubuntu.Components 1.1
3197+
3198+
3199+Rectangle {
3200+ id: card
3201+ color: "transparent"
3202+ height: cardColumn.childrenRect.height + 2 * bg.anchors.margins
3203+
3204+ property alias coverSources: coverGrid.covers
3205+ property alias primaryText: primaryLabel.text
3206+ property alias secondaryText: secondaryLabel.text
3207+ property alias secondaryTextVisible: secondaryLabel.visible
3208+
3209+ signal clicked(var mouse)
3210+ signal pressAndHold(var mouse)
3211+
3212+ /* Animations */
3213+ Behavior on height {
3214+ UbuntuNumberAnimation {
3215+
3216+ }
3217+ }
3218+
3219+ Behavior on width {
3220+ UbuntuNumberAnimation {
3221+
3222+ }
3223+ }
3224+
3225+ Behavior on x {
3226+ UbuntuNumberAnimation {
3227+
3228+ }
3229+ }
3230+
3231+ Behavior on y {
3232+ UbuntuNumberAnimation {
3233+
3234+ }
3235+ }
3236+
3237+ /* Background for card */
3238+ Rectangle {
3239+ id: bg
3240+ anchors {
3241+ fill: parent
3242+ margins: units.gu(1)
3243+ }
3244+ color: "#2c2c34"
3245+ }
3246+
3247+ /* Column containing image and labels */
3248+ Column {
3249+ id: cardColumn
3250+ anchors {
3251+ fill: bg
3252+ }
3253+ spacing: units.gu(0.5)
3254+
3255+ CoverGrid {
3256+ id: coverGrid
3257+ size: parent.width
3258+ }
3259+
3260+ Rectangle {
3261+ color: "transparent"
3262+ height: units.gu(1)
3263+ width: units.gu(1)
3264+ }
3265+
3266+ Label {
3267+ id: primaryLabel
3268+ anchors {
3269+ left: parent.left
3270+ leftMargin: units.gu(1)
3271+ right: parent.right
3272+ rightMargin: units.gu(1)
3273+ }
3274+ color: "#FFF"
3275+ elide: Text.ElideRight
3276+ fontSize: "small"
3277+ opacity: 1.0
3278+ wrapMode: Text.WordWrap
3279+ }
3280+
3281+ Label {
3282+ id: secondaryLabel
3283+ anchors {
3284+ left: parent.left
3285+ leftMargin: units.gu(1)
3286+ right: parent.right
3287+ rightMargin: units.gu(1)
3288+ }
3289+ color: "#FFF"
3290+ elide: Text.ElideRight
3291+ fontSize: "small"
3292+ opacity: 0.4
3293+ wrapMode: Text.WordWrap
3294+ }
3295+
3296+ Rectangle {
3297+ color: "transparent"
3298+ height: units.gu(1.5)
3299+ width: units.gu(1)
3300+ }
3301+ }
3302+
3303+ /* Overlay for when card is pressed */
3304+ Rectangle {
3305+ id: overlay
3306+ anchors {
3307+ fill: bg
3308+ }
3309+ color: "#000"
3310+ opacity: 0
3311+
3312+ Behavior on opacity {
3313+ UbuntuNumberAnimation {
3314+
3315+ }
3316+ }
3317+ }
3318+
3319+ /* Capture mouse events */
3320+ MouseArea {
3321+ anchors {
3322+ fill: parent
3323+ }
3324+ onClicked: card.clicked(mouse)
3325+ onPressAndHold: card.pressAndHold(mouse)
3326+ onPressedChanged: overlay.opacity = pressed ? 0.3 : 0
3327+ }
3328+}
3329
3330=== added file 'common/CardView.qml'
3331--- common/CardView.qml 1970-01-01 00:00:00 +0000
3332+++ common/CardView.qml 2014-10-16 23:15:23 +0000
3333@@ -0,0 +1,43 @@
3334+/*
3335+ * Copyright (C) 2014
3336+ * Andrew Hayzen <ahayzen@gmail.com>
3337+ *
3338+ * This program is free software; you can redistribute it and/or modify
3339+ * it under the terms of the GNU General Public License as published by
3340+ * the Free Software Foundation; version 3.
3341+ *
3342+ * This program is distributed in the hope that it will be useful,
3343+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3344+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3345+ * GNU General Public License for more details.
3346+ *
3347+ * You should have received a copy of the GNU General Public License
3348+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3349+ */
3350+
3351+import QtQuick 2.3
3352+import Ubuntu.Components 1.1
3353+
3354+
3355+Flickable {
3356+ anchors {
3357+ fill: parent
3358+ margins: units.gu(1)
3359+ }
3360+
3361+ // dont use flow.contentHeight as it is inaccurate due to height of labels
3362+ // changing as they load
3363+ contentHeight: flow.childrenRect.height
3364+ contentWidth: width
3365+
3366+ property alias count: flow.count
3367+ property alias delegate: flow.delegate
3368+ property alias model: flow.model
3369+ property real itemWidth: units.gu(15)
3370+
3371+ ColumnFlow {
3372+ id: flow
3373+ columns: parseInt(width / itemWidth)
3374+ width: parent.width
3375+ }
3376+}
3377
3378=== added file 'common/ColumnFlow.qml'
3379--- common/ColumnFlow.qml 1970-01-01 00:00:00 +0000
3380+++ common/ColumnFlow.qml 2014-10-16 23:15:23 +0000
3381@@ -0,0 +1,160 @@
3382+/*
3383+ * Copyright (C) 2014
3384+ * Andrew Hayzen <ahayzen@gmail.com>
3385+ * Michael Spencer <sonrisesoftware@gmail.com>
3386+ *
3387+ * This program is free software; you can redistribute it and/or modify
3388+ * it under the terms of the GNU General Public License as published by
3389+ * the Free Software Foundation; version 3.
3390+ *
3391+ * This program is distributed in the hope that it will be useful,
3392+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3393+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3394+ * GNU General Public License for more details.
3395+ *
3396+ * You should have received a copy of the GNU General Public License
3397+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3398+ *
3399+ * Upstream location:
3400+ * https://github.com/iBeliever/ubuntu-ui-extras/blob/master/ColumnFlow.qml
3401+ */
3402+
3403+import QtQuick 2.3
3404+
3405+
3406+Item {
3407+ id: columnFlow
3408+ property int columns: 1
3409+ property bool repeaterCompleted: false
3410+ property alias count: repeater.count
3411+ property alias model: repeater.model
3412+ property alias delegate: repeater.delegate
3413+ property int contentHeight: 0
3414+
3415+ onColumnsChanged: reEvalColumns()
3416+ onModelChanged: reEvalColumns()
3417+ onWidthChanged: updateWidths()
3418+
3419+ function updateWidths() {
3420+ if (repeaterCompleted) {
3421+ var count = 0
3422+
3423+ //add the first <column> elements
3424+ for (var i = 0; count < columns && i < columnFlow.children.length; i++) {
3425+ //print(i, count)
3426+ if (!columnFlow.children[i] || String(columnFlow.children[i]).indexOf("QQuickRepeater") == 0)
3427+ //|| !columnFlow.children[i].visible) // CUSTOM - view is invisible at start
3428+ continue
3429+
3430+ columnFlow.children[i].width = width / columns
3431+
3432+ count++
3433+ }
3434+ }
3435+ }
3436+
3437+ function reEvalColumns() {
3438+ if (columnFlow.repeaterCompleted === false)
3439+ return
3440+
3441+ if (columns === 0) {
3442+ contentHeight = 0
3443+ return
3444+ }
3445+
3446+ var i, j
3447+ var columnHeights = new Array(columns);
3448+ var lastItem = new Array(columns)
3449+ var lastI = -1
3450+ var count = 0
3451+
3452+ //add the first <column> elements
3453+ for (i = 0; count < columns && i < columnFlow.children.length; i++) {
3454+ // CUSTOM - ignore if has just been removed
3455+ if (i === repeater.removeHintIndex && columnFlow.children[i] === repeater.removeHintItem) {
3456+ continue
3457+ }
3458+
3459+ if (!columnFlow.children[i] || String(columnFlow.children[i]).indexOf("QQuickRepeater") == 0)
3460+ //|| !columnFlow.children[i].visible) // CUSTOM - view is invisible at start
3461+ continue
3462+
3463+ lastItem[count] = i
3464+
3465+ columnHeights[count] = columnFlow.children[i].height
3466+ columnFlow.children[i].anchors.top = columnFlow.top
3467+ columnFlow.children[i].anchors.left = (lastI === -1 ? columnFlow.left : columnFlow.children[lastI].right)
3468+ columnFlow.children[i].anchors.right = undefined
3469+ columnFlow.children[i].width = columnFlow.width / columns
3470+
3471+ lastI = i
3472+ count++
3473+ }
3474+
3475+ //add the other elements
3476+ for (i = i; i < columnFlow.children.length; i++) {
3477+ var highestHeight = Number.MAX_VALUE
3478+ var newColumn = 0
3479+
3480+ // CUSTOM - ignore if has just been removed
3481+ if (i === repeater.removeHintIndex && columnFlow.children[i] === repeater.removeHintItem) {
3482+ continue
3483+ }
3484+
3485+ if (!columnFlow.children[i] || String(columnFlow.children[i]).indexOf("QQuickRepeater") == 0)
3486+ //|| !columnFlow.children[i].visible) // CUSTOM - view is invisible at start
3487+ continue
3488+
3489+ // find the shortest column
3490+ for (j = 0; j < columns; j++) {
3491+ if (columnHeights[j] !== null && columnHeights[j] < highestHeight) {
3492+ newColumn = j
3493+ highestHeight = columnHeights[j]
3494+ }
3495+ }
3496+
3497+ // add the element to the shortest column
3498+ columnFlow.children[i].anchors.top = columnFlow.children[lastItem[newColumn]].bottom
3499+ columnFlow.children[i].anchors.left = columnFlow.children[lastItem[newColumn]].left
3500+ columnFlow.children[i].anchors.right = columnFlow.children[lastItem[newColumn]].right
3501+
3502+ lastItem[newColumn] = i
3503+ columnHeights[newColumn] += columnFlow.children[i].height
3504+ }
3505+
3506+ var cHeight = 0
3507+
3508+ for (i = 0; i < columnHeights.length; i++) {
3509+ if (columnHeights[i])
3510+ cHeight = Math.max(cHeight, columnHeights[i])
3511+ }
3512+
3513+ contentHeight = cHeight
3514+ updateWidths()
3515+ }
3516+
3517+ Repeater {
3518+ id: repeater
3519+ model: columnFlow.model
3520+ Component.onCompleted: {
3521+ columnFlow.repeaterCompleted = true
3522+ columnFlow.reEvalColumns()
3523+ }
3524+
3525+ // Provide a hint of the removed item
3526+ property int removeHintIndex: -1 // CUSTOM
3527+ property var removeHintItem // CUSTOM
3528+
3529+ onItemAdded: columnFlow.reEvalColumns() // CUSTOM - ms2 models are live
3530+ onItemRemoved: {
3531+ removeHintIndex = index
3532+ removeHintItem = item
3533+
3534+ columnFlow.reEvalColumns() // CUSTOM - ms2 models are live
3535+
3536+ // Set back to null to allow freeing of memory
3537+ removeHintIndex = -1
3538+ removeHintItem = undefined
3539+ }
3540+ }
3541+}
3542
3543=== added file 'common/CoverGrid.qml'
3544--- common/CoverGrid.qml 1970-01-01 00:00:00 +0000
3545+++ common/CoverGrid.qml 2014-10-16 23:15:23 +0000
3546@@ -0,0 +1,71 @@
3547+/*
3548+ * Copyright (C) 2013, 2014
3549+ * Andrew Hayzen <ahayzen@gmail.com>
3550+ * Nekhelesh Ramananthan <krnekhelesh@gmail.com>
3551+ * Victor Thompson <victor.thompson@gmail.com>
3552+ *
3553+ * This program is free software; you can redistribute it and/or modify
3554+ * it under the terms of the GNU General Public License as published by
3555+ * the Free Software Foundation; version 3.
3556+ *
3557+ * This program is distributed in the hope that it will be useful,
3558+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3559+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3560+ * GNU General Public License for more details.
3561+ *
3562+ * You should have received a copy of the GNU General Public License
3563+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3564+ */
3565+
3566+import QtQuick 2.3
3567+import Ubuntu.Components 1.1
3568+
3569+Rectangle {
3570+ id: coverGrid
3571+ color: "transparent"
3572+ height: size
3573+ width: size
3574+
3575+ // Property (array) to store the cover images
3576+ property var covers
3577+
3578+ // Property to set the size of the cover image
3579+ property int size
3580+
3581+ onCoversChanged: {
3582+ if (covers !== undefined) {
3583+ while (covers.length > 4) { // remove any covers after 4
3584+ covers.pop()
3585+ }
3586+ }
3587+ }
3588+
3589+ // Flow of the cover arts in either 1, 1x1, 2x1, 2x2
3590+ Flow {
3591+ id: imageRow
3592+ anchors {
3593+ fill: parent
3594+ }
3595+
3596+ Repeater {
3597+ id: repeat
3598+ model: coverGrid.covers.length === 0 ? 1 : coverGrid.covers.length
3599+ delegate: Image {
3600+ fillMode: Image.PreserveAspectCrop
3601+ height: coverGrid.size / (coverGrid.covers.length > 1 ? 2 : 1)
3602+ width: coverGrid.size / (coverGrid.covers.length > 2 && !(coverGrid.covers.length === 3 && index === 2) ? 2 : 1)
3603+ source: coverGrid.covers.length !== 0 && coverGrid.covers[index] !== "" && coverGrid.covers[index] !== undefined
3604+ ? (coverGrid.covers[index].art !== undefined
3605+ ? coverGrid.covers[index].art
3606+ : "image://albumart/artist=" + coverGrid.covers[index].author + "&album=" + coverGrid.covers[index].album)
3607+ : Qt.resolvedUrl("../images/music-app-cover@30.png")
3608+ onStatusChanged: {
3609+ if (status === Image.Error) {
3610+ source = Qt.resolvedUrl("../images/music-app-cover@30.png")
3611+ }
3612+ }
3613+ }
3614+ }
3615+ }
3616+}
3617+
3618
3619=== removed file 'common/ListItemActions/DeletePlaylist.qml'
3620--- common/ListItemActions/DeletePlaylist.qml 2014-09-20 10:50:45 +0000
3621+++ common/ListItemActions/DeletePlaylist.qml 1970-01-01 00:00:00 +0000
3622@@ -1,29 +0,0 @@
3623-/*
3624- * Copyright (C) 2014 Andrew Hayzen <ahayzen@gmail.com>
3625- * Daniel Holm <d.holmen@gmail.com>
3626- * Victor Thompson <victor.thompson@gmail.com>
3627- *
3628- * This program is free software; you can redistribute it and/or modify
3629- * it under the terms of the GNU General Public License as published by
3630- * the Free Software Foundation; version 3.
3631- *
3632- * This program is distributed in the hope that it will be useful,
3633- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3634- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3635- * GNU General Public License for more details.
3636- *
3637- * You should have received a copy of the GNU General Public License
3638- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3639- */
3640-
3641-import QtQuick 2.3
3642-import Ubuntu.Components 1.1
3643-import Ubuntu.Components.Popups 1.0
3644-
3645-Action {
3646- iconName: "delete"
3647- // TRANSLATORS: this refers to deleting a playlist
3648- text: i18n.tr("Delete")
3649-
3650- property bool primed: false
3651-}
3652
3653=== removed file 'common/ListItemActions/EditPlaylist.qml'
3654--- common/ListItemActions/EditPlaylist.qml 2014-09-20 10:50:45 +0000
3655+++ common/ListItemActions/EditPlaylist.qml 1970-01-01 00:00:00 +0000
3656@@ -1,35 +0,0 @@
3657-/*
3658- * Copyright (C) 2014 Andrew Hayzen <ahayzen@gmail.com>
3659- * Daniel Holm <d.holmen@gmail.com>
3660- * Victor Thompson <victor.thompson@gmail.com>
3661- *
3662- * This program is free software; you can redistribute it and/or modify
3663- * it under the terms of the GNU General Public License as published by
3664- * the Free Software Foundation; version 3.
3665- *
3666- * This program is distributed in the hope that it will be useful,
3667- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3668- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3669- * GNU General Public License for more details.
3670- *
3671- * You should have received a copy of the GNU General Public License
3672- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3673- */
3674-
3675-import QtQuick 2.3
3676-import Ubuntu.Components 1.1
3677-import Ubuntu.Components.Popups 1.0
3678-
3679-Action {
3680- iconName: "edit"
3681- // TRANSLATORS: this refers to editing a playlist
3682- text: i18n.tr("Edit")
3683-
3684- property bool primed: false
3685-
3686- onTriggered: {
3687- customdebug("Edit playlist")
3688- oldPlaylistName = model.name
3689- PopupUtils.open(editPlaylistDialog, mainView)
3690- }
3691-}
3692
3693=== modified file 'common/MusicPage.qml'
3694--- common/MusicPage.qml 2014-08-20 17:35:52 +0000
3695+++ common/MusicPage.qml 2014-10-16 23:15:23 +0000
3696@@ -23,6 +23,10 @@
3697 // generic page for music, could be useful for bottomedge implementation
3698 Page {
3699 id: thisPage
3700+ anchors {
3701+ bottomMargin: musicToolbar.visible ? musicToolbar.currentHeight : 0
3702+ fill: parent
3703+ }
3704
3705 onVisibleChanged: {
3706 if (visible) {
3707
3708=== modified file 'common/MusicRow.qml'
3709--- common/MusicRow.qml 2014-09-20 10:50:45 +0000
3710+++ common/MusicRow.qml 2014-10-16 23:15:23 +0000
3711@@ -24,35 +24,64 @@
3712 Row {
3713 anchors {
3714 left: parent.left
3715- leftMargin: units.gu(1)
3716+ leftMargin: units.gu(2)
3717 right: parent.right
3718- rightMargin: units.gu(1)
3719+ rightMargin: units.gu(2)
3720 }
3721
3722 property alias covers: coverRow.covers
3723+ property bool showCovers: true
3724+ property bool isSquare: false
3725 property alias pressed: coverRow.pressed
3726 property alias column: columnComponent.sourceComponent
3727+ property real coverSize: styleMusic.common.albumSize
3728
3729 spacing: units.gu(1)
3730
3731 CoverRow {
3732 id: coverRow
3733+ visible: showCovers && !isSquare
3734 anchors {
3735 top: parent.top
3736 topMargin: units.gu(1)
3737 }
3738 count: covers.length
3739 covers: []
3740- size: styleMusic.common.albumSize
3741+ size: coverSize
3742+ }
3743+
3744+ Image {
3745+ id: coverSquare
3746+ visible: showCovers && isSquare
3747+ width: coverSize
3748+ height: coverSize
3749+ anchors {
3750+ verticalCenter: parent.verticalCenter
3751+ topMargin: units.gu(0.5)
3752+ bottomMargin: units.gu(0.5)
3753+ leftMargin: units.gu(2)
3754+ }
3755+ source: coverRow.count !== 0 && coverRow.covers[0] !== "" && coverRow.covers[0] !== undefined
3756+ ? (coverRow.covers[0].art !== undefined
3757+ ? coverRow.covers[0].art
3758+ : "image://albumart/artist=" + coverRow.covers[0].author + "&album=" + coverRow.covers[0].album)
3759+ : Qt.resolvedUrl("../images/music-app-cover@30.png")
3760+ onStatusChanged: {
3761+ if (status === Image.Error) {
3762+ source = Qt.resolvedUrl("../images/music-app-cover@30.png")
3763+ }
3764+ }
3765 }
3766
3767 Loader {
3768 id: columnComponent
3769 anchors {
3770 top: parent.top
3771- topMargin: units.gu(2)
3772+ topMargin: units.gu(1)
3773 }
3774- width: parent.width - coverRow.width - parent.spacing
3775+ width: !showCovers ? parent.width - parent.spacing
3776+ : (isSquare ? parent.width - coverSquare.width - parent.spacing
3777+ : parent.width - coverRow.width - parent.spacing)
3778
3779 onSourceComponentChanged: {
3780 for (var i=0; i < item.children.length; i++) {
3781
3782=== modified file 'common/SongsPage.qml'
3783--- common/SongsPage.qml 2014-09-20 15:41:33 +0000
3784+++ common/SongsPage.qml 2014-10-16 23:15:23 +0000
3785@@ -20,6 +20,7 @@
3786 import QtQuick 2.3
3787 import Ubuntu.Components 1.1
3788 import Ubuntu.Components.ListItems 1.0 as ListItem
3789+import Ubuntu.Components.Popups 1.0
3790 import Ubuntu.MediaScanner 0.1
3791 import Ubuntu.Thumbnailer 0.1
3792 import QtQuick.LocalStorage 2.0
3793@@ -29,7 +30,6 @@
3794
3795 MusicPage {
3796 id: songStackPage
3797- anchors.bottomMargin: units.gu(.5)
3798 objectName: "songsPage"
3799 visible: false
3800
3801@@ -44,6 +44,47 @@
3802 property alias album: songsModel.album
3803 property alias genre: songsModel.genre
3804
3805+ state: songStackPage.line1 === i18n.tr("Playlist") ? "playlist" : "album"
3806+ states: [
3807+ PageHeadState {
3808+ id: albumState
3809+ name: "album"
3810+ PropertyChanges {
3811+ target: songStackPage.head
3812+ backAction: albumState.backAction
3813+ actions: albumState.actions
3814+ }
3815+ },
3816+ PageHeadState {
3817+ id: playlistState
3818+
3819+ name: "playlist"
3820+ actions: [
3821+ Action {
3822+ objectName: "editPlaylist"
3823+ iconName: "edit"
3824+ onTriggered: {
3825+ var dialog = PopupUtils.open(editPlaylistDialog, mainView)
3826+ dialog.oldPlaylistName = line2
3827+ }
3828+ },
3829+ Action {
3830+ objectName: "deletePlaylist"
3831+ iconName: "delete"
3832+ onTriggered: {
3833+ var dialog = PopupUtils.open(removePlaylistDialog, mainView)
3834+ dialog.oldPlaylistName = line2
3835+ }
3836+ }
3837+ ]
3838+ PropertyChanges {
3839+ target: songStackPage.head
3840+ backAction: playlistState.backAction
3841+ actions: playlistState.actions
3842+ }
3843+ }
3844+ ]
3845+
3846 SongsModel {
3847 id: songsModel
3848 store: musicStore
3849@@ -52,7 +93,6 @@
3850 ListView {
3851 id: albumtrackslist
3852 anchors {
3853- bottomMargin: wideAspect ? musicToolbar.fullHeight : musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
3854 fill: parent
3855 }
3856 delegate: albumTracksDelegate
3857@@ -61,19 +101,47 @@
3858 width: parent.width
3859 header: ListItem.Standard {
3860 id: albumInfo
3861- height: units.gu(22)
3862-
3863- CoverRow {
3864- id: albumImage
3865+ height: albumArtist.visible ? units.gu(33) : units.gu(30)
3866+
3867+ BlurredBackground {
3868+ id: blurredBackground
3869+ height: parent.height
3870+ art: coversImage.covers.length > 0
3871+ ? (coversImage.covers[0].art !== undefined
3872+ ? coversImage.covers[0].art
3873+ : decodeURIComponent("image://albumart/artist=" + coversImage.covers[0].author + "&album=" + coversImage.covers[0].album))
3874+ : Qt.resolvedUrl("../images/music-app-cover@30.png")
3875+ }
3876+
3877+ CoverGrid {
3878+ id: coversImage
3879 anchors {
3880 top: parent.top
3881 left: parent.left
3882- margins: units.gu(1)
3883+ topMargin: units.gu(3)
3884+ bottomMargin: units.gu(2)
3885+ leftMargin: units.gu(2)
3886+ rightMargin: units.gu(2)
3887 }
3888- count: songStackPage.covers.length
3889- size: units.gu(20)
3890 covers: songStackPage.covers
3891- spacing: units.gu(2)
3892+ size: units.gu(18)
3893+ }
3894+
3895+ Label {
3896+ id: albumLabel
3897+ wrapMode: Text.NoWrap
3898+ maximumLineCount: 1
3899+ fontSize: "x-large"
3900+ color: styleMusic.common.music
3901+ anchors {
3902+ top: coversImage.bottom
3903+ topMargin: units.gu(1)
3904+ left: coversImage.left
3905+ right: parent.right
3906+ rightMargin: units.gu(2)
3907+ }
3908+ elide: Text.ElideRight
3909+ text: line2
3910 }
3911
3912 Label {
3913@@ -83,77 +151,113 @@
3914 maximumLineCount: 1
3915 fontSize: "small"
3916 color: styleMusic.common.subtitle
3917- anchors.left: albumImage.right
3918- anchors.leftMargin: units.gu(1)
3919- anchors.top: parent.top
3920- anchors.topMargin: units.gu(1.5)
3921- anchors.right: parent.right
3922- anchors.rightMargin: units.gu(1.5)
3923+ visible: text !== i18n.tr("Playlist") &&
3924+ text !== i18n.tr("Genre")
3925+ anchors {
3926+ top: albumLabel.bottom
3927+ topMargin: units.gu(0.75)
3928+ left: coversImage.left
3929+ right: parent.right
3930+ rightMargin: units.gu(2)
3931+ }
3932 elide: Text.ElideRight
3933 text: line1
3934 }
3935- Label {
3936- id: albumLabel
3937- wrapMode: Text.NoWrap
3938- maximumLineCount: 2
3939- fontSize: "medium"
3940- color: styleMusic.common.music
3941- anchors.left: albumImage.right
3942- anchors.leftMargin: units.gu(1)
3943- anchors.top: albumArtist.bottom
3944- anchors.topMargin: units.gu(0.8)
3945- anchors.right: parent.right
3946- anchors.rightMargin: units.gu(1.5)
3947- elide: Text.ElideRight
3948- text: line2
3949- }
3950+
3951 Label {
3952 id: albumYear
3953 wrapMode: Text.NoWrap
3954 maximumLineCount: 1
3955- fontSize: "x-small"
3956+ fontSize: "small"
3957 color: styleMusic.common.subtitle
3958- anchors.left: albumImage.right
3959- anchors.leftMargin: units.gu(1)
3960- anchors.top: albumLabel.bottom
3961- anchors.topMargin: units.gu(2)
3962- anchors.right: parent.right
3963- anchors.rightMargin: units.gu(1.5)
3964+ anchors {
3965+ top: albumArtist.visible ? albumArtist.bottom
3966+ : albumLabel.bottom
3967+ topMargin: units.gu(1)
3968+ left: coversImage.left
3969+ right: parent.right
3970+ rightMargin: units.gu(2)
3971+ }
3972 elide: Text.ElideRight
3973 text: isAlbum && line1 !== i18n.tr("Genre") ? year + " | " + i18n.tr("%1 song", "%1 songs", albumtrackslist.count).arg(albumtrackslist.count)
3974 : i18n.tr("%1 song", "%1 songs", albumtrackslist.count).arg(albumtrackslist.count)
3975
3976 }
3977
3978+ // Shuffle
3979+ Button {
3980+ id: shuffleRow
3981+ anchors {
3982+ bottom: queueAllRow.top
3983+ bottomMargin: units.gu(2)
3984+ left: coversImage.right
3985+ leftMargin: units.gu(2)
3986+ }
3987+ strokeColor: UbuntuColors.green
3988+ height: units.gu(4)
3989+ width: units.gu(15)
3990+ Text {
3991+ anchors {
3992+ centerIn: parent
3993+ }
3994+ color: "white"
3995+ text: i18n.tr("Shuffle")
3996+ }
3997+ MouseArea {
3998+ anchors.fill: parent
3999+ onClicked: {
4000+ shuffleModel(albumtrackslist.model) // play track
4001+
4002+ if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) {
4003+ Library.addRecent(songStackPage.line2, songStackPage.line1, songStackPage.covers[0], songStackPage.line2, "album")
4004+ recentModel.filterRecent()
4005+ } else if (songStackPage.line1 === i18n.tr("Playlist")) {
4006+ Library.addRecent(songStackPage.line2, "Playlist", songStackPage.covers[0], songStackPage.line2, "playlist")
4007+ recentModel.filterRecent()
4008+ }
4009+ }
4010+ }
4011+ }
4012+
4013+ // Queue
4014+ Button {
4015+ id: queueAllRow
4016+ anchors {
4017+ bottom: playRow.top
4018+ bottomMargin: units.gu(2)
4019+ left: coversImage.right
4020+ leftMargin: units.gu(2)
4021+ }
4022+ strokeColor: UbuntuColors.green
4023+ height: units.gu(4)
4024+ width: units.gu(15)
4025+ Text {
4026+ anchors {
4027+ centerIn: parent
4028+ }
4029+ color: "white"
4030+ text: i18n.tr("Queue all")
4031+ }
4032+ MouseArea {
4033+ anchors.fill: parent
4034+ onClicked: {
4035+ addQueueFromModel(albumtrackslist.model)
4036+ }
4037+ }
4038+ }
4039+
4040 // Play
4041- Rectangle {
4042+ Button {
4043 id: playRow
4044- anchors.top: albumYear.bottom
4045- anchors.topMargin: units.gu(1)
4046- anchors.left: albumImage.right
4047- anchors.leftMargin: units.gu(1)
4048- color: "transparent"
4049+ anchors {
4050+ bottom: coversImage.bottom
4051+ left: coversImage.right
4052+ leftMargin: units.gu(2)
4053+ }
4054+ color: UbuntuColors.green
4055 height: units.gu(4)
4056 width: units.gu(15)
4057- Icon {
4058- id: playTrack
4059- objectName: "songspage-playtrack"
4060- anchors.verticalCenter: parent.verticalCenter
4061- name: "media-playback-start"
4062- height: styleMusic.common.expandedItem
4063- width: styleMusic.common.expandedItem
4064- }
4065- Label {
4066- anchors.left: playTrack.right
4067- anchors.leftMargin: units.gu(0.5)
4068- anchors.verticalCenter: parent.verticalCenter
4069- fontSize: "small"
4070- color: styleMusic.common.subtitle
4071- width: parent.width - playTrack.width - units.gu(1)
4072- text: i18n.tr("Play all")
4073- wrapMode: Text.WordWrap
4074- maximumLineCount: 3
4075- }
4076+ text: i18n.tr("Play all")
4077 MouseArea {
4078 anchors.fill: parent
4079 onClicked: {
4080@@ -161,53 +265,14 @@
4081
4082 if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) {
4083 Library.addRecent(songStackPage.line2, songStackPage.line1, songStackPage.covers[0], songStackPage.line2, "album")
4084- mainView.hasRecent = true
4085 recentModel.filterRecent()
4086 } else if (songStackPage.line1 === i18n.tr("Playlist")) {
4087 Library.addRecent(songStackPage.line2, "Playlist", songStackPage.covers[0], songStackPage.line2, "playlist")
4088- mainView.hasRecent = true
4089 recentModel.filterRecent()
4090 }
4091 }
4092 }
4093 }
4094-
4095- // Queue
4096- Rectangle {
4097- id: queueAllRow
4098- anchors.top: playRow.bottom
4099- anchors.topMargin: units.gu(1)
4100- anchors.left: albumImage.right
4101- anchors.leftMargin: units.gu(1)
4102- color: "transparent"
4103- height: units.gu(4)
4104- width: units.gu(15)
4105- Icon {
4106- id: queueAll
4107- objectName: "songspage-queue-all"
4108- anchors.verticalCenter: parent.verticalCenter
4109- name: "add"
4110- height: styleMusic.common.expandedItem
4111- width: styleMusic.common.expandedItem
4112- }
4113- Label {
4114- anchors.left: queueAll.right
4115- anchors.leftMargin: units.gu(0.5)
4116- anchors.verticalCenter: parent.verticalCenter
4117- fontSize: "small"
4118- color: styleMusic.common.subtitle
4119- width: parent.width - queueAll.width - units.gu(1)
4120- text: i18n.tr("Add to queue")
4121- wrapMode: Text.WordWrap
4122- maximumLineCount: 3
4123- }
4124- MouseArea {
4125- anchors.fill: parent
4126- onClicked: {
4127- addQueueFromModel(albumtrackslist.model)
4128- }
4129- }
4130- }
4131 }
4132
4133 Component {
4134@@ -219,7 +284,8 @@
4135 objectName: "songsPageListItem" + index
4136 iconFrame: false
4137 progression: false
4138- height: styleMusic.common.itemHeight
4139+ showDivider: false
4140+ height: units.gu(6)
4141
4142 leftSideAction: songStackPage.line1 === i18n.tr("Playlist")
4143 ? playlistRemoveAction.item : null
4144@@ -239,11 +305,9 @@
4145
4146 if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) {
4147 Library.addRecent(songStackPage.line2, songStackPage.line1, model.art, songStackPage.line2, "album")
4148- mainView.hasRecent = true
4149 recentModel.filterRecent()
4150 } else if (songStackPage.line1 === i18n.tr("Playlist")) {
4151 Library.addRecent(songStackPage.line2, "Playlist", songStackPage.covers[0], songStackPage.line2, "playlist")
4152- mainView.hasRecent = true
4153 recentModel.filterRecent()
4154 }
4155 }
4156@@ -272,30 +336,23 @@
4157
4158 MusicRow {
4159 id: musicRow
4160- covers: model.art !== undefined ? [{art: model.art}] : [{author: model.author, album: model.album}]
4161+ covers: []
4162+ showCovers: false
4163 column: Column {
4164- spacing: units.gu(1)
4165+ Label {
4166+ id: trackTitle
4167+ color: styleMusic.common.music
4168+ fontSize: "small"
4169+ objectName: "songspage-tracktitle"
4170+ text: model.title
4171+ }
4172+
4173 Label {
4174 id: trackArtist
4175 color: styleMusic.common.subtitle
4176 fontSize: "x-small"
4177 text: model.author
4178 }
4179-
4180- Label {
4181- id: trackTitle
4182- color: styleMusic.common.subtitle
4183- fontSize: "medium"
4184- objectName: "songspage-tracktitle"
4185- text: model.title
4186- }
4187-
4188- Label {
4189- id: trackAlbum
4190- color: styleMusic.common.subtitle
4191- fontSize: "xx-small"
4192- text: model.album
4193- }
4194 }
4195 }
4196
4197@@ -309,4 +366,93 @@
4198 }
4199 }
4200 }
4201+
4202+ // Edit name of playlist dialog
4203+ Component {
4204+ id: editPlaylistDialog
4205+ Dialog {
4206+ id: dialogEditPlaylist
4207+ // TRANSLATORS: this is a title of a dialog with a prompt to rename a playlist
4208+ title: i18n.tr("Change name")
4209+ text: i18n.tr("Enter the new name of the playlist.")
4210+
4211+ property alias oldPlaylistName: playlistName.placeholderText
4212+
4213+ TextField {
4214+ id: playlistName
4215+ inputMethodHints: Qt.ImhNoPredictiveText
4216+
4217+ onPlaceholderTextChanged: text = placeholderText
4218+ }
4219+ Label {
4220+ id: editplaylistoutput
4221+ color: "red"
4222+ visible: false
4223+ }
4224+
4225+ Button {
4226+ text: i18n.tr("Change")
4227+ color: styleMusic.dialog.confirmButtonColor
4228+ onClicked: {
4229+ editplaylistoutput.visible = true
4230+
4231+ if (playlistName.text.length > 0) { // make sure something is acually inputed
4232+ console.debug("Debug: User changed name from "+playlistName.placeholderText+" to "+playlistName.text)
4233+
4234+ if (Playlists.renamePlaylist(playlistName.placeholderText, playlistName.text) === true) {
4235+ playlistModel.filterPlaylists()
4236+
4237+ PopupUtils.close(dialogEditPlaylist)
4238+
4239+ line2 = playlistName.text
4240+ }
4241+ else {
4242+ editplaylistoutput.text = i18n.tr("Playlist already exists")
4243+ }
4244+ }
4245+ else {
4246+ editplaylistoutput.text = i18n.tr("Please type in a name.")
4247+ }
4248+ }
4249+ }
4250+ Button {
4251+ text: i18n.tr("Cancel")
4252+ color: styleMusic.dialog.cancelButtonColor
4253+ onClicked: PopupUtils.close(dialogEditPlaylist)
4254+ }
4255+ }
4256+ }
4257+
4258+ // Remove playlist dialog
4259+ Component {
4260+ id: removePlaylistDialog
4261+ Dialog {
4262+ id: dialogRemovePlaylist
4263+ // TRANSLATORS: this is a title of a dialog with a prompt to delete a playlist
4264+ title: i18n.tr("Are you sure?")
4265+ text: i18n.tr("This will delete your playlist.")
4266+
4267+ property string oldPlaylistName
4268+
4269+ Button {
4270+ text: i18n.tr("Remove")
4271+ color: styleMusic.dialog.confirmButtonColor
4272+ onClicked: {
4273+ // removing playlist
4274+ Playlists.removePlaylist(dialogRemovePlaylist.oldPlaylistName)
4275+
4276+ playlistModel.filterPlaylists();
4277+
4278+ PopupUtils.close(dialogRemovePlaylist)
4279+
4280+ musicToolbar.goBack()
4281+ }
4282+ }
4283+ Button {
4284+ text: i18n.tr("Cancel")
4285+ color: styleMusic.dialog.cancelButtonColor
4286+ onClicked: PopupUtils.close(dialogRemovePlaylist)
4287+ }
4288+ }
4289+ }
4290 }
4291
4292=== modified file 'music-app.qml'
4293--- music-app.qml 2014-09-23 15:59:28 +0000
4294+++ music-app.qml 2014-10-16 23:15:23 +0000
4295@@ -40,18 +40,13 @@
4296 id: mainView
4297 useDeprecatedToolbar: false
4298
4299- // Use toolbar color for header
4300- headerColor: styleMusic.toolbar.fullBackgroundColor
4301- backgroundColor: styleMusic.toolbar.fullBackgroundColor
4302+ backgroundColor: "#1e1e23"
4303+ headerColor: "#1e1e23"
4304
4305 // Global keyboard shortcuts
4306 focus: true
4307 Keys.onPressed: {
4308- if (event.key === Qt.Key_Alt) {
4309- // On alt key press show toolbar and start autohide timer
4310- musicToolbar.showToolbar();
4311- }
4312- else if(event.key === Qt.Key_Escape) {
4313+ if(event.key === Qt.Key_Escape) {
4314 musicToolbar.goBack(); // Esc Go back
4315 }
4316 else if(event.modifiers === Qt.AltModifier) {
4317@@ -94,13 +89,11 @@
4318 }
4319 break;
4320 case Qt.Key_J: // Ctrl+J Jump to playing song
4321- nowPlaying.visible = true;
4322- nowPlaying.positionAt(player.currentIndex);
4323- musicToolbar.showToolbar();
4324+ tabs.pushNowPlaying()
4325+ nowPlaying.isListView = true;
4326 break;
4327 case Qt.Key_N: // Ctrl+N Show now playing
4328- nowPlaying.visible = true;
4329- musicToolbar.showToolbar();
4330+ tabs.pushNowPlaying()
4331 break;
4332 case Qt.Key_P: // Ctrl+P Toggle playing state
4333 player.toggle();
4334@@ -218,7 +211,6 @@
4335
4336 // Add album to recent list
4337 Library.addRecent(songsAlbumArtistModel.album, songsAlbumArtistModel.artist, songsAlbumArtistModel.art, songsAlbumArtistModel.album, "album")
4338- mainView.hasRecent = true
4339 recentModel.filterRecent()
4340 }
4341
4342@@ -569,7 +561,9 @@
4343 // TODO: Switch tabs back and forth to get the background color in the
4344 // header to work properly.
4345 tabs.selectedTabIndex = 1
4346- tabs.selectedTabIndex = 0
4347+
4348+ // goto Recent if there are items otherwise go to Albums
4349+ tabs.selectedTabIndex = Library.isRecentEmpty() ? 2 : 0
4350
4351 // Run post load
4352 tabs.ensurePopulated(tabs.selectedTab);
4353@@ -577,28 +571,20 @@
4354 if (args.values.url) {
4355 uriHandler.process(args.values.url, true);
4356 }
4357-
4358- // Show toolbar and start timer if there is music
4359- if (!emptyPage.noMusic) {
4360- musicToolbar.showToolbar();
4361- musicToolbar.startAutohideTimer();
4362- }
4363 }
4364
4365 // VARIABLES
4366 property string musicName: i18n.tr("Music")
4367 property string appVersion: '1.2'
4368- property bool hasRecent: !Library.isRecentEmpty()
4369 property bool scrobble: false
4370 property string lastfmusername
4371 property string lastfmpassword
4372 property string timestamp // used to scrobble
4373 property var chosenElement: null
4374- property bool toolbarShown: musicToolbar.shown
4375+ property bool toolbarShown: musicToolbar.visible
4376 property bool selectedAlbum: false
4377
4378 signal listItemSwiping(int i)
4379- signal onToolbarShownChanged(bool shown, var currentPage, var currentTab)
4380
4381 property bool wideAspect: width >= units.gu(70) && loadedUI
4382 property bool loadedUI: false // property to detect if the UI has finished
4383@@ -679,9 +665,6 @@
4384
4385 // Show the Now Playing page and make sure the track is visible
4386 tabs.pushNowPlaying();
4387- nowPlaying.ensureVisibleIndex = index;
4388-
4389- musicToolbar.showToolbar();
4390 }
4391 else {
4392 player.source = file;
4393@@ -697,10 +680,9 @@
4394 }
4395
4396 // Show the Now Playing page and make sure the track is visible
4397- tabs.pushNowPlaying();
4398- nowPlaying.ensureVisibleIndex = index;
4399-
4400- musicToolbar.showToolbar();
4401+ if (!nowPlaying.isListView) {
4402+ tabs.pushNowPlaying();
4403+ }
4404 }
4405
4406 function playRandomSong(shuffle)
4407@@ -716,6 +698,17 @@
4408 trackClicked(allSongsModel, index, true)
4409 }
4410
4411+ function shuffleModel(model)
4412+ {
4413+ var now = new Date();
4414+ var seed = now.getSeconds();
4415+ var index = Math.floor(model.count * Math.random(seed));
4416+
4417+ player.shuffle = true;
4418+
4419+ trackClicked(model, index, true)
4420+ }
4421+
4422 // Load mediascanner store
4423 MediaStore {
4424 id: musicStore
4425@@ -867,10 +860,6 @@
4426 id: searchSheet
4427 }
4428
4429- // Blurred background
4430- BlurredBackground {
4431- }
4432-
4433 // Popover for tracks, queue and add to playlist, for example
4434 Component {
4435 id: trackPopoverComponent
4436@@ -973,6 +962,7 @@
4437
4438 MusicToolbar {
4439 id: musicToolbar
4440+ visible: nowPlaying.isListView || !nowPlaying.visible
4441 objectName: "musicToolbarObject"
4442 z: 200 // put on top of everything else
4443 }
4444@@ -983,7 +973,6 @@
4445 Tabs {
4446 id: tabs
4447 anchors {
4448- bottomMargin: wideAspect ? musicToolbar.fullHeight : undefined
4449 fill: parent
4450 }
4451
4452@@ -1110,6 +1099,8 @@
4453 if (mainPageStack.currentPage !== nowPlaying) {
4454 mainPageStack.push(nowPlaying);
4455 }
4456+
4457+ nowPlaying.isListView = false; // ensure full view
4458 }
4459
4460 Component.onCompleted: musicToolbar.currentTab = selectedTab
4461
4462=== modified file 'po/com.ubuntu.music.pot'
4463--- po/com.ubuntu.music.pot 2014-09-23 12:44:36 +0000
4464+++ po/com.ubuntu.music.pot 2014-10-16 23:15:23 +0000
4465@@ -8,7 +8,7 @@
4466 msgstr ""
4467 "Project-Id-Version: music-app\n"
4468 "Report-Msgid-Bugs-To: \n"
4469-"POT-Creation-Date: 2014-09-23 13:43+0100\n"
4470+"POT-Creation-Date: 2014-10-14 01:06+0100\n"
4471 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
4472 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
4473 "Language-Team: LANGUAGE <LL@li.org>\n"
4474@@ -18,7 +18,7 @@
4475 "Content-Transfer-Encoding: 8bit\n"
4476 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
4477
4478-#: ../LoginLastFM.qml:48 ../MusicSettings.qml:145 ../MusicSettings.qml:153
4479+#: ../LoginLastFM.qml:48 ../MusicSettings.qml:134 ../MusicSettings.qml:142
4480 msgid "Last.fm"
4481 msgstr ""
4482
4483@@ -54,12 +54,12 @@
4484 msgid "You forgot to set your username and/or password"
4485 msgstr ""
4486
4487-#: ../MusicAlbums.qml:35 ../MusicStart.qml:392
4488+#: ../MusicAlbums.qml:29 ../MusicStart.qml:392
4489 msgid "Albums"
4490 msgstr ""
4491
4492-#: ../MusicAlbums.qml:152 ../MusicStart.qml:200 ../MusicStart.qml:454
4493-#: ../common/AlbumsPage.qml:264
4494+#: ../MusicAlbums.qml:57 ../MusicStart.qml:200 ../MusicStart.qml:454
4495+#: ../common/AlbumsPage.qml:262
4496 msgid "Album"
4497 msgstr ""
4498
4499@@ -67,164 +67,133 @@
4500 msgid "Artists"
4501 msgstr ""
4502
4503-#: ../MusicArtists.qml:107 ../common/AlbumsPage.qml:112
4504-#, qt-format
4505-msgid "%1 album"
4506-msgid_plural "%1 albums"
4507-msgstr[0] ""
4508-msgstr[1] ""
4509-
4510-#: ../MusicArtists.qml:113 ../MusicPlaylists.qml:180 ../MusicStart.qml:371
4511-#: ../MusicaddtoPlaylist.qml:106 ../common/AlbumsPage.qml:331
4512-#: ../common/SongsPage.qml:123 ../common/SongsPage.qml:124
4513-#, qt-format
4514-msgid "%1 song"
4515-msgid_plural "%1 songs"
4516-msgstr[0] ""
4517-msgstr[1] ""
4518-
4519-#: ../MusicArtists.qml:123
4520+#: ../MusicArtists.qml:78
4521 msgid "Artist"
4522 msgstr ""
4523
4524 #: ../MusicNowPlaying.qml:33
4525-msgid "Now Playing"
4526+msgid "Queue"
4527+msgstr ""
4528+
4529+#: ../MusicNowPlaying.qml:33
4530+msgid "Now playing"
4531 msgstr ""
4532
4533 #. TRANSLATORS: this is the name of the playlists page shown in the tab header.
4534 #. Remember to keep the translation short to fit the screen width
4535-#: ../MusicPlaylists.qml:38
4536+#: ../MusicPlaylists.qml:35
4537 msgid "Playlists"
4538 msgstr ""
4539
4540-#: ../MusicPlaylists.qml:48 ../MusicaddtoPlaylist.qml:48
4541-msgid "New playlist"
4542-msgstr ""
4543-
4544-#. TRANSLATORS: this is a title of a dialog with a prompt to rename a playlist
4545-#: ../MusicPlaylists.qml:64
4546-msgid "Change name"
4547-msgstr ""
4548-
4549-#: ../MusicPlaylists.qml:65
4550-msgid "Enter the new name of the playlist."
4551-msgstr ""
4552-
4553-#: ../MusicPlaylists.qml:78
4554-msgid "Change"
4555-msgstr ""
4556-
4557-#: ../MusicPlaylists.qml:96 ../music-app.qml:956
4558-msgid "Playlist already exists"
4559-msgstr ""
4560-
4561-#: ../MusicPlaylists.qml:100 ../music-app.qml:961
4562-msgid "Please type in a name."
4563-msgstr ""
4564-
4565-#: ../MusicPlaylists.qml:105 ../music-app.qml:493 ../music-app.qml:967
4566-msgid "Cancel"
4567-msgstr ""
4568-
4569-#: ../MusicPlaylists.qml:159 ../MusicPlaylists.qml:163 ../MusicStart.qml:118
4570-#: ../MusicStart.qml:200 ../common/SongsPage.qml:166
4571-#: ../common/SongsPage.qml:224 ../common/SongsPage.qml:226
4572-#: ../common/SongsPage.qml:244
4573+#: ../MusicPlaylists.qml:61 ../MusicStart.qml:371
4574+#: ../MusicaddtoPlaylist.qml:105 ../common/AlbumsPage.qml:329
4575+#: ../common/SongsPage.qml:184 ../common/SongsPage.qml:185
4576+#, qt-format
4577+msgid "%1 song"
4578+msgid_plural "%1 songs"
4579+msgstr[0] ""
4580+msgstr[1] ""
4581+
4582+#: ../MusicPlaylists.qml:66 ../MusicPlaylists.qml:70 ../MusicStart.qml:118
4583+#: ../MusicStart.qml:200 ../common/SongsPage.qml:47
4584+#: ../common/SongsPage.qml:156 ../common/SongsPage.qml:217
4585+#: ../common/SongsPage.qml:274 ../common/SongsPage.qml:296
4586+#: ../common/SongsPage.qml:298 ../common/SongsPage.qml:316
4587 msgid "Playlist"
4588 msgstr ""
4589
4590-#: ../MusicSearch.qml:44 ../MusicSearch.qml:75 ../MusicToolbar.qml:519
4591-#: ../music-app.qml:93 ../music-app.qml:141 ../music-app.qml:147
4592+#: ../MusicSearch.qml:44 ../MusicSearch.qml:75 ../music-app.qml:88
4593+#: ../music-app.qml:134 ../music-app.qml:140
4594 msgid "Search"
4595 msgstr ""
4596
4597-#: ../MusicSettings.qml:30 ../music-app.qml:191
4598+#: ../MusicSettings.qml:30 ../music-app.qml:184
4599 msgid "Settings"
4600 msgstr ""
4601
4602-#: ../MusicSettings.qml:81
4603+#: ../MusicSettings.qml:70
4604 msgid "Equaliser"
4605 msgstr ""
4606
4607-#: ../MusicSettings.qml:82
4608+#: ../MusicSettings.qml:71
4609 msgid "Default"
4610 msgstr ""
4611
4612-#: ../MusicSettings.qml:83
4613+#: ../MusicSettings.qml:72
4614 msgid "Acoustic"
4615 msgstr ""
4616
4617-#: ../MusicSettings.qml:84
4618+#: ../MusicSettings.qml:73
4619 msgid "Classical"
4620 msgstr ""
4621
4622-#: ../MusicSettings.qml:85
4623+#: ../MusicSettings.qml:74
4624 msgid "Electronic"
4625 msgstr ""
4626
4627-#: ../MusicSettings.qml:86
4628+#: ../MusicSettings.qml:75
4629 msgid "Flat"
4630 msgstr ""
4631
4632-#: ../MusicSettings.qml:87
4633+#: ../MusicSettings.qml:76
4634 msgid "Hip Hop"
4635 msgstr ""
4636
4637-#: ../MusicSettings.qml:88
4638+#: ../MusicSettings.qml:77
4639 msgid "Jazz"
4640 msgstr ""
4641
4642-#: ../MusicSettings.qml:89
4643+#: ../MusicSettings.qml:78
4644 msgid "Metal"
4645 msgstr ""
4646
4647-#: ../MusicSettings.qml:90
4648+#: ../MusicSettings.qml:79
4649 msgid "Pop"
4650 msgstr ""
4651
4652-#: ../MusicSettings.qml:91
4653+#: ../MusicSettings.qml:80
4654 msgid "Rock"
4655 msgstr ""
4656
4657-#: ../MusicSettings.qml:92
4658+#: ../MusicSettings.qml:81
4659 msgid "Custom"
4660 msgstr ""
4661
4662-#: ../MusicSettings.qml:112
4663+#: ../MusicSettings.qml:101
4664 msgid ""
4665 "Snap to current song \n"
4666 "when opening toolbar"
4667 msgstr ""
4668
4669-#: ../MusicSettings.qml:132
4670+#: ../MusicSettings.qml:121
4671 msgid "Accounts"
4672 msgstr ""
4673
4674-#: ../MusicSettings.qml:146
4675+#: ../MusicSettings.qml:135
4676 msgid "Login to scrobble and import playlists"
4677 msgstr ""
4678
4679-#: ../MusicSettings.qml:169
4680+#: ../MusicSettings.qml:158
4681 msgid "Music Streaming"
4682 msgstr ""
4683
4684-#: ../MusicSettings.qml:179
4685+#: ../MusicSettings.qml:168
4686 msgid "Ubuntu One"
4687 msgstr ""
4688
4689-#: ../MusicSettings.qml:180
4690+#: ../MusicSettings.qml:169
4691 msgid "Sign in to stream your cloud music"
4692 msgstr ""
4693
4694-#: ../MusicSettings.qml:196
4695+#: ../MusicSettings.qml:185
4696 msgid "Stream only on Wi-Fi"
4697 msgstr ""
4698
4699-#: ../MusicSettings.qml:230
4700+#: ../MusicSettings.qml:219
4701 msgid "Clean everything!"
4702 msgstr ""
4703
4704-#: ../MusicStart.qml:35 ../music-app.qml:589 ../music-app.qml:1150
4705+#: ../MusicStart.qml:35 ../music-app.qml:576 ../music-app.qml:1141
4706 #: com.ubuntu.music_music.desktop.in.in.h:1
4707 msgid "Music"
4708 msgstr ""
4709@@ -241,13 +210,14 @@
4710 msgid "Genres"
4711 msgstr ""
4712
4713-#: ../MusicStart.qml:316 ../MusicStart.qml:318 ../common/SongsPage.qml:123
4714-#: ../common/SongsPage.qml:162 ../common/SongsPage.qml:240
4715+#: ../MusicStart.qml:316 ../MusicStart.qml:318 ../common/SongsPage.qml:157
4716+#: ../common/SongsPage.qml:184 ../common/SongsPage.qml:213
4717+#: ../common/SongsPage.qml:270 ../common/SongsPage.qml:312
4718 msgid "Genre"
4719 msgstr ""
4720
4721-#: ../MusicToolbar.qml:760
4722-msgid "Tap play to shuffle music"
4723+#: ../MusicToolbar.qml:150
4724+msgid "Tap to shuffle music"
4725 msgstr ""
4726
4727 #: ../MusicTracks.qml:35
4728@@ -258,17 +228,28 @@
4729 msgid "Select playlist"
4730 msgstr ""
4731
4732-#: ../common/AlbumsPage.qml:167 ../common/AlbumsPage.qml:360
4733-#: ../common/SongsPage.qml:153
4734+#: ../MusicaddtoPlaylist.qml:48
4735+msgid "New playlist"
4736+msgstr ""
4737+
4738+#: ../common/AlbumsPage.qml:110
4739+#, qt-format
4740+msgid "%1 album"
4741+msgid_plural "%1 albums"
4742+msgstr[0] ""
4743+msgstr[1] ""
4744+
4745+#: ../common/AlbumsPage.qml:165 ../common/AlbumsPage.qml:358
4746+#: ../common/SongsPage.qml:264
4747 msgid "Play all"
4748 msgstr ""
4749
4750-#: ../common/AlbumsPage.qml:211 ../common/AlbumsPage.qml:400
4751-#: ../common/SongsPage.qml:200 ../music-app.qml:888
4752+#: ../common/AlbumsPage.qml:209 ../common/AlbumsPage.qml:398
4753+#: ../music-app.qml:877
4754 msgid "Add to queue"
4755 msgstr ""
4756
4757-#: ../common/ListItemActions/AddToPlaylist.qml:25 ../music-app.qml:902
4758+#: ../common/ListItemActions/AddToPlaylist.qml:25 ../music-app.qml:891
4759 msgid "Add to playlist"
4760 msgstr ""
4761
4762@@ -276,17 +257,7 @@
4763 msgid "Add to Queue"
4764 msgstr ""
4765
4766-#. TRANSLATORS: this refers to deleting a playlist
4767-#: ../common/ListItemActions/DeletePlaylist.qml:26
4768-msgid "Delete"
4769-msgstr ""
4770-
4771-#. TRANSLATORS: this refers to editing a playlist
4772-#: ../common/ListItemActions/EditPlaylist.qml:26
4773-msgid "Edit"
4774-msgstr ""
4775-
4776-#: ../common/ListItemActions/Remove.qml:27
4777+#: ../common/ListItemActions/Remove.qml:27 ../common/SongsPage.qml:446
4778 msgid "Remove"
4779 msgstr ""
4780
4781@@ -294,6 +265,49 @@
4782 msgid "Loading..."
4783 msgstr ""
4784
4785+#: ../common/SongsPage.qml:206
4786+msgid "Shuffle"
4787+msgstr ""
4788+
4789+#: ../common/SongsPage.qml:243
4790+msgid "Queue all"
4791+msgstr ""
4792+
4793+#. TRANSLATORS: this is a title of a dialog with a prompt to rename a playlist
4794+#: ../common/SongsPage.qml:384
4795+msgid "Change name"
4796+msgstr ""
4797+
4798+#: ../common/SongsPage.qml:385
4799+msgid "Enter the new name of the playlist."
4800+msgstr ""
4801+
4802+#: ../common/SongsPage.qml:402
4803+msgid "Change"
4804+msgstr ""
4805+
4806+#: ../common/SongsPage.qml:418 ../music-app.qml:945
4807+msgid "Playlist already exists"
4808+msgstr ""
4809+
4810+#: ../common/SongsPage.qml:422 ../music-app.qml:950
4811+msgid "Please type in a name."
4812+msgstr ""
4813+
4814+#: ../common/SongsPage.qml:427 ../common/SongsPage.qml:460
4815+#: ../music-app.qml:486 ../music-app.qml:956
4816+msgid "Cancel"
4817+msgstr ""
4818+
4819+#. TRANSLATORS: this is a title of a dialog with a prompt to delete a playlist
4820+#: ../common/SongsPage.qml:440
4821+msgid "Are you sure?"
4822+msgstr ""
4823+
4824+#: ../common/SongsPage.qml:441
4825+msgid "This will delete your playlist."
4826+msgstr ""
4827+
4828 #: ../common/SwipeDelete.qml:52 ../common/SwipeDelete.qml:88
4829 msgid "Clear"
4830 msgstr ""
4831@@ -306,127 +320,127 @@
4832 msgid "Unknown Artist"
4833 msgstr ""
4834
4835-#: ../music-app.qml:142
4836+#: ../music-app.qml:135
4837 msgid "Search Track"
4838 msgstr ""
4839
4840-#: ../music-app.qml:154
4841+#: ../music-app.qml:147
4842 msgid "Next"
4843 msgstr ""
4844
4845-#: ../music-app.qml:155
4846+#: ../music-app.qml:148
4847 msgid "Next Track"
4848 msgstr ""
4849
4850-#: ../music-app.qml:161
4851+#: ../music-app.qml:154
4852 msgid "Pause"
4853 msgstr ""
4854
4855-#: ../music-app.qml:161
4856+#: ../music-app.qml:154
4857 msgid "Play"
4858 msgstr ""
4859
4860-#: ../music-app.qml:163
4861+#: ../music-app.qml:156
4862 msgid "Pause Playback"
4863 msgstr ""
4864
4865-#: ../music-app.qml:163
4866+#: ../music-app.qml:156
4867 msgid "Continue or start playback"
4868 msgstr ""
4869
4870-#: ../music-app.qml:168
4871+#: ../music-app.qml:161
4872 msgid "Back"
4873 msgstr ""
4874
4875-#: ../music-app.qml:169
4876+#: ../music-app.qml:162
4877 msgid "Go back to last page"
4878 msgstr ""
4879
4880-#: ../music-app.qml:177
4881+#: ../music-app.qml:170
4882 msgid "Previous"
4883 msgstr ""
4884
4885-#: ../music-app.qml:178
4886+#: ../music-app.qml:171
4887 msgid "Previous Track"
4888 msgstr ""
4889
4890-#: ../music-app.qml:183
4891+#: ../music-app.qml:176
4892 msgid "Stop"
4893 msgstr ""
4894
4895-#: ../music-app.qml:184
4896+#: ../music-app.qml:177
4897 msgid "Stop Playback"
4898 msgstr ""
4899
4900-#: ../music-app.qml:192
4901+#: ../music-app.qml:185
4902 msgid "Music Settings"
4903 msgstr ""
4904
4905 #. TRANSLATORS: This string represents that the target destination filepath does not start with ~/Music/Imported/
4906-#: ../music-app.qml:338
4907+#: ../music-app.qml:331
4908 msgid "Filepath must start with"
4909 msgstr ""
4910
4911 #. TRANSLATORS: This string represents that a blank filepath destination has been used
4912-#: ../music-app.qml:364
4913+#: ../music-app.qml:357
4914 msgid "Filepath must be a file"
4915 msgstr ""
4916
4917 #. TRANSLATORS: This string represents that there was failure moving the file to the target destination
4918-#: ../music-app.qml:370
4919+#: ../music-app.qml:363
4920 msgid "Failed to move file"
4921 msgstr ""
4922
4923-#: ../music-app.qml:447
4924+#: ../music-app.qml:440
4925 msgid "Waiting for file(s)..."
4926 msgstr ""
4927
4928-#: ../music-app.qml:466
4929+#: ../music-app.qml:459
4930 msgid "OK"
4931 msgstr ""
4932
4933-#: ../music-app.qml:479
4934+#: ../music-app.qml:472
4935 msgid "Imported file not found"
4936 msgstr ""
4937
4938-#: ../music-app.qml:483
4939+#: ../music-app.qml:476
4940 msgid "Wait"
4941 msgstr ""
4942
4943 #. TRANSLATORS: this refers to a number of songs greater than one. The actual number will be prepended to the string automatically (plural forms are not yet fully supported in usermetrics, the library that displays that string)
4944-#: ../music-app.qml:504
4945+#: ../music-app.qml:497
4946 msgid "songs played today"
4947 msgstr ""
4948
4949-#: ../music-app.qml:505
4950+#: ../music-app.qml:498
4951 msgid "No songs played today"
4952 msgstr ""
4953
4954-#: ../music-app.qml:613
4955+#: ../music-app.qml:599
4956 msgid "Debug: "
4957 msgstr ""
4958
4959-#: ../music-app.qml:925
4960+#: ../music-app.qml:914
4961 msgid "New Playlist"
4962 msgstr ""
4963
4964-#: ../music-app.qml:926
4965+#: ../music-app.qml:915
4966 msgid "Name your playlist."
4967 msgstr ""
4968
4969-#: ../music-app.qml:930
4970+#: ../music-app.qml:919
4971 msgid "Name"
4972 msgstr ""
4973
4974-#: ../music-app.qml:940
4975+#: ../music-app.qml:929
4976 msgid "Create"
4977 msgstr ""
4978
4979-#: ../music-app.qml:1176
4980+#: ../music-app.qml:1167
4981 msgid "No music found"
4982 msgstr ""
4983
4984-#: ../music-app.qml:1183
4985+#: ../music-app.qml:1174
4986 msgid "Please import music"
4987 msgstr ""
4988
4989
4990=== modified file 'po/pt_BR.po'
4991--- po/pt_BR.po 2014-10-01 06:25:24 +0000
4992+++ po/pt_BR.po 2014-10-16 23:15:23 +0000
4993@@ -1,24 +1,34 @@
4994 # Brazilian Portuguese translation for music-app
4995-# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
4996+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
4997 # This file is distributed under the same license as the music-app package.
4998-# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
4999+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
5000 #
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: