Merge lp:~renatofilho/address-book-app/choose-default-address-book into lp:address-book-app

Proposed by Renato Araujo Oliveira Filho
Status: Merged
Approved by: Bill Filler
Approved revision: 502
Merged at revision: 520
Proposed branch: lp:~renatofilho/address-book-app/choose-default-address-book
Merge into: lp:address-book-app
Diff against target: 529 lines (+330/-46)
8 files modified
src/app/addressbookapp.cpp (+1/-0)
src/app/addressbookapp.h (+1/-0)
src/imports/ABContactEditorPage.qml (+4/-0)
src/imports/Settings/CMakeLists.txt (+1/-0)
src/imports/Settings/SettingsDefaultSyncTarget.qml (+229/-0)
src/imports/Settings/SettingsPage.qml (+10/-0)
src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailSyncTargetEditor.qml (+81/-40)
tests/qml/tst_ContactEditor.qml (+3/-6)
To merge this branch: bzr merge lp:~renatofilho/address-book-app/choose-default-address-book
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Bill Filler (community) Needs Fixing
Gustavo Pichorim Boiko (community) Approve
Review via email: mp+279135@code.launchpad.net

Commit message

Implemented the ability to choose the default address-book from settings page.

Description of the change

TESTING
========

 * Test change the default address-book:
  * Open address-book app
  * Enter on settings page
  * Select a different "Default address book"
  * Close settings page
  * Do a bottom edge swipe to create a new contact
  * Check if the selected address-book is the one that you choose on settings page.
  * Save the contact
  * Open the recent created contact and check if the address-book is the correct one

To post a comment you must log in.
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 :

Just a couple remarks.

review: Needs Fixing
Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

All comments fixed on rev.497

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

Looks good now!

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

If I switch off contact syncing for any account in the list, it should be removed from the list. If the account was the default account, then Personal should be made the new default account.

review: Needs Fixing
Revision history for this message
Bill Filler (bfiller) wrote :

If I switch contact-sync back on for the account then it should be added back to the list, but not made the default

review: Needs Fixing
498. By Renato Araujo Oliveira Filho

Update source list on application active to keep it in sync.

499. By Renato Araujo Oliveira Filho

Make sure the correct source is selected after reload source list.

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

Trunk merged.

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

Created 'saveActionEnabled' property to avoid problems on tests.
Used that new property instead of search for Action.

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

Update source list if sources change while the settings and edit page are visible.

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/app/addressbookapp.cpp'
--- src/app/addressbookapp.cpp 2015-09-29 19:03:44 +0000
+++ src/app/addressbookapp.cpp 2015-12-11 16:43:55 +0000
@@ -430,6 +430,7 @@
430 qWarning() << "Fail to connect with pim service.";430 qWarning() << "Fail to connect with pim service.";
431 }431 }
432 connect(m_server.data(), SIGNAL(safeModeChanged()), SIGNAL(serverSafeModeChanged()));432 connect(m_server.data(), SIGNAL(safeModeChanged()), SIGNAL(serverSafeModeChanged()));
433 connect(m_server.data(), SIGNAL(sourcesChanged()), SIGNAL(sourcesChanged()));
433 Q_EMIT serverSafeModeChanged();434 Q_EMIT serverSafeModeChanged();
434}435}
435436
436437
=== modified file 'src/app/addressbookapp.h'
--- src/app/addressbookapp.h 2015-09-16 01:08:07 +0000
+++ src/app/addressbookapp.h 2015-12-11 16:43:55 +0000
@@ -51,6 +51,7 @@
51 void isOnlineChanged();51 void isOnlineChanged();
52 void serverSafeModeChanged();52 void serverSafeModeChanged();
53 void updatingChanged();53 void updatingChanged();
54 void sourcesChanged();
5455
55public Q_SLOTS:56public Q_SLOTS:
56 void activateWindow();57 void activateWindow();
5758
=== modified file 'src/imports/ABContactEditorPage.qml'
--- src/imports/ABContactEditorPage.qml 2015-10-26 13:18:11 +0000
+++ src/imports/ABContactEditorPage.qml 2015-12-11 16:43:55 +0000
@@ -27,6 +27,9 @@
2727
28 property alias backIconName: backAction.iconName28 property alias backIconName: backAction.iconName
2929
30 // Property used on unit tests
31 readonly property alias saveActionEnabled: saveAction.enabled
32
30 head.backAction: Action {33 head.backAction: Action {
31 id: backAction34 id: backAction
3235
@@ -42,6 +45,7 @@
4245
43 head.actions: [46 head.actions: [
44 Action {47 Action {
48 id: saveAction
45 objectName: "save"49 objectName: "save"
46 name: "save"50 name: "save"
4751
4852
=== modified file 'src/imports/Settings/CMakeLists.txt'
--- src/imports/Settings/CMakeLists.txt 2015-03-17 17:14:09 +0000
+++ src/imports/Settings/CMakeLists.txt 2015-12-11 16:43:55 +0000
@@ -1,5 +1,6 @@
1set(CONTACT_SETTINGS_QMLS1set(CONTACT_SETTINGS_QMLS
2 MyselfPhoneNumbersModel.qml2 MyselfPhoneNumbersModel.qml
3 SettingsDefaultSyncTarget.qml
3 SettingsPage.qml4 SettingsPage.qml
4)5)
56
67
=== added file 'src/imports/Settings/SettingsDefaultSyncTarget.qml'
--- src/imports/Settings/SettingsDefaultSyncTarget.qml 1970-01-01 00:00:00 +0000
+++ src/imports/Settings/SettingsDefaultSyncTarget.qml 2015-12-11 16:43:55 +0000
@@ -0,0 +1,229 @@
1/*
2* Copyright (C) 2015 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
19
20import Ubuntu.Components 1.3
21import Ubuntu.Components.ListItems 1.3
22
23import Ubuntu.Contacts 0.1
24import Ubuntu.AddressBook.Base 0.1
25
26Empty {
27 id: root
28
29 signal changed()
30
31 function update()
32 {
33 sourceModel.update()
34 }
35
36 function save()
37 {
38 var changed = false
39 var selectedSource = getSelectedSource()
40 if (!selectedSource) {
41 return
42 }
43
44 var details = selectedSource.details(ContactDetail.ExtendedDetail)
45 for(var d in details) {
46 if (details[d].name === "IS-PRIMARY") {
47 if (!details[d].data) {
48 details[d].data = true
49 changed = true
50 break
51 }
52 }
53 }
54 if (changed) {
55 sourceModel.saveContact(selectedSource)
56 }
57 }
58
59 function getSelectedSource() {
60 if (sources.model.count <= 0)
61 return -1
62
63 return sources.model.get(sources.selectedIndex).source
64 }
65
66 height: sources.currentlyExpanded ?
67 sources.containerHeight + units.gu(6) + label.height :
68 sources.itemHeight + units.gu(6) + label.height
69
70 ContactModel {
71 id: sourceModel
72
73 manager: (typeof(QTCONTACTS_MANAGER_OVERRIDE) !== "undefined") && (QTCONTACTS_MANAGER_OVERRIDE != "") ?
74 QTCONTACTS_MANAGER_OVERRIDE : "galera"
75 filter: DetailFilter {
76 detail: ContactDetail.Type
77 field: Type.TypeField
78 value: Type.Group
79 matchFlags: DetailFilter.MatchExactly
80 }
81 autoUpdate: false
82 onContactsChanged: {
83 if (contacts.length > 0) {
84 writableSources.reload()
85 root.changed()
86 }
87 }
88 }
89
90 ListModel {
91 id: writableSources
92
93 function getSourceMetaData(contact) {
94 var metaData = {'read-only' : false,
95 'account-provider': '',
96 'account-id': 0,
97 'is-primary': false}
98
99 var details = contact.details(ContactDetail.ExtendedDetail)
100 for(var d in details) {
101 if (details[d].name === "READ-ONLY") {
102 metaData['read-only'] = details[d].data
103 } else if (details[d].name === "PROVIDER") {
104 metaData['account-provider'] = details[d].data
105 } else if (details[d].name === "APPLICATION-ID") {
106 metaData['account-id'] = details[d].data
107 } else if (details[d].name === "IS-PRIMARY") {
108 metaData['is-primary'] = details[d].data
109 }
110 }
111 return metaData
112 }
113
114 function reload() {
115 sources._notify = false
116
117 clear()
118 // filter out read-only sources
119 var contacts = sourceModel.contacts
120 if (contacts.length === 0) {
121 return
122 }
123
124 var data = []
125 for(var i in contacts) {
126 var sourceMetaData = getSourceMetaData(contacts[i])
127 if (!sourceMetaData['readOnly']) {
128 data.push({'sourceId': contacts[i].guid.guid,
129 'sourceName': contacts[i].displayLabel.label,
130 'accountId': sourceMetaData['account-id'],
131 'accountProvider': sourceMetaData['account-provider'],
132 'readOnly': sourceMetaData['read-only'],
133 'isPrimary': sourceMetaData['is-primary'],
134 'source': contacts[i]
135 })
136 }
137 }
138
139 data.sort(function(a, b) {
140 var valA = a.accountId
141 var valB = b.accountId
142 if (a.accountId == b.accountId) {
143 valA = a.sourceName
144 valB = b.sourceName
145 }
146
147 if (valA == valB) {
148 return 0
149 } else if (valA < valB) {
150 return -1
151 } else {
152 return 1
153 }
154 })
155
156 sources.selectedIndex = 0
157 var primaryIndex = 0
158 for (var i in data) {
159 if (data[i].isPrimary) {
160 primaryIndex = i
161 }
162 append(data[i])
163 }
164
165 // select primary account
166 sources.selectedIndex = primaryIndex
167 sources._notify = true
168 }
169 }
170
171 Label {
172 id: label
173
174 text: i18n.tr("Default Addressbook")
175 anchors {
176 left: parent.left
177 top: parent.top
178 right: parent.right
179 margins: units.gu(2)
180 }
181 height: units.gu(4)
182 }
183
184 OptionSelector {
185 id: sources
186 property bool _notify: true
187
188 model: writableSources
189 anchors {
190 left: parent.left
191 leftMargin: units.gu(2)
192 top: label.bottom
193 right: parent.right
194 rightMargin: units.gu(2)
195 bottom: parent.bottom
196 bottomMargin: units.gu(2)
197 }
198
199 delegate: OptionSelectorDelegate {
200 text: {
201 if ((sourceId != "system-address-book") &&
202 (iconSource == "image://theme/address-book-app-symbolic")) {
203 return i18n.dtr("address-book-app", "Personal - %1").arg(sourceName)
204 } else {
205 return sourceName
206 }
207 }
208 constrainImage: true
209 iconSource: accountProvider == "" ?
210 "image://theme/address-book-app-symbolic" :
211 "image://theme/online-accounts-%1".arg(accountProvider)
212 height: units.gu(4)
213 }
214
215 containerHeight: sources.model && sources.model.count > 4 ? itemHeight * 4 : sources.model ? itemHeight * sources.model.count : 0
216 onSelectedIndexChanged: {
217 if (_notify && selectedIndex >= 0) {
218 root.changed()
219 }
220 }
221 }
222
223 // In case of sources changed we need to update the model
224 Connections {
225 target: application
226 onSourcesChanged: root.update()
227 }
228}
229
0230
=== modified file 'src/imports/Settings/SettingsPage.qml'
--- src/imports/Settings/SettingsPage.qml 2015-12-02 13:36:03 +0000
+++ src/imports/Settings/SettingsPage.qml 2015-12-11 16:43:55 +0000
@@ -74,6 +74,10 @@
74 onClicked: pageStack.addPageToCurrentColumn(root, simCardImportPageComponent)74 onClicked: pageStack.addPageToCurrentColumn(root, simCardImportPageComponent)
75 enabled: (simList.sims.length > 0) && (simList.present.length > 0)75 enabled: (simList.sims.length > 0) && (simList.present.length > 0)
76 }76 }
77 SettingsDefaultSyncTarget {
78 id: defaultSyncTarget
79 onChanged: save()
80 }
77 }81 }
78 }82 }
79 ContactsUI.OnlineAccountsHelper {83 ContactsUI.OnlineAccountsHelper {
@@ -92,4 +96,10 @@
92 onImportCompleted: pageStack.removePages(root)96 onImportCompleted: pageStack.removePages(root)
93 }97 }
94 }98 }
99
100 onActiveChanged: {
101 if (active) {
102 defaultSyncTarget.update()
103 }
104 }
95}105}
96106
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailSyncTargetEditor.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailSyncTargetEditor.qml 2015-10-26 13:18:11 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailSyncTargetEditor.qml 2015-12-11 16:43:55 +0000
@@ -27,6 +27,10 @@
27 id: root27 id: root
2828
29 property alias active: sourceModel.autoUpdate29 property alias active: sourceModel.autoUpdate
30 property bool isNewContact: contact && contact.contactId === "qtcontacts:::"
31 property real myHeight: label.height + units.gu(6) + (sources.currentlyExpanded ? sources.containerHeight :
32 sources.itemHeight)
33
30 signal changed()34 signal changed()
3135
32 function save() {36 function save() {
@@ -49,9 +53,9 @@
49 if (sources.model.count <= 0)53 if (sources.model.count <= 0)
50 return -154 return -1
5155
52 var selectedContact = sources.model.get(sources.selectedIndex).contact56 var selectedSourceId = sources.model.get(sources.selectedIndex).sourceId
53 if (selectedContact) {57 if (selectedSourceId) {
54 return selectedContact.guid.guid58 return selectedSourceId
55 } else {59 } else {
56 return -160 return -1
57 }61 }
@@ -69,23 +73,6 @@
69 return true73 return true
70 }74 }
7175
72 function targetIsReadOnly(target) {
73 if (!target)
74 return true
75
76 var details = target.details(ContactDetail.ExtendedDetail)
77 for(var d in details) {
78 if ((details[d].name === "READ-ONLY") && (details[d].data === true)) {
79 return true
80 }
81 }
82
83 return false
84 }
85
86 property bool isNewContact: contact && contact.contactId === "qtcontacts:::"
87 property real myHeight: sources.currentlyExpanded ? sources.containerHeight + units.gu(6) + label.height : sources.itemHeight + units.gu(6) + label.height
88
89 detail: root.contact ? contact.detail(ContactDetail.SyncTarget) : null76 detail: root.contact ? contact.detail(ContactDetail.SyncTarget) : null
90 implicitHeight: root.isNewContact && sources.model && (sources.model.count > 1) ? myHeight : 077 implicitHeight: root.isNewContact && sources.model && (sources.model.count > 1) ? myHeight : 0
9178
@@ -111,6 +98,27 @@
111 ListModel {98 ListModel {
112 id: writableSources99 id: writableSources
113100
101 function getSourceMetaData(contact) {
102 var metaData = {'read-only' : false,
103 'account-provider': '',
104 'account-id': 0,
105 'is-primary': false}
106
107 var details = contact.details(ContactDetail.ExtendedDetail)
108 for(var d in details) {
109 if (details[d].name === "READ-ONLY") {
110 metaData['read-only'] = details[d].data
111 } else if (details[d].name === "PROVIDER") {
112 metaData['account-provider'] = details[d].data
113 } else if (details[d].name === "APPLICATION-ID") {
114 metaData['account-id'] = details[d].data
115 } else if (details[d].name === "IS-PRIMARY") {
116 metaData['is-primary'] = details[d].data
117 }
118 }
119 return metaData
120 }
121
114 function reload() {122 function reload() {
115 clear()123 clear()
116124
@@ -120,11 +128,47 @@
120 return128 return
121 }129 }
122130
131 var data = []
123 for(var i in contacts) {132 for(var i in contacts) {
124 if (!targetIsReadOnly(contacts[i])) {133 var sourceMetaData = getSourceMetaData(contacts[i])
125 append({'contact': contacts[i]})134 if (!sourceMetaData['readOnly']) {
126 }135 data.push({'sourceId': contacts[i].guid.guid,
127 }136 'sourceName': contacts[i].displayLabel.label,
137 'accountId': sourceMetaData['account-id'],
138 'accountProvider': sourceMetaData['account-provider'],
139 'readOnly': sourceMetaData['read-only'],
140 'isPrimary': sourceMetaData['is-primary']
141 })
142 }
143 }
144
145 data.sort(function(a, b) {
146 var valA = a.accountId
147 var valB = b.accountId
148 if (a.accountId == b.accountId) {
149 valA = a.sourceName
150 valB = b.sourceName
151 }
152
153 if (valA == valB) {
154 return 0
155 } else if (valA < valB) {
156 return -1
157 } else {
158 return 1
159 }
160 })
161
162 var primaryIndex = 0
163 for (var i in data) {
164 if (data[i].isPrimary) {
165 primaryIndex = i
166 }
167 append(data[i])
168 }
169
170 // select primary account
171 sources.selectedIndex = primaryIndex
128 }172 }
129 }173 }
130174
@@ -164,27 +208,18 @@
164208
165 delegate: OptionSelectorDelegate {209 delegate: OptionSelectorDelegate {
166 text: {210 text: {
167 if ((contact.guid.guid != "system-address-book") &&211 if ((sourceId != "system-address-book") &&
168 (iconSource == "image://theme/address-book-app-symbolic")) {212 (iconSource == "image://theme/address-book-app-symbolic")) {
169 return i18n.dtr("address-book-app", "Personal - %1").arg(contact.displayLabel.label)213 //TRANSLATORS: %1 is the display name of the source (address-book)
214 return i18n.dtr("address-book-app", "Personal - %1").arg(sourceName)
170 } else {215 } else {
171 return contact.displayLabel.label216 return sourceName
172 }217 }
173 }218 }
174 constrainImage: true219 constrainImage: true
175 iconSource: {220 iconSource: accountProvider == "" ?
176 var details = contact.details(ContactDetail.ExtendedDetail)221 "image://theme/address-book-app-symbolic" :
177 for(var i in details) {222 "image://theme/online-accounts-%1".arg(accountProvider)
178 if (details[i].name === "PROVIDER") {
179 if (details[i].data === "") {
180 return "image://theme/address-book-app-symbolic"
181 } else {
182 return "image://theme/online-accounts-%1".arg(details[i].data)
183 }
184 }
185 }
186 return "image://theme/address-book-app-symbolic"
187 }
188 height: units.gu(4)223 height: units.gu(4)
189 }224 }
190225
@@ -196,5 +231,11 @@
196 sourceModel.update()231 sourceModel.update()
197 }232 }
198 }233 }
234
235 // In case of sources changed we need to update the model
236 Connections {
237 target: application
238 onSourcesChanged: sourceModel.update()
239 }
199}240}
200241
201242
=== modified file 'tests/qml/tst_ContactEditor.qml'
--- tests/qml/tst_ContactEditor.qml 2015-12-08 07:47:18 +0000
+++ tests/qml/tst_ContactEditor.qml 2015-12-11 16:43:55 +0000
@@ -69,8 +69,7 @@
6969
70 function init() {70 function init() {
71 waitForRendering(contactEditor);71 waitForRendering(contactEditor);
72 var saveButton = findChild(root, 'save_button');72 tryCompare(contactEditor, 'saveActionEnabled', false);
73 compare(saveButton.enabled, false);
74 }73 }
7574
76 function cleanup() {75 function cleanup() {
@@ -113,8 +112,7 @@
113 function test_fillRequiredFieldsMustEnableSaveButton(data) {112 function test_fillRequiredFieldsMustEnableSaveButton(data) {
114 var textField = findChild(root, data.objectName);113 var textField = findChild(root, data.objectName);
115 textField.text = 'test'114 textField.text = 'test'
116 var saveButton = findChild(root, 'save_button');115 tryCompare(contactEditor, 'saveActionEnabled', true);
117 tryCompare(saveButton, 'enabled', true);
118 }116 }
119117
120 function test_fillOptionalFieldsMustNotEnableSaveButton_data() {118 function test_fillOptionalFieldsMustNotEnableSaveButton_data() {
@@ -125,8 +123,7 @@
125 function test_fillOptionalFieldsMustNotEnableSaveButton(data) {123 function test_fillOptionalFieldsMustNotEnableSaveButton(data) {
126 var textField = findChild(root, data.objectName);124 var textField = findChild(root, data.objectName);
127 textField.text = 'test'125 textField.text = 'test'
128 var saveButton = findChild(root, 'save_button');126 tryCompare(contactEditor, 'saveActionEnabled', false);
129 tryCompare(saveButton, 'enabled', false);
130 }127 }
131128
132 function test_enterKeyMoveFocusedItem() {129 function test_enterKeyMoveFocusedItem() {

Subscribers

People subscribed via source and target branches