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

Proposed by Michael Zanetti
Status: Merged
Approved by: Riccardo Padovani
Approved revision: 455
Merged at revision: 461
Proposed branch: lp:~mzanetti/reminders-app/contenthub-import
Merge into: lp:reminders-app
Diff against target: 597 lines (+335/-89)
11 files modified
CMakeLists.txt (+1/-0)
manifest.json.in (+2/-1)
reminders-contenthub.json (+8/-0)
src/app/qml/components/NotesDelegate.qml (+1/-1)
src/app/qml/components/StatusBar.qml (+35/-21)
src/app/qml/reminders.qml (+112/-18)
src/app/qml/ui/NotesPage.qml (+0/-3)
src/libqtevernote/note.cpp (+15/-1)
src/libqtevernote/note.h (+2/-0)
src/libqtevernote/utils/enmldocument.cpp (+155/-44)
src/libqtevernote/utils/enmldocument.h (+4/-0)
To merge this branch: bzr merge lp:~mzanetti/reminders-app/contenthub-import
Reviewer Review Type Date Requested Status
Riccardo Padovani Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+261919@code.launchpad.net

Commit message

Make Notes a Content Hub Target for pictures and links

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: Approve (continuous-integration)
Revision history for this message
Riccardo Padovani (rpadovani) wrote :

Looks good (just three little things to change if you don't mind).

review: Needs Fixing
455. By Michael Zanetti

fix nitpicks from review

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

Thanks!

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 2015-02-16 22:01:20 +0000
+++ CMakeLists.txt 2015-06-22 08:35:28 +0000
@@ -74,6 +74,7 @@
74 reminders.url-dispatcher74 reminders.url-dispatcher
75 push-helper.json75 push-helper.json
76 push-helper.apparmor76 push-helper.apparmor
77 reminders-contenthub.json
77 DESTINATION ${CMAKE_INSTALL_PREFIX})78 DESTINATION ${CMAKE_INSTALL_PREFIX})
78install(FILES COPYING DESTINATION ${CMAKE_INSTALL_PREFIX})79install(FILES COPYING DESTINATION ${CMAKE_INSTALL_PREFIX})
79else(CLICK_MODE)80else(CLICK_MODE)
8081
=== modified file 'manifest.json.in'
--- manifest.json.in 2015-03-20 11:16:35 +0000
+++ manifest.json.in 2015-06-22 08:35:28 +0000
@@ -8,7 +8,8 @@
8 "account-service": "@ACCOUNT_SERVICE_DIR@/com.ubuntu.reminders_reminders.service",8 "account-service": "@ACCOUNT_SERVICE_DIR@/com.ubuntu.reminders_reminders.service",
9 "apparmor": "reminders.apparmor",9 "apparmor": "reminders.apparmor",
10 "desktop": "com.ubuntu.reminders.desktop",10 "desktop": "com.ubuntu.reminders.desktop",
11 "urls": "reminders.url-dispatcher"11 "urls": "reminders.url-dispatcher",
12 "content-hub": "reminders-contenthub.json"
12 },13 },
13 "evernote-account-plugin": {14 "evernote-account-plugin": {
14 "account-qml-plugin": "@ACCOUNT_QML_PLUGIN_DIR@/evernote",15 "account-qml-plugin": "@ACCOUNT_QML_PLUGIN_DIR@/evernote",
1516
=== added file 'reminders-contenthub.json'
--- reminders-contenthub.json 1970-01-01 00:00:00 +0000
+++ reminders-contenthub.json 2015-06-22 08:35:28 +0000
@@ -0,0 +1,8 @@
1{
2 "destination": [
3 "pictures",
4 "links",
5 "text"
6 ]
7}
8
09
=== modified file 'src/app/qml/components/NotesDelegate.qml'
--- src/app/qml/components/NotesDelegate.qml 2015-03-15 20:00:21 +0000
+++ src/app/qml/components/NotesDelegate.qml 2015-06-22 08:35:28 +0000
@@ -136,7 +136,7 @@
136 Layout.fillHeight: true136 Layout.fillHeight: true
137 text: "<font color=\"" + root.notebookColor + "\">" +137 text: "<font color=\"" + root.notebookColor + "\">" +
138 Qt.formatDateTime(root.date, Qt.LocalDate) +138 Qt.formatDateTime(root.date, Qt.LocalDate) +
139 " </font>" + root.content139 " </font>" + root.content.replace("\n", " ").trim()
140 wrapMode: Text.WordWrap140 wrapMode: Text.WordWrap
141 textFormat: Text.StyledText141 textFormat: Text.StyledText
142 maximumLineCount: 2142 maximumLineCount: 2
143143
=== modified file 'src/app/qml/components/StatusBar.qml'
--- src/app/qml/components/StatusBar.qml 2015-03-08 21:29:28 +0000
+++ src/app/qml/components/StatusBar.qml 2015-06-22 08:35:28 +0000
@@ -10,36 +10,50 @@
1010
11 property bool shown: false11 property bool shown: false
12 property alias iconName: icon.name12 property alias iconName: icon.name
13 property alias iconColor: icon.color
13 property alias text: label.text14 property alias text: label.text
15 property alias showCancelButton: cancelButton.visible
16
17 signal cancel();
1418
15 Behavior on height {19 Behavior on height {
16 UbuntuNumberAnimation {}20 UbuntuNumberAnimation {}
17 }21 }
1822
19 ColumnLayout {23 RowLayout {
20 id: statusBarContents24 id: statusBarContents
21 anchors { left: parent.left; top: parent.top; right: parent.right }25 anchors { left: parent.left; right: parent.right; leftMargin: units.gu(1); rightMargin: units.gu(1); verticalCenter: parent.verticalCenter }
22 spacing: units.gu(1)26 spacing: units.gu(1)
2327 Column {
24 Row {
25 anchors { left: parent.left; right: parent.right; margins: units.gu(1) }
26 spacing: units.gu(1)28 spacing: units.gu(1)
27 height: label.height29 Layout.fillWidth: true
2830
29 Icon {31 Row {
30 id: icon32 anchors { left: parent.left; right: parent.right }
31 height: units.gu(3)33 spacing: units.gu(1)
32 width: height34 height: label.height
33 color: UbuntuColors.red35
34 anchors.verticalCenter: parent.verticalCenter36 Icon {
35 }37 id: icon
3638 height: units.gu(3)
37 Label {39 width: height
38 id: label40 anchors.verticalCenter: parent.verticalCenter
39 width: parent.width - x41 }
40 wrapMode: Text.WordWrap42
41 anchors.verticalCenter: parent.verticalCenter43 Label {
42 }44 id: label
45 width: parent.width - x
46 wrapMode: Text.WordWrap
47 anchors.verticalCenter: parent.verticalCenter
48 }
49 }
50 }
51
52 Button {
53 id: cancelButton
54 Layout.preferredWidth: height
55 iconName: "cancel"
56 onClicked: root.cancel();
43 }57 }
44 }58 }
45}59}
4660
=== modified file 'src/app/qml/reminders.qml'
--- src/app/qml/reminders.qml 2015-06-12 09:48:22 +0000
+++ src/app/qml/reminders.qml 2015-06-22 08:35:28 +0000
@@ -26,6 +26,7 @@
26import Ubuntu.OnlineAccounts 0.126import Ubuntu.OnlineAccounts 0.1
27import Ubuntu.OnlineAccounts.Client 0.127import Ubuntu.OnlineAccounts.Client 0.1
28import Ubuntu.PushNotifications 0.128import Ubuntu.PushNotifications 0.1
29import Ubuntu.Content 1.0
29import "components"30import "components"
30import "ui"31import "ui"
3132
@@ -79,6 +80,45 @@
79 }80 }
80 }81 }
8182
83 property var importTransfer: null
84 function handleImportTransfer(note) {
85 if (importTransfer == null) return;
86
87 for (var i = 0; i < importTransfer.items.length; i++) {
88 var url = importTransfer.items[i].url;
89 switch (importTransfer.contentType) {
90 case ContentType.Links:
91 note.insertLink(note.plaintextContent.length, url)
92 break;
93 default:
94 note.attachFile(note.plaintextContent.length, url)
95 break;
96 }
97 }
98 note.save();
99 importTransfer = null;
100 }
101
102 Connections {
103 target: ContentHub
104 onImportRequested: {
105 importTransfer = transfer;
106 var popup = PopupUtils.open(importQuestionComponent);
107 popup.accepted.connect(function(createNew) {
108 PopupUtils.close(popup);
109 if (createNew) {
110 var note = NotesStore.createNote(i18n.tr("Untitled"));
111 handleImportTransfer(note);
112 }
113 })
114
115 popup.rejected.connect(function() {
116 PopupUtils.close(popup);
117 importTransfer = null;
118 })
119 }
120 }
121
82 Timer {122 Timer {
83 id: connectDelayTimer123 id: connectDelayTimer
84 interval: 2000124 interval: 2000
@@ -107,6 +147,10 @@
107 conflictMode = false;147 conflictMode = false;
108 }148 }
109149
150 if (importTransfer != null) {
151 handleImportTransfer(note);
152 }
153
110 print("displayNote:", note.guid)154 print("displayNote:", note.guid)
111 note.load(true);155 note.load(true);
112 if (root.narrowMode) {156 if (root.narrowMode) {
@@ -436,26 +480,43 @@
436 }480 }
437 }481 }
438482
439 StatusBar {483 Column {
440 id: statusBar484 id: statusBar
441 anchors { left: parent.left; right: parent.right; top: parent.top; topMargin: units.gu(9) }485 anchors { left: parent.left; right: parent.right; top: parent.top; topMargin: units.gu(9) }
442 color: root.backgroundColor486
443 shown: text487 StatusBar {
444 text: EvernoteConnection.error || NotesStore.error488 anchors { left: parent.left; right: parent.right }
445 iconName: "sync-error"489 color: root.backgroundColor
446490 shown: text
447 Timer {491 text: EvernoteConnection.error || NotesStore.error
448 interval: 5000492 iconName: "sync-error"
449 repeat: true493 iconColor: UbuntuColors.red
450 running: NotesStore.error494 showCancelButton: true
451 onTriggered: NotesStore.clearError();495
452 }496 onCancel: {
453497 NotesStore.clearError();
454 MouseArea {498 }
455 anchors.fill: parent499
456 onClicked: NotesStore.clearError();500 Timer {
457 }501 interval: 5000
458502 repeat: true
503 running: NotesStore.error
504 onTriggered: NotesStore.clearError();
505 }
506 }
507
508 StatusBar {
509 anchors { left: parent.left; right: parent.right }
510 color: root.backgroundColor
511 shown: importTransfer != null
512 text: importTransfer.items.length === 1 ? i18n.tr("Select note to attach imported file") : i18n.tr("Select note to attach imported files")
513 iconName: "document-save"
514 showCancelButton: true
515
516 onCancel: {
517 importTransfer = null;
518 }
519 }
459 }520 }
460521
461 PageStack {522 PageStack {
@@ -673,4 +734,37 @@
673 }734 }
674 }735 }
675 }736 }
737
738 Component {
739 id: importQuestionComponent
740
741 Dialog {
742 id: importDialog
743 title: importTransfer.items.length > 1 ?
744 i18n.tr("Importing %1 items").arg(importTransfer.items.length)
745 : i18n.tr("Importing 1 item")
746 text: importTransfer.items.length > 1 ?
747 i18n.tr("Do you want to create a new note for those items or do you want to attach them to an existing note?")
748 : i18n.tr("Do you want to create a new note for this item or do you want to attach it to an existing note?")
749
750 signal accepted(bool createNew);
751 signal rejected();
752
753 Button {
754 text: i18n.tr("Create new note")
755 onClicked: importDialog.accepted(true)
756 color: UbuntuColors.green
757 }
758 Button {
759 text: i18n.tr("Attach to existing note")
760 onClicked: importDialog.accepted(false);
761 color: UbuntuColors.blue
762 }
763 Button {
764 text: i18n.tr("Cancel import")
765 onClicked: importDialog.rejected();
766 color: UbuntuColors.red
767 }
768 }
769 }
676}770}
677771
=== modified file 'src/app/qml/ui/NotesPage.qml'
--- src/app/qml/ui/NotesPage.qml 2015-06-11 22:02:25 +0000
+++ src/app/qml/ui/NotesPage.qml 2015-06-22 08:35:28 +0000
@@ -142,15 +142,12 @@
142 }142 }
143143
144 function sortOrderToString(sortOrder){144 function sortOrderToString(sortOrder){
145 print("asking for sortOrder", sortOrder, Notes.SortOrderDateUpdatedNewest)
146 switch(sortOrder) {145 switch(sortOrder) {
147 case Notes.SortOrderDateCreatedNewest:146 case Notes.SortOrderDateCreatedNewest:
148 case Notes.SortOrderDateCreatedOldest:147 case Notes.SortOrderDateCreatedOldest:
149 print("returning createdString")
150 return "createdString";148 return "createdString";
151 case Notes.SortOrderDateUpdatedNewest:149 case Notes.SortOrderDateUpdatedNewest:
152 case Notes.SortOrderDateUpdatedOldest:150 case Notes.SortOrderDateUpdatedOldest:
153 print("returning updatedString")
154 return "updatedString";151 return "updatedString";
155 case Notes.SortOrderTitleAscending:152 case Notes.SortOrderTitleAscending:
156 case Notes.SortOrderTitleDescending:153 case Notes.SortOrderTitleDescending:
157154
=== modified file 'src/libqtevernote/note.cpp'
--- src/libqtevernote/note.cpp 2015-06-03 17:45:45 +0000
+++ src/libqtevernote/note.cpp 2015-06-22 08:35:28 +0000
@@ -277,7 +277,7 @@
277277
278QString Note::plaintextContent() const278QString Note::plaintextContent() const
279{279{
280 return m_content.toPlaintext().trimmed();280 return m_content.toPlaintext();
281}281}
282282
283QString Note::tagline() const283QString Note::tagline() const
@@ -570,6 +570,20 @@
570 NotesStore::instance()->untagNote(m_guid, tagGuid);570 NotesStore::instance()->untagNote(m_guid, tagGuid);
571}571}
572572
573void Note::insertText(int position, const QString &text)
574{
575 m_content.insertText(position, text);
576 m_tagline = m_content.toPlaintext().left(100);
577 emit contentChanged();
578}
579
580void Note::insertLink(int position, const QString &url)
581{
582 m_content.insertLink(position, url);
583 m_tagline = m_content.toPlaintext().left(100);
584 emit contentChanged();
585}
586
573int Note::renderWidth() const587int Note::renderWidth() const
574{588{
575 return m_content.renderWidth();589 return m_content.renderWidth();
576590
=== modified file 'src/libqtevernote/note.h'
--- src/libqtevernote/note.h 2015-03-15 20:00:21 +0000
+++ src/libqtevernote/note.h 2015-06-22 08:35:28 +0000
@@ -165,6 +165,8 @@
165 Q_INVOKABLE void attachFile(int position, const QUrl &fileName);165 Q_INVOKABLE void attachFile(int position, const QUrl &fileName);
166 Q_INVOKABLE void addTag(const QString &tagGuid);166 Q_INVOKABLE void addTag(const QString &tagGuid);
167 Q_INVOKABLE void removeTag(const QString &tagGuid);167 Q_INVOKABLE void removeTag(const QString &tagGuid);
168 Q_INVOKABLE void insertText(int position, const QString &text);
169 Q_INVOKABLE void insertLink(int position, const QString &url);
168170
169 int renderWidth() const;171 int renderWidth() const;
170 void setRenderWidth(int renderWidth);172 void setRenderWidth(int renderWidth);
171173
=== modified file 'src/libqtevernote/utils/enmldocument.cpp'
--- src/libqtevernote/utils/enmldocument.cpp 2015-04-13 20:42:38 +0000
+++ src/libqtevernote/utils/enmldocument.cpp 2015-06-22 08:35:28 +0000
@@ -486,48 +486,161 @@
486486
487void EnmlDocument::attachFile(int position, const QString &hash, const QString &type)487void EnmlDocument::attachFile(int position, const QString &hash, const QString &type)
488{488{
489 QXmlStreamReader reader(m_enml);489 qCDebug(dcEnml) << "Attaching file at position" << position;
490490 QXmlStreamReader reader(m_enml);
491 QString output;491
492 QXmlStreamWriter writer(&output);492 QString output;
493 writer.writeStartDocument();493 QXmlStreamWriter writer(&output);
494 writer.writeDTD("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">");494 writer.writeStartDocument();
495495 writer.writeDTD("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">");
496 int textPos = 0;496
497 bool inserted = false;497 int textPos = 0;
498498 bool inserted = false;
499 while (!reader.atEnd() && !reader.hasError()) {499
500 QXmlStreamReader::TokenType token = reader.readNext();500 while (!reader.atEnd() && !reader.hasError()) {
501501 QXmlStreamReader::TokenType token = reader.readNext();
502 if (token == QXmlStreamReader::StartElement) {502
503 writer.writeStartElement(reader.name().toString());503 if (token == QXmlStreamReader::StartElement) {
504 writer.writeAttributes(reader.attributes());504 writer.writeStartElement(reader.name().toString());
505 }505 writer.writeAttributes(reader.attributes());
506506 }
507 if (token == QXmlStreamReader::Characters) {507
508 QString textString = reader.text().toString();508 if (token == QXmlStreamReader::Characters) {
509 if (textPos <= position && textPos + textString.length() > position) {509 QString textString = reader.text().toString();
510 writer.writeCharacters(textString.left(position - textPos));510 if (textPos <= position && textPos + textString.length() > position) {
511511 writer.writeCharacters(textString.left(position - textPos));
512 writer.writeStartElement("en-media");512
513 writer.writeAttribute("hash", hash);513 writer.writeStartElement("en-media");
514 writer.writeAttribute("type", type);514 writer.writeAttribute("hash", hash);
515 writer.writeEndElement();515 writer.writeAttribute("type", type);
516 inserted = true;516 writer.writeEndElement();
517517 inserted = true;
518 writer.writeCharacters(textString.right(textString.length() - (position - textPos)));518
519 } else {519 writer.writeCharacters(textString.right(textString.length() - (position - textPos)));
520 writer.writeCharacters(reader.text().toString());520 } else {
521 }521 writer.writeCharacters(reader.text().toString());
522 textPos += textString.length();522 }
523 }523 textPos += textString.length();
524 if (token == QXmlStreamReader::EndElement) {524 }
525525 if (token == QXmlStreamReader::EndElement) {
526 // The above logic would fail on an empty note526
527 if (reader.name() == "en-note" && !inserted) {527 // The above logic would fail on an empty note
528 writer.writeStartElement("en-media");528 if (reader.name() == "en-note" && !inserted) {
529 writer.writeAttribute("hash", hash);529 writer.writeStartElement("en-media");
530 writer.writeAttribute("type", type);530 writer.writeAttribute("hash", hash);
531 writer.writeAttribute("type", type);
532 writer.writeEndElement();
533 }
534
535 writer.writeEndElement();
536 }
537 }
538 m_enml = output;
539}
540
541void EnmlDocument::insertText(int position, const QString &text)
542{
543 qCDebug(dcEnml) << "Inserting Text at position" << position;
544
545 QXmlStreamReader reader(m_enml);
546
547 QString output;
548 QXmlStreamWriter writer(&output);
549 writer.writeStartDocument();
550 writer.writeDTD("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">");
551
552 int textPos = 0;
553 bool inserted = false;
554
555 while (!reader.atEnd() && !reader.hasError()) {
556 QXmlStreamReader::TokenType token = reader.readNext();
557
558 if (token == QXmlStreamReader::StartElement) {
559 writer.writeStartElement(reader.name().toString());
560 writer.writeAttributes(reader.attributes());
561 }
562
563 if (token == QXmlStreamReader::Characters) {
564 QString textString = reader.text().toString();
565 if (textPos <= position && textPos + textString.length() > position) {
566 writer.writeCharacters(textString.left(position - textPos));
567
568 writer.writeStartElement("div");
569 writer.writeCharacters(text);
570 writer.writeEndElement();
571 inserted = true;
572
573 writer.writeCharacters(textString.right(textString.length() - (position - textPos)));
574 } else {
575 writer.writeCharacters(reader.text().toString());
576 }
577 textPos += textString.length();
578 }
579 if (token == QXmlStreamReader::EndElement) {
580
581 // The above logic would fail on an empty note
582 if (reader.name() == "en-note" && !inserted) {
583 writer.writeStartElement("div");
584 writer.writeCharacters(text);
585 writer.writeEndElement();
586 }
587
588 writer.writeEndElement();
589 }
590 }
591 m_enml = output;
592}
593
594void EnmlDocument::insertLink(int position, const QString &url)
595{
596 qCDebug(dcEnml) << "Inserting Link at position" << position;
597
598 QXmlStreamReader reader(m_enml);
599
600 QString output;
601 QXmlStreamWriter writer(&output);
602 writer.writeStartDocument();
603 writer.writeDTD("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">");
604
605 int textPos = 0;
606 bool inserted = false;
607
608 while (!reader.atEnd() && !reader.hasError()) {
609 QXmlStreamReader::TokenType token = reader.readNext();
610
611 if (token == QXmlStreamReader::StartElement) {
612 writer.writeStartElement(reader.name().toString());
613 writer.writeAttributes(reader.attributes());
614 }
615
616 if (token == QXmlStreamReader::Characters) {
617 QString textString = reader.text().toString();
618 if (textPos <= position && textPos + textString.length() > position) {
619 writer.writeCharacters(textString.left(position - textPos));
620
621 writer.writeStartElement("div");
622 writer.writeStartElement("a");
623 writer.writeAttribute("href", url);
624 writer.writeCharacters(url);
625 writer.writeEndElement();
626 writer.writeEndElement();
627 inserted = true;
628
629 writer.writeCharacters(textString.right(textString.length() - (position - textPos)));
630 } else {
631 writer.writeCharacters(reader.text().toString());
632 }
633 textPos += textString.length();
634 }
635 if (token == QXmlStreamReader::EndElement) {
636
637 // The above logic would fail on an empty note
638 if (reader.name() == "en-note" && !inserted) {
639 writer.writeStartElement("div");
640 writer.writeStartElement("a");
641 writer.writeAttribute("href", url);
642 writer.writeCharacters(url);
643 writer.writeEndElement();
531 writer.writeEndElement();644 writer.writeEndElement();
532 }645 }
533646
@@ -551,10 +664,8 @@
551 // Write all normal text inside <body> </body> to output664 // Write all normal text inside <body> </body> to output
552 if (token == QXmlStreamReader::Characters) {665 if (token == QXmlStreamReader::Characters) {
553 plaintext.append(reader.text().toString());666 plaintext.append(reader.text().toString());
554 plaintext.append(' ');
555 }667 }
556 }668 }
557669
558 plaintext.remove('\n').trimmed();
559 return plaintext;670 return plaintext;
560}671}
561672
=== modified file 'src/libqtevernote/utils/enmldocument.h'
--- src/libqtevernote/utils/enmldocument.h 2015-03-05 18:23:25 +0000
+++ src/libqtevernote/utils/enmldocument.h 2015-06-22 08:35:28 +0000
@@ -41,6 +41,10 @@
41 // Will insert the file described by hash at position in the plaintext string41 // Will insert the file described by hash at position in the plaintext string
42 void attachFile(int position, const QString &hash, const QString &type);42 void attachFile(int position, const QString &hash, const QString &type);
4343
44 // Convenience functions to insert some text without having a complete Editor attached
45 void insertText(int position, const QString &text);
46 void insertLink(int position, const QString &url);
47
44 void markTodo(const QString &todoId, bool checked);48 void markTodo(const QString &todoId, bool checked);
4549
46 int renderWidth() const;50 int renderWidth() const;

Subscribers

People subscribed via source and target branches