Merge lp:~renatofilho/address-book-app/fix-1226378 into lp:address-book-app

Proposed by Renato Araujo Oliveira Filho
Status: Merged
Approved by: Gustavo Pichorim Boiko
Approved revision: 69
Merged at revision: 69
Proposed branch: lp:~renatofilho/address-book-app/fix-1226378
Merge into: lp:address-book-app
Diff against target: 380 lines (+219/-4)
9 files modified
src/app/addressbookapp.cpp (+101/-4)
src/app/addressbookapp.h (+2/-0)
src/app/addressbookappdbus.cpp (+6/-0)
src/app/addressbookappdbus.h (+1/-0)
src/imports/ContactEdit/CMakeLists.txt (+1/-0)
src/imports/ContactEdit/ContactEditor.qml (+59/-0)
src/imports/ContactEdit/ContactFetchError.qml (+37/-0)
src/imports/ContactList/ContactListPage.qml (+4/-0)
src/imports/main.qml (+8/-0)
To merge this branch: bzr merge lp:~renatofilho/address-book-app/fix-1226378
Reviewer Review Type Date Requested Status
Gustavo Pichorim Boiko (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+186176@code.launchpad.net

Commit message

Implemented new app uri support.

Add a phone number to a existing contact.
addressbook://addphone?id=<contactid>&phone=<phone>

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Gustavo Pichorim Boiko (boiko) wrote :

Looks good and works as expected.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/app/addressbookapp.cpp'
2--- src/app/addressbookapp.cpp 2013-08-01 19:58:35 +0000
3+++ src/app/addressbookapp.cpp 2013-09-17 22:21:49 +0000
4@@ -20,6 +20,7 @@
5
6 #include <QDir>
7 #include <QUrl>
8+#include <QUrlQuery>
9 #include <QDebug>
10 #include <QStringList>
11 #include <QQuickItem>
12@@ -39,6 +40,9 @@
13 << arguments.at(0).toUtf8().constData()
14 << "[contact://CONTACT_ID]"
15 << "[create://PHONE_NUMBER]"
16+ << "[addressbook://addphone?id=<contact-id>&phone=<phone-number>"
17+ << "[addressbook://contact?id=<contact-id>"
18+ << "[addressbook://create?phone=<phone-number>"
19 << "[--fullscreen]"
20 << "[--help]"
21 << "[-testability]";
22@@ -81,6 +85,7 @@
23 if (validSchemes.isEmpty()) {
24 validSchemes << "contact";
25 validSchemes << "create";
26+ validSchemes << "addressbook";
27 }
28
29 QString contactKey;
30@@ -197,32 +202,124 @@
31 }
32 }
33
34+void AddressBookApp::parseUrl(const QString &arg)
35+{
36+ QUrl url(arg);
37+
38+ QString methodName = url.host();
39+ QStringList args;
40+
41+ QMap<QString, QStringList> methodsMetaData;
42+
43+ if (methodsMetaData.isEmpty()) {
44+ QStringList args;
45+ //edit
46+ args << "id" << "phone";
47+ methodsMetaData.insert("addphone", args);
48+ args.clear();
49+
50+ //view
51+ args << "id";
52+ methodsMetaData.insert("contact", args);
53+ args.clear();
54+
55+ //add
56+ args << "phone";
57+ methodsMetaData.insert("create", args);
58+ args.clear();
59+ }
60+
61+ QUrlQuery query(url);
62+ QList<QPair<QString, QString> > queryItemsPair = query.queryItems();
63+ QMap<QString, QString> queryItems;
64+
65+ //convert items to map
66+ for(int i=0; i < queryItemsPair.count(); i++) {
67+ QPair<QString, QString> item = queryItemsPair[i];
68+ queryItems.insert(item.first, item.second);
69+ }
70+
71+ if (methodsMetaData.contains(methodName)) {
72+ QStringList argsNames = methodsMetaData[methodName];
73+
74+ if (queryItems.size() != argsNames.size()) {
75+ qWarning() << "invalid" << methodName << "arguments size";
76+ return;
77+ }
78+
79+ Q_FOREACH(QString arg, argsNames) {
80+ if (queryItems.contains(arg)) {
81+ args << queryItems[arg];
82+ } else {
83+ qWarning() << "argument" << arg << "not found in method" << methodName << "call";
84+ return;
85+ }
86+ }
87+ } else {
88+ qWarning() << "method" << methodName << "not supported";
89+ return;
90+ }
91+
92+ callQMLMethod(methodName, args);
93+}
94+
95 void AddressBookApp::parseArgument(const QString &arg)
96 {
97 if (arg.isEmpty()) {
98 return;
99 }
100
101+ // new scheme
102+ if (arg.startsWith("addressbook://")) {
103+ parseUrl(arg);
104+ return;
105+ }
106+
107 QStringList args = arg.split("://");
108 if (args.size() != 2) {
109 return;
110 }
111
112 QString scheme = args[0];
113- QString value = args[1];
114-
115+ QStringList values;
116+ values << args[1];
117+
118+ callQMLMethod(scheme, values);
119+}
120+
121+void AddressBookApp::callQMLMethod(const QString name, QStringList args)
122+{
123 QQuickItem *mainView = m_view->rootObject();
124 if (!mainView) {
125 return;
126 }
127 const QMetaObject *mo = mainView->metaObject();
128
129+ // create QML signature: Ex. function(QVariant, QVariant, QVariant)
130+ QString argsSignature = QString("QVariant,").repeated(args.size());
131+ if (argsSignature.endsWith(",")) {
132+ argsSignature = argsSignature.left(argsSignature.size() - 1);
133+ }
134
135- QString methodSignature = QString("%1(%2)").arg(scheme).arg(scheme.isEmpty() ? "" : "QVariant");
136+ QString methodSignature = QString("%1(%2)").arg(name).arg(argsSignature);
137 int index = mo->indexOfMethod(methodSignature.toUtf8().data());
138 if (index != -1) {
139 QMetaMethod method = mo->method(index);
140- method.invoke(mainView, Q_ARG(QVariant, QVariant(value)));
141+ switch(args.count()) {
142+ case 0:
143+ method.invoke(mainView);
144+ break;
145+ case 1:
146+ method.invoke(mainView, Q_ARG(QVariant, QVariant(args[0])));
147+ break;
148+ case 2:
149+ method.invoke(mainView, Q_ARG(QVariant, QVariant(args[0])),
150+ Q_ARG(QVariant, QVariant(args[1])));
151+ break;
152+ default:
153+ qWarning() << "Invalid arguments";
154+ break;
155+ }
156 }
157 }
158
159
160=== modified file 'src/app/addressbookapp.h'
161--- src/app/addressbookapp.h 2013-07-31 22:24:45 +0000
162+++ src/app/addressbookapp.h 2013-09-17 22:21:49 +0000
163@@ -38,6 +38,8 @@
164
165 private:
166 void parseArgument(const QString &arg);
167+ void parseUrl(const QString &arg);
168+ void callQMLMethod(const QString name, QStringList args);
169
170 private Q_SLOTS:
171 void onMessageReceived(const QString &message);
172
173=== modified file 'src/app/addressbookappdbus.cpp'
174--- src/app/addressbookappdbus.cpp 2013-08-01 19:58:35 +0000
175+++ src/app/addressbookappdbus.cpp 2013-09-17 22:21:49 +0000
176@@ -71,3 +71,9 @@
177 qDebug() << "DBUS CALLL" << message;
178 Q_EMIT request(message);
179 }
180+
181+void AddressBookAppDBus::AddPhoneToContact(const QString &contactId, const QString &phoneNumber)
182+{
183+ Q_EMIT request(QString("addressbook://edit?%1&%2").arg(contactId).arg(phoneNumber));
184+}
185+
186
187=== modified file 'src/app/addressbookappdbus.h'
188--- src/app/addressbookappdbus.h 2013-08-01 19:58:35 +0000
189+++ src/app/addressbookappdbus.h 2013-09-17 22:21:49 +0000
190@@ -41,6 +41,7 @@
191 Q_NOREPLY void ShowContact(const QVariant &contactId);
192 Q_NOREPLY void CreateContact(const QString &phoneNumber);
193 Q_NOREPLY void SendAppMessage(const QString &message);
194+ Q_NOREPLY void AddPhoneToContact(const QString &contactId, const QString &phoneNumber);
195
196 Q_SIGNALS:
197 void request(const QString &message);
198
199=== modified file 'src/imports/ContactEdit/CMakeLists.txt'
200--- src/imports/ContactEdit/CMakeLists.txt 2013-08-02 17:40:44 +0000
201+++ src/imports/ContactEdit/CMakeLists.txt 2013-09-17 22:21:49 +0000
202@@ -8,6 +8,7 @@
203 ContactDetailPhoneNumbersEditor.qml
204 ContactDetailWithTypeEditor.qml
205 ContactEditor.qml
206+ ContactFetchError.qml
207 EditToolbar.qml
208 TextInputDetail.qml
209 ValueSelector.qml
210
211=== modified file 'src/imports/ContactEdit/ContactEditor.qml'
212--- src/imports/ContactEdit/ContactEditor.qml 2013-09-12 23:22:06 +0000
213+++ src/imports/ContactEdit/ContactEditor.qml 2013-09-17 22:21:49 +0000
214@@ -18,6 +18,7 @@
215 import QtContacts 5.0
216 import Ubuntu.Components 0.1
217 import Ubuntu.Components.ListItems 0.1 as ListItem
218+import Ubuntu.Components.Popups 0.1
219
220 Page {
221 id: contactEditor
222@@ -25,6 +26,11 @@
223 property QtObject contact: null
224 property QtObject model: null
225
226+ // this is used to add a phone number to a existing contact
227+ property int currentFetchOperation: -1
228+ property string contactId: null
229+ property string newPhoneNumber: null
230+
231 property QtObject activeItem: null
232
233 // we use a custom toolbar in this view
234@@ -93,6 +99,57 @@
235 scrollArea.returnToBounds()
236 }
237
238+ ContactFetchError {
239+ id: fetchErrorDialog
240+ }
241+
242+ Connections {
243+ target: model
244+ onContactsFetched: {
245+ if (requestId == currentFetchOperation) {
246+ currentFetchOperation = -1
247+ // this fetch request can only return one contact
248+ if(fetchedContacts.length !== 1) {
249+ PopupUtils.open(fetchErrorDialog, null)
250+ }
251+ contact = fetchedContacts[0]
252+ }
253+ }
254+ }
255+
256+ onContactIdChanged: {
257+ if (contactId) {
258+ currentFetchOperation = model.fetchContacts(contactId)
259+ }
260+ }
261+
262+ onContactChanged: {
263+ if (contact && (newPhoneNumber.length > 0)) {
264+ var detailSourceTemplate = "import QtContacts 5.0; PhoneNumber{ number: \"" + newPhoneNumber + "\" }"
265+ var newDetail = Qt.createQmlObject(detailSourceTemplate, contactEditor)
266+ if (newDetail) {
267+ contact.addDetail(newDetail)
268+ // we need to wait for the field be created
269+ focusTimer.restart()
270+
271+ }
272+ newPhoneNumber = ""
273+
274+ }
275+ }
276+
277+ Timer {
278+ id: focusTimer
279+
280+ interval: 200
281+ running: false
282+ onTriggered: {
283+ // get last phone field and set focus
284+ var lastPhoneField = phones.detailDelegates[phones.detailDelegates.length - 2].item
285+ lastPhoneField.forceActiveFocus()
286+ }
287+ }
288+
289 flickable: null
290 Flickable {
291 id: scrollArea
292@@ -143,6 +200,8 @@
293 }
294
295 ContactDetailPhoneNumbersEditor {
296+ id: phones
297+
298 contact: contactEditor.contact
299 anchors {
300 left: parent.left
301
302=== added file 'src/imports/ContactEdit/ContactFetchError.qml'
303--- src/imports/ContactEdit/ContactFetchError.qml 1970-01-01 00:00:00 +0000
304+++ src/imports/ContactEdit/ContactFetchError.qml 2013-09-17 22:21:49 +0000
305@@ -0,0 +1,37 @@
306+/*
307+ * Copyright (C) 2012-2013 Canonical, Ltd.
308+ *
309+ * This program is free software; you can redistribute it and/or modify
310+ * it under the terms of the GNU General Public License as published by
311+ * the Free Software Foundation; version 3.
312+ *
313+ * This program is distributed in the hope that it will be useful,
314+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
315+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
316+ * GNU General Public License for more details.
317+ *
318+ * You should have received a copy of the GNU General Public License
319+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
320+ */
321+
322+import QtQuick 2.0
323+import Ubuntu.Components 0.1
324+import Ubuntu.Components.Popups 0.1
325+
326+Component {
327+ Dialog {
328+ id: dialogue
329+
330+ title: i18n.tr("Error")
331+ text: i18n.tr("Contact not found")
332+
333+ Button {
334+ text: "Cancel"
335+ gradient: UbuntuColors.greyGradient
336+ onClicked: {
337+ PopupUtils.close(dialogue)
338+ pageStack.pop()
339+ }
340+ }
341+ }
342+}
343
344=== modified file 'src/imports/ContactList/ContactListPage.qml'
345--- src/imports/ContactList/ContactListPage.qml 2013-08-29 20:13:18 +0000
346+++ src/imports/ContactList/ContactListPage.qml 2013-09-17 22:21:49 +0000
347@@ -134,5 +134,9 @@
348 pageStack.push(Qt.resolvedUrl("../ContactEdit/ContactEditor.qml"),
349 {model: contactList.listModel, contact: newContact})
350 }
351+ onEditContatRequested: {
352+ pageStack.push(Qt.resolvedUrl("../ContactEdit/ContactEditor.qml"),
353+ {model: contactList.listModel, contactId: contactId, newPhoneNumber: phoneNumber })
354+ }
355 }
356 }
357
358=== modified file 'src/imports/main.qml'
359--- src/imports/main.qml 2013-09-09 21:38:01 +0000
360+++ src/imports/main.qml 2013-09-17 22:21:49 +0000
361@@ -35,11 +35,19 @@
362 mainStack.createContactRequested(phoneNumber)
363 }
364
365+ function addphone(contactId, phoneNumber) {
366+ mainStack.newPhoneNumber = phoneNumber
367+ mainStack.editContatRequested(contactId, phoneNumber)
368+ }
369+
370 PageStack {
371 id: mainStack
372
373+ property string newPhoneNumber: ""
374+
375 signal contactRequested(string contactId)
376 signal createContactRequested(string phoneNumber)
377+ signal editContatRequested(string contactId, string phoneNumber)
378
379 anchors {
380 fill: parent

Subscribers

People subscribed via source and target branches