Merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/content-hub-support into lp:ubuntu-docviewer-app/trunk

Proposed by Stefano Verzegnassi
Status: Merged
Approved by: Stefano Verzegnassi
Approved revision: 45
Merged at revision: 39
Proposed branch: lp:~verzegnassi-stefano/ubuntu-docviewer-app/content-hub-support
Merge into: lp:ubuntu-docviewer-app/trunk
Prerequisite: lp:~verzegnassi-stefano/ubuntu-docviewer-app/fix-1387651-1387023
Diff against target: 431 lines (+216/-35)
14 files modified
CMakeLists.txt (+2/-2)
docviewer-content.json (+7/-0)
docviewer.apparmor (+4/-2)
manifest.json.in (+4/-3)
src/app/main.cpp (+3/-0)
src/app/qml/ContentHubProxy.qml (+38/-0)
src/app/qml/DetailsPage.qml (+3/-2)
src/app/qml/ErrorDialog.qml (+16/-0)
src/app/qml/ImageView.qml (+16/-0)
src/app/qml/PdfView.qml (+13/-1)
src/app/qml/TextView.qml (+16/-0)
src/app/qml/WelcomePage.qml (+51/-0)
src/app/qml/ubuntu-docviewer-app.qml (+35/-22)
tests/autopilot/ubuntu_docviewer_app/tests/test_docviewer.py (+8/-3)
To merge this branch: bzr merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/content-hub-support
Reviewer Review Type Date Requested Status
Arthur Mello (community) Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Ubuntu Document Viewer Developers Pending
Review via email: mp+240331@code.launchpad.net

Commit message

Added ContentHub support

Description of the change

Now we support ContentHub to load documents through other apps.
There are two ways to load a document on the device:
1) From the Application scope: a "welcome" page is shown and user can choose a peer from the list.
2) From an external app: e.g. ubuntu-filemanager-app. docviewer-app will appear in the list of apps that can import that type of content.

KNOWN ISSUES:
* On a device, 'Creation Date' always refers to the moment we import some content from the ContentHub. This is because ContentHub creates a new copy of the file in "$HOME/.cache".

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
42. By Stefano Verzegnassi

Fixed autopilot error: 'Too many blank lines'

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
43. By Stefano Verzegnassi

Added header backAction in imageView and textView

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
44. By Stefano Verzegnassi

It's called head.backAction...

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
45. By Stefano Verzegnassi

Fixed issue with ContentPeerPicker (binding loop for visible property while importing a file from an external source)

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

