Merge lp:~renatofilho/address-book-app/release-2014-06-27 into lp:address-book-app

Proposed by Renato Araujo Oliveira Filho
Status: Merged
Approved by: Gustavo Pichorim Boiko
Approved revision: 196
Merged at revision: 215
Proposed branch: lp:~renatofilho/address-book-app/release-2014-06-27
Merge into: lp:address-book-app
Diff against target: 1436 lines (+681/-178)
18 files modified
click/CMakeLists.txt (+4/-0)
debian/address-book-app.install (+1/-0)
debian/control (+5/-3)
po/address-book-app.pot (+99/-36)
src/app/addressbookapp.cpp (+7/-1)
src/imports/ContactEdit/ContactDetailAvatarEditor.qml (+1/-1)
src/imports/ContactList/CMakeLists.txt (+1/-0)
src/imports/ContactList/ContactListPage.qml (+33/-12)
src/imports/ContactList/VCardImportDialog.qml (+94/-0)
src/imports/MainWindow.qml (+14/-0)
src/imports/Ubuntu/Contacts/CMakeLists.txt (+1/-0)
src/imports/Ubuntu/Contacts/ContactAvatar.qml (+1/-1)
src/imports/Ubuntu/Contacts/ContactDelegate.qml (+84/-10)
src/imports/Ubuntu/Contacts/ContactListView.qml (+149/-32)
src/imports/Ubuntu/Contacts/ContactSimpleListView.qml (+1/-80)
src/imports/Ubuntu/Contacts/Contacts.js (+2/-2)
src/imports/Ubuntu/Contacts/MostCalledModel.qml (+183/-0)
src/imports/Ubuntu/Contacts/qmldir (+1/-0)
To merge this branch: bzr merge lp:~renatofilho/address-book-app/release-2014-06-27
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Gustavo Pichorim Boiko (community) Approve
Review via email: mp+224809@code.launchpad.net

Commit message

* Updated pot file.
* Implemented frequently called list.
* Implemented vcard import.
* Search contacts by phone number and name.

To post a comment you must log in.
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/history-service/qml-fetch-more/+merge/224169

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 the packaging (debian), did you subscribe a core-dev to this MP? NO PACKAGE CHANGED

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.
Yes

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

Code looks good and works as expected!

review: Approve
197. By Renato Araujo Oliveira Filho

