Merge lp:~renatofilho/dialer-app/addressbook-components into lp:dialer-app

Proposed by Renato Araujo Oliveira Filho
Status: Merged
Approved by: Gustavo Pichorim Boiko
Approved revision: 416
Merged at revision: 410
Proposed branch: lp:~renatofilho/dialer-app/addressbook-components
Merge into: lp:dialer-app
Diff against target: 992 lines (+625/-42)
23 files modified
debian/control (+3/-2)
debian/dialer-app-autopilot.install (+1/-0)
debian/dialer-app.install (+2/-0)
src/dialerapplication.cpp (+4/-0)
src/qml/CMakeLists.txt (+2/-0)
src/qml/ContactEditorPage/CMakeLists.txt (+7/-0)
src/qml/ContactEditorPage/DialerContactEditorPage.qml (+60/-0)
src/qml/ContactViewPage/CMakeLists.txt (+7/-0)
src/qml/ContactViewPage/DialerContactViewPage.qml (+139/-0)
src/qml/ContactsPage/ContactsPage.qml (+55/-7)
src/qml/DialerPage/DialerPage.qml (+1/-0)
src/qml/HistoryPage/HistoryDetailsPage.qml (+1/-1)
src/qml/HistoryPage/HistoryPage.qml (+1/-1)
src/qml/dialer-app.qml (+35/-17)
tests/CMakeLists.txt (+4/-1)
tests/autopilot/CMakeLists.txt (+0/-2)
tests/autopilot/dialer_app/__init__.py (+95/-0)
tests/autopilot/dialer_app/fixture_setup.py (+37/-0)
tests/autopilot/dialer_app/tests/__init__.py (+8/-4)
tests/autopilot/dialer_app/tests/test_contacts.py (+45/-0)
tests/autopilot/dialer_app/tests/test_logs.py (+78/-7)
tests/data/CMakeLists.txt (+10/-0)
tests/data/vcard.vcf (+30/-0)
To merge this branch: bzr merge lp:~renatofilho/dialer-app/addressbook-components
Reviewer Review Type Date Requested Status
Ricardo Salveti (community) packaging Approve
PS Jenkins bot continuous-integration Needs Fixing
Gustavo Pichorim Boiko (community) Approve
Review via email: mp+257914@code.launchpad.net

Commit message

Make use of the new address book components instead of launch the address-book-app.

To post a comment you must log in.
400. By Renato Araujo Oliveira Filho

Added new dependency.

401. By Renato Araujo Oliveira Filho

Updated dialer app install file.

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)
402. By Renato Araujo Oliveira Filho

Fixed build deps.

403. By Renato Araujo Oliveira Filho

Fixed add number to contact use case.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
404. By Renato Araujo Oliveira Filho

Update autopilot test.

405. By Renato Araujo Oliveira Filho

Trunk merged.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
406. By Renato Araujo Oliveira Filho

Trigger a call if clicked on contact phone on contact view page.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
407. By Renato Araujo Oliveira Filho

Update test log to check if the contact was created with the correct phone number.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
408. By Renato Araujo Oliveira Filho

Create autopilot test for contacts page.

409. By Renato Araujo Oliveira Filho

Removed debug messages.
Updated autopilot install file with the new data dir.

410. By Renato Araujo Oliveira Filho

Trunk merged.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
411. By Renato Araujo Oliveira Filho

Add missing test.

412. By Renato Araujo Oliveira Filho

Fixed debian package.

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

Are there any related MPs required for this MP to build/function as expected?
YES: https://code.launchpad.net/~renatofilho/address-book-app/split-app/+merge/258937

Is your branch in sync with latest trunk?
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 on device or emulator?
YES

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

If you changed UI labels, did you update the pot file?
NO LABEL CHANGE

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

413. By Renato Araujo Oliveira Filho

Avoid fetch contact twice while adding a new number.

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

dialer-app-autopilot needs to depend on address-book-app-autopilot for the tests to work

review: Needs Fixing
414. By Renato Araujo Oliveira Filho

Added 'address-book-app-autopilot' into autopilot dep list.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
415. By Renato Araujo Oliveira Filho

Install vcard files into autopilot data dir.

416. By Renato Araujo Oliveira Filho

Updated header.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
417. By Renato Araujo Oliveira Filho

Trunk merged.

418. By Renato Araujo Oliveira Filho

Fixed flake8.

Revision history for this message
Gustavo Pichorim Boiko (boiko) wrote :

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

Did CI run pass? If not, please explain why.
No: this change needs changes on address-book-app to work

Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?
Yes

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
419. By Renato Araujo Oliveira Filho

call external urls as ("<action>:<value>") instead of ("<action>:///<value>")

Revision history for this message
Ricardo Salveti (rsalveti) wrote :

Packaging changes look fine.

review: Approve (packaging)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2015-04-27 22:15:19 +0000
+++ debian/control 2015-05-15 15:18:10 +0000
@@ -16,7 +16,7 @@
16 qtdeclarative5-dev (>= 5.0),16 qtdeclarative5-dev (>= 5.0),
17 qtdeclarative5-dev-tools,17 qtdeclarative5-dev-tools,
18 qtdeclarative5-ubuntu-telephony0.1 | qtdeclarative5-ubuntu-telephony-plugin,18 qtdeclarative5-ubuntu-telephony0.1 | qtdeclarative5-ubuntu-telephony-plugin,
19 qtdeclarative5-ubuntu-contacts0.1,19 qtdeclarative5-ubuntu-addressbook0.1,
20 qtdeclarative5-qtcontacts-plugin,20 qtdeclarative5-qtcontacts-plugin,
21 qtdeclarative5-ubuntu-telephony-phonenumber0.1,21 qtdeclarative5-ubuntu-telephony-phonenumber0.1,
22 qtdeclarative5-ubuntu-history0.1,22 qtdeclarative5-ubuntu-history0.1,
@@ -39,7 +39,7 @@
39 qtdeclarative5-ubuntu-telephony0.1 | qtdeclarative5-ubuntu-telephony-plugin,39 qtdeclarative5-ubuntu-telephony0.1 | qtdeclarative5-ubuntu-telephony-plugin,
40 qtdeclarative5-ubuntu-telephony-phonenumber0.1,40 qtdeclarative5-ubuntu-telephony-phonenumber0.1,
41 qtdeclarative5-ubuntu-ui-toolkit-plugin | qt-components-ubuntu,41 qtdeclarative5-ubuntu-ui-toolkit-plugin | qt-components-ubuntu,
42 qtdeclarative5-ubuntu-contacts0.1 (>= 0.2+14.10.20140805),42 qtdeclarative5-ubuntu-addressbook0.1,
43 qtdeclarative5-qtcontacts-plugin,43 qtdeclarative5-qtcontacts-plugin,
44Recommends: unity8 (>= 7.81.0~),44Recommends: unity8 (>= 7.81.0~),
45Description: Dialer application for Ubuntu45Description: Dialer application for Ubuntu
@@ -50,6 +50,7 @@
50Section: debug50Section: debug
51Depends: ${misc:Depends},51Depends: ${misc:Depends},
52 ${python3:Depends},52 ${python3:Depends},
53 address-book-app-autopilot,
53 autopilot-qt5,54 autopilot-qt5,
54 dbus,55 dbus,
55 libqt5test5,56 libqt5test5,
5657
=== modified file 'debian/dialer-app-autopilot.install'
--- debian/dialer-app-autopilot.install 2013-07-16 14:05:40 +0000
+++ debian/dialer-app-autopilot.install 2015-05-15 15:18:10 +0000
@@ -1,1 +1,2 @@
1usr/lib/python*/dist-packages/dialer_app/*1usr/lib/python*/dist-packages/dialer_app/*
2usr/lib/python*/dist-packages/dialer_app/testdata/*
23
=== modified file 'debian/dialer-app.install'
--- debian/dialer-app.install 2014-08-22 14:51:14 +0000
+++ debian/dialer-app.install 2015-05-15 15:18:10 +0000
@@ -6,6 +6,8 @@
6usr/share/dialer-app/HistoryPage6usr/share/dialer-app/HistoryPage
7usr/share/dialer-app/DialerPage7usr/share/dialer-app/DialerPage
8usr/share/dialer-app/ContactsPage8usr/share/dialer-app/ContactsPage
9usr/share/dialer-app/ContactViewPage
10usr/share/dialer-app/ContactEditorPage
9usr/share/dialer-app/Dialogs11usr/share/dialer-app/Dialogs
10usr/share/dialer-app/assets12usr/share/dialer-app/assets
11usr/share/dialer-app/MMI13usr/share/dialer-app/MMI
1214
=== modified file 'src/dialerapplication.cpp'
--- src/dialerapplication.cpp 2014-11-13 14:41:07 +0000
+++ src/dialerapplication.cpp 2015-05-15 15:18:10 +0000
@@ -143,6 +143,10 @@
143 m_view->rootContext()->setContextProperty("QTCONTACTS_MANAGER_OVERRIDE", contactsBackend);143 m_view->rootContext()->setContextProperty("QTCONTACTS_MANAGER_OVERRIDE", contactsBackend);
144 }144 }
145145
146 // used by autopilot tests to load vcards during tests
147 QByteArray testData = qgetenv("QTCONTACTS_PRELOAD_VCARD");
148 m_view->rootContext()->setContextProperty("QTCONTACTS_PRELOAD_VCARD", testData);
149
146 QString pluginPath = ubuntuPhonePluginPath();150 QString pluginPath = ubuntuPhonePluginPath();
147 if (!pluginPath.isNull()) {151 if (!pluginPath.isNull()) {
148 m_view->engine()->addImportPath(pluginPath);152 m_view->engine()->addImportPath(pluginPath);
149153
=== modified file 'src/qml/CMakeLists.txt'
--- src/qml/CMakeLists.txt 2014-08-27 16:07:33 +0000
+++ src/qml/CMakeLists.txt 2015-05-15 15:18:10 +0000
@@ -16,4 +16,6 @@
16add_subdirectory(HistoryPage)16add_subdirectory(HistoryPage)
17add_subdirectory(LiveCallPage)17add_subdirectory(LiveCallPage)
18add_subdirectory(ContactsPage)18add_subdirectory(ContactsPage)
19add_subdirectory(ContactViewPage)
20add_subdirectory(ContactEditorPage)
19add_subdirectory(Dialogs)21add_subdirectory(Dialogs)
2022
=== added directory 'src/qml/ContactEditorPage'
=== added file 'src/qml/ContactEditorPage/CMakeLists.txt'
--- src/qml/ContactEditorPage/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/qml/ContactEditorPage/CMakeLists.txt 2015-05-15 15:18:10 +0000
@@ -0,0 +1,7 @@
1file(GLOB CONTACT_EDITOR_QML_JS_FILES *.qml *.js)
2
3# make the files visible on qtcreator
4add_custom_target(dialer_contacteditor_QMlFiles ALL SOURCES ${CONTACT_EDITOR_QML_JS_FILES})
5
6install(FILES ${CONTACT_EDITOR_QML_JS_FILES} DESTINATION ${DIALER_APP_DIR}/ContactEditorPage)
7
08
=== added file 'src/qml/ContactEditorPage/DialerContactEditorPage.qml'
--- src/qml/ContactEditorPage/DialerContactEditorPage.qml 1970-01-01 00:00:00 +0000
+++ src/qml/ContactEditorPage/DialerContactEditorPage.qml 2015-05-15 15:18:10 +0000
@@ -0,0 +1,60 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This file is part of dialer-app.
5 *
6 * dialer-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * dialer-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.2
20import QtContacts 5.0
21
22import Ubuntu.Components 1.1
23
24import Ubuntu.AddressBook.ContactEditor 0.1
25
26ContactEditorPage {
27 id: root
28 objectName: "contactEditorPage"
29
30 property var contactListPage: null
31
32 head.backAction: Action {
33 objectName: "cancel"
34
35 text: i18n.tr("Cancel")
36 iconName: "back"
37 onTriggered: {
38 root.cancel()
39 root.active = false
40 }
41 }
42
43 head.actions: [
44 Action {
45 objectName: "save"
46
47 text: i18n.tr("Save")
48 iconName: "ok"
49 enabled: root.isContactValid
50 onTriggered: root.save()
51 }
52 ]
53
54 onContactSaved: {
55 if (root.contactListPage) {
56 root.contactListPage.moveListToContact(contact)
57 root.contactListPage.phoneToAdd = ""
58 }
59 }
60}
061
=== added directory 'src/qml/ContactViewPage'
=== added file 'src/qml/ContactViewPage/CMakeLists.txt'
--- src/qml/ContactViewPage/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/qml/ContactViewPage/CMakeLists.txt 2015-05-15 15:18:10 +0000
@@ -0,0 +1,7 @@
1file(GLOB CONTACT_VIEW_QML_JS_FILES *.qml *.js)
2
3# make the files visible on qtcreator
4add_custom_target(dialer_contactviewpage_QMlFiles ALL SOURCES ${CONTACT_VIEW_QML_JS_FILES})
5
6install(FILES ${CONTACT_VIEW_QML_JS_FILES} DESTINATION ${DIALER_APP_DIR}/ContactViewPage)
7
08
=== added file 'src/qml/ContactViewPage/DialerContactViewPage.qml'
--- src/qml/ContactViewPage/DialerContactViewPage.qml 1970-01-01 00:00:00 +0000
+++ src/qml/ContactViewPage/DialerContactViewPage.qml 2015-05-15 15:18:10 +0000
@@ -0,0 +1,139 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This file is part of dialer-app.
5 *
6 * dialer-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * dialer-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20import QtQuick 2.2
21import QtContacts 5.0
22
23import Ubuntu.Components 1.1
24import Ubuntu.Components.Popups 1.0 as Popups
25import Ubuntu.Contacts 0.1
26
27import Ubuntu.AddressBook.Base 0.1
28import Ubuntu.AddressBook.ContactView 0.1
29import Ubuntu.AddressBook.ContactShare 0.1
30
31ContactViewPage {
32 id: root
33 objectName: "contactViewPage"
34
35 readonly property string contactEditorPageURL: Qt.resolvedUrl("../ContactEditorPage/DialerContactEditorPage.qml")
36 property string addPhoneToContact: ""
37 property var contactListPage: null
38
39 function addPhoneToContactImpl(contact, phoneNumber)
40 {
41 var detailSourceTemplate = "import QtContacts 5.0; PhoneNumber{ number: \"" + phoneNumber.trim() + "\" }"
42 var newDetail = Qt.createQmlObject(detailSourceTemplate, contact)
43 if (newDetail) {
44 contact.addDetail(newDetail)
45 pageStack.push(root.contactEditorPageURL,
46 { model: root.model,
47 contact: contact,
48 initialFocusSection: "phones",
49 newDetails: [newDetail],
50 contactListPage: root.contactListPage })
51 root.addPhoneToContact = ""
52 } else {
53 console.warn("Fail to create phone number detail")
54 }
55 }
56
57 head.actions: [
58 Action {
59 objectName: "share"
60 text: i18n.tr("Share")
61 iconName: "share"
62 onTriggered: {
63 pageStack.push(root.contactShareComponent,
64 {contactModel: root.model, contacts: [root.contact]})
65 }
66 },
67 Action {
68 objectName: "edit"
69 text: i18n.tr("Edit")
70 iconName: "edit"
71 onTriggered: {
72 pageStack.push(contactEditorPageURL,
73 { model: root.model,
74 contact: root.contact,
75 contactListPage: root.contactListPage })
76 }
77 }
78 ]
79
80 extensions: ContactDetailSyncTargetView {
81 contact: root.contact
82 anchors {
83 left: parent.left
84 right: parent.right
85 }
86 height: implicitHeight
87 }
88
89 onContactRemoved: pageStack.pop()
90 onActionTrigerred: {
91 if ((action == "tel") || (action == "default")) {
92 if (callManager.hasCalls) {
93 mainView.call(detail.number, mainView.account.accountId);
94 } else {
95 mainView.populateDialpad(detail.number)
96 }
97 } else {
98 Qt.openUrlExternally(("%1:%2").arg(action).arg(detail.value(0)))
99 }
100 }
101
102 Component {
103 id: contactShareComponent
104 ContactSharePage {}
105 }
106
107 onContactFetched: {
108 root.contact = contact
109 if (root.active && root.addPhoneToContact != "") {
110 root.addPhoneToContactImpl(contact, root.addPhoneToContact)
111 root.addPhoneToContact = ""
112 }
113 }
114
115 Component {
116 id: contactModelComponent
117
118 ContactModel {
119 id: contactModelHelper
120
121 manager: (typeof(QTCONTACTS_MANAGER_OVERRIDE) !== "undefined") &&
122 (QTCONTACTS_MANAGER_OVERRIDE != "") ? QTCONTACTS_MANAGER_OVERRIDE : "galera"
123 autoUpdate: false
124 }
125 }
126
127 onActiveChanged: {
128 if (active && root.contact && root.addPhoneToContact != "") {
129 root.addPhoneToContactImpl(contact, root.addPhoneToContact)
130 root.addPhoneToContact = ""
131 }
132 }
133
134 Component.onCompleted: {
135 if (!root.model) {
136 root.model = contactModelComponent.createObject(root)
137 }
138 }
139}
0140
=== modified file 'src/qml/ContactsPage/ContactsPage.qml'
--- src/qml/ContactsPage/ContactsPage.qml 2015-02-06 00:12:03 +0000
+++ src/qml/ContactsPage/ContactsPage.qml 2015-05-15 15:18:10 +0000
@@ -27,10 +27,30 @@
27 id: contactsPage27 id: contactsPage
28 objectName: "contactsPage"28 objectName: "contactsPage"
2929
30 property QtObject contact30 property string phoneToAdd: ""
31 property QtObject contactIndex: null
32
33 function moveListToContact(contact)
34 {
35 if (active) {
36 contactsPage.contactIndex = null
37 contactList.positionViewAtContact(contact)
38 } else {
39 contactsPage.contactIndex = contact
40 }
41 }
42
43 Connections {
44 target: contactList.listModel
45 onContactsChanged: {
46 if (contactsPage.contactIndex) {
47 contactList.positionViewAtContact(contactsPage.contactIndex)
48 contactsPage.contactIndex = null
49 }
50 }
51 }
3152
32 title: i18n.tr("Contacts")53 title: i18n.tr("Contacts")
33
34 TextField {54 TextField {
35 id: searchField55 id: searchField
3656
@@ -138,17 +158,36 @@
138 }158 }
139159
140 showAddNewButton: true160 showAddNewButton: true
141 showImportOptions: (contactList.count === 0) && (filterTerm === "")161 showImportOptions: (contactList.count === 0) &&
142 onAddNewContactClicked: mainView.createNewContactForPhone(" ")162 (filterTerm === "") &&
143 onInfoRequested: mainView.viewContact(contact.contactId)163 (contactsPage.phoneToAdd === "")
164 onAddNewContactClicked: {
165 var newContact = ContactsJS.createEmptyContact(contactsPage.phoneToAdd, contactsPage)
166 pageStack.push(Qt.resolvedUrl("../ContactEditorPage/DialerContactEditorPage.qml"),
167 { model: contactList.listModel,
168 contact: newContact,
169 initialFocusSection: (contactsPage.phoneToAdd != "" ? "phones" : "name"),
170 contactListPage: contactsPage
171 })
172 }
173 onInfoRequested: mainView.viewContact(contact.contactId, contactList.listModel)
144174
145 filterTerm: searchField.text175 filterTerm: searchField.text
146 detailToPick: ContactDetail.PhoneNumber176 detailToPick: (contactsPage.phoneToAdd != "") ? -1 : ContactDetail.PhoneNumber
147 onDetailClicked: {177 onDetailClicked: {
148 if (action === "message") {178 if (action === "message") {
149 Qt.openUrlExternally("message:///" + encodeURIComponent(detail.number))179 Qt.openUrlExternally("message:///" + encodeURIComponent(detail.number))
150 return180 return
151 }181 }
182
183 if (contactsPage.phoneToAdd != "") {
184 mainView.addPhoneToContact(contact,
185 contactsPage.phoneToAdd,
186 contactsPage,
187 contactList.listModel)
188 return
189 }
190
152 pageStackNormalMode.pop()191 pageStackNormalMode.pop()
153 if (callManager.hasCalls) {192 if (callManager.hasCalls) {
154 mainView.call(detail.number, mainView.account.accountId);193 mainView.call(detail.number, mainView.account.accountId);
@@ -156,7 +195,16 @@
156 mainView.populateDialpad(detail.number)195 mainView.populateDialpad(detail.number)
157 }196 }
158 }197 }
159 onAddDetailClicked: mainView.addPhoneToContact(contact.contactId, " ")198 onAddDetailClicked: mainView.addPhoneToContact(contact.contactId,
199 " ",
200 contactsPage,
201 contactList.listModel)
202 }
203
204 Component.onCompleted: {
205 if (QTCONTACTS_PRELOAD_VCARD !== "") {
206 contactList.listModel.importContacts("file://" + QTCONTACTS_PRELOAD_VCARD)
207 }
160 }208 }
161209
162 KeyboardRectagle {210 KeyboardRectagle {
163211
=== modified file 'src/qml/DialerPage/DialerPage.qml'
--- src/qml/DialerPage/DialerPage.qml 2015-04-08 22:41:26 +0000
+++ src/qml/DialerPage/DialerPage.qml 2015-05-15 15:18:10 +0000
@@ -37,6 +37,7 @@
37 property list<Action> actionsGreeter37 property list<Action> actionsGreeter
38 property list<Action> actionsNormal: [38 property list<Action> actionsNormal: [
39 Action {39 Action {
40 objectName: "contacts"
40 iconName: "contact"41 iconName: "contact"
41 text: i18n.tr("Contacts")42 text: i18n.tr("Contacts")
42 onTriggered: pageStackNormalMode.push(Qt.resolvedUrl("../ContactsPage/ContactsPage.qml"))43 onTriggered: pageStackNormalMode.push(Qt.resolvedUrl("../ContactsPage/ContactsPage.qml"))
4344
=== modified file 'src/qml/HistoryPage/HistoryDetailsPage.qml'
--- src/qml/HistoryPage/HistoryDetailsPage.qml 2015-04-09 19:49:26 +0000
+++ src/qml/HistoryPage/HistoryDetailsPage.qml 2015-05-15 15:18:10 +0000
@@ -57,7 +57,7 @@
57 if (unknownContact) {57 if (unknownContact) {
58 mainView.addNewPhone(phoneNumber)58 mainView.addNewPhone(phoneNumber)
59 } else {59 } else {
60 mainView.viewContact(contactWatcher.contactId)60 mainView.viewContact(contactWatcher.contactId, null)
61 }61 }
62 }62 }
63 },63 },
6464
=== modified file 'src/qml/HistoryPage/HistoryPage.qml'
--- src/qml/HistoryPage/HistoryPage.qml 2015-05-06 20:06:37 +0000
+++ src/qml/HistoryPage/HistoryPage.qml 2015-05-15 15:18:10 +0000
@@ -347,7 +347,7 @@
347 if (unknownContact) {347 if (unknownContact) {
348 mainView.addNewPhone(phoneNumber)348 mainView.addNewPhone(phoneNumber)
349 } else {349 } else {
350 mainView.viewContact(contactId)350 mainView.viewContact(contactId, null)
351 }351 }
352 }352 }
353 visible: knownNumber353 visible: knownNumber
354354
=== modified file 'src/qml/dialer-app.qml'
--- src/qml/dialer-app.qml 2015-04-21 14:28:14 +0000
+++ src/qml/dialer-app.qml 2015-05-15 15:18:10 +0000
@@ -18,9 +18,11 @@
1818
19import QtQuick 2.019import QtQuick 2.0
20import Qt.labs.settings 1.020import Qt.labs.settings 1.0
21
21import Ubuntu.Components 1.122import Ubuntu.Components 1.1
22import Ubuntu.Components.Popups 0.123import Ubuntu.Components.Popups 0.1
23import Ubuntu.Telephony 0.124import Ubuntu.Telephony 0.1
25import Ubuntu.Contacts 0.1
2426
25MainView {27MainView {
26 id: mainView28 id: mainView
@@ -69,7 +71,7 @@
69 if (pageStackNormalMode.depth > 2 && pageStackNormalMode.currentPage.objectName == "contactsPage") {71 if (pageStackNormalMode.depth > 2 && pageStackNormalMode.currentPage.objectName == "contactsPage") {
70 pageStackNormalMode.pop();72 pageStackNormalMode.pop();
71 }73 }
72 74
73 // pop live call views from both stacks if we have no calls.75 // pop live call views from both stacks if we have no calls.
74 if (pageStackNormalMode.depth > 1 && pageStackNormalMode.currentPage.objectName == "pageLiveCall") {76 if (pageStackNormalMode.depth > 1 && pageStackNormalMode.currentPage.objectName == "pageLiveCall") {
75 pageStackNormalMode.pop();77 pageStackNormalMode.pop();
@@ -175,22 +177,38 @@
175 return false;177 return false;
176 }178 }
177179
178 function createNewContactForPhone(phoneNumber)180 function addNewPhone(phoneNumber)
179 {181 {
180 Qt.openUrlExternally("addressbook:///create?callback=dialer-app.desktop&phone=" + encodeURIComponent(phoneNumber))182 pageStackNormalMode.push(Qt.resolvedUrl("ContactsPage/ContactsPage.qml"),
181 }183 {"phoneToAdd": phoneNumber})
182184 }
183 function viewContact(contactId) {185
184 Qt.openUrlExternally("addressbook:///contact?callback=dialer-app.desktop&id=" + encodeURIComponent(contactId))186 function viewContact(contactId, model) {
185 }187 var initialPropers = {}
186188 if (model) {
187 function addNewPhone(phoneNumber) {189 initialPropers = {"contactId": contactId, "model": model}
188 Qt.openUrlExternally("addressbook:///addnewphone?callback=dialer-app.desktop&phone=" + encodeURIComponent(phoneNumber))190 } else {
189 }191 initialPropers = {"contactId": contactId}
190192 }
191 function addPhoneToContact(contactId, phoneNumber) {193 pageStackNormalMode.push(Qt.resolvedUrl("ContactViewPage/DialerContactViewPage.qml"),
192 Qt.openUrlExternally("addressbook:///addphone?callback=dialer-app.desktop&id=%1&phone=%2".arg(encodeURIComponent(contactId))194 initialPropers)
193 .arg(encodeURIComponent(phoneNumber)))195 }
196
197 function addPhoneToContact(contact, phoneNumber, contactListPage, model) {
198 var initialPropers = {"addPhoneToContact": phoneNumber,
199 "contactListPage": contactListPage}
200
201 if (model) {
202 initialPropers["model"] = model
203 }
204 if (typeof(contact) == 'string') {
205 initialPropers["contactId"] = contact
206 } else {
207 initialPropers["contact"] = contact
208 }
209
210 pageStackNormalMode.push(Qt.resolvedUrl("ContactViewPage/DialerContactViewPage.qml"),
211 initialPropers)
194 }212 }
195213
196 function sendMessage(phoneNumber) {214 function sendMessage(phoneNumber) {
@@ -396,7 +414,7 @@
396 if (currentStack.currentPage.objectName == "pageLiveCall") {414 if (currentStack.currentPage.objectName == "pageLiveCall") {
397 return;415 return;
398 }416 }
399 417
400 currentStack.push(Qt.resolvedUrl("LiveCallPage/LiveCall.qml"), properties)418 currentStack.push(Qt.resolvedUrl("LiveCallPage/LiveCall.qml"), properties)
401 }419 }
402420
403421
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2014-09-02 21:54:21 +0000
+++ tests/CMakeLists.txt 2015-05-15 15:18:10 +0000
@@ -1,3 +1,6 @@
1execute_process(COMMAND python3 -c "from distutils.sysconfig import get_python_lib; print (get_python_lib())"
2 OUTPUT_VARIABLE PYTHON_PACKAGE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
3
1add_subdirectory(qml)4add_subdirectory(qml)
25add_subdirectory(data)
3add_subdirectory(autopilot)6add_subdirectory(autopilot)
47
=== modified file 'tests/autopilot/CMakeLists.txt'
--- tests/autopilot/CMakeLists.txt 2014-08-13 17:24:42 +0000
+++ tests/autopilot/CMakeLists.txt 2015-05-15 15:18:10 +0000
@@ -1,7 +1,5 @@
1set(AUTOPILOT_DIR dialer_app)1set(AUTOPILOT_DIR dialer_app)
22
3execute_process(COMMAND python3 -c "from distutils.sysconfig import get_python_lib; print (get_python_lib())"
4 OUTPUT_VARIABLE PYTHON_PACKAGE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
53
6install(DIRECTORY ${AUTOPILOT_DIR}4install(DIRECTORY ${AUTOPILOT_DIR}
7 DESTINATION ${PYTHON_PACKAGE_DIR}5 DESTINATION ${PYTHON_PACKAGE_DIR}
86
=== modified file 'tests/autopilot/dialer_app/__init__.py'
--- tests/autopilot/dialer_app/__init__.py 2015-04-27 22:15:19 +0000
+++ tests/autopilot/dialer_app/__init__.py 2015-05-15 15:18:10 +0000
@@ -12,6 +12,9 @@
12import logging12import logging
1313
14import ubuntuuitoolkit14import ubuntuuitoolkit
15
16from address_book_app.address_book import _common
17from address_book_app import address_book
15from autopilot import exceptions as autopilot_exceptions18from autopilot import exceptions as autopilot_exceptions
1619
1720
@@ -30,6 +33,18 @@
30 self.hasCalls.wait_for(True)33 self.hasCalls.wait_for(True)
31 return self.wait_select_single(LiveCall, active=True)34 return self.wait_select_single(LiveCall, active=True)
3235
36 @property
37 def contacts_page(self):
38 return self._get_page(ContactsPage, 'contactsPage')
39
40 @property
41 def contact_editor_page(self):
42 return self._get_page(DialerContactEditorPage, 'contactEditorPage')
43
44 @property
45 def contact_view_page(self):
46 return self._get_page(DialerContactViewPage, 'contactViewPage')
47
33 def get_first_log(self):48 def get_first_log(self):
34 return self.wait_select_single(objectName="historyDelegate0")49 return self.wait_select_single(objectName="historyDelegate0")
3550
@@ -63,6 +78,11 @@
6378
64 return dialog.visible79 return dialog.visible
6580
81 def _get_page(self, page_type, page_name):
82 page = self.wait_select_single(
83 page_type, objectName=page_name, active=True)
84 return page
85
6686
67class LiveCall(MainView):87class LiveCall(MainView):
6888
@@ -197,3 +217,78 @@
197 self.dial_number(number, formattedNumber)217 self.dial_number(number, formattedNumber)
198 self.click_call_button()218 self.click_call_button()
199 return self.get_root_instance().wait_select_single(LiveCall)219 return self.get_root_instance().wait_select_single(LiveCall)
220
221 def get_header(self):
222 """Return the Header custom proxy object of the Page."""
223 return self.get_root_instance().select_single(
224 'MainView').get_header()
225
226 def click_contacts_button(self):
227 self.get_header().click_action_button('contacts')
228
229
230class DialerContactViewPage(address_book.ContactViewPage):
231 """Autopilot custom proxy object for DialerContactViewPage components."""
232
233 def call_phone(self, index):
234 phone_group = self.select_single(
235 'ContactDetailGroupWithTypeView',
236 objectName='phones')
237
238 call_buttons = phone_group.select_many(
239 "ActionButton",
240 objectName="tel-contact")
241 self.pointing_device.click_object(call_buttons[index])
242
243
244class DialerContactEditorPage(address_book.ContactEditorPage):
245 """Autopilot custom proxy object for DialerContactEditorPage components."""
246
247 def save(self):
248 """
249 Press the 'Save' button
250 """
251 header = self.get_header(main_window_name='MainView')
252 header.click_action_button('save')
253
254
255class ContactsPage(_common.PageWithHeader):
256 """Autopilot custom proxy object for ContactsPage components."""
257
258 def _click_button(self, button):
259 """Generic way to click a button"""
260 self.visible.wait_for(True)
261 button.visible.wait_for(True)
262 self.pointing_device.click_object(button)
263 return button
264
265 def _get_add_new_button(self):
266 """Return the add-new button"""
267 return self.wait_select_single('ContactListButtonDelegate',
268 objectName='addNewButton')
269
270 def click_add_new(self):
271 self._click_button(self._get_add_new_button())
272
273 def click_contact(self, index):
274 contact_delegate = self._get_contact_delegate(index)
275 self.pointing_device.click_object(contact_delegate)
276
277 def open_contact(self, index):
278 contact_delegate = self._get_contact_delegate(index)
279 self.pointing_device.click_object(contact_delegate)
280 contact_delegate.state.wait_for('expanded')
281 details_button = contact_delegate.wait_select_single(
282 objectName='infoIcon')
283 self.pointing_device.click_object(details_button)
284 return self.get_root_instance().select_single(
285 DialerContactViewPage, objectName='contactViewPage')
286
287 def _get_contact_delegate(self, index):
288 contact_delegates = self._get_sorted_contact_delegates()
289 return contact_delegates[index]
290
291 def _get_sorted_contact_delegates(self):
292 contact_delegates = self.select_many('ContactDelegate', visible=True)
293 return sorted(
294 contact_delegates, key=lambda delegate: delegate.globalRect.y)
200295
=== modified file 'tests/autopilot/dialer_app/fixture_setup.py'
--- tests/autopilot/dialer_app/fixture_setup.py 2015-04-30 18:26:46 +0000
+++ tests/autopilot/dialer_app/fixture_setup.py 2015-05-15 15:18:10 +0000
@@ -24,6 +24,7 @@
24import dbusmock24import dbusmock
25from autopilot.platform import model25from autopilot.platform import model
26import dbus26import dbus
27from ubuntuuitoolkit import fixture_setup
2728
2829
29class TestabilityEnvironment(fixtures.Fixture):30class TestabilityEnvironment(fixtures.Fixture):
@@ -136,6 +137,42 @@
136 subprocess.call(['mc-tool', 'reconnect', 'ofono/ofono/account0'])137 subprocess.call(['mc-tool', 'reconnect', 'ofono/ofono/account0'])
137138
138139
140class UseMemoryContactBackend(fixtures.Fixture):
141
142 def setUp(self):
143 super().setUp()
144 self.useFixture(
145 fixtures.EnvironmentVariable(
146 'QTCONTACTS_MANAGER_OVERRIDE', newvalue='memory')
147 )
148 self.useFixture(
149 fixture_setup.InitctlEnvironmentVariable(
150 QTCONTACTS_MANAGER_OVERRIDE='memory')
151 )
152
153
154class PreloadVcards(fixtures.Fixture):
155 AUTOPILOT_DIR = "/usr/lib/python3/dist-packages/dialer_app/"
156 VCARD_PATH_BIN = ("%s/testdata/vcard.vcf" % AUTOPILOT_DIR)
157 VCARD_PATH_DEV = os.path.abspath("../data/vcard.vcf")
158
159 def setUp(self):
160 super().setUp()
161 vcard_full_path = PreloadVcards.VCARD_PATH_BIN
162 if os.path.isfile(PreloadVcards.VCARD_PATH_DEV):
163 vcard_full_path = PreloadVcards.VCARD_PATH_DEV
164
165 print("Loading contacts from: %s" % vcard_full_path)
166 self.useFixture(
167 fixtures.EnvironmentVariable(
168 'QTCONTACTS_PRELOAD_VCARD', newvalue=vcard_full_path)
169 )
170 self.useFixture(
171 fixture_setup.InitctlEnvironmentVariable(
172 QTCONTACTS_PRELOAD_VCARD=vcard_full_path)
173 )
174
175
139class MockNotificationSystem(fixtures.Fixture):176class MockNotificationSystem(fixtures.Fixture):
140177
141 def setUp(self):178 def setUp(self):
142179
=== modified file 'tests/autopilot/dialer_app/tests/__init__.py'
--- tests/autopilot/dialer_app/tests/__init__.py 2015-04-29 21:53:05 +0000
+++ tests/autopilot/dialer_app/tests/__init__.py 2015-05-15 15:18:10 +0000
@@ -82,7 +82,8 @@
8282
83 def create_config_file(self, firstLaunch=False):83 def create_config_file(self, firstLaunch=False):
84 self.user_config_dir = tempfile.mkdtemp(suffix='', prefix='dialer-app')84 self.user_config_dir = tempfile.mkdtemp(suffix='', prefix='dialer-app')
85 self.app_config_dir = (self.user_config_dir + '/com.ubuntu.dialer-app/')85 self.app_config_dir = (self.user_config_dir +
86 '/com.ubuntu.dialer-app/')
86 os.makedirs(self.app_config_dir)87 os.makedirs(self.app_config_dir)
87 config_file_path = (self.app_config_dir + '/DialerApp.conf')88 config_file_path = (self.app_config_dir + '/DialerApp.conf')
8889
@@ -91,13 +92,16 @@
91 else:92 else:
92 first_launch_flag = 'false'93 first_launch_flag = 'false'
93 with open(config_file_path, 'w') as config_file:94 with open(config_file_path, 'w') as config_file:
94 config_file.write('[General]\nhintNecessary=%s\n' % (first_launch_flag))95 config_file.write(
96 '[General]\nhintNecessary=%s\n' % (first_launch_flag))
9597
96 self.useFixture(98 self.useFixture(
97 fixtures.EnvironmentVariable('XDG_CONFIG_HOME', newvalue=self.user_config_dir)99 fixtures.EnvironmentVariable('XDG_CONFIG_HOME',
100 newvalue=self.user_config_dir)
98 )101 )
99 self.useFixture(102 self.useFixture(
100 fixture_setup.InitctlEnvironmentVariable(XDG_CONFIG_HOME=self.user_config_dir)103 fixture_setup.InitctlEnvironmentVariable(
104 XDG_CONFIG_HOME=self.user_config_dir)
101 )105 )
102106
103 @property107 @property
104108
=== added file 'tests/autopilot/dialer_app/tests/test_contacts.py'
--- tests/autopilot/dialer_app/tests/test_contacts.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/dialer_app/tests/test_contacts.py 2015-05-15 15:18:10 +0000
@@ -0,0 +1,45 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2015 Canonical
3# Author: Renato Araujo Oliveira Filho <renato.filho@canonical.com>
4#
5# This file is part of dialer-app.
6#
7# dialer-app is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10
11"""Tests for the Dialer App"""
12
13from autopilot.matchers import Eventually
14from testtools.matchers import Equals
15
16from dialer_app.tests import DialerAppTestCase
17from dialer_app import fixture_setup
18
19
20class TestContacts(DialerAppTestCase):
21 """Tests for the contacts interaction with the app."""
22
23 def setUp(self):
24 # set the fixtures before launching the app
25 testability_environment = fixture_setup.TestabilityEnvironment()
26 self.useFixture(testability_environment)
27 memory_backend = fixture_setup.UseMemoryContactBackend()
28 self.useFixture(memory_backend)
29 preload_data = fixture_setup.PreloadVcards()
30 self.useFixture(preload_data)
31
32 # now launch the app
33 super().setUp()
34
35 def _get_main_view(self, proxy_object):
36 return proxy_object.wait_select_single('QQuickView')
37
38 def test_call_a_contact_from_contact_view(self):
39 dialer_page = self.main_view.dialer_page
40 dialer_page.click_contacts_button()
41 contact_view_page = self.main_view.contacts_page.open_contact(0)
42
43 contact_view_page.call_phone(0)
44 entry = dialer_page._get_keypad_entry()
45 self.assertThat(entry.value, Eventually(Equals('444-44')))
046
=== modified file 'tests/autopilot/dialer_app/tests/test_logs.py'
--- tests/autopilot/dialer_app/tests/test_logs.py 2015-04-29 21:53:05 +0000
+++ tests/autopilot/dialer_app/tests/test_logs.py 2015-05-15 15:18:10 +0000
@@ -19,13 +19,12 @@
19 fixture_setup as url_dispatcher_fixtures19 fixture_setup as url_dispatcher_fixtures
20)20)
2121
22from address_book_app.address_book import data
22from dialer_app.tests import DialerAppTestCase23from dialer_app.tests import DialerAppTestCase
23from dialer_app import fixture_setup24from dialer_app import fixture_setup
24from dialer_app import ListItemWithActions25from dialer_app import ListItemWithActions
2526
2627
27@skipIf(model() == 'Desktop',
28 'only run on Ubuntu touch platforms')
29class TestCallLogs(DialerAppTestCase):28class TestCallLogs(DialerAppTestCase):
30 """Tests for the call log panel."""29 """Tests for the call log panel."""
3130
@@ -37,6 +36,10 @@
37 self.useFixture(fill_history)36 self.useFixture(fill_history)
38 self.fake_url_dispatcher = url_dispatcher_fixtures.FakeURLDispatcher()37 self.fake_url_dispatcher = url_dispatcher_fixtures.FakeURLDispatcher()
39 self.useFixture(self.fake_url_dispatcher)38 self.useFixture(self.fake_url_dispatcher)
39 memory_backend = fixture_setup.UseMemoryContactBackend()
40 self.useFixture(memory_backend)
41 preload_data = fixture_setup.PreloadVcards()
42 self.useFixture(preload_data)
4043
41 # now launch the app44 # now launch the app
42 super().setUp()45 super().setUp()
@@ -52,6 +55,7 @@
52 except fake_dispatcher.FakeDispatcherException:55 except fake_dispatcher.FakeDispatcherException:
53 return None56 return None
5457
58 @skipIf(model() == 'Desktop', 'only run on Ubuntu touch platforms')
55 def test_call_log_item_opens_messaging(self):59 def test_call_log_item_opens_messaging(self):
56 """Ensure tapping on 'send text message' item of a call log opens60 """Ensure tapping on 'send text message' item of a call log opens
57 the messaging app.61 the messaging app.
@@ -74,11 +78,78 @@
74 ListItemWithActions.HistoryDelegate, objectName='historyDelegate0')78 ListItemWithActions.HistoryDelegate, objectName='historyDelegate0')
75 delegate.add_contact()79 delegate.add_contact()
7680
77 self.assertThat(81 contacts_page = self.main_view.contacts_page
78 self.get_last_dispatch_url_call_parameter,82 self.assertThat(
79 Eventually(Equals(83 contacts_page.phoneToAdd, Eventually(Equals('800')))
80 'addressbook:///addnewphone?callback=dialer-app.desktop&'84
81 'phone=800')))85 # click add new button
86 contacts_page.click_add_new()
87
88 # wait page be ready for edit
89 contact_editor_page = self.main_view.contact_editor_page
90 self.main_view.contact_editor_page.wait_get_focus('phones')
91
92 # fill contact name
93 test_contact = data.Contact('FirstName', 'LastName')
94 test_contact.professional_details = []
95 contact_editor_page.fill_form(test_contact)
96
97 # save contact
98 contact_editor_page.save()
99
100 # contact view will appear with the new contact data
101 contact_view_page = contacts_page.open_contact(3)
102 self.assertThat(contact_view_page.visible, Eventually(Equals(True)))
103
104 # check if contact contains the new phone number
105 phone_group = contact_view_page.select_single(
106 'ContactDetailGroupWithTypeView',
107 objectName='phones')
108 self.assertThat(phone_group.detailsCount, Eventually(Equals(1)))
109
110 # check if the new value is correct
111 phone_label_1 = contact_view_page.select_single(
112 "Label",
113 objectName="label_phoneNumber_0.0")
114 self.assertThat(phone_label_1.text, Eventually(Equals('800')))
115
116 def test_add_number_into_old_contact_from_log(self):
117 """Ensure tapping on 'add new contact' item of a call log opens
118 the address-book app to allow add the numbe into a contact
119
120 """
121 delegate = self.main_view.wait_select_single(
122 ListItemWithActions.HistoryDelegate, objectName='historyDelegate0')
123 delegate.add_contact()
124
125 contacts_page = self.main_view.contacts_page
126 self.assertThat(
127 contacts_page.phoneToAdd, Eventually(Equals('800')))
128
129 # click on first contact to add number
130 contacts_page.click_contact(0)
131
132 # wait page be ready for edit
133 contact_editor_page = self.main_view.contact_editor_page
134 contact_editor_page.wait_get_focus('phones')
135
136 # save contact
137 contact_editor_page.save()
138
139 # contact view will appear with the new contact data
140 contact_view_page = self.main_view.contact_view_page
141
142 # check if contact contains the new phone number
143 phone_group = contact_view_page.select_single(
144 'ContactDetailGroupWithTypeView',
145 objectName='phones')
146 self.assertThat(phone_group.detailsCount, Eventually(Equals(2)))
147
148 # check if the new value is correct
149 phone_label_1 = contact_view_page.select_single(
150 "Label",
151 objectName="label_phoneNumber_1.0")
152 self.assertThat(phone_label_1.text, Eventually(Equals('800')))
82153
83154
84class TestSwipeItemTutorial(DialerAppTestCase):155class TestSwipeItemTutorial(DialerAppTestCase):
85156
=== added directory 'tests/data'
=== added file 'tests/data/CMakeLists.txt'
--- tests/data/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/data/CMakeLists.txt 2015-05-15 15:18:10 +0000
@@ -0,0 +1,10 @@
1project(test_data)
2
3set(AUTOPILOT_DATA
4 vcard.vcf
5)
6
7install(FILES ${AUTOPILOT_DATA}
8 DESTINATION ${PYTHON_PACKAGE_DIR}/dialer_app/testdata/
9)
10
011
=== added file 'tests/data/vcard.vcf'
--- tests/data/vcard.vcf 1970-01-01 00:00:00 +0000
+++ tests/data/vcard.vcf 2015-05-15 15:18:10 +0000
@@ -0,0 +1,30 @@
1BEGIN:VCARD
2VERSION:3.0
3UID:47bbbfcab7c9b8ef0e7375074d22ff54905174bd
4X-QTPROJECT-EXTENDED-DETAIL:CLIENTPIDMAP;[\n "1"\n]\n
5N:teste3;teste3;;;
6FN:teste3 teste3
7X-QTPROJECT-FAVORITE:false;0
8TEL:3333333
9CATEGORIES:T
10END:VCARD
11BEGIN:VCARD
12VERSION:3.0
13UID:e5bb57fc852541dfc9ad29d583a36f1c353b65ed
14X-QTPROJECT-EXTENDED-DETAIL:CLIENTPIDMAP;[\n "1"\n]\n
15N:test34;teste;;;
16FN:teste test34
17X-QTPROJECT-FAVORITE:false;0
18TEL:44444
19CATEGORIES:T
20END:VCARD
21BEGIN:VCARD
22VERSION:3.0
23UID:0d753ce1005dde92f69e4ddb62222240691693a0
24X-QTPROJECT-EXTENDED-DETAIL:CLIENTPIDMAP;[\n "1"\n]\n
25N:teste2;teste;;;
26FN:teste teste2
27X-QTPROJECT-FAVORITE:false;0
28TEL:111111
29CATEGORIES:T
30END:VCARD

Subscribers

People subscribed via source and target branches