Merge lp:~mzanetti/reminders-app/contenthub into lp:reminders-app

Proposed by Michael Zanetti
Status: Merged
Approved by: Riccardo Padovani
Approved revision: 352
Merged at revision: 348
Proposed branch: lp:~mzanetti/reminders-app/contenthub
Merge into: lp:reminders-app
Prerequisite: lp:~mzanetti/reminders-app/listitemwithactions
Diff against target: 463 lines (+143/-53)
14 files modified
reminders.apparmor (+2/-1)
src/app/qml/components/NotesDelegate.qml (+9/-6)
src/app/qml/ui/NotePage.qml (+1/-1)
src/app/qml/ui/NoteView.qml (+51/-5)
src/app/qml/ui/reminders-scripts.js (+13/-3)
src/libqtevernote/evernoteconnection.cpp (+4/-2)
src/libqtevernote/note.cpp (+2/-0)
src/libqtevernote/note.h (+1/-1)
src/libqtevernote/notesstore.cpp (+4/-4)
src/libqtevernote/resource.cpp (+7/-2)
src/libqtevernote/resource.h (+2/-0)
src/libqtevernote/resourceimageprovider.cpp (+5/-2)
src/libqtevernote/utils/enmldocument.cpp (+40/-26)
src/libqtevernote/utils/enmldocument.h (+2/-0)
To merge this branch: bzr merge lp:~mzanetti/reminders-app/contenthub
Reviewer Review Type Date Requested Status
Riccardo Padovani Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+249894@code.launchpad.net

Commit message

Add better attachment handling and integrate with ContentHub

To post a comment you must log in.
348. By Michael Zanetti

cleanup

349. By Michael Zanetti

hide page title when in ContentPeerPicker

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

merge trunk

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
Riccardo Padovani (rpadovani) wrote :

lgtm, but I'm a bit puzzled by an if, see inline comment please :-)

review: Needs Information
351. By Michael Zanetti

drop a debug print

352. By Michael Zanetti

cleanup more debug prints

Revision history for this message
Riccardo Padovani (rpadovani) wrote :

Now it's perfect, thanks :-)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'reminders.apparmor'
2--- reminders.apparmor 2015-02-12 20:34:11 +0000
3+++ reminders.apparmor 2015-02-23 17:57:16 +0000
4@@ -7,7 +7,8 @@
5 "webview",
6 "push-notification-client",
7 "calendar",
8- "connectivity"
9+ "connectivity",
10+ "content_exchange_source"
11 ],
12 "policy_version": 1.2
13 }
14\ No newline at end of file
15
16=== modified file 'src/app/qml/components/NotesDelegate.qml'
17--- src/app/qml/components/NotesDelegate.qml 2015-02-23 11:31:34 +0000
18+++ src/app/qml/components/NotesDelegate.qml 2015-02-23 17:57:16 +0000
19@@ -94,15 +94,10 @@
20 anchors.fill: parent
21 spacing: 0
22
23- Rectangle {
24+ Item {
25 Layout.fillWidth: true
26 Layout.fillHeight: true
27
28- gradient: Gradient {
29- GradientStop{ position: 0.8; color: "transparent" }
30- GradientStop{ position: 1; color: "#d9d9d9" }
31- }
32-
33 RowLayout {
34 anchors.fill: parent
35 anchors.margins: units.gu(1)
36@@ -177,6 +172,14 @@
37 fillMode: Image.PreserveAspectCrop
38 }
39 }
40+ Rectangle {
41+ anchors.fill: parent
42+ gradient: Gradient {
43+ GradientStop{ position: 0.8; color: "transparent" }
44+ GradientStop{ position: 1; color: "#d9d9d9" }
45+ }
46+ }
47 }
48+
49 }
50 }
51
52=== modified file 'src/app/qml/ui/NotePage.qml'
53--- src/app/qml/ui/NotePage.qml 2014-12-10 18:09:10 +0000
54+++ src/app/qml/ui/NotePage.qml 2015-02-23 17:57:16 +0000
55@@ -23,7 +23,7 @@
56
57 Page {
58 id: root
59- title: noteView.title || i18n.tr("Untitled")
60+ title: noteView.title
61 property alias note: noteView.note
62
63 signal editNote(var note)
64
65=== modified file 'src/app/qml/ui/NoteView.qml'
66--- src/app/qml/ui/NoteView.qml 2014-12-10 18:09:10 +0000
67+++ src/app/qml/ui/NoteView.qml 2015-02-23 17:57:16 +0000
68@@ -19,12 +19,14 @@
69 import QtQuick 2.3
70 import Ubuntu.Components 1.1
71 import com.canonical.Oxide 1.0
72+import Ubuntu.Content 1.0
73 import Evernote 0.1
74 import "../components"
75
76 Item {
77 id: root
78- property string title: note ? note.title : ""
79+ property string title: contentPeerPicker.visible ? ""
80+ : note ? note.title : i18n.tr("Untitled")
81 property var note: null
82
83 signal openTaggedNotes(string title, string tagGuid)
84@@ -40,7 +42,7 @@
85
86 userScripts: [
87 UserScript {
88- context: 'reminders://todo'
89+ context: 'reminders://interaction'
90 url: Qt.resolvedUrl("reminders-scripts.js");
91 }
92 ]
93@@ -70,16 +72,32 @@
94
95 messageHandlers: [
96 ScriptMessageHandler {
97- msgId: 'todo'
98- contexts: ['reminders://todo']
99+ msgId: 'interaction'
100+ contexts: ['reminders://interaction']
101 callback: function(message, frame) {
102 var data = message.args;
103
104 switch (data.type) {
105- case "checkboxChanged":
106+ case "checkboxChanged":
107 note.markTodo(data.todoId, data.checked);
108 NotesStore.saveNote(note.guid);
109 break;
110+ case "attachmentOpened":
111+ var filePath = root.note.resource(data.resourceHash).hashedFilePath;
112+ contentPeerPicker.filePath = filePath;
113+
114+ if (data.mediaType == "application/pdf") {
115+ contentPeerPicker.contentType = ContentType.Documents;
116+ } else if (data.mediaType.split("/")[0] == "audio" ) {
117+ contentPeerPicker.contentType = ContentType.Music;
118+ } else if (data.mediaType.split("/")[0] == "image" ) {
119+ contentPeerPicker.contentType = ContentType.Pictures;
120+ } else if (data.mediaType == "application/octet-stream" ) {
121+ contentPeerPicker.contentType = ContentType.All;
122+ } else {
123+ contentPeerPicker.contentType = ContentType.Unknown;
124+ }
125+ contentPeerPicker.visible = true;
126 }
127 }
128 }
129@@ -121,4 +139,32 @@
130 }
131 }
132 }
133+
134+ ContentItem {
135+ id: exportItem
136+ name: i18n.tr("Attachment")
137+ }
138+
139+ ContentPeerPicker {
140+ id: contentPeerPicker
141+ visible: false
142+ contentType: ContentType.Unknown
143+ handler: ContentHandler.Destination
144+ anchors.fill: parent
145+
146+ property string filePath: ""
147+ onPeerSelected: {
148+ var transfer = peer.request();
149+ if (transfer.state === ContentTransfer.InProgress) {
150+ var items = new Array()
151+ var path = contentPeerPicker.filePath;
152+ exportItem.url = path
153+ items.push(exportItem);
154+ transfer.items = items;
155+ transfer.state = ContentTransfer.Charged;
156+ }
157+ contentPeerPicker.visible = false
158+ }
159+ onCancelPressed: contentPeerPicker.visible = false
160+ }
161 }
162
163=== modified file 'src/app/qml/ui/reminders-scripts.js'
164--- src/app/qml/ui/reminders-scripts.js 2014-07-14 15:40:30 +0000
165+++ src/app/qml/ui/reminders-scripts.js 2015-02-23 17:57:16 +0000
166@@ -1,12 +1,22 @@
167 function handleClickEvent(event) {
168 var todoTag = "en-todo";
169- if (event.srcElement.id.slice(0, todoTag.length) === todoTag) {
170+ var attachmentTag = "en-attachment";
171+
172+ var idFields = event.srcElement.id.split("/");
173+ if (idFields[0] === todoTag) {
174 message = new Object;
175 message.type = "checkboxChanged";
176- message.todoId = event.srcElement.id;
177+ message.todoId = idFields[1];
178 message.checked = event.srcElement.checked;
179- oxide.sendMessage('todo', message);
180+ oxide.sendMessage('interaction', message);
181+ } else if (idFields[0] === attachmentTag) {
182+ message = new Object;
183+ message.type = "attachmentOpened";
184+ message.resourceHash = idFields[1];
185+ message.mediaType = idFields[2] + "/" + idFields[3]
186+ oxide.sendMessage('interaction', message);
187 }
188+
189 }
190
191 var doc = document.documentElement;
192
193=== modified file 'src/libqtevernote/evernoteconnection.cpp'
194--- src/libqtevernote/evernoteconnection.cpp 2014-12-14 20:19:58 +0000
195+++ src/libqtevernote/evernoteconnection.cpp 2015-02-23 17:57:16 +0000
196@@ -161,8 +161,10 @@
197 m_errorMessage.clear();
198 emit errorChanged();
199
200- m_notesStoreHttpClient->close();
201- m_userStoreHttpClient->close();
202+ try {
203+ m_notesStoreHttpClient->close();
204+ m_userStoreHttpClient->close();
205+ } catch (...) {}
206 emit isConnectedChanged();
207 }
208
209
210=== modified file 'src/libqtevernote/note.cpp'
211--- src/libqtevernote/note.cpp 2015-02-12 22:57:46 +0000
212+++ src/libqtevernote/note.cpp 2015-02-23 17:57:16 +0000
213@@ -501,9 +501,11 @@
214 return m_resources.value(hash);
215 }
216
217+ qDebug() << "adding resource" << fileName << type;
218 Resource *resource = new Resource(data, hash, fileName, type, this);
219 m_resources.insert(hash, resource);
220 emit resourcesChanged();
221+ emit contentChanged();
222
223 QSettings infoFile(m_infoFile, QSettings::IniFormat);
224 infoFile.beginGroup("resources");
225
226=== modified file 'src/libqtevernote/note.h'
227--- src/libqtevernote/note.h 2014-12-16 21:01:28 +0000
228+++ src/libqtevernote/note.h 2015-02-23 17:57:16 +0000
229@@ -148,7 +148,7 @@
230 bool conflicting() const;
231
232 QStringList resourceUrls() const;
233- Resource* resource(const QString &hash);
234+ Q_INVOKABLE Resource* resource(const QString &hash);
235 QList<Resource*> resources() const;
236 Resource *addResource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type);
237
238
239=== modified file 'src/libqtevernote/notesstore.cpp'
240--- src/libqtevernote/notesstore.cpp 2015-02-12 21:57:51 +0000
241+++ src/libqtevernote/notesstore.cpp 2015-02-23 17:57:16 +0000
242@@ -787,7 +787,7 @@
243 qDebug() << "refetching for image";
244 refreshWithResourceData = true;
245 }
246- roles << RoleResourceUrls;
247+ roles << RoleHtmlContent << RoleEnmlContent << RoleResourceUrls;
248 }
249
250 if (what == FetchNoteJob::LoadContent) {
251@@ -822,10 +822,10 @@
252 if (refreshWithResourceData) {
253 qDebug() << "refreshWithResourceData";
254 refreshNoteContent(note->guid(), FetchNoteJob::LoadResources);
255+ } else {
256+ syncToCacheFile(note); // Syncs into the list cache
257+ note->syncToCacheFile(); // Syncs note's content into notes cache
258 }
259-
260- syncToCacheFile(note); // Syncs into the list cache
261- note->syncToCacheFile(); // Syncs note's content into notes cache
262 }
263
264 void NotesStore::refreshNotebooks()
265
266=== modified file 'src/libqtevernote/resource.cpp'
267--- src/libqtevernote/resource.cpp 2015-02-12 20:30:07 +0000
268+++ src/libqtevernote/resource.cpp 2015-02-23 17:57:16 +0000
269@@ -35,7 +35,7 @@
270 m_type(type)
271 {
272
273- m_filePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first() + "/" + NotesStore::instance()->username() + "/" + hash + "." + type.split('/').last();
274+ m_filePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first() + "/" + NotesStore::instance()->username() + "/" + hash + "." + m_fileName.split('.').last();
275
276 QFile file(m_filePath);
277 if (!data.isEmpty() && !file.exists()) {
278@@ -84,7 +84,7 @@
279 qWarning() << "cannot determine mime type of file" << m_fileName;
280 }
281
282- m_filePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first() + "/" + NotesStore::instance()->username() + "/" + m_hash + "." + m_type.split('/').last();
283+ m_filePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first() + "/" + NotesStore::instance()->username() + "/" + m_hash + "." + m_fileName.split('.').last();
284
285 QFile copy(m_filePath);
286 if (!copy.exists()) {
287@@ -108,6 +108,11 @@
288 return m_type;
289 }
290
291+QString Resource::hashedFilePath() const
292+{
293+ return m_filePath;
294+}
295+
296 QByteArray Resource::imageData(const QSize &size)
297 {
298 if (!m_type.startsWith("image/")) {
299
300=== modified file 'src/libqtevernote/resource.h'
301--- src/libqtevernote/resource.h 2014-10-23 21:27:46 +0000
302+++ src/libqtevernote/resource.h 2015-02-23 17:57:16 +0000
303@@ -32,6 +32,7 @@
304 Q_PROPERTY(QString hash READ hash CONSTANT)
305 Q_PROPERTY(QString fileName READ fileName CONSTANT)
306 Q_PROPERTY(QString type READ type CONSTANT)
307+ Q_PROPERTY(QString hashedFilePath READ hashedFilePath CONSTANT)
308
309 public:
310 Resource(const QString &path, QObject *parent = 0);
311@@ -43,6 +44,7 @@
312 QString hash() const;
313 QString fileName() const;
314 QString type() const;
315+ QString hashedFilePath() const;
316
317 QByteArray imageData(const QSize &size = QSize());
318
319
320=== modified file 'src/libqtevernote/resourceimageprovider.cpp'
321--- src/libqtevernote/resourceimageprovider.cpp 2015-02-20 18:30:08 +0000
322+++ src/libqtevernote/resourceimageprovider.cpp 2015-02-23 17:57:16 +0000
323@@ -32,10 +32,13 @@
324 }
325 image = QImage::fromData(NotesStore::instance()->note(noteGuid)->resource(resourceHash)->imageData(tmpSize));
326 } else if (mediaType.startsWith("audio")) {
327- image.load("/usr/share/icons/ubuntu-mobile/actions/scalable/media-playback-start.svg");
328+ image.load("/usr/share/icons/suru/mimetypes/scalable/audio-x-generic-symbolic.svg");
329+ } else if (mediaType == "application/pdf") {
330+ image.load("/usr/share/icons/suru/mimetypes/scalable/application-pdf-symbolic.svg");
331 } else {
332- image.load("/usr/share/icons/ubuntu-mobile/actions/scalable/help.svg");
333+ image.load("/usr/share/icons/suru/mimetypes/scalable/empty-symbolic.svg");
334 }
335+
336 *size = image.size();
337 return image;
338 }
339
340=== modified file 'src/libqtevernote/utils/enmldocument.cpp'
341--- src/libqtevernote/utils/enmldocument.cpp 2014-12-14 23:31:19 +0000
342+++ src/libqtevernote/utils/enmldocument.cpp 2015-02-23 17:57:16 +0000
343@@ -157,15 +157,11 @@
344 writer.writeStartElement("img");
345 if (mediaType.startsWith("image")) {
346 if (type == TypeRichText) {
347- QUrl url("image://resource/" + mediaType);
348- QUrlQuery arguments;
349- arguments.addQueryItem("noteGuid", noteGuid);
350- arguments.addQueryItem("hash", hash);
351- url.setQuery(arguments);
352- writer.writeAttribute("src", url.toString());
353+ writer.writeAttribute("src", composeMediaTypeUrl(mediaType, noteGuid, hash));
354 } else if (type == TypeHtml) {
355 QString imagePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first() + "/" + NotesStore::instance()->username() + "/" + hash + "." + mediaType.split('/').last();
356 writer.writeAttribute("src", imagePath);
357+ writer.writeAttribute("id", "en-attachment/" + hash + "/" + mediaType);
358 }
359
360 //set the width
361@@ -183,29 +179,37 @@
362 }
363 } else if (mediaType.startsWith("audio")) {
364 if (type == TypeRichText) {
365- QUrl url("image://resource/" + mediaType);
366- QUrlQuery arguments;
367- arguments.addQueryItem("noteGuid", noteGuid);
368- arguments.addQueryItem("hash", hash);
369- url.setQuery(arguments);
370- writer.writeAttribute("src", url.toString());
371- } else if (type == TypeHtml) {
372- QString imagePath = "file:///usr/share/icons/ubuntu-mobile/actions/scalable/media-playback-start.svg";
373- writer.writeAttribute("src", imagePath);
374- writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resource(hash)->fileName());
375+ writer.writeAttribute("src", composeMediaTypeUrl(mediaType, noteGuid, hash));
376+ } else if (type == TypeHtml) {
377+ QString imagePath = "file:///usr/share/icons/suru/mimetypes/scalable/audio-x-generic-symbolic.svg";
378+ writer.writeAttribute("src", imagePath);
379+ writer.writeAttribute("id", "en-attachment/" + hash + "/" + mediaType);
380+ if (NotesStore::instance()->note(noteGuid)->resource(hash)) {
381+ writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resource(hash)->fileName());
382+ }
383+ }
384+ } else if (mediaType == "application/pdf") {
385+ if (type == TypeRichText) {
386+ writer.writeAttribute("src", composeMediaTypeUrl(mediaType, noteGuid, hash));
387+ } else if (type == TypeHtml) {
388+ QString imagePath = "file:///usr/share/icons/suru/mimetypes/scalable/application-pdf-symbolic.svg";
389+ writer.writeAttribute("src", imagePath);
390+ writer.writeAttribute("id", "en-attachment/" + hash + "/" + mediaType);
391+ if (NotesStore::instance()->note(noteGuid)->resource(hash)) {
392+ writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resource(hash)->fileName());
393+ }
394 }
395 } else {
396+ qDebug() << "unknown mediatype" << mediaType;
397 if (type == TypeRichText) {
398- QUrl url("image://resource/" + mediaType);
399- QUrlQuery arguments;
400- arguments.addQueryItem("noteGuid", noteGuid);
401- arguments.addQueryItem("hash", hash);
402- url.setQuery(arguments);
403- writer.writeAttribute("src", url.toString());
404+ writer.writeAttribute("src", composeMediaTypeUrl(mediaType, noteGuid, hash));
405 } else if (type == TypeHtml) {
406- QString imagePath = "file:///usr/share/icons/ubuntu-mobile/actions/scalable/help.svg";
407+ QString imagePath = "file:///usr/share/icons/suru/mimetypes/scalable/empty-symbolic.svg";
408 writer.writeAttribute("src", imagePath);
409- writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resource(hash)->fileName());
410+ writer.writeAttribute("id", "en-attachment/" + hash + "/" + mediaType);
411+ if (NotesStore::instance()->note(noteGuid)->resource(hash)) {
412+ writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resource(hash)->fileName());
413+ }
414 }
415 }
416 }
417@@ -225,7 +229,7 @@
418 writer.writeAttribute("height", QString::number(gu(2)));
419 } else if (type == TypeHtml){
420 writer.writeStartElement("input");
421- writer.writeAttribute("id", "en-todo" + QString::number(todoIndex++));
422+ writer.writeAttribute("id", "en-todo/" + QString::number(todoIndex++));
423 writer.writeAttribute("type", "checkbox");
424 if (checked) {
425 writer.writeAttribute("checked", "true");
426@@ -283,6 +287,16 @@
427 return px * ppgu;
428 }
429
430+QString EnmlDocument::composeMediaTypeUrl(const QString &mediaType, const QString &noteGuid, const QString &hash) const
431+{
432+ QUrl url("image://resource/" + mediaType);
433+ QUrlQuery arguments;
434+ arguments.addQueryItem("noteGuid", noteGuid);
435+ arguments.addQueryItem("hash", hash);
436+ url.setQuery(arguments);
437+ return url.toString();
438+}
439+
440 void EnmlDocument::setRichText(const QString &richText)
441 {
442 // output
443@@ -408,7 +422,7 @@
444 writer.writeDTD("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">");
445
446 QString tmp = todoId;
447- int todoIndex = tmp.remove("en-todo").toInt();
448+ int todoIndex = tmp.toInt();
449 int todoCounter = 0;
450
451 while (!reader.atEnd() && !reader.hasError()) {
452
453=== modified file 'src/libqtevernote/utils/enmldocument.h'
454--- src/libqtevernote/utils/enmldocument.h 2014-11-10 00:54:16 +0000
455+++ src/libqtevernote/utils/enmldocument.h 2015-02-23 17:57:16 +0000
456@@ -53,6 +53,8 @@
457
458 qreal gu(qreal px) const;
459
460+ QString composeMediaTypeUrl(const QString &mediaType, const QString &noteGuid, const QString &hash) const;
461+
462 private:
463 QString m_enml;
464

Subscribers

People subscribed via source and target branches