Merge lp:~fboucault/music-app/startup_time into lp:music-app

Proposed by Florian Boucault
Status: Merged
Approved by: Andrew Hayzen
Approved revision: 1020
Merged at revision: 1019
Proposed branch: lp:~fboucault/music-app/startup_time
Merge into: lp:music-app
Diff against target: 481 lines (+81/-76)
17 files modified
app/components/CoverGrid.qml (+5/-1)
app/components/Delegates/MusicListItem.qml (+1/-1)
app/components/ListItemReorderComponent.qml (+1/-0)
app/components/MusicToolbar.qml (+2/-0)
app/components/NowPlayingToolbar.qml (+5/-0)
app/components/Walkthrough/Slide1.qml (+1/-0)
app/components/Walkthrough/Slide2.qml (+1/-0)
app/components/Walkthrough/Slide3.qml (+1/-0)
app/components/Walkthrough/Walkthrough.qml (+2/-0)
app/music-app.qml (+51/-22)
app/ui/Albums.qml (+0/-10)
app/ui/Artists.qml (+0/-10)
app/ui/Genres.qml (+0/-10)
app/ui/LibraryEmptyState.qml (+3/-0)
app/ui/Playlists.qml (+0/-10)
app/ui/Recent.qml (+0/-10)
tests/autopilot/music_app/__init__.py (+8/-2)
To merge this branch: bzr merge lp:~fboucault/music-app/startup_time
Reviewer Review Type Date Requested Status
Jenkins Bot continuous-integration Approve
Andrew Hayzen Approve
Review via email: mp+301057@code.launchpad.net

Commit message

Improve startup time (by around 900ms on BQ E4.5):
- load Icons asynchronously.
- load Images asynchronously.
- load Tabs on demand.

Description of the change

Improve startup time (by around 900ms on BQ E4.5):
- load Icons asynchronously.
- load Images asynchronously.
- load Tabs on demand.

To post a comment you must log in.
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

Thank you for looking into this :-)

FYI, we had a branch to do the tabs on demand and async before, but decided against it as it caused a flicker in the GridView and the thumbnailer needed to reload all the cover art (eg going from Artists->Albums->Artists). I wonder if we can make it smoother by fading the items or something? But even then, before, we preferred smoothness of changing tabs over loading performance in that case.

I'll see if I can find the branch, because what we also tried was loading the selected tab in async, and then once that has loaded, load the other tabs in the background async and then not unloading them so that there is no flicker.

Also, we know that the localstorage solution for restoring the queue on startup is slow, I'm currently resolving this upstream by fixing the load and save methods of the new Playlist component within qtubuntu-media and qtmultimedia. So don't worry about trying to speed up that part if you find it is slow :-)

Furthermore, I've found if you go Artists->Albums->Artists and scroll, you seem to have a double GridView in the Artists tab for some reason - I don't remember seeing this before.

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

This is the super old branch from before [0], you can see the discussions we had. The preferred solution in that was to load the selected tab and then the others in async, but not unload. As the flicker was a large distraction to the user, note that the branch was on a much older codebase (before moving to GridView etc).

0 - https://code.launchpad.net/~ahayzen/music-app/refactor-async-loader-pages/+merge/248477

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

I think the way to progress forwards with this branch is to land the async changes to images and icons. But the loading tabs on demand should be put in a separate branch and changed to load the current tab and then load the others in the background, but with no unloading.

Then when we go through our redesign, which currently changes to the way tabs are used and changes the existing tabs to head sections, we can load (and unload) the head sections on demand - as then the whole of the header won't flicker while loading.

lp:~fboucault/music-app/startup_time updated
1015. By Florian Boucault

Merged from trunk

1016. By Florian Boucault

Fixed double loading of artists page

1017. By Florian Boucault

Reduce flicker by loading tabs synchronously

1018. By Florian Boucault

Use image scaling adequately for music-app-cover.png

1019. By Florian Boucault

Nicer tabs transition by fading in art

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

This is now looking visually much better and the code looks good as well. I just need to run autopilot on device and then it should be good to go :-) Thanks!

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

Running this against autopilot on my device I get many failures related to any test that change the tab, this is one of the failures [1].

It appears that it is failing because it tried to check self.autoClose [2] *after* clicking the action, which then fails because the tab has changed and the one autopilot is looking at has been unloaded.

Either, we need to write our own helper, or we could capture StateNotFoundError errors in our switch_to_tab_wrapper() and assume that the next part of the text will fail/check we are in the right place. (Which most do as in the get_songs_page() case it then tried to get the Page, so it would fail then).

So probably the best solution for now is putting a try catch in the switch_to_tab_wrapper() [3].

