Merge lp:~vthompson/music-app/remix-do-not-show-artist-in-albumspage into lp:music-app/trusty

Proposed by Victor Thompson
Status: Superseded
Proposed branch: lp:~vthompson/music-app/remix-do-not-show-artist-in-albumspage
Merge into: lp:music-app/trusty
Diff against target: 6798 lines (+2635/-2615) (has conflicts)
32 files modified
MusicAlbums.qml (+21/-123)
MusicArtists.qml (+37/-87)
MusicNowPlaying.qml (+377/-219)
MusicPlaylists.qml (+34/-10)
MusicSettings.qml (+0/-11)
MusicStart.qml (+37/-474)
MusicToolbar.qml (+161/-953)
MusicTracks.qml (+14/-15)
MusicaddtoPlaylist.qml (+0/-1)
Player.qml (+5/-1)
Style.qml (+2/-2)
click/apparmor.json (+12/-2)
com.ubuntu.music_music.desktop.in.in (+3/-0)
common/AlbumsPage.qml (+117/-7)
common/BlurredBackground.qml (+12/-14)
common/BlurredHeader.qml (+69/-0)
common/Card.qml (+151/-0)
common/CardView.qml (+61/-0)
common/ColumnFlow.qml (+160/-0)
common/CoverGrid.qml (+78/-0)
common/CoverRow.qml (+2/-0)
common/ListItemActions/DeletePlaylist.qml (+0/-29)
common/ListItemActions/EditPlaylist.qml (+0/-35)
common/MusicPage.qml (+4/-0)
common/MusicRow.qml (+24/-5)
common/SongsPage.qml (+275/-162)
music-app.qml (+27/-36)
po/ca@valencia.po (+459/-0)
po/com.ubuntu.music.pot (+150/-148)
po/pt_BR.po (+179/-151)
tests/autopilot/music_app/__init__.py (+104/-84)
tests/autopilot/music_app/tests/test_music.py (+60/-46)
Text conflict in MusicPlaylists.qml
Text conflict in common/AlbumsPage.qml
Conflict adding file po/ca@valencia.po.  Moved existing file to po/ca@valencia.po.moved.
Text conflict in po/pt_BR.po
To merge this branch: bzr merge lp:~vthompson/music-app/remix-do-not-show-artist-in-albumspage
Reviewer Review Type Date Requested Status
Music App Developers Pending
Review via email: mp+239083@code.launchpad.net

This proposal has been superseded by a proposal from 2014-10-21.

Commit message

Do not show the artist in the grid of albums

Description of the change

Do not show the artist in the grid of albums

To post a comment you must log in.

Unmerged revisions

682. By Victor Thompson

Do not show the artist in the grid of albums

681. By Andrew Hayzen

* Add back confinement. Fixes: https://bugs.launchpad.net/bugs/1315386.

Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.

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

Launchpad automatic translations update.

679. By Andrew Hayzen

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

Approved by Ubuntu Phone Apps Jenkins Bot, Victor Thompson.

678. By Andrew Hayzen

* Set sourceSize of images.

Approved by Ubuntu Phone Apps Jenkins Bot, Victor Thompson.

677. By Victor Thompson

Force AlbumsPage's SongsModel to filter upon startup.

Approved by Ubuntu Phone Apps Jenkins Bot, Andrew Hayzen.

676. By Victor Thompson

Fix playlist deletion and renaming in recent table. Fixes: https://bugs.launchpad.net/bugs/1382170.

Approved by Andrew Hayzen, Ubuntu Phone Apps Jenkins Bot.

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

Launchpad automatic translations update.

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

Launchpad automatic translations update.

673. By Andrew Hayzen

* Add support for CardView in AlbumsPage.qml
* Add support for header property in CardView.qml
* Add BlurredHeader.qml
* Make AlbumsPage.qml and SongsPage.qml use BlurredHeader.qml.

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

Subscribers

People subscribed via source and target branches

to status/vote changes: