Merge lp:~renatofilho/address-book-service/demo-app-with-fetch-hint into lp:~phablet-team/address-book-service/contact-demo-app
- demo-app-with-fetch-hint
- Merge into contact-demo-app
Proposed by
Renato Araujo Oliveira Filho
Status: | Merged |
---|---|
Approved by: | Renato Araujo Oliveira Filho |
Approved revision: | 17 |
Merged at revision: | 9 |
Proposed branch: | lp:~renatofilho/address-book-service/demo-app-with-fetch-hint |
Merge into: | lp:~phablet-team/address-book-service/contact-demo-app |
Prerequisite: | lp:~renatofilho/address-book-service/fetch-hint |
Diff against target: |
347 lines (+200/-35) 4 files modified
ContactEditor.qml (+7/-8) ContactList.js (+35/-0) ContactList.qml (+157/-27) debian/contacts-demo-app.install (+1/-0) |
To merge this branch: | bzr merge lp:~renatofilho/address-book-service/demo-app-with-fetch-hint |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bill Filler (community) | Approve | ||
Review via email: mp+171630@code.launchpad.net |
Commit message
Used fetcHint on contact model to fetch only contact name and phone.
Description of the change
To post a comment you must log in.
- 16. By Renato Araujo Oliveira Filho
-
Merged "lp:~renatofilho/address-book-service/demo-app-with-section"
- 17. By Renato Araujo Oliveira Filho
-
Fixed contact edit action
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'ContactEditor.qml' | |||
2 | --- ContactEditor.qml 2013-06-23 00:19:40 +0000 | |||
3 | +++ ContactEditor.qml 2013-06-27 17:17:26 +0000 | |||
4 | @@ -73,14 +73,13 @@ | |||
5 | 73 | } | 73 | } |
6 | 74 | ListItem.ThinDivider {} | 74 | ListItem.ThinDivider {} |
7 | 75 | } | 75 | } |
9 | 76 | 76 | ||
10 | 77 | function setContactDetails(contact) { | 77 | function setContactDetails(contact) { |
11 | 78 | contact.name.firstName = contactFirstName.text | 78 | contact.name.firstName = contactFirstName.text |
12 | 79 | contact.name.middleName = contactMiddleName.text | 79 | contact.name.middleName = contactMiddleName.text |
13 | 80 | contact.name.lastName = contactLastName.text | 80 | contact.name.lastName = contactLastName.text |
14 | 81 | contact.email.emailAddress = contactEmail.text | 81 | contact.email.emailAddress = contactEmail.text |
15 | 82 | contact.phoneNumber.number = contactPhone.text | 82 | contact.phoneNumber.number = contactPhone.text |
16 | 83 | console.debug("Update contact number:" + contactPhone.text) | ||
17 | 84 | } | 83 | } |
18 | 85 | 84 | ||
19 | 86 | function updateContact() { | 85 | function updateContact() { |
20 | @@ -90,14 +89,14 @@ | |||
21 | 90 | newContact.save() | 89 | newContact.save() |
22 | 91 | contactEditor.model.saveContact(newContact) | 90 | contactEditor.model.saveContact(newContact) |
23 | 92 | 91 | ||
29 | 93 | } else if ((contactFirstName.text != contactEditor.contact.name.firstName) || | 92 | } else if ((contactFirstName.text !== contactEditor.contact.name.firstName) || |
30 | 94 | (contactMiddleName.text != contactEditor.contact.name.middleName) || | 93 | (contactMiddleName.text !== contactEditor.contact.name.middleName) || |
31 | 95 | (contactLastName.text != contactEditor.contact.name.lastName) || | 94 | (contactLastName.text !== contactEditor.contact.name.lastName) || |
32 | 96 | (contactEmail.text != contactEditor.contact.email.emailAddress) || | 95 | (contactEmail.text !== contactEditor.contact.email.emailAddress) || |
33 | 97 | (contactPhone.text != contactEditor.contact.phoneNumber.number)) { | 96 | (contactPhone.text !== contactEditor.contact.phoneNumber.number)) { |
34 | 98 | // update existing contact | 97 | // update existing contact |
35 | 99 | setContactDetails(contactEditor.contact) | 98 | setContactDetails(contactEditor.contact) |
37 | 100 | contactEditor.contact.save() | 99 | contact.save() |
38 | 101 | } | 100 | } |
39 | 102 | } | 101 | } |
40 | 103 | 102 | ||
41 | 104 | 103 | ||
42 | === added file 'ContactList.js' | |||
43 | --- ContactList.js 1970-01-01 00:00:00 +0000 | |||
44 | +++ ContactList.js 2013-06-27 17:17:26 +0000 | |||
45 | @@ -0,0 +1,35 @@ | |||
46 | 1 | /**************************************************************************** | ||
47 | 2 | ** | ||
48 | 3 | ** Copyright (C) 2013 Canonical Ltd | ||
49 | 4 | ** | ||
50 | 5 | ****************************************************************************/ | ||
51 | 6 | |||
52 | 7 | var sectionData = []; | ||
53 | 8 | var _sections = []; | ||
54 | 9 | |||
55 | 10 | function initSectionData(list) { | ||
56 | 11 | if (!list || !list.model) { | ||
57 | 12 | return; | ||
58 | 13 | } | ||
59 | 14 | |||
60 | 15 | sectionData = []; | ||
61 | 16 | _sections = []; | ||
62 | 17 | |||
63 | 18 | var current = "", | ||
64 | 19 | prop = list.section.property, | ||
65 | 20 | item; | ||
66 | 21 | |||
67 | 22 | for (var i = 0, count = list.model.contacts.length; i < count; i++) { | ||
68 | 23 | item = list.sectionValueForContact(list.model.contacts[i]) | ||
69 | 24 | if (item !== current) { | ||
70 | 25 | current = item; | ||
71 | 26 | _sections.push(current); | ||
72 | 27 | sectionData.push({ index: i, header: current }); | ||
73 | 28 | } | ||
74 | 29 | } | ||
75 | 30 | } | ||
76 | 31 | |||
77 | 32 | function getIndexFor(sectionName) { | ||
78 | 33 | var val = sectionData[_sections.indexOf(sectionName)].index; | ||
79 | 34 | return val === 0 || val > 0 ? val : -1; | ||
80 | 35 | } | ||
81 | 0 | 36 | ||
82 | === modified file 'ContactList.qml' | |||
83 | --- ContactList.qml 2013-06-23 00:19:40 +0000 | |||
84 | +++ ContactList.qml 2013-06-27 17:17:26 +0000 | |||
85 | @@ -8,6 +8,8 @@ | |||
86 | 8 | import Ubuntu.Components 0.1 | 8 | import Ubuntu.Components 0.1 |
87 | 9 | import Ubuntu.Components.ListItems 0.1 as ListItem | 9 | import Ubuntu.Components.ListItems 0.1 as ListItem |
88 | 10 | 10 | ||
89 | 11 | import "ContactList.js" as Sections | ||
90 | 12 | |||
91 | 11 | Page { | 13 | Page { |
92 | 12 | id: mainPage | 14 | id: mainPage |
93 | 13 | 15 | ||
94 | @@ -32,6 +34,13 @@ | |||
95 | 32 | direction: Qt.AscendingOrder | 34 | direction: Qt.AscendingOrder |
96 | 33 | } | 35 | } |
97 | 34 | ] | 36 | ] |
98 | 37 | |||
99 | 38 | fetchHint: FetchHint { | ||
100 | 39 | detailTypesHint: [ContactDetail.Avatar, | ||
101 | 40 | ContactDetail.Name, | ||
102 | 41 | ContactDetail.PhoneNumber] | ||
103 | 42 | } | ||
104 | 43 | |||
105 | 35 | Component.onCompleted: { | 44 | Component.onCompleted: { |
106 | 36 | if (manager == "memory") | 45 | if (manager == "memory") |
107 | 37 | contactsModel.importContacts(Qt.resolvedUrl("example.vcf")) | 46 | contactsModel.importContacts(Qt.resolvedUrl("example.vcf")) |
108 | @@ -41,9 +50,7 @@ | |||
109 | 41 | var fullValue = "" | 50 | var fullValue = "" |
110 | 42 | 51 | ||
111 | 43 | if (contact) { | 52 | if (contact) { |
112 | 44 | console.debug("FieldNames:" + fieldNames) | ||
113 | 45 | var fieldNameList = fieldNames.split(",") | 53 | var fieldNameList = fieldNames.split(",") |
114 | 46 | console.debug("FieldNameList:" + fieldNameList) | ||
115 | 47 | for (var fieldNameIndex in fieldNameList) { | 54 | for (var fieldNameIndex in fieldNameList) { |
116 | 48 | var fieldName = fieldNameList[fieldNameIndex] | 55 | var fieldName = fieldNameList[fieldNameIndex] |
117 | 49 | var value = ""; | 56 | var value = ""; |
118 | @@ -73,52 +80,137 @@ | |||
119 | 73 | } | 80 | } |
120 | 74 | } | 81 | } |
121 | 75 | 82 | ||
126 | 76 | 83 | ListView { | |
127 | 77 | 84 | id: alphabetView | |
128 | 78 | ListView { | 85 | |
129 | 79 | id: listView | 86 | property string selectedLetter: contactListView.contentY > 0 ? contactListView.itemAt(0, contactListView.contentY).sectionName : "A" |
130 | 87 | |||
131 | 88 | anchors { | ||
132 | 89 | top: parent.top | ||
133 | 90 | left: parent.left | ||
134 | 91 | right: parent.right | ||
135 | 92 | } | ||
136 | 93 | focus: true | ||
137 | 94 | height: units.gu(4) | ||
138 | 95 | orientation: ListView.Horizontal | ||
139 | 96 | |||
140 | 97 | model: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ] | ||
141 | 98 | delegate: Label { | ||
142 | 99 | text: modelData | ||
143 | 100 | font.bold: alphabetView.selectedLetter == text | ||
144 | 101 | horizontalAlignment: Text.AlignHCenter | ||
145 | 102 | fontSize: "large" | ||
146 | 103 | width: units.gu(3) | ||
147 | 104 | |||
148 | 105 | MouseArea { | ||
149 | 106 | anchors.fill: parent | ||
150 | 107 | onClicked: { | ||
151 | 108 | contactListView.scroolToSection(modelData) | ||
152 | 109 | } | ||
153 | 110 | } | ||
154 | 111 | |||
155 | 112 | } | ||
156 | 113 | } | ||
157 | 114 | |||
158 | 115 | ListView { | ||
159 | 116 | id: contactListView | ||
160 | 80 | 117 | ||
161 | 81 | property string title | 118 | property string title |
162 | 82 | 119 | ||
164 | 83 | anchors.fill: parent | 120 | clip: true |
165 | 121 | snapMode: ListView.NoSnap | ||
166 | 122 | section { | ||
167 | 123 | property: "contact.name.firstName" | ||
168 | 124 | criteria: ViewSection.FirstCharacter | ||
169 | 125 | delegate: ListItem.Header { | ||
170 | 126 | id: listHeader | ||
171 | 127 | //text: section | ||
172 | 128 | visible: false | ||
173 | 129 | height: 0 | ||
174 | 130 | } | ||
175 | 131 | } | ||
176 | 132 | |||
177 | 133 | anchors { | ||
178 | 134 | top: alphabetView.bottom | ||
179 | 135 | left: parent.left | ||
180 | 136 | right: parent.right | ||
181 | 137 | bottom: parent.bottom | ||
182 | 138 | } | ||
183 | 84 | model: contactsModel | 139 | model: contactsModel |
184 | 85 | header: ListItem.Header { | 140 | header: ListItem.Header { |
188 | 86 | id: listHeader | 141 | text: contactListView.title |
186 | 87 | |||
187 | 88 | text: listView.title | ||
189 | 89 | } | 142 | } |
190 | 90 | 143 | ||
191 | 91 | onCountChanged: { | 144 | onCountChanged: { |
192 | 145 | dirtyTimer.restart() | ||
193 | 92 | if (mainPage.startTime) { | 146 | if (mainPage.startTime) { |
194 | 93 | var currentTime = new Date(); | 147 | var currentTime = new Date(); |
195 | 94 | var elapsed = currentTime.getTime() - mainPage.startTime.getTime() | 148 | var elapsed = currentTime.getTime() - mainPage.startTime.getTime() |
197 | 95 | listView.title = "Elapsed time to load " + count + " contacts: " + (elapsed/1000) + " secs" | 149 | contactListView.title = "Elapsed time to load " + count + " contacts: " + (elapsed/1000) + " secs" |
198 | 96 | } | 150 | } |
199 | 97 | } | 151 | } |
200 | 98 | 152 | ||
201 | 99 | delegate: ListItem.Subtitled { | 153 | delegate: ListItem.Subtitled { |
202 | 100 | property variant contactObject: contact | 154 | property variant contactObject: contact |
203 | 101 | property string contactId: contact.contactId | 155 | property string contactId: contact.contactId |
204 | 156 | property string sectionName: ListView.section | ||
205 | 102 | 157 | ||
207 | 103 | icon: Qt.resolvedUrl("avatar.png") | 158 | icon: contact && contact.avatar && (contact.avatar.imageUrl != "") ? Qt.resolvedUrl(contact.avatar.imageUrl) : Qt.resolvedUrl("avatar.png") |
208 | 104 | text: contactsModel.titleField ? contactsModel.getContactDetails(contact, contactsModel.titleField) : "" | 159 | text: contactsModel.titleField ? contactsModel.getContactDetails(contact, contactsModel.titleField) : "" |
209 | 105 | subText: contactsModel.subTitleField ? contactsModel.getContactDetails(contact, contactsModel.subTitleField) : "" | 160 | subText: contactsModel.subTitleField ? contactsModel.getContactDetails(contact, contactsModel.subTitleField) : "" |
216 | 106 | selected: listView.currentIndex === index | 161 | selected: contactListView.currentIndex === index |
217 | 107 | 162 | ||
218 | 108 | onClicked: { | 163 | MouseArea { |
219 | 109 | listView.currentIndex = index | 164 | anchors.fill: parent |
220 | 110 | pageStack.push(Qt.resolvedUrl("ContactEditor.qml"), {model: contactsModel, contact: listView.currentItem.contactObject}) | 165 | onClicked: { |
221 | 111 | } | 166 | contactListView.currentIndex = index |
222 | 167 | } | ||
223 | 168 | onDoubleClicked: { | ||
224 | 169 | editContactPriv.contactId = contactListView.currentItem.contactObject.contactId | ||
225 | 170 | } | ||
226 | 171 | } | ||
227 | 172 | } | ||
228 | 173 | |||
229 | 174 | UbuntuNumberAnimation { id: scroolToSectionAnimation; target: contactListView; property: "contentY"; } | ||
230 | 175 | function scroolToSection(targetSection) { | ||
231 | 176 | scroolToSectionAnimation.from = contactListView.contentY | ||
232 | 177 | contactListView.positionViewAtIndex(Sections.getIndexFor(targetSection), ListView.Beginning) | ||
233 | 178 | scroolToSectionAnimation.to = contactListView.contentY | ||
234 | 179 | scroolToSectionAnimation.running = true | ||
235 | 180 | } | ||
236 | 181 | |||
237 | 182 | // function used to build the section cache by "ContactList.js" | ||
238 | 183 | function sectionValueForContact(contact) { | ||
239 | 184 | if (contact) { | ||
240 | 185 | return contact.name && contact.name.firstName ? contact.name.firstName[0] : "" | ||
241 | 186 | } else { | ||
242 | 187 | return null | ||
243 | 188 | } | ||
244 | 189 | } | ||
245 | 190 | } | ||
246 | 191 | |||
247 | 192 | Timer { | ||
248 | 193 | id: dirtyTimer | ||
249 | 194 | |||
250 | 195 | interval: 2000 | ||
251 | 196 | running: false | ||
252 | 197 | repeat: false | ||
253 | 198 | onTriggered: { | ||
254 | 199 | Sections.initSectionData(contactListView) | ||
255 | 112 | } | 200 | } |
256 | 113 | } | 201 | } |
257 | 114 | 202 | ||
258 | 115 | ActivityIndicator { | 203 | ActivityIndicator { |
260 | 116 | running: listView.count == 0 | 204 | id: busyIndicator |
261 | 205 | |||
262 | 206 | property bool pageIsBusy: false | ||
263 | 207 | |||
264 | 208 | running: contactListView.count == 0 || pageIsBusy | ||
265 | 117 | visible: running | 209 | visible: running |
267 | 118 | anchors.centerIn: listView | 210 | anchors.centerIn: contactListView |
268 | 119 | } | 211 | } |
269 | 120 | 212 | ||
271 | 121 | tools: ToolbarItems { | 213 | tools: ToolbarActions { |
272 | 122 | Action { | 214 | Action { |
273 | 123 | text: i18n.tr("Settings") | 215 | text: i18n.tr("Settings") |
274 | 124 | iconSource: Qt.resolvedUrl("settings.png") | 216 | iconSource: Qt.resolvedUrl("settings.png") |
275 | @@ -128,7 +220,9 @@ | |||
276 | 128 | Action { | 220 | Action { |
277 | 129 | text: i18n.tr("Edit") | 221 | text: i18n.tr("Edit") |
278 | 130 | iconSource: Qt.resolvedUrl("edit.png") | 222 | iconSource: Qt.resolvedUrl("edit.png") |
280 | 131 | onTriggered: pageStack.push(Qt.resolvedUrl("ContactEditor.qml"), {model: contactsModel, contact: listView.currentItem.contactObject}) | 223 | onTriggered: { |
281 | 224 | editContactPriv.contactId = contactListView.currentItem.contactObject.contactId | ||
282 | 225 | } | ||
283 | 132 | } | 226 | } |
284 | 133 | Action { | 227 | Action { |
285 | 134 | text: i18n.tr("New") | 228 | text: i18n.tr("New") |
286 | @@ -139,9 +233,45 @@ | |||
287 | 139 | text: i18n.tr("Delete") | 233 | text: i18n.tr("Delete") |
288 | 140 | iconSource: Qt.resolvedUrl("delete.png") | 234 | iconSource: Qt.resolvedUrl("delete.png") |
289 | 141 | onTriggered: { | 235 | onTriggered: { |
295 | 142 | console.debug("Delete: " + listView.currentItem.contactId) | 236 | contactsModel.removeContact(contactListView.currentItem.contactId); |
296 | 143 | contactsModel.removeContact(listView.currentItem.contactId); | 237 | } |
297 | 144 | } | 238 | } |
298 | 145 | } | 239 | } |
299 | 146 | } | 240 | |
300 | 241 | Item { | ||
301 | 242 | id: editContactPriv | ||
302 | 243 | |||
303 | 244 | property string contactId | ||
304 | 245 | property int currentQueryId: -1 | ||
305 | 246 | |||
306 | 247 | visible: false | ||
307 | 248 | Connections { | ||
308 | 249 | target: contactsModel | ||
309 | 250 | onContactsFetched: { | ||
310 | 251 | if (requestId == editContactPriv.currentQueryId) { | ||
311 | 252 | editContactPriv.currentQueryId = -1 | ||
312 | 253 | busyIndicator.pageIsBusy = false | ||
313 | 254 | pageStack.push(Qt.resolvedUrl("ContactEditor.qml"), | ||
314 | 255 | {model: contactsModel, contact: fetchedContacts[0]}) | ||
315 | 256 | } | ||
316 | 257 | } | ||
317 | 258 | } | ||
318 | 259 | |||
319 | 260 | onContactIdChanged: { | ||
320 | 261 | if (!contactId || (currentQueryId != -1)) { | ||
321 | 262 | return | ||
322 | 263 | } | ||
323 | 264 | |||
324 | 265 | busyIndicator.pageIsBusy = true | ||
325 | 266 | |||
326 | 267 | currentQueryId = contactsModel.fetchContacts([contactId]) | ||
327 | 268 | if (currentQueryId == -1) { | ||
328 | 269 | busyIndicator.pageIsBusy = false | ||
329 | 270 | } | ||
330 | 271 | } | ||
331 | 272 | |||
332 | 273 | |||
333 | 274 | } | ||
334 | 275 | |||
335 | 276 | |||
336 | 147 | } | 277 | } |
337 | 148 | 278 | ||
338 | === modified file 'debian/contacts-demo-app.install' | |||
339 | --- debian/contacts-demo-app.install 2013-06-07 19:19:01 +0000 | |||
340 | +++ debian/contacts-demo-app.install 2013-06-27 17:17:26 +0000 | |||
341 | @@ -1,5 +1,6 @@ | |||
342 | 1 | contacts-demo-app usr/bin/ | 1 | contacts-demo-app usr/bin/ |
343 | 2 | contacts-demo-app.desktop usr/share/applications/ | 2 | contacts-demo-app.desktop usr/share/applications/ |
344 | 3 | *.qml usr/share/contacts-demo-app/ | 3 | *.qml usr/share/contacts-demo-app/ |
345 | 4 | *.js usr/share/contacts-demo-app/ | ||
346 | 4 | *.png usr/share/contacts-demo-app/ | 5 | *.png usr/share/contacts-demo-app/ |
347 | 5 | *.vcf usr/share/contacts-demo-app/ | 6 | *.vcf usr/share/contacts-demo-app/ |
not working right.
- I can't select an item from the list
- double clicking only sometimes works and only ever shows the first contact in the list as that's the one that is selected
- we shouldn't use double click to get into edit mode, single click should do that like in the past
- in fact, single click should just take you into view of contact detail mode. Editing is then done from there not from the main screen.