Fixed MostCalled list visibility.

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
1=== modified file 'click/CMakeLists.txt'
2--- click/CMakeLists.txt 2014-03-12 01:34:34 +0000
3+++ click/CMakeLists.txt 2014-06-27 21:27:44 +0000
4@@ -9,4 +9,8 @@
5 DESTINATION ${CMAKE_INSTALL_PREFIX})
6 install(FILES address-book-content.json
7 DESTINATION ${CMAKE_INSTALL_PREFIX})
8+else(CLICK_MODE)
9+ install(FILES address-book-content.json
10+ DESTINATION ${CMAKE_INSTALL_DATADIR}/content-hub/peers
11+ RENAME address-book-app)
12 endif(CLICK_MODE)
13
14=== modified file 'debian/address-book-app.install'
15--- debian/address-book-app.install 2014-02-10 21:09:43 +0000
16+++ debian/address-book-app.install 2014-06-27 21:27:44 +0000
17@@ -3,4 +3,5 @@
18 usr/share/address-book-app/imports
19 usr/share/applications/address-book-app.desktop
20 usr/share/url-dispatcher/urls/
21+usr/share/content-hub/peers/address-book-app
22 usr/share/locale/*/LC_MESSAGES/address-book-app.mo
23
24=== modified file 'debian/control'
25--- debian/control 2014-06-11 21:25:08 +0000
26+++ debian/control 2014-06-27 21:27:44 +0000
27@@ -25,12 +25,14 @@
28 libqt5versit5,
29 qmlscene,
30 qtcontact5-galera,
31+ qtdeclarative5-qtcontacts-plugin,
32+ qtdeclarative5-qtquick2-plugin,
33 qtdeclarative5-ubuntu-contacts0.1 (= ${binary:Version}),
34- qtdeclarative5-ubuntu-telephony-phonenumber0.1,
35 qtdeclarative5-ubuntu-content0.1,
36+ qtdeclarative5-ubuntu-history0.1,
37 qtdeclarative5-ubuntu-keyboard-extensions0.1,
38- qtdeclarative5-qtcontacts-plugin,
39- qtdeclarative5-qtquick2-plugin,
40+ qtdeclarative5-ubuntu-telephony-phonenumber0.1,
41+ qtdeclarative5-ubuntu-telephony0.1,
42 ${misc:Depends},
43 ${shlibs:Depends},
44 Description: Address Book application
45
46=== modified file 'po/address-book-app.pot'
47--- po/address-book-app.pot 2014-05-13 18:53:02 +0000
48+++ po/address-book-app.pot 2014-06-27 21:27:44 +0000
49@@ -8,7 +8,7 @@
50 msgstr ""
51 "Project-Id-Version: address-book-app\n"
52 "Report-Msgid-Bugs-To: \n"
53-"POT-Creation-Date: 2014-05-13 15:51-0300\n"
54+"POT-Creation-Date: 2014-06-27 09:54-0300\n"
55 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
56 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
57 "Language-Team: LANGUAGE <LL@li.org>\n"
58@@ -17,16 +17,22 @@
59 "Content-Type: text/plain; charset=CHARSET\n"
60 "Content-Transfer-Encoding: 8bit\n"
61
62-#: src/imports/ContactList/ContactListPage.qml:193
63-msgid "Add"
64-msgstr ""
65-
66+#: src/imports/ContactList/VCardImportDialog.qml:72
67+#, qt-format
68+msgid "%1 vCards imported"
69+msgstr ""
70+
71+#: src/imports/ContactEdit/ContactEditor.qml:322
72+msgid "Add Field"
73+msgstr ""
74+
75+#: src/imports/ContactEdit/AddFieldDialog.qml:59
76 #: src/imports/ContactEdit/ContactDetailAddressesEditor.qml:23
77 #: src/imports/ContactView/ContactDetailAddressesView.qml:24
78 msgid "Address"
79 msgstr ""
80
81-#: src/imports/ContactEdit/ContactDetailSyncTargetEditor.qml:73
82+#: src/imports/ContactEdit/ContactDetailSyncTargetEditor.qml:77
83 #: src/imports/ContactView/ContactDetailSyncTargetView.qml:48
84 msgid "Addressbook"
85 msgstr ""
86@@ -35,22 +41,39 @@
87 msgid "Aim"
88 msgstr ""
89
90-#: src/imports/Ubuntu/Contacts/ContactListView.qml:66
91+#: src/imports/Ubuntu/Contacts/ContactListView.qml:316
92 msgid "All"
93 msgstr ""
94
95-#: src/imports/ContactEdit/ContactEditor.qml:300
96-#: src/imports/ContactEdit/EditToolbar.qml:42
97+#: src/imports/Common/RemoveContactsDialog.qml:51
98+msgid "Are you sure that you want to remove all selected contacts?"
99+msgstr ""
100+
101+#: src/imports/Common/RemoveContactsDialog.qml:49
102+msgid "Are you sure that you want to remove this contact?"
103+msgstr ""
104+
105+#: src/imports/ContactEdit/AddFieldDialog.qml:133
106+#: src/imports/ContactEdit/ContactEditor.qml:372
107+#: src/imports/ContactList/ContactListPage.qml:324
108 #: src/imports/Ubuntu/Contacts/DialogButtons.qml:37
109 msgid "Cancel"
110 msgstr ""
111
112-#: src/imports/ContactEdit/ContactFetchError.qml:26
113+#: src/imports/ContactList/ContactListPage.qml:252
114+msgid "Cancel selection"
115+msgstr ""
116+
117+#: src/imports/ContactList/VCardImportDialog.qml:80
118+msgid "Close"
119+msgstr ""
120+
121+#: src/imports/ContactView/ContactFetchError.qml:26
122 msgid "Contact not found"
123 msgstr ""
124
125 #: data/address-book-app.desktop.in:6 data/address-book-app.desktop.in:7
126-#: src/imports/ContactList/ContactListPage.qml:57
127+#: src/imports/ContactList/ContactListPage.qml:75
128 msgid "Contacts"
129 msgstr ""
130
131@@ -62,21 +85,22 @@
132 msgid "Country"
133 msgstr ""
134
135-#: src/imports/ContactList/ContactListPage.qml:83
136-#: src/imports/ContactView/ContactView.qml:181
137-#: src/imports/Ubuntu/Contacts/ContactSimpleListView.qml:288
138+#: src/imports/ContactEdit/ContactEditor.qml:337
139+#: src/imports/ContactList/ContactListPage.qml:148
140+#: src/imports/ContactList/ContactListPage.qml:277
141 msgid "Delete"
142 msgstr ""
143
144-#: src/imports/ContactEdit/EditToolbar.qml:57
145 #: src/imports/Ubuntu/Contacts/DialogButtons.qml:53
146 msgid "Done"
147 msgstr ""
148
149-#: src/imports/ContactView/ContactView.qml:193
150+#: src/imports/ContactEdit/ContactEditor.qml:141
151+#: src/imports/ContactView/ContactView.qml:219
152 msgid "Edit"
153 msgstr ""
154
155+#: src/imports/ContactEdit/AddFieldDialog.qml:57
156 #: src/imports/ContactEdit/ContactDetailEmailsEditor.qml:23
157 #: src/imports/ContactView/ContactDetailEmailsView.qml:23
158 #: src/imports/ContactView/ContactDetailEmailsView.qml:26
159@@ -95,23 +119,27 @@
160 msgid "Enter an email address"
161 msgstr ""
162
163-#: src/imports/ContactEdit/ContactFetchError.qml:25
164-#: src/imports/MainWindow.qml:94
165+#: src/imports/ContactView/ContactFetchError.qml:25
166+#: src/imports/MainWindow.qml:98
167 msgid "Error"
168 msgstr ""
169
170-#: src/imports/ContactView/ContactDetailPhoneNumbersView.qml:33
171+#: src/imports/ContactView/ContactView.qml:195
172 msgid "Favorite"
173 msgstr ""
174
175-#: src/imports/Ubuntu/Contacts/ContactListView.qml:93
176+#: src/imports/Ubuntu/Contacts/ContactListView.qml:348
177 msgid "Favourites"
178 msgstr ""
179
180-#: src/imports/ContactEdit/ContactDetailNameEditor.qml:81
181+#: src/imports/ContactEdit/ContactDetailNameEditor.qml:83
182 msgid "First name"
183 msgstr ""
184
185+#: src/imports/Ubuntu/Contacts/ContactListView.qml:427
186+msgid "Frequently called"
187+msgstr ""
188+
189 #: src/imports/Common/ContactDetailGroupWithTypeBase.qml:116
190 #: src/imports/Ubuntu/Contacts/ContactDetailPhoneNumberTypeModel.qml:94
191 msgid "Home"
192@@ -125,19 +153,27 @@
193 msgid "IM"
194 msgstr ""
195
196+#: src/imports/ContactList/VCardImportDialog.qml:71
197+msgid "Import vCards"
198+msgstr ""
199+
200+#: src/imports/ContactList/VCardImportDialog.qml:72
201+msgid "Importing..."
202+msgstr ""
203+
204 #: src/imports/Ubuntu/Contacts/ContactDetailOnlineAccountTypeModel.qml:64
205 msgid "Jabber"
206 msgstr ""
207
208-#: src/imports/ContactEdit/ContactDetailNameEditor.qml:81
209+#: src/imports/ContactEdit/ContactDetailNameEditor.qml:83
210 msgid "Last name"
211 msgstr ""
212
213-#: src/imports/ContactEdit/ContactDetailAvatarEditor.qml:85
214+#: src/imports/ContactEdit/AvatarImport.qml:71
215 msgid "Loading"
216 msgstr ""
217
218-#: src/imports/ContactList/ContactListPage.qml:163
219+#: src/imports/ContactList/ContactListPage.qml:242
220 msgid "Loading..."
221 msgstr ""
222
223@@ -153,14 +189,23 @@
224 msgid "Mobile"
225 msgstr ""
226
227-#: src/imports/ContactEdit/TextInputDetail.qml:46
228+#: src/imports/Common/RemoveContactsDialog.qml:44
229+msgid "Multiple contacts"
230+msgstr ""
231+
232+#: src/imports/ContactEdit/TextInputDetail.qml:77
233 msgid "Next"
234 msgstr ""
235
236+#: src/imports/Common/RemoveContactsDialog.qml:74
237 #: src/imports/ContactList/OnlineAccountsMessage.qml:48
238 msgid "No"
239 msgstr ""
240
241+#: src/imports/Common/RemoveContactsDialog.qml:40
242+msgid "No contact selected."
243+msgstr ""
244+
245 #: src/imports/ContactEdit/ContactDetailOrganizationsEditor.qml:30
246 msgid "Organization"
247 msgstr ""
248@@ -170,6 +215,7 @@
249 msgid "Other"
250 msgstr ""
251
252+#: src/imports/ContactEdit/AddFieldDialog.qml:55
253 #: src/imports/ContactEdit/ContactDetailPhoneNumbersEditor.qml:24
254 #: src/imports/ContactView/ContactDetailPhoneNumbersView.qml:30
255 msgid "Phone"
256@@ -179,6 +225,10 @@
257 msgid "Post code"
258 msgstr ""
259
260+#: src/imports/ContactEdit/AddFieldDialog.qml:63
261+msgid "Professional Details"
262+msgstr ""
263+
264 #: src/imports/ContactEdit/ContactDetailOrganizationsEditor.qml:23
265 #: src/imports/ContactView/ContactDetailOrganizationsView.qml:27
266 msgid "Professional details"
267@@ -192,19 +242,35 @@
268 msgid "Role"
269 msgstr ""
270
271-#: src/imports/ContactEdit/ContactEditor.qml:295
272+#: src/imports/ContactEdit/ContactEditor.qml:385
273 msgid "Save"
274 msgstr ""
275
276-#: src/imports/ContactList/ContactListPage.qml:83
277-#: src/imports/ContactList/ContactListPage.qml:185
278+#: src/imports/ContactList/ContactListPage.qml:302
279+msgid "Search"
280+msgstr ""
281+
282+#: src/imports/ContactList/ContactListPage.qml:277
283 msgid "Select"
284 msgstr ""
285
286+#: src/imports/ContactList/ContactListPage.qml:261
287+msgid "Select All"
288+msgstr ""
289+
290+#: src/imports/ContactList/ContactListPage.qml:75
291+msgid "Select Contacts"
292+msgstr ""
293+
294+#: src/imports/ContactEdit/AddFieldDialog.qml:116
295+msgid "Select a field"
296+msgstr ""
297+
298 #: src/imports/Ubuntu/Contacts/ContactDetailOnlineAccountTypeModel.qml:67
299 msgid "Skype"
300 msgstr ""
301
302+#: src/imports/ContactEdit/AddFieldDialog.qml:61
303 #: src/imports/ContactView/ContactDetailOnlineAccountsView.qml:27
304 msgid "Social"
305 msgstr ""
306@@ -213,15 +279,15 @@
307 msgid "Street"
308 msgstr ""
309
310-#: src/imports/ContactList/ContactListPage.qml:176
311+#: src/imports/ContactList/ContactListPage.qml:293
312 msgid "Sync"
313 msgstr ""
314
315-#: src/imports/ContactList/ContactListPage.qml:176
316+#: src/imports/ContactList/ContactListPage.qml:293
317 msgid "Syncing"
318 msgstr ""
319
320-#: src/imports/ContactList/ContactListPage.qml:163
321+#: src/imports/ContactList/ContactListPage.qml:242
322 msgid "Syncing..."
323 msgstr ""
324
325@@ -235,14 +301,10 @@
326
327 #. TRANSLATORS: This value is used as default value for phone number format, when no coutry code is provided
328 #. the supported values can be found in: https://www.iso.org/obp/ui/#search
329-#: src/imports/ContactEdit/TextInputDetail.qml:41
330+#: src/imports/ContactEdit/TextInputDetail.qml:73
331 msgid "US"
332 msgstr ""
333
334-#: src/imports/Ubuntu/Contacts/ContactDetailPickerPhoneNumberDelegate.qml:111
335-msgid "View contact's profile"
336-msgstr ""
337-
338 #: src/imports/Common/ContactDetailGroupWithTypeBase.qml:117
339 #: src/imports/Ubuntu/Contacts/ContactDetailPhoneNumberTypeModel.qml:96
340 msgid "Work"
341@@ -262,6 +324,7 @@
342 msgid "Yahoo"
343 msgstr ""
344
345+#: src/imports/Common/RemoveContactsDialog.qml:62
346 #: src/imports/ContactList/OnlineAccountsMessage.qml:36
347 msgid "Yes"
348 msgstr ""
349
350=== modified file 'src/app/addressbookapp.cpp'
351--- src/app/addressbookapp.cpp 2014-06-11 21:25:08 +0000
352+++ src/app/addressbookapp.cpp 2014-06-27 21:27:44 +0000
353@@ -43,6 +43,7 @@
354 << "[addressbook:///contact?id=<contact-id>"
355 << "[addressbook:///create?phone=<phone-number>"
356 << "[addressbook:///pick?single=<true/false>"
357+ << "[addressbook:///importvcard?url=<vcard-file>"
358 << "[--fullscreen]"
359 << "[--help]"
360 << "[-testability]";
361@@ -297,6 +298,11 @@
362 args << "single";
363 methodsMetaData.insert("pick", args);
364 args.clear();
365+
366+ //vcard
367+ args << "url";
368+ methodsMetaData.insert("importvcard", args);
369+ args.clear();
370 }
371
372 QUrlQuery query(url);
373@@ -356,7 +362,7 @@
374 method.invoke(mainView);
375 break;
376 case 1:
377- method.invoke(mainView, Q_ARG(QVariant, QVariant(args[0].toUtf8())));
378+ method.invoke(mainView, Q_ARG(QVariant, QVariant(args[0])));
379 break;
380 case 2:
381 method.invoke(mainView, Q_ARG(QVariant, QVariant(args[0].toUtf8())),
382
383=== modified file 'src/imports/ContactEdit/ContactDetailAvatarEditor.qml'
384--- src/imports/ContactEdit/ContactDetailAvatarEditor.qml 2014-06-13 19:54:01 +0000
385+++ src/imports/ContactEdit/ContactDetailAvatarEditor.qml 2014-06-27 21:27:44 +0000
386@@ -52,7 +52,7 @@
387
388 if (avatarDetail) {
389 var avatarValue = avatarDetail.value(Avatar.ImageUrl)
390- if (avatarValue != "") {
391+ if (avatarValue && (avatarValue != "")) {
392 avatarUrl = avatarValue
393 }
394 }
395
396=== modified file 'src/imports/ContactList/CMakeLists.txt'
397--- src/imports/ContactList/CMakeLists.txt 2014-05-07 13:14:28 +0000
398+++ src/imports/ContactList/CMakeLists.txt 2014-06-27 21:27:44 +0000
399@@ -3,6 +3,7 @@
400 ContactExporter.qml
401 OnlineAccountsMessage.qml
402 PageWithBottomEdge.qml
403+ VCardImportDialog.qml
404 )
405
406 install(FILES ${CONTACT_LIST_QMLS}
407
408=== modified file 'src/imports/ContactList/ContactListPage.qml'
409--- src/imports/ContactList/ContactListPage.qml 2014-06-17 14:25:22 +0000
410+++ src/imports/ContactList/ContactListPage.qml 2014-06-27 21:27:44 +0000
411@@ -58,6 +58,20 @@
412 return newContact
413 }
414
415+ function createContactWithPhoneNumber(phoneNumber)
416+ {
417+ var newContact = mainPage.createEmptyContact(phoneNumber)
418+ //WORKAROUND: SKD changes the page header as soon as the page get created
419+ // setting active false will avoid that
420+ mainPage.showBottomEdgePage(Qt.resolvedUrl("../ContactEdit/ContactEditor.qml"),
421+ {model: contactList.listModel,
422+ contact: newContact,
423+ active: false,
424+ enabled: false,
425+ initialFocusSection: "name"})
426+
427+ }
428+
429 title: contactList.isInSelectionMode ? i18n.tr("Select Contacts") : i18n.tr("Contacts")
430
431 //bottom edge page
432@@ -121,7 +135,7 @@
433 bottom: keyboard.top
434 right: parent.right
435 }
436- contactNameFilter: searchField.text
437+ filterTerm: searchField.text
438 detailToPick: ContactDetail.PhoneNumber
439 multiSelectionEnabled: true
440 multipleSelection: !pickMode ||
441@@ -160,6 +174,8 @@
442 }
443 }
444
445+ onAddContactClicked: mainPage.createContactWithPhoneNumber(label)
446+
447 onInfoRequested: {
448 mainPage.state = ""
449 pageStack.push(Qt.resolvedUrl("../ContactView/ContactView.qml"),
450@@ -343,6 +359,10 @@
451 __customHeaderContents: searchField
452 tools: toolbarItemsSearch
453 }
454+ PropertyChanges {
455+ target: contactList
456+ showFavourites: false
457+ }
458 },
459 State {
460 name: "selection"
461@@ -388,21 +408,11 @@
462
463 Connections {
464 target: pageStack
465+ onCreateContactRequested: mainPage.createContactWithPhoneNumber(phoneNumber)
466 onContactRequested: {
467 pageStack.push(Qt.resolvedUrl("../ContactView/ContactView.qml"),
468 {model: contactList.listModel, contactId: contactId})
469 }
470- onCreateContactRequested: {
471- var newContact = mainPage.createEmptyContact(phoneNumber)
472- //WORKAROUND: SKD changes the page header as soon as the page get created
473- // setting active false will avoid that
474- mainPage.showBottomEdgePage(Qt.resolvedUrl("../ContactEdit/ContactEditor.qml"),
475- {model: contactList.listModel,
476- contact: newContact,
477- active: false,
478- enabled: false,
479- initialFocusSection: "name"})
480- }
481 onEditContatRequested: {
482 pageStack.push(Qt.resolvedUrl("../ContactView/ContactView.qml"),
483 {model: contactList.listModel,
484@@ -412,6 +422,17 @@
485 onContactCreated: {
486 mainPage.contactIndex = contact
487 }
488+
489+ onImportContactRequested: {
490+ if (urls.length > 0) {
491+ var importDialog = Qt.createQmlObject("VCardImportDialog{}",
492+ mainPage,
493+ "VCardImportDialog")
494+ if (importDialog) {
495+ importDialog.importVCards(contactList.listModel, urls)
496+ }
497+ }
498+ }
499 }
500
501 KeyboardRectangle {
502
503=== added file 'src/imports/ContactList/VCardImportDialog.qml'
504--- src/imports/ContactList/VCardImportDialog.qml 1970-01-01 00:00:00 +0000
505+++ src/imports/ContactList/VCardImportDialog.qml 2014-06-27 21:27:44 +0000
506@@ -0,0 +1,94 @@
507+/*
508+ * Copyright (C) 2014 Canonical, Ltd.
509+ *
510+ * This program is free software; you can redistribute it and/or modify
511+ * it under the terms of the GNU General Public License as published by
512+ * the Free Software Foundation; version 3.
513+ *
514+ * This program is distributed in the hope that it will be useful,
515+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
516+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
517+ * GNU General Public License for more details.
518+ *
519+ * You should have received a copy of the GNU General Public License
520+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
521+ */
522+
523+import QtQuick 2.2
524+import QtContacts 5.0
525+import Ubuntu.Components 0.1
526+import Ubuntu.Components.Popups 0.1 as Popups
527+
528+Item {
529+ id: root
530+
531+ property alias model: modelConnections.target
532+ property var vcards: []
533+ property var importedVcards: []
534+ property var importErrors: []
535+ property var dialog: null
536+
537+ signal finished()
538+
539+ function importVCards(model, vcards)
540+ {
541+ if (dialog || vcards.length === 0) {
542+ return
543+ }
544+
545+ root.model = model
546+ root.vcards = vcards
547+ dialog = Popups.PopupUtils.open(importDialogComponent, root)
548+
549+ for(var i=0, iMax=vcards.length; i < iMax; i++) {
550+ var vcardUrl = vcards[i]
551+ model.importContacts(vcardUrl)
552+ }
553+ }
554+
555+ Connections {
556+ id: modelConnections
557+
558+ onImportCompleted: {
559+ var imported = root.importedVcards
560+ var importErrors = root.importErrors
561+ imported.push(url)
562+ if (error !== ContactModel.ImportNoError) {
563+ root.importErrors.push(error)
564+ console.error("Fail to import vcard:" + error)
565+ }
566+ root.importedVcards = imported
567+ root.importErrors = importErrors
568+ }
569+ }
570+
571+ Component {
572+ id: importDialogComponent
573+
574+ Popups.Dialog {
575+ id: importDialog
576+
577+ title: i18n.tr("Import vCards")
578+ text: root.importedVcards.length === 0 ? i18n.tr("Importing...") : i18n.tr("%1 vCards imported").arg(root.importedVcards.length)
579+
580+ Button {
581+ anchors {
582+ left: parent.left
583+ right: parent.right
584+ margins: units.gu(1)
585+ }
586+ text: i18n.tr("Close")
587+ enabled: (root.importedVcards.length === root.vcards.length)
588+ onClicked: {
589+ root.dialog = null
590+ Popups.PopupUtils.close(importDialog)
591+ }
592+ }
593+
594+ Component.onDestruction: root.destroy()
595+ }
596+ }
597+}
598+
599+
600+
601
602=== modified file 'src/imports/MainWindow.qml'
603--- src/imports/MainWindow.qml 2014-06-11 21:25:08 +0000
604+++ src/imports/MainWindow.qml 2014-06-27 21:27:44 +0000
605@@ -50,6 +50,10 @@
606 mainStack.push(Qt.createComponent("ContactList/ContactListPage.qml"), { pickMode: true, pickMultipleContacts: !isSingle})
607 }
608
609+ function importvcard(_url) {
610+ mainStack.importContactRequested([_url])
611+ }
612+
613 PageStack {
614 id: mainStack
615
616@@ -60,6 +64,7 @@
617 signal editContatRequested(string contactId, string phoneNumber)
618 signal contactCreated(QtObject contact)
619 signal contactModelError(string errorMessage)
620+ signal importContactRequested(var urls)
621
622 anchors {
623 fill: parent
624@@ -118,5 +123,14 @@
625 {pickMode: true,
626 contentHubTransfer: transfer})
627 }
628+ onImportRequested: {
629+ if (transfer.state === ContentHub.ContentTransfer.Charged) {
630+ var urls = []
631+ for(var i=0; i < transfer.items.length; i++) {
632+ urls.push(transfer.items[i].url)
633+ }
634+ mainStack.importContactRequested(urls)
635+ }
636+ }
637 }
638 }
639
640=== modified file 'src/imports/Ubuntu/Contacts/CMakeLists.txt'
641--- src/imports/Ubuntu/Contacts/CMakeLists.txt 2014-06-09 14:12:58 +0000
642+++ src/imports/Ubuntu/Contacts/CMakeLists.txt 2014-06-27 21:27:44 +0000
643@@ -12,6 +12,7 @@
644 DialogButtons.qml
645 FastScroll.qml
646 FastScroll.js
647+ MostCalledModel.qml
648 MultipleSelectionListView.qml
649 MultipleSelectionVisualModel.qml
650 qmldir
651
652=== modified file 'src/imports/Ubuntu/Contacts/ContactAvatar.qml'
653--- src/imports/Ubuntu/Contacts/ContactAvatar.qml 2014-06-16 17:25:21 +0000
654+++ src/imports/Ubuntu/Contacts/ContactAvatar.qml 2014-06-27 21:27:44 +0000
655@@ -26,7 +26,7 @@
656 property string displayName: ContactsJS.formatToDisplay(contactElement, ContactDetail.Name, [Name.FirstName, Name.LastName])
657 readonly property string defaultAvatar: "image://theme/contact"
658 readonly property string avatarUrl: ContactsJS.getAvatar(contactElement, "")
659- readonly property bool useDefaultAvatar: (displayName === "" || contact.tag.tag === "") && (avatarUrl === "")
660+ readonly property bool useDefaultAvatar: (contactElement == null) || (displayName === "" || contactElement.tag.tag === "") && (avatarUrl === "")
661
662 function reload()
663 {
664
665=== modified file 'src/imports/Ubuntu/Contacts/ContactDelegate.qml'
666--- src/imports/Ubuntu/Contacts/ContactDelegate.qml 2014-06-18 21:27:05 +0000
667+++ src/imports/Ubuntu/Contacts/ContactDelegate.qml 2014-06-27 21:27:44 +0000
668@@ -25,7 +25,9 @@
669
670 property bool showAvatar: true
671 property bool selected: false
672+ property bool isCurrentItem: false
673 property string defaultAvatarUrl: ""
674+ property string defaultTitle: ""
675 property int titleDetail: ContactDetail.Name
676 property variant titleFields: [ Name.FirstName, Name.LastName ]
677 property bool detailsShown: false
678@@ -35,16 +37,13 @@
679 signal pressAndHold(int index, QtObject contact)
680 signal detailClicked(QtObject contact, QtObject detail, string action)
681 signal infoRequested(int index, QtObject contact)
682+ signal addContactClicked(string label)
683
684 function _onDetailClicked(detail, action)
685 {
686 detailClicked(contact, detail, action)
687 }
688
689- // ListItemWithActions
690- //onItemClicked: root.clicked(index, contact)
691- //onItemPressAndHold: root.pressAndHold(index, contact)
692-
693 height: delegate.height
694 implicitHeight: delegate.height + (pickerLoader.item ? pickerLoader.item.height : 0)
695 width: parent ? parent.width : 0
696@@ -100,7 +99,7 @@
697 }
698 font.pointSize: 88
699 color: UbuntuColors.lightAubergine
700- text: ContactsJS.formatToDisplay(contact, root.titleDetail, root.titleFields)
701+ text: contact ? ContactsJS.formatToDisplay(contact, root.titleDetail, root.titleFields, "") : root.defaultTitle
702 elide: Text.ElideRight
703 }
704
705@@ -113,7 +112,7 @@
706 rightMargin: units.gu(2)
707 verticalCenter: parent.verticalCenter
708 }
709- name: "contact"
710+ name: contact ? "contact" : "new-contact"
711 height: units.gu(3)
712 width: opacity > 0.0 ? height : 0
713 opacity: root.detailsShown ? 1.0 : 0.0
714@@ -122,8 +121,14 @@
715 }
716
717 MouseArea {
718- anchors.fill: parent
719- onClicked: root.infoRequested(index, contact)
720+ anchors.fill: parent
721+ onClicked: {
722+ if (contact) {
723+ root.infoRequested(index, contact)
724+ } else {
725+ root.addContactClicked(name.text)
726+ }
727+ }
728 }
729 }
730
731@@ -139,7 +144,7 @@
732 return Qt.resolvedUrl("ContactDetailPickerPhoneNumberDelegate.qml")
733 }
734 }
735- active: root.detailsShown
736+ active: contact && root.detailsShown
737 asynchronous: true
738 anchors {
739 top: delegate.bottom
740@@ -153,10 +158,79 @@
741 }
742
743 onStatusChanged: {
744- if (status == Loader.Ready) {
745+ if ((status == Loader.Ready) && contact) {
746 pickerLoader.item.updateDetails(contact)
747 pickerLoader.item.detailClicked.connect(root._onDetailClicked)
748 }
749 }
750 }
751+
752+ Behavior on height {
753+ id: behaviorOnHeight
754+
755+ enabled: false
756+ UbuntuNumberAnimation { }
757+ }
758+
759+ state: isCurrentItem ? "expanded" : ""
760+ states: [
761+ State {
762+ name: "expanded"
763+ PropertyChanges {
764+ target: root
765+ clip: true
766+ height: root.implicitHeight
767+ loaderOpacity: 1.0
768+ // FIXME: Setting detailsShown to true on expanded state cause the property to change to false and true during the state transition, and that
769+ // causes the loader to load twice
770+ //detailsShown: true
771+ }
772+ PropertyChanges {
773+ target: behaviorOnHeight
774+ enabled: true
775+ }
776+ }
777+ ]
778+ transitions: [
779+ Transition {
780+ from: "expanded"
781+ to: ""
782+ SequentialAnimation {
783+ UbuntuNumberAnimation {
784+ target: root
785+ properties: "height, loaderOpacity"
786+ }
787+ PropertyAction {
788+ target: root
789+ property: "clip"
790+ }
791+ PropertyAction {
792+ target: root
793+ property: "detailsShown"
794+ value: false
795+ }
796+ PropertyAction {
797+ target: root
798+ property: "ListView.delayRemove"
799+ value: false
800+ }
801+ }
802+ },
803+ Transition {
804+ from: ""
805+ to: "expanded"
806+ SequentialAnimation {
807+ PropertyAction {
808+ target: root
809+ properties: "detailsShown"
810+ value: true
811+ }
812+ PropertyAction {
813+ target: root
814+ properties: "ListView.delayRemove"
815+ value: true
816+ }
817+ }
818+ }
819+ ]
820 }
821
822=== modified file 'src/imports/Ubuntu/Contacts/ContactListView.qml'
823--- src/imports/Ubuntu/Contacts/ContactListView.qml 2014-06-18 15:56:42 +0000
824+++ src/imports/Ubuntu/Contacts/ContactListView.qml 2014-06-27 21:27:44 +0000
825@@ -45,12 +45,12 @@
826 readonly property alias count: view.count
827
828 /*!
829- \qmlproperty string contactNameFilter
830+ \qmlproperty string contactStringFilter
831
832 This property holds a string that will be used to filter contacts on the list
833 By default this is set to empty
834 */
835- property string contactNameFilter: ""
836+ property string filterTerm: ""
837 /*!
838 \qmlproperty Filter filter
839
840@@ -223,6 +223,10 @@
841 */
842 signal detailClicked(QtObject contact, QtObject detail, string action)
843 /*!
844+ This handler is called when a unknown contact is clicked, the label contains the phone number
845+ */
846+ signal addContactClicked(string label)
847+ /*!
848 This handler is called when the contact delegate disapear (height === 0) caused by the function call makeDisappear
849 */
850 signal contactDisappeared(QtObject contact)
851@@ -290,7 +294,8 @@
852 Rectangle {
853 id: itemHeader
854
855- height: units.gu(2)
856+ visible: root.showFavourites && (root.filterTerm.length === 0)
857+ height: visible ? units.gu(2) : 0
858 anchors {
859 left: parent.left
860 right: parent.right
861@@ -311,14 +316,14 @@
862 text: i18n.dtr("address-book-app", "All")
863 horizontalAlignment: Text.AlignHCenter
864 verticalAlignment: Text.AlignVCenter
865- color: root.showFavourites ? UbuntuColors.warmGrey : UbuntuColors.orange
866+ color: view.favouritesIsSelected ? UbuntuColors.warmGrey : UbuntuColors.orange
867 MouseArea {
868 anchors.fill: parent
869 onClicked: {
870 //WORKAROUND: clear the model before start populate it with the new contacts
871 //otherwise the model will wait for all contacts before show any new contact
872 root.changeFilter(root.filter)
873- root.showFavourites = false
874+ view.favouritesIsSelected = false
875 }
876 }
877 }
878@@ -343,21 +348,22 @@
879 text: i18n.dtr("address-book-app", "Favourites")
880 horizontalAlignment: Text.AlignHCenter
881 verticalAlignment: Text.AlignVCenter
882- color: root.showFavourites ? UbuntuColors.orange : UbuntuColors.warmGrey
883+ color: view.favouritesIsSelected ? UbuntuColors.orange : UbuntuColors.warmGrey
884 MouseArea {
885 anchors.fill: parent
886- onClicked: root.showFavourites = true
887+ onClicked: view.favouritesIsSelected = true
888 }
889 }
890 }
891 }
892
893- onContactNameFilterChanged: contactSearchTimeout.restart()
894+ onFilterTermChanged: contactSearchTimeout.restart()
895
896 ContactSimpleListView {
897 id: view
898
899- property bool showFavourites: false
900+ property bool showFavourites: true
901+ property bool favouritesIsSelected: false
902
903 function getSectionText(index) {
904 var tag = listModel.contacts[index].tag.tag
905@@ -371,14 +377,93 @@
906 top: itemHeader.bottom
907 left: parent.left
908 right: parent.right
909+ bottom: parent.bottom
910 rightMargin: fastScroll.showing ? fastScroll.width - units.gu(1) : 0
911- bottom: parent.bottom
912-
913 Behavior on rightMargin {
914 UbuntuNumberAnimation {}
915 }
916 }
917
918+ header: Column {
919+ id: mostCalledView
920+
921+ function makeItemVisible(item)
922+ {
923+ var itemY = mostCalledView.y + item.y
924+ var areaY = view.contentY
925+ if (itemY < areaY) {
926+ view.contentY = itemY
927+ }
928+ }
929+
930+ anchors {
931+ left: parent.left
932+ right: parent.right
933+ }
934+ height: visible ? childrenRect.height : 0
935+ visible: view.favouritesIsSelected && (callerRepeat.count > 0)
936+ onHeightChanged: {
937+ // make selected item fully visible
938+ if (calledModel.currentIndex != -1) {
939+ mostCalledView.makeItemVisible(callerRepeat.itemAt(calledModel.currentIndex))
940+ } else {
941+ // WORKAROUND: The SDK header causes the contactY to move to a wrong postion
942+ // this should fix the Y position (630 is the header height)
943+ view.contentY = -630
944+ }
945+ }
946+
947+ Rectangle {
948+ color: Theme.palette.normal.background
949+ anchors {
950+ left: parent.left
951+ right: parent.right
952+ margins: units.gu(1)
953+ }
954+ height: units.gu(3)
955+ Label {
956+ anchors.fill: parent
957+ verticalAlignment: Text.AlignVCenter
958+ text: i18n.tr("Frequently called")
959+ font.pointSize: 76
960+ }
961+ ListItem.ThinDivider {
962+ anchors {
963+ left: parent.left
964+ right: parent.right
965+ bottom: parent.bottom
966+ }
967+ }
968+ }
969+ Repeater {
970+ id: callerRepeat
971+
972+ model: MostCalledModel {
973+ id: calledModel
974+ maxCount: 20
975+
976+ onInfoRequested: root.infoRequested(contact)
977+ onDetailClicked: root.detailClicked(contact, detail, action)
978+ onAddContactClicked: root.addContactClicked(label)
979+ onCurrentIndexChanged: {
980+ if (currentIndex !== -1) {
981+ view.currentIndex = -1
982+ }
983+ }
984+ }
985+ }
986+
987+ Connections {
988+ target: view
989+ onCurrentIndexChanged: {
990+ if (view.currentIndex !== -1) {
991+ calledModel.currentIndex = -1
992+ }
993+ }
994+ }
995+ }
996+
997+ height: Math.min(root.height, contentHeight)
998 onError: root.error(message)
999 onInfoRequested: root.infoRequested(contact)
1000 onDetailClicked: root.detailClicked(contact, detail, action)
1001@@ -400,6 +485,34 @@
1002 matchFlags: DetailFilter.MatchExactly
1003 }
1004
1005+ UnionFilter {
1006+ id: contactTermFilter
1007+
1008+ property string value: ""
1009+
1010+ DetailFilter {
1011+ detail: ContactDetail.DisplayLabel
1012+ field: DisplayLabel.Label
1013+ value: contactTermFilter.value
1014+ matchFlags: DetailFilter.MatchContains
1015+ }
1016+
1017+ DetailFilter {
1018+ detail: ContactDetail.PhoneNumber
1019+ field: PhoneNumber.Number
1020+ value: contactTermFilter.value
1021+ matchFlags: DetailFilter.MatchPhoneNumber
1022+ }
1023+
1024+ DetailFilter {
1025+ detail: ContactDetail.PhoneNumber
1026+ field: PhoneNumber.Number
1027+ value: contactTermFilter.value
1028+ matchFlags: DetailFilter.MatchContains
1029+ }
1030+ }
1031+
1032+
1033 IntersectionFilter {
1034 id: contactsFilter
1035
1036@@ -407,29 +520,21 @@
1037
1038 filters: {
1039 var filters = []
1040- if (root.showFavourites) {
1041+ if (contactTermFilter.value.length > 0) {
1042+ filters.push(contactTermFilter)
1043+ } else if (view.showFavourites && view.favouritesIsSelected) {
1044 filters.push(favouritesFilter)
1045 }
1046+
1047 if (root.filter) {
1048 filters.push(root.filter)
1049 }
1050- if (nameFilter.value && (nameFilter.value.length > 0)) {
1051- filters.push(nameFilter)
1052- }
1053+
1054 active = (filters.length > 0)
1055 return filters
1056 }
1057 }
1058
1059- DetailFilter {
1060- id: nameFilter
1061-
1062- detail: ContactDetail.DisplayLabel
1063- field: DisplayLabel.Label
1064- value: root.nameFilter
1065- matchFlags: DetailFilter.MatchContains
1066- }
1067-
1068 Timer {
1069 id: contactSearchTimeout
1070
1071@@ -437,14 +542,26 @@
1072 repeat: false
1073 interval: 300
1074 onTriggered: {
1075- if (root.contactNameFilter === "") { // if the search criteria is empty clear the list before show all contacts
1076- contactList.changeFilter(root.filter)
1077- nameFilter.value = ""
1078+ var needUpdate = false
1079+ if (root.filterTerm === "") { // if the search criteria is empty clear the list before show all contacts
1080+ if (contactTermFilter.value !== "") {
1081+ root.changeFilter(root.filter)
1082+ contactTermFilter.value = ""
1083+ needUpdate = true
1084+ }
1085 } else {
1086- if (nameFilter.value === "") { // if the search starts clear the list before show results
1087- contactList.changeFilter(root.filter)
1088+ if (contactTermFilter.value !== root.filterTerm) {
1089+ if (contactTermFilter.value === "") { // if the search starts clear the list before show results
1090+ root.changeFilter(root.filter)
1091+ }
1092+ contactTermFilter.value = root.filterTerm
1093+ needUpdate = true
1094 }
1095- nameFilter.value = root.contactNameFilter
1096+ }
1097+
1098+ // manually update if autoUpdate is disabled
1099+ if (needUpdate && !root.autoUpdate) {
1100+ contactsModel.update()
1101 }
1102 }
1103 }
1104@@ -499,9 +616,9 @@
1105 enabled: view.contentHeight > (view.height * 2)
1106
1107 anchors {
1108- top: itemHeader.bottom
1109+ top: view.top
1110 topMargin: units.gu(0.5)
1111- bottom: parent.bottom
1112+ bottom: view.bottom
1113 right: parent.right
1114 }
1115 }
1116
1117=== modified file 'src/imports/Ubuntu/Contacts/ContactSimpleListView.qml'
1118--- src/imports/Ubuntu/Contacts/ContactSimpleListView.qml 2014-06-16 17:33:52 +0000
1119+++ src/imports/Ubuntu/Contacts/ContactSimpleListView.qml 2014-06-27 21:27:44 +0000
1120@@ -268,34 +268,16 @@
1121 listDelegate: ContactDelegate {
1122 id: contactDelegate
1123
1124- // overwrite
1125- function disappeared()
1126- {
1127- contactListView.contactDisappeared(contact)
1128- }
1129-
1130 width: parent.width
1131 selected: contactListView.multiSelectionEnabled && contactListView.isSelected(contactDelegate)
1132 defaultAvatarUrl: contactListView.defaultAvatarImageUrl
1133 titleDetail: contactListView.titleDetail
1134 titleFields: contactListView.titleFields
1135-
1136- // ListItemWithActions
1137- //locked: contactListView.isInSelectionMode || detailsShown
1138- //triggerActionOnMouseRelease: true
1139- //leftSideAction: contactListView.leftSideAction
1140- //rightSideActions: contactListView.rightSideActions
1141+ isCurrentItem: ListView.isCurrentItem
1142
1143 onDetailClicked: contactListView.detailClicked(contact, detail, action)
1144 onInfoRequested: contactListView._fetchContact(index, contact)
1145
1146- Behavior on height {
1147- id: behaviorOnHeight
1148-
1149- enabled: false
1150- UbuntuNumberAnimation { }
1151- }
1152-
1153 // collapse the item before remove it, to avoid crash
1154 ListView.onRemove: SequentialAnimation {
1155 ScriptAction {
1156@@ -333,67 +315,6 @@
1157 contactListView.selectItem(contactDelegate)
1158 }
1159 }
1160- state: ListView.isCurrentItem ? "expanded" : ""
1161- states: [
1162- State {
1163- name: "expanded"
1164- PropertyChanges {
1165- target: contactDelegate
1166- clip: true
1167- height: contactDelegate.implicitHeight
1168- loaderOpacity: 1.0
1169- // FIXME: Setting detailsShown to true on expanded state cause the property to change to false and true during the state transition, and that
1170- // causes the loader to load twice
1171- //detailsShown: true
1172- }
1173- PropertyChanges {
1174- target: behaviorOnHeight
1175- enabled: true
1176- }
1177- }
1178- ]
1179- transitions: [
1180- Transition {
1181- from: "expanded"
1182- to: ""
1183- SequentialAnimation {
1184- UbuntuNumberAnimation {
1185- target: contactDelegate
1186- properties: "height, loaderOpacity"
1187- }
1188- PropertyAction {
1189- target: contactDelegate
1190- property: "clip"
1191- }
1192- PropertyAction {
1193- target: contactDelegate
1194- property: "detailsShown"
1195- value: false
1196- }
1197- PropertyAction {
1198- target: contactDelegate
1199- property: "ListView.delayRemove"
1200- value: false
1201- }
1202- }
1203- },
1204- Transition {
1205- from: ""
1206- to: "expanded"
1207- SequentialAnimation {
1208- PropertyAction {
1209- target: contactDelegate
1210- properties: "detailsShown"
1211- value: true
1212- }
1213- PropertyAction {
1214- target: contactDelegate
1215- properties: "ListView.delayRemove"
1216- value: true
1217- }
1218- }
1219- }
1220- ]
1221 }
1222
1223 ContactFetch {
1224
1225=== modified file 'src/imports/Ubuntu/Contacts/Contacts.js'
1226--- src/imports/Ubuntu/Contacts/Contacts.js 2014-06-06 17:52:58 +0000
1227+++ src/imports/Ubuntu/Contacts/Contacts.js 2014-06-27 21:27:44 +0000
1228@@ -2,9 +2,9 @@
1229 var phoneTypeModel = null
1230
1231 // Format contact name to be displayed
1232-function formatToDisplay(contact, contactDetail, detailFields, detail) {
1233+function formatToDisplay(contact, contactDetail, detailFields, detail, defaultTitle) {
1234 if (!contact) {
1235- return ""
1236+ return defaultTitle
1237 }
1238
1239 if (!detail) {
1240
1241=== added file 'src/imports/Ubuntu/Contacts/MostCalledModel.qml'
1242--- src/imports/Ubuntu/Contacts/MostCalledModel.qml 1970-01-01 00:00:00 +0000
1243+++ src/imports/Ubuntu/Contacts/MostCalledModel.qml 2014-06-27 21:27:44 +0000
1244@@ -0,0 +1,183 @@
1245+/*
1246+ * Copyright (C) 2012-2013 Canonical, Ltd.
1247+ *
1248+ * This program is free software; you can redistribute it and/or modify
1249+ * it under the terms of the GNU General Public License as published by
1250+ * the Free Software Foundation; version 3.
1251+ *
1252+ * This program is distributed in the hope that it will be useful,
1253+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1254+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1255+ * GNU General Public License for more details.
1256+ *
1257+ * You should have received a copy of the GNU General Public License
1258+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1259+ */
1260+
1261+
1262+import QtQuick 2.2
1263+import QtContacts 5.0
1264+import Ubuntu.History 0.1
1265+import Ubuntu.Telephony 0.1
1266+
1267+VisualDataModel {
1268+ id: root
1269+
1270+ property int maxCount: 10
1271+ property var contactModel: null
1272+ property var historyModel
1273+ property int currentIndex: -1
1274+
1275+ signal clicked(int index, QtObject contact)
1276+ signal detailClicked(QtObject contact, QtObject detail, string action)
1277+ signal infoRequested(int index, QtObject contact)
1278+ signal addContactClicked(string label)
1279+
1280+ function filterEntries()
1281+ {
1282+ var contacts = {}
1283+ var interval = new Date()
1284+ var secs = (interval.getTime() - 2592000000) // one month ago
1285+ interval.setTime(secs)
1286+
1287+ var totalCount = 0
1288+ var i = 0;
1289+ while(true) {
1290+ var event = historyModel.getItem(i)
1291+ if (!event) {
1292+ break
1293+ }
1294+
1295+ if (event.timestamp < interval) {
1296+ break
1297+ }
1298+
1299+ var participants = event.participants
1300+ for (var p=0; p < participants.length; p++) {
1301+ var phoneNumber = participants[p]
1302+ if (phoneNumber) {
1303+ if (contacts[phoneNumber] === undefined) {
1304+ contacts[phoneNumber] = 1
1305+ } else {
1306+ var count = contacts[phoneNumber]
1307+ contacts[phoneNumber] = count + 1
1308+ }
1309+ totalCount += 1
1310+ }
1311+ }
1312+ i++
1313+ }
1314+
1315+ listModel.clear()
1316+ if (totalCount == 0) {
1317+ return
1318+ }
1319+
1320+ // sort phones most called first
1321+ var mostCalledFirst = []
1322+ for (var key in contacts) {
1323+ mostCalledFirst.push([key, contacts[key]]);
1324+ }
1325+
1326+ mostCalledFirst.sort(function(a, b) {
1327+ a = a[1];
1328+ b = b[1];
1329+
1330+ return a < b ? -1 : (a > b ? 1 : 0);
1331+ });
1332+
1333+ contacts = {}
1334+ for (var i = 0; i < mostCalledFirst.length; i++) {
1335+ var key = mostCalledFirst[i][0];
1336+ var value = mostCalledFirst[i][1];
1337+ contacts[key] = value
1338+ }
1339+
1340+ // get the avarage frequency
1341+ var average = totalCount / mostCalledFirst.length
1342+
1343+ for (var phone in contacts) {
1344+ if (contacts[phone] >= average) {
1345+ listModel.insert(0, {"participant": phone})
1346+ if (listModel.count >= root.maxCount) {
1347+ return;
1348+ }
1349+ }
1350+ }
1351+ }
1352+
1353+ model: ListModel {
1354+ id: listModel
1355+ }
1356+
1357+ historyModel: HistoryEventModel {
1358+
1359+ function getItem(row) {
1360+ while ((row >= count) && (canFetchMore())) {
1361+ fetchMore()
1362+ }
1363+ return get(row)
1364+ }
1365+
1366+ type: HistoryThreadModel.EventTypeVoice
1367+ sort: HistorySort {
1368+ sortField: "timestamp"
1369+ sortOrder: HistorySort.DescendingOrder
1370+ }
1371+ Component.onCompleted: root.filterEntries()
1372+ }
1373+
1374+
1375+ delegate: ContactDelegate {
1376+ id: contactDelegate
1377+
1378+ readonly property alias contact: contactFetch.contact
1379+
1380+ onDetailClicked: root.detailClicked(contact, detail, action)
1381+ onInfoRequested: root.infoRequested(index, contact)
1382+ onAddContactClicked: root.addContactClicked(label)
1383+
1384+ defaultAvatarUrl: "image://theme/contacts"
1385+ defaultTitle: participant
1386+ width: parent.width
1387+ titleDetail: ContactDetail.DisplayLabel
1388+ titleFields: [ DisplayLabel.Label ]
1389+ isCurrentItem: root.currentIndex === index
1390+
1391+ // collapse the item before remove it, to avoid crash
1392+ ListView.onRemove: SequentialAnimation {
1393+ ScriptAction {
1394+ script: {
1395+ if (contactDelegate.state !== "") {
1396+ historyModel.currentIndex = -1
1397+ }
1398+ }
1399+ }
1400+ }
1401+
1402+ onClicked: {
1403+ if (root.currentIndex === index) {
1404+ root.currentIndex = -1
1405+ return
1406+ } else if (detailToPick !== 0) {
1407+ root.currentIndex = index
1408+ return
1409+ } else if (detailToPick == 0) {
1410+ contactListView.detailClicked(contact, null, "")
1411+ }
1412+ }
1413+
1414+ ContactWatcher {
1415+ id: contactWatcher
1416+
1417+ phoneNumber: participant
1418+ onContactIdChanged: contactFetch.fetchContact(contactId)
1419+ }
1420+
1421+ ContactFetch {
1422+ id: contactFetch
1423+
1424+ model: contactsModel
1425+ }
1426+ }
1427+}
1428
1429=== modified file 'src/imports/Ubuntu/Contacts/qmldir'
1430--- src/imports/Ubuntu/Contacts/qmldir 2014-06-09 15:52:06 +0000
1431+++ src/imports/Ubuntu/Contacts/qmldir 2014-06-27 21:27:44 +0000
1432@@ -16,3 +16,4 @@
1433 internal ContactJs Contacts.js
1434 internal FastScroll FastScroll.qml
1435 internal FastScrollJs FastScroll.js
1436+internal MostCalledModel MostCalledModel.qml

Subscribers

People subscribed via source and target branches