1 - http://pastebin.ubuntu.com/23374367/
2 - http://bazaar.launchpad.net/~ubuntu-sdk-team/ubuntu-ui-toolkit/trunk/view/head:/tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/popups.py#L108
3 - http://bazaar.launchpad.net/~fboucault/music-app/startup_time/view/head:/tests/autopilot/music_app/__init__.py#L483

review: Needs Fixing
lp:~fboucault/music-app/startup_time updated
1020. By Florian Boucault

Fixed autopilot failures due to disappearing popovers

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

Thanks for fixing those issues. LGTM, all tests 'pass' (I seem to be a getting one random failure due to the mediascanner mocking failing [also occurs on trunk so my device might just be racey]).

Sorry this took a long time to land.

review: Approve
Revision history for this message
Jenkins Bot (ubuntu-core-apps-jenkins-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'app/components/CoverGrid.qml'
2--- app/components/CoverGrid.qml 2016-03-15 02:09:37 +0000
3+++ app/components/CoverGrid.qml 2016-10-25 13:44:39 +0000
4@@ -63,7 +63,7 @@
5 ? (coverGrid.covers[index].art !== undefined
6 ? coverGrid.covers[index].art
7 : "image://albumart/artist=" + coverGrid.covers[index].author + "&album=" + coverGrid.covers[index].album)
8- : Qt.resolvedUrl("../graphics/music-app-cover@30.png")
9+ : Qt.resolvedUrl("../graphics/music-app-cover.png")
10
11 // TODO: This should be investigated once http://pad.lv/1391368
12 // is resolved. Once it is, these can either be set to
13@@ -89,6 +89,10 @@
14 firstSource = source
15 }
16 }
17+ opacity: status == Image.Ready ? 1.0 : 0.0
18+ Behavior on opacity {
19+ UbuntuNumberAnimation {}
20+ }
21 }
22 }
23 }
24
25=== modified file 'app/components/Delegates/MusicListItem.qml'
26--- app/components/Delegates/MusicListItem.qml 2016-02-26 03:16:35 +0000
27+++ app/components/Delegates/MusicListItem.qml 2016-10-25 13:44:39 +0000
28@@ -105,7 +105,7 @@
29
30 onStatusChanged: {
31 if (status === Image.Error) {
32- source = Qt.resolvedUrl("../../graphics/music-app-cover@30.png")
33+ source = Qt.resolvedUrl("../../graphics/music-app-cover.png")
34 }
35 }
36
37
38=== modified file 'app/components/ListItemReorderComponent.qml'
39--- app/components/ListItemReorderComponent.qml 2015-08-12 23:36:44 +0000
40+++ app/components/ListItemReorderComponent.qml 2016-10-25 13:44:39 +0000
41@@ -33,6 +33,7 @@
42 name: "navigation-menu" // TODO: use proper image
43 height: width
44 width: units.gu(3)
45+ asynchronous: true
46 }
47
48 MouseArea {
49
50=== modified file 'app/components/MusicToolbar.qml'
51--- app/components/MusicToolbar.qml 2016-01-16 17:46:59 +0000
52+++ app/components/MusicToolbar.qml 2016-10-25 13:44:39 +0000
53@@ -108,6 +108,7 @@
54 "media-playback-pause" : "media-playback-start"
55 objectName: "disabledSmallPlayShape"
56 width: height
57+ asynchronous: true
58 }
59
60 /* Click to shuffle music */
61@@ -203,6 +204,7 @@
62 "media-playback-pause" : "media-playback-start"
63 objectName: "playShape"
64 width: height
65+ asynchronous: true
66 }
67
68 /* Mouse area to jump to now playing */
69
70=== modified file 'app/components/NowPlayingToolbar.qml'
71--- app/components/NowPlayingToolbar.qml 2016-03-07 20:01:22 +0000
72+++ app/components/NowPlayingToolbar.qml 2016-10-25 13:44:39 +0000
73@@ -54,6 +54,7 @@
74 name: "media-playlist-repeat"
75 objectName: "repeatShape"
76 opacity: player.repeat ? 1 : .2
77+ asynchronous: true
78 }
79 }
80
81@@ -78,6 +79,7 @@
82 name: "media-skip-backward"
83 objectName: "previousShape"
84 opacity: parent.enabled ? 1 : .2
85+ asynchronous: true
86 }
87 }
88
89@@ -98,6 +100,7 @@
90 color: parent.pressed ? UbuntuColors.blue : "white"
91 name: player.mediaPlayer.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start"
92 objectName: "playShape"
93+ asynchronous: true
94 }
95 }
96
97@@ -122,6 +125,7 @@
98 name: "media-skip-forward"
99 objectName: "forwardShape"
100 opacity: parent.enabled ? 1 : .2
101+ asynchronous: true
102 }
103 }
104
105@@ -145,6 +149,7 @@
106 name: "media-playlist-shuffle"
107 objectName: "shuffleShape"
108 opacity: player.shuffle ? 1 : .2
109+ asynchronous: true
110 }
111 }
112
113
114=== modified file 'app/components/Walkthrough/Slide1.qml'
115--- app/components/Walkthrough/Slide1.qml 2015-10-18 17:45:48 +0000
116+++ app/components/Walkthrough/Slide1.qml 2016-10-25 13:44:39 +0000
117@@ -41,6 +41,7 @@
118 source: Image {
119 id: centerImage
120 source: Qt.resolvedUrl("../../graphics/music-app@30.png")
121+ asynchronous: true
122 }
123
124 width: height
125
126=== modified file 'app/components/Walkthrough/Slide2.qml'
127--- app/components/Walkthrough/Slide2.qml 2015-08-12 23:36:44 +0000
128+++ app/components/Walkthrough/Slide2.qml 2016-10-25 13:44:39 +0000
129@@ -39,6 +39,7 @@
130 height: (parent.height - bodyText.contentHeight - introductionText.height - 4*units.gu(4))/2
131 fillMode: Image.PreserveAspectFit
132 source: Qt.resolvedUrl("../../graphics/sd_phone_icon.png")
133+ asynchronous: true
134 }
135
136 Label {
137
138=== modified file 'app/components/Walkthrough/Slide3.qml'
139--- app/components/Walkthrough/Slide3.qml 2015-08-12 23:36:44 +0000
140+++ app/components/Walkthrough/Slide3.qml 2016-10-25 13:44:39 +0000
141@@ -39,6 +39,7 @@
142 height: (parent.height - introductionText.height - finalMessage.contentHeight - 4.5*units.gu(4))/2
143 fillMode: Image.PreserveAspectFit
144 source: Qt.resolvedUrl("../../graphics/music_download_icon.png")
145+ asynchronous: true
146 }
147
148 Label {
149
150=== modified file 'app/components/Walkthrough/Walkthrough.qml'
151--- app/components/Walkthrough/Walkthrough.qml 2015-10-28 01:05:33 +0000
152+++ app/components/Walkthrough/Walkthrough.qml 2016-10-25 13:44:39 +0000
153@@ -171,6 +171,7 @@
154 height: width
155 source: listView.currentIndex == index ? "../../graphics/Ellipse@27.png" : "../../graphics/Ellipse_15_opacity@27.png"
156 width: units.gu(1.5)
157+ asynchronous: true
158 }
159 }
160 }
161@@ -187,6 +188,7 @@
162 name: "chevron"
163 visible: listView.currentIndex !== 2
164 width: height
165+ asynchronous: true
166 }
167
168 MouseArea {
169
170=== renamed file 'app/graphics/music-app-cover@30.png' => 'app/graphics/music-app-cover@13.png'
171=== modified file 'app/music-app.qml'
172--- app/music-app.qml 2016-08-15 22:27:23 +0000
173+++ app/music-app.qml 2016-10-25 13:44:39 +0000
174@@ -446,10 +446,8 @@
175
176 // TODO: improve in refactoring to be able detect when a track is removed
177 // Update playlists page
178- if (playlistsPage.visible) {
179+ if (tabs.selectedTab == playlistsTab) {
180 playlistModel.filterPlaylists()
181- } else {
182- playlistsPage.changed = true
183 }
184 }
185 }
186@@ -587,7 +585,7 @@
187 // Go back up the stack if possible
188 function goBack() {
189 // Ensure in the case that goBack is called programmatically that any dialogs are closed
190- if (mainPageStack.currentMusicPage.currentDialog !== null) {
191+ if (mainPageStack.currentMusicPage && mainPageStack.currentMusicPage.currentDialog !== null) {
192 PopupUtils.close(mainPageStack.currentMusicPage.currentDialog)
193 }
194
195@@ -677,6 +675,9 @@
196 }
197 ]
198
199+ property bool completed: false
200+ Component.onCompleted: completed = true
201+
202 onSelectedTabChanged: {
203 // pause loading of the models in the old tab
204 if (lastTab !== null && lastTab !== selectedTab) {
205@@ -717,11 +718,14 @@
206 id: recentTab
207 objectName: "recentTab"
208 anchors.fill: parent
209- title: page.title
210+ title: i18n.tr("Recent")
211
212 // Tab content begins here
213- page: Recent {
214- id: recentPage
215+ page: Loader {
216+ width: mainPageStack.width
217+ height: mainPageStack.height
218+ active: tabs.selectedTab == recentTab
219+ source: Qt.resolvedUrl("ui/Recent.qml")
220 }
221 }
222 }
223@@ -764,11 +768,16 @@
224 id: artistsTab
225 objectName: "artistsTab"
226 anchors.fill: parent
227- title: page.title
228+ title: i18n.tr("Artists")
229
230 // tab content
231- page: Artists {
232- id: artistsPage
233+ page: Loader {
234+ width: mainPageStack.width
235+ height: mainPageStack.height
236+ // condition on tabs.completed necessary to avoid QTBUG 54657
237+ // https://bugreports.qt.io/browse/QTBUG-54657
238+ active: tabs.completed && tabs.selectedTab == artistsTab
239+ source: Qt.resolvedUrl("ui/Artists.qml")
240 }
241 }
242
243@@ -781,11 +790,16 @@
244 id: albumsTab
245 objectName: "albumsTab"
246 anchors.fill: parent
247- title: page.title
248+ title: i18n.tr("Albums")
249
250 // Tab content begins here
251- page: Albums {
252- id: albumsPage
253+ page: Loader {
254+ width: mainPageStack.width
255+ height: mainPageStack.height
256+ // condition on tabs.completed necessary to avoid QTBUG 54657
257+ // https://bugreports.qt.io/browse/QTBUG-54657
258+ active: tabs.completed && tabs.selectedTab == albumsTab
259+ source: Qt.resolvedUrl("ui/Albums.qml")
260 }
261 }
262
263@@ -798,11 +812,16 @@
264 id: genresTab
265 objectName: "genresTab"
266 anchors.fill: parent
267- title: page.title
268+ title: i18n.tr("Genres")
269
270 // Tab content begins here
271- page: Genres {
272- id: genresPage
273+ page: Loader {
274+ width: mainPageStack.width
275+ height: mainPageStack.height
276+ // condition on tabs.completed necessary to avoid QTBUG 54657
277+ // https://bugreports.qt.io/browse/QTBUG-54657
278+ active: tabs.completed && tabs.selectedTab == genresTab
279+ source: Qt.resolvedUrl("ui/Genres.qml")
280 }
281 }
282
283@@ -815,11 +834,16 @@
284 id: songsTab
285 objectName: "songsTab"
286 anchors.fill: parent
287- title: page.title
288+ title: i18n.tr("Tracks")
289
290 // Tab content begins here
291- page: Songs {
292- id: tracksPage
293+ page: Loader {
294+ width: mainPageStack.width
295+ height: mainPageStack.height
296+ // condition on tabs.completed necessary to avoid QTBUG 54657
297+ // https://bugreports.qt.io/browse/QTBUG-54657
298+ active: tabs.completed && tabs.selectedTab == songsTab
299+ source: Qt.resolvedUrl("ui/Songs.qml")
300 }
301 }
302
303@@ -832,11 +856,16 @@
304 id: playlistsTab
305 objectName: "playlistsTab"
306 anchors.fill: parent
307- title: page.title
308+ title: i18n.tr("Playlists")
309
310 // Tab content begins here
311- page: Playlists {
312- id: playlistsPage
313+ page: Loader {
314+ width: mainPageStack.width
315+ height: mainPageStack.height
316+ // condition on tabs.completed necessary to avoid QTBUG 54657
317+ // https://bugreports.qt.io/browse/QTBUG-54657
318+ active: tabs.completed && tabs.selectedTab == playlistsTab
319+ source: Qt.resolvedUrl("ui/Playlists.qml")
320 }
321 }
322
323
324=== modified file 'app/ui/Albums.qml'
325--- app/ui/Albums.qml 2016-03-07 20:01:22 +0000
326+++ app/ui/Albums.qml 2016-10-25 13:44:39 +0000
327@@ -44,16 +44,6 @@
328 }
329 ]
330
331- // FIXME: workaround for pad.lv/1531016 (gridview juddery)
332- anchors {
333- bottom: parent.bottom
334- fill: undefined
335- left: parent.left
336- top: parent.top
337- }
338- height: mainPageStack.height
339- width: mainPageStack.width
340-
341 // Hack for autopilot otherwise Albums appears as MusicPage
342 // due to bug 1341671 it is required that there is a property so that
343 // qml doesn't optimise using the parent type
344
345=== modified file 'app/ui/Artists.qml'
346--- app/ui/Artists.qml 2016-03-07 20:01:22 +0000
347+++ app/ui/Artists.qml 2016-10-25 13:44:39 +0000
348@@ -48,16 +48,6 @@
349 }
350 ]
351
352- // FIXME: workaround for pad.lv/1531016 (gridview juddery)
353- anchors {
354- bottom: parent.bottom
355- fill: undefined
356- left: parent.left
357- top: parent.top
358- }
359- height: mainPageStack.height
360- width: mainPageStack.width
361-
362 // Hack for autopilot otherwise Artists appears as MusicPage
363 // due to bug 1341671 it is required that there is a property so that
364 // qml doesn't optimise using the parent type
365
366=== modified file 'app/ui/Genres.qml'
367--- app/ui/Genres.qml 2016-03-07 20:01:22 +0000
368+++ app/ui/Genres.qml 2016-10-25 13:44:39 +0000
369@@ -44,16 +44,6 @@
370 }
371 ]
372
373- // FIXME: workaround for pad.lv/1531016 (gridview juddery)
374- anchors {
375- bottom: parent.bottom
376- fill: undefined
377- left: parent.left
378- top: parent.top
379- }
380- height: mainPageStack.height
381- width: mainPageStack.width
382-
383 // Hack for autopilot otherwise Albums appears as MusicPage
384 // due to bug 1341671 it is required that there is a property so that
385 // qml doesn't optimise using the parent type
386
387=== modified file 'app/ui/LibraryEmptyState.qml'
388--- app/ui/LibraryEmptyState.qml 2015-12-20 00:10:13 +0000
389+++ app/ui/LibraryEmptyState.qml 2016-10-25 13:44:39 +0000
390@@ -75,6 +75,7 @@
391 height: units.gu(10)
392 smooth: true
393 source: "../graphics/music_download_icon.png"
394+ asynchronous: true
395 }
396 }
397
398@@ -93,6 +94,7 @@
399 height: units.gu(6)
400 smooth: true
401 source: "../graphics/div.png"
402+ asynchronous: true
403 }
404 }
405
406@@ -106,6 +108,7 @@
407 height: units.gu(7)
408 smooth: true
409 source: "../graphics/sd_phone_icon.png"
410+ asynchronous: true
411 }
412 }
413
414
415=== modified file 'app/ui/Playlists.qml'
416--- app/ui/Playlists.qml 2016-03-07 20:01:22 +0000
417+++ app/ui/Playlists.qml 2016-10-25 13:44:39 +0000
418@@ -49,16 +49,6 @@
419 }
420 ]
421
422- // FIXME: workaround for pad.lv/1531016 (gridview juddery)
423- anchors {
424- bottom: parent.bottom
425- fill: undefined
426- left: parent.left
427- top: parent.top
428- }
429- height: mainPageStack.height
430- width: mainPageStack.width
431-
432 property bool changed: false
433 property bool childrenChanged: false
434
435
436=== modified file 'app/ui/Recent.qml'
437--- app/ui/Recent.qml 2016-08-15 23:15:01 +0000
438+++ app/ui/Recent.qml 2016-10-25 13:44:39 +0000
439@@ -73,16 +73,6 @@
440 }
441 title: i18n.tr("Recent")
442
443- // FIXME: workaround for pad.lv/1531016 (gridview juddery)
444- anchors {
445- bottom: parent.bottom
446- fill: undefined
447- left: parent.left
448- top: parent.top
449- }
450- height: mainPageStack.height
451- width: mainPageStack.width
452-
453 property bool changed: false
454 property bool childrenChanged: false
455
456
457=== modified file 'tests/autopilot/music_app/__init__.py'
458--- tests/autopilot/music_app/__init__.py 2016-08-15 19:56:11 +0000
459+++ tests/autopilot/music_app/__init__.py 2016-10-25 13:44:39 +0000
460@@ -9,6 +9,7 @@
461 from ubuntuuitoolkit import (
462 MainView, UbuntuUIToolkitCustomProxyObjectBase, UCListItem
463 )
464+from autopilot.introspection import dbus
465
466
467 class MusicAppException(Exception):
468@@ -482,6 +483,11 @@
469
470 def switch_to_tab_wrapper(self, objectName):
471 # We use leadingActionBar instead of Tabs so create wrapper
472- self.wait_select_single(
473+ action_bar = self.wait_select_single(
474 "ActionBar", objectName="tabsLeadingActionBar", visible=True,
475- ).click_action_button(objectName)
476+ )
477+ try:
478+ action_bar.click_action_button(objectName)
479+ except dbus.StateNotFoundError:
480+ # the popover was deleted when clicking the button
481+ pass

Subscribers

People subscribed via source and target branches