Code looks good to me.
I tested the branch opening PDF files from the Browser and the GMail web app and it worked as expected.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2014-10-21 13:23:11 +0000
+++ CMakeLists.txt 2014-11-04 18:55:53 +0000
@@ -54,11 +54,11 @@
54 set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")54 set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")
55 set(BIN_DIR /lib/${ARCH_TRIPLET}/bin)55 set(BIN_DIR /lib/${ARCH_TRIPLET}/bin)
56 set(DATA_DIR /)56 set(DATA_DIR /)
57 set (ICON ${ICON_FILE})57 set(ICON ${ICON_FILE})
58 set(DESKTOP_DIR ${DATA_DIR})58 set(DESKTOP_DIR ${DATA_DIR})
59 set(URLS_DIR ${DATA_DIR})59 set(URLS_DIR ${DATA_DIR})
60 configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)60 configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)
61 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json docviewer.apparmor61 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json docviewer.apparmor docviewer-content.json
62 DESTINATION ${CMAKE_INSTALL_PREFIX})62 DESTINATION ${CMAKE_INSTALL_PREFIX})
63 # Make the click files visible in Qt Creator63 # Make the click files visible in Qt Creator
64 file(GLOB CLICK_FILES64 file(GLOB CLICK_FILES
6565
=== added file 'docviewer-content.json'
--- docviewer-content.json 1970-01-01 00:00:00 +0000
+++ docviewer-content.json 2014-11-04 18:55:53 +0000
@@ -0,0 +1,7 @@
1{
2 "destination": [
3 "pictures",
4 "documents",
5 "unknown"
6 ]
7}
08
=== modified file 'docviewer.apparmor'
--- docviewer.apparmor 2014-09-24 04:46:27 +0000
+++ docviewer.apparmor 2014-11-04 18:55:53 +0000
@@ -1,4 +1,6 @@
1{1{
2 "policy_groups": [],2 "policy_groups": [
3 "content_exchange"
4 ],
3 "policy_version": 1.25 "policy_version": 1.2
4}
5\ No newline at end of file6\ No newline at end of file
7}
68
=== modified file 'manifest.json.in'
--- manifest.json.in 2014-11-04 18:55:53 +0000
+++ manifest.json.in 2014-11-04 18:55:53 +0000
@@ -1,14 +1,15 @@
1{1{
2 "description": "Document Viewer application for Ubuntu devices",2 "description": "Document Viewer application for Ubuntu devices",
3 "framework": "ubuntu-sdk-14.10-qml-dev3",3 "framework": "ubuntu-sdk-14.10-qml-dev3",
4 "architecture": "all",4 "architecture": "@CLICK_ARCH@",
5 "hooks": {5 "hooks": {
6 "docviewer": {6 "docviewer": {
7 "apparmor": "docviewer.apparmor",7 "apparmor": "docviewer.apparmor",
8 "desktop": "com.ubuntu.docviewer.desktop"8 "desktop": "com.ubuntu.docviewer.desktop",
9 "content-hub": "docviewer-content.json"
9 }10 }
10 },11 },
11 "maintainer": "Stefano Verzegnassi <stefano92.100@gmail.com>",12 "maintainer": "Ubuntu App Cats <ubuntu-touch-coreapps@lists.launchpad.net>",
12 "name": "com.ubuntu.docviewer",13 "name": "com.ubuntu.docviewer",
13 "title": "Document viewer",14 "title": "Document viewer",
14 "version": "0.1.@BZR_REVNO@"15 "version": "0.1.@BZR_REVNO@"
1516
=== modified file 'src/app/main.cpp'
--- src/app/main.cpp 2014-10-08 05:09:22 +0000
+++ src/app/main.cpp 2014-11-04 18:55:53 +0000
@@ -122,6 +122,9 @@
122 cacheDir.mkpath(cacheDir.absolutePath());122 cacheDir.mkpath(cacheDir.absolutePath());
123 }123 }
124124
125 // Expose quit() signal to QML
126 QObject::connect(view.engine(), SIGNAL(quit()), &a, SLOT(quit()));
127
125 qDebug() << "using main qml file from:" << qmlfile;128 qDebug() << "using main qml file from:" << qmlfile;
126 view.setSource(QUrl::fromLocalFile(qmlfile));129 view.setSource(QUrl::fromLocalFile(qmlfile));
127 view.show();130 view.show();
128131
=== added file 'src/app/qml/ContentHubProxy.qml'
--- src/app/qml/ContentHubProxy.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/ContentHubProxy.qml 2014-11-04 18:55:53 +0000
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2012-2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18import Ubuntu.Content 1.1 as ContentHub
19
20QtObject {
21 property QtObject pageStack: null
22 property list<QtObject> objects: [
23 Connections {
24 target: ContentHub.ContentHub
25
26 onImportRequested: {
27 if (transfer.state === ContentHub.ContentTransfer.Charged) {
28 // We have no signals to know if an import was requested before Component.completed signal
29 // is emitted. So clear the stack when this occurs.
30 pageStack.clear()
31
32 console.log("[CONTENT-HUB] Incoming Import Request")
33 file.path = transfer.items[0].url.toString().replace("file://", "");
34 }
35 }
36 }
37 ]
38}
039
=== modified file 'src/app/qml/DetailsPage.qml'
--- src/app/qml/DetailsPage.qml 2014-10-28 22:41:46 +0000
+++ src/app/qml/DetailsPage.qml 2014-11-04 18:55:53 +0000
@@ -6,6 +6,8 @@
66
7Page {7Page {
8 id: detailsPage8 id: detailsPage
9 objectName: "detailsPage"
10
9 title: i18n.tr("Details")11 title: i18n.tr("Details")
1012
11 Column {13 Column {
@@ -22,7 +24,6 @@
2224
23 ListItem.Subtitled {25 ListItem.Subtitled {
24 text: i18n.tr("Created")26 text: i18n.tr("Created")
25 // FIXME: the creationTime property is not yet available
26 subText: file.creationTime.toLocaleString(Qt.locale())27 subText: file.creationTime.toLocaleString(Qt.locale())
27 }28 }
2829
@@ -35,7 +36,7 @@
35 id: mimetypeItem36 id: mimetypeItem
36 objectName: "mimetypeItem"37 objectName: "mimetypeItem"
37 text: i18n.tr("MIME type")38 text: i18n.tr("MIME type")
38 subText: mainView.mimetype39 subText: file.mimetype
39 }40 }
40 }41 }
41}42}
4243
=== added file 'src/app/qml/ErrorDialog.qml'
--- src/app/qml/ErrorDialog.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/ErrorDialog.qml 2014-11-04 18:55:53 +0000
@@ -0,0 +1,16 @@
1import QtQuick 2.3
2import Ubuntu.Components 1.1
3import Ubuntu.Components.Popups 1.0
4
5Dialog {
6 id: errorDialogue
7 title: i18n.tr("Error")
8 text: i18n.tr("File does not exist")
9
10 Button {
11 text: i18n.tr("Close")
12 color: "red"
13
14 onClicked: Qt.quit();
15 }
16}
017
=== modified file 'src/app/qml/ImageView.qml'
--- src/app/qml/ImageView.qml 2014-10-20 20:31:41 +0000
+++ src/app/qml/ImageView.qml 2014-11-04 18:55:53 +0000
@@ -7,8 +7,24 @@
7 id: pageMain7 id: pageMain
8 title: Utils.getNameOfFile(file.path);8 title: Utils.getNameOfFile(file.path);
99
10 head.backAction: Action {
11 iconName: "back"
12 text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
13 onTriggered: {
14 if (pageStack.depth > 1) {
15 // Go back to Welcome page
16 pageStack.pop();
17 } else {
18 // File has been imported through Content Hub (or was not chosen through WelcomePage)
19 // Close the application and show our source app (e.g. ubuntu-filemanager-app if used to open a document)
20 Qt.quit()
21 }
22 }
23 }
24
10 head.actions: [25 head.actions: [
11 Action {26 Action {
27 objectName: "detailsAction"
12 text: i18n.tr("Details")28 text: i18n.tr("Details")
13 iconName: "info"29 iconName: "info"
14 onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))30 onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
1531
=== modified file 'src/app/qml/PdfView.qml'
--- src/app/qml/PdfView.qml 2014-11-04 18:55:53 +0000
+++ src/app/qml/PdfView.qml 2014-11-04 18:55:53 +0000
@@ -47,7 +47,7 @@
47 /* FIXME: Don't set 'path' property directly, but set it through onCompleted signal.47 /* FIXME: Don't set 'path' property directly, but set it through onCompleted signal.
48 By doing otherwise, PDF pages are loaded two times, but only48 By doing otherwise, PDF pages are loaded two times, but only
49 the first delegates are working. Asking to the image provider49 the first delegates are working. Asking to the image provider
50 to get the second ones makes the app instable.50 to get the second ones, makes the app instable.
51 (e.g. We have a PDF document with 10 pages. The plugin loads51 (e.g. We have a PDF document with 10 pages. The plugin loads
52 them twice - 2x10 = 20 pages - but only the first 10 are shown.52 them twice - 2x10 = 20 pages - but only the first 10 are shown.
53 While trying to get the 11th, the app crashes). */53 While trying to get the 11th, the app crashes). */
@@ -126,6 +126,17 @@
126126
127 backAction: Action {127 backAction: Action {
128 iconName: "back"128 iconName: "back"
129 text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
130 onTriggered: {
131 if (pageStack.depth > 1) {
132 // Go back to Welcome page
133 pageStack.pop();
134 } else {
135 // File has been imported through Content Hub (or was not chosen through WelcomePage)
136 // Close the application and show our source app (e.g. ubuntu-filemanager-app if used to open a document)
137 Qt.quit()
138 }
139 }
129 }140 }
130141
131 actions: [142 actions: [
@@ -143,6 +154,7 @@
143 },154 },
144155
145 Action {156 Action {
157 objectName: "detailsAction"
146 text: i18n.tr("Details")158 text: i18n.tr("Details")
147 iconName: "info"159 iconName: "info"
148 onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))160 onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
149161
=== modified file 'src/app/qml/TextView.qml'
--- src/app/qml/TextView.qml 2014-10-21 15:15:11 +0000
+++ src/app/qml/TextView.qml 2014-11-04 18:55:53 +0000
@@ -8,8 +8,24 @@
8 id: pageMain8 id: pageMain
9 title: Utils.getNameOfFile(file.path);9 title: Utils.getNameOfFile(file.path);
1010
11 head.backAction: Action {
12 iconName: "back"
13 text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
14 onTriggered: {
15 if (pageStack.depth > 1) {
16 // Go back to Welcome page
17 pageStack.pop();
18 } else {
19 // File has been imported through Content Hub (or was not chosen through WelcomePage)
20 // Close the application and show our source app (e.g. ubuntu-filemanager-app if used to open a document)
21 Qt.quit()
22 }
23 }
24 }
25
11 head.actions: [26 head.actions: [
12 Action {27 Action {
28 objectName: "detailsAction"
13 text: i18n.tr("Details")29 text: i18n.tr("Details")
14 iconName: "info"30 iconName: "info"
15 onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))31 onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
1632
=== added file 'src/app/qml/WelcomePage.qml'
--- src/app/qml/WelcomePage.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/WelcomePage.qml 2014-11-04 18:55:53 +0000
@@ -0,0 +1,51 @@
1import QtQuick 2.0
2import Ubuntu.Components 1.1
3import Ubuntu.Content 1.1
4
5Page {
6 id: picker
7
8 property var activeTransfer
9
10 ContentTransferHint {
11 id: transferHint
12 anchors.fill: parent
13 activeTransfer: picker.activeTransfer
14 }
15
16 title: i18n.tr("Open with...")
17 head.sections.model: [i18n.tr("Pictures"), i18n.tr("Documents"), i18n.tr("Unknown")]
18 head.backAction: Action {
19 iconName: "close"
20 text: i18n.tr("Close")
21 onTriggered: Qt.quit()
22 }
23
24 ContentPeerPicker {
25 showTitle: false
26
27 contentType: {
28 switch (picker.head.sections.selectedIndex) {
29 case 0:
30 return ContentType.Pictures
31 case 1:
32 return ContentType.Documents
33 case 2:
34 return ContentType.Unknown
35 }
36 }
37 handler: ContentHandler.Source
38
39 onPeerSelected: picker.activeTransfer = peer.request();
40 }
41
42 Connections {
43 target: picker.activeTransfer ? picker.activeTransfer : null
44 onStateChanged: {
45 if (picker.activeTransfer.state === ContentTransfer.Charged) {
46 file.path = picker.activeTransfer.items[0].url.toString().replace("file://", "")
47 console.log("[CONTENT-HUB] Content imported!")
48 }
49 }
50 }
51}
052
=== modified file 'src/app/qml/ubuntu-docviewer-app.qml'
--- src/app/qml/ubuntu-docviewer-app.qml 2014-11-04 18:55:53 +0000
+++ src/app/qml/ubuntu-docviewer-app.qml 2014-11-04 18:55:53 +0000
@@ -15,11 +15,11 @@
15 width: units.gu(50)15 width: units.gu(50)
16 height: units.gu(75)16 height: units.gu(75)
1717
18 property string mimetype: "none"18 Arguments {
19
20 Arguments {
21 id: args19 id: args
2220
21 // It returns "expected argument" message when not specified a path.
22 // It works anyway, but it may be worth to use Argument{} in future
23 defaultArgument.help: "Path of the document"23 defaultArgument.help: "Path of the document"
24 defaultArgument.valueNames: ["path"]24 defaultArgument.valueNames: ["path"]
25 }25 }
@@ -27,29 +27,42 @@
27 File {27 File {
28 objectName: "fileObject"28 objectName: "fileObject"
29 id: file29 id: file
30 path: args.defaultArgument.at(0)30
3131 onMimetypeChanged: LoadComponent.load(mimetype)
32 onMimetypeChanged: mainView.mimetype = LoadComponent.load(file.mimetype);32 onErrorChanged: { if (error == -1); PopupUtils.open(errorDialog) }
33 }33 }
3434
35 PageStack {35 Component.onCompleted: {
36 id: pageStack36 // Check if a value has been specified for "path" argument
3737 if (args.defaultArgument.at(0)) {
38 Component {38 // If so, send the path to the File plugin
39 DetailsPage {39 console.log("Path argument is:", args.defaultArgument.at(0))
40 objectName: "TabDetails"40 file.path = args.defaultArgument.at(0)
41 id: tabDetails;41 } else {
42 // Otherwise, push a welcome screen in the stack
43 pageStack.push(Qt.resolvedUrl("WelcomePage.qml"))
44 }
45 }
46
47 // Content Importer
48 Loader {
49 id: contentHubLoader
50
51 asynchronous: true
52 source: Qt.resolvedUrl("ContentHubProxy.qml")
53 onStatusChanged: {
54 if (status === Loader.Ready) {
55 item.pageStack = pageStack
42 }56 }
43 }57 }
44 }58 }
4559
46 Component {60 function runUnknownTypeDialog() {
47 id: unknownTypeDialog
48 UnknownTypeDialog {}
49 }
50
51 function runUnknownTypeDialog()
52 {
53 PopupUtils.open(unknownTypeDialog);61 PopupUtils.open(unknownTypeDialog);
54 }62 }
63
64 PageStack { id: pageStack }
65
66 Component { id: errorDialog; ErrorDialog {} }
67 Component { id: unknownTypeDialog; UnknownTypeDialog {} }
55}68}
5669
=== modified file 'tests/autopilot/ubuntu_docviewer_app/tests/test_docviewer.py'
--- tests/autopilot/ubuntu_docviewer_app/tests/test_docviewer.py 2014-10-28 22:01:16 +0000
+++ tests/autopilot/ubuntu_docviewer_app/tests/test_docviewer.py 2014-11-04 18:55:53 +0000
@@ -74,10 +74,15 @@
74 self.check_mimeType()74 self.check_mimeType()
7575
76 def check_mimeType(self):76 def check_mimeType(self):
77 # Click "Details" action in the header
78 header = self.main_view.get_header()
79 header.click_action_button('detailsAction')
80
81 mimetypeItem = self.main_view.select_single(
82 "Subtitled", objectName="mimetypeItem")
83
77 self.assertThat(84 self.assertThat(
78 self.app.select_single("MainView",85 mimetypeItem.subText, Eventually(NotEquals(False)))
79 objectName="docviewer").mimetype,
80 Eventually(NotEquals(False)))
8186
82 def test_unknown_file_type(self):87 def test_unknown_file_type(self):
83 filePath = 'ubuntu_docviewer_app/files/unknown.type'88 filePath = 'ubuntu_docviewer_app/files/unknown.type'

Subscribers

People subscribed via source and target branches