Merge lp:~ahayzen/music-app/refactor-split-content-hub-url-handler-metrics into lp:music-app
- refactor-split-content-hub-url-handler-metrics
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Victor Thompson |
Approved revision: | 843 |
Merged at revision: | 846 |
Proposed branch: | lp:~ahayzen/music-app/refactor-split-content-hub-url-handler-metrics |
Merge into: | lp:music-app |
Diff against target: |
816 lines (+425/-312) 7 files modified
app/components/CMakeLists.txt (+1/-0) app/components/Helpers/CMakeLists.txt (+4/-0) app/components/Helpers/ContentHubHelper.qml (+208/-0) app/components/Helpers/UriHandlerHelper.qml (+97/-0) app/components/Helpers/UserMetricsHelper.qml (+56/-0) app/components/WorkerWaiter.qml (+48/-0) app/music-app.qml (+11/-312) |
To merge this branch: | bzr merge lp:~ahayzen/music-app/refactor-split-content-hub-url-handler-metrics |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Victor Thompson | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+249887@code.launchpad.net |
Commit message
* Split content-hub, uri-handler and metrics into Helpers
Description of the change
* Split content-hub, uri-handler and metrics into Helpers
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
- 842. By Andrew Hayzen
-
* Merge of lp:music-app/refactor
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:842
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
This looks good and I haven't found any issues. I think it might be best to rename MetricHelper as UserMetricsHelper. Even though the component is called "Metric" I think naming the helper so it matches the library being used makes things more clear. The other helpers have names that describe their content quite clearly.
- 843. By Andrew Hayzen
-
* Rename MetricHelper.qml to UserMetricsHelp
er.qml
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:843
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
lgtm! Thanks! :)
Preview Diff
1 | === modified file 'app/components/CMakeLists.txt' |
2 | --- app/components/CMakeLists.txt 2015-02-16 20:27:40 +0000 |
3 | +++ app/components/CMakeLists.txt 2015-03-09 00:13:54 +0000 |
4 | @@ -1,6 +1,7 @@ |
5 | add_subdirectory(Delegates) |
6 | add_subdirectory(Dialog) |
7 | add_subdirectory(HeadState) |
8 | +add_subdirectory(Helpers) |
9 | add_subdirectory(Flickables) |
10 | add_subdirectory(ListItemActions) |
11 | add_subdirectory(ViewButton) |
12 | |
13 | === added directory 'app/components/Helpers' |
14 | === added file 'app/components/Helpers/CMakeLists.txt' |
15 | --- app/components/Helpers/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
16 | +++ app/components/Helpers/CMakeLists.txt 2015-03-09 00:13:54 +0000 |
17 | @@ -0,0 +1,4 @@ |
18 | +# make the qml files visible on qtcreator |
19 | +file(GLOB HELPERS_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) |
20 | + |
21 | +add_custom_target(com_ubuntu_music_HELPERS_QMLFiles ALL SOURCES ${HELPERS_QML_FILES}) |
22 | |
23 | === added file 'app/components/Helpers/ContentHubHelper.qml' |
24 | --- app/components/Helpers/ContentHubHelper.qml 1970-01-01 00:00:00 +0000 |
25 | +++ app/components/Helpers/ContentHubHelper.qml 2015-03-09 00:13:54 +0000 |
26 | @@ -0,0 +1,208 @@ |
27 | +/* |
28 | + * Copyright (C) 2014, 2015 |
29 | + * Andrew Hayzen <ahayzen@gmail.com> |
30 | + * Daniel Holm <d.holmen@gmail.com> |
31 | + * Victor Thompson <victor.thompson@gmail.com> |
32 | + * |
33 | + * This program is free software; you can redistribute it and/or modify |
34 | + * it under the terms of the GNU General Public License as published by |
35 | + * the Free Software Foundation; version 3. |
36 | + * |
37 | + * This program is distributed in the hope that it will be useful, |
38 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
39 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
40 | + * GNU General Public License for more details. |
41 | + * |
42 | + * You should have received a copy of the GNU General Public License |
43 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
44 | + */ |
45 | + |
46 | +import QtQuick 2.3 |
47 | +import Ubuntu.Components 1.1 |
48 | +import Ubuntu.Components.Popups 1.0 |
49 | +import Ubuntu.Content 0.1 |
50 | + |
51 | + |
52 | +Item { |
53 | + property var activeTransfer |
54 | + property int importId: 0 |
55 | + property list<ContentItem> importItems |
56 | + property bool processing: contentHubWaitForFile !== -1 |
57 | + |
58 | + ContentTransferHint { |
59 | + anchors { |
60 | + fill: parent |
61 | + } |
62 | + activeTransfer: parent.activeTransfer |
63 | + } |
64 | + |
65 | + Connections { |
66 | + id: contentHub |
67 | + target: ContentHub |
68 | + |
69 | + property var searchPaths: [] |
70 | + |
71 | + onImportRequested: { |
72 | + activeTransfer = transfer; |
73 | + |
74 | + if (activeTransfer.state === ContentTransfer.Charged) { |
75 | + importItems = activeTransfer.items; |
76 | + |
77 | + var processId = importId++; |
78 | + |
79 | + console.debug("Triggering content-hub import ID", processId); |
80 | + |
81 | + searchPaths = []; |
82 | + |
83 | + var err = []; |
84 | + var path; |
85 | + var res; |
86 | + var success = true; |
87 | + var url; |
88 | + |
89 | + for (var i=0; i < importItems.length; i++) { |
90 | + url = importItems[i].url.toString() |
91 | + console.debug("Triggered content-hub import for item", url) |
92 | + |
93 | + // fixed path allows for apparmor protection |
94 | + path = "~/Music/Imported/" + Qt.formatDateTime(new Date(), "yyyy/MM/dd/hhmmss") + "-" + url.split("/").pop() |
95 | + res = contentHub.importFile(importItems[i], path) |
96 | + |
97 | + if (res !== true) { |
98 | + success = false; |
99 | + err.push(url.split("/").pop() + " " + res) |
100 | + } |
101 | + } |
102 | + |
103 | + |
104 | + if (success === true) { |
105 | + if (contentHubWaitForFile.processId === -1) { |
106 | + contentHubWaitForFile.dialog = PopupUtils.open(Qt.resolvedUrl("../Dialog/ContentHubWaitDialog.qml"), mainView) |
107 | + contentHubWaitForFile.searchPaths = contentHub.searchPaths; |
108 | + contentHubWaitForFile.processId = processId; |
109 | + contentHubWaitForFile.start(); |
110 | + |
111 | + // Stop queue loading in bg |
112 | + queueLoaderWorker.canLoad = false |
113 | + } else { |
114 | + contentHubWaitForFile.searchPaths.push.apply(contentHubWaitForFile.searchPaths, contentHub.searchPaths); |
115 | + contentHubWaitForFile.count = 0; |
116 | + contentHubWaitForFile.restart(); |
117 | + } |
118 | + } |
119 | + else { |
120 | + var errordialog = PopupUtils.open(Qt.resolvedUrl("../Dialog/ContentHubErrorDialog.qml"), mainView) |
121 | + errordialog.errorText = err.join("\n") |
122 | + } |
123 | + } |
124 | + } |
125 | + |
126 | + function importFile(contentItem, path) { |
127 | + var contentUrl = contentItem.url.toString() |
128 | + |
129 | + if (path.indexOf("~/Music/Imported/") !== 0) { |
130 | + console.debug("Invalid dest (not in ~/Music/Imported/)") |
131 | + |
132 | + // TRANSLATORS: This string represents that the target destination filepath does not start with ~/Music/Imported/ |
133 | + return i18n.tr("Filepath must start with") + " ~/Music/Imported/" |
134 | + } |
135 | + else { |
136 | + // extract /home/$USER (or $HOME) from contentitem url |
137 | + var homepath = contentUrl.substring(7).split("/"); |
138 | + |
139 | + if (homepath[1] === "home") { |
140 | + homepath.splice(3, homepath.length - 3) |
141 | + homepath = homepath.join("/") |
142 | + } |
143 | + else { |
144 | + console.debug("/home/$USER not detecting in contentItem assuming /home/phablet/") |
145 | + homepath = "/home/phablet" |
146 | + } |
147 | + |
148 | + console.debug("Move:", contentUrl, "to", path) |
149 | + |
150 | + // Extract filename from path and replace ~ with $HOME |
151 | + var dir = path.split("/") |
152 | + var filename = dir.pop() |
153 | + dir = dir.join("/").replace("~/", homepath + "/") |
154 | + |
155 | + if (filename === "") { |
156 | + console.debug("Invalid dest (filename blank)") |
157 | + |
158 | + // TRANSLATORS: This string represents that a blank filepath destination has been used |
159 | + return i18n.tr("Filepath must be a file") |
160 | + } |
161 | + else if (!contentItem.move(dir, filename)) { |
162 | + console.debug("Move failed! DIR:", dir, "FILE:", filename) |
163 | + |
164 | + // TRANSLATORS: This string represents that there was failure moving the file to the target destination |
165 | + return i18n.tr("Failed to move file") |
166 | + } |
167 | + else { |
168 | + contentHub.searchPaths.push(dir + "/" + filename) |
169 | + return true |
170 | + } |
171 | + } |
172 | + } |
173 | + } |
174 | + |
175 | + Timer { |
176 | + id: contentHubWaitForFile |
177 | + interval: 1000 |
178 | + triggeredOnStart: false |
179 | + repeat: true |
180 | + |
181 | + property var dialog: null |
182 | + property var searchPaths |
183 | + property int count: 0 |
184 | + property int processId: -1 |
185 | + |
186 | + function stopTimer() { |
187 | + processId = -1; |
188 | + count = 0; |
189 | + stop(); |
190 | + |
191 | + PopupUtils.close(dialog) |
192 | + } |
193 | + |
194 | + onTriggered: { |
195 | + var found = true |
196 | + var i; |
197 | + var model; |
198 | + |
199 | + for (i=0; i < searchPaths.length; i++) { |
200 | + model = musicStore.lookup(searchPaths[i]) |
201 | + |
202 | + console.debug("MusicStore model from lookup", JSON.stringify(model)) |
203 | + |
204 | + if (!model) { |
205 | + found = false |
206 | + } |
207 | + } |
208 | + |
209 | + if (!found) { |
210 | + count++; |
211 | + |
212 | + if (count >= 10) { // wait for 10s |
213 | + stopTimer(); |
214 | + |
215 | + console.debug("File(s) were not found", JSON.stringify(searchPaths)) |
216 | + PopupUtils.open(Qt.resolvedUrl("../Dialog/ContentHubNotFoundDialog.qml"), mainView) |
217 | + } |
218 | + } |
219 | + else { |
220 | + stopTimer(); |
221 | + |
222 | + trackQueue.clear(); |
223 | + |
224 | + for (i=0; i < searchPaths.length; i++) { |
225 | + model = musicStore.lookup(searchPaths[i]) |
226 | + |
227 | + trackQueue.append(makeDict(model)); |
228 | + } |
229 | + |
230 | + trackQueueClick(0); |
231 | + } |
232 | + } |
233 | + } |
234 | +} |
235 | |
236 | === added file 'app/components/Helpers/UriHandlerHelper.qml' |
237 | --- app/components/Helpers/UriHandlerHelper.qml 1970-01-01 00:00:00 +0000 |
238 | +++ app/components/Helpers/UriHandlerHelper.qml 2015-03-09 00:13:54 +0000 |
239 | @@ -0,0 +1,97 @@ |
240 | +/* |
241 | + * Copyright (C) 2013, 2014, 2015 |
242 | + * Andrew Hayzen <ahayzen@gmail.com> |
243 | + * Daniel Holm <d.holmen@gmail.com> |
244 | + * Victor Thompson <victor.thompson@gmail.com> |
245 | + * |
246 | + * This program is free software; you can redistribute it and/or modify |
247 | + * it under the terms of the GNU General Public License as published by |
248 | + * the Free Software Foundation; version 3. |
249 | + * |
250 | + * This program is distributed in the hope that it will be useful, |
251 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
252 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
253 | + * GNU General Public License for more details. |
254 | + * |
255 | + * You should have received a copy of the GNU General Public License |
256 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
257 | + */ |
258 | + |
259 | +import QtQuick 2.3 |
260 | +import Ubuntu.Components 1.1 |
261 | +import "../" |
262 | + |
263 | + |
264 | +Item { |
265 | + id: uriHandler |
266 | + |
267 | + Connections { |
268 | + target: UriHandler |
269 | + |
270 | + onOpened: { |
271 | + for (var i=0; i < uris.length; i++) { |
272 | + console.debug("URI=" + uris[i]) |
273 | + uriHandler.process(uris[i], i === 0); |
274 | + } |
275 | + } |
276 | + } |
277 | + |
278 | + function processAlbum(uri) { |
279 | + selectedAlbum = true; |
280 | + var split = uri.split("/"); |
281 | + |
282 | + if (split.length < 2) { |
283 | + console.debug("Unknown artist-album " + uri + ", skipping") |
284 | + return; |
285 | + } |
286 | + |
287 | + // Filter by artist and album |
288 | + songsAlbumArtistModel.albumArtist = decodeURIComponent(split[0]); |
289 | + songsAlbumArtistModel.album = decodeURIComponent(split[1]); |
290 | + } |
291 | + |
292 | + function processFile(uri, play) { |
293 | + // Stop queue loading in the background |
294 | + queueLoaderWorker.canLoad = false |
295 | + |
296 | + if (queueLoaderWorker.processing > 0) { |
297 | + waitForWorker.workerStop(queueLoaderWorker, processFile, [uri, play]) |
298 | + return; |
299 | + } |
300 | + |
301 | + uri = decodeURIComponent(uri); |
302 | + |
303 | + // Lookup track in songs model |
304 | + var track = musicStore.lookup(decodeURIComponent(uri)); |
305 | + |
306 | + if (!track) { |
307 | + console.debug("Unknown file " + uri + ", skipping") |
308 | + return; |
309 | + } |
310 | + |
311 | + if (play) { |
312 | + // clear play queue |
313 | + trackQueue.clear() |
314 | + } |
315 | + |
316 | + // enqueue |
317 | + trackQueue.append(makeDict(track)); |
318 | + |
319 | + // play first URI |
320 | + if (play) { |
321 | + trackQueueClick(trackQueue.model.count - 1); |
322 | + } |
323 | + } |
324 | + |
325 | + function process(uri, play) { |
326 | + if (uri.indexOf("album:///") === 0) { |
327 | + processAlbum(uri.substring(9)); |
328 | + } else if (uri.indexOf("file://") === 0) { |
329 | + processFile(uri.substring(7), play); |
330 | + } else if (uri.indexOf("music://") === 0) { |
331 | + processFile(uri.substring(8), play); |
332 | + } else { |
333 | + console.debug("Unsupported URI " + uri + ", skipping") |
334 | + } |
335 | + } |
336 | +} |
337 | |
338 | === added file 'app/components/Helpers/UserMetricsHelper.qml' |
339 | --- app/components/Helpers/UserMetricsHelper.qml 1970-01-01 00:00:00 +0000 |
340 | +++ app/components/Helpers/UserMetricsHelper.qml 2015-03-09 00:13:54 +0000 |
341 | @@ -0,0 +1,56 @@ |
342 | +/* |
343 | + * Copyright (C) 2013, 2014, 2015 |
344 | + * Andrew Hayzen <ahayzen@gmail.com> |
345 | + * Daniel Holm <d.holmen@gmail.com> |
346 | + * Victor Thompson <victor.thompson@gmail.com> |
347 | + * |
348 | + * This program is free software; you can redistribute it and/or modify |
349 | + * it under the terms of the GNU General Public License as published by |
350 | + * the Free Software Foundation; version 3. |
351 | + * |
352 | + * This program is distributed in the hope that it will be useful, |
353 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
354 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
355 | + * GNU General Public License for more details. |
356 | + * |
357 | + * You should have received a copy of the GNU General Public License |
358 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
359 | + */ |
360 | + |
361 | +import QtQuick 2.3 |
362 | +import Ubuntu.Components 1.1 |
363 | +import UserMetrics 0.1 |
364 | + |
365 | + |
366 | +Item { |
367 | + // UserMetrics to show Music stuff on welcome screen |
368 | + Metric { |
369 | + id: songsMetric |
370 | + name: "music-metrics" |
371 | + // TRANSLATORS: this refers to a number of songs greater than one. The actual number will be prepended to the string automatically (plural forms are not yet fully supported in usermetrics, the library that displays that string) |
372 | + format: "<b>%1</b> " + i18n.tr("songs played today") |
373 | + emptyFormat: i18n.tr("No songs played today") |
374 | + domain: "com.ubuntu.music" |
375 | + } |
376 | + |
377 | + // Connections for usermetrics |
378 | + Connections { |
379 | + id: userMetricPlayerConnection |
380 | + target: player |
381 | + property bool songCounted: false |
382 | + |
383 | + onSourceChanged: { |
384 | + songCounted = false |
385 | + } |
386 | + |
387 | + onPositionChanged: { |
388 | + // Increment song count on Welcome screen if song has been |
389 | + // playing for over 10 seconds. |
390 | + if (player.position > 10000 && !songCounted) { |
391 | + songCounted = true |
392 | + songsMetric.increment() |
393 | + console.debug("Increment UserMetrics") |
394 | + } |
395 | + } |
396 | + } |
397 | +} |
398 | |
399 | === added file 'app/components/WorkerWaiter.qml' |
400 | --- app/components/WorkerWaiter.qml 1970-01-01 00:00:00 +0000 |
401 | +++ app/components/WorkerWaiter.qml 2015-03-09 00:13:54 +0000 |
402 | @@ -0,0 +1,48 @@ |
403 | +/* |
404 | + * Copyright (C) 2014, 2015 |
405 | + * Andrew Hayzen <ahayzen@gmail.com> |
406 | + * Daniel Holm <d.holmen@gmail.com> |
407 | + * Victor Thompson <victor.thompson@gmail.com> |
408 | + * |
409 | + * This program is free software; you can redistribute it and/or modify |
410 | + * it under the terms of the GNU General Public License as published by |
411 | + * the Free Software Foundation; version 3. |
412 | + * |
413 | + * This program is distributed in the hope that it will be useful, |
414 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
415 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
416 | + * GNU General Public License for more details. |
417 | + * |
418 | + * You should have received a copy of the GNU General Public License |
419 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
420 | + */ |
421 | + |
422 | +import QtQuick 2.3 |
423 | +import Ubuntu.Components 1.1 |
424 | + |
425 | + |
426 | +Timer { // A timer to wait for a worker to stop |
427 | + id: waitForWorker |
428 | + interval: 16 |
429 | + repeat: true |
430 | + |
431 | + property var func |
432 | + property var params // don't use args/arguments as they are already defined/internal |
433 | + property WorkerScript worker |
434 | + |
435 | + onTriggered: { |
436 | + if (worker.processing === 0) { |
437 | + stop() |
438 | + func.apply(this, params) |
439 | + } |
440 | + } |
441 | + |
442 | + // Waits until the worker has stopped and then calls the func(*params) |
443 | + function workerStop(worker, func, params) |
444 | + { |
445 | + waitForWorker.func = func |
446 | + waitForWorker.params = params |
447 | + waitForWorker.worker = worker |
448 | + start() |
449 | + } |
450 | +} |
451 | |
452 | === modified file 'app/music-app.qml' |
453 | --- app/music-app.qml 2015-03-06 02:27:26 +0000 |
454 | +++ app/music-app.qml 2015-03-09 00:13:54 +0000 |
455 | @@ -19,18 +19,15 @@ |
456 | |
457 | import QtQuick 2.3 |
458 | import Ubuntu.Components 1.1 |
459 | -import Ubuntu.Components.Popups 1.0 |
460 | -import Ubuntu.Components.ListItems 1.0 as ListItem |
461 | -import Ubuntu.Content 0.1 |
462 | import Ubuntu.MediaScanner 0.1 |
463 | import Qt.labs.settings 1.0 |
464 | import QtMultimedia 5.0 |
465 | import QtQuick.LocalStorage 2.0 |
466 | import QtGraphicalEffects 1.0 |
467 | -import UserMetrics 0.1 |
468 | import "logic/meta-database.js" as Library |
469 | import "logic/playlists.js" as Playlists |
470 | import "components" |
471 | +import "components/Helpers" |
472 | import "ui" |
473 | |
474 | MainView { |
475 | @@ -180,291 +177,16 @@ |
476 | |
477 | actions: [nextAction, playsAction, prevAction, stopAction, backAction] |
478 | |
479 | - // signal to open new URIs |
480 | - Connections { |
481 | + UriHandlerHelper { |
482 | id: uriHandler |
483 | - target: UriHandler |
484 | - |
485 | - function processAlbum(uri) { |
486 | - selectedAlbum = true; |
487 | - var split = uri.split("/"); |
488 | - |
489 | - if (split.length < 2) { |
490 | - console.debug("Unknown artist-album " + uri + ", skipping") |
491 | - return; |
492 | - } |
493 | - |
494 | - // Filter by artist and album |
495 | - songsAlbumArtistModel.albumArtist = decodeURIComponent(split[0]); |
496 | - songsAlbumArtistModel.album = decodeURIComponent(split[1]); |
497 | - } |
498 | - |
499 | - function processFile(uri, play) { |
500 | - // Stop queue loading in the background |
501 | - queueLoaderWorker.canLoad = false |
502 | - |
503 | - if (queueLoaderWorker.processing > 0) { |
504 | - waitForWorker.workerStop(queueLoaderWorker, processFile, [uri, play]) |
505 | - return; |
506 | - } |
507 | - |
508 | - uri = decodeURIComponent(uri); |
509 | - |
510 | - // Lookup track in songs model |
511 | - var track = musicStore.lookup(decodeURIComponent(uri)); |
512 | - |
513 | - if (!track) { |
514 | - console.debug("Unknown file " + uri + ", skipping") |
515 | - return; |
516 | - } |
517 | - |
518 | - if (play) { |
519 | - // clear play queue |
520 | - trackQueue.clear() |
521 | - } |
522 | - |
523 | - // enqueue |
524 | - trackQueue.append(makeDict(track)); |
525 | - |
526 | - // play first URI |
527 | - if (play) { |
528 | - trackQueueClick(trackQueue.model.count - 1); |
529 | - } |
530 | - } |
531 | - |
532 | - function process(uri, play) { |
533 | - if (uri.indexOf("album:///") === 0) { |
534 | - uriHandler.processAlbum(uri.substring(9)); |
535 | - } |
536 | - else if (uri.indexOf("file://") === 0) { |
537 | - uriHandler.processFile(uri.substring(7), play); |
538 | - } |
539 | - else if (uri.indexOf("music://") === 0) { |
540 | - uriHandler.processFile(uri.substring(8), play); |
541 | - } |
542 | - else { |
543 | - console.debug("Unsupported URI " + uri + ", skipping") |
544 | - } |
545 | - } |
546 | - |
547 | - onOpened: { |
548 | - for (var i=0; i < uris.length; i++) { |
549 | - console.debug("URI=" + uris[i]) |
550 | - |
551 | - uriHandler.process(uris[i], i === 0); |
552 | - } |
553 | - } |
554 | - } |
555 | - |
556 | - // Content hub support |
557 | - property list<ContentItem> importItems |
558 | - property var activeTransfer |
559 | - property int importId: 0 |
560 | - |
561 | - ContentTransferHint { |
562 | - anchors { |
563 | - fill: parent |
564 | - } |
565 | - activeTransfer: parent.activeTransfer |
566 | - } |
567 | - |
568 | - Connections { |
569 | + } |
570 | + |
571 | + ContentHubHelper { |
572 | id: contentHub |
573 | - target: ContentHub |
574 | - onImportRequested: { |
575 | - activeTransfer = transfer; |
576 | - if (activeTransfer.state === ContentTransfer.Charged) { |
577 | - importItems = activeTransfer.items; |
578 | - |
579 | - var processId = importId++; |
580 | - |
581 | - console.debug("Triggering content-hub import ID", processId); |
582 | - |
583 | - searchPaths = []; |
584 | - |
585 | - var err = []; |
586 | - var path; |
587 | - var res; |
588 | - var success = true; |
589 | - var url; |
590 | - |
591 | - for (var i=0; i < importItems.length; i++) { |
592 | - url = importItems[i].url.toString() |
593 | - console.debug("Triggered content-hub import for item", url) |
594 | - |
595 | - // fixed path allows for apparmor protection |
596 | - path = "~/Music/Imported/" + Qt.formatDateTime(new Date(), "yyyy/MM/dd/hhmmss") + "-" + url.split("/").pop() |
597 | - res = contentHub.importFile(importItems[i], path) |
598 | - |
599 | - if (res !== true) { |
600 | - success = false; |
601 | - err.push(url.split("/").pop() + " " + res) |
602 | - } |
603 | - } |
604 | - |
605 | - |
606 | - if (success === true) { |
607 | - if (contentHubWaitForFile.processId === -1) { |
608 | - contentHubWaitForFile.dialog = PopupUtils.open(Qt.resolvedUrl("components/Dialog/ContentHubWaitDialog.qml"), mainView) |
609 | - contentHubWaitForFile.searchPaths = contentHub.searchPaths; |
610 | - contentHubWaitForFile.processId = processId; |
611 | - contentHubWaitForFile.start(); |
612 | - |
613 | - // Stop queue loading in bg |
614 | - queueLoaderWorker.canLoad = false |
615 | - } else { |
616 | - contentHubWaitForFile.searchPaths.push.apply(contentHubWaitForFile.searchPaths, contentHub.searchPaths); |
617 | - contentHubWaitForFile.count = 0; |
618 | - contentHubWaitForFile.restart(); |
619 | - } |
620 | - } |
621 | - else { |
622 | - var errordialog = PopupUtils.open(Qt.resolvedUrl("components/Dialog/ContentHubErrorDialog.qml"), mainView) |
623 | - errordialog.errorText = err.join("\n") |
624 | - } |
625 | - } |
626 | - } |
627 | - |
628 | - property var searchPaths: [] |
629 | - |
630 | - function importFile(contentItem, path) { |
631 | - var contentUrl = contentItem.url.toString() |
632 | - |
633 | - if (path.indexOf("~/Music/Imported/") !== 0) { |
634 | - console.debug("Invalid dest (not in ~/Music/Imported/)") |
635 | - |
636 | - // TRANSLATORS: This string represents that the target destination filepath does not start with ~/Music/Imported/ |
637 | - return i18n.tr("Filepath must start with") + " ~/Music/Imported/" |
638 | - } |
639 | - else { |
640 | - // extract /home/$USER (or $HOME) from contentitem url |
641 | - var homepath = contentUrl.substring(7).split("/"); |
642 | - |
643 | - if (homepath[1] === "home") { |
644 | - homepath.splice(3, homepath.length - 3) |
645 | - homepath = homepath.join("/") |
646 | - } |
647 | - else { |
648 | - console.debug("/home/$USER not detecting in contentItem assuming /home/phablet/") |
649 | - homepath = "/home/phablet" |
650 | - } |
651 | - |
652 | - console.debug("Move:", contentUrl, "to", path) |
653 | - |
654 | - // Extract filename from path and replace ~ with $HOME |
655 | - var dir = path.split("/") |
656 | - var filename = dir.pop() |
657 | - dir = dir.join("/").replace("~/", homepath + "/") |
658 | - |
659 | - if (filename === "") { |
660 | - console.debug("Invalid dest (filename blank)") |
661 | - |
662 | - // TRANSLATORS: This string represents that a blank filepath destination has been used |
663 | - return i18n.tr("Filepath must be a file") |
664 | - } |
665 | - else if (!contentItem.move(dir, filename)) { |
666 | - console.debug("Move failed! DIR:", dir, "FILE:", filename) |
667 | - |
668 | - // TRANSLATORS: This string represents that there was failure moving the file to the target destination |
669 | - return i18n.tr("Failed to move file") |
670 | - } |
671 | - else { |
672 | - contentHub.searchPaths.push(dir + "/" + filename) |
673 | - return true |
674 | - } |
675 | - } |
676 | - } |
677 | - } |
678 | - |
679 | - Timer { |
680 | - id: contentHubWaitForFile |
681 | - interval: 1000 |
682 | - triggeredOnStart: false |
683 | - repeat: true |
684 | - |
685 | - property var dialog: null |
686 | - property var searchPaths |
687 | - property int count: 0 |
688 | - property int processId: -1 |
689 | - |
690 | - function stopTimer() { |
691 | - processId = -1; |
692 | - count = 0; |
693 | - stop(); |
694 | - |
695 | - PopupUtils.close(dialog) |
696 | - } |
697 | - |
698 | - onTriggered: { |
699 | - var found = true |
700 | - var i; |
701 | - var model; |
702 | - |
703 | - for (i=0; i < searchPaths.length; i++) { |
704 | - model = musicStore.lookup(searchPaths[i]) |
705 | - |
706 | - console.debug("MusicStore model from lookup", JSON.stringify(model)) |
707 | - |
708 | - if (!model) { |
709 | - found = false |
710 | - } |
711 | - } |
712 | - |
713 | - if (!found) { |
714 | - count++; |
715 | - |
716 | - if (count >= 10) { // wait for 10s |
717 | - stopTimer(); |
718 | - |
719 | - console.debug("File(s) were not found", JSON.stringify(searchPaths)) |
720 | - PopupUtils.open(Qt.resolvedUrl("components/Dialog/ContentHubNotFoundDialog.qml"), mainView) |
721 | - } |
722 | - } |
723 | - else { |
724 | - stopTimer(); |
725 | - |
726 | - trackQueue.clear(); |
727 | - |
728 | - for (i=0; i < searchPaths.length; i++) { |
729 | - model = musicStore.lookup(searchPaths[i]) |
730 | - |
731 | - trackQueue.append(makeDict(model)); |
732 | - } |
733 | - |
734 | - trackQueueClick(0); |
735 | - } |
736 | - } |
737 | - } |
738 | - |
739 | - // UserMetrics to show Music stuff on welcome screen |
740 | - Metric { |
741 | - id: songsMetric |
742 | - name: "music-metrics" |
743 | - // TRANSLATORS: this refers to a number of songs greater than one. The actual number will be prepended to the string automatically (plural forms are not yet fully supported in usermetrics, the library that displays that string) |
744 | - format: "<b>%1</b> " + i18n.tr("songs played today") |
745 | - emptyFormat: i18n.tr("No songs played today") |
746 | - domain: "com.ubuntu.music" |
747 | - } |
748 | - |
749 | - // Connections for usermetrics |
750 | - Connections { |
751 | - id: userMetricPlayerConnection |
752 | - target: player |
753 | - property bool songCounted: false |
754 | - |
755 | - onSourceChanged: { |
756 | - songCounted = false |
757 | - } |
758 | - |
759 | - onPositionChanged: { |
760 | - // Increment song count on Welcome screen if song has been |
761 | - // playing for over 10 seconds. |
762 | - if (player.position > 10000 && !songCounted) { |
763 | - songCounted = true |
764 | - songsMetric.increment() |
765 | - console.debug("Increment UserMetrics") |
766 | - } |
767 | - } |
768 | + } |
769 | + |
770 | + UserMetricsHelper { |
771 | + id: userMetrics |
772 | } |
773 | |
774 | // Design stuff |
775 | @@ -486,31 +208,8 @@ |
776 | } |
777 | } |
778 | |
779 | - // A timer to wait for a worker to stop |
780 | - Timer { |
781 | + WorkerWaiter { |
782 | id: waitForWorker |
783 | - interval: 16 |
784 | - repeat: true |
785 | - |
786 | - property var func |
787 | - property var params // don't use args/arguments as they are already defined/internal |
788 | - property WorkerScript worker |
789 | - |
790 | - onTriggered: { |
791 | - if (worker.processing === 0) { |
792 | - stop() |
793 | - func.apply(this, params) |
794 | - } |
795 | - } |
796 | - |
797 | - // Waits until the worker has stopped and then calls the func(*params) |
798 | - function workerStop(worker, func, params) |
799 | - { |
800 | - waitForWorker.func = func |
801 | - waitForWorker.params = params |
802 | - waitForWorker.worker = worker |
803 | - start() |
804 | - } |
805 | } |
806 | |
807 | // Run on startup |
808 | @@ -1252,7 +951,7 @@ |
809 | id: emptyPageLoader |
810 | // Do not be active if content-hub is importing due to the models resetting |
811 | // this then causes the empty page loader to partially run then showing a blank header |
812 | - active: noMusic && !firstRun && contentHubWaitForFile.processId === -1 |
813 | + active: noMusic && !firstRun && !contentHub.processing |
814 | anchors { |
815 | fill: parent |
816 | } |
PASSED: Continuous integration, rev:841 91.189. 93.70:8080/ job/music- app-refactor- ci/40/ 91.189. 93.70:8080/ job/generic- mediumtests- vivid/1082 91.189. 93.70:8080/ job/generic- mediumtests- vivid/1082/ artifact/ work/output/ *zip*/output. zip 91.189. 93.70:8080/ job/music- app-refactor- vivid-amd64- ci/40
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/40/rebuild
http://