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
=== modified file 'MusicAlbums.qml'
--- MusicAlbums.qml 2014-09-20 15:41:33 +0000
+++ MusicAlbums.qml 2014-10-21 15:31:33 +0000
@@ -19,37 +19,17 @@
1919
20import QtQuick 2.320import QtQuick 2.3
21import Ubuntu.Components 1.121import Ubuntu.Components 1.1
22import Ubuntu.Components.Popups 1.0
23import Ubuntu.MediaScanner 0.122import Ubuntu.MediaScanner 0.1
24import Ubuntu.Thumbnailer 0.1
25import QtMultimedia 5.0
26import QtQuick.LocalStorage 2.0
27import QtGraphicalEffects 1.0
28import "settings.js" as Settings
29import "playlists.js" as Playlists
30import "common"23import "common"
3124
25
32MusicPage {26MusicPage {
33 id: mainpage27 id: albumsPage
34 objectName: "albumsPage"28 objectName: "albumsPage"
35 title: i18n.tr("Albums")29 title: i18n.tr("Albums")
3630
37 // TODO: This ListView is empty and causes the header to get painted with the desired background color because the31 CardView {
38 // page is now vertically flickable.32 id: albumCardView
39 ListView {
40 anchors.fill: parent
41 anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
42 }
43
44 GridView {
45 id: albumlist
46 anchors.fill: parent
47 anchors.leftMargin: units.gu(1)
48 anchors.top: parent.top
49 anchors.topMargin: mainView.header.height + units.gu(1)
50 anchors.bottomMargin: units.gu(1)
51 cellHeight: height/3
52 cellWidth: height/3
53 model: SortFilterModel {33 model: SortFilterModel {
54 id: albumsModelFilter34 id: albumsModelFilter
55 property alias rowCount: albumsModel.rowCount35 property alias rowCount: albumsModel.rowCount
@@ -60,106 +40,24 @@
60 sort.property: "title"40 sort.property: "title"
61 sort.order: Qt.AscendingOrder41 sort.order: Qt.AscendingOrder
62 }42 }
6343 delegate: Card {
64 delegate: albumDelegate44 id: albumCard
65 flow: GridView.TopToBottom45 coverSources: [{art: model.art}]
6646 objectName: "albumsPageGridItem" + index
67 Component {47 primaryText: model.title
68 id: albumDelegate48 secondaryText: model.artist
69 Item {49
70 property string artist: model.artist50 onClicked: {
71 property string album: model.title51 songsPage.album = model.title;
72 property var covers: [{art: model.art}]52 songsPage.covers = [{art: model.art}]
7353 songsPage.genre = undefined
74 id: albumItem54 songsPage.isAlbum = true
75 height: albumlist.cellHeight - units.gu(1)55 songsPage.line1 = model.artist
76 objectName: "albumsPageGridItem" + index56 songsPage.line2 = model.title
77 width: albumlist.cellHeight - units.gu(1)57 songsPage.title = i18n.tr("Album")
78 anchors.margins: units.gu(1)58
7959 mainPageStack.push(songsPage)
80 CoverRow {
81 id: albumShape
82 anchors {
83 top: parent.top
84 left: parent.left
85 verticalCenter: parent.verticalCenter
86 }
87 count: albumItem.covers.length
88 size: albumItem.width
89 covers: albumItem.covers
90 spacing: units.gu(2)
91 }
92 Item { // Background so can see text in current state
93 id: albumBg
94 anchors {
95 bottom: parent.bottom
96 left: parent.left
97 right: parent.right
98 }
99 height: units.gu(6)
100 clip: true
101 UbuntuShape{
102 anchors {
103 bottom: parent.bottom
104 left: parent.left
105 right: parent.right
106 }
107 height: albumShape.height
108 radius: "medium"
109 color: styleMusic.common.black
110 opacity: 0.6
111 }
112 }
113 Label {
114 id: albumArtist
115 objectName: "albums-albumartist"
116 anchors.bottom: parent.bottom
117 anchors.bottomMargin: units.gu(1)
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.artist
125 fontSize: "x-small"
126 }
127 Label {
128 id: albumLabel
129 anchors.bottom: parent.bottom
130 anchors.bottomMargin: units.gu(3)
131 anchors.left: parent.left
132 anchors.leftMargin: units.gu(1)
133 anchors.right: parent.right
134 anchors.rightMargin: units.gu(1)
135 color: styleMusic.common.white
136 elide: Text.ElideRight
137 text: model.title
138 fontSize: "small"
139 font.weight: Font.DemiBold
140 }
141
142
143 MouseArea {
144 anchors.fill: parent
145 onClicked: {
146 songsPage.album = model.title;
147 songsPage.covers = [{art: model.art}]
148 songsPage.genre = undefined
149 songsPage.isAlbum = true
150 songsPage.line1 = model.artist
151 songsPage.line2 = model.title
152 songsPage.title = i18n.tr("Album")
153
154 mainPageStack.push(songsPage)
155 }
156
157 // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
158 onPressedChanged: albumShape.pressed = pressed
159 }
160 }60 }
161 }61 }
162 }62 }
163}63}
164
165
16664
=== modified file 'MusicArtists.qml'
--- MusicArtists.qml 2014-09-20 15:41:33 +0000
+++ MusicArtists.qml 2014-10-21 15:31:33 +0000
@@ -36,98 +36,48 @@
36 objectName: "artistsPage"36 objectName: "artistsPage"
37 title: i18n.tr("Artists")37 title: i18n.tr("Artists")
3838
39 ListView {39 CardView {
40 id: artistlist40 id: artistCardView
41 anchors.fill: parent41 itemWidth: units.gu(12)
42 anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
43 model: ArtistsModel {42 model: ArtistsModel {
44 id: artistsModel43 id: artistsModel
45 albumArtists: true44 albumArtists: true
46 store: musicStore45 store: musicStore
47 }46 }
4847 delegate: Card {
49 delegate: artistDelegate48 id: artistCard
5049 coverSources: [{art: "image://artistart/artist=" + model.artist + "&album=" + artistCard.album}]
51 Component {50 objectName: "artistsPageGridItem" + index
52 id: artistDelegate51 primaryText: model.artist
5352 secondaryTextVisible: false
54 ListItem.Standard {53
55 id: track54 property string album: ""
56 objectName: "artistsPageListItem" + index55
57 height: styleMusic.common.itemHeight56 AlbumsModel {
5857 id: albumArtistModel
59 AlbumsModel {58 albumArtist: model.artist
60 id: albumArtistModel59 store: musicStore
61 albumArtist: model.artist60 }
62 store: musicStore61
63 }62 Repeater {
6463 id: albumArtistModelRepeater
65 Repeater {64 model: albumArtistModel
66 id: albumArtistModelRepeater65 delegate: Item {
67 model: albumArtistModel66 property string album: model.title
68 delegate: Item {67 }
69 property string art: model.art68
70 }69 onItemAdded: {
71 property var covers: []70 artistCard.album = item.album
72 signal finished()71 }
7372 }
74 onFinished: {73
75 musicRow.covers = covers74
76 }75 onClicked: {
77 onItemAdded: {76 albumsPage.artist = model.artist;
78 covers.push({art: item.art});77 albumsPage.covers = artistCard.coverSources
7978 albumsPage.title = i18n.tr("Artist")
80 if (index === count - 1) {79
81 finished();80 mainPageStack.push(albumsPage)
82 }
83 }
84 }
85
86 SongsModel {
87 id: songArtistModel
88 albumArtist: model.artist
89 store: musicStore
90 }
91
92 MusicRow {
93 id: musicRow
94 column: Column {
95 spacing: units.gu(1)
96 Label {
97 id: trackArtistAlbum
98 color: styleMusic.common.music
99 fontSize: "medium"
100 objectName: "artists-artist"
101 text: model.artist
102 }
103 Label {
104 id: trackArtistAlbums
105 color: styleMusic.common.subtitle
106 fontSize: "x-small"
107 text: i18n.tr("%1 album", "%1 albums", albumArtistModel.rowCount).arg(albumArtistModel.rowCount)
108 }
109 Label {
110 id: trackArtistAlbumTracks
111 color: styleMusic.common.subtitle
112 fontSize: "x-small"
113 text: i18n.tr("%1 song", "%1 songs", songArtistModel.rowCount).arg(songArtistModel.rowCount)
114 }
115 }
116 }
117
118 MouseArea {
119 anchors.fill: parent
120 onClicked: {
121 albumsPage.artist = model.artist
122 albumsPage.covers = musicRow.covers
123 albumsPage.title = i18n.tr("Artist")
124
125 mainPageStack.push(albumsPage)
126 }
127
128 // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
129 onPressedChanged: musicRow.pressed = pressed
130 }
131 }81 }
132 }82 }
133 }83 }
13484
=== modified file 'MusicNowPlaying.qml'
--- MusicNowPlaying.qml 2014-09-20 15:41:33 +0000
+++ MusicNowPlaying.qml 2014-10-21 15:31:33 +0000
@@ -17,7 +17,6 @@
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */18 */
1919
20
21import QtMultimedia 5.020import QtMultimedia 5.0
22import QtQuick 2.321import QtQuick 2.3
23import QtQuick.LocalStorage 2.022import QtQuick.LocalStorage 2.0
@@ -29,65 +28,363 @@
2928
30MusicPage {29MusicPage {
31 id: nowPlaying30 id: nowPlaying
31 flickable: isListView ? queuelist : null // Ensures that the header is shown in fullview
32 objectName: "nowPlayingPage"32 objectName: "nowPlayingPage"
33 title: i18n.tr("Now Playing")33 title: isListView ? i18n.tr("Queue") : i18n.tr("Now playing")
34 visible: false34 visible: false
3535
36 property int ensureVisibleIndex: 0 // ensure first index is visible at startup36 property bool isListView: false
37
38 onIsListViewChanged: {
39 if (isListView) {
40 positionAt(player.currentIndex);
41 }
42 }
43
44 head.backAction: Action {
45 iconName: "back";
46 objectName: "backButton"
47 onTriggered: {
48 mainPageStack.pop();
49
50 while (mainPageStack.depth > 1) { // jump back to the tab layer if via SongsPage
51 mainPageStack.pop();
52 }
53 }
54 }
55
56 head {
57 actions: [
58 Action {
59 objectName: "clearQueue"
60 iconName: "delete"
61 visible: isListView
62 onTriggered: {
63 head.backAction.trigger()
64 trackQueue.model.clear()
65 }
66 },
67 Action {
68 objectName: "toggleView"
69 iconName: "media-playlist"
70 onTriggered: {
71 isListView = !isListView
72 }
73 }
74 ]
75 }
76
77 function positionAt(index) {
78 queuelist.positionViewAtIndex(index, ListView.Center);
79 }
3780
38 Rectangle {81 Rectangle {
82 id: fullview
39 anchors.fill: parent83 anchors.fill: parent
40 color: styleMusic.nowPlaying.backgroundColor84 color: "transparent"
41 opacity: 0.75 // change later85 visible: !isListView
42 MouseArea { // Block events to lower layers86
43 anchors.fill: parent87 BlurredBackground {
44 }88 id: blurredBackground
45 }89 anchors.top: parent.top
4690 anchors.topMargin: mainView.header.height
47 Component.onCompleted: {91 height: units.gu(27)
48 onToolbarShownChanged.connect(jumpToCurrent)92 art: albumImage.firstSource
49 }93
5094 CoverGrid {
51 Connections {95 id: albumImage
52 target: player96 anchors {
53 onCurrentIndexChanged: {97 centerIn: parent
54 if (player.source === "") {98 }
55 return;99 covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaAlbum}]
56 }100 size: units.gu(18)
57101 }
58 queuelist.currentIndex = player.currentIndex;102 }
59103
60 customdebug("MusicQueue update currentIndex: " + player.source);104 /* Full toolbar */
61105 Item {
62 // Always jump to current track106 id: musicToolbarFullContainer
63 nowPlaying.jumpToCurrent(musicToolbar.opened, nowPlaying, musicToolbar.currentTab)107 anchors.top: blurredBackground.bottom
64108 anchors.topMargin: units.gu(4)
65 }109 width: blurredBackground.width
66 }110
67111 /* Column for labels in wideAspect */
68 function jumpToCurrent(shown, currentPage, currentTab)112 Column {
69 {113 id: nowPlayingWideAspectLabels
70 // If the toolbar is shown, the page is now playing and snaptrack is enabled114 spacing: units.gu(1)
71 if (shown && currentPage === nowPlaying && Settings.getSetting("snaptrack") === "1")115 anchors {
72 {116 left: parent.left
73 // Then position the view at the current index117 leftMargin: units.gu(2)
74 queuelist.positionViewAtIndex(queuelist.currentIndex, ListView.Beginning);118 right: parent.right
75 }119 rightMargin: units.gu(2)
76 }120 }
77121
78 function positionAt(index) {122 /* Title of track */
79 queuelist.positionViewAtIndex(index, ListView.Beginning);123 Label {
80 queuelist.contentY -= header.height;124 id: nowPlayingWideAspectTitle
125 anchors {
126 left: parent.left
127 leftMargin: units.gu(1)
128 right: parent.right
129 rightMargin: units.gu(1)
130 }
131 color: styleMusic.playerControls.labelColor
132 elide: Text.ElideRight
133 fontSize: "x-large"
134 objectName: "playercontroltitle"
135 text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle
136 }
137
138 /* Artist of track */
139 Label {
140 id: nowPlayingWideAspectArtist
141 anchors {
142 left: parent.left
143 leftMargin: units.gu(1)
144 right: parent.right
145 rightMargin: units.gu(1)
146 }
147 color: styleMusic.nowPlaying.labelSecondaryColor
148 elide: Text.ElideRight
149 fontSize: "small"
150 text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist
151 }
152 }
153
154 /* Progress bar component */
155 MouseArea {
156 id: musicToolbarFullProgressContainer
157 anchors.left: parent.left
158 anchors.leftMargin: units.gu(3)
159 anchors.right: parent.right
160 anchors.rightMargin: units.gu(3)
161 anchors.top: nowPlayingWideAspectLabels.bottom
162 anchors.topMargin: units.gu(3)
163 height: units.gu(3)
164 width: parent.width
165
166 /* Position label */
167 Label {
168 id: musicToolbarFullPositionLabel
169 anchors.top: progressSliderMusic.bottom
170 anchors.topMargin: units.gu(-2)
171 anchors.left: parent.left
172 color: styleMusic.nowPlaying.labelSecondaryColor
173 fontSize: "small"
174 height: parent.height
175 horizontalAlignment: Text.AlignHCenter
176 text: durationToString(player.position)
177 verticalAlignment: Text.AlignVCenter
178 width: units.gu(3)
179 }
180
181 Slider {
182 id: progressSliderMusic
183 anchors.left: parent.left
184 anchors.right: parent.right
185 objectName: "progressSliderShape"
186
187 function formatValue(v) {
188 if (seeking) { // update position label while dragging
189 musicToolbarFullPositionLabel.text = durationToString(v)
190 }
191
192 return durationToString(v)
193 }
194
195 property bool seeking: false
196 property bool seeked: false
197
198 onSeekingChanged: {
199 if (seeking === false) {
200 musicToolbarFullPositionLabel.text = durationToString(player.position)
201 }
202 }
203
204 Component.onCompleted: {
205 Theme.palette.selected.foreground = UbuntuColors.blue
206 }
207
208 onPressedChanged: {
209 seeking = pressed
210 if (!pressed) {
211 seeked = true
212 player.seek(value)
213 }
214 }
215
216 Connections {
217 target: player
218 onDurationChanged: {
219 musicToolbarFullDurationLabel.text = durationToString(player.duration)
220 progressSliderMusic.maximumValue = player.duration
221 }
222 onPositionChanged: {
223 // seeked is a workaround for bug 1310706 as the first position after a seek is sometimes invalid (0)
224 if (progressSliderMusic.seeking === false && !progressSliderMusic.seeked) {
225 progressSliderMusic.value = player.position
226 musicToolbarFullPositionLabel.text = durationToString(player.position)
227 musicToolbarFullDurationLabel.text = durationToString(player.duration)
228 }
229
230 progressSliderMusic.seeked = false;
231 }
232 onStopped: {
233 musicToolbarFullPositionLabel.text = durationToString(0);
234 musicToolbarFullDurationLabel.text = durationToString(0);
235 }
236 }
237 }
238
239 /* Duration label */
240 Label {
241 id: musicToolbarFullDurationLabel
242 anchors.top: progressSliderMusic.bottom
243 anchors.topMargin: units.gu(-2)
244 anchors.right: parent.right
245 color: styleMusic.nowPlaying.labelSecondaryColor
246 fontSize: "small"
247 height: parent.height
248 horizontalAlignment: Text.AlignHCenter
249 text: durationToString(player.duration)
250 verticalAlignment: Text.AlignVCenter
251 width: units.gu(3)
252 }
253 }
254
255 /* Repeat button */
256 MouseArea {
257 id: nowPlayingRepeatButton
258 anchors.right: nowPlayingPreviousButton.left
259 anchors.rightMargin: units.gu(1)
260 anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
261 height: units.gu(6)
262 opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
263 width: height
264 onClicked: player.repeat = !player.repeat
265
266 Icon {
267 id: repeatIcon
268 height: units.gu(3)
269 width: height
270 anchors.verticalCenter: parent.verticalCenter
271 anchors.horizontalCenter: parent.horizontalCenter
272 color: "white"
273 name: "media-playlist-repeat"
274 objectName: "repeatShape"
275 opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
276 }
277 }
278
279 /* Previous button */
280 MouseArea {
281 id: nowPlayingPreviousButton
282 anchors.right: nowPlayingPlayButton.left
283 anchors.rightMargin: units.gu(1)
284 anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
285 height: units.gu(6)
286 opacity: trackQueue.model.count === 0 ? .4 : 1
287 width: height
288 onClicked: player.previousSong()
289
290 Icon {
291 id: nowPlayingPreviousIndicator
292 height: units.gu(3)
293 width: height
294 anchors.verticalCenter: parent.verticalCenter
295 anchors.horizontalCenter: parent.horizontalCenter
296 color: "white"
297 name: "media-skip-backward"
298 objectName: "previousShape"
299 opacity: 1
300 }
301 }
302
303 /* Play/Pause button */
304 MouseArea {
305 id: nowPlayingPlayButton
306 anchors.horizontalCenter: parent.horizontalCenter
307 anchors.top: musicToolbarFullProgressContainer.bottom
308 anchors.topMargin: units.gu(2)
309 height: units.gu(12)
310 width: height
311 onClicked: player.toggle()
312
313 Icon {
314 id: nowPlayingPlayIndicator
315 height: units.gu(6)
316 width: height
317 anchors.verticalCenter: parent.verticalCenter
318 anchors.horizontalCenter: parent.horizontalCenter
319 opacity: emptyPage.noMusic ? .4 : 1
320 color: "white"
321 name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start"
322 objectName: "playShape"
323 }
324 }
325
326 /* Next button */
327 MouseArea {
328 id: nowPlayingNextButton
329 anchors.left: nowPlayingPlayButton.right
330 anchors.leftMargin: units.gu(1)
331 anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
332 height: units.gu(6)
333 opacity: trackQueue.model.count === 0 ? .4 : 1
334 width: height
335 onClicked: player.nextSong()
336
337 Icon {
338 id: nowPlayingNextIndicator
339 height: units.gu(3)
340 width: height
341 anchors.verticalCenter: parent.verticalCenter
342 anchors.horizontalCenter: parent.horizontalCenter
343 color: "white"
344 name: "media-skip-forward"
345 objectName: "forwardShape"
346 opacity: 1
347 }
348 }
349
350 /* Shuffle button */
351 MouseArea {
352 id: nowPlayingShuffleButton
353 anchors.left: nowPlayingNextButton.right
354 anchors.leftMargin: units.gu(1)
355 anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
356 height: units.gu(6)
357 opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
358 width: height
359 onClicked: player.shuffle = !player.shuffle
360
361 Icon {
362 id: shuffleIcon
363 height: units.gu(3)
364 width: height
365 anchors.verticalCenter: parent.verticalCenter
366 anchors.horizontalCenter: parent.horizontalCenter
367 color: "white"
368 name: "media-playlist-shuffle"
369 objectName: "shuffleShape"
370 opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
371 }
372 }
373 }
81 }374 }
82375
83 ListView {376 ListView {
84 id: queuelist377 id: queuelist
85 objectName: "nowPlayingQueueList"378 anchors {
86 anchors.fill: parent379 fill: parent
87 anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight380 topMargin: units.gu(2)
381 }
88 delegate: queueDelegate382 delegate: queueDelegate
383 footer: Item {
384 height: mainView.height - (styleMusic.common.expandHeight + queuelist.currentHeight) + units.gu(8)
385 }
89 model: trackQueue.model386 model: trackQueue.model
90 highlightFollowsCurrentItem: false387 objectName: "nowPlayingQueueList"
91 state: "normal"388 state: "normal"
92 states: [389 states: [
93 State {390 State {
@@ -105,33 +402,29 @@
105 }402 }
106 }403 }
107 ]404 ]
108 footer: Item {405 visible: isListView
109 height: mainView.height - (styleMusic.common.expandHeight + queuelist.currentHeight) + units.gu(8)
110 }
111406
112 property int normalHeight: units.gu(12)407 property int normalHeight: units.gu(6)
113 property int currentHeight: units.gu(40)
114 property int transitionDuration: 250 // transition length of animations408 property int transitionDuration: 250 // transition length of animations
115409
116 onCountChanged: {410 onCountChanged: {
117 customdebug("Queue: Now has: " + queuelist.count + " tracks")411 customdebug("Queue: Now has: " + queuelist.count + " tracks")
118 }412 }
119413
120 onMovementStarted: {
121 musicToolbar.hideToolbar();
122 }
123
124 Component {414 Component {
125 id: queueDelegate415 id: queueDelegate
126 ListItemWithActions {416 ListItemWithActions {
127 id: queueListItem417 id: queueListItem
128 color: "transparent"418 color: player.currentIndex === index ? "#2c2c34" : "transparent"
129 height: queuelist.normalHeight419 height: queuelist.normalHeight
130 objectName: "nowPlayingListItem" + index420 objectName: "nowPlayingListItem" + index
131 state: queuelist.currentIndex == index && !reordering ? "current" : ""421 showDivider: false
422 state: ""
132423
133 leftSideAction: Remove {424 leftSideAction: Remove {
134 onTriggered: {425 onTriggered: {
426 var removedIndex = index
427
135 if (queuelist.count === 1) {428 if (queuelist.count === 1) {
136 player.stop()429 player.stop()
137 musicToolbar.goBack()430 musicToolbar.goBack()
@@ -139,12 +432,12 @@
139 player.nextSong(player.isPlaying);432 player.nextSong(player.isPlaying);
140 }433 }
141434
142 if (index < player.currentIndex) {435 queuelist.model.remove(index);
436
437 if (removedIndex < player.currentIndex) {
143 // update index as the old has been removed438 // update index as the old has been removed
144 player.currentIndex -= 1;439 player.currentIndex -= 1;
145 }440 }
146
147 queuelist.model.remove(index);
148 }441 }
149 }442 }
150 reorderable: true443 reorderable: true
@@ -177,14 +470,10 @@
177 }470 }
178 }471 }
179472
180 // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
181 onPressedChanged: trackImage.pressed = pressed
182
183 Rectangle {473 Rectangle {
184 id: trackContainer;474 id: trackContainer;
185 anchors {475 anchors {
186 fill: parent476 fill: parent
187 margins: units.gu(1)
188 }477 }
189 color: "transparent"478 color: "transparent"
190479
@@ -204,159 +493,28 @@
204 to: units.gu(0.5)493 to: units.gu(0.5)
205 }494 }
206495
207 CoverRow {496 MusicRow {
208 id: trackImage497 id: musicRow
209498 covers: [{art: model.art, album: model.album, author: model.author}]
210 anchors {499 showCovers: false
211 top: parent.top500 coverSize: units.gu(6)
212 left: parent.left501 column: Column {
213 leftMargin: units.gu(1.5)502 Label {
214 }503 id: trackTitle
215 count: 1504 color: player.currentIndex === index ? UbuntuColors.blue
216 size: (queueListItem.state === "current"505 : styleMusic.common.music
217 ? (mainView.wideAspect506 fontSize: "small"
218 ? queuelist.currentHeight507 objectName: "titleLabel"
219 : mainView.width - (trackImage.anchors.leftMargin * 2))508 text: model.title
220 : queuelist.normalHeight) - units.gu(2)509 }
221 covers: [{art: model.art}]510
222511 Label {
223 spacing: units.gu(2)512 id: trackArtist
224513 color: styleMusic.common.subtitle
225 Item { // Background so can see text in current state514 fontSize: "x-small"
226 id: albumBg515 objectName: "artistLabel"
227 visible: false516 text: model.author
228 anchors {517 }
229 bottom: parent.bottom
230 left: parent.left
231 right: parent.right
232 }
233 height: units.gu(9)
234 clip: true
235 UbuntuShape{
236 anchors {
237 bottom: parent.bottom
238 left: parent.left
239 right: parent.right
240 }
241 height: trackImage.height
242 radius: "medium"
243 color: styleMusic.common.black
244 opacity: 0.6
245 }
246 }
247
248 function calcAnchors() {
249 if (trackImage.height > queuelist.normalHeight && mainView.wideAspect) {
250 trackImage.anchors.left = undefined
251 trackImage.anchors.horizontalCenter = trackImage.parent.horizontalCenter
252 } else {
253 trackImage.anchors.left = trackImage.parent.left
254 trackImage.anchors.horizontalCenter = undefined
255 }
256
257 trackImage.width = trackImage.height; // force width to match height
258 }
259
260 Connections {
261 target: mainView
262 onWideAspectChanged: trackImage.calcAnchors()
263 }
264
265 onHeightChanged: {
266 calcAnchors()
267 }
268 Behavior on height {
269 NumberAnimation {
270 target: trackImage;
271 property: "height";
272 duration: queuelist.transitionDuration;
273 }
274 }
275 }
276 Label {
277 id: nowPlayingArtist
278 objectName: "artistLabel"
279 color: styleMusic.nowPlaying.labelSecondaryColor
280 elide: Text.ElideRight
281 height: units.gu(1)
282 text: model.author
283 fontSize: 'small'
284 width: parent.width - trackImage.width - units.gu(3.5)
285 x: trackImage.x + trackImage.width + units.gu(1)
286 y: trackImage.y + units.gu(1)
287 }
288 Label {
289 id: nowPlayingTitle
290 objectName: "titleLabel"
291 color: styleMusic.common.white
292 elide: Text.ElideRight
293 height: units.gu(1)
294 text: model.title
295 fontSize: 'medium'
296 width: parent.width - trackImage.width - units.gu(3.5)
297 x: trackImage.x + trackImage.width + units.gu(1)
298 y: nowPlayingArtist.y + nowPlayingArtist.height + units.gu(1.25)
299 }
300 Label {
301 id: nowPlayingAlbum
302 objectName: "albumLabel"
303 color: styleMusic.nowPlaying.labelSecondaryColor
304 elide: Text.ElideRight
305 height: units.gu(1)
306 text: model.album
307 fontSize: 'x-small'
308 width: parent.width - trackImage.width - units.gu(3.5)
309 x: trackImage.x + trackImage.width + units.gu(1)
310 y: nowPlayingTitle.y + nowPlayingTitle.height + units.gu(1.25)
311 }
312 }
313
314 states: State {
315 name: "current"
316 PropertyChanges {
317 target: queueListItem
318 height: trackImage.size + (trackContainer.anchors.margins * 2)
319 }
320 PropertyChanges {
321 target: nowPlayingArtist
322 width: trackImage.width - units.gu(4)
323 x: trackImage.x + units.gu(2)
324 y: trackImage.y + trackImage.height - albumBg.height + units.gu(1)
325 color: styleMusic.common.white
326 }
327 PropertyChanges {
328 target: nowPlayingTitle
329 width: trackImage.width - units.gu(4)
330 x: trackImage.x + units.gu(2)
331 y: nowPlayingArtist.y + nowPlayingArtist.height + units.gu(1.25)
332 color: styleMusic.common.white
333 font.weight: Font.DemiBold
334 }
335 PropertyChanges {
336 target: nowPlayingAlbum
337 width: trackImage.width - units.gu(4)
338 x: trackImage.x + units.gu(2)
339 y: nowPlayingTitle.y + nowPlayingTitle.height + units.gu(1.25)
340 color: styleMusic.common.white
341 }
342 PropertyChanges {
343 target: albumBg
344 visible: true
345 }
346 }
347 transitions: Transition {
348 from: ",current"
349 to: "current,"
350 NumberAnimation {
351 duration: queuelist.transitionDuration
352 properties: "height,opacity,width,x,y"
353 }
354
355 onRunningChanged: {
356 if (running === false && ensureVisibleIndex != -1)
357 {
358 queuelist.positionViewAtIndex(ensureVisibleIndex, ListView.Beginning);
359 ensureVisibleIndex = -1;
360 }518 }
361 }519 }
362 }520 }
363521
=== modified file 'MusicPlaylists.qml'
--- MusicPlaylists.qml 2014-10-19 06:28:03 +0000
+++ MusicPlaylists.qml 2014-10-21 15:31:33 +0000
@@ -23,36 +23,37 @@
23import Ubuntu.Components.Popups 1.023import Ubuntu.Components.Popups 1.0
24import QtMultimedia 5.024import QtMultimedia 5.0
25import QtQuick.LocalStorage 2.025import QtQuick.LocalStorage 2.0
26<<<<<<< TREE
26import "meta-database.js" as Library27import "meta-database.js" as Library
27import "settings.js" as Settings28import "settings.js" as Settings
28import "scrobble.js" as Scrobble29import "scrobble.js" as Scrobble
30=======
31>>>>>>> MERGE-SOURCE
29import "playlists.js" as Playlists32import "playlists.js" as Playlists
30import "common"33import "common"
31import "common/ListItemActions"
3234
33// page for the playlists35// page for the playlists
34MusicPage {36MusicPage {
35 id: listspage37 id: playlistsPage
36 objectName: "playlistsPage"38 objectName: "playlistsPage"
37 // TRANSLATORS: this is the name of the playlists page shown in the tab header.39 // TRANSLATORS: this is the name of the playlists page shown in the tab header.
38 // Remember to keep the translation short to fit the screen width40 // Remember to keep the translation short to fit the screen width
39 title: i18n.tr("Playlists")41 title: i18n.tr("Playlists")
4042
41 property string playlistTracks: ""43 property string playlistTracks: ""
42 property string oldPlaylistName: ""
43 property string inPlaylist: ""44 property string inPlaylist: ""
4445
45 tools: ToolbarItems {46 head {
46 ToolbarButton {47 actions: [
47 action: Action {48 Action {
48 objectName: "newplaylistButton"49 objectName: "newplaylistButton"
49 text: i18n.tr("New playlist")
50 iconName: "add"50 iconName: "add"
51 onTriggered: {51 onTriggered: {
52 customdebug("New playlist.")52 customdebug("New playlist.")
53 PopupUtils.open(newPlaylistDialog, mainView)53 PopupUtils.open(newPlaylistDialog, mainView)
54 }54 }
55 }55 }
56<<<<<<< TREE
56 }57 }
57 }58 }
5859
@@ -120,11 +121,15 @@
120 }121 }
121122
122 ListView {123 ListView {
124=======
125 ]
126 }
127
128 CardView {
129>>>>>>> MERGE-SOURCE
123 id: playlistslist130 id: playlistslist
124 objectName: "playlistsListView"
125 anchors.fill: parent
126 anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
127 model: playlistModel.model131 model: playlistModel.model
132<<<<<<< TREE
128 delegate: playlistDelegate133 delegate: playlistDelegate
129 onCountChanged: {134 onCountChanged: {
130 customdebug("onCountChanged: " + playlistslist.count)135 customdebug("onCountChanged: " + playlistslist.count)
@@ -199,6 +204,25 @@
199 }204 }
200 }205 }
201 }206 }
207=======
208 objectName: "playlistsCardView"
209 delegate: Card {
210 id: playlistCard
211 coverSources: Playlists.getPlaylistCovers(name)
212 primaryText: name
213 secondaryText: i18n.tr("%1 song", "%1 songs", count).arg(count)
214
215 onClicked: {
216 albumTracksModel.filterPlaylistTracks(name)
217 songsPage.isAlbum = false
218 songsPage.line1 = i18n.tr("Playlist")
219 songsPage.line2 = model.name
220 songsPage.covers = coverSources
221 songsPage.genre = undefined
222 songsPage.title = i18n.tr("Playlist")
223
224 mainPageStack.push(songsPage)
225>>>>>>> MERGE-SOURCE
202 }226 }
203 }227 }
204 }228 }
205229
=== modified file 'MusicSettings.qml'
--- MusicSettings.qml 2014-09-20 10:50:45 +0000
+++ MusicSettings.qml 2014-10-21 15:31:33 +0000
@@ -30,17 +30,6 @@
30 title: i18n.tr("Settings")30 title: i18n.tr("Settings")
31 contentsHeight: parent.height;31 contentsHeight: parent.height;
3232
33 onVisibleChanged: {
34 if (visible === true)
35 {
36 musicToolbar.disableToolbar()
37 }
38 else
39 {
40 musicToolbar.enableToolbar()
41 }
42 }
43
44 onCancelClicked: PopupUtils.close(musicSettings)33 onCancelClicked: PopupUtils.close(musicSettings)
45 onConfirmClicked: {34 onConfirmClicked: {
46 PopupUtils.close(musicSettings)35 PopupUtils.close(musicSettings)
4736
=== modified file 'MusicStart.qml'
--- MusicStart.qml 2014-09-20 15:41:33 +0000
+++ MusicStart.qml 2014-10-21 15:31:33 +0000
@@ -32,482 +32,45 @@
3232
33MusicPage {33MusicPage {
34 id: mainpage34 id: mainpage
35 title: i18n.tr("Music")35 title: i18n.tr("Recent")
3636
37 /* Dev button for search.37 head {
38 Button {38 actions: [
39 id: searchButton39 Action {
40 text: i18n.tr("Search")40 iconName: "delete"
41 anchors.top: parent.top41 onTriggered: {
42 anchors.topMargin: units.gu(2)42 Library.clearRecentHistory()
43 anchors.bottom: recentlyPlayed.top43 recentModel.filterRecent()
44 anchors.bottomMargin: units.gu(1)44 }
45 height: units.gu(4)45 }
46 onClicked: {46 ]
47 PopupUtils.open(Qt.resolvedUrl("MusicSearch.qml"), mainView,
48 {
49 title: i18n.tr("Search")
50 } )
51 }
52 }47 }
53 */48
54 Flickable{49 CardView {
55 id: musicFlickable50 id: recentCardView
56 anchors.fill: parent51 model: recentModel.model
5752 delegate: Card {
58 width: mainpage.width53 id: albumCard
59 height: mainpage.height54 coverSources: model.type === "playlist" ? Playlists.getPlaylistCovers(title) : (model.art !== undefined ? [{art: model.art}] : [{author: model.title2, album: model.title}])
6055 objectName: "albumsPageGridItem" + index
61 contentHeight: mainView.hasRecent ? recentlyPlayed.height + recentlist.height + genres.height + genrelist.height + albums.height + albumlist.height + units.gu(4)56 primaryText: model.title
62 : genres.height + genrelist.height + albums.height + albumlist.height + units.gu(3)57 secondaryText: model.title2 !== "Playlist" ? model.title2 : i18n.tr("Playlist")
63 contentWidth: width58
6459 onClicked: {
65 focus: true60 if (type === "playlist") {
6661 albumTracksModel.filterPlaylistTracks(model.key)
67 ListItem.Standard {62 } else {
68 id: recentlyPlayed63 songsPage.album = title;
69 Label {64 }
70 anchors {65 songsPage.genre = undefined;
71 verticalCenter: parent.verticalCenter66
72 left: parent.left67 songsPage.line1 = secondaryText
73 leftMargin: units.gu(2)68 songsPage.line2 = primaryText
74 }69 songsPage.covers = coverSources
75 text: i18n.tr("Recent")70 songsPage.isAlbum = (type === "album")
76 color: styleMusic.common.music71 songsPage.title = songsPage.isAlbum ? i18n.tr("Album") : i18n.tr("Playlist")
77 }72
78 visible: mainView.hasRecent73 mainPageStack.push(songsPage)
79 }
80
81 ListView {
82 id: recentlist
83 anchors.top: recentlyPlayed.bottom
84 anchors.topMargin: units.gu(1)
85 width: parent.width
86 spacing: units.gu(1)
87 height: units.gu(18)
88 // TODO: Update when view counts are collected
89 model: recentModel.model
90 delegate: recentDelegate
91 header: Item {
92 id: recentSpacer
93 width: units.gu(1)
94 }
95 footer: Item {
96 id: clearRecent
97 width: recentlist.height - units.gu(2)
98 height: width
99 visible: mainView.hasRecent && !loading.visible
100 Button {
101 id: clearRecentButton
102 anchors.centerIn: parent
103 text: i18n.tr("Clear History")
104 onClicked: {
105 Library.clearRecentHistory()
106 mainView.hasRecent = false
107 recentModel.filterRecent()
108 }
109 }
110 }
111 orientation: ListView.Horizontal
112 visible: mainView.hasRecent
113
114 Component {
115 id: recentDelegate
116 Item {
117 property string title: model.title
118 property string title2: model.title2 !== "Playlist" ? model.title2 : i18n.tr("Playlist")
119 property var covers: type === "playlist" ? Playlists.getPlaylistCovers(title) : (model.art !== undefined ? [{art: model.art}] : [{author: model.title2, album: model.title}])
120 property string type: model.type
121 property string time: model.time
122 property string key: model.key
123 id: recentItem
124 height: recentlist.height - units.gu(1)
125 width: height
126 CoverRow {
127 id: recentShape
128 anchors {
129 top: parent.top
130 left: parent.left
131 verticalCenter: parent.verticalCenter
132 }
133 count: recentItem.covers.length
134 size: recentItem.width
135 covers: recentItem.covers
136 spacing: units.gu(2)
137 }
138 Item { // Background so can see text in current state
139 id: albumBg
140 anchors {
141 bottom: parent.bottom
142 left: parent.left
143 right: parent.right
144 }
145 height: units.gu(6)
146 clip: true
147 UbuntuShape{
148 anchors {
149 bottom: parent.bottom
150 left: parent.left
151 right: parent.right
152 }
153 height: recentShape.height
154 radius: "medium"
155 color: styleMusic.common.black
156 opacity: 0.6
157 }
158 }
159 Label {
160 id: albumArtist
161 anchors.bottom: parent.bottom
162 anchors.bottomMargin: units.gu(3)
163 anchors.left: parent.left
164 anchors.leftMargin: units.gu(1)
165 anchors.right: parent.right
166 anchors.rightMargin: units.gu(1)
167 color: styleMusic.common.white
168 elide: Text.ElideRight
169 text: title
170 fontSize: "small"
171 font.weight: Font.DemiBold
172 }
173 Label {
174 id: albumLabel
175 anchors.left: parent.left
176 anchors.leftMargin: units.gu(1)
177 anchors.bottom: parent.bottom
178 anchors.bottomMargin: units.gu(1)
179 anchors.right: parent.right
180 anchors.rightMargin: units.gu(1)
181 color: styleMusic.common.white
182 elide: Text.ElideRight
183 text: title2
184 fontSize: "x-small"
185 }
186 MouseArea {
187 anchors.fill: parent
188 onClicked: {
189 if (type === "playlist") {
190 albumTracksModel.filterPlaylistTracks(key)
191 } else {
192 songsPage.album = title;
193 }
194 songsPage.genre = undefined;
195
196 songsPage.line1 = title2
197 songsPage.line2 = title
198 songsPage.covers = recentItem.covers
199 songsPage.isAlbum = (type === "album")
200 songsPage.title = songsPage.isAlbum ? i18n.tr("Album") : i18n.tr("Playlist")
201
202 mainPageStack.push(songsPage)
203 }
204
205 // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
206 onPressedChanged: recentShape.pressed = pressed
207 }
208 }
209 }
210 }
211
212 ListItem.ThinDivider {
213 id: genreDivider
214 anchors.top: mainView.hasRecent ? recentlist.bottom : parent.top
215 visible: genrelist.count > 1
216 }
217 ListItem.Standard {
218 id: genres
219 anchors.top: genreDivider.bottom
220 visible: genrelist.count > 1
221 Label {
222 anchors {
223 verticalCenter: parent.verticalCenter
224 left: parent.left
225 leftMargin: units.gu(2)
226 }
227 text: i18n.tr("Genres")
228 color: styleMusic.common.music
229 }
230 }
231 // TODO: add music genres. frequency of play? most tracks?
232 ListView {
233 id: genrelist
234 width: parent.width
235 anchors.top: genres.bottom
236 anchors.topMargin: units.gu(1)
237 spacing: units.gu(1)
238 height: units.gu(18)
239 visible: genrelist.count > 1
240 model: SortFilterModel {
241 id: genresModelFilter
242 model: GenresModel {
243 id: genresModel
244 store: musicStore
245 }
246 filter.property: "genre"
247 filter.pattern: /\S+/
248 }
249
250 delegate: genreDelegate
251 header: Item {
252 id: genreSpacer
253 width: units.gu(1)
254 }
255 orientation: ListView.Horizontal
256
257 Component {
258 id: genreDelegate
259 Item {
260 id: genreItem
261 objectName: "genreItemObject"
262 height: genrelist.height - units.gu(1)
263 width: height
264
265 Repeater {
266 id: albumGenreModelRepeater
267 model: AlbumsModel {
268 genre: model.genre
269 store: musicStore
270 }
271
272 delegate: Item {
273 property string art: model.art
274 }
275 property var covers: []
276 signal finished()
277
278 onFinished: {
279 genreShape.count = count
280 genreShape.covers = covers
281 }
282 onItemAdded: {
283 covers.push({art: item.art});
284
285 if (index === count - 1) {
286 finished();
287 }
288 }
289 }
290
291 SongsModel {
292 id: songGenreModel
293 genre: model.genre
294 store: musicStore
295 }
296
297 CoverRow {
298 id: genreShape
299 anchors {
300 top: parent.top
301 left: parent.left
302 verticalCenter: parent.verticalCenter
303 }
304 count: 0
305 size: genreItem.width
306 covers: []
307 spacing: units.gu(2)
308 }
309 MouseArea {
310 anchors.fill: parent
311 onClicked: {
312 songsPage.album = undefined
313 songsPage.covers = genreShape.covers
314 songsPage.genre = model.genre
315 songsPage.isAlbum = true
316 songsPage.line1 = i18n.tr("Genre")
317 songsPage.line2 = model.genre
318 songsPage.title = i18n.tr("Genre")
319
320 mainPageStack.push(songsPage)
321 }
322
323 // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
324 onPressedChanged: genreShape.pressed = pressed
325 }
326 Item { // Background so can see text in current state
327 id: genreBg
328 anchors {
329 bottom: parent.bottom
330 left: parent.left
331 right: parent.right
332 }
333 height: units.gu(5.5)
334 clip: true
335 UbuntuShape{
336 anchors {
337 bottom: parent.bottom
338 left: parent.left
339 right: parent.right
340 }
341 height: genreShape.height
342 radius: "medium"
343 color: styleMusic.common.black
344 opacity: 0.6
345 }
346 }
347 Label {
348 id: genreLabel
349 anchors.bottom: parent.bottom
350 anchors.bottomMargin: units.gu(1)
351 anchors.left: parent.left
352 anchors.leftMargin: units.gu(1)
353 anchors.right: parent.right
354 anchors.rightMargin: units.gu(1)
355 color: styleMusic.common.white
356 elide: Text.ElideRight
357 text: model.genre
358 fontSize: "small"
359 font.weight: Font.DemiBold
360 }
361 Label {
362 id: genreTotal
363 anchors.bottom: parent.bottom
364 anchors.bottomMargin: units.gu(3)
365 anchors.left: parent.left
366 anchors.leftMargin: units.gu(1)
367 anchors.right: parent.right
368 anchors.rightMargin: units.gu(1)
369 color: styleMusic.common.white
370 elide: Text.ElideRight
371 text: i18n.tr("%1 song", "%1 songs", songGenreModel.rowCount).arg(songGenreModel.rowCount)
372 fontSize: "x-small"
373 }
374 }
375 }
376 }
377
378 ListItem.ThinDivider {
379 id: albumsDivider
380 anchors.top: genrelist.visible
381 ? genrelist.bottom
382 : (mainView.hasRecent ? recentlist.bottom : parent.top)
383 }
384 ListItem.Standard {
385 id: albums
386 Label {
387 anchors {
388 verticalCenter: parent.verticalCenter
389 left: parent.left
390 leftMargin: units.gu(2)
391 }
392 text: i18n.tr("Albums")
393 color: styleMusic.common.music
394 }
395 anchors.top: albumsDivider.bottom
396 }
397
398 ListView {
399 id: albumlist
400 width: parent.width
401 anchors.top: albums.bottom
402 anchors.topMargin: units.gu(1)
403 spacing: units.gu(1)
404 height: units.gu(18)
405 model: SortFilterModel {
406 id: albumsModelFilter
407 property alias rowCount: albumsModel.rowCount
408 model: AlbumsModel {
409 id: albumsModel
410 store: musicStore
411 }
412 sort.property: "title"
413 sort.order: Qt.AscendingOrder
414 }
415 delegate: albumDelegate
416 header: Item {
417 id: albumSpacer
418 width: units.gu(1)
419 }
420 orientation: ListView.Horizontal
421
422 Component {
423 id: albumDelegate
424 Item {
425 property string artist: model.artist
426 property string album: model.title
427 property var covers: [{art: model.art}]
428
429 id: albumItem
430 objectName: "albumItemObject"
431 height: albumlist.height - units.gu(1)
432 width: height
433 CoverRow {
434 id: albumShape
435 anchors {
436 top: parent.top
437 left: parent.left
438 verticalCenter: parent.verticalCenter
439 }
440 count: albumItem.covers.length
441 size: albumItem.width
442 covers: albumItem.covers
443 spacing: units.gu(2)
444 }
445 MouseArea {
446 anchors.fill: parent
447 onClicked: {
448 songsPage.album = album
449 songsPage.covers = covers
450 songsPage.genre = undefined
451 songsPage.isAlbum = true
452 songsPage.line1 = artist
453 songsPage.line2 = album
454 songsPage.title = i18n.tr("Album")
455
456 mainPageStack.push(songsPage)
457 }
458
459 // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well.
460 onPressedChanged: albumShape.pressed = pressed
461 }
462 Item { // Background so can see text in current state
463 id: albumBg
464 anchors {
465 bottom: parent.bottom
466 left: parent.left
467 right: parent.right
468 }
469 height: units.gu(6)
470 clip: true
471 UbuntuShape{
472 anchors {
473 bottom: parent.bottom
474 left: parent.left
475 right: parent.right
476 }
477 height: albumShape.height
478 radius: "medium"
479 color: styleMusic.common.black
480 opacity: 0.6
481 }
482 }
483 Label {
484 id: albumLabel
485 anchors.bottom: parent.bottom
486 anchors.bottomMargin: units.gu(1)
487 anchors.left: parent.left
488 anchors.leftMargin: units.gu(1)
489 anchors.right: parent.right
490 anchors.rightMargin: units.gu(1)
491 color: styleMusic.common.white
492 elide: Text.ElideRight
493 text: artist
494 fontSize: "x-small"
495 }
496 Label {
497 id: albumLabel2
498 anchors.bottom: parent.bottom
499 anchors.bottomMargin: units.gu(3)
500 anchors.left: parent.left
501 anchors.leftMargin: units.gu(1)
502 anchors.right: parent.right
503 anchors.rightMargin: units.gu(1)
504 color: styleMusic.common.white
505 elide: Text.ElideRight
506 text: album
507 fontSize: "small"
508 font.weight: Font.DemiBold
509 }
510 }
511 }74 }
512 }75 }
513 }76 }
51477
=== modified file 'MusicToolbar.qml'
--- MusicToolbar.qml 2014-09-23 20:45:41 +0000
+++ MusicToolbar.qml 2014-10-21 15:31:33 +0000
@@ -22,6 +22,7 @@
22import QtMultimedia 5.022import QtMultimedia 5.0
23import Ubuntu.Components 1.123import Ubuntu.Components 1.1
24import Ubuntu.Components.Popups 1.024import Ubuntu.Components.Popups 1.0
25import "common"
25import "settings.js" as Settings26import "settings.js" as Settings
2627
27Item {28Item {
@@ -35,59 +36,13 @@
35 property var currentPage: null36 property var currentPage: null
36 property var currentSheet: []37 property var currentSheet: []
37 property var currentTab: null38 property var currentTab: null
38 property var previousPage: null
3939
40 // Properties and signals for the toolbar40 // Properties and signals for the toolbar
41 property var cachedStates: []
42 property bool shown: false
43 property int transitionDuration: 100
44
45 property alias currentHeight: musicToolbarPanel.height41 property alias currentHeight: musicToolbarPanel.height
46 property alias minimizedHeight: musicToolbarPanel.minimizedHeight
47 property alias expandedHeight: musicToolbarPanel.expandedHeight
48 property alias fullHeight: musicToolbarPanel.fullHeight
49 property alias mouseAreaOffset: musicToolbarPanel.hintSize
50
51 property alias animating: musicToolbarPanel.animating
52 property alias opened: musicToolbarPanel.opened42 property alias opened: musicToolbarPanel.opened
5343
54 // Alias for autopilot
55 property alias currentMode: musicToolbarPanel.currentMode
56
57 Connections {
58 id: pageStackConn
59 target: mainPageStack
60
61 onCurrentPageChanged: {
62 previousPage = currentPage;
63
64 // If going back from nowPlaying jump back to tabs
65 if (previousPage === nowPlaying && mainPageStack.currentPage !== nowPlaying) {
66 while (mainPageStack.depth > 1) {
67 mainPageStack.pop(mainPageStack.currentPage)
68 }
69 }
70 }
71 }
72
73 /* Helper functions */44 /* Helper functions */
7445
75 // Disable the toolbar for this page/view (eg a dialog)
76 function disableToolbar()
77 {
78 cachedStates.push(state);
79 musicToolbarPanel.state = "hidden";
80 }
81
82 // Enable the toolbar (run when closing a page that disabled it)
83 function enableToolbar()
84 {
85 if (cachedStates.length > 0)
86 {
87 musicToolbarPanel.state = cachedStates.pop();
88 }
89 }
90
91 // Back button has been pressed, jump up pageStack or back to parent page46 // Back button has been pressed, jump up pageStack or back to parent page
92 function goBack()47 function goBack()
93 {48 {
@@ -98,18 +53,6 @@
98 else if (mainPageStack !== null && mainPageStack.depth > 1) {53 else if (mainPageStack !== null && mainPageStack.depth > 1) {
99 mainPageStack.pop(currentPage)54 mainPageStack.pop(currentPage)
100 }55 }
101
102 startAutohideTimer()
103 }
104
105 // Hide the toolbar
106 function hideToolbar()
107 {
108 if (!wideAspect) {
109 musicToolbarPanel.close();
110 }
111
112 toolbarAutoHideTimer.stop(); // cancel any autohide
113 }56 }
11457
115 // Remove sheet as it has been closed58 // Remove sheet as it has been closed
@@ -126,8 +69,6 @@
126 function setPage(childPage)69 function setPage(childPage)
127 {70 {
128 currentPage = childPage;71 currentPage = childPage;
129 // note: If pageStack tracking is needed readd here
130 //currentPageStack = pageStack === undefined ? null : pageStack;
131 }72 }
13273
133 // Set the current sheet (overrides page)74 // Set the current sheet (overrides page)
@@ -135,32 +76,6 @@
135 currentSheet.push(sheet)76 currentSheet.push(sheet)
136 }77 }
13778
138 // Show the toolbar
139 function showToolbar()
140 {
141 startAutohideTimer(); // always attempt to autohide toolbar
142
143 if (!musicToolbarPanel.opened) {
144 musicToolbarPanel.open();
145 }
146 }
147
148 // Start the autohidetimer
149 function startAutohideTimer()
150 {
151 toolbarAutoHideTimer.restart();
152 }
153
154 Connections {
155 target: mainView
156 onWideAspectChanged: {
157 // Force toolbar to show if in wideAspect
158 if (wideAspect && !opened) {
159 showToolbar();
160 }
161 }
162 }
163
164 Panel {79 Panel {
165 id: musicToolbarPanel80 id: musicToolbarPanel
166 anchors {81 anchors {
@@ -168,543 +83,9 @@
168 right: parent.right83 right: parent.right
169 bottom: parent.bottom84 bottom: parent.bottom
170 }85 }
171 height: currentMode === "full" ? fullHeight : expandedHeight86 height: units.gu(7.25)
172 locked: wideAspect87 locked: true
17388 opened: true
174 __closeOnContentsClicks: false // TODO: fix bug 1295720
175
176 // The current mode of the controls
177 property string currentMode: wideAspect || (currentPage === nowPlaying)
178 ? "full" : "expanded"
179
180 // Properties for the different heights
181 property int minimizedHeight: units.gu(0.5)
182 property int expandedHeight: units.gu(8)
183 property int fullHeight: units.gu(11)
184
185 onCurrentModeChanged: {
186 musicToolbarFullProgressMouseArea.enabled = currentMode === "full"
187 }
188
189 onOpenedChanged: {
190 onToolbarShownChanged(opened, currentPage, currentTab);
191
192 if (opened) {
193 startAutohideTimer();
194 }
195 }
196
197 /* Full toolbar */
198 Rectangle {
199 id: musicToolbarFullContainer
200 anchors {
201 fill: parent
202 }
203 color: styleMusic.toolbar.fullBackgroundColor
204 visible: musicToolbarPanel.currentMode === "full"
205
206 /* Buttons component */
207 Rectangle {
208 id: musicToolbarFullButtonsContainer
209 anchors.left: parent.left
210 anchors.top: musicToolbarFullProgressContainer.bottom
211 color: "transparent"
212 height: parent.height - musicToolbarFullProgressContainer.height
213 width: parent.width
214
215 /* Column for labels in wideAspect */
216 Column {
217 id: nowPlayingWideAspectLabels
218 anchors {
219 left: parent.left
220 leftMargin: units.gu(1)
221 right: nowPlayingRepeatButton.left
222 rightMargin: units.gu(1)
223 verticalCenter: parent.verticalCenter
224 }
225 visible: wideAspect
226
227 /* Clicking in the area shows the queue */
228 function trigger() {
229 if (trackQueue.model.count !== 0 && currentPage !== nowPlaying) {
230 tabs.pushNowPlaying();
231 }
232 else if (currentPage === nowPlaying) {
233 musicToolbar.goBack();
234 }
235 }
236
237 /* Title of track */
238 Label {
239 id: nowPlayingWideAspectTitle
240 anchors {
241 left: parent.left
242 leftMargin: units.gu(1)
243 right: parent.right
244 rightMargin: units.gu(1)
245 }
246 color: styleMusic.playerControls.labelColor
247 elide: Text.ElideRight
248 fontSize: "medium"
249 objectName: "playercontroltitle"
250 text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle
251 }
252
253 /* Artist of track */
254 Label {
255 id: nowPlayingWideAspectArtist
256 anchors {
257 left: parent.left
258 leftMargin: units.gu(1)
259 right: parent.right
260 rightMargin: units.gu(1)
261 }
262 color: styleMusic.playerControls.labelColor
263 elide: Text.ElideRight
264 fontSize: "small"
265 text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist
266 }
267
268 /* Album of track */
269 Label {
270 id: nowPlayingWideAspectAlbum
271 anchors {
272 left: parent.left
273 leftMargin: units.gu(1)
274 right: parent.right
275 rightMargin: units.gu(1)
276 }
277 color: styleMusic.playerControls.labelColor
278 elide: Text.ElideRight
279 fontSize: "small"
280 text: trackQueue.model.count === 0 ? "" : player.currentMetaAlbum
281 }
282 }
283
284 /* Repeat button */
285 Item {
286 id: nowPlayingRepeatButton
287 objectName: "repeatShape"
288 anchors.right: nowPlayingPreviousButton.left
289 anchors.rightMargin: units.gu(1)
290 anchors.verticalCenter: parent.verticalCenter
291 height: units.gu(6)
292 opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
293 width: height
294
295 function trigger() {
296 if (emptyPage.noMusic) {
297 return;
298 }
299
300 // Invert repeat settings
301 player.repeat = !player.repeat
302 }
303
304 Image {
305 id: repeatIcon
306 height: units.gu(3)
307 width: height
308 anchors.verticalCenter: parent.verticalCenter
309 anchors.horizontalCenter: parent.horizontalCenter
310 source: Qt.resolvedUrl("images/media-playlist-repeat.svg")
311 verticalAlignment: Text.AlignVCenter
312 opacity: player.repeat && !emptyPage.noMusic ? 1 : .4
313 }
314 }
315
316 /* Previous button */
317 Item {
318 id: nowPlayingPreviousButton
319 anchors.right: nowPlayingPlayButton.left
320 anchors.rightMargin: units.gu(1)
321 anchors.verticalCenter: parent.verticalCenter
322 height: units.gu(6)
323 objectName: "previousShape"
324 opacity: trackQueue.model.count === 0 ? .4 : 1
325 width: height
326
327 function trigger() {
328 if (trackQueue.model.count === 0) {
329 return;
330 }
331
332 player.previousSong()
333 }
334
335 Image {
336 id: nowPlayingPreviousIndicator
337 height: units.gu(3)
338 width: height
339 anchors.horizontalCenter: parent.horizontalCenter
340 anchors.verticalCenter: parent.verticalCenter
341 source: Qt.resolvedUrl("images/media-skip-backward.svg")
342 opacity: 1
343 }
344 }
345
346 /* Play/Pause button */
347 Rectangle {
348 id: nowPlayingPlayButton
349 anchors.horizontalCenter: parent.horizontalCenter
350 anchors.verticalCenter: parent.verticalCenter
351 antialiasing: true
352 color: styleMusic.toolbar.fullOuterPlayCircleColor
353 height: units.gu(12)
354 radius: height / 2
355 width: height
356
357 // draws the outter shadow/highlight
358 Rectangle {
359 id: sourceOutterFull
360 anchors { fill: parent; margins: -units.gu(0.1) }
361 radius: (width / 2)
362 antialiasing: true
363 gradient: Gradient {
364 GradientStop { position: 0.0; color: "black" }
365 GradientStop { position: 0.5; color: "transparent" }
366 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
367 }
368
369 Rectangle {
370 anchors.horizontalCenter: parent.horizontalCenter
371 anchors.verticalCenter: parent.verticalCenter
372 antialiasing: true
373 color: styleMusic.toolbar.fullOuterPlayCircleColor
374 height: nowPlayingPlayButton.height - units.gu(.1)
375 radius: height / 2
376 width: height
377
378 Rectangle {
379 id: nowPlayingPlayButtonInner
380 anchors.horizontalCenter: parent.horizontalCenter
381 anchors.verticalCenter: parent.verticalCenter
382 antialiasing: true
383 color: styleMusic.toolbar.fullInnerPlayCircleColor
384 height: units.gu(7)
385 radius: height / 2
386 width: height
387
388 // draws the inner shadow/highlight
389 Rectangle {
390 id: sourceInnerFull
391 anchors { fill: parent; margins: -units.gu(0.1) }
392 radius: (width / 2)
393 antialiasing: true
394 gradient: Gradient {
395 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
396 GradientStop { position: 0.5; color: "transparent" }
397 GradientStop { position: 1.0; color: "black" }
398 }
399
400 Rectangle {
401 anchors.horizontalCenter: parent.horizontalCenter
402 anchors.verticalCenter: parent.verticalCenter
403 antialiasing: true
404 color: styleMusic.toolbar.fullInnerPlayCircleColor
405 height: nowPlayingPlayButtonInner.height - units.gu(.1)
406 objectName: "playShape"
407 radius: height / 2
408 width: height
409
410 function trigger() {
411 if (emptyPage.noMusic) {
412 return;
413 }
414
415 if (trackQueue.model.count === 0) {
416 playRandomSong();
417 }
418 else {
419 player.toggle();
420 }
421 }
422
423 Image {
424 id: nowPlayingPlayIndicator
425 height: units.gu(6)
426 width: height
427 anchors.horizontalCenter: parent.horizontalCenter
428 anchors.verticalCenter: parent.verticalCenter
429 opacity: emptyPage.noMusic ? .4 : 1
430 source: player.playbackState === MediaPlayer.PlayingState ?
431 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
432 }
433 }
434 }
435 }
436 }
437 }
438 }
439
440 /* Next button */
441 Item {
442 id: nowPlayingNextButton
443 anchors.left: nowPlayingPlayButton.right
444 anchors.leftMargin: units.gu(1)
445 anchors.verticalCenter: parent.verticalCenter
446 height: units.gu(6)
447 objectName: "forwardShape"
448 opacity: trackQueue.model.count === 0 ? .4 : 1
449 width: height
450
451 function trigger() {
452 if (trackQueue.model.count === 0 || emptyPage.noMusic) {
453 return;
454 }
455
456 player.nextSong()
457 }
458
459 Image {
460 id: nowPlayingNextIndicator
461 height: units.gu(3)
462 width: height
463 anchors.horizontalCenter: parent.horizontalCenter
464 anchors.verticalCenter: parent.verticalCenter
465 source: Qt.resolvedUrl("images/media-skip-forward.svg")
466 opacity: 1
467 }
468 }
469
470 /* Shuffle button */
471 Item {
472 id: nowPlayingShuffleButton
473 objectName: "shuffleShape"
474 anchors.left: nowPlayingNextButton.right
475 anchors.leftMargin: units.gu(1)
476 anchors.verticalCenter: parent.verticalCenter
477 height: units.gu(6)
478 opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
479 width: height
480
481 function trigger() {
482 if (emptyPage.noMusic) {
483 return;
484 }
485
486 // Invert shuffle settings
487 player.shuffle = !player.shuffle
488 }
489
490 Image {
491 id: shuffleIcon
492 height: units.gu(3)
493 width: height
494 anchors.verticalCenter: parent.verticalCenter
495 anchors.horizontalCenter: parent.horizontalCenter
496 source: Qt.resolvedUrl("images/media-playlist-shuffle.svg")
497 opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4
498 }
499 }
500
501 /* Search button in wideAspect */
502 Item {
503 id: nowPlayingSearchButton
504 objectName: "searchShape"
505 anchors {
506 right: parent.right
507 rightMargin: units.gu(1)
508 verticalCenter: parent.verticalCenter
509 }
510 height: units.gu(6)
511 opacity: !emptyPage.noMusic ? 1 : .4
512 width: height
513 visible: wideAspect
514
515 function trigger() {
516 if (emptyPage.noMusic) {
517 return;
518 }
519
520 if (!searchSheet.sheetVisible) {
521 PopupUtils.open(searchSheet.sheet,
522 mainView, { title: i18n.tr("Search")} )
523 }
524 }
525
526 Image {
527 id: searchIcon
528 anchors {
529 horizontalCenter: parent.horizontalCenter
530 verticalCenter: parent.verticalCenter
531 }
532 height: units.gu(3)
533 opacity: !emptyPage.noMusic ? 1 : .4
534 source: Qt.resolvedUrl("images/search.svg")
535 width: height
536 }
537 }
538 }
539
540 /* Progress bar component */
541 Rectangle {
542 id: musicToolbarFullProgressContainer
543 anchors.left: parent.left
544 anchors.top: parent.top
545 color: styleMusic.toolbar.fullBackgroundColor
546 height: units.gu(3)
547 width: parent.width
548
549 /* Position label */
550 Label {
551 id: musicToolbarFullPositionLabel
552 anchors.left: parent.left
553 anchors.leftMargin: units.gu(2)
554 anchors.top: parent.top
555 color: styleMusic.nowPlaying.labelColor
556 fontSize: "x-small"
557 height: parent.height
558 horizontalAlignment: Text.AlignHCenter
559 text: durationToString(player.position)
560 verticalAlignment: Text.AlignVCenter
561 width: units.gu(3)
562 }
563
564 /* Progress bar */
565 Rectangle {
566 id: musicToolbarFullProgressBarContainer
567 objectName: "progressBarShape"
568 anchors.left: musicToolbarFullPositionLabel.right
569 anchors.leftMargin: units.gu(2)
570 anchors.right: musicToolbarFullDurationLabel.left
571 anchors.rightMargin: units.gu(2)
572 anchors.verticalCenter: parent.verticalCenter
573 color: "transparent"
574 height: units.gu(1);
575 state: trackQueue.model.count === 0 ? "disabled" : "enabled"
576
577 states: [
578 State {
579 name: "disabled"
580 PropertyChanges {
581 target: musicToolbarFullProgressMouseArea
582 enabled: false
583 }
584 PropertyChanges {
585 target: musicToolbarFullProgressTrough
586 visible: false
587 }
588 PropertyChanges {
589 target: musicToolbarFullProgressHandle
590 visible: false
591 }
592 },
593 State {
594 name: "enabled"
595 PropertyChanges {
596 target: musicToolbarFullProgressMouseArea
597 enabled: true
598 }
599 PropertyChanges {
600 target: musicToolbarFullProgressTrough
601 visible: true
602 }
603 PropertyChanges {
604 target: musicToolbarFullProgressHandle
605 visible: true
606 }
607 }
608 ]
609
610 property bool seeking: false
611
612 onSeekingChanged: {
613 if (seeking === false) {
614 musicToolbarFullPositionLabel.text = durationToString(player.position)
615 }
616 }
617
618 Connections {
619 target: player
620 onDurationChanged: {
621 console.debug("Duration changed: " + player.duration)
622 musicToolbarFullDurationLabel.text = durationToString(player.duration)
623 }
624 onPositionChanged: {
625 if (musicToolbarFullProgressBarContainer.seeking === false)
626 {
627 musicToolbarFullPositionLabel.text = durationToString(player.position)
628 musicToolbarFullDurationLabel.text = durationToString(player.duration)
629 musicToolbarFullProgressHandle.x = (player.position / player.duration) * musicToolbarFullProgressBarContainer.width
630 - musicToolbarFullProgressHandle.width / 2;
631 }
632 }
633 onStopped: {
634 musicToolbarFullProgressHandle.x = -musicToolbarFullProgressHandle.width / 2;
635
636 musicToolbarFullPositionLabel.text = durationToString(0);
637 musicToolbarFullDurationLabel.text = durationToString(0);
638 }
639 }
640
641 // Black background behind the progress bar
642 Rectangle {
643 id: musicToolbarFullProgressBackground
644 anchors.verticalCenter: parent.verticalCenter;
645 color: styleMusic.toolbar.fullProgressBackgroundColor;
646 height: parent.height;
647 radius: units.gu(0.5)
648 width: parent.width;
649 }
650
651 // The orange fill of the progress bar
652 Rectangle {
653 id: musicToolbarFullProgressTrough
654 anchors.verticalCenter: parent.verticalCenter;
655 antialiasing: true
656 color: styleMusic.toolbar.fullProgressTroughColor;
657 height: parent.height;
658 radius: units.gu(0.5)
659 width: musicToolbarFullProgressHandle.x + (height / 2); // +radius
660 }
661
662 // The current position (handle) of the progress bar
663 Rectangle {
664 id: musicToolbarFullProgressHandle
665 anchors.verticalCenter: musicToolbarFullProgressBackground.verticalCenter
666 antialiasing: true
667 color: styleMusic.nowPlaying.progressHandleColor
668 height: units.gu(1.5)
669 radius: height / 2
670 width: height
671
672 // On X change update the position string
673 onXChanged: {
674 if (musicToolbarFullProgressBarContainer.seeking) {
675 var fraction = (x + (width / 2)) / parent.width;
676 musicToolbarFullPositionLabel.text = durationToString(fraction * player.duration)
677 }
678 }
679 }
680 }
681
682 /* Duration label */
683 Label {
684 id: musicToolbarFullDurationLabel
685 anchors.right: parent.right
686 anchors.rightMargin: units.gu(2)
687 anchors.top: parent.top
688 color: styleMusic.nowPlaying.labelColor
689 fontSize: "x-small"
690 height: parent.height
691 horizontalAlignment: Text.AlignHCenter
692 text: durationToString(player.duration)
693 verticalAlignment: Text.AlignVCenter
694 width: units.gu(3)
695 }
696
697 /* Border at the bottom */
698 Rectangle {
699 anchors.bottom: parent.bottom
700 anchors.left: parent.left
701 anchors.right: parent.right
702 color: styleMusic.common.white
703 height: units.gu(0.1)
704 opacity: 0.1
705 }
706 }
707 }
70889
709 /* Expanded toolbar */90 /* Expanded toolbar */
710 Rectangle {91 Rectangle {
@@ -713,12 +94,13 @@
713 fill: parent94 fill: parent
714 }95 }
715 color: "transparent"96 color: "transparent"
716 visible: musicToolbarPanel.currentMode === "expanded"
71797
718 Rectangle {98 Rectangle {
719 id: musicToolbarPlayerControls99 id: musicToolbarPlayerControls
720 anchors.fill: parent100 anchors {
721 color: styleMusic.playerControls.backgroundColor101 fill: parent
102 }
103 color: "#000"
722 state: trackQueue.model.count === 0 ? "disabled" : "enabled"104 state: trackQueue.model.count === 0 ? "disabled" : "enabled"
723 states: [105 states: [
724 State {106 State {
@@ -745,39 +127,55 @@
745 }127 }
746 ]128 ]
747129
130 /* Disabled (empty state) controls */
748 Rectangle {131 Rectangle {
749 id: disabledPlayerControlsGroup132 id: disabledPlayerControlsGroup
750 anchors.fill: parent133 anchors {
134 bottom: playerControlsProgressBar.top
135 left: parent.left
136 right: parent.right
137 top: parent.top
138 }
751 color: "transparent"139 color: "transparent"
752 visible: trackQueue.model.count === 0
753140
754 Label {141 Label {
755 id: noSongsInQueueLabel142 id: noSongsInQueueLabel
756 anchors {143 anchors {
757 left: parent.left144 left: parent.left
145 leftMargin: units.gu(2)
758 right: disabledPlayerControlsPlayButton.left146 right: disabledPlayerControlsPlayButton.left
759 margins: units.gu(1)147 rightMargin: units.gu(2)
760 top: parent.top148 verticalCenter: parent.verticalCenter
761 }149 }
762 color: styleMusic.playerControls.labelColor150 color: styleMusic.playerControls.labelColor
763 text: i18n.tr("Tap play to shuffle music")151 text: i18n.tr("Tap to shuffle music")
764 fontSize: "large"152 fontSize: "large"
765 wrapMode: Text.WordWrap153 wrapMode: Text.WordWrap
766 maximumLineCount: 2154 maximumLineCount: 2
767 }155 }
768156
769 Rectangle {157 /* Play/Pause button */
158 Icon {
770 id: disabledPlayerControlsPlayButton159 id: disabledPlayerControlsPlayButton
771 anchors.right: parent.right160 anchors {
772 anchors.rightMargin: units.gu(1)161 right: parent.right
773 anchors.verticalCenter: parent.verticalCenter162 rightMargin: units.gu(3)
774 antialiasing: true163 verticalCenter: parent.verticalCenter
775 color: "#444"164 }
776 height: units.gu(7)165 color: "#FFF"
777 radius: height / 2166 height: units.gu(2.5)
167 name: player.playbackState === MediaPlayer.PlayingState ?
168 "media-playback-pause" : "media-playback-start"
169 objectName: "disabledSmallPlayShape"
778 width: height170 width: height
171 }
779172
780 function trigger() {173 /* Click to shuffle music */
174 MouseArea {
175 anchors {
176 fill: parent
177 }
178 onClicked: {
781 if (emptyPage.noMusic) {179 if (emptyPage.noMusic) {
782 return;180 return;
783 }181 }
@@ -789,230 +187,54 @@
789 player.toggle();187 player.toggle();
790 }188 }
791 }189 }
792
793 // draws the outer shadow/highlight
794 Rectangle {
795 id: disabledSourceOutter
796 anchors { fill: parent; margins: -units.gu(0.1) }
797 radius: (width / 2)
798 antialiasing: true
799 gradient: Gradient {
800 GradientStop { position: 0.0; color: "black" }
801 GradientStop { position: 0.5; color: "transparent" }
802 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
803 }
804
805 Rectangle {
806 anchors.verticalCenter: parent.verticalCenter
807 anchors.horizontalCenter: parent.horizontalCenter
808 antialiasing: true
809 color: "#444"
810 height: playerControlsPlayButton.height - units.gu(.1)
811 radius: height / 2
812 width: height
813
814 Rectangle {
815 id: disabledPlayerControlsPlayInnerCircle
816 anchors.horizontalCenter: parent.horizontalCenter
817 anchors.verticalCenter: parent.verticalCenter
818 antialiasing: true
819 height: units.gu(4.5)
820 radius: height / 2
821 width: height
822 color: styleMusic.toolbar.fullInnerPlayCircleColor
823
824 // draws the inner shadow/highlight
825 Rectangle {
826 id: disabledSourceInner
827 anchors { fill: parent; margins: -units.gu(0.1) }
828 radius: (width / 2)
829 antialiasing: true
830 gradient: Gradient {
831 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
832 GradientStop { position: 0.5; color: "transparent" }
833 GradientStop { position: 1.0; color: "black" }
834 }
835
836 Rectangle {
837 anchors.verticalCenter: parent.verticalCenter
838 anchors.horizontalCenter: parent.horizontalCenter
839 antialiasing: true
840 height: playerControlsPlayInnerCircle.height - units.gu(.1)
841 radius: height / 2
842 width: height
843 color: styleMusic.toolbar.fullInnerPlayCircleColor
844
845 Image {
846 id: disabledPlayIndicator
847 height: units.gu(4)
848 width: height
849 anchors.horizontalCenter: parent.horizontalCenter
850 anchors.verticalCenter: parent.verticalCenter
851 opacity: emptyPage.noMusic ? .4 : 1
852 source: player.playbackState === MediaPlayer.PlayingState ?
853 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
854 }
855 }
856 }
857 }
858 }
859 }
860 }190 }
861 }191 }
862192
193 /* Enabled (queue > 0) controls */
863 Rectangle {194 Rectangle {
864 id: enabledPlayerControlsGroup195 id: enabledPlayerControlsGroup
865 anchors.fill: parent196 anchors {
197 bottom: playerControlsProgressBar.top
198 left: parent.left
199 right: parent.right
200 top: parent.top
201 }
866 color: "transparent"202 color: "transparent"
867 visible: trackQueue.model.count !== 0203
868204 /* Album art in player controls */
869 /* Settings button */205 CoverGrid {
870 // TODO: Enable settings when it is practical206 id: playerControlsImage
871 /* Rectangle {207 anchors {
872 id: playerControlsSettings208 bottom: parent.bottom
873 anchors.right: parent.right209 left: parent.left
874 anchors.verticalCenter: parent.verticalCenter210 top: parent.top
875 width: units.gu(6)211 }
876 height: width212 covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaArt}]
877 color: "transparent"213 size: parent.height
878
879 Image {
880 anchors.horizontalCenter: parent.horizontalCenter
881 anchors.verticalCenter: parent.verticalCenter
882 height: units.gu(3)
883 source: Qt.resolvedUrl("images/settings.png")
884 width: height
885 }
886
887 MouseArea {
888 anchors.fill: parent
889 onClicked: {
890 console.debug('Debug: Show settings')
891 PopupUtils.open(Qt.resolvedUrl("MusicSettings.qml"), mainView,
892 {
893 title: i18n.tr("Settings")
894 } )
895 }
896 }
897 } */
898
899 /* Play/Pause button TODO: image and colours needs updating */
900 Rectangle {
901 id: playerControlsPlayButton
902 anchors.right: parent.right
903 anchors.rightMargin: units.gu(1)
904 anchors.verticalCenter: parent.verticalCenter
905 antialiasing: true
906 color: "#444"
907 height: units.gu(7)
908 objectName: "smallPlayShape"
909 radius: height / 2
910 width: height
911
912 function trigger() {
913 if (emptyPage.noMusic) {
914 return;
915 }
916
917 if (trackQueue.model.count === 0) {
918 playRandomSong();
919 }
920 else {
921 player.toggle();
922 }
923 }
924
925 // draws the outer shadow/highlight
926 Rectangle {
927 id: sourceOutter
928 anchors { fill: parent; margins: -units.gu(0.1) }
929 radius: (width / 2)
930 antialiasing: true
931 gradient: Gradient {
932 GradientStop { position: 0.0; color: "black" }
933 GradientStop { position: 0.5; color: "transparent" }
934 GradientStop { position: 1.0; color: UbuntuColors.warmGrey }
935 }
936
937 Rectangle {
938 anchors.verticalCenter: parent.verticalCenter
939 anchors.horizontalCenter: parent.horizontalCenter
940 antialiasing: true
941 color: "#444"
942 height: playerControlsPlayButton.height - units.gu(.1)
943 radius: height / 2
944 width: height
945
946 Rectangle {
947 id: playerControlsPlayInnerCircle
948 anchors.horizontalCenter: parent.horizontalCenter
949 anchors.verticalCenter: parent.verticalCenter
950 antialiasing: true
951 height: units.gu(4.5)
952 radius: height / 2
953 width: height
954 color: styleMusic.toolbar.fullInnerPlayCircleColor
955
956 // draws the inner shadow/highlight
957 Rectangle {
958 id: sourceInner
959 anchors { fill: parent; margins: -units.gu(0.1) }
960 radius: (width / 2)
961 antialiasing: true
962 gradient: Gradient {
963 GradientStop { position: 0.0; color: UbuntuColors.warmGrey }
964 GradientStop { position: 0.5; color: "transparent" }
965 GradientStop { position: 1.0; color: "black" }
966 }
967
968 Rectangle {
969 anchors.verticalCenter: parent.verticalCenter
970 anchors.horizontalCenter: parent.horizontalCenter
971 antialiasing: true
972 height: playerControlsPlayInnerCircle.height - units.gu(.1)
973 radius: height / 2
974 width: height
975 color: styleMusic.toolbar.fullInnerPlayCircleColor
976
977 Image {
978 id: playindicator
979 height: units.gu(4)
980 width: height
981 anchors.horizontalCenter: parent.horizontalCenter
982 anchors.verticalCenter: parent.verticalCenter
983 opacity: emptyPage.noMusic ? .4 : 1
984 source: player.playbackState === MediaPlayer.PlayingState ?
985 Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg")
986 }
987 }
988 }
989 }
990 }
991 }
992 }214 }
993215
994 /* Container holding the labels for the toolbar */216 /* Column of meta labels */
995 Rectangle {217 Column {
996 id: playerControlLabelContainer218 id: playerControlsLabels
997 anchors.bottom: parent.bottom219 anchors {
998 anchors.left: parent.left220 left: playerControlsImage.right
999 anchors.right: playerControlsPlayButton.left221 leftMargin: units.gu(1.5)
1000 anchors.top: parent.top222 right: playerControlsPlayButton.left
1001 color: "transparent"223 rightMargin: units.gu(1)
224 verticalCenter: parent.verticalCenter
225 }
1002226
1003 /* Title of track */227 /* Title of track */
1004 Label {228 Label {
1005 id: playerControlsTitle229 id: playerControlsTitle
1006 anchors.left: parent.left230 anchors {
1007 anchors.leftMargin: units.gu(1)231 left: parent.left
1008 anchors.right: parent.right232 right: parent.right
1009 anchors.rightMargin: units.gu(1)233 }
1010 anchors.top: parent.top234 color: "#FFF"
1011 anchors.topMargin: units.gu(1)
1012 color: styleMusic.playerControls.labelColor
1013 elide: Text.ElideRight235 elide: Text.ElideRight
1014 fontSize: "medium"236 fontSize: "small"
1015 objectName: "playercontroltitle"237 font.weight: Font.DemiBold
1016 text: player.currentMetaTitle === ""238 text: player.currentMetaTitle === ""
1017 ? player.source : player.currentMetaTitle239 ? player.source : player.currentMetaTitle
1018 }240 }
@@ -1020,119 +242,105 @@
1020 /* Artist of track */242 /* Artist of track */
1021 Label {243 Label {
1022 id: playerControlsArtist244 id: playerControlsArtist
1023 anchors.left: parent.left245 anchors {
1024 anchors.leftMargin: units.gu(1)246 left: parent.left
1025 anchors.right: parent.right247 right: parent.right
1026 anchors.rightMargin: units.gu(1)248 }
1027 anchors.top: playerControlsTitle.bottom249 color: "#FFF"
1028 color: styleMusic.playerControls.labelColor
1029 elide: Text.ElideRight250 elide: Text.ElideRight
1030 fontSize: "small"251 fontSize: "small"
252 opacity: 0.4
1031 text: player.currentMetaArtist253 text: player.currentMetaArtist
1032 }254 }
1033255 }
1034 /* Album of track */256
1035 Label {257 /* Play/Pause button */
1036 id: playerControlsAlbum258 Icon {
1037 anchors.left: parent.left259 id: playerControlsPlayButton
1038 anchors.leftMargin: units.gu(1)260 anchors {
1039 anchors.right: parent.right261 right: parent.right
1040 anchors.rightMargin: units.gu(1)262 rightMargin: units.gu(3)
1041 anchors.top: playerControlsArtist.bottom263 verticalCenter: parent.verticalCenter
1042 color: styleMusic.playerControls.labelColor264 }
1043 elide: Text.ElideRight265 color: "#FFF"
1044 fontSize: "small"266 height: units.gu(2.5)
1045 text: player.currentMetaAlbum267 name: player.playbackState === MediaPlayer.PlayingState ?
1046 }268 "media-playback-pause" : "media-playback-start"
1047 }269 objectName: "playShape"
1048270 width: height
271 }
272
273 MouseArea {
274 anchors {
275 bottom: parent.bottom
276 horizontalCenter: playerControlsPlayButton.horizontalCenter
277 top: parent.top
278 }
279 onClicked: player.toggle()
280 width: units.gu(8)
281
282 Rectangle {
283 anchors {
284 fill: parent
285 }
286 color: "#FFF"
287 opacity: parent.pressed ? 0.1 : 0
288
289 Behavior on opacity {
290 UbuntuNumberAnimation {
291 duration: UbuntuAnimation.FastDuration
292 }
293 }
294 }
295 }
296
297 /* Mouse area to jump to now playing */
1049 Rectangle {298 Rectangle {
1050 anchors.fill: playerControlLabelContainer299 anchors {
300 bottom: parent.bottom
301 left: parent.left
302 right: playerControlsLabels.right
303 top: parent.top
304 }
1051 color: "transparent"305 color: "transparent"
306 objectName: "jumpNowPlaying"
1052 function trigger() {307 function trigger() {
1053 tabs.pushNowPlaying();308 tabs.pushNowPlaying();
1054 }309 }
1055 }310 }
1056 }311 }
1057 }312
1058 }313 /* Object which provides the progress bar when toolbar is minimized */
1059314 Rectangle {
1060 /* Object which provides the progress bar when toolbar is minimized */315 id: playerControlsProgressBar
1061 Rectangle {316 anchors {
1062 id: musicToolbarSmallProgressBackground317 bottom: parent.bottom
1063 anchors {318 left: parent.left
1064 bottom: parent.top319 right: parent.right
1065 left: parent.left320 }
1066 right: parent.right321 color: styleMusic.common.black
1067 }322 height: units.gu(0.25)
1068 color: styleMusic.common.black323
1069 height: musicToolbarPanel.minimizedHeight324 Rectangle {
1070 visible: (!musicToolbarPanel.animating &&325 id: playerControlsProgressBarHint
1071 !musicToolbarPanel.opened)326 anchors {
1072 || musicToolbarPanel.currentMode == "expanded"327 left: parent.left
1073328 top: parent.top
1074 Rectangle {329 }
1075 id: musicToolbarSmallProgressHint330 color: UbuntuColors.blue
1076 anchors.left: parent.left331 height: parent.height
1077 anchors.top: parent.top332 width: 0
1078 color: styleMusic.nowPlaying.progressForegroundColor333
1079 height: parent.height334 Connections {
1080 width: 0335 target: player
1081336 onPositionChanged: {
1082 Connections {337 playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width
1083 target: player338 }
1084 onPositionChanged: {339 onStopped: {
1085 musicToolbarSmallProgressHint.width = (player.position / player.duration) * musicToolbarSmallProgressBackground.width340 playerControlsProgressBarHint.width = 0;
1086 }341 }
1087 onStopped: {342 }
1088 musicToolbarSmallProgressHint.width = 0;343 }
1089 }
1090 }
1091 }
1092 }
1093
1094 /* Mouse events for the progress bar
1095 is after musicToolbarMouseArea so that it captures mouse events for dragging */
1096 MouseArea {
1097 id: musicToolbarFullProgressMouseArea
1098 height: units.gu(2)
1099 width: musicToolbarFullProgressBarContainer.width
1100 x: musicToolbarFullProgressBarContainer.x
1101 y: musicToolbarFullProgressBarContainer.y
1102
1103 drag.axis: Drag.XAxis
1104 drag.minimumX: -(musicToolbarFullProgressHandle.width / 2)
1105 drag.maximumX: musicToolbarFullProgressBarContainer.width - (musicToolbarFullProgressHandle.width / 2)
1106 drag.target: musicToolbarFullProgressHandle
1107
1108 onPressed: {
1109 musicToolbarFullProgressBarContainer.seeking = true;
1110
1111 // Jump the handle to the current mouse position
1112 musicToolbarFullProgressHandle.x = mouse.x - (musicToolbarFullProgressHandle.width / 2);
1113 }
1114
1115 onReleased: {
1116 var fraction = mouse.x / musicToolbarFullProgressBarContainer.width;
1117
1118 // Limit the bounds of the fraction
1119 fraction = fraction < 0 ? 0 : fraction
1120 fraction = fraction > 1 ? 1 : fraction
1121
1122 player.seek((fraction) * player.duration);
1123 musicToolbarFullProgressBarContainer.seeking = false;
1124 }
1125 }
1126
1127 // Timer for autohide
1128 Timer {
1129 id: toolbarAutoHideTimer
1130 interval: 5000
1131 repeat: false
1132 running: false
1133 onTriggered: {
1134 if (currentPage !== nowPlaying) { // don't autohide on now playing
1135 hideToolbar();
1136 }344 }
1137 }345 }
1138 }346 }
1139347
=== modified file 'MusicTracks.qml'
--- MusicTracks.qml 2014-09-20 15:41:33 +0000
+++ MusicTracks.qml 2014-10-21 15:31:33 +0000
@@ -36,8 +36,10 @@
3636
37 ListView {37 ListView {
38 id: tracklist38 id: tracklist
39 anchors.fill: parent39 anchors {
40 anchors.bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight40 fill: parent
41 topMargin: units.gu(2)
42 }
41 highlightFollowsCurrentItem: false43 highlightFollowsCurrentItem: false
42 objectName: "trackstab-listview"44 objectName: "trackstab-listview"
43 model: SortFilterModel {45 model: SortFilterModel {
@@ -59,7 +61,8 @@
59 color: "transparent"61 color: "transparent"
60 objectName: "tracksPageListItem" + index62 objectName: "tracksPageListItem" + index
61 width: parent.width63 width: parent.width
62 height: styleMusic.common.itemHeight64 height: units.gu(7)
65 showDivider: false
6366
64 rightSideActions: [67 rightSideActions: [
65 AddToQueue {68 AddToQueue {
@@ -77,29 +80,25 @@
7780
78 MusicRow {81 MusicRow {
79 id: musicRow82 id: musicRow
83 anchors.verticalCenter: parent.verticalCenter
80 covers: [{art: model.art}]84 covers: [{art: model.art}]
85 isSquare: true
86 coverSize: units.gu(6)
87 spacing: units.gu(2)
81 column: Column {88 column: Column {
82 spacing: units.gu(1)
83 Label {
84 id: trackArtist
85 color: styleMusic.common.subtitle
86 fontSize: "x-small"
87 text: model.author
88 }
89
90 Label {89 Label {
91 id: trackTitle90 id: trackTitle
92 color: styleMusic.common.music91 color: styleMusic.common.music
93 fontSize: "medium"92 fontSize: "small"
94 objectName: "tracktitle"93 objectName: "tracktitle"
95 text: model.title94 text: model.title
96 }95 }
9796
98 Label {97 Label {
99 id: trackAlbum98 id: trackArtist
100 color: styleMusic.common.subtitle99 color: styleMusic.common.subtitle
101 fontSize: "xx-small"100 fontSize: "x-small"
102 text: model.album101 text: model.author
103 }102 }
104 }103 }
105 }104 }
106105
=== modified file 'MusicaddtoPlaylist.qml'
--- MusicaddtoPlaylist.qml 2014-09-20 10:50:45 +0000
+++ MusicaddtoPlaylist.qml 2014-10-21 15:31:33 +0000
@@ -65,7 +65,6 @@
65 ListView {65 ListView {
66 id: addtoPlaylistView66 id: addtoPlaylistView
67 anchors {67 anchors {
68 bottomMargin: musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
69 fill: parent68 fill: parent
70 }69 }
71 clip: true70 clip: true
7271
=== modified file 'Player.qml'
--- Player.qml 2014-09-20 15:41:33 +0000
+++ Player.qml 2014-10-21 15:31:33 +0000
@@ -187,7 +187,11 @@
187 else {187 else {
188 var obj = trackQueue.model.get(player.currentIndex);188 var obj = trackQueue.model.get(player.currentIndex);
189 currentMetaAlbum = obj.album;189 currentMetaAlbum = obj.album;
190 currentMetaArt = obj.art;190
191 if (obj.art !== undefined) { // FIXME: protect against not art property in playlists
192 currentMetaArt = obj.art;
193 }
194
191 currentMetaArtist = obj.author;195 currentMetaArtist = obj.author;
192 currentMetaFile = obj.filename;196 currentMetaFile = obj.filename;
193 currentMetaTitle = obj.title;197 currentMetaTitle = obj.title;
194198
=== modified file 'Style.qml'
--- Style.qml 2014-09-20 10:50:45 +0000
+++ Style.qml 2014-10-21 15:31:33 +0000
@@ -34,8 +34,8 @@
34 property QtObject common: QtObject {34 property QtObject common: QtObject {
35 property color black: "#000000";35 property color black: "#000000";
36 property color white: "#FFFFFF";36 property color white: "#FFFFFF";
37 property color music: "#333333";37 property color music: "#FFFFFF";
38 property color subtitle: "#666666";38 property color subtitle: "#999999";
39 property color expandedColor: "#000000";39 property color expandedColor: "#000000";
40 property int albumSize: units.gu(10);40 property int albumSize: units.gu(10);
41 property int itemHeight: units.gu(12);41 property int itemHeight: units.gu(12);
4242
=== modified file 'click/apparmor.json'
--- click/apparmor.json 2014-07-01 23:13:50 +0000
+++ click/apparmor.json 2014-10-21 15:31:33 +0000
@@ -1,7 +1,17 @@
1{1{
2 "policy_version": 1.2,2 "policy_version": 1.2,
3 "template": "unconfined",
4 "policy_groups": [3 "policy_groups": [
5 "content_exchange"4 "audio",
5 "content_exchange",
6 "music_files_read",
7 "networking",
8 "usermetrics"
9 ],
10 "read_path": [
11 "@{HOME}/.cache/media-art/",
12 "@{HOME}/.cache/mediascanner-2.0/"
13 ],
14 "write_path": [
15 "@{HOME}/Music/Imported/"
6 ]16 ]
7}17}
818
=== modified file 'com.ubuntu.music_music.desktop.in.in'
--- com.ubuntu.music_music.desktop.in.in 2014-07-21 14:49:14 +0000
+++ com.ubuntu.music_music.desktop.in.in 2014-10-21 15:31:33 +0000
@@ -9,4 +9,7 @@
9StartupNotify=true9StartupNotify=true
10X-Ubuntu-Touch=true10X-Ubuntu-Touch=true
11X-Ubuntu-Single-Instance=true11X-Ubuntu-Single-Instance=true
12X-Ubuntu-Splash-Show-Header=true
13_X-Ubuntu-Splash-Title=Music
14X-Ubuntu-Splash-Color=#1e1e23
12X-Ubuntu-Default-Department-ID=sound-video15X-Ubuntu-Default-Department-ID=sound-video
1316
=== modified file 'common/AlbumsPage.qml'
--- common/AlbumsPage.qml 2014-10-07 02:15:06 +0000
+++ common/AlbumsPage.qml 2014-10-21 15:31:33 +0000
@@ -28,26 +28,116 @@
2828
29MusicPage {29MusicPage {
30 id: albumStackPage30 id: albumStackPage
31 anchors.bottomMargin: units.gu(.5)
32 objectName: "albumsArtistPage"31 objectName: "albumsArtistPage"
33 visible: false32 visible: false
3433
35 property string artist: ""34 property string artist: "Unknown Artist"
36 property var covers: []35 property var covers: []
3736
38 ListView {37 CardView {
39 id: albumtrackslist38 id: artistAlbumView
40 anchors {39 anchors {
41 bottomMargin: wideAspect ? musicToolbar.fullHeight : musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
42 fill: parent40 fill: parent
43 }41 }
44 delegate: albumTracksDelegate42 header: BlurredHeader {
45 header: artistHeaderDelegate43 rightColumn: Column {
44 spacing: units.gu(2)
45 Button {
46 id: shuffleRow
47 height: units.gu(4)
48 strokeColor: UbuntuColors.green
49 width: units.gu(15)
50 Text {
51 anchors {
52 centerIn: parent
53 }
54 color: "white"
55 text: i18n.tr("Shuffle")
56 }
57 MouseArea {
58 anchors.fill: parent
59 onClicked: shuffleModel(songArtistModel)
60 }
61 }
62 Button {
63 id: queueAllRow
64 height: units.gu(4)
65 strokeColor: UbuntuColors.green
66 width: units.gu(15)
67 Text {
68 anchors {
69 centerIn: parent
70 }
71 color: "white"
72 text: i18n.tr("Queue all")
73 }
74 MouseArea {
75 anchors.fill: parent
76 onClicked: addQueueFromModel(songArtistModel)
77 }
78 }
79 Button {
80 id: playRow
81 color: UbuntuColors.green
82 height: units.gu(4)
83 text: i18n.tr("Play all")
84 width: units.gu(15)
85 MouseArea {
86 anchors.fill: parent
87 onClicked: trackClicked(songArtistModel, 0, true)
88 }
89 }
90 }
91 coverSources: albumStackPage.covers
92 height: units.gu(30)
93 bottomColumn: Column {
94 Label {
95 id: artistLabel
96 anchors {
97 left: parent.left
98 right: parent.right
99 }
100 color: styleMusic.common.music
101 elide: Text.ElideRight
102 fontSize: "x-large"
103 maximumLineCount: 1
104 objectName: "artistLabel"
105 text: artist
106 wrapMode: Text.NoWrap
107 }
108
109 Item {
110 height: units.gu(1)
111 width: parent.width
112 }
113
114 Label {
115 id: artistCount
116 anchors {
117 left: parent.left
118 right: parent.right
119 }
120 color: styleMusic.common.subtitle
121 elide: Text.ElideRight
122 fontSize: "small"
123 maximumLineCount: 1
124 text: i18n.tr("%1 album", "%1 albums", artistsModel.count).arg(artistsModel.count)
125 }
126 }
127
128 SongsModel {
129 id: songArtistModel
130 albumArtist: albumStackPage.artist
131 store: musicStore
132 }
133 }
134 itemWidth: units.gu(12)
46 model: AlbumsModel {135 model: AlbumsModel {
47 id: artistsModel136 id: artistsModel
48 albumArtist: albumStackPage.artist137 albumArtist: albumStackPage.artist
49 store: musicStore138 store: musicStore
50 }139 }
140<<<<<<< TREE
51 width: parent.width141 width: parent.width
52142
53 Component {143 Component {
@@ -408,6 +498,26 @@
408 }498 }
409 }499 }
410 }500 }
501=======
502 delegate: Card {
503 id: albumCard
504 coverSources: [{art: model.art}]
505 objectName: "albumsPageGridItem" + index
506 primaryText: model.title
507 secondaryTextVisible: false
508
509 onClicked: {
510 songsPage.album = model.title;
511
512 songsPage.line1 = model.artist
513 songsPage.line2 = model.title
514 songsPage.isAlbum = true
515 songsPage.covers = [{art: model.art}]
516 songsPage.genre = undefined
517 songsPage.title = i18n.tr("Album")
518
519 mainPageStack.push(songsPage)
520>>>>>>> MERGE-SOURCE
411 }521 }
412 }522 }
413 }523 }
414524
=== modified file 'common/BlurredBackground.qml'
--- common/BlurredBackground.qml 2014-09-20 15:41:33 +0000
+++ common/BlurredBackground.qml 2014-10-21 15:31:33 +0000
@@ -23,8 +23,14 @@
2323
24// Blurred background24// Blurred background
25Rectangle {25Rectangle {
26 anchors.fill: parent26 width: parent.width
27 property string art: player.currentMetaFile === "" ? Qt.resolvedUrl("../images/music-app-cover@30.png") : player.currentMetaArt27 property string art // : player.currentMetaFile === "" ? Qt.resolvedUrl("../images/music-app-cover@30.png") : player.currentMetaArt
28
29 // dark layer
30 Rectangle {
31 anchors.fill: parent
32 color: "black"
33 }
2834
29 // the album art35 // the album art
30 Image {36 Image {
@@ -32,27 +38,19 @@
32 anchors.horizontalCenter: parent.horizontalCenter38 anchors.horizontalCenter: parent.horizontalCenter
33 anchors.verticalCenter: parent.verticalCenter39 anchors.verticalCenter: parent.verticalCenter
34 source: art // this has to be fixed for the default cover art to work - cant find in this dir40 source: art // this has to be fixed for the default cover art to work - cant find in this dir
35 height: Math.max(parent.height, parent.width)41 fillMode: Image.PreserveAspectCrop
42 height: parent.height
36 width: Math.max(parent.height, parent.width)43 width: Math.max(parent.height, parent.width)
37 visible: false44 visible: false
38 onStatusChanged: {
39 if (status === Image.Error) {
40 source = Qt.resolvedUrl("../images/music-app-cover@30.png")
41 }
42 }
43 }45 }
46
44 // the blur47 // the blur
45 FastBlur {48 FastBlur {
46 id: backgroundBlur49 id: backgroundBlur
47 anchors.fill: backgroundImage50 anchors.fill: backgroundImage
48 source: backgroundImage51 source: backgroundImage
49 radius: units.dp(42)52 radius: units.dp(42)
50 }53 opacity: 0.2
51 // transparent white layer
52 Rectangle {
53 anchors.fill: parent
54 color: "white"
55 opacity: 0.7
56 }54 }
57 onArtChanged: {55 onArtChanged: {
58 // TODO: This is a work around for LP:1261078 and LP:1306845. Ideally,56 // TODO: This is a work around for LP:1261078 and LP:1306845. Ideally,
5957
=== added file 'common/BlurredHeader.qml'
--- common/BlurredHeader.qml 1970-01-01 00:00:00 +0000
+++ common/BlurredHeader.qml 2014-10-21 15:31:33 +0000
@@ -0,0 +1,69 @@
1/*
2 * Copyright (C) 2014
3 * Andrew Hayzen <ahayzen@gmail.com>
4 * Victor Thompson <victor.thompson@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.3
20import Ubuntu.Components 1.1
21import Ubuntu.Components.ListItems 1.0 as ListItem
22
23ListItem.Standard {
24 id: albumInfo
25 width: parent.width
26
27 property alias bottomColumn: bottomColumnLoader.sourceComponent
28 property alias coverSources: coversImage.covers
29 property alias rightColumn: rightColumnLoader.sourceComponent
30
31 BlurredBackground {
32 id: blurredBackground
33 height: parent.height
34 art: coversImage.firstSource
35 }
36
37 CoverGrid {
38 id: coversImage
39 anchors {
40 bottomMargin: units.gu(2)
41 left: parent.left
42 leftMargin: units.gu(2)
43 rightMargin: units.gu(2)
44 top: parent.top
45 topMargin: units.gu(3)
46 }
47 size: units.gu(18)
48 }
49
50 Loader {
51 id: rightColumnLoader
52 anchors {
53 bottom: coversImage.bottom
54 left: coversImage.right
55 leftMargin: units.gu(2)
56 }
57 }
58
59 Loader {
60 id: bottomColumnLoader
61 anchors {
62 left: coversImage.left
63 right: parent.right
64 rightMargin: units.gu(2)
65 top: coversImage.bottom
66 topMargin: units.gu(1)
67 }
68 }
69}
070
=== added file 'common/Card.qml'
--- common/Card.qml 1970-01-01 00:00:00 +0000
+++ common/Card.qml 2014-10-21 15:31:33 +0000
@@ -0,0 +1,151 @@
1/*
2 * Copyright (C) 2014
3 * Andrew Hayzen <ahayzen@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18import QtQuick 2.3
19import Ubuntu.Components 1.1
20
21
22Rectangle {
23 id: card
24 color: "transparent"
25 height: cardColumn.childrenRect.height + 2 * bg.anchors.margins
26
27 property alias coverSources: coverGrid.covers
28 property alias primaryText: primaryLabel.text
29 property alias secondaryText: secondaryLabel.text
30 property alias secondaryTextVisible: secondaryLabel.visible
31
32 signal clicked(var mouse)
33 signal pressAndHold(var mouse)
34
35 /* Animations */
36 Behavior on height {
37 UbuntuNumberAnimation {
38
39 }
40 }
41
42 Behavior on width {
43 UbuntuNumberAnimation {
44
45 }
46 }
47
48 Behavior on x {
49 UbuntuNumberAnimation {
50
51 }
52 }
53
54 Behavior on y {
55 UbuntuNumberAnimation {
56
57 }
58 }
59
60 /* Background for card */
61 Rectangle {
62 id: bg
63 anchors {
64 fill: parent
65 margins: units.gu(1)
66 }
67 color: "#2c2c34"
68 }
69
70 /* Column containing image and labels */
71 Column {
72 id: cardColumn
73 anchors {
74 fill: bg
75 }
76 spacing: units.gu(0.5)
77
78 CoverGrid {
79 id: coverGrid
80 size: parent.width
81 }
82
83 Rectangle {
84 color: "transparent"
85 height: units.gu(1)
86 width: units.gu(1)
87 }
88
89 Label {
90 id: primaryLabel
91 anchors {
92 left: parent.left
93 leftMargin: units.gu(1)
94 right: parent.right
95 rightMargin: units.gu(1)
96 }
97 color: "#FFF"
98 elide: Text.ElideRight
99 fontSize: "small"
100 opacity: 1.0
101 wrapMode: Text.WordWrap
102 }
103
104 Label {
105 id: secondaryLabel
106 anchors {
107 left: parent.left
108 leftMargin: units.gu(1)
109 right: parent.right
110 rightMargin: units.gu(1)
111 }
112 color: "#FFF"
113 elide: Text.ElideRight
114 fontSize: "small"
115 opacity: 0.4
116 wrapMode: Text.WordWrap
117 }
118
119 Rectangle {
120 color: "transparent"
121 height: units.gu(1.5)
122 width: units.gu(1)
123 }
124 }
125
126 /* Overlay for when card is pressed */
127 Rectangle {
128 id: overlay
129 anchors {
130 fill: bg
131 }
132 color: "#000"
133 opacity: 0
134
135 Behavior on opacity {
136 UbuntuNumberAnimation {
137
138 }
139 }
140 }
141
142 /* Capture mouse events */
143 MouseArea {
144 anchors {
145 fill: parent
146 }
147 onClicked: card.clicked(mouse)
148 onPressAndHold: card.pressAndHold(mouse)
149 onPressedChanged: overlay.opacity = pressed ? 0.3 : 0
150 }
151}
0152
=== added file 'common/CardView.qml'
--- common/CardView.qml 1970-01-01 00:00:00 +0000
+++ common/CardView.qml 2014-10-21 15:31:33 +0000
@@ -0,0 +1,61 @@
1/*
2 * Copyright (C) 2014
3 * Andrew Hayzen <ahayzen@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18import QtQuick 2.3
19import Ubuntu.Components 1.1
20
21
22Flickable {
23 anchors {
24 fill: parent
25 }
26
27 // dont use flow.contentHeight as it is inaccurate due to height of labels
28 // changing as they load
29 contentHeight: headerLoader.childrenRect.height + flowContainer.height
30 contentWidth: width
31
32 property alias count: flow.count
33 property alias delegate: flow.delegate
34 property alias header: headerLoader.sourceComponent
35 property alias model: flow.model
36 property real itemWidth: units.gu(15)
37
38 Loader {
39 id: headerLoader
40 width: parent.width
41 }
42
43 Item {
44 id: flowContainer
45 anchors {
46 top: headerLoader.bottom
47 }
48 height: flow.childrenRect.height + flow.anchors.margins * 2
49 width: parent.width
50
51 ColumnFlow {
52 id: flow
53 anchors {
54 fill: parent
55 margins: units.gu(1)
56 }
57
58 columns: parseInt(width / itemWidth)
59 }
60 }
61}
062
=== added file 'common/ColumnFlow.qml'
--- common/ColumnFlow.qml 1970-01-01 00:00:00 +0000
+++ common/ColumnFlow.qml 2014-10-21 15:31:33 +0000
@@ -0,0 +1,160 @@
1/*
2 * Copyright (C) 2014
3 * Andrew Hayzen <ahayzen@gmail.com>
4 * Michael Spencer <sonrisesoftware@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Upstream location:
19 * https://github.com/iBeliever/ubuntu-ui-extras/blob/master/ColumnFlow.qml
20 */
21
22import QtQuick 2.3
23
24
25Item {
26 id: columnFlow
27 property int columns: 1
28 property bool repeaterCompleted: false
29 property alias count: repeater.count
30 property alias model: repeater.model
31 property alias delegate: repeater.delegate
32 property int contentHeight: 0
33
34 onColumnsChanged: reEvalColumns()
35 onModelChanged: reEvalColumns()
36 onWidthChanged: updateWidths()
37
38 function updateWidths() {
39 if (repeaterCompleted) {
40 var count = 0
41
42 //add the first <column> elements
43 for (var i = 0; count < columns && i < columnFlow.children.length; i++) {
44 //print(i, count)
45 if (!columnFlow.children[i] || String(columnFlow.children[i]).indexOf("QQuickRepeater") == 0)
46 //|| !columnFlow.children[i].visible) // CUSTOM - view is invisible at start
47 continue
48
49 columnFlow.children[i].width = width / columns
50
51 count++
52 }
53 }
54 }
55
56 function reEvalColumns() {
57 if (columnFlow.repeaterCompleted === false)
58 return
59
60 if (columns === 0) {
61 contentHeight = 0
62 return
63 }
64
65 var i, j
66 var columnHeights = new Array(columns);
67 var lastItem = new Array(columns)
68 var lastI = -1
69 var count = 0
70
71 //add the first <column> elements
72 for (i = 0; count < columns && i < columnFlow.children.length; i++) {
73 // CUSTOM - ignore if has just been removed
74 if (i === repeater.removeHintIndex && columnFlow.children[i] === repeater.removeHintItem) {
75 continue
76 }
77
78 if (!columnFlow.children[i] || String(columnFlow.children[i]).indexOf("QQuickRepeater") == 0)
79 //|| !columnFlow.children[i].visible) // CUSTOM - view is invisible at start
80 continue
81
82 lastItem[count] = i
83
84 columnHeights[count] = columnFlow.children[i].height
85 columnFlow.children[i].anchors.top = columnFlow.top
86 columnFlow.children[i].anchors.left = (lastI === -1 ? columnFlow.left : columnFlow.children[lastI].right)
87 columnFlow.children[i].anchors.right = undefined
88 columnFlow.children[i].width = columnFlow.width / columns
89
90 lastI = i
91 count++
92 }
93
94 //add the other elements
95 for (i = i; i < columnFlow.children.length; i++) {
96 var highestHeight = Number.MAX_VALUE
97 var newColumn = 0
98
99 // CUSTOM - ignore if has just been removed
100 if (i === repeater.removeHintIndex && columnFlow.children[i] === repeater.removeHintItem) {
101 continue
102 }
103
104 if (!columnFlow.children[i] || String(columnFlow.children[i]).indexOf("QQuickRepeater") == 0)
105 //|| !columnFlow.children[i].visible) // CUSTOM - view is invisible at start
106 continue
107
108 // find the shortest column
109 for (j = 0; j < columns; j++) {
110 if (columnHeights[j] !== null && columnHeights[j] < highestHeight) {
111 newColumn = j
112 highestHeight = columnHeights[j]
113 }
114 }
115
116 // add the element to the shortest column
117 columnFlow.children[i].anchors.top = columnFlow.children[lastItem[newColumn]].bottom
118 columnFlow.children[i].anchors.left = columnFlow.children[lastItem[newColumn]].left
119 columnFlow.children[i].anchors.right = columnFlow.children[lastItem[newColumn]].right
120
121 lastItem[newColumn] = i
122 columnHeights[newColumn] += columnFlow.children[i].height
123 }
124
125 var cHeight = 0
126
127 for (i = 0; i < columnHeights.length; i++) {
128 if (columnHeights[i])
129 cHeight = Math.max(cHeight, columnHeights[i])
130 }
131
132 contentHeight = cHeight
133 updateWidths()
134 }
135
136 Repeater {
137 id: repeater
138 model: columnFlow.model
139 Component.onCompleted: {
140 columnFlow.repeaterCompleted = true
141 columnFlow.reEvalColumns()
142 }
143
144 // Provide a hint of the removed item
145 property int removeHintIndex: -1 // CUSTOM
146 property var removeHintItem // CUSTOM
147
148 onItemAdded: columnFlow.reEvalColumns() // CUSTOM - ms2 models are live
149 onItemRemoved: {
150 removeHintIndex = index
151 removeHintItem = item
152
153 columnFlow.reEvalColumns() // CUSTOM - ms2 models are live
154
155 // Set back to null to allow freeing of memory
156 removeHintIndex = -1
157 removeHintItem = undefined
158 }
159 }
160}
0161
=== added file 'common/CoverGrid.qml'
--- common/CoverGrid.qml 1970-01-01 00:00:00 +0000
+++ common/CoverGrid.qml 2014-10-21 15:31:33 +0000
@@ -0,0 +1,78 @@
1/*
2 * Copyright (C) 2013, 2014
3 * Andrew Hayzen <ahayzen@gmail.com>
4 * Nekhelesh Ramananthan <krnekhelesh@gmail.com>
5 * Victor Thompson <victor.thompson@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 3.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20import QtQuick 2.3
21import Ubuntu.Components 1.1
22
23Rectangle {
24 id: coverGrid
25 color: "transparent"
26 height: size
27 width: size
28
29 // Property (array) to store the cover images
30 property var covers
31
32 // Property to set the size of the cover image
33 property int size
34
35 property string firstSource
36
37 onCoversChanged: {
38 if (covers !== undefined) {
39 while (covers.length > 4) { // remove any covers after 4
40 covers.pop()
41 }
42 }
43 }
44
45 // Flow of the cover arts in either 1, 1x1, 2x1, 2x2
46 Flow {
47 id: imageRow
48 anchors {
49 fill: parent
50 }
51
52 Repeater {
53 id: repeat
54 model: coverGrid.covers.length === 0 ? 1 : coverGrid.covers.length
55 delegate: Image {
56 fillMode: Image.PreserveAspectCrop
57 height: coverGrid.size / (coverGrid.covers.length > 1 ? 2 : 1)
58 width: coverGrid.size / (coverGrid.covers.length > 2 && !(coverGrid.covers.length === 3 && index === 2) ? 2 : 1)
59 source: coverGrid.covers.length !== 0 && coverGrid.covers[index] !== "" && coverGrid.covers[index] !== undefined
60 ? (coverGrid.covers[index].art !== undefined
61 ? coverGrid.covers[index].art
62 : "image://albumart/artist=" + coverGrid.covers[index].author + "&album=" + coverGrid.covers[index].album)
63 : undefined
64 sourceSize.height: height
65 sourceSize.width: width
66
67 onStatusChanged: {
68 if (status === Image.Error) {
69 source = Qt.resolvedUrl("../images/music-app-cover@30.png")
70 } else if (status === Image.Ready && index === 0) {
71 firstSource = source
72 }
73 }
74 }
75 }
76 }
77}
78
079
=== modified file 'common/CoverRow.qml'
--- common/CoverRow.qml 2014-09-20 15:41:33 +0000
+++ common/CoverRow.qml 2014-10-21 15:31:33 +0000
@@ -63,6 +63,8 @@
63 ? coverRow.covers[index].art63 ? coverRow.covers[index].art
64 : "image://albumart/artist=" + coverRow.covers[index].author + "&album=" + coverRow.covers[index].album)64 : "image://albumart/artist=" + coverRow.covers[index].author + "&album=" + coverRow.covers[index].album)
65 : Qt.resolvedUrl("../images/music-app-cover@30.png")65 : Qt.resolvedUrl("../images/music-app-cover@30.png")
66 sourceSize.height: height
67 sourceSize.width: width
66 onStatusChanged: {68 onStatusChanged: {
67 if (status === Image.Error) {69 if (status === Image.Error) {
68 source = Qt.resolvedUrl("../images/music-app-cover@30.png")70 source = Qt.resolvedUrl("../images/music-app-cover@30.png")
6971
=== removed file 'common/ListItemActions/DeletePlaylist.qml'
--- common/ListItemActions/DeletePlaylist.qml 2014-09-20 10:50:45 +0000
+++ common/ListItemActions/DeletePlaylist.qml 1970-01-01 00:00:00 +0000
@@ -1,29 +0,0 @@
1/*
2 * Copyright (C) 2014 Andrew Hayzen <ahayzen@gmail.com>
3 * Daniel Holm <d.holmen@gmail.com>
4 * Victor Thompson <victor.thompson@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.3
20import Ubuntu.Components 1.1
21import Ubuntu.Components.Popups 1.0
22
23Action {
24 iconName: "delete"
25 // TRANSLATORS: this refers to deleting a playlist
26 text: i18n.tr("Delete")
27
28 property bool primed: false
29}
300
=== removed file 'common/ListItemActions/EditPlaylist.qml'
--- common/ListItemActions/EditPlaylist.qml 2014-09-20 10:50:45 +0000
+++ common/ListItemActions/EditPlaylist.qml 1970-01-01 00:00:00 +0000
@@ -1,35 +0,0 @@
1/*
2 * Copyright (C) 2014 Andrew Hayzen <ahayzen@gmail.com>
3 * Daniel Holm <d.holmen@gmail.com>
4 * Victor Thompson <victor.thompson@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.3
20import Ubuntu.Components 1.1
21import Ubuntu.Components.Popups 1.0
22
23Action {
24 iconName: "edit"
25 // TRANSLATORS: this refers to editing a playlist
26 text: i18n.tr("Edit")
27
28 property bool primed: false
29
30 onTriggered: {
31 customdebug("Edit playlist")
32 oldPlaylistName = model.name
33 PopupUtils.open(editPlaylistDialog, mainView)
34 }
35}
360
=== modified file 'common/MusicPage.qml'
--- common/MusicPage.qml 2014-08-20 17:35:52 +0000
+++ common/MusicPage.qml 2014-10-21 15:31:33 +0000
@@ -23,6 +23,10 @@
23// generic page for music, could be useful for bottomedge implementation23// generic page for music, could be useful for bottomedge implementation
24Page {24Page {
25 id: thisPage25 id: thisPage
26 anchors {
27 bottomMargin: musicToolbar.visible ? musicToolbar.currentHeight : 0
28 fill: parent
29 }
2630
27 onVisibleChanged: {31 onVisibleChanged: {
28 if (visible) {32 if (visible) {
2933
=== modified file 'common/MusicRow.qml'
--- common/MusicRow.qml 2014-09-20 10:50:45 +0000
+++ common/MusicRow.qml 2014-10-21 15:31:33 +0000
@@ -24,35 +24,54 @@
24Row {24Row {
25 anchors {25 anchors {
26 left: parent.left26 left: parent.left
27 leftMargin: units.gu(1)27 leftMargin: units.gu(2)
28 right: parent.right28 right: parent.right
29 rightMargin: units.gu(1)29 rightMargin: units.gu(2)
30 }30 }
3131
32 property alias covers: coverRow.covers32 property alias covers: coverRow.covers
33 property bool showCovers: true
34 property bool isSquare: false
33 property alias pressed: coverRow.pressed35 property alias pressed: coverRow.pressed
34 property alias column: columnComponent.sourceComponent36 property alias column: columnComponent.sourceComponent
37 property real coverSize: styleMusic.common.albumSize
3538
36 spacing: units.gu(1)39 spacing: units.gu(1)
3740
38 CoverRow {41 CoverRow {
39 id: coverRow42 id: coverRow
43 visible: showCovers && !isSquare
40 anchors {44 anchors {
41 top: parent.top45 top: parent.top
42 topMargin: units.gu(1)46 topMargin: units.gu(1)
43 }47 }
44 count: covers.length48 count: covers.length
45 covers: []49 covers: []
46 size: styleMusic.common.albumSize50 size: coverSize
51 }
52
53 CoverGrid {
54 id: coverSquare
55 anchors {
56 verticalCenter: parent.verticalCenter
57 topMargin: units.gu(0.5)
58 bottomMargin: units.gu(0.5)
59 leftMargin: units.gu(2)
60 }
61 covers: coverRow.covers
62 size: coverSize
63 visible: showCovers && isSquare
47 }64 }
4865
49 Loader {66 Loader {
50 id: columnComponent67 id: columnComponent
51 anchors {68 anchors {
52 top: parent.top69 top: parent.top
53 topMargin: units.gu(2)70 topMargin: units.gu(1)
54 }71 }
55 width: parent.width - coverRow.width - parent.spacing72 width: !showCovers ? parent.width - parent.spacing
73 : (isSquare ? parent.width - coverSquare.width - parent.spacing
74 : parent.width - coverRow.width - parent.spacing)
5675
57 onSourceComponentChanged: {76 onSourceComponentChanged: {
58 for (var i=0; i < item.children.length; i++) {77 for (var i=0; i < item.children.length; i++) {
5978
=== modified file 'common/SongsPage.qml'
--- common/SongsPage.qml 2014-09-20 15:41:33 +0000
+++ common/SongsPage.qml 2014-10-21 15:31:33 +0000
@@ -20,6 +20,7 @@
20import QtQuick 2.320import QtQuick 2.3
21import Ubuntu.Components 1.121import Ubuntu.Components 1.1
22import Ubuntu.Components.ListItems 1.0 as ListItem22import Ubuntu.Components.ListItems 1.0 as ListItem
23import Ubuntu.Components.Popups 1.0
23import Ubuntu.MediaScanner 0.124import Ubuntu.MediaScanner 0.1
24import Ubuntu.Thumbnailer 0.125import Ubuntu.Thumbnailer 0.1
25import QtQuick.LocalStorage 2.026import QtQuick.LocalStorage 2.0
@@ -29,7 +30,6 @@
2930
30MusicPage {31MusicPage {
31 id: songStackPage32 id: songStackPage
32 anchors.bottomMargin: units.gu(.5)
33 objectName: "songsPage"33 objectName: "songsPage"
34 visible: false34 visible: false
3535
@@ -44,6 +44,47 @@
44 property alias album: songsModel.album44 property alias album: songsModel.album
45 property alias genre: songsModel.genre45 property alias genre: songsModel.genre
4646
47 state: songStackPage.line1 === i18n.tr("Playlist") ? "playlist" : "album"
48 states: [
49 PageHeadState {
50 id: albumState
51 name: "album"
52 PropertyChanges {
53 target: songStackPage.head
54 backAction: albumState.backAction
55 actions: albumState.actions
56 }
57 },
58 PageHeadState {
59 id: playlistState
60
61 name: "playlist"
62 actions: [
63 Action {
64 objectName: "editPlaylist"
65 iconName: "edit"
66 onTriggered: {
67 var dialog = PopupUtils.open(editPlaylistDialog, mainView)
68 dialog.oldPlaylistName = line2
69 }
70 },
71 Action {
72 objectName: "deletePlaylist"
73 iconName: "delete"
74 onTriggered: {
75 var dialog = PopupUtils.open(removePlaylistDialog, mainView)
76 dialog.oldPlaylistName = line2
77 }
78 }
79 ]
80 PropertyChanges {
81 target: songStackPage.head
82 backAction: playlistState.backAction
83 actions: playlistState.actions
84 }
85 }
86 ]
87
47 SongsModel {88 SongsModel {
48 id: songsModel89 id: songsModel
49 store: musicStore90 store: musicStore
@@ -52,160 +93,141 @@
52 ListView {93 ListView {
53 id: albumtrackslist94 id: albumtrackslist
54 anchors {95 anchors {
55 bottomMargin: wideAspect ? musicToolbar.fullHeight : musicToolbar.mouseAreaOffset + musicToolbar.minimizedHeight
56 fill: parent96 fill: parent
57 }97 }
58 delegate: albumTracksDelegate98 delegate: albumTracksDelegate
59 model: isAlbum ? songsModel : albumTracksModel.model99 model: isAlbum ? songsModel : albumTracksModel.model
60 objectName: "songspage-listview"100 objectName: "songspage-listview"
61 width: parent.width101 width: parent.width
62 header: ListItem.Standard {102 header: BlurredHeader {
63 id: albumInfo103 rightColumn: Column {
64 height: units.gu(22)
65
66 CoverRow {
67 id: albumImage
68 anchors {
69 top: parent.top
70 left: parent.left
71 margins: units.gu(1)
72 }
73 count: songStackPage.covers.length
74 size: units.gu(20)
75 covers: songStackPage.covers
76 spacing: units.gu(2)104 spacing: units.gu(2)
77 }105 Button {
78106 id: shuffleRow
79 Label {107 height: units.gu(4)
80 id: albumArtist108 strokeColor: UbuntuColors.green
81 objectName: "songsPageHeaderAlbumArtist"109 width: units.gu(15)
82 wrapMode: Text.NoWrap110 Text {
83 maximumLineCount: 1111 anchors {
84 fontSize: "small"112 centerIn: parent
85 color: styleMusic.common.subtitle113 }
86 anchors.left: albumImage.right114 color: "white"
87 anchors.leftMargin: units.gu(1)115 text: i18n.tr("Shuffle")
88 anchors.top: parent.top116 }
89 anchors.topMargin: units.gu(1.5)117 MouseArea {
90 anchors.right: parent.right118 anchors.fill: parent
91 anchors.rightMargin: units.gu(1.5)119 onClicked: {
92 elide: Text.ElideRight120 shuffleModel(albumtrackslist.model) // play track
93 text: line1121
94 }122 if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) {
95 Label {123 Library.addRecent(songStackPage.line2, songStackPage.line1, songStackPage.covers[0], songStackPage.line2, "album")
96 id: albumLabel124 recentModel.filterRecent()
97 wrapMode: Text.NoWrap125 } else if (songStackPage.line1 === i18n.tr("Playlist")) {
98 maximumLineCount: 2126 Library.addRecent(songStackPage.line2, "Playlist", songStackPage.covers[0], songStackPage.line2, "playlist")
99 fontSize: "medium"127 recentModel.filterRecent()
100 color: styleMusic.common.music128 }
101 anchors.left: albumImage.right129 }
102 anchors.leftMargin: units.gu(1)130 }
103 anchors.top: albumArtist.bottom131 }
104 anchors.topMargin: units.gu(0.8)132 Button {
105 anchors.right: parent.right133 id: queueAllRow
106 anchors.rightMargin: units.gu(1.5)134 height: units.gu(4)
107 elide: Text.ElideRight135 strokeColor: UbuntuColors.green
108 text: line2136 width: units.gu(15)
109 }137 Text {
110 Label {138 anchors {
111 id: albumYear139 centerIn: parent
112 wrapMode: Text.NoWrap140 }
113 maximumLineCount: 1141 color: "white"
114 fontSize: "x-small"142 text: i18n.tr("Queue all")
115 color: styleMusic.common.subtitle143 }
116 anchors.left: albumImage.right144 MouseArea {
117 anchors.leftMargin: units.gu(1)145 anchors.fill: parent
118 anchors.top: albumLabel.bottom146 onClicked: addQueueFromModel(albumtrackslist.model)
119 anchors.topMargin: units.gu(2)147 }
120 anchors.right: parent.right148 }
121 anchors.rightMargin: units.gu(1.5)149 Button {
122 elide: Text.ElideRight150 id: playRow
123 text: isAlbum && line1 !== i18n.tr("Genre") ? year + " | " + i18n.tr("%1 song", "%1 songs", albumtrackslist.count).arg(albumtrackslist.count)151 color: UbuntuColors.green
124 : i18n.tr("%1 song", "%1 songs", albumtrackslist.count).arg(albumtrackslist.count)152 height: units.gu(4)
125
126 }
127
128 // Play
129 Rectangle {
130 id: playRow
131 anchors.top: albumYear.bottom
132 anchors.topMargin: units.gu(1)
133 anchors.left: albumImage.right
134 anchors.leftMargin: units.gu(1)
135 color: "transparent"
136 height: units.gu(4)
137 width: units.gu(15)
138 Icon {
139 id: playTrack
140 objectName: "songspage-playtrack"
141 anchors.verticalCenter: parent.verticalCenter
142 name: "media-playback-start"
143 height: styleMusic.common.expandedItem
144 width: styleMusic.common.expandedItem
145 }
146 Label {
147 anchors.left: playTrack.right
148 anchors.leftMargin: units.gu(0.5)
149 anchors.verticalCenter: parent.verticalCenter
150 fontSize: "small"
151 color: styleMusic.common.subtitle
152 width: parent.width - playTrack.width - units.gu(1)
153 text: i18n.tr("Play all")153 text: i18n.tr("Play all")
154 wrapMode: Text.WordWrap154 width: units.gu(15)
155 maximumLineCount: 3155 MouseArea {
156 }156 anchors.fill: parent
157 MouseArea {157 onClicked: {
158 anchors.fill: parent158 trackClicked(albumtrackslist.model, 0) // play track
159 onClicked: {
160 trackClicked(albumtrackslist.model, 0) // play track
161159
162 if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) {160 if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) {
163 Library.addRecent(songStackPage.line2, songStackPage.line1, songStackPage.covers[0], songStackPage.line2, "album")161 Library.addRecent(songStackPage.line2, songStackPage.line1, songStackPage.covers[0], songStackPage.line2, "album")
164 mainView.hasRecent = true162 recentModel.filterRecent()
165 recentModel.filterRecent()163 } else if (songStackPage.line1 === i18n.tr("Playlist")) {
166 } else if (songStackPage.line1 === i18n.tr("Playlist")) {164 Library.addRecent(songStackPage.line2, "Playlist", songStackPage.covers[0], songStackPage.line2, "playlist")
167 Library.addRecent(songStackPage.line2, "Playlist", songStackPage.covers[0], songStackPage.line2, "playlist")165 recentModel.filterRecent()
168 mainView.hasRecent = true166 }
169 recentModel.filterRecent()
170 }167 }
171 }168 }
172 }169 }
173 }170 }
174171 coverSources: songStackPage.covers
175 // Queue172 height: songStackPage.line1 !== i18n.tr("Playlist") &&
176 Rectangle {173 songStackPage.line1 !== i18n.tr("Genre") ?
177 id: queueAllRow174 units.gu(33) : units.gu(30)
178 anchors.top: playRow.bottom175 bottomColumn: Column {
179 anchors.topMargin: units.gu(1)176 Label {
180 anchors.left: albumImage.right177 id: albumLabel
181 anchors.leftMargin: units.gu(1)178 anchors {
182 color: "transparent"179 left: parent.left
183 height: units.gu(4)180 right: parent.right
184 width: units.gu(15)181 }
185 Icon {182 color: styleMusic.common.music
186 id: queueAll183 elide: Text.ElideRight
187 objectName: "songspage-queue-all"184 fontSize: "x-large"
188 anchors.verticalCenter: parent.verticalCenter185 maximumLineCount: 1
189 name: "add"186 text: line2
190 height: styleMusic.common.expandedItem187 wrapMode: Text.NoWrap
191 width: styleMusic.common.expandedItem188 }
192 }189
193 Label {190 Item {
194 anchors.left: queueAll.right191 height: units.gu(0.75)
195 anchors.leftMargin: units.gu(0.5)192 width: parent.width
196 anchors.verticalCenter: parent.verticalCenter193 visible: albumArtist.visible
197 fontSize: "small"194 }
198 color: styleMusic.common.subtitle195
199 width: parent.width - queueAll.width - units.gu(1)196 Label {
200 text: i18n.tr("Add to queue")197 id: albumArtist
201 wrapMode: Text.WordWrap198 anchors {
202 maximumLineCount: 3199 left: parent.left
203 }200 right: parent.right
204 MouseArea {201 }
205 anchors.fill: parent202 color: styleMusic.common.subtitle
206 onClicked: {203 elide: Text.ElideRight
207 addQueueFromModel(albumtrackslist.model)204 fontSize: "small"
208 }205 maximumLineCount: 1
206 objectName: "songsPageHeaderAlbumArtist"
207 text: line1
208 visible: text !== i18n.tr("Playlist") &&
209 text !== i18n.tr("Genre")
210 wrapMode: Text.NoWrap
211 }
212
213 Item {
214 height: units.gu(1)
215 width: parent.width
216 }
217
218 Label {
219 id: albumYear
220 anchors {
221 left: parent.left
222 right: parent.right
223 }
224 color: styleMusic.common.subtitle
225 elide: Text.ElideRight
226 fontSize: "small"
227 maximumLineCount: 1
228 text: isAlbum && line1 !== i18n.tr("Genre") ? year + " | " + i18n.tr("%1 song", "%1 songs", albumtrackslist.count).arg(albumtrackslist.count)
229 : i18n.tr("%1 song", "%1 songs", albumtrackslist.count).arg(albumtrackslist.count)
230 wrapMode: Text.NoWrap
209 }231 }
210 }232 }
211 }233 }
@@ -219,7 +241,8 @@
219 objectName: "songsPageListItem" + index241 objectName: "songsPageListItem" + index
220 iconFrame: false242 iconFrame: false
221 progression: false243 progression: false
222 height: styleMusic.common.itemHeight244 showDivider: false
245 height: units.gu(6)
223246
224 leftSideAction: songStackPage.line1 === i18n.tr("Playlist")247 leftSideAction: songStackPage.line1 === i18n.tr("Playlist")
225 ? playlistRemoveAction.item : null248 ? playlistRemoveAction.item : null
@@ -239,11 +262,9 @@
239262
240 if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) {263 if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) {
241 Library.addRecent(songStackPage.line2, songStackPage.line1, model.art, songStackPage.line2, "album")264 Library.addRecent(songStackPage.line2, songStackPage.line1, model.art, songStackPage.line2, "album")
242 mainView.hasRecent = true
243 recentModel.filterRecent()265 recentModel.filterRecent()
244 } else if (songStackPage.line1 === i18n.tr("Playlist")) {266 } else if (songStackPage.line1 === i18n.tr("Playlist")) {
245 Library.addRecent(songStackPage.line2, "Playlist", songStackPage.covers[0], songStackPage.line2, "playlist")267 Library.addRecent(songStackPage.line2, "Playlist", songStackPage.covers[0], songStackPage.line2, "playlist")
246 mainView.hasRecent = true
247 recentModel.filterRecent()268 recentModel.filterRecent()
248 }269 }
249 }270 }
@@ -272,30 +293,23 @@
272293
273 MusicRow {294 MusicRow {
274 id: musicRow295 id: musicRow
275 covers: model.art !== undefined ? [{art: model.art}] : [{author: model.author, album: model.album}]296 covers: []
297 showCovers: false
276 column: Column {298 column: Column {
277 spacing: units.gu(1)299 Label {
300 id: trackTitle
301 color: styleMusic.common.music
302 fontSize: "small"
303 objectName: "songspage-tracktitle"
304 text: model.title
305 }
306
278 Label {307 Label {
279 id: trackArtist308 id: trackArtist
280 color: styleMusic.common.subtitle309 color: styleMusic.common.subtitle
281 fontSize: "x-small"310 fontSize: "x-small"
282 text: model.author311 text: model.author
283 }312 }
284
285 Label {
286 id: trackTitle
287 color: styleMusic.common.subtitle
288 fontSize: "medium"
289 objectName: "songspage-tracktitle"
290 text: model.title
291 }
292
293 Label {
294 id: trackAlbum
295 color: styleMusic.common.subtitle
296 fontSize: "xx-small"
297 text: model.album
298 }
299 }313 }
300 }314 }
301315
@@ -309,4 +323,103 @@
309 }323 }
310 }324 }
311 }325 }
326
327 // Edit name of playlist dialog
328 Component {
329 id: editPlaylistDialog
330 Dialog {
331 id: dialogEditPlaylist
332 // TRANSLATORS: this is a title of a dialog with a prompt to rename a playlist
333 title: i18n.tr("Change name")
334 text: i18n.tr("Enter the new name of the playlist.")
335
336 property alias oldPlaylistName: playlistName.placeholderText
337
338 TextField {
339 id: playlistName
340 inputMethodHints: Qt.ImhNoPredictiveText
341
342 onPlaceholderTextChanged: text = placeholderText
343 }
344 Label {
345 id: editplaylistoutput
346 color: "red"
347 visible: false
348 }
349
350 Button {
351 text: i18n.tr("Change")
352 color: styleMusic.dialog.confirmButtonColor
353 onClicked: {
354 editplaylistoutput.visible = true
355
356 if (playlistName.text.length > 0) { // make sure something is acually inputed
357 console.debug("Debug: User changed name from "+playlistName.placeholderText+" to "+playlistName.text)
358
359 if (Playlists.renamePlaylist(playlistName.placeholderText, playlistName.text) === true) {
360 playlistModel.filterPlaylists()
361
362 if (Library.recentContainsPlaylist(playlistName.placeholderText)) {
363 Library.recentRenamePlaylist(playlistName.placeholderText, playlistName.text)
364 recentModel.filterRecent()
365 }
366
367 PopupUtils.close(dialogEditPlaylist)
368
369 line2 = playlistName.text
370 }
371 else {
372 editplaylistoutput.text = i18n.tr("Playlist already exists")
373 }
374 }
375 else {
376 editplaylistoutput.text = i18n.tr("Please type in a name.")
377 }
378 }
379 }
380 Button {
381 text: i18n.tr("Cancel")
382 color: styleMusic.dialog.cancelButtonColor
383 onClicked: PopupUtils.close(dialogEditPlaylist)
384 }
385 }
386 }
387
388 // Remove playlist dialog
389 Component {
390 id: removePlaylistDialog
391 Dialog {
392 id: dialogRemovePlaylist
393 // TRANSLATORS: this is a title of a dialog with a prompt to delete a playlist
394 title: i18n.tr("Are you sure?")
395 text: i18n.tr("This will delete your playlist.")
396
397 property string oldPlaylistName
398
399 Button {
400 text: i18n.tr("Remove")
401 color: styleMusic.dialog.confirmButtonColor
402 onClicked: {
403 // removing playlist
404 Playlists.removePlaylist(dialogRemovePlaylist.oldPlaylistName)
405
406 playlistModel.filterPlaylists();
407
408 if (Library.recentContainsPlaylist(dialogRemovePlaylist.oldPlaylistName)) {
409 Library.recentRemovePlaylist(dialogRemovePlaylist.oldPlaylistName)
410 recentModel.filterRecent()
411 }
412
413 PopupUtils.close(dialogRemovePlaylist)
414
415 musicToolbar.goBack()
416 }
417 }
418 Button {
419 text: i18n.tr("Cancel")
420 color: styleMusic.dialog.cancelButtonColor
421 onClicked: PopupUtils.close(dialogRemovePlaylist)
422 }
423 }
424 }
312}425}
313426
=== modified file 'music-app.qml'
--- music-app.qml 2014-10-16 22:19:13 +0000
+++ music-app.qml 2014-10-21 15:31:33 +0000
@@ -40,18 +40,13 @@
40 id: mainView40 id: mainView
41 useDeprecatedToolbar: false41 useDeprecatedToolbar: false
4242
43 // Use toolbar color for header43 backgroundColor: "#1e1e23"
44 headerColor: styleMusic.toolbar.fullBackgroundColor44 headerColor: "#1e1e23"
45 backgroundColor: styleMusic.toolbar.fullBackgroundColor
4645
47 // Global keyboard shortcuts46 // Global keyboard shortcuts
48 focus: true47 focus: true
49 Keys.onPressed: {48 Keys.onPressed: {
50 if (event.key === Qt.Key_Alt) {49 if(event.key === Qt.Key_Escape) {
51 // On alt key press show toolbar and start autohide timer
52 musicToolbar.showToolbar();
53 }
54 else if(event.key === Qt.Key_Escape) {
55 musicToolbar.goBack(); // Esc Go back50 musicToolbar.goBack(); // Esc Go back
56 }51 }
57 else if(event.modifiers === Qt.AltModifier) {52 else if(event.modifiers === Qt.AltModifier) {
@@ -94,13 +89,11 @@
94 }89 }
95 break;90 break;
96 case Qt.Key_J: // Ctrl+J Jump to playing song91 case Qt.Key_J: // Ctrl+J Jump to playing song
97 nowPlaying.visible = true;92 tabs.pushNowPlaying()
98 nowPlaying.positionAt(player.currentIndex);93 nowPlaying.isListView = true;
99 musicToolbar.showToolbar();
100 break;94 break;
101 case Qt.Key_N: // Ctrl+N Show now playing95 case Qt.Key_N: // Ctrl+N Show now playing
102 nowPlaying.visible = true;96 tabs.pushNowPlaying()
103 musicToolbar.showToolbar();
104 break;97 break;
105 case Qt.Key_P: // Ctrl+P Toggle playing state98 case Qt.Key_P: // Ctrl+P Toggle playing state
106 player.toggle();99 player.toggle();
@@ -218,7 +211,6 @@
218211
219 // Add album to recent list212 // Add album to recent list
220 Library.addRecent(songsAlbumArtistModel.album, songsAlbumArtistModel.artist, songsAlbumArtistModel.art, songsAlbumArtistModel.album, "album")213 Library.addRecent(songsAlbumArtistModel.album, songsAlbumArtistModel.artist, songsAlbumArtistModel.art, songsAlbumArtistModel.album, "album")
221 mainView.hasRecent = true
222 recentModel.filterRecent()214 recentModel.filterRecent()
223 }215 }
224216
@@ -583,7 +575,9 @@
583 // TODO: Switch tabs back and forth to get the background color in the575 // TODO: Switch tabs back and forth to get the background color in the
584 // header to work properly.576 // header to work properly.
585 tabs.selectedTabIndex = 1577 tabs.selectedTabIndex = 1
586 tabs.selectedTabIndex = 0578
579 // goto Recent if there are items otherwise go to Albums
580 tabs.selectedTabIndex = Library.isRecentEmpty() ? 2 : 0
587581
588 // Run post load582 // Run post load
589 tabs.ensurePopulated(tabs.selectedTab);583 tabs.ensurePopulated(tabs.selectedTab);
@@ -591,28 +585,20 @@
591 if (args.values.url) {585 if (args.values.url) {
592 uriHandler.process(args.values.url, true);586 uriHandler.process(args.values.url, true);
593 }587 }
594
595 // Show toolbar and start timer if there is music
596 if (!emptyPage.noMusic) {
597 musicToolbar.showToolbar();
598 musicToolbar.startAutohideTimer();
599 }
600 }588 }
601589
602 // VARIABLES590 // VARIABLES
603 property string musicName: i18n.tr("Music")591 property string musicName: i18n.tr("Music")
604 property string appVersion: '1.2'592 property string appVersion: '1.2'
605 property bool hasRecent: !Library.isRecentEmpty()
606 property bool scrobble: false593 property bool scrobble: false
607 property string lastfmusername594 property string lastfmusername
608 property string lastfmpassword595 property string lastfmpassword
609 property string timestamp // used to scrobble596 property string timestamp // used to scrobble
610 property var chosenElement: null597 property var chosenElement: null
611 property bool toolbarShown: musicToolbar.shown598 property bool toolbarShown: musicToolbar.visible
612 property bool selectedAlbum: false599 property bool selectedAlbum: false
613600
614 signal listItemSwiping(int i)601 signal listItemSwiping(int i)
615 signal onToolbarShownChanged(bool shown, var currentPage, var currentTab)
616602
617 property bool wideAspect: width >= units.gu(70) && loadedUI603 property bool wideAspect: width >= units.gu(70) && loadedUI
618 property bool loadedUI: false // property to detect if the UI has finished604 property bool loadedUI: false // property to detect if the UI has finished
@@ -693,9 +679,6 @@
693679
694 // Show the Now Playing page and make sure the track is visible680 // Show the Now Playing page and make sure the track is visible
695 tabs.pushNowPlaying();681 tabs.pushNowPlaying();
696 nowPlaying.ensureVisibleIndex = index;
697
698 musicToolbar.showToolbar();
699 }682 }
700 else {683 else {
701 player.source = file;684 player.source = file;
@@ -711,10 +694,9 @@
711 }694 }
712695
713 // Show the Now Playing page and make sure the track is visible696 // Show the Now Playing page and make sure the track is visible
714 tabs.pushNowPlaying();697 if (!nowPlaying.isListView) {
715 nowPlaying.ensureVisibleIndex = index;698 tabs.pushNowPlaying();
716699 }
717 musicToolbar.showToolbar();
718 }700 }
719701
720 function playRandomSong(shuffle)702 function playRandomSong(shuffle)
@@ -730,6 +712,17 @@
730 trackClicked(allSongsModel, index, true)712 trackClicked(allSongsModel, index, true)
731 }713 }
732714
715 function shuffleModel(model)
716 {
717 var now = new Date();
718 var seed = now.getSeconds();
719 var index = Math.floor(model.count * Math.random(seed));
720
721 player.shuffle = true;
722
723 trackClicked(model, index, true)
724 }
725
733 // Load mediascanner store726 // Load mediascanner store
734 MediaStore {727 MediaStore {
735 id: musicStore728 id: musicStore
@@ -881,10 +874,6 @@
881 id: searchSheet874 id: searchSheet
882 }875 }
883876
884 // Blurred background
885 BlurredBackground {
886 }
887
888 // Popover for tracks, queue and add to playlist, for example877 // Popover for tracks, queue and add to playlist, for example
889 Component {878 Component {
890 id: trackPopoverComponent879 id: trackPopoverComponent
@@ -987,6 +976,7 @@
987976
988 MusicToolbar {977 MusicToolbar {
989 id: musicToolbar978 id: musicToolbar
979 visible: nowPlaying.isListView || !nowPlaying.visible
990 objectName: "musicToolbarObject"980 objectName: "musicToolbarObject"
991 z: 200 // put on top of everything else981 z: 200 // put on top of everything else
992 }982 }
@@ -997,7 +987,6 @@
997 Tabs {987 Tabs {
998 id: tabs988 id: tabs
999 anchors {989 anchors {
1000 bottomMargin: wideAspect ? musicToolbar.fullHeight : undefined
1001 fill: parent990 fill: parent
1002 }991 }
1003992
@@ -1124,6 +1113,8 @@
1124 if (mainPageStack.currentPage !== nowPlaying) {1113 if (mainPageStack.currentPage !== nowPlaying) {
1125 mainPageStack.push(nowPlaying);1114 mainPageStack.push(nowPlaying);
1126 }1115 }
1116
1117 nowPlaying.isListView = false; // ensure full view
1127 }1118 }
11281119
1129 Component.onCompleted: musicToolbar.currentTab = selectedTab1120 Component.onCompleted: musicToolbar.currentTab = selectedTab
11301121
=== added file 'po/ca@valencia.po'
--- po/ca@valencia.po 1970-01-01 00:00:00 +0000
+++ po/ca@valencia.po 2014-10-21 15:31:33 +0000
@@ -0,0 +1,459 @@
1# Catalan (Valencian) translation for music-app
2# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
3# This file is distributed under the same license as the music-app package.
4# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
5#
6msgid ""
7msgstr ""
8"Project-Id-Version: music-app\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-10-20 15:09+0100\n"
11"PO-Revision-Date: 2014-10-17 05:37+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Catalan (Valencian) <ca@valencia@li.org>\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18"X-Launchpad-Export-Date: 2014-10-21 07:54+0000\n"
19"X-Generator: Launchpad (build 17203)\n"
20
21#: ../LoginLastFM.qml:48 ../MusicSettings.qml:134 ../MusicSettings.qml:142
22msgid "Last.fm"
23msgstr "Last.fm"
24
25#: ../LoginLastFM.qml:54
26msgid "Login to be able to scrobble."
27msgstr "Inicia una sessió per poder navegar."
28
29#: ../LoginLastFM.qml:62
30msgid "Username"
31msgstr "Nom d'usuari"
32
33#: ../LoginLastFM.qml:72
34msgid "Password"
35msgstr "Contrasenya"
36
37#: ../LoginLastFM.qml:94
38msgid "Login"
39msgstr "Inicia la sessió"
40
41#: ../LoginLastFM.qml:101
42msgid "Trying to login..."
43msgstr "S'està intentant iniciar la sessió..."
44
45#: ../LoginLastFM.qml:115
46msgid "Login Successful"
47msgstr "Inici de sessió correcte"
48
49#: ../LoginLastFM.qml:121
50msgid "Login Failed"
51msgstr "Error en l'inici de sessió"
52
53#: ../LoginLastFM.qml:127
54msgid "You forgot to set your username and/or password"
55msgstr "Vos heu oblidat d'establir el vostre nom d'usuari i/o la contrasenya"
56
57#: ../MusicAlbums.qml:29
58msgid "Albums"
59msgstr "Àlbums"
60
61#: ../MusicAlbums.qml:57 ../MusicStart.qml:71 ../common/AlbumsPage.qml:155
62msgid "Album"
63msgstr "Àlbum"
64
65#: ../MusicArtists.qml:37
66msgid "Artists"
67msgstr "Artistes"
68
69#: ../MusicArtists.qml:78
70msgid "Artist"
71msgstr "Artista"
72
73#: ../MusicNowPlaying.qml:33
74msgid "Queue"
75msgstr ""
76
77#: ../MusicNowPlaying.qml:33
78msgid "Now playing"
79msgstr ""
80
81#. TRANSLATORS: this is the name of the playlists page shown in the tab header.
82#. Remember to keep the translation short to fit the screen width
83#: ../MusicPlaylists.qml:35
84msgid "Playlists"
85msgstr "Llistes de reproducció"
86
87#: ../MusicPlaylists.qml:61 ../MusicaddtoPlaylist.qml:105
88#: ../common/SongsPage.qml:228 ../common/SongsPage.qml:229
89#, qt-format
90msgid "%1 song"
91msgid_plural "%1 songs"
92msgstr[0] "%1 tema"
93msgstr[1] "%1 temes"
94
95#: ../MusicPlaylists.qml:66 ../MusicPlaylists.qml:70 ../MusicStart.qml:57
96#: ../MusicStart.qml:71 ../common/SongsPage.qml:47 ../common/SongsPage.qml:125
97#: ../common/SongsPage.qml:163 ../common/SongsPage.qml:172
98#: ../common/SongsPage.qml:208 ../common/SongsPage.qml:247
99#: ../common/SongsPage.qml:249 ../common/SongsPage.qml:266
100msgid "Playlist"
101msgstr "Llista de reproducció"
102
103#: ../MusicSearch.qml:44 ../MusicSearch.qml:75 ../music-app.qml:88
104#: ../music-app.qml:134 ../music-app.qml:140
105msgid "Search"
106msgstr "Cerca"
107
108#: ../MusicSettings.qml:30 ../music-app.qml:184
109msgid "Settings"
110msgstr "Paràmetres"
111
112#: ../MusicSettings.qml:70
113msgid "Equaliser"
114msgstr "Equalitzador"
115
116#: ../MusicSettings.qml:71
117msgid "Default"
118msgstr "Per defecte"
119
120#: ../MusicSettings.qml:72
121msgid "Acoustic"
122msgstr "Acústic"
123
124#: ../MusicSettings.qml:73
125msgid "Classical"
126msgstr "Clàssica"
127
128#: ../MusicSettings.qml:74
129msgid "Electronic"
130msgstr "Electrònica"
131
132#: ../MusicSettings.qml:75
133msgid "Flat"
134msgstr "Pla"
135
136#: ../MusicSettings.qml:76
137msgid "Hip Hop"
138msgstr "Hip Hop"
139
140#: ../MusicSettings.qml:77
141msgid "Jazz"
142msgstr "Jazz"
143
144#: ../MusicSettings.qml:78
145msgid "Metal"
146msgstr "Metal"
147
148#: ../MusicSettings.qml:79
149msgid "Pop"
150msgstr "Pop"
151
152#: ../MusicSettings.qml:80
153msgid "Rock"
154msgstr "Rock"
155
156#: ../MusicSettings.qml:81
157msgid "Custom"
158msgstr "Personalitzada"
159
160#: ../MusicSettings.qml:101
161msgid ""
162"Snap to current song \n"
163"when opening toolbar"
164msgstr ""
165"Salta a la cançó actual \n"
166"quan s'estiga obrint una barra d'eines"
167
168#: ../MusicSettings.qml:121
169msgid "Accounts"
170msgstr "Comptes"
171
172#: ../MusicSettings.qml:135
173msgid "Login to scrobble and import playlists"
174msgstr "Inicieu una sessió per navegar i importar llistes de reproducció"
175
176#: ../MusicSettings.qml:158
177msgid "Music Streaming"
178msgstr "Transmissió de música"
179
180#: ../MusicSettings.qml:168
181msgid "Ubuntu One"
182msgstr "Ubuntu One"
183
184#: ../MusicSettings.qml:169
185msgid "Sign in to stream your cloud music"
186msgstr "Inicieu una sessió per transmetre la vostra música al núvol"
187
188#: ../MusicSettings.qml:185
189msgid "Stream only on Wi-Fi"
190msgstr "Transmet únicament amb la connexió inalàmbrica"
191
192#: ../MusicSettings.qml:219
193msgid "Clean everything!"
194msgstr "Neteja-ho tot"
195
196#: ../MusicStart.qml:35
197msgid "Recent"
198msgstr "Recents"
199
200#: ../MusicToolbar.qml:150
201msgid "Tap to shuffle music"
202msgstr ""
203
204#: ../MusicTracks.qml:35
205msgid "Songs"
206msgstr "Temes"
207
208#: ../MusicaddtoPlaylist.qml:41
209msgid "Select playlist"
210msgstr "Seleccioneu una llista de reproducció"
211
212#: ../MusicaddtoPlaylist.qml:48
213msgid "New playlist"
214msgstr "Llista de reproducció nova"
215
216#: ../common/AlbumsPage.qml:55 ../common/SongsPage.qml:115
217msgid "Shuffle"
218msgstr ""
219
220#: ../common/AlbumsPage.qml:72 ../common/SongsPage.qml:142
221msgid "Queue all"
222msgstr ""
223
224#: ../common/AlbumsPage.qml:83 ../common/SongsPage.qml:153
225msgid "Play all"
226msgstr "Reprodueix-ho tot"
227
228#: ../common/AlbumsPage.qml:124
229#, qt-format
230msgid "%1 album"
231msgid_plural "%1 albums"
232msgstr[0] "%1 àlbum"
233msgstr[1] "%1 àlbums"
234
235#: ../common/ListItemActions/AddToPlaylist.qml:25 ../music-app.qml:905
236msgid "Add to playlist"
237msgstr "Afig a la llista de reproducció"
238
239#: ../common/ListItemActions/AddToQueue.qml:25
240msgid "Add to Queue"
241msgstr "Afig a la cua"
242
243#: ../common/ListItemActions/Remove.qml:27 ../common/SongsPage.qml:400
244msgid "Remove"
245msgstr "Suprimeix-la"
246
247#: ../common/LoadingSpinnerComponent.qml:47
248msgid "Loading..."
249msgstr "S'està carregant..."
250
251#: ../common/SongsPage.qml:122 ../common/SongsPage.qml:160
252#: ../common/SongsPage.qml:173 ../common/SongsPage.qml:209
253#: ../common/SongsPage.qml:228 ../common/SongsPage.qml:263
254msgid "Genre"
255msgstr "Gènere"
256
257#. TRANSLATORS: this is a title of a dialog with a prompt to rename a playlist
258#: ../common/SongsPage.qml:333
259msgid "Change name"
260msgstr "Canvia el nom"
261
262#: ../common/SongsPage.qml:334
263msgid "Enter the new name of the playlist."
264msgstr "Escriviu un nom nou per a la llista de reproducció."
265
266#: ../common/SongsPage.qml:351
267msgid "Change"
268msgstr "Canvia"
269
270#: ../common/SongsPage.qml:372 ../music-app.qml:959
271msgid "Playlist already exists"
272msgstr "Ja existeix la llista de reproducció"
273
274#: ../common/SongsPage.qml:376 ../music-app.qml:964
275msgid "Please type in a name."
276msgstr "Escriviu un nom"
277
278#: ../common/SongsPage.qml:381 ../common/SongsPage.qml:420
279#: ../music-app.qml:499 ../music-app.qml:970
280msgid "Cancel"
281msgstr "Cancel·la"
282
283#. TRANSLATORS: this is a title of a dialog with a prompt to delete a playlist
284#: ../common/SongsPage.qml:394
285msgid "Are you sure?"
286msgstr ""
287
288#: ../common/SongsPage.qml:395
289msgid "This will delete your playlist."
290msgstr ""
291
292#: ../common/SwipeDelete.qml:52 ../common/SwipeDelete.qml:88
293msgid "Clear"
294msgstr "Esborra"
295
296#: ../meta-database.js:90 ../meta-database.js:92
297msgid "Unknown Album"
298msgstr "Àlbum desconegut"
299
300#: ../meta-database.js:91
301msgid "Unknown Artist"
302msgstr "Artista desconegut"
303
304#: ../music-app.qml:135
305msgid "Search Track"
306msgstr "Cerca de temes"
307
308#: ../music-app.qml:147
309msgid "Next"
310msgstr "Següent"
311
312#: ../music-app.qml:148
313msgid "Next Track"
314msgstr "Tema següent"
315
316#: ../music-app.qml:154
317msgid "Pause"
318msgstr "Posa en pausa"
319
320#: ../music-app.qml:154
321msgid "Play"
322msgstr "Reprodueix"
323
324#: ../music-app.qml:156
325msgid "Pause Playback"
326msgstr "Posa la reproducció en pausa"
327
328#: ../music-app.qml:156
329msgid "Continue or start playback"
330msgstr "Continua o inicia la reproducció"
331
332#: ../music-app.qml:161
333msgid "Back"
334msgstr "Arrere"
335
336#: ../music-app.qml:162
337msgid "Go back to last page"
338msgstr "Torna a la pàgina anterior"
339
340#: ../music-app.qml:170
341msgid "Previous"
342msgstr "Anterior"
343
344#: ../music-app.qml:171
345msgid "Previous Track"
346msgstr "Tema anterior"
347
348#: ../music-app.qml:176
349msgid "Stop"
350msgstr "Para"
351
352#: ../music-app.qml:177
353msgid "Stop Playback"
354msgstr "Para la reproducció"
355
356#: ../music-app.qml:185
357msgid "Music Settings"
358msgstr "Paràmetres de la música"
359
360#. TRANSLATORS: This string represents that the target destination filepath does not start with ~/Music/Imported/
361#: ../music-app.qml:342
362msgid "Filepath must start with"
363msgstr "El camí del fitxer ha de començar per"
364
365#. TRANSLATORS: This string represents that a blank filepath destination has been used
366#: ../music-app.qml:368
367msgid "Filepath must be a file"
368msgstr "El camí del fitxer ha d'apuntar a un fitxer"
369
370#. TRANSLATORS: This string represents that there was failure moving the file to the target destination
371#: ../music-app.qml:374
372msgid "Failed to move file"
373msgstr "Ha fallat el trasllat del fitxer"
374
375#: ../music-app.qml:453
376msgid "Waiting for file(s)..."
377msgstr "S'estan esperant els fitxers..."
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: