Merge lp:~renatofilho/address-book-app/improve-vcard-import into lp:address-book-app
- improve-vcard-import
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Arthur Mello |
Approved revision: | 516 |
Merged at revision: | 510 |
Proposed branch: | lp:~renatofilho/address-book-app/improve-vcard-import |
Merge into: | lp:address-book-app |
Prerequisite: | lp:~renatofilho/address-book-app/fix-1511477 |
Diff against target: |
424 lines (+183/-116) 6 files modified
src/imports/ABContactListPage.qml (+136/-20) src/imports/CMakeLists.txt (+0/-1) src/imports/VCardImportDialog.qml (+0/-94) tests/autopilot/address_book_app/tests/__init__.py (+5/-1) tests/autopilot/address_book_app/tests/test_import_from_sim.py (+3/-0) tests/autopilot/address_book_app/tests/test_import_vcard.py (+39/-0) |
To merge this branch: | bzr merge lp:~renatofilho/address-book-app/improve-vcard-import |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Arthur Mello (community) | Approve | ||
Review via email: mp+278165@code.launchpad.net |
This proposal supersedes a proposal from 2015-11-18.
Commit message
Show a list of imported contacts when importing vcards.
Description of the change
Test vcard import
Import a vcard into contacts app using content-hub:
You can use gmail webapp or messaging app to receive vcards on the phone.
Test if a list with imported contacts appear
Test if the imported contact was imported to default address-book.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:502
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:503
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 504. By Renato Araujo Oliveira Filho
-
Merged: ~renatofilho/
address- book-app/ vcard-does- not-export- uid - 505. By Renato Araujo Oliveira Filho
-
Merged: ~renatofilho/
address- book-app/ contact- view-editable
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:503
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:505
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 506. By Renato Araujo Oliveira Filho
-
Does not reset contact list state after edit a contact while importing contacts.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:506
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 507. By Renato Araujo Oliveira Filho
-
Show a 'busy' dialog while importing contacts.
- 508. By Renato Araujo Oliveira Filho
-
Make sure that the contact list is cleared before apply a new filter to avoid delays on contact populte.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:508
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 509. By Renato Araujo Oliveira Filho
-
Trunk merged.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:509
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 510. By Renato Araujo Oliveira Filho
-
Trunk merged.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:510
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 511. By Renato Araujo Oliveira Filho
-
Show a error message if the contact import fails.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:511
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 512. By Renato Araujo Oliveira Filho
-
Test import vcard.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:512
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Arthur Mello (artmello) : | # |
- 513. By Renato Araujo Oliveira Filho
-
Typo fixed.
- 514. By Renato Araujo Oliveira Filho
-
Only try to stop maliit if it is running already.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:514
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 515. By Renato Araujo Oliveira Filho
-
Avoid switch to importVcard state while loading test data.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:515
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 516. By Renato Araujo Oliveira Filho
-
Update import from sim autopilot test.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:516
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'src/imports/ABContactListPage.qml' |
2 | --- src/imports/ABContactListPage.qml 2015-11-24 00:30:20 +0000 |
3 | +++ src/imports/ABContactListPage.qml 2015-11-25 18:33:17 +0000 |
4 | @@ -38,6 +38,8 @@ |
5 | property alias contactManager: contactList.manager |
6 | property Page contactViewPage: null |
7 | property Page contactEditorPage: null |
8 | + property var _busyDialog: null |
9 | + property bool _importingTestData: false |
10 | |
11 | readonly property bool bottomEdgePageOpened: bottomEdge.opened && bottomEdge.fullLoaded |
12 | readonly property bool isEmpty: (contactList.count === 0) |
13 | @@ -84,7 +86,8 @@ |
14 | function showContact(contact) |
15 | { |
16 | // go back to normal state if not searching |
17 | - if (state !== "searching") { |
18 | + if ((state !== "searching") && |
19 | + (state !== "vcardImported")) { |
20 | mainPage.state = "default"; |
21 | } |
22 | openViewPage({model: contactList.listModel, |
23 | @@ -106,14 +109,21 @@ |
24 | |
25 | function importContact(urls) |
26 | { |
27 | - if (urls.length > 0) { |
28 | - var importDialog = Qt.createQmlObject("VCardImportDialog{}", |
29 | - mainPage, |
30 | - "VCardImportDialog") |
31 | - if (importDialog) { |
32 | - importDialog.importVCards(contactList.listModel, urls) |
33 | + mainPage._busyDialog = PopupUtils.open(busyDialogComponent, mainPage) |
34 | + |
35 | + var importing = false |
36 | + for(var i=0, iMax=urls.length; i < iMax; i++) { |
37 | + var url = urls[i] |
38 | + if (url && url != "") { |
39 | + importing = true |
40 | + contactList.listModel.importContacts(url) |
41 | } |
42 | } |
43 | + |
44 | + if (!importing) { |
45 | + PopupUtils.close(mainPage._busyDialog) |
46 | + mainPage._busyDialog = null |
47 | + } |
48 | } |
49 | |
50 | function startPickMode(isSingleSelection, activeTransfer) |
51 | @@ -126,8 +136,9 @@ |
52 | |
53 | function moveListToContact(contact) |
54 | { |
55 | - // skipt it if searching |
56 | - if (state === "searching") { |
57 | + // skipt it if searching or importing contacts |
58 | + if ((state === "searching") || |
59 | + (state === "vcardImported")) { |
60 | return |
61 | } |
62 | |
63 | @@ -428,6 +439,53 @@ |
64 | detailToPick: -1 |
65 | showAddNewButton: true |
66 | } |
67 | + PropertyChanges { |
68 | + target: bottomEdge |
69 | + enabled: false |
70 | + } |
71 | + }, |
72 | + PageHeadState { |
73 | + id: vcardImportedState |
74 | + |
75 | + name: "vcardImported" |
76 | + backAction: Action { |
77 | + iconName: "back" |
78 | + text: i18n.tr("Back") |
79 | + onTriggered: { |
80 | + contactList.forceActiveFocus() |
81 | + mainPage.state = "default" |
82 | + importedIdsFilter.ids = [] |
83 | + } |
84 | + } |
85 | + PropertyChanges { |
86 | + target: mainPage.head |
87 | + backAction: vcardImportedState.backAction |
88 | + } |
89 | + PropertyChanges { |
90 | + target: bottomEdge |
91 | + enabled: false |
92 | + } |
93 | + PropertyChanges { |
94 | + target: mainPage |
95 | + title: i18n.tr("Imported contacts") |
96 | + } |
97 | + } |
98 | + ] |
99 | + |
100 | + //WORKAROUND: we need to call 'changeFilter' manually to make sure that the model will be cleared |
101 | + // before update it with the new model. This is faster than do a match of contacts |
102 | + transitions: [ |
103 | + Transition { |
104 | + from: "vcardImported" |
105 | + ScriptAction { |
106 | + script: contactList.listModel.changeFilter(null) |
107 | + } |
108 | + }, |
109 | + Transition { |
110 | + to: "vcardImported" |
111 | + ScriptAction { |
112 | + script: contactList.listModel.changeFilter(importedIdsFilter) |
113 | + } |
114 | } |
115 | ] |
116 | |
117 | @@ -440,6 +498,10 @@ |
118 | } |
119 | } |
120 | |
121 | + IdFilter { |
122 | + id: importedIdsFilter |
123 | + } |
124 | + |
125 | KeyboardRectangle { |
126 | id: keyboard |
127 | } |
128 | @@ -492,16 +554,6 @@ |
129 | } |
130 | } |
131 | |
132 | - Connections { |
133 | - target: mainPage.contactModel |
134 | - onContactsChanged: { |
135 | - if (contactIndex) { |
136 | - contactList.positionViewAtContact(mainPage.contactIndex) |
137 | - mainPage.contactIndex = null |
138 | - } |
139 | - } |
140 | - } |
141 | - |
142 | ContactExporter { |
143 | id: contactExporter |
144 | |
145 | @@ -543,6 +595,35 @@ |
146 | } |
147 | |
148 | Component { |
149 | + id: busyDialogComponent |
150 | + |
151 | + Popups.Dialog { |
152 | + id: busyDialog |
153 | + |
154 | + property alias allowToClose: closeButton.visible |
155 | + property alias showActivity: busyIndicator.visible |
156 | + |
157 | + title: i18n.tr("Importing...") |
158 | + |
159 | + ActivityIndicator { |
160 | + id: busyIndicator |
161 | + running: visible |
162 | + visible: true |
163 | + } |
164 | + Button { |
165 | + id: closeButton |
166 | + text: i18n.tr("Close") |
167 | + visible: false |
168 | + color: UbuntuColors.red |
169 | + onClicked: { |
170 | + PopupUtils.close(mainPage._busyDialog) |
171 | + mainPage._busyDialog = null |
172 | + } |
173 | + } |
174 | + } |
175 | + } |
176 | + |
177 | + Component { |
178 | id: contactShareComponent |
179 | |
180 | ContactSharePage { |
181 | @@ -552,7 +633,8 @@ |
182 | |
183 | Component.onCompleted: { |
184 | application.elapsed() |
185 | - if ((typeof(TEST_DATA) !== "undefined") && (TEST_DATA !== "")) { |
186 | + if ((typeof(TEST_DATA) !== "undefined") && (TEST_DATA != "")) { |
187 | + mainPage._importingTestData = true |
188 | contactList.listModel.importContacts("file://" + TEST_DATA) |
189 | } |
190 | |
191 | @@ -661,6 +743,40 @@ |
192 | } |
193 | |
194 | Connections { |
195 | + target: mainPage.contactModel |
196 | + onContactsChanged: { |
197 | + if (contactIndex) { |
198 | + contactList.positionViewAtContact(mainPage.contactIndex) |
199 | + mainPage.contactIndex = null |
200 | + } |
201 | + } |
202 | + onImportCompleted: { |
203 | + if (mainPage._importingTestData) { |
204 | + mainPage._importingTestData = false |
205 | + return |
206 | + } |
207 | + |
208 | + if (error !== ContactModel.ImportNoError) { |
209 | + console.error("Fail to import vcard:" + error) |
210 | + mainPage._busyDialog.title = i18n.tr("Fail to import contacts!") |
211 | + mainPage._busyDialog.allowToClose = true |
212 | + mainPage._busyDialog.showActivity = false |
213 | + } else { |
214 | + var importedIds = ids |
215 | + importedIds.concat(importedIdsFilter.ids) |
216 | + importedIdsFilter.ids = importedIds |
217 | + console.debug("Imported ids:" + importedIds) |
218 | + mainPage.state = "vcardImported" |
219 | + |
220 | + if (mainPage._busyDialog) { |
221 | + PopupUtils.close(mainPage._busyDialog) |
222 | + mainPage._busyDialog = null |
223 | + } |
224 | + } |
225 | + } |
226 | + } |
227 | + |
228 | + Connections { |
229 | target: mainPage.contactViewPage |
230 | onEditContact: { |
231 | openEditPage(editPageProperties, mainPage.contactViewPage); |
232 | |
233 | === modified file 'src/imports/CMakeLists.txt' |
234 | --- src/imports/CMakeLists.txt 2015-10-16 13:37:25 +0000 |
235 | +++ src/imports/CMakeLists.txt 2015-11-25 18:33:17 +0000 |
236 | @@ -6,7 +6,6 @@ |
237 | ABContactViewPage.qml |
238 | ContentHubProxy.qml |
239 | MainWindow.qml |
240 | - VCardImportDialog.qml |
241 | BottomEdgeShadow.qml |
242 | BottomEdge.qml |
243 | ) |
244 | |
245 | === removed file 'src/imports/VCardImportDialog.qml' |
246 | --- src/imports/VCardImportDialog.qml 2015-10-26 13:18:11 +0000 |
247 | +++ src/imports/VCardImportDialog.qml 1970-01-01 00:00:00 +0000 |
248 | @@ -1,94 +0,0 @@ |
249 | -/* |
250 | - * Copyright (C) 2014 Canonical, Ltd. |
251 | - * |
252 | - * This program is free software; you can redistribute it and/or modify |
253 | - * it under the terms of the GNU General Public License as published by |
254 | - * the Free Software Foundation; version 3. |
255 | - * |
256 | - * This program is distributed in the hope that it will be useful, |
257 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
258 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
259 | - * GNU General Public License for more details. |
260 | - * |
261 | - * You should have received a copy of the GNU General Public License |
262 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
263 | - */ |
264 | - |
265 | -import QtQuick 2.4 |
266 | -import QtContacts 5.0 |
267 | -import Ubuntu.Components 1.3 |
268 | -import Ubuntu.Components.Popups 1.3 as Popups |
269 | - |
270 | -Item { |
271 | - id: root |
272 | - |
273 | - property alias model: modelConnections.target |
274 | - property var vcards: [] |
275 | - property var importedVcards: [] |
276 | - property var importErrors: [] |
277 | - property var dialog: null |
278 | - |
279 | - signal finished() |
280 | - |
281 | - function importVCards(model, vcards) |
282 | - { |
283 | - if (dialog || vcards.length === 0) { |
284 | - return |
285 | - } |
286 | - |
287 | - root.model = model |
288 | - root.vcards = vcards |
289 | - dialog = Popups.PopupUtils.open(importDialogComponent, root) |
290 | - |
291 | - for(var i=0, iMax=vcards.length; i < iMax; i++) { |
292 | - var vcardUrl = vcards[i] |
293 | - model.importContacts(vcardUrl) |
294 | - } |
295 | - } |
296 | - |
297 | - Connections { |
298 | - id: modelConnections |
299 | - |
300 | - onImportCompleted: { |
301 | - var imported = root.importedVcards |
302 | - var importErrors = root.importErrors |
303 | - imported.push(url) |
304 | - if (error !== ContactModel.ImportNoError) { |
305 | - root.importErrors.push(error) |
306 | - console.error("Fail to import vcard:" + error) |
307 | - } |
308 | - root.importedVcards = imported |
309 | - root.importErrors = importErrors |
310 | - } |
311 | - } |
312 | - |
313 | - Component { |
314 | - id: importDialogComponent |
315 | - |
316 | - Popups.Dialog { |
317 | - id: importDialog |
318 | - |
319 | - title: i18n.tr("Import vCards") |
320 | - text: root.importedVcards.length === 0 ? i18n.tr("Importing...") : i18n.tr("%1 vCards imported").arg(root.importedVcards.length) |
321 | - |
322 | - Button { |
323 | - anchors { |
324 | - left: parent.left |
325 | - right: parent.right |
326 | - margins: units.gu(1) |
327 | - } |
328 | - text: i18n.tr("Close") |
329 | - enabled: (root.importedVcards.length === root.vcards.length) |
330 | - onClicked: { |
331 | - root.dialog = null |
332 | - Popups.PopupUtils.close(importDialog) |
333 | - } |
334 | - } |
335 | - |
336 | - Component.onDestruction: root.destroy() |
337 | - } |
338 | - } |
339 | -} |
340 | - |
341 | - |
342 | - |
343 | |
344 | === modified file 'tests/autopilot/address_book_app/tests/__init__.py' |
345 | --- tests/autopilot/address_book_app/tests/__init__.py 2015-09-29 18:05:25 +0000 |
346 | +++ tests/autopilot/address_book_app/tests/__init__.py 2015-11-25 18:33:17 +0000 |
347 | @@ -19,6 +19,7 @@ |
348 | import os |
349 | import time |
350 | import subprocess |
351 | +import re |
352 | |
353 | from autopilot.testcase import AutopilotTestCase |
354 | from autopilot.matchers import Eventually |
355 | @@ -47,7 +48,10 @@ |
356 | |
357 | # stop vkb |
358 | if model() != "Desktop": |
359 | - subprocess.check_call(["/sbin/initctl", "stop", "maliit-server"]) |
360 | + maliit_info = subprocess.Popen(['/sbin/initctl', 'status', 'maliit-server'], stdout=subprocess.PIPE) |
361 | + result = maliit_info.stdout.read() |
362 | + if b'start/running,' in result.split(): |
363 | + subprocess.check_call(['/sbin/initctl', 'stop', 'maliit-server']) |
364 | |
365 | if 'AUTOPILOT_APP' in os.environ: |
366 | self.app_bin = os.environ['AUTOPILOT_APP'] |
367 | |
368 | === modified file 'tests/autopilot/address_book_app/tests/test_import_from_sim.py' |
369 | --- tests/autopilot/address_book_app/tests/test_import_from_sim.py 2015-04-30 17:22:48 +0000 |
370 | +++ tests/autopilot/address_book_app/tests/test_import_from_sim.py 2015-11-25 18:33:17 +0000 |
371 | @@ -70,6 +70,9 @@ |
372 | self.assertThat(len(contacts), Equals(2)) |
373 | self.app.main_window.confirm_import() |
374 | |
375 | + # dismiss imported contact list |
376 | + self.app.main_window.cancel() |
377 | + |
378 | # verify if the contact was imported |
379 | new_contacts = list_page.get_contacts() |
380 | self.assertThat(len(new_contacts), Equals(2)) |
381 | |
382 | === added file 'tests/autopilot/address_book_app/tests/test_import_vcard.py' |
383 | --- tests/autopilot/address_book_app/tests/test_import_vcard.py 1970-01-01 00:00:00 +0000 |
384 | +++ tests/autopilot/address_book_app/tests/test_import_vcard.py 2015-11-25 18:33:17 +0000 |
385 | @@ -0,0 +1,39 @@ |
386 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
387 | +# Copyright 2015 Canonical |
388 | +# |
389 | +# This program is free software: you can redistribute it and/or modify it |
390 | +# under the terms of the GNU General Public License version 3, as published |
391 | +# by the Free Software Foundation. |
392 | + |
393 | +"""Tests for the Addressbook App""" |
394 | + |
395 | +from __future__ import absolute_import |
396 | +from testtools.matchers import Equals |
397 | +from autopilot.matchers import Eventually |
398 | +import os |
399 | + |
400 | +from address_book_app.tests import AddressBookAppTestCase |
401 | + |
402 | + |
403 | +class TeseImportVCard(AddressBookAppTestCase): |
404 | + """Tests import vcard""" |
405 | + |
406 | + def setUp(self): |
407 | + vcard_path = AddressBookAppTestCase.VCARD_PATH_DEV |
408 | + if os.path.exists(AddressBookAppTestCase.VCARD_PATH_BIN): |
409 | + vcard_path = AddressBookAppTestCase.VCARD_PATH_BIN |
410 | + |
411 | + self.ARGS.append("addressbook:///importvcard?url=file://%s" % vcard_path) |
412 | + super(TeseImportVCard, self).setUp() |
413 | + |
414 | + def test_import_vcard_results(self): |
415 | + # check if app enter on import state |
416 | + list_page = self.app.main_window.get_contact_list_page() |
417 | + self.assertThat(list_page.state, Eventually(Equals('vcardImported'))) |
418 | + self.assertThat(list_page.title, Eventually(Equals('Imported contacts'))) |
419 | + self.assertThat(len(list_page.get_contacts()), Equals(3)) |
420 | + |
421 | + #leave import state and show full contact list |
422 | + self.app.main_window.cancel() |
423 | + self.assertThat(list_page.state, Eventually(Equals('default'))) |
424 | + self.assertThat(list_page.title, Eventually(Equals('Contacts'))) |
FAILED: Continuous integration, rev:501 jenkins. qa.ubuntu. com/job/ address- book-app- ci/1009/ jenkins. qa.ubuntu. com/job/ address- book-app- vivid-i386- ci/312/ console jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 5253/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 5273/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/address- book-app- ci/1009/ rebuild
http://