Merge lp:~michael-sheldon/webbrowser-app/general-download-support into lp:webbrowser-app

Proposed by Michael Sheldon
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 593
Merged at revision: 617
Proposed branch: lp:~michael-sheldon/webbrowser-app/general-download-support
Merge into: lp:webbrowser-app
Diff against target: 444 lines (+276/-23)
9 files modified
debian/control (+2/-2)
src/app/ContentDownloadDialog.qml (+2/-2)
src/app/ContentPickerDialog.qml (+6/-1)
src/app/ContentShareDialog.qml (+2/-2)
src/app/Downloader.qml (+26/-11)
src/app/FileExtensionMapper.js (+211/-0)
src/app/MimeTypeMapper.js (+3/-1)
src/app/Share.qml (+5/-4)
src/app/WebViewImpl.qml (+19/-0)
To merge this branch: bzr merge lp:~michael-sheldon/webbrowser-app/general-download-support
Reviewer Review Type Date Requested Status
Olivier Tilloy Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+225143@code.launchpad.net

Commit message

Add support for downloads via content-hub on non-desktop devices when it's either not possible to render a file within the browser itself or when a download is explicitly requested via the Content-Disposition header.

Description of the change

Adds support for downloads via content-hub on non-desktop devices when it's either not possible to render a file within the browser itself or when a download is explicitly requested via the Content-Disposition header.

To post a comment you must log in.
585. By Michael Sheldon

Merge from trunk

586. By Michael Sheldon

Even out bracket spacing

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

Testing with the latest oxide built from trunk (revision 634) and ubuntu-download-manager built from revision 320 of https://code.launchpad.net/~mandel/ubuntu-download-manager/expose-property/+merge/223874, and downloading image attachments from gmail works. Trying to download an mp4 video attachment results in a message that tells me there is no app installed that can handle this type of content. Is that expected? The same happens for PDF, but I know this is expected.

Revision history for this message
Olivier Tilloy (osomon) wrote :

315 + headers["Referer"] = request.referrer

It seems "referer" is a common mispelling of "referrer", would that be a bug/typo in UDM?

317 + headers["User-Agent"] = webview.context.userAgent

This won’t get us the overridden UA if any, it’s probably good enough in most cases but I would bet some corner cases will fail because the download is not requested with the same UA as the one that was used to request the parent page.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

It looks like Ken's branch for adding video as one of gallery's accepted types was never merged: https://code.launchpad.net/~ken-vandine/gallery-app/register_for_videos

I'll propose something new for that tomorrow.

The "Referer" spelling is pretty interesting and something I only found out about whilst implementing this; it's actually a misspelling carried forward from the original HTTP spec, so the correct header for HTTP requests is "Referer" instead of "Referrer" (http://en.wikipedia.org/wiki/HTTP_referer#Origin_of_the_term_referer has a bit of detail on that).

Is there a mechanism by which we could be getting the overridden user agent?

Revision history for this message
Olivier Tilloy (osomon) wrote :

> The "Referer" spelling is pretty interesting and something I only found out
> about whilst implementing this; it's actually a misspelling carried forward
> from the original HTTP spec, so the correct header for HTTP requests is
> "Referer" instead of "Referrer"
> (http://en.wikipedia.org/wiki/HTTP_referer#Origin_of_the_term_referer has a
> bit of detail on that).

Interesting. Thanks for the pointer, I learnt some history today :)

> Is there a mechanism by which we could be getting the overridden user agent?

Not without modifying the UA override mechanism. I see a few options:

 - In UbuntuWebContext, in the message handler for the networkRequestDelegate, we could store the url and corresponding override in a dictionary that would be exposed as a property (or a method) of the context. We would then query this dictionary to get the overridden UA for the URL of the current page, and if not found, use the default.

 - Alternatively, we could expose the UA override mechanism as a method of the context, but that’s not necessarily trivial as the mechanism involves user scripts which would need to be refactored to be exposed as generic JS libs.

 - Finally, another option would be to add an API to oxide itself to expose the HTTP headers for the current page, that might be useful for other use cases.

What do you think? In case you reckon option #1 is reasonable, feel free to go ahead with it (it shouldn’t be too much work). Other options look more involved, so I think it’s OK to go with the current implementation for now (but in that case please file a bug report and add a comment that points to it).

587. By Michael Sheldon

Merge from trunk

Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Are there any related MPs required for this MP to build/function as expected? Please list.

 * Requires oxide trunk release
 * https://code.launchpad.net/~mandel/ubuntu-download-manager/expose-property/+merge/223874

Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes)

 * Yes

Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator?

 * Yes

Did you successfully run all tests found in your component's Test Plan (https://wiki.ubuntu.com/Process/Merges/TestPlan/webbrowser-app) on device or emulator?

 * Yes, except for youtube videos, which I assume is due to my local oxide build being built with default free ffmpeg codecs (I seem to remember this has to be rebuilt in some way to enable non-free codecs?) - Could someone confirm this?

If you changed the UI, was the change specified/approved by design?

 * No change

If you changed the packaging (debian), did you add a core-dev as a reviewer to this MP?

 * No change

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:587
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/922/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/1588/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/1355
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/121
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/121
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/121/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/121
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/1863/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/2589
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/2589/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/9324
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/1123
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1519
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1519/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/922/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

In debian/control, can you bump the required version of liboxideqt-qmlplugin to >= 1.1.0 ?

Note that the build-dep probably doesn’t need to be bumped, and neither does the runtime dep for qtdeclarative5-ubuntu-web-plugin, however runtime deps for webbrowser-app and webapp-container do.

588. By Michael Sheldon

Set required version of liboxideqt-qmlplugin to >= 1.1.0 for webbrowser-app and webapp-container

589. By Michael Sheldon

Add 'm4v' to file extension mapper

590. By Michael Sheldon

Merge from trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
591. By Michael Sheldon

Use PopupUtils open and close methods instead of experimental show/hide

592. By Michael Sheldon

Pass content picker popup parameters as part of PopupUtils.open call

593. By Michael Sheldon

Change liboxideqt-qmlplugin version requirement to >= 1.1 for webbrowser-app and webapp-container

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:590
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/931/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/1744/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/1468/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/130
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/130
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/130/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/130
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/2006/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/2800
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/2800/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/9529
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/1224/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1650
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1650/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/931/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2014-07-04 15:05:13 +0000
3+++ debian/control 2014-07-09 13:31:51 +0000
4@@ -33,7 +33,7 @@
5 Depends: ${misc:Depends},
6 ${shlibs:Depends},
7 fonts-liberation,
8- liboxideqt-qmlplugin (>= 1.0.2),
9+ liboxideqt-qmlplugin (>= 1.1),
10 libqt5sql5-sqlite,
11 qtdeclarative5-dialogs-plugin,
12 qtdeclarative5-qtquick2-plugin,
13@@ -56,7 +56,7 @@
14 Depends: ${misc:Depends},
15 ${shlibs:Depends},
16 fonts-liberation,
17- liboxideqt-qmlplugin (>= 1.0.2),
18+ liboxideqt-qmlplugin (>= 1.1),
19 libqt5sql5-sqlite,
20 libqt5webkit5-qmlwebkitplugin,
21 qtdeclarative5-accounts-plugin,
22
23=== modified file 'src/app/ContentDownloadDialog.qml'
24--- src/app/ContentDownloadDialog.qml 2014-05-05 15:31:21 +0000
25+++ src/app/ContentDownloadDialog.qml 2014-07-09 13:31:51 +0000
26@@ -39,11 +39,11 @@
27 activeTransfer = peer.request()
28 activeTransfer.downloadId = downloadDialog.downloadId
29 activeTransfer.state = ContentTransfer.Downloading
30- downloadDialog.hide()
31+ PopupUtils.close(downloadDialog)
32 }
33
34 onCancelPressed: {
35- downloadDialog.hide()
36+ PopupUtils.close(downloadDialog)
37 }
38 }
39 }
40
41=== modified file 'src/app/ContentPickerDialog.qml'
42--- src/app/ContentPickerDialog.qml 2014-05-22 16:11:25 +0000
43+++ src/app/ContentPickerDialog.qml 2014-07-09 13:31:51 +0000
44@@ -93,7 +93,12 @@
45
46 Component.onCompleted: {
47 if(acceptTypes.length === 1) {
48- peerPicker.contentType = MimeTypeMapper.mimeTypeToContentType(acceptTypes[0])
49+ var contentType = MimeTypeMapper.mimeTypeToContentType(acceptTypes[0])
50+ if(contentType == ContentType.Unknown) {
51+ // If we don't recognise the type, allow uploads from any app
52+ contentType = ContentType.All
53+ }
54+ peerPicker.contentType = contentType
55 } else {
56 peerPicker.contentType = ContentType.All
57 }
58
59=== modified file 'src/app/ContentShareDialog.qml'
60--- src/app/ContentShareDialog.qml 2014-06-17 14:32:58 +0000
61+++ src/app/ContentShareDialog.qml 2014-07-09 13:31:51 +0000
62@@ -39,11 +39,11 @@
63 activeTransfer = peer.request()
64 activeTransfer.items = shareDialog.items
65 activeTransfer.state = ContentTransfer.Charged
66- shareDialog.hide()
67+ PopupUtils.close(shareDialog)
68 }
69
70 onCancelPressed: {
71- shareDialog.hide()
72+ PopupUtils.close(shareDialog)
73 }
74 }
75 }
76
77=== modified file 'src/app/Downloader.qml'
78--- src/app/Downloader.qml 2014-05-12 10:13:50 +0000
79+++ src/app/Downloader.qml 2014-07-09 13:31:51 +0000
80@@ -18,34 +18,49 @@
81
82 import QtQuick 2.0
83 import Ubuntu.Components 0.1
84+import Ubuntu.Components.Popups 0.1
85 import Ubuntu.DownloadManager 0.1
86 import Ubuntu.Content 0.1
87+import "MimeTypeMapper.js" as MimeTypeMapper
88+import "FileExtensionMapper.js" as FileExtensionMapper
89
90 Item {
91+ id: downloadItem
92
93- ContentDownloadDialog {
94+ Component {
95 id: downloadDialog
96+ ContentDownloadDialog { }
97 }
98
99 SingleDownload {
100 id: singleDownload
101 autoStart: false
102+ property var contentType
103 onDownloadIdChanged: {
104- downloadDialog.downloadId = singleDownload.downloadId
105- downloadDialog.show()
106+ PopupUtils.open(downloadDialog, downloadItem, {"contentType" : singleDownload.contentType, "downloadId" : singleDownload.downloadId})
107 }
108 }
109
110- function download(url, contentType) {
111- if(contentType) {
112- downloadDialog.contentType = contentType
113- } else {
114- downloaddialog.contentType = ContentType.All
115+ function download(url, contentType, headers) {
116+ singleDownload.contentType = contentType
117+ if(headers) {
118+ singleDownload.headers = headers
119 }
120 singleDownload.download(url)
121 }
122
123- function downloadPicture(url) {
124- download(url, ContentType.Pictures)
125- }
126+ function downloadPicture(url, headers) {
127+ download(url, ContentType.Pictures, headers)
128+ }
129+
130+ function downloadMimeType(url, mimeType, headers, filename) {
131+ var contentType = MimeTypeMapper.mimeTypeToContentType(mimeType)
132+ if (contentType == ContentType.Unknown && filename) {
133+ // If we can't determine the content type from the mime-type
134+ // attempt to discover it from the file extension
135+ contentType = FileExtensionMapper.filenameToContentType(filename)
136+ }
137+ download(url, contentType, headers)
138+ }
139+
140 }
141
142=== added file 'src/app/FileExtensionMapper.js'
143--- src/app/FileExtensionMapper.js 1970-01-01 00:00:00 +0000
144+++ src/app/FileExtensionMapper.js 2014-07-09 13:31:51 +0000
145@@ -0,0 +1,211 @@
146+/*
147+ * Copyright 2014 Canonical Ltd.
148+ *
149+ * This file is part of webbrowser-app.
150+ *
151+ * webbrowser-app is free software; you can redistribute it and/or modify
152+ * it under the terms of the GNU General Public License as published by
153+ * the Free Software Foundation; version 3.
154+ *
155+ * webbrowser-app is distributed in the hope that it will be useful,
156+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
157+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
158+ * GNU General Public License for more details.
159+ *
160+ * You should have received a copy of the GNU General Public License
161+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
162+*/
163+
164+// Constructed from /etc/mime.types
165+function filenameToContentType(filename) {
166+ var filenameParts = filename.split(".");
167+ if(filenameParts.length === 1 || (filenameParts[0] === "" && filenameParts.length === 2)) {
168+ return ContentType.Unknown;
169+ }
170+ var ext = filenameParts.pop().toLowerCase();
171+ switch(ext) {
172+ case "art":
173+ case "bmp":
174+ case "cdr":
175+ case "cdt":
176+ case "cpt":
177+ case "cr2":
178+ case "crw":
179+ case "djv":
180+ case "djvu":
181+ case "erf":
182+ case "gif":
183+ case "ico":
184+ case "ief":
185+ case "jng":
186+ case "jp2":
187+ case "jpe":
188+ case "jpeg":
189+ case "jpf":
190+ case "jpg":
191+ case "jpg2":
192+ case "jpm":
193+ case "jpx":
194+ case "nef":
195+ case "orf":
196+ case "pat":
197+ case "pbm":
198+ case "pcx":
199+ case "pgm":
200+ case "png":
201+ case "pnm":
202+ case "ppm":
203+ case "psd":
204+ case "ras":
205+ case "rgb":
206+ case "svg":
207+ case "svgz":
208+ case "tif":
209+ case "tiff":
210+ case "wbmp":
211+ case "xbm":
212+ case "xpm":
213+ case "xwd":
214+ return ContentType.Pictures;
215+ case "3gp":
216+ case "asf":
217+ case "asx":
218+ case "avi":
219+ case "axv":
220+ case "dif":
221+ case "dl":
222+ case "dv":
223+ case "fli":
224+ case "flv":
225+ case "gl":
226+ case "lsf":
227+ case "lsx":
228+ case "m4v":
229+ case "mkv":
230+ case "mng":
231+ case "mov":
232+ case "movie":
233+ case "mp4":
234+ case "mpe":
235+ case "mpeg":
236+ case "mpg":
237+ case "mpv":
238+ case "mxu":
239+ case "ogv":
240+ case "qt":
241+ case "ts":
242+ case "webm":
243+ case "wm":
244+ case "wmv":
245+ case "wmx":
246+ case "wvx":
247+ return ContentType.Videos;
248+ case "aif":
249+ case "aifc":
250+ case "aiff":
251+ case "amr":
252+ case "au":
253+ case "awb":
254+ case "axa":
255+ case "csd":
256+ case "flac":
257+ case "gsm":
258+ case "kar":
259+ case "m3u":
260+ case "m4a":
261+ case "mid":
262+ case "midi":
263+ case "mp2":
264+ case "mp3":
265+ case "mpega":
266+ case "mpga":
267+ case "oga":
268+ case "ogg":
269+ case "opus":
270+ case "orc":
271+ case "pls":
272+ case "ra":
273+ case "ram":
274+ case "rm":
275+ case "sco":
276+ case "sd2":
277+ case "sid":
278+ case "snd":
279+ case "spx":
280+ case "wav":
281+ case "wax":
282+ case "wma":
283+ return ContentType.Music;
284+ case "vcard":
285+ case "vcf":
286+ return ContentType.Contacts;
287+ case "323":
288+ case "appcache":
289+ case "asc":
290+ case "bib":
291+ case "boo":
292+ case "brf":
293+ case "c":
294+ case "c++":
295+ case "cc":
296+ case "cls":
297+ case "cpp":
298+ case "csh":
299+ case "css":
300+ case "csv":
301+ case "cxx":
302+ case "d":
303+ case "diff":
304+ case "etx":
305+ case "gcd":
306+ case "h":
307+ case "hh":
308+ case "h++":
309+ case "hpp":
310+ case "hs":
311+ case "htc":
312+ case "htm":
313+ case "html":
314+ case "hxx":
315+ case "ics":
316+ case "icz":
317+ case "jad":
318+ case "java":
319+ case "lhs":
320+ case "ltx":
321+ case "ly":
322+ case "mml":
323+ case "moc":
324+ case "p":
325+ case "pas":
326+ case "patch":
327+ case "pl":
328+ case "pm":
329+ case "pot":
330+ case "py":
331+ case "rtx":
332+ case "scala":
333+ case "sct":
334+ case "sfv":
335+ case "sh":
336+ case "shtml":
337+ case "srt":
338+ case "sty":
339+ case "tcl":
340+ case "tex":
341+ case "text":
342+ case "tk":
343+ case "tm":
344+ case "tsv":
345+ case "ttl":
346+ case "txt":
347+ case "uls":
348+ case "vcs":
349+ case "wml":
350+ case "wmls":
351+ case "wsc":
352+ return ContentType.Documents;
353+ default:
354+ return ContentType.Unknown;
355+ }
356+}
357
358=== modified file 'src/app/MimeTypeMapper.js'
359--- src/app/MimeTypeMapper.js 2014-05-22 20:03:22 +0000
360+++ src/app/MimeTypeMapper.js 2014-07-09 13:31:51 +0000
361@@ -22,11 +22,13 @@
362 return ContentType.Pictures;
363 } else if(mimeType.search("audio/") === 0) {
364 return ContentType.Music;
365+ } else if(mimeType.search("video/") === 0) {
366+ return ContentType.Videos;
367 } else if(mimeType.search("text/x-vcard") === 0) {
368 return ContentType.Contacts;
369 } else if(mimeType.search("text/") === 0) {
370 return ContentType.Documents;
371 } else {
372- return ContentType.All;
373+ return ContentType.Unknown;
374 }
375 }
376
377=== modified file 'src/app/Share.qml'
378--- src/app/Share.qml 2014-06-20 15:52:26 +0000
379+++ src/app/Share.qml 2014-07-09 13:31:51 +0000
380@@ -18,14 +18,16 @@
381
382 import QtQuick 2.0
383 import Ubuntu.Components 0.1
384+import Ubuntu.Components.Popups 0.1
385 import Ubuntu.DownloadManager 0.1
386 import Ubuntu.Content 0.1
387
388 Item {
389 id: shareItem
390
391- ContentShareDialog {
392+ Component {
393 id: shareDialog
394+ ContentShareDialog { }
395 }
396
397 Component {
398@@ -34,9 +36,8 @@
399 }
400
401 function share(url, name, contentType) {
402- shareDialog.contentType = contentType
403- shareDialog.items.push(contentItemComponent.createObject(shareItem, {"url" : url, "name" : name}))
404- shareDialog.show()
405+ var sharePopup = PopupUtils.open(shareDialog, shareItem, {"contentType" : contentType})
406+ sharePopup.items.push(contentItemComponent.createObject(shareItem, {"url" : url, "name" : name}))
407 }
408
409 function shareLink(url, title) {
410
411=== modified file 'src/app/WebViewImpl.qml'
412--- src/app/WebViewImpl.qml 2014-06-25 17:07:29 +0000
413+++ src/app/WebViewImpl.qml 2014-07-09 13:31:51 +0000
414@@ -37,11 +37,30 @@
415 beforeUnloadDialog: BeforeUnloadDialog {}
416 filePicker: filePickerLoader.item
417
418+ onDownloadRequested: {
419+ if (downloadLoader.status == Loader.Ready) {
420+ var headers = { }
421+ if(request.cookies.length > 0) {
422+ headers["Cookie"] = request.cookies.join(";")
423+ }
424+ if(request.referrer) {
425+ headers["Referer"] = request.referrer
426+ }
427+ headers["User-Agent"] = webview.context.userAgent
428+ downloadLoader.item.downloadMimeType(request.url, request.mimeType, headers, request.suggestedFilename)
429+ }
430+ }
431+
432 Loader {
433 id: filePickerLoader
434 source: formFactor == "desktop" ? "FilePickerDialog.qml" : "ContentPickerDialog.qml"
435 }
436
437+ Loader {
438+ id: downloadLoader
439+ source: formFactor == "desktop" ? "" : "Downloader.qml"
440+ }
441+
442 selectionActions: ActionList {
443 Actions.Copy {
444 onTriggered: copy()

Subscribers

People subscribed via source and target branches

to status/vote changes: