Merge lp:~ahayzen/music-app/refactor-async-loader-pages into lp:music-app
- refactor-async-loader-pages
- Merge into trunk
Status: | Work in progress |
---|---|
Proposed branch: | lp:~ahayzen/music-app/refactor-async-loader-pages |
Merge into: | lp:music-app |
Diff against target: |
355 lines (+132/-36) 7 files modified
app/components/ColumnFlow.qml (+20/-3) app/components/Flickables/CardView.qml (+1/-7) app/components/MusicToolbar.qml (+1/-0) app/music-app.qml (+107/-26) app/ui/Albums.qml (+1/-0) app/ui/Genres.qml (+1/-0) app/ui/Playlists.qml (+1/-0) |
To merge this branch: | bzr merge lp:~ahayzen/music-app/refactor-async-loader-pages |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Victor Thompson | Needs Information | ||
Review via email: mp+248477@code.launchpad.net |
Commit message
* Load pages in async, the current page first then the other pages
Description of the change
* Load pages in async, the current page first then the other pages
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Victor Thompson (vthompson) wrote : | # |
The reason this makes a difference is because we are now waiting to load the Songs tab until it becomes visible. I'm not sure the others really need to be loaded asynchronously--as they currently behave this way internally anyway.
I'd also like us to revisit what it means to load things in this fashion. There's a loading time hit for every CardView filled tab (and now ListView) we currently have in the app. So with this MP it's every tab. This makes it a bit annoying (slow and distracting, as well) to browse from tab to tab. I think a better idea might be to load things asynchronously, but do so upon app startup. Maybe wait until the current view has finished, then load the other views. This would mean the below Loaders would be made "active: true" and the CardView would be made to load when not visible. But we should discuss this.
Since this isn't very important for the goal of refactoring, let's think this through a bit more before making a decision.
- 835. By Andrew Hayzen
-
* Load the other pages/tabs once the first is complete
- 836. By Andrew Hayzen
-
* Merge of trunk
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:836
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 837. By Andrew Hayzen
-
* Merge of trunk
Andrew Hayzen (ahayzen) wrote : | # |
We are going to make a version for trunk first, therefore marking this as WIP for now.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:837
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 838. By Andrew Hayzen
-
* Allow empty ColumnFlow's to load when not visible
- 839. By Andrew Hayzen
-
* Pull of /refactor
- 840. By Andrew Hayzen
-
* Pull of changes to ColumnFlow.qml in async-loader-pages that teach it about preloading
- 841. By Andrew Hayzen
-
* Wait until the toolbar has shown before loading further pages
Unmerged revisions
- 841. By Andrew Hayzen
-
* Wait until the toolbar has shown before loading further pages
- 840. By Andrew Hayzen
-
* Pull of changes to ColumnFlow.qml in async-loader-pages that teach it about preloading
- 839. By Andrew Hayzen
-
* Pull of /refactor
- 838. By Andrew Hayzen
-
* Allow empty ColumnFlow's to load when not visible
- 837. By Andrew Hayzen
-
* Merge of trunk
- 836. By Andrew Hayzen
-
* Merge of trunk
- 835. By Andrew Hayzen
-
* Load the other pages/tabs once the first is complete
- 834. By Andrew Hayzen
-
* Load pages in async and only when visible
Preview Diff
1 | === modified file 'app/components/ColumnFlow.qml' | |||
2 | --- app/components/ColumnFlow.qml 2015-01-11 17:40:13 +0000 | |||
3 | +++ app/components/ColumnFlow.qml 2015-05-02 16:02:00 +0000 | |||
4 | @@ -40,6 +40,7 @@ | |||
5 | 40 | property bool removing: false | 40 | property bool removing: false |
6 | 41 | property bool restoring: false // is the view restoring? | 41 | property bool restoring: false // is the view restoring? |
7 | 42 | property var restoreItems: ({}) // when rebuilding items are stored here temporarily | 42 | property var restoreItems: ({}) // when rebuilding items are stored here temporarily |
8 | 43 | property bool preloading: true // when visible has only been false allow loading (as no child objects [eg pages] can have been created on the fly) | ||
9 | 43 | 44 | ||
10 | 44 | onColumnWidthChanged: { | 45 | onColumnWidthChanged: { |
11 | 45 | if (restoring) { | 46 | if (restoring) { |
12 | @@ -62,6 +63,10 @@ | |||
13 | 62 | } | 63 | } |
14 | 63 | 64 | ||
15 | 64 | onVisibleChanged: { | 65 | onVisibleChanged: { |
16 | 66 | if (visible) { | ||
17 | 67 | preloading = false; | ||
18 | 68 | } | ||
19 | 69 | |||
20 | 65 | if (visible && delayRebuildIndex !== -1) { // restore from count change | 70 | if (visible && delayRebuildIndex !== -1) { // restore from count change |
21 | 66 | if (delayRebuildIndex === 0) { | 71 | if (delayRebuildIndex === 0) { |
22 | 67 | reset() | 72 | reset() |
23 | @@ -86,7 +91,7 @@ | |||
24 | 86 | Connections { | 91 | Connections { |
25 | 87 | target: model === undefined ? fakeModel : model | 92 | target: model === undefined ? fakeModel : model |
26 | 88 | onModelReset: { | 93 | onModelReset: { |
28 | 89 | if (!visible) { | 94 | if (!visible && lastIndex > 0 && !preloading) { |
29 | 90 | delayRebuildIndex = 0 | 95 | delayRebuildIndex = 0 |
30 | 91 | } else { | 96 | } else { |
31 | 92 | reset() | 97 | reset() |
32 | @@ -94,7 +99,7 @@ | |||
33 | 94 | } | 99 | } |
34 | 95 | } | 100 | } |
35 | 96 | onRowsInserted: { | 101 | onRowsInserted: { |
37 | 97 | if (!visible) { | 102 | if (!visible && lastIndex > 0 && !preloading) { |
38 | 98 | setDelayRebuildIndex(first) | 103 | setDelayRebuildIndex(first) |
39 | 99 | } else { | 104 | } else { |
40 | 100 | if (first <= lastIndex) { | 105 | if (first <= lastIndex) { |
41 | @@ -161,7 +166,8 @@ | |||
42 | 161 | // and | 166 | // and |
43 | 162 | // allow if the y position is within the viewport | 167 | // allow if the y position is within the viewport |
44 | 163 | // or if loadBefore is true then allow if the y position is before the viewport | 168 | // or if loadBefore is true then allow if the y position is before the viewport |
46 | 164 | if (((count > 0 && lastIndex < count && insertMax === undefined) || (insertMax !== undefined && lastIndex <= insertMax)) && (inViewport(y, 0) || (loadBefore === true && beforeViewport(y)))) { | 169 | if (((count > 0 && lastIndex < count && insertMax === undefined) || (insertMax !== undefined && lastIndex <= insertMax)) |
47 | 170 | && (inViewport(y, 0) || (loadBefore === true && beforeViewport(y)))) { | ||
48 | 165 | incubateObject(lastIndex++, columnsByHeight[i], getMaxInColumn(columnsByHeight[i]), append); | 171 | incubateObject(lastIndex++, columnsByHeight[i], getMaxInColumn(columnsByHeight[i]), append); |
49 | 166 | workDone = true | 172 | workDone = true |
50 | 167 | } else { | 173 | } else { |
51 | @@ -489,4 +495,15 @@ | |||
52 | 489 | delayRebuildIndex = index | 495 | delayRebuildIndex = index |
53 | 490 | } | 496 | } |
54 | 491 | } | 497 | } |
55 | 498 | |||
56 | 499 | Component.onCompleted: { | ||
57 | 500 | // Ensure that initial column vars are set | ||
58 | 501 | for (var j=0; j < columns; j++) { | ||
59 | 502 | columnHeights.push({}) | ||
60 | 503 | } | ||
61 | 504 | |||
62 | 505 | cacheColumnHeights() | ||
63 | 506 | |||
64 | 507 | append(true) | ||
65 | 508 | } | ||
66 | 492 | } | 509 | } |
67 | 493 | 510 | ||
68 | === modified file 'app/components/Flickables/CardView.qml' | |||
69 | --- app/components/Flickables/CardView.qml 2015-02-08 04:06:28 +0000 | |||
70 | +++ app/components/Flickables/CardView.qml 2015-05-02 16:02:00 +0000 | |||
71 | @@ -35,17 +35,11 @@ | |||
72 | 35 | property alias delegate: flow.delegate | 35 | property alias delegate: flow.delegate |
73 | 36 | property var getter | 36 | property var getter |
74 | 37 | property alias header: headerLoader.sourceComponent | 37 | property alias header: headerLoader.sourceComponent |
76 | 38 | property var model: flow.model | 38 | property alias model: flow.model |
77 | 39 | property real itemWidth: units.gu(15) | 39 | property real itemWidth: units.gu(15) |
78 | 40 | 40 | ||
79 | 41 | onGetterChanged: flow.getter = getter // cannot use alias to set a function (must be var) | 41 | onGetterChanged: flow.getter = getter // cannot use alias to set a function (must be var) |
80 | 42 | 42 | ||
81 | 43 | onVisibleChanged: { | ||
82 | 44 | if (visible) { // only load model once CardView is visible | ||
83 | 45 | flow.model = model | ||
84 | 46 | } | ||
85 | 47 | } | ||
86 | 48 | |||
87 | 49 | Loader { | 43 | Loader { |
88 | 50 | id: headerLoader | 44 | id: headerLoader |
89 | 51 | visible: sourceComponent !== undefined | 45 | visible: sourceComponent !== undefined |
90 | 52 | 46 | ||
91 | === modified file 'app/components/MusicToolbar.qml' | |||
92 | --- app/components/MusicToolbar.qml 2015-02-04 16:43:17 +0000 | |||
93 | +++ app/components/MusicToolbar.qml 2015-05-02 16:02:00 +0000 | |||
94 | @@ -20,6 +20,7 @@ | |||
95 | 20 | import QtQuick 2.3 | 20 | import QtQuick 2.3 |
96 | 21 | import QtMultimedia 5.0 | 21 | import QtMultimedia 5.0 |
97 | 22 | import Ubuntu.Components 1.1 | 22 | import Ubuntu.Components 1.1 |
98 | 23 | import Ubuntu.Thumbnailer 0.1 | ||
99 | 23 | 24 | ||
100 | 24 | Rectangle { | 25 | Rectangle { |
101 | 25 | anchors { | 26 | anchors { |
102 | 26 | 27 | ||
103 | === modified file 'app/music-app.qml' | |||
104 | --- app/music-app.qml 2015-04-29 00:55:02 +0000 | |||
105 | +++ app/music-app.qml 2015-05-02 16:02:00 +0000 | |||
106 | @@ -458,10 +458,12 @@ | |||
107 | 458 | 458 | ||
108 | 459 | // TODO: improve in refactoring to be able detect when a track is removed | 459 | // TODO: improve in refactoring to be able detect when a track is removed |
109 | 460 | // Update playlists page | 460 | // Update playlists page |
114 | 461 | if (playlistsPage.visible) { | 461 | if (playlistsPageLoader.status === Loader.Ready) { |
115 | 462 | playlistModel.filterPlaylists() | 462 | if (playlistsPageLoader.item.visible) { |
116 | 463 | } else { | 463 | playlistModel.filterPlaylists() |
117 | 464 | playlistsPage.changed = true | 464 | } else { |
118 | 465 | playlistsPageLoader.item.changed = true | ||
119 | 466 | } | ||
120 | 465 | } | 467 | } |
121 | 466 | } | 468 | } |
122 | 467 | } | 469 | } |
123 | @@ -497,10 +499,12 @@ | |||
124 | 497 | console.debug("Removed recent:", JSON.stringify(removed)) | 499 | console.debug("Removed recent:", JSON.stringify(removed)) |
125 | 498 | Library.recentRemoveAlbums(removed) | 500 | Library.recentRemoveAlbums(removed) |
126 | 499 | 501 | ||
131 | 500 | if (recentPage.visible) { | 502 | if (recentPageLoader.status === Loader.Ready) { |
132 | 501 | recentModel.filterRecent() | 503 | if (recentPageLoader.item.visible) { |
133 | 502 | } else { | 504 | recentModel.filterRecent() |
134 | 503 | recentPage.changed = true | 505 | } else { |
135 | 506 | recentPageLoader.item.changed = true | ||
136 | 507 | } | ||
137 | 504 | } | 508 | } |
138 | 505 | } | 509 | } |
139 | 506 | } | 510 | } |
140 | @@ -756,6 +760,7 @@ | |||
141 | 756 | } | 760 | } |
142 | 757 | 761 | ||
143 | 758 | property Tab lastTab: selectedTab | 762 | property Tab lastTab: selectedTab |
144 | 763 | property bool firstTabAyncLoadComplete: false | ||
145 | 759 | 764 | ||
146 | 760 | onSelectedTabChanged: { | 765 | onSelectedTabChanged: { |
147 | 761 | // pause loading of the models in the old tab | 766 | // pause loading of the models in the old tab |
148 | @@ -797,11 +802,23 @@ | |||
149 | 797 | id: recentTab | 802 | id: recentTab |
150 | 798 | objectName: "recentTab" | 803 | objectName: "recentTab" |
151 | 799 | anchors.fill: parent | 804 | anchors.fill: parent |
153 | 800 | title: page.title | 805 | title: i18n.tr("Recent") |
154 | 801 | 806 | ||
155 | 802 | // Tab content begins here | 807 | // Tab content begins here |
158 | 803 | page: Recent { | 808 | page: Loader { |
159 | 804 | id: recentPage | 809 | id: recentPageLoader |
160 | 810 | anchors { | ||
161 | 811 | fill: parent | ||
162 | 812 | } | ||
163 | 813 | active: tabs.firstTabAyncLoadComplete && musicToolbar.status == Loader.Ready | ||
164 | 814 | asynchronous: true | ||
165 | 815 | source: "ui/Recent.qml" | ||
166 | 816 | |||
167 | 817 | onStatusChanged: { | ||
168 | 818 | if (status == Loader.Ready) { | ||
169 | 819 | tabs.firstTabAyncLoadComplete = true | ||
170 | 820 | } | ||
171 | 821 | } | ||
172 | 805 | } | 822 | } |
173 | 806 | } | 823 | } |
174 | 807 | } | 824 | } |
175 | @@ -844,11 +861,23 @@ | |||
176 | 844 | id: artistsTab | 861 | id: artistsTab |
177 | 845 | objectName: "artistsTab" | 862 | objectName: "artistsTab" |
178 | 846 | anchors.fill: parent | 863 | anchors.fill: parent |
180 | 847 | title: page.title | 864 | title: i18n.tr("Artists") |
181 | 848 | 865 | ||
182 | 849 | // tab content | 866 | // tab content |
185 | 850 | page: Artists { | 867 | page: Loader { |
186 | 851 | id: artistsPage | 868 | id: artistsPageLoader |
187 | 869 | anchors { | ||
188 | 870 | fill: parent | ||
189 | 871 | } | ||
190 | 872 | active: tabs.firstTabAyncLoadComplete && musicToolbar.status == Loader.Ready | ||
191 | 873 | asynchronous: true | ||
192 | 874 | source: "ui/Artists.qml" | ||
193 | 875 | |||
194 | 876 | onStatusChanged: { | ||
195 | 877 | if (status == Loader.Ready) { | ||
196 | 878 | tabs.firstTabAyncLoadComplete = true | ||
197 | 879 | } | ||
198 | 880 | } | ||
199 | 852 | } | 881 | } |
200 | 853 | } | 882 | } |
201 | 854 | 883 | ||
202 | @@ -861,11 +890,23 @@ | |||
203 | 861 | id: albumsTab | 890 | id: albumsTab |
204 | 862 | objectName: "albumsTab" | 891 | objectName: "albumsTab" |
205 | 863 | anchors.fill: parent | 892 | anchors.fill: parent |
207 | 864 | title: page.title | 893 | title: i18n.tr("Albums") |
208 | 865 | 894 | ||
209 | 866 | // Tab content begins here | 895 | // Tab content begins here |
212 | 867 | page: Albums { | 896 | page: Loader { |
213 | 868 | id: albumsPage | 897 | id: albumsPageLoader |
214 | 898 | anchors { | ||
215 | 899 | fill: parent | ||
216 | 900 | } | ||
217 | 901 | active: tabs.firstTabAyncLoadComplete && musicToolbar.status == Loader.Ready | ||
218 | 902 | asynchronous: true | ||
219 | 903 | source: "ui/Albums.qml" | ||
220 | 904 | |||
221 | 905 | onStatusChanged: { | ||
222 | 906 | if (status == Loader.Ready) { | ||
223 | 907 | tabs.firstTabAyncLoadComplete = true | ||
224 | 908 | } | ||
225 | 909 | } | ||
226 | 869 | } | 910 | } |
227 | 870 | } | 911 | } |
228 | 871 | 912 | ||
229 | @@ -878,11 +919,23 @@ | |||
230 | 878 | id: genresTab | 919 | id: genresTab |
231 | 879 | objectName: "genresTab" | 920 | objectName: "genresTab" |
232 | 880 | anchors.fill: parent | 921 | anchors.fill: parent |
234 | 881 | title: page.title | 922 | title: i18n.tr("Genres") |
235 | 882 | 923 | ||
236 | 883 | // Tab content begins here | 924 | // Tab content begins here |
239 | 884 | page: Genres { | 925 | page: Loader { |
240 | 885 | id: genresPage | 926 | id: genresPageLoader |
241 | 927 | anchors { | ||
242 | 928 | fill: parent | ||
243 | 929 | } | ||
244 | 930 | active: tabs.firstTabAyncLoadComplete && musicToolbar.status == Loader.Ready | ||
245 | 931 | asynchronous: true | ||
246 | 932 | source: "ui/Genres.qml" | ||
247 | 933 | |||
248 | 934 | onStatusChanged: { | ||
249 | 935 | if (status == Loader.Ready) { | ||
250 | 936 | tabs.firstTabAyncLoadComplete = true | ||
251 | 937 | } | ||
252 | 938 | } | ||
253 | 886 | } | 939 | } |
254 | 887 | } | 940 | } |
255 | 888 | 941 | ||
256 | @@ -895,11 +948,23 @@ | |||
257 | 895 | id: songsTab | 948 | id: songsTab |
258 | 896 | objectName: "songsTab" | 949 | objectName: "songsTab" |
259 | 897 | anchors.fill: parent | 950 | anchors.fill: parent |
261 | 898 | title: page.title | 951 | title: i18n.tr("Songs") |
262 | 899 | 952 | ||
263 | 900 | // Tab content begins here | 953 | // Tab content begins here |
266 | 901 | page: Songs { | 954 | page: Loader { |
267 | 902 | id: tracksPage | 955 | id: songsPageLoader |
268 | 956 | anchors { | ||
269 | 957 | fill: parent | ||
270 | 958 | } | ||
271 | 959 | active: tabs.firstTabAyncLoadComplete && musicToolbar.status == Loader.Ready | ||
272 | 960 | asynchronous: true | ||
273 | 961 | source: "ui/Songs.qml" | ||
274 | 962 | |||
275 | 963 | onStatusChanged: { | ||
276 | 964 | if (status == Loader.Ready) { | ||
277 | 965 | tabs.firstTabAyncLoadComplete = true | ||
278 | 966 | } | ||
279 | 967 | } | ||
280 | 903 | } | 968 | } |
281 | 904 | } | 969 | } |
282 | 905 | 970 | ||
283 | @@ -913,17 +978,33 @@ | |||
284 | 913 | id: playlistsTab | 978 | id: playlistsTab |
285 | 914 | objectName: "playlistsTab" | 979 | objectName: "playlistsTab" |
286 | 915 | anchors.fill: parent | 980 | anchors.fill: parent |
288 | 916 | title: page.title | 981 | title: i18n.tr("Playlists") |
289 | 917 | 982 | ||
290 | 918 | // Tab content begins here | 983 | // Tab content begins here |
293 | 919 | page: Playlists { | 984 | page: Loader { |
294 | 920 | id: playlistsPage | 985 | id: playlistsPageLoader |
295 | 986 | anchors { | ||
296 | 987 | fill: parent | ||
297 | 988 | } | ||
298 | 989 | active: tabs.firstTabAyncLoadComplete && musicToolbar.status == Loader.Ready | ||
299 | 990 | asynchronous: true | ||
300 | 991 | source: "ui/Playlists.qml" | ||
301 | 992 | |||
302 | 993 | onStatusChanged: { | ||
303 | 994 | if (status == Loader.Ready) { | ||
304 | 995 | tabs.firstTabAyncLoadComplete = true | ||
305 | 996 | } | ||
306 | 997 | } | ||
307 | 921 | } | 998 | } |
308 | 922 | } | 999 | } |
309 | 923 | 1000 | ||
310 | 924 | // Set the models in the tab to allow/disallow loading | 1001 | // Set the models in the tab to allow/disallow loading |
311 | 925 | function allowLoading(tabToLoad, state) | 1002 | function allowLoading(tabToLoad, state) |
312 | 926 | { | 1003 | { |
313 | 1004 | if (loadedUI) { | ||
314 | 1005 | selectedTab.page.active = true | ||
315 | 1006 | } | ||
316 | 1007 | |||
317 | 927 | if (tabToLoad && tabToLoad.model !== undefined) | 1008 | if (tabToLoad && tabToLoad.model !== undefined) |
318 | 928 | { | 1009 | { |
319 | 929 | for (var i=0; i < tabToLoad.model.length; i++) | 1010 | for (var i=0; i < tabToLoad.model.length; i++) |
320 | 930 | 1011 | ||
321 | === modified file 'app/ui/Albums.qml' | |||
322 | --- app/ui/Albums.qml 2015-02-16 20:27:40 +0000 | |||
323 | +++ app/ui/Albums.qml 2015-05-02 16:02:00 +0000 | |||
324 | @@ -20,6 +20,7 @@ | |||
325 | 20 | import QtQuick 2.3 | 20 | import QtQuick 2.3 |
326 | 21 | import Ubuntu.Components 1.1 | 21 | import Ubuntu.Components 1.1 |
327 | 22 | import Ubuntu.MediaScanner 0.1 | 22 | import Ubuntu.MediaScanner 0.1 |
328 | 23 | import Ubuntu.Thumbnailer 0.1 | ||
329 | 23 | import "../components" | 24 | import "../components" |
330 | 24 | import "../components/Delegates" | 25 | import "../components/Delegates" |
331 | 25 | import "../components/Flickables" | 26 | import "../components/Flickables" |
332 | 26 | 27 | ||
333 | === modified file 'app/ui/Genres.qml' | |||
334 | --- app/ui/Genres.qml 2015-02-16 20:27:40 +0000 | |||
335 | +++ app/ui/Genres.qml 2015-05-02 16:02:00 +0000 | |||
336 | @@ -20,6 +20,7 @@ | |||
337 | 20 | import QtQuick 2.3 | 20 | import QtQuick 2.3 |
338 | 21 | import Ubuntu.Components 1.1 | 21 | import Ubuntu.Components 1.1 |
339 | 22 | import Ubuntu.MediaScanner 0.1 | 22 | import Ubuntu.MediaScanner 0.1 |
340 | 23 | import Ubuntu.Thumbnailer 0.1 | ||
341 | 23 | import "../components" | 24 | import "../components" |
342 | 24 | import "../components/Delegates" | 25 | import "../components/Delegates" |
343 | 25 | import "../components/Flickables" | 26 | import "../components/Flickables" |
344 | 26 | 27 | ||
345 | === modified file 'app/ui/Playlists.qml' | |||
346 | --- app/ui/Playlists.qml 2015-04-28 17:37:33 +0000 | |||
347 | +++ app/ui/Playlists.qml 2015-05-02 16:02:00 +0000 | |||
348 | @@ -21,6 +21,7 @@ | |||
349 | 21 | import QtQuick 2.3 | 21 | import QtQuick 2.3 |
350 | 22 | import Ubuntu.Components 1.1 | 22 | import Ubuntu.Components 1.1 |
351 | 23 | import Ubuntu.Components.Popups 1.0 | 23 | import Ubuntu.Components.Popups 1.0 |
352 | 24 | import Ubuntu.Thumbnailer 0.1 | ||
353 | 24 | import QtMultimedia 5.0 | 25 | import QtMultimedia 5.0 |
354 | 25 | import QtQuick.LocalStorage 2.0 | 26 | import QtQuick.LocalStorage 2.0 |
355 | 26 | import "../logic/playlists.js" as Playlists | 27 | import "../logic/playlists.js" as Playlists |
PASSED: Continuous integration, rev:834 91.189. 93.70:8080/ job/music- app-refactor- ci/20/ 91.189. 93.70:8080/ job/generic- mediumtests- vivid/980 91.189. 93.70:8080/ job/generic- mediumtests- vivid/980/ artifact/ work/output/ *zip*/output. zip 91.189. 93.70:8080/ job/music- app-refactor- vivid-amd64- ci/20
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/music- app-refactor- ci/20/rebuild
http://