Merge lp:~renatofilho/address-book-app/improve-vcard-import into lp:address-book-app

Proposed by Renato Araujo Oliveira Filho
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
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.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
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

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

Does not reset contact list state after edit a contact while importing contacts.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

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

Trunk merged.

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

Trunk merged.

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

Show a error message if the contact import fails.

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

Test import vcard.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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.

Revision history for this message
Arthur Mello (artmello) wrote :

lgtm

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

Avoid switch to importVcard state while loading test data.

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

Update import from sim autopilot test.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/imports/ABContactListPage.qml'
--- src/imports/ABContactListPage.qml 2015-11-24 00:30:20 +0000
+++ src/imports/ABContactListPage.qml 2015-11-25 18:33:17 +0000
@@ -38,6 +38,8 @@
38 property alias contactManager: contactList.manager38 property alias contactManager: contactList.manager
39 property Page contactViewPage: null39 property Page contactViewPage: null
40 property Page contactEditorPage: null40 property Page contactEditorPage: null
41 property var _busyDialog: null
42 property bool _importingTestData: false
4143
42 readonly property bool bottomEdgePageOpened: bottomEdge.opened && bottomEdge.fullLoaded44 readonly property bool bottomEdgePageOpened: bottomEdge.opened && bottomEdge.fullLoaded
43 readonly property bool isEmpty: (contactList.count === 0)45 readonly property bool isEmpty: (contactList.count === 0)
@@ -84,7 +86,8 @@
84 function showContact(contact)86 function showContact(contact)
85 {87 {
86 // go back to normal state if not searching88 // go back to normal state if not searching
87 if (state !== "searching") {89 if ((state !== "searching") &&
90 (state !== "vcardImported")) {
88 mainPage.state = "default";91 mainPage.state = "default";
89 }92 }
90 openViewPage({model: contactList.listModel,93 openViewPage({model: contactList.listModel,
@@ -106,14 +109,21 @@
106109
107 function importContact(urls)110 function importContact(urls)
108 {111 {
109 if (urls.length > 0) {112 mainPage._busyDialog = PopupUtils.open(busyDialogComponent, mainPage)
110 var importDialog = Qt.createQmlObject("VCardImportDialog{}",113
111 mainPage,114 var importing = false
112 "VCardImportDialog")115 for(var i=0, iMax=urls.length; i < iMax; i++) {
113 if (importDialog) {116 var url = urls[i]
114 importDialog.importVCards(contactList.listModel, urls)117 if (url && url != "") {
118 importing = true
119 contactList.listModel.importContacts(url)
115 }120 }
116 }121 }
122
123 if (!importing) {
124 PopupUtils.close(mainPage._busyDialog)
125 mainPage._busyDialog = null
126 }
117 }127 }
118128
119 function startPickMode(isSingleSelection, activeTransfer)129 function startPickMode(isSingleSelection, activeTransfer)
@@ -126,8 +136,9 @@
126136
127 function moveListToContact(contact)137 function moveListToContact(contact)
128 {138 {
129 // skipt it if searching139 // skipt it if searching or importing contacts
130 if (state === "searching") {140 if ((state === "searching") ||
141 (state === "vcardImported")) {
131 return142 return
132 }143 }
133144
@@ -428,6 +439,53 @@
428 detailToPick: -1439 detailToPick: -1
429 showAddNewButton: true440 showAddNewButton: true
430 }441 }
442 PropertyChanges {
443 target: bottomEdge
444 enabled: false
445 }
446 },
447 PageHeadState {
448 id: vcardImportedState
449
450 name: "vcardImported"
451 backAction: Action {
452 iconName: "back"
453 text: i18n.tr("Back")
454 onTriggered: {
455 contactList.forceActiveFocus()
456 mainPage.state = "default"
457 importedIdsFilter.ids = []
458 }
459 }
460 PropertyChanges {
461 target: mainPage.head
462 backAction: vcardImportedState.backAction
463 }
464 PropertyChanges {
465 target: bottomEdge
466 enabled: false
467 }
468 PropertyChanges {
469 target: mainPage
470 title: i18n.tr("Imported contacts")
471 }
472 }
473 ]
474
475 //WORKAROUND: we need to call 'changeFilter' manually to make sure that the model will be cleared
476 // before update it with the new model. This is faster than do a match of contacts
477 transitions: [
478 Transition {
479 from: "vcardImported"
480 ScriptAction {
481 script: contactList.listModel.changeFilter(null)
482 }
483 },
484 Transition {
485 to: "vcardImported"
486 ScriptAction {
487 script: contactList.listModel.changeFilter(importedIdsFilter)
488 }
431 }489 }
432 ]490 ]
433491
@@ -440,6 +498,10 @@
440 }498 }
441 }499 }
442500
501 IdFilter {
502 id: importedIdsFilter
503 }
504
443 KeyboardRectangle {505 KeyboardRectangle {
444 id: keyboard506 id: keyboard
445 }507 }
@@ -492,16 +554,6 @@
492 }554 }
493 }555 }
494556
495 Connections {
496 target: mainPage.contactModel
497 onContactsChanged: {
498 if (contactIndex) {
499 contactList.positionViewAtContact(mainPage.contactIndex)
500 mainPage.contactIndex = null
501 }
502 }
503 }
504
505 ContactExporter {557 ContactExporter {
506 id: contactExporter558 id: contactExporter
507559
@@ -543,6 +595,35 @@
543 }595 }
544596
545 Component {597 Component {
598 id: busyDialogComponent
599
600 Popups.Dialog {
601 id: busyDialog
602
603 property alias allowToClose: closeButton.visible
604 property alias showActivity: busyIndicator.visible
605
606 title: i18n.tr("Importing...")
607
608 ActivityIndicator {
609 id: busyIndicator
610 running: visible
611 visible: true
612 }
613 Button {
614 id: closeButton
615 text: i18n.tr("Close")
616 visible: false
617 color: UbuntuColors.red
618 onClicked: {
619 PopupUtils.close(mainPage._busyDialog)
620 mainPage._busyDialog = null
621 }
622 }
623 }
624 }
625
626 Component {
546 id: contactShareComponent627 id: contactShareComponent
547628
548 ContactSharePage {629 ContactSharePage {
@@ -552,7 +633,8 @@
552633
553 Component.onCompleted: {634 Component.onCompleted: {
554 application.elapsed()635 application.elapsed()
555 if ((typeof(TEST_DATA) !== "undefined") && (TEST_DATA !== "")) {636 if ((typeof(TEST_DATA) !== "undefined") && (TEST_DATA != "")) {
637 mainPage._importingTestData = true
556 contactList.listModel.importContacts("file://" + TEST_DATA)638 contactList.listModel.importContacts("file://" + TEST_DATA)
557 }639 }
558640
@@ -661,6 +743,40 @@
661 }743 }
662744
663 Connections {745 Connections {
746 target: mainPage.contactModel
747 onContactsChanged: {
748 if (contactIndex) {
749 contactList.positionViewAtContact(mainPage.contactIndex)
750 mainPage.contactIndex = null
751 }
752 }
753 onImportCompleted: {
754 if (mainPage._importingTestData) {
755 mainPage._importingTestData = false
756 return
757 }
758
759 if (error !== ContactModel.ImportNoError) {
760 console.error("Fail to import vcard:" + error)
761 mainPage._busyDialog.title = i18n.tr("Fail to import contacts!")
762 mainPage._busyDialog.allowToClose = true
763 mainPage._busyDialog.showActivity = false
764 } else {
765 var importedIds = ids
766 importedIds.concat(importedIdsFilter.ids)
767 importedIdsFilter.ids = importedIds
768 console.debug("Imported ids:" + importedIds)
769 mainPage.state = "vcardImported"
770
771 if (mainPage._busyDialog) {
772 PopupUtils.close(mainPage._busyDialog)
773 mainPage._busyDialog = null
774 }
775 }
776 }
777 }
778
779 Connections {
664 target: mainPage.contactViewPage780 target: mainPage.contactViewPage
665 onEditContact: {781 onEditContact: {
666 openEditPage(editPageProperties, mainPage.contactViewPage);782 openEditPage(editPageProperties, mainPage.contactViewPage);
667783
=== modified file 'src/imports/CMakeLists.txt'
--- src/imports/CMakeLists.txt 2015-10-16 13:37:25 +0000
+++ src/imports/CMakeLists.txt 2015-11-25 18:33:17 +0000
@@ -6,7 +6,6 @@
6 ABContactViewPage.qml6 ABContactViewPage.qml
7 ContentHubProxy.qml7 ContentHubProxy.qml
8 MainWindow.qml8 MainWindow.qml
9 VCardImportDialog.qml
10 BottomEdgeShadow.qml9 BottomEdgeShadow.qml
11 BottomEdge.qml10 BottomEdge.qml
12)11)
1312
=== removed file 'src/imports/VCardImportDialog.qml'
--- src/imports/VCardImportDialog.qml 2015-10-26 13:18:11 +0000
+++ src/imports/VCardImportDialog.qml 1970-01-01 00:00:00 +0000
@@ -1,94 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import QtContacts 5.0
19import Ubuntu.Components 1.3
20import Ubuntu.Components.Popups 1.3 as Popups
21
22Item {
23 id: root
24
25 property alias model: modelConnections.target
26 property var vcards: []
27 property var importedVcards: []
28 property var importErrors: []
29 property var dialog: null
30
31 signal finished()
32
33 function importVCards(model, vcards)
34 {
35 if (dialog || vcards.length === 0) {
36 return
37 }
38
39 root.model = model
40 root.vcards = vcards
41 dialog = Popups.PopupUtils.open(importDialogComponent, root)
42
43 for(var i=0, iMax=vcards.length; i < iMax; i++) {
44 var vcardUrl = vcards[i]
45 model.importContacts(vcardUrl)
46 }
47 }
48
49 Connections {
50 id: modelConnections
51
52 onImportCompleted: {
53 var imported = root.importedVcards
54 var importErrors = root.importErrors
55 imported.push(url)
56 if (error !== ContactModel.ImportNoError) {
57 root.importErrors.push(error)
58 console.error("Fail to import vcard:" + error)
59 }
60 root.importedVcards = imported
61 root.importErrors = importErrors
62 }
63 }
64
65 Component {
66 id: importDialogComponent
67
68 Popups.Dialog {
69 id: importDialog
70
71 title: i18n.tr("Import vCards")
72 text: root.importedVcards.length === 0 ? i18n.tr("Importing...") : i18n.tr("%1 vCards imported").arg(root.importedVcards.length)
73
74 Button {
75 anchors {
76 left: parent.left
77 right: parent.right
78 margins: units.gu(1)
79 }
80 text: i18n.tr("Close")
81 enabled: (root.importedVcards.length === root.vcards.length)
82 onClicked: {
83 root.dialog = null
84 Popups.PopupUtils.close(importDialog)
85 }
86 }
87
88 Component.onDestruction: root.destroy()
89 }
90 }
91}
92
93
94
950
=== modified file 'tests/autopilot/address_book_app/tests/__init__.py'
--- tests/autopilot/address_book_app/tests/__init__.py 2015-09-29 18:05:25 +0000
+++ tests/autopilot/address_book_app/tests/__init__.py 2015-11-25 18:33:17 +0000
@@ -19,6 +19,7 @@
19import os19import os
20import time20import time
21import subprocess21import subprocess
22import re
2223
23from autopilot.testcase import AutopilotTestCase24from autopilot.testcase import AutopilotTestCase
24from autopilot.matchers import Eventually25from autopilot.matchers import Eventually
@@ -47,7 +48,10 @@
4748
48 # stop vkb49 # stop vkb
49 if model() != "Desktop":50 if model() != "Desktop":
50 subprocess.check_call(["/sbin/initctl", "stop", "maliit-server"])51 maliit_info = subprocess.Popen(['/sbin/initctl', 'status', 'maliit-server'], stdout=subprocess.PIPE)
52 result = maliit_info.stdout.read()
53 if b'start/running,' in result.split():
54 subprocess.check_call(['/sbin/initctl', 'stop', 'maliit-server'])
5155
52 if 'AUTOPILOT_APP' in os.environ:56 if 'AUTOPILOT_APP' in os.environ:
53 self.app_bin = os.environ['AUTOPILOT_APP']57 self.app_bin = os.environ['AUTOPILOT_APP']
5458
=== modified file 'tests/autopilot/address_book_app/tests/test_import_from_sim.py'
--- tests/autopilot/address_book_app/tests/test_import_from_sim.py 2015-04-30 17:22:48 +0000
+++ tests/autopilot/address_book_app/tests/test_import_from_sim.py 2015-11-25 18:33:17 +0000
@@ -70,6 +70,9 @@
70 self.assertThat(len(contacts), Equals(2))70 self.assertThat(len(contacts), Equals(2))
71 self.app.main_window.confirm_import()71 self.app.main_window.confirm_import()
7272
73 # dismiss imported contact list
74 self.app.main_window.cancel()
75
73 # verify if the contact was imported76 # verify if the contact was imported
74 new_contacts = list_page.get_contacts()77 new_contacts = list_page.get_contacts()
75 self.assertThat(len(new_contacts), Equals(2))78 self.assertThat(len(new_contacts), Equals(2))
7679
=== added file 'tests/autopilot/address_book_app/tests/test_import_vcard.py'
--- tests/autopilot/address_book_app/tests/test_import_vcard.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/address_book_app/tests/test_import_vcard.py 2015-11-25 18:33:17 +0000
@@ -0,0 +1,39 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2015 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8"""Tests for the Addressbook App"""
9
10from __future__ import absolute_import
11from testtools.matchers import Equals
12from autopilot.matchers import Eventually
13import os
14
15from address_book_app.tests import AddressBookAppTestCase
16
17
18class TeseImportVCard(AddressBookAppTestCase):
19 """Tests import vcard"""
20
21 def setUp(self):
22 vcard_path = AddressBookAppTestCase.VCARD_PATH_DEV
23 if os.path.exists(AddressBookAppTestCase.VCARD_PATH_BIN):
24 vcard_path = AddressBookAppTestCase.VCARD_PATH_BIN
25
26 self.ARGS.append("addressbook:///importvcard?url=file://%s" % vcard_path)
27 super(TeseImportVCard, self).setUp()
28
29 def test_import_vcard_results(self):
30 # check if app enter on import state
31 list_page = self.app.main_window.get_contact_list_page()
32 self.assertThat(list_page.state, Eventually(Equals('vcardImported')))
33 self.assertThat(list_page.title, Eventually(Equals('Imported contacts')))
34 self.assertThat(len(list_page.get_contacts()), Equals(3))
35
36 #leave import state and show full contact list
37 self.app.main_window.cancel()
38 self.assertThat(list_page.state, Eventually(Equals('default')))
39 self.assertThat(list_page.title, Eventually(Equals('Contacts')))

Subscribers

People subscribed via source and target branches