Merge lp:~vthompson/music-app/recent-items into lp:music-app/trusty

Proposed by Victor Thompson
Status: Merged
Approved by: Victor Thompson
Approved revision: 226
Merged at revision: 229
Proposed branch: lp:~vthompson/music-app/recent-items
Merge into: lp:music-app/trusty
Diff against target: 350 lines (+176/-23)
6 files modified
LibraryListModel.qml (+19/-0)
MusicAlbums.qml (+4/-0)
MusicPlaylists.qml (+5/-2)
MusicStart.qml (+65/-20)
meta-database.js (+75/-1)
music-app.qml (+8/-0)
To merge this branch: bzr merge lp:~vthompson/music-app/recent-items
Reviewer Review Type Date Requested Status
Andrew Hayzen Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+191738@code.launchpad.net

Commit message

* Add database schema to track recent items
* Change models to query selected playlist or album
* Update recent list when an album or playlist is selected from either its tab or the recent list

Description of the change

* Add database schema to track recent items
* Change models to query selected playlist or album
* Update recent list when an album or playlist is selected from either its tab or the recent list

Note, that this change does not implement the sheet pattern for the items in the Recent list. That will need to be implemented at a later time.

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)
lp:~vthompson/music-app/recent-items updated
223. By Victor Thompson

Show recent list as empty instead of hiding it when it is empty

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

Could I get someone to review this? If you want to toggle back to the empty state with no recent items do the following:
1) uncomment L222 of meta-database.js in the reset function.
2) start the app and then kill it
3) re-comment L222

lp:~vthompson/music-app/recent-items updated
224. By Victor Thompson

Add a button to clear history.

225. By Victor Thompson

Fix button visibility

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

I implemented a clear button (not in the design spec) that I found useful.

Revision history for this message
Andrew Hayzen (ahayzen) wrote :

Looks good, I think we need to talk to design regarding the clear button (I guess if we had the setting page it could go in there? but we don't at the moment).

Also on the first run I noticed I got this error.
meta-database.js:329: Error: no such table: recent Unable to execute statement

lp:~vthompson/music-app/recent-items updated
226. By Victor Thompson

Resolve warning upon initialization.

Revision history for this message
Victor Thompson (vthompson) wrote :

I see that error as well, but when the app starts to load content and isRecentEmpty() is called before the table exists it was designed to return true in all cases but when entries were found. I've fixed the issue, however.

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
Andrew Hayzen (ahayzen) wrote :

Awesome! I approve assuming design agree on the clear button.

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-09-15 03:03:04 +0000
3+++ LibraryListModel.qml 2013-10-20 07:13:40 +0000
4@@ -159,6 +159,25 @@
5 }
6 }
7
8+ function filterRecent() {
9+ worker.sendMessage({'clear': true, 'model': libraryModel})
10+
11+ console.log("called LibraryListModel::filterRecent()")
12+
13+ // Save query for queue
14+ query = Library.getRecent
15+ param = null
16+
17+ var library = Library.getRecent()
18+
19+ for ( var key in library ) {
20+ var add = library[key];
21+ console.log("add.recent: "+add.recent)
22+ console.log(JSON.stringify(add))
23+ worker.sendMessage({'add': add, 'model': libraryModel})
24+ }
25+ }
26+
27 function filterGenres() {
28 worker.sendMessage({'clear': true, 'model': libraryModel})
29
30
31=== modified file 'MusicAlbums.qml'
32--- MusicAlbums.qml 2013-10-18 07:05:29 +0000
33+++ MusicAlbums.qml 2013-10-20 07:13:40 +0000
34@@ -251,6 +251,10 @@
35 focus = true
36 }
37 trackClicked(albumTracksModel, index) // play track
38+ Library.addRecent(album, artist, cover, album, "album")
39+ mainView.hasRecent = true
40+ recentModel.filterRecent()
41+
42 // TODO: This closes the SDK defined sheet
43 // component. It should be able to close
44 // albumSheet.
45
46=== modified file 'MusicPlaylists.qml'
47--- MusicPlaylists.qml 2013-10-18 07:05:29 +0000
48+++ MusicPlaylists.qml 2013-10-20 07:13:40 +0000
49@@ -289,8 +289,8 @@
50 expandable.visible = true
51 playlist.height = styleMusic.playlists.expandedHeight
52 }
53- }
54- }
55+ }
56+ }
57
58 Rectangle {
59 id: expandable
60@@ -837,6 +837,9 @@
61 onClicked: {
62 customdebug("File: " + file) // debugger
63 trackClicked(playlisttracksModel, index) // play track
64+ Library.addRecent(oldPlaylistName, "Playlist", cover, oldPlaylistName, "playlist")
65+ mainView.hasRecent = true
66+ recentModel.filterRecent()
67 }
68
69 onMouseXChanged: {
70
71=== modified file 'MusicStart.qml'
72--- MusicStart.qml 2013-10-18 07:05:29 +0000
73+++ MusicStart.qml 2013-10-20 07:13:40 +0000
74@@ -42,23 +42,57 @@
75 id: recentlyPlayed
76 text: i18n.tr("Recent")
77 }
78+ Item {
79+ id: recentlistempty
80+ anchors.top: recentlyPlayed.bottom
81+ anchors.topMargin: units.gu(1)
82+ height: units.gu(22)
83+ width: parent.width
84+ visible: !mainView.hasRecent
85+
86+ Label {
87+ horizontalAlignment: Text.AlignHCenter
88+ verticalAlignment: Text.AlignVCenter
89+ color: styleMusic.nowPlaying.labelSecondaryColor
90+ anchors.centerIn: parent
91+ elide: Text.ElideRight
92+ fontSize: "large"
93+ text: i18n.tr("No recent albums or playlists")
94+ }
95+ }
96
97 ListView {
98 id: recentlist
99 width: parent.width
100 anchors.top: recentlyPlayed.bottom
101 anchors.topMargin: units.gu(1)
102- //anchors.bottom: genres.top
103 spacing: units.gu(2)
104 height: units.gu(22)
105 // TODO: Update when view counts are collected
106- model: albumModel.model
107+ model: recentModel.model
108 delegate: recentDelegate
109 header: Item {
110 id: spacer
111 width: units.gu(1)
112 }
113+ footer: Item {
114+ id: clearRecent
115+ width: units.gu(20)
116+ height: units.gu(20)
117+ visible: mainView.hasRecent && !loading.visible
118+ Button {
119+ id: clearRecentButton
120+ anchors.centerIn: parent
121+ text: "Clear History"
122+ onClicked: {
123+ Library.clearRecentHistory()
124+ mainView.hasRecent = false
125+ recentModel.filterRecent()
126+ }
127+ }
128+ }
129 orientation: ListView.Horizontal
130+ visible: mainView.hasRecent
131
132 Component {
133 id: recentDelegate
134@@ -73,13 +107,12 @@
135 image: Image {
136 id: icon
137 fillMode: Image.Stretch
138- property string artist: model.artist
139- property string album: model.album
140 property string title: model.title
141+ property string title2: model.title2
142 property string cover: model.cover
143- property string length: model.length
144- property string file: model.file
145- property string year: model.year
146+ property string type: model.type
147+ property string time: model.time
148+ property string key: model.key
149 source: cover !== "" ? cover : "images/cover_default.png"
150 }
151 }
152@@ -98,10 +131,10 @@
153 anchors.leftMargin: units.gu(1)
154 anchors.right: parent.right
155 anchors.rightMargin: units.gu(1)
156- color: styleMusic.nowPlaying.labelSecondaryColor
157+ color: styleMusic.common.white
158 elide: Text.ElideRight
159- text: artist
160- fontSize: "x-small"
161+ text: title
162+ fontSize: "small"
163 }
164 }
165 UbuntuShape { // Background so can see text in current state
166@@ -118,21 +151,33 @@
167 anchors.bottomMargin: units.gu(1)
168 anchors.right: parent.right
169 anchors.rightMargin: units.gu(1)
170- color: styleMusic.common.white
171+ color: styleMusic.nowPlaying.labelSecondaryColor
172 elide: Text.ElideRight
173- text: album
174- fontSize: "small"
175+ text: title2
176+ fontSize: "x-small"
177 }
178 }
179 MouseArea {
180 anchors.fill: parent
181 onClicked: {
182- recentAlbumTracksModel.filterAlbumTracks(album)
183- trackQueue.model.clear()
184- addQueueFromModel(recentAlbumTracksModel)
185- currentModel = recentAlbumTracksModel
186- currentQuery = recentAlbumTracksModel.query
187- currentParam = recentAlbumTracksModel.param
188+ if (type === "album") {
189+ recentAlbumTracksModel.filterAlbumTracks(key)
190+ trackQueue.model.clear()
191+ addQueueFromModel(recentAlbumTracksModel)
192+ currentModel = recentAlbumTracksModel
193+ currentQuery = recentAlbumTracksModel.query
194+ currentParam = recentAlbumTracksModel.param
195+ } else if (type === "playlist") {
196+ recentPlaylistTracksModel.filterPlaylistTracks(key)
197+ trackQueue.model.clear()
198+ addQueueFromModel(recentPlaylistTracksModel)
199+ currentModel = recentPlaylistTracksModel
200+ currentQuery = recentPlaylistTracksModel.query
201+ currentParam = recentPlaylistTracksModel.param
202+ }
203+ Library.addRecent(title, title2, cover, key, type)
204+ mainView.hasRecent = true
205+ recentModel.filterRecent()
206 var file = trackQueue.model.get(0).file
207 currentIndex = trackQueue.indexOf(file)
208 queueChanged = true
209@@ -149,7 +194,7 @@
210
211 ListItem.ThinDivider {
212 id: divider
213- anchors.top: recentlist.bottom
214+ anchors.top: recentlist.visible ? recentlist.bottom : recentlistempty.bottom
215 }
216 ListItem.Standard {
217 id: genres
218
219=== modified file 'meta-database.js'
220--- meta-database.js 2013-10-10 22:49:31 +0000
221+++ meta-database.js 2013-10-20 07:13:40 +0000
222@@ -32,6 +32,7 @@
223 // If the table exists, this is skipped
224 //tx.executeSql('DROP TABLE metadata');
225 tx.executeSql('CREATE TABLE IF NOT EXISTS metadata(file TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, cover TEXT, year TEXT, number TEXT, length TEXT, genre TEXT)');
226+ createRecent();
227 });
228 }
229 function reset() {
230@@ -42,7 +43,27 @@
231 // If the table exists, this is skipped
232 tx.executeSql('DROP TABLE IF EXISTS metadata');
233 tx.executeSql('CREATE TABLE IF NOT EXISTS metadata(file TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, cover TEXT, year TEXT, number TEXT, length TEXT, genre TEXT)');
234- //tx.executeSql('CREATE TABLE IF NOT EXISTS metadata(file TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, cover TEXT, year TEXT, number TEXT, length TEXT, genre TEXT)');
235+ createRecent();
236+ });
237+}
238+
239+function createRecent() {
240+ var db = getDatabase();
241+ db.transaction(
242+ function(tx) {
243+ // "key" is the search criteria for the type.
244+ // album title for album, and playlist title for playlist
245+ //tx.executeSql('DROP TABLE recent');
246+ tx.executeSql("CREATE TABLE IF NOT EXISTS recent(time DATETIME, title TEXT, title2 TEXT, cover TEXT, key TEXT UNIQUE, type TEXT)");
247+ });
248+}
249+
250+function clearRecentHistory() {
251+ var db = getDatabase();
252+ db.transaction(
253+ function(tx) {
254+ tx.executeSql('DROP TABLE IF EXISTS recent');
255+ tx.executeSql("CREATE TABLE IF NOT EXISTS recent(time DATETIME, title TEXT, title2 TEXT, cover TEXT, key TEXT UNIQUE, type TEXT)");
256 });
257 }
258
259@@ -269,3 +290,56 @@
260 });
261 return res;
262 }
263+
264+// This function is used to insert a recent item into the database
265+function addRecent(title, title2, cover, key, type) {
266+ var db = getDatabase();
267+ var res="";
268+
269+ console.log("RECENT " + key + title + title2 + cover)
270+
271+ db.transaction(function(tx) {
272+ var rs = tx.executeSql('INSERT OR REPLACE INTO recent (time, title, title2, cover, key, type) VALUES (?,?,?,?,?,?);', [new Date(), title, title2, cover, key, type]);
273+ if (rs.rowsAffected > 0) {
274+ console.log("RECENT add OK")
275+ res = "OK";
276+ } else {
277+ console.log("RECENT add Fail")
278+ res = "Error";
279+ }
280+ }
281+ );
282+}
283+
284+function getRecent() {
285+ var res = [];
286+ var db = getDatabase();
287+ db.transaction( function(tx) {
288+ var rs = tx.executeSql("SELECT * FROM recent ORDER BY time DESC LIMIT 15");
289+ for(var i = 0; i < rs.rows.length; i++) {
290+ var dbItem = rs.rows.item(i);
291+ console.log("Time:"+ dbItem.time + ", Key:"+dbItem.key + ", Title:"+dbItem.title + ", Title2:"+dbItem.title2 + ", Cover:"+dbItem.cover + ", Type:"+dbItem.type);
292+ res.push({time:dbItem.time, title:dbItem.title, title2:dbItem.title2, cover:dbItem.cover, key:dbItem.key, type:dbItem.type});
293+ }
294+ });
295+ return res;
296+}
297+
298+function isRecentEmpty() {
299+ var db = getDatabase();
300+ var res = 0;
301+
302+ db.transaction( function(tx) {
303+ createRecent();
304+ var rs = tx.executeSql("SELECT count(*) as value FROM recent")
305+ if (rs.rows.item(0).value > 0) {
306+ res = rs.rows.item(0).value;
307+ } else {
308+ console.log("RECENT does not exist")
309+ res = 0;
310+ }
311+ }
312+ );
313+ return res === 0;
314+}
315+
316
317=== modified file 'music-app.qml'
318--- music-app.qml 2013-10-18 07:05:29 +0000
319+++ music-app.qml 2013-10-20 07:13:40 +0000
320@@ -209,6 +209,7 @@
321 property string musicName: i18n.tr("Music")
322 property string appVersion: '1.0'
323 property bool isPlaying: false
324+ property bool hasRecent: !Library.isRecentEmpty()
325 property bool random: false
326 property bool scrobble: false
327 property string lastfmusername
328@@ -685,8 +686,14 @@
329 }
330
331 LibraryListModel {
332+ id: recentModel
333+ }
334+ LibraryListModel {
335 id: recentAlbumTracksModel
336 }
337+ LibraryListModel {
338+ id: recentPlaylistTracksModel
339+ }
340
341 LibraryListModel {
342 id: genreModel
343@@ -757,6 +764,7 @@
344 libraryModel.populate()
345 albumModel.filterAlbums()
346 artistModel.filterArtists()
347+ recentModel.filterRecent()
348 genreModel.filterGenres()
349 timer.stop()
350 loading.visible = false

Subscribers

People subscribed via source and target branches

to status/vote changes: