Merge lp:~vthompson/music-app/fix-1201702-implement-artists-tab into lp:music-app/trusty

Proposed by Victor Thompson
Status: Merged
Approved by: Daniel Holm
Approved revision: 52
Merged at revision: 53
Proposed branch: lp:~vthompson/music-app/fix-1201702-implement-artists-tab
Merge into: lp:music-app/trusty
Diff against target: 420 lines (+200/-171)
4 files modified
LibraryListModel.qml (+15/-0)
MusicArtists.qml (+167/-170)
meta-database.js (+14/-0)
music-app.qml (+4/-1)
To merge this branch: bzr merge lp:~vthompson/music-app/fix-1201702-implement-artists-tab
Reviewer Review Type Date Requested Status
Daniel Holm Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+175194@code.launchpad.net

Commit message

Put together some initial functionality for the Albums tab.

Description of the change

Put together some initial functionality for the Albums tab.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel Holm (danielholm) wrote :

Great work!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'LibraryListModel.qml'
2--- LibraryListModel.qml 2013-07-15 21:58:50 +0000
3+++ LibraryListModel.qml 2013-07-17 04:18:23 +0000
4@@ -55,6 +55,21 @@
5 }
6 }
7
8+ function filterArtistTracks(artist) {
9+ // TODO: Currently clearing the model causes the ListView not to refresh when an artist is selected the second time.
10+ // However, without the call to clear(), each artist's tracks are appended to the ListView.
11+ // libraryModel.clear();
12+ console.log("called LibraryListModel::filterArtistsTracks()")
13+
14+ var library = Library.getArtistTracks(artist)
15+
16+ for ( var key in library ) {
17+ var add = library[key];
18+ console.log(JSON.stringify(add))
19+ worker.sendMessage({'add': add, 'model': libraryModel})
20+ }
21+ }
22+
23 function filterAlbums() {
24 libraryModel.clear();
25 console.log("called LibraryListModel::filterAlbums()")
26
27=== modified file 'MusicArtists.qml'
28--- MusicArtists.qml 2013-07-16 23:19:38 +0000
29+++ MusicArtists.qml 2013-07-17 04:18:23 +0000
30@@ -25,175 +25,172 @@
31 import QtQuick.LocalStorage 2.0
32 import "settings.js" as Settings
33 import "meta-database.js" as Library
34-import "playing-list.js" as PlayingList
35-
36-Page {
37- title: i18n.tr("Artists")
38-
39- tools: ToolbarItems {
40- // Settings dialog
41- ToolbarButton {
42- objectName: "settingsaction"
43- iconSource: Qt.resolvedUrl("images/settings.png")
44- text: i18n.tr("Settings")
45-
46- onTriggered: {
47- console.debug('Debug: Show settings')
48- PopupUtils.open(Qt.resolvedUrl("MusicSettings.qml"), mainView,
49- {
50- title: i18n.tr("Settings")
51- } )
52- }
53- }
54-
55- // Queue dialog
56- ToolbarButton {
57- objectName: "queuesaction"
58- iconSource: Qt.resolvedUrl("images/folder.png") // change this icon later
59- text: i18n.tr("Queue")
60-
61- onTriggered: {
62- console.debug('Debug: Show queue')
63- PopupUtils.open(Qt.resolvedUrl("QueueDialog.qml"), mainView,
64- {
65- title: i18n.tr("Queue")
66- } )
67- }
68- }
69- }
70-
71- Component {
72- id: highlight
73- Rectangle {
74- width: 5; height: 40
75- color: "#DD4814";
76- Behavior on y {
77- SpringAnimation {
78- spring: 3
79- damping: 0.2
80- }
81- }
82- }
83- }
84-
85- ListView {
86- id: artistlist
87- width: parent.width
88- anchors.top: parent.top
89- anchors.bottom: parent.bottom
90- anchors.bottomMargin: units.gu(8)
91- highlight: highlight
92- highlightFollowsCurrentItem: true
93- model: artistModel.model
94- delegate: artistDelegate
95-
96- Component {
97- id: artistDelegate
98-
99- ListItem.Standard {
100- id: track
101- property string artist: model.artist
102- property string album: model.album
103- property string title: model.title
104- property string cover: model.cover
105- property string length: model.length
106- property string file: model.file
107- icon: cover === "" ? (file.match("\\.mp3") ? Qt.resolvedUrl("images/audio-x-mpeg.png") : Qt.resolvedUrl("images/audio-x-vorbis+ogg.png")) : "image://cover-art/"+file
108- iconFrame: false
109- Label {
110- id: trackTitle
111- wrapMode: Text.NoWrap
112- maximumLineCount: 1
113- fontSize: "medium"
114- anchors.left: parent.left
115- anchors.leftMargin: units.gu(8)
116- anchors.top: parent.top
117- anchors.topMargin: 5
118- anchors.right: parent.right
119- text: track.title == "" ? track.file : track.title
120- }
121- Label {
122- id: trackArtistAlbum
123- wrapMode: Text.NoWrap
124- maximumLineCount: 2
125- fontSize: "small"
126- anchors.left: parent.left
127- anchors.leftMargin: units.gu(8)
128- anchors.top: trackTitle.bottom
129- anchors.right: parent.right
130- text: artist == "" ? "" : artist + " - " + album
131- }
132- Label {
133- id: trackDuration
134- wrapMode: Text.NoWrap
135- maximumLineCount: 2
136- fontSize: "small"
137- anchors.left: parent.left
138- anchors.leftMargin: units.gu(8)
139- anchors.top: trackArtistAlbum.bottom
140- anchors.right: parent.right
141- visible: false
142- text: ""
143- }
144-
145- onFocusChanged: {
146- if (focus == false) {
147- selected = false
148- } else {
149- selected = false
150- mainView.currentArtist = artist
151- mainView.currentAlbum = album
152- mainView.currentTracktitle = title
153- mainView.currentFile = file
154- mainView.currentCover = cover
155- }
156- }
157- MouseArea {
158- anchors.fill: parent
159- onDoubleClicked: {
160- }
161- onPressAndHold: {
162- trackQueue.append({"title": title, "artist": artist, "file": file})
163- }
164- onClicked: {
165- if (focus == false) {
166- focus = true
167- }
168- console.log("fileName: " + file)
169- if (tracklist.currentIndex == index) {
170- if (player.playbackState === MediaPlayer.PlayingState) {
171- player.pause()
172- } else if (player.playbackState === MediaPlayer.PausedState) {
173- player.play()
174- }
175- } else {
176- player.stop()
177- player.source = Qt.resolvedUrl(file)
178- tracklist.currentIndex = index
179- playing = PlayingList.indexOf(file)
180- console.log("Playing click: "+player.source)
181- console.log("Index: " + tracklist.currentIndex)
182- player.play()
183- }
184- console.log("Source: " + player.source.toString())
185- console.log("Length: " + length.toString())
186- }
187- }
188- Component.onCompleted: {
189- if (PlayingList.size() === 0) {
190- player.source = file
191- }
192-
193- if (!PlayingList.contains(file)) {
194- console.log("Adding file:" + file)
195- PlayingList.addItem(file, itemnum)
196- console.log(itemnum)
197- }
198- console.log("Title:" + title + " Artist: " + artist)
199- itemnum++
200- }
201- }
202- }
203- }
204+
205+PageStack {
206+ id: pageStack
207+ anchors.fill: parent
208+
209+
210+ Page {
211+ id: mainpage
212+ title: i18n.tr("Artists")
213+ Component.onCompleted: {
214+ pageStack.push(mainpage)
215+ }
216+
217+ tools: ToolbarItems {
218+ // Settings dialog
219+ ToolbarButton {
220+ objectName: "settingsaction"
221+ iconSource: Qt.resolvedUrl("images/settings.png")
222+ text: i18n.tr("Settings")
223+
224+ onTriggered: {
225+ console.debug('Debug: Show settings')
226+ PopupUtils.open(Qt.resolvedUrl("MusicSettings.qml"), mainView,
227+ {
228+ title: i18n.tr("Settings")
229+ } )
230+ }
231+ }
232+
233+ // Queue dialog
234+ ToolbarButton {
235+ objectName: "queuesaction"
236+ iconSource: Qt.resolvedUrl("images/folder.png") // change this icon later
237+ text: i18n.tr("Queue")
238+
239+ onTriggered: {
240+ console.debug('Debug: Show queue')
241+ PopupUtils.open(Qt.resolvedUrl("QueueDialog.qml"), mainView,
242+ {
243+ title: i18n.tr("Queue")
244+ } )
245+ }
246+ }
247+ }
248+
249+ ListView {
250+ id: artistlist
251+ width: parent.width
252+ anchors.top: parent.top
253+ anchors.bottom: parent.bottom
254+ anchors.bottomMargin: units.gu(8)
255+ model: artistModel.model
256+ delegate: artistDelegate
257+
258+ Component {
259+ id: artistDelegate
260+
261+ ListItem.Standard {
262+ id: track
263+ property string artist: model.artist
264+ property string cover: model.cover
265+ icon: cover === "" ? (file.match("\\.mp3") ? Qt.resolvedUrl("images/audio-x-mpeg.png") : Qt.resolvedUrl("images/audio-x-vorbis+ogg.png")) : "image://cover-art/"+file
266+ iconFrame: false
267+ progression: true
268+ Label {
269+ id: trackArtistAlbum
270+ wrapMode: Text.NoWrap
271+ maximumLineCount: 2
272+ fontSize: "large"
273+ anchors.left: parent.left
274+ anchors.leftMargin: units.gu(8)
275+ anchors.verticalCenter: parent.verticalCenter
276+ anchors.right: parent.right
277+ text: artist
278+ }
279+
280+ onFocusChanged: {
281+ }
282+ MouseArea {
283+ anchors.fill: parent
284+ onDoubleClicked: {
285+ }
286+ onPressAndHold: {
287+ }
288+ onClicked: {
289+ artistTracksModel.filterArtistTracks(artist)
290+ pageStack.push(artistpage)
291+ }
292+ }
293+ Component.onCompleted: {
294+ }
295+ }
296+ }
297+ }
298+ }
299+
300+ Page {
301+ id: artistpage
302+ title: i18n.tr("Tracks")
303+
304+ ListView {
305+ id: artisttrackslist
306+ width: parent.width
307+ anchors.top: parent.top
308+ anchors.bottom: parent.bottom
309+ anchors.bottomMargin: units.gu(8)
310+ model: artistTracksModel.model
311+ delegate: artistTracksDelegate
312+
313+ Component {
314+ id: artistTracksDelegate
315+
316+ ListItem.Standard {
317+ id: track
318+ property string artist: model.artist
319+ property string album: model.album
320+ property string title: model.title
321+ property string cover: model.cover
322+ property string length: model.length
323+ property string file: model.file
324+ icon: cover === "" ? (file.match("\\.mp3") ? Qt.resolvedUrl("images/audio-x-mpeg.png") : Qt.resolvedUrl("images/audio-x-vorbis+ogg.png")) : "image://cover-art/"+file
325+ iconFrame: false
326+ progression: false
327+ Label {
328+ id: trackTitle
329+ wrapMode: Text.NoWrap
330+ maximumLineCount: 1
331+ fontSize: "medium"
332+ anchors.left: parent.left
333+ anchors.leftMargin: units.gu(8)
334+ anchors.top: parent.top
335+ anchors.topMargin: 5
336+ anchors.right: parent.right
337+ text: track.title == "" ? track.file : track.title
338+ }
339+ Label {
340+ id: trackArtistAlbum
341+ wrapMode: Text.NoWrap
342+ maximumLineCount: 2
343+ fontSize: "small"
344+ anchors.left: parent.left
345+ anchors.leftMargin: units.gu(8)
346+ anchors.top: trackTitle.bottom
347+ anchors.right: parent.right
348+ text: artist == "" ? "" : artist + " - " + album
349+ }
350+
351+ onFocusChanged: {
352+ }
353+ MouseArea {
354+ anchors.fill: parent
355+ onDoubleClicked: {
356+ }
357+ onPressAndHold: {
358+ }
359+ onClicked: {
360+ }
361+ }
362+ Component.onCompleted: {
363+ }
364+ }
365+ }
366+ }
367+ }
368+
369+
370+
371 }
372
373
374=== modified file 'meta-database.js'
375--- meta-database.js 2013-07-15 22:05:23 +0000
376+++ meta-database.js 2013-07-17 04:18:23 +0000
377@@ -150,6 +150,20 @@
378 return res;
379 }
380
381+function getArtistTracks(artist) {
382+ var res = [];
383+ var db = getDatabase();
384+ db.transaction( function(tx) {
385+ var rs = tx.executeSql("SELECT * FROM metadata WHERE artist=? ORDER BY artist ASC, album ASC, file ASC", [artist]);
386+ for(var i = 0; i < rs.rows.length; i++) {
387+ var dbItem = rs.rows.item(i);
388+ console.log("Artist:"+ dbItem.artist + ", Album:"+dbItem.album + ", Title:"+dbItem.title + ", File:"+dbItem.file + ", Art:"+dbItem.cover);
389+ res.push({artist:dbItem.artist, album:dbItem.album, title:dbItem.title, file:dbItem.file, cover:dbItem.cover, length:dbItem.length});
390+ }
391+ });
392+ return res;
393+}
394+
395 function getAlbums() {
396 var res = [];
397 var db = getDatabase();
398
399=== modified file 'music-app.qml'
400--- music-app.qml 2013-07-16 01:09:42 +0000
401+++ music-app.qml 2013-07-17 04:18:23 +0000
402@@ -272,6 +272,9 @@
403 LibraryListModel {
404 id: artistModel
405 }
406+ LibraryListModel {
407+ id: artistTracksModel
408+ }
409
410 LibraryListModel {
411 id: albumModel
412@@ -362,7 +365,7 @@
413 Library.writeDb()
414 libraryModel.populate()
415 albumModel.filterAlbums()
416- artistModel.populate()
417+ artistModel.filterArtists()
418 PlayingList.clear()
419 itemnum = 0
420 timer.stop()

Subscribers

People subscribed via source and target branches

to status/vote changes: