Merge lp:~renatofilho/address-book-app/release-2014-07-17 into lp:address-book-app

Proposed by Renato Araujo Oliveira Filho
Status: Merged
Approved by: Bill Filler
Approved revision: 240
Merged at revision: 252
Proposed branch: lp:~renatofilho/address-book-app/release-2014-07-17
Merge into: lp:address-book-app
Diff against target: 994 lines (+484/-123)
13 files modified
CMakeLists.txt (+8/-0)
debian/control (+1/-1)
src/imports/ContactEdit/ContactDetailSyncTargetEditor.qml (+3/-5)
src/imports/ContactEdit/ContactEditor.qml (+1/-1)
src/imports/ContactList/ContactListPage.qml (+41/-23)
src/imports/Ubuntu/Contacts/ContactDelegate.qml (+6/-6)
src/imports/Ubuntu/Contacts/ContactListView.qml (+111/-78)
src/imports/Ubuntu/Contacts/ContactSimpleListView.qml (+4/-1)
src/imports/Ubuntu/Contacts/FastScroll.qml (+9/-3)
src/imports/Ubuntu/Contacts/ListItemWithActions.qml (+9/-4)
tests/autopilot/address_book_app/tests/__init__.py (+2/-0)
tests/qml/CMakeLists.txt (+8/-1)
tests/qml/tst_ListWithActions.qml (+281/-0)
To merge this branch: bzr merge lp:~renatofilho/address-book-app/release-2014-07-17
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Bill Filler (community) Needs Fixing
Gustavo Pichorim Boiko (community) Approve
Review via email: mp+227255@code.launchpad.net

Commit message

[Contacts] Fixed delete action activation.
[ContactEditPage] Make sure that the address book combo box is visible when creating a new contact from a external app using the uri handler.
[ContatListPage] Update ContactListPage "+ Create New" button visuals.
[Contacts] Export header property on ContactListView
[ContactListView]Fixed fast scroll freeze while trying jump into a section while still scrolling.

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
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
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? NO

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? YES

If you changed the packaging (debian), did you add a core-dev as a reviewer to this MP? NO PACKAGE CHANGE

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
Revision history for this message
Bill Filler (bfiller) wrote :

Not working for me, a few issues:

1) swipe to delete on contacts list page still doesn't work
2) Address book combo is not displayed when creating a new contact directly from address book app. Works only via url handler now.
3) "create new" when called from url handler doesn't ensure the contact list is visible and scrolled to the top.
 -- If you previously had app open and list scrolled down it should ensure it's scrolled to top so you can see "+ create new" button
 -- If you previously had app open and viewing favorites, it should reset to top of "All" list. Currently it stays on favorites.
4) Fast scroll and release on letter "A" and a lot of times the "A" icon gets stuck visible even though the fast scroll list has disappeared
5) Contact list should collapse any expansions when you start scrolling, currently the contact stays expanded

review: Needs Fixing
229. By Renato Araujo Oliveira Filho

Fixed swipe to delete.

230. By Renato Araujo Oliveira Filho

Fixed addressbook visibility when creating a new contact.

231. By Renato Araujo Oliveira Filho

Make sure that the list scroll back to begginer when app is invoked by other app.

232. By Renato Araujo Oliveira Filho

Fixed fast scroll disappear while jumping into the letters.

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

Reset contact list when the address-book app is called from another app.

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

colllapse contact if the user starts scrolling the list.

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

Fixed focus problem in search field.

236. By Renato Araujo Oliveira Filho

Make sure that the fast scroll letter disappear with the alphabetical list.

237. By Renato Araujo Oliveira Filho

Updated save icon on contact indicator.

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

Only problem is see now is this:
>5) Contact list should collapse any expansions when you start scrolling, currently the contact >stays expanded

During manual scrolling the list is collapsed as it should be. The problem now is if the keyboard is visible and you try to expand a row that is right above keyboard. It starts to expand, then scrolls up so it's visible, and then the scrolling causes it to collapse.

To reproduce:
- search for contacts
- select a contact that is directly above keyboard
- notice that it expands and then collapses before you can see it
- it should expand and scroll into view

If we can't detect the different kinds of scrolls then lets not autocollapse for now.

review: Needs Fixing
238. By Renato Araujo Oliveira Filho

Only auto collapse the contact when flick starts.

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

Fixed list flicking stop during the item expansion animation

240. By Renato Araujo Oliveira Filho

Avoid to stop the contact list view while collapsing the contact.

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

going to land this MR but still one problem you can fix later.
If contact expanded it works fine when you flick up. But when you flick down the contact usually gets stuck at the bottom and the flick doesn't continue. Sometimes it works but mostly not.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-07-16 12:56:19 +0000
3+++ CMakeLists.txt 2014-07-23 23:51:06 +0000
4@@ -21,6 +21,13 @@
5 find_program(INTLTOOL_MERGE intltool-merge)
6 find_program(INTLTOOL_EXTRACT intltool-extract)
7
8+if(NOT INTLTOOL_MERGE)
9+ message(FATAL_ERROR "intltool-merge not found. Try install intltool package;")
10+endif()
11+if(NOT INTLTOOL_EXTRACT)
12+ message(FATAL_ERROR "intltool-extract not found. Try install intltool package;")
13+endif()
14+
15 set(ADDRESS_BOOK_APP_DIR ${CMAKE_INSTALL_DATADIR}/address-book-app)
16 set(ADDRESS_BOOK_APP_FULL_DIR ${CMAKE_INSTALL_FULL_DATADIR}/address-book-app)
17 set(ADDRESS_BOOK_APP_NAME "Address Book")
18@@ -34,6 +41,7 @@
19 option(INSTALL_TESTS "Install the tests on make install" on)
20 option(INSTALL_COMPONENTS "Install the Ubuntu contact components" on)
21 option(CLICK_MODE "Installs to a contained location" off)
22+option(USE_XVFB "Use XVFB to run qml tests" on)
23
24 # Tests
25 enable_testing()
26
27=== modified file 'debian/control'
28--- debian/control 2014-07-09 17:22:14 +0000
29+++ debian/control 2014-07-23 23:51:06 +0000
30@@ -41,7 +41,7 @@
31 qtdeclarative5-ubuntu-content0.1,
32 qtdeclarative5-ubuntu-history0.1,
33 qtdeclarative5-ubuntu-keyboard-extensions0.1,
34- qtdeclarative5-ubuntu-telephony-phonenumber0.1,
35+ qtdeclarative5-ubuntu-telephony-phonenumber0.1 (>= 0.1+14.10.20140715.1),
36 ${misc:Depends},
37 ${shlibs:Depends},
38 Description: Address Book application
39
40=== modified file 'src/imports/ContactEdit/ContactDetailSyncTargetEditor.qml'
41--- src/imports/ContactEdit/ContactDetailSyncTargetEditor.qml 2014-06-12 22:55:20 +0000
42+++ src/imports/ContactEdit/ContactDetailSyncTargetEditor.qml 2014-07-23 23:51:06 +0000
43@@ -24,7 +24,7 @@
44 ContactDetailBase {
45 id: root
46
47- property bool active: false
48+ property alias active: sourceModel.autoUpdate
49
50 function save() {
51 // only changes the target sync for new contacts
52@@ -54,9 +54,8 @@
53 property bool isNewContact: contact && contact.contactId === "qtcontacts:::"
54 property real myHeight: sources.containerHeight + units.gu(4) + label.height
55
56- detail: contact ? contact.detail(ContactDetail.SyncTarget) : null
57- implicitHeight: isNewContact && sources.model && (sources.model.contacts.length > 1) ? myHeight : 0
58-
59+ detail: root.contact ? contact.detail(ContactDetail.SyncTarget) : null
60+ implicitHeight: root.isNewContact && sources.model && (sources.model.contacts.length > 1) ? myHeight : 0
61
62 ContactModel {
63 id: sourceModel
64@@ -118,6 +117,5 @@
65 sourceModel.update()
66 }
67 }
68-
69 }
70
71
72=== modified file 'src/imports/ContactEdit/ContactEditor.qml'
73--- src/imports/ContactEdit/ContactEditor.qml 2014-07-11 17:27:03 +0000
74+++ src/imports/ContactEdit/ContactEditor.qml 2014-07-23 23:51:06 +0000
75@@ -381,7 +381,7 @@
76 action: Action {
77 objectName: "save"
78
79- iconName: "save"
80+ iconName: "ok"
81 text: i18n.tr("Save")
82 enabled: !nameEditor.isEmpty() || !phonesEditor.isEmpty()
83 onTriggered: contactEditor.save()
84
85=== modified file 'src/imports/ContactList/ContactListPage.qml'
86--- src/imports/ContactList/ContactListPage.qml 2014-07-16 21:46:54 +0000
87+++ src/imports/ContactList/ContactListPage.qml 2014-07-23 23:51:06 +0000
88@@ -139,6 +139,7 @@
89 {
90 newPhoneToAdd = phoneNumber
91 state = "newphone"
92+ contactList.reset()
93 }
94
95 title: i18n.tr("Contacts")
96@@ -193,30 +194,45 @@
97 }
98 }
99
100- Button {
101- id: addNewContactButton
102- objectName: "addNewContact"
103-
104- text: i18n.tr("+ New Contact")
105- anchors {
106- top: parent.top
107- left: parent.left
108- right: parent.right
109- margins: visible ? units.gu(2) : 0
110- }
111- height: visible ? units.gu(4) : 0
112- visible: false
113- onClicked: mainPage.createContactWithPhoneNumber(mainPage.newPhoneToAdd)
114- }
115-
116 flickable: null //contactList.fastScrolling ? null : contactList.view
117 ContactsUI.ContactListView {
118 id: contactList
119 objectName: "contactListView"
120
121+ header: Rectangle {
122+ id: addNewContactButton
123+ objectName: "addNewContact"
124+
125+ anchors {
126+ left: parent.left
127+ right: parent.right
128+ }
129+ height: visible ? units.gu(8) : 0
130+ color: Theme.palette.normal.background
131+
132+ Rectangle {
133+ anchors.fill: parent
134+ color: Theme.palette.selected.background
135+ opacity: addNewContactButtonArea.pressed ? 1.0 : 0.0
136+ }
137+
138+ Label {
139+ anchors.centerIn: parent
140+ text: i18n.tr("+ Create New")
141+ fontSize: "large"
142+ }
143+
144+ visible: false
145+ MouseArea {
146+ id: addNewContactButtonArea
147+
148+ anchors.fill: parent
149+ onClicked: mainPage.createContactWithPhoneNumber(mainPage.newPhoneToAdd)
150+ }
151+ }
152+
153 anchors {
154- top: addNewContactButton.bottom
155- topMargin: addNewContactButton.visible ? units.gu(2) : 0
156+ top: parent.top
157 left: parent.left
158 bottom: keyboard.top
159 right: parent.right
160@@ -417,7 +433,10 @@
161 visible: mainPage.searching
162 iconName: "close"
163 text: i18n.tr("Cancel")
164- onTriggered: mainPage.state = (mainPage.state === "newphoneSearching" ? "newphone" : "")
165+ onTriggered: {
166+ contactList.forceActiveFocus()
167+ mainPage.state = (mainPage.state === "newphoneSearching" ? "newphone" : "")
168+ }
169 }
170 }
171 }
172@@ -518,11 +537,10 @@
173 }
174 ]
175 tools: toolbarItemsNormalMode
176-
177- // WORKAROUND: Avoid the gap btw the header and the contact list when the list moves
178- // see bug #1296764
179 onActiveChanged: {
180- contactList.returnToBounds()
181+ if (active && addNewContactButton.visible) {
182+ contactList.positionViewAtBeginning()
183+ }
184 }
185
186 onSyncEnabledChanged: {
187
188=== modified file 'src/imports/Ubuntu/Contacts/ContactDelegate.qml'
189--- src/imports/Ubuntu/Contacts/ContactDelegate.qml 2014-07-10 20:23:11 +0000
190+++ src/imports/Ubuntu/Contacts/ContactDelegate.qml 2014-07-23 23:51:06 +0000
191@@ -32,6 +32,7 @@
192 property variant titleFields: [ Name.FirstName, Name.LastName ]
193 property bool detailsShown: false
194 property int loaderOpacity: 0.0
195+ property bool flicking: false
196
197 signal clicked(int index, QtObject contact)
198 signal pressAndHold(int index, QtObject contact)
199@@ -181,7 +182,9 @@
200 Behavior on height {
201 id: behaviorOnHeight
202
203- enabled: false
204+ property bool active: false
205+
206+ enabled: active && !root.flicking
207 UbuntuNumberAnimation { }
208 }
209
210@@ -201,7 +204,7 @@
211 }
212 PropertyChanges {
213 target: behaviorOnHeight
214- enabled: true
215+ active: true
216 }
217 }
218 ]
219@@ -210,10 +213,6 @@
220 from: "expanded"
221 to: ""
222 SequentialAnimation {
223- UbuntuNumberAnimation {
224- target: root
225- properties: "height, loaderOpacity"
226- }
227 PropertyAction {
228 target: root
229 property: "clip"
230@@ -244,6 +243,7 @@
231 properties: "ListView.delayRemove"
232 value: true
233 }
234+
235 }
236 }
237 ]
238
239=== modified file 'src/imports/Ubuntu/Contacts/ContactListView.qml'
240--- src/imports/Ubuntu/Contacts/ContactListView.qml 2014-07-16 19:31:08 +0000
241+++ src/imports/Ubuntu/Contacts/ContactListView.qml 2014-07-23 23:51:06 +0000
242@@ -44,6 +44,8 @@
243 readonly property alias view: view
244 readonly property alias count: view.count
245
246+ property var header: []
247+
248 /*!
249 \qmlproperty string contactStringFilter
250
251@@ -202,6 +204,7 @@
252 This property holds a list with the index of selected items
253 */
254 readonly property alias isInSelectionMode: view.isInSelectionMode
255+
256 /*!
257 This handler is called when the selection mode is finished without be canceled
258 */
259@@ -273,7 +276,7 @@
260 }
261 function positionViewAtBeginning()
262 {
263- view.positionViewAtBeginning()
264+ moveToBegining.restart()
265 }
266 function changeFilter(newFilter)
267 {
268@@ -282,6 +285,16 @@
269 }
270 root.filter = newFilter
271 }
272+ function reset()
273+ {
274+ if (view.favouritesIsSelected) {
275+ root.changeFilter(root.filter)
276+ view.favouritesIsSelected = false
277+ } else {
278+ positionViewAtBeginning()
279+ }
280+ }
281+
282 /*!
283 Causes the list to update
284 \l autoUpdate
285@@ -405,105 +418,119 @@
286 }
287 }
288
289+ // WORKAROUND: The SDK header causes the contactY to move to a wrong postion
290+ // calling the positionViewAtBeginning after the list created fix that
291+ Timer {
292+ id: moveToBegining
293+
294+ interval: 100
295+ running: false
296+ repeat: false
297+ onTriggered: view.positionViewAtBeginning()
298+ }
299+
300 header: Column {
301 id: mostCalledView
302
303- function makeItemVisible(item)
304- {
305- var itemY = mostCalledView.y + item.y
306- var areaY = view.contentY
307- if (itemY < areaY) {
308- view.contentY = itemY
309- view.returnToBounds()
310- }
311- }
312-
313 anchors {
314 left: parent.left
315 right: parent.right
316 }
317- height: visible ? childrenRect.height : 0
318- visible: view.favouritesIsSelected && (callerRepeat.count > 0)
319 onHeightChanged: {
320 if (calledModel.currentIndex != -1) {
321 mostCalledView.makeItemVisible(callerRepeat.itemAt(calledModel.currentIndex))
322 }
323 }
324-
325- // WORKAROUND: The SDK header causes the contactY to move to a wrong postion
326- // calling the positionViewAtBeginning after the list created fix that
327- Timer {
328- id: moveToBegining
329-
330- interval: 100
331- running: false
332- repeat: false
333- onTriggered: view.positionViewAtBeginning()
334+ Item {
335+ id: headerContents
336+ anchors {
337+ left: parent.left
338+ right: parent.right
339+ }
340+ height: childrenRect.height
341+ children: root.header
342 }
343
344- Rectangle {
345- color: Theme.palette.normal.background
346+ Column {
347+ function makeItemVisible(item)
348+ {
349+ var itemY = mostCalledView.y + item.y
350+ var areaY = view.contentY
351+ if (itemY < areaY) {
352+ view.contentY = itemY
353+ view.returnToBounds()
354+ }
355+ }
356+
357+ visible: view.favouritesIsSelected && (callerRepeat.count > 0)
358 anchors {
359 left: parent.left
360 right: parent.right
361- margins: units.gu(1)
362- }
363- height: units.gu(3)
364- Label {
365- anchors.fill: parent
366- verticalAlignment: Text.AlignVCenter
367- text: i18n.tr("Frequently called")
368- font.pointSize: 76
369- }
370- ListItem.ThinDivider {
371+ }
372+ height: visible ? childrenRect.height : 0
373+
374+ Rectangle {
375+ color: Theme.palette.normal.background
376 anchors {
377 left: parent.left
378 right: parent.right
379- bottom: parent.bottom
380- }
381- }
382- }
383- Repeater {
384- id: callerRepeat
385-
386- model: MostCalledModel {
387- id: calledModel
388-
389- readonly property bool visible: view.favouritesIsSelected
390-
391- onVisibleChanged: {
392- // update the model every time that it became visible
393- // in fact calling update only reloads the model data if it has changed
394- if (visible) {
395- model.update()
396- }
397- }
398- onInfoRequested: root.infoRequested(contact)
399- onDetailClicked: root.detailClicked(contact, detail, action)
400- onAddContactClicked: root.addContactClicked(label)
401- onCurrentIndexChanged: {
402- if (currentIndex !== -1) {
403- view.currentIndex = -1
404- }
405- }
406-
407- // WORKAROUND: The SDK header causes the contactY to move to a wrong postion
408- // calling the positionViewAtBeginning after the list created fix that
409- onLoaded: moveToBegining.restart()
410- }
411- }
412-
413- Connections {
414- target: view
415- onCurrentIndexChanged: {
416- if (view.currentIndex !== -1) {
417- calledModel.currentIndex = -1
418+ margins: units.gu(1)
419+ }
420+ height: units.gu(3)
421+ Label {
422+ anchors.fill: parent
423+ verticalAlignment: Text.AlignVCenter
424+ text: i18n.tr("Frequently called")
425+ font.pointSize: 76
426+ }
427+ ListItem.ThinDivider {
428+ anchors {
429+ left: parent.left
430+ right: parent.right
431+ bottom: parent.bottom
432+ }
433+ }
434+ }
435+ Repeater {
436+ id: callerRepeat
437+
438+ model: MostCalledModel {
439+ id: calledModel
440+
441+ readonly property bool visible: view.favouritesIsSelected
442+
443+ onVisibleChanged: {
444+ // update the model every time that it became visible
445+ // in fact calling update only reloads the model data if it has changed
446+ if (visible) {
447+ model.update()
448+ }
449+ }
450+ onInfoRequested: root.infoRequested(contact)
451+ onDetailClicked: root.detailClicked(contact, detail, action)
452+ onAddContactClicked: root.addContactClicked(label)
453+ onCurrentIndexChanged: {
454+ if (currentIndex !== -1) {
455+ view.currentIndex = -1
456+ }
457+ }
458+
459+ // WORKAROUND: The SDK header causes the contactY to move to a wrong postion
460+ // calling the positionViewAtBeginning after the list created fix that
461+ onLoaded: moveToBegining.restart()
462+ }
463+ }
464+
465+ Connections {
466+ target: view
467+ onCurrentIndexChanged: {
468+ if (view.currentIndex !== -1) {
469+ calledModel.currentIndex = -1
470+ }
471 }
472 }
473 }
474 }
475-
476- height: Math.min(root.height, contentHeight)
477 onError: root.error(message)
478 onInfoRequested: root.infoRequested(contact)
479 onDetailClicked: root.detailClicked(contact, detail, action)
480@@ -556,6 +583,9 @@
481 IntersectionFilter {
482 id: contactsFilter
483
484+ // avoid runtime warning "depends on non-NOTIFYable properties"
485+ readonly property alias filtersProxy: contactsFilter.filters
486+
487 property bool active: {
488 var filters_ = []
489 if (contactTermFilter.value.length > 0) {
490@@ -569,7 +599,7 @@
491 }
492
493 // check if the filter has changed
494- var oldFilters = contactsFilter.filters
495+ var oldFilters = filtersProxy
496 if (oldFilters.length !== filters_.length) {
497 contactsFilter.filters = filters_
498 } else {
499@@ -650,7 +680,10 @@
500
501 listView: view
502 // only enable FastScroll if the we have more than 2 pages of content and sections is enabled
503- enabled: showSections && (view.contentHeight > (view.height * 2)) && (view.height >= minimumHeight)
504+ enabled: showSections &&
505+ (view.contentHeight > (view.height * 2)) &&
506+ (view.height >= minimumHeight) &&
507+ (((view.contentY - view.originY) - view.headerItem.height) >= 0) // hearder already invisble
508
509 anchors {
510 top: view.top
511
512=== modified file 'src/imports/Ubuntu/Contacts/ContactSimpleListView.qml'
513--- src/imports/Ubuntu/Contacts/ContactSimpleListView.qml 2014-07-15 20:27:57 +0000
514+++ src/imports/Ubuntu/Contacts/ContactSimpleListView.qml 2014-07-23 23:51:06 +0000
515@@ -286,6 +286,7 @@
516 dirtyModel.restart()
517 }
518
519+ onFlickStarted: view.currentIndex = -1
520 listDelegate: ContactDelegate {
521 id: contactDelegate
522
523@@ -296,6 +297,7 @@
524 removalAnimation.start()
525 }
526
527+ flicking: contactListView.flicking
528 width: parent.width
529 selected: contactListView.multiSelectionEnabled && contactListView.isSelected(contactDelegate)
530 defaultAvatarUrl: contactListView.defaultAvatarImageUrl
531@@ -323,6 +325,7 @@
532 }
533 }
534
535+
536 // used by swipe to delete
537 removalAnimation: SequentialAnimation {
538 alwaysRunToEnd: true
539@@ -359,6 +362,7 @@
540 return
541 // check if we should expand and display the details picker
542 } else if (detailToPick !== -1) {
543+ //view.highlightFollowsCurrentItem = true
544 contactListView.currentIndex = index
545 return
546 } else if (detailToPick == -1) {
547@@ -384,7 +388,6 @@
548 model: root.listModel
549 onContactFetched: contactListView.infoRequested(contact)
550 }
551-
552 // This is a workaround to make sure the spinner will disappear if the model is empty
553 // FIXME: implement a model property to say if the model still busy or not
554 Item {
555
556=== modified file 'src/imports/Ubuntu/Contacts/FastScroll.qml'
557--- src/imports/Ubuntu/Contacts/FastScroll.qml 2014-07-16 19:31:08 +0000
558+++ src/imports/Ubuntu/Contacts/FastScroll.qml 2014-07-23 23:51:06 +0000
559@@ -75,7 +75,7 @@
560 radius: height * 0.3
561 height: pinSize * 2
562 width: height
563- opacity: internal.fastScrolling ? 1.0 : 0.0
564+ opacity: internal.fastScrolling && root.enabled ? 1.0 : 0.0
565 x: -cursor.width - units.gu(3)
566 y: {
567 if (internal.currentItem) {
568@@ -144,6 +144,8 @@
569 if (isVisible) {
570 rail.opacity = 1.0
571 hideTimer.stop()
572+ } else if (!root.enabled) {
573+ rail.opacity = 0.0
574 } else {
575 hideTimer.restart()
576 }
577@@ -167,7 +169,7 @@
578 horizontalAlignment: Text.AlignHCenter
579 text: internal.fastScrolling && internal.targetSection == modelData ? "" : modelData
580 fontSize: "x-small"
581- color: internal.currentItem.text === text ? Theme.palette.selected.foregroundText : Theme.palette.selected.backgroundText
582+ color: internal.currentItem && (internal.currentItem.text === text) ? Theme.palette.selected.foregroundText : Theme.palette.selected.backgroundText
583 opacity: !internal.modelDirty && Sections.contains(text) ? 1.0 : 0.5
584 }
585 }
586@@ -236,6 +238,7 @@
587 if (internal.desireSection != internal.currentSection) {
588 var idx = Sections.getIndexFor(internal.desireSection)
589 if (idx !== -1) {
590+ listView.cancelFlick()
591 listView.positionViewAtIndex(idx, ListView.Beginning)
592 }
593 }
594@@ -290,7 +293,9 @@
595 if (internal.desireSection !== section) {
596 internal.desireSection = section
597 moveIndicator(section)
598- timerScroll.restart()
599+ if (dragArea.pressed) {
600+ timerScroll.restart()
601+ }
602 }
603 }
604
605@@ -303,3 +308,4 @@
606 }
607 }
608 }
609+
610
611=== modified file 'src/imports/Ubuntu/Contacts/ListItemWithActions.qml'
612--- src/imports/Ubuntu/Contacts/ListItemWithActions.qml 2014-07-16 20:40:36 +0000
613+++ src/imports/Ubuntu/Contacts/ListItemWithActions.qml 2014-07-23 23:51:06 +0000
614@@ -152,6 +152,7 @@
615 leftMargin: units.gu(1)
616 bottom: main.bottom
617 }
618+ visible: rightSideActions.length > 0
619 width: rightActionsRepeater.count > 0 ? rightActionsRepeater.count * (root.actionWidth + units.gu(2)) + actionThreshold : 0
620 Row {
621 anchors.fill: parent
622@@ -186,6 +187,7 @@
623
624 Rectangle {
625 id: main
626+ objectName: "mainItem"
627
628 anchors {
629 top: parent.top
630@@ -238,9 +240,7 @@
631 value: 1.0
632 }
633 ScriptAction {
634- script: {
635- root.activeAction.triggered(root)
636- }
637+ script: root.activeAction.triggered(root)
638 }
639 PauseAnimation {
640 duration: 500
641@@ -263,7 +263,7 @@
642 drag {
643 target: locked ? null : main
644 axis: Drag.XAxis
645- minimumX: -(rightActionsView.width + root.actionThreshold)
646+ minimumX: rightActionsView.visible ? -(rightActionsView.width + root.actionThreshold) : 0
647 maximumX: leftActionView.visible ? leftActionView.width : 0
648 }
649
650@@ -278,6 +278,11 @@
651 onClicked: {
652 if (main.x === 0) {
653 root.itemClicked(mouse)
654+ } else if (main.x > 0) {
655+ var action = getActionAt(Qt.point(mouse.x, mouse.y))
656+ if (action && action !== -1) {
657+ action.triggered(root)
658+ }
659 } else {
660 var actionIndex = getActionAt(Qt.point(mouse.x, mouse.y))
661 if (actionIndex !== -1) {
662
663=== modified file 'tests/autopilot/address_book_app/tests/__init__.py'
664--- tests/autopilot/address_book_app/tests/__init__.py 2014-07-07 13:44:45 +0000
665+++ tests/autopilot/address_book_app/tests/__init__.py 2014-07-23 23:51:06 +0000
666@@ -61,6 +61,8 @@
667 vcard_data = AddressBookAppTestCase.VCARD_PATH_BIN
668
669 os.environ["ADDRESS_BOOK_TEST_DATA"] = vcard_data
670+ os.environ["LANG"] = "en_US.UTF-8"
671+ os.environ["LANGUAGE"] ="en_US"
672 if vcard_data != "":
673 print("Using vcard %s" % vcard_data)
674 if os.path.exists(self.app_bin):
675
676=== modified file 'tests/qml/CMakeLists.txt'
677--- tests/qml/CMakeLists.txt 2014-07-05 22:00:45 +0000
678+++ tests/qml/CMakeLists.txt 2014-07-23 23:51:06 +0000
679@@ -9,15 +9,21 @@
680 )
681
682 macro(DECLARE_QML_TEST TST_NAME TST_QML_FILE)
683+ if(USE_XVFB)
684+ set(COMMAND_PREFIX ${XVFB_RUN_BIN} -a -s "-screen 0 1024x768x24")
685+ else()
686+ set(COMMAND_PREFIX "")
687+ endif()
688 add_test(NAME ${TST_NAME}
689 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
690- COMMAND ${XVFB_RUN_BIN} -a -s "-screen 0 1024x768x24" ${QMLTESTRUNNER_BIN} -import ${imports_BINARY_DIR} -input ${CMAKE_CURRENT_SOURCE_DIR}/${TST_QML_FILE}
691+ COMMAND ${COMMAND_PREFIX} ${QMLTESTRUNNER_BIN} -import ${imports_BINARY_DIR} -input ${CMAKE_CURRENT_SOURCE_DIR}/${TST_QML_FILE}
692 )
693 endmacro()
694
695 if(QMLTESTRUNNER_BIN AND XVFB_RUN_BIN)
696 declare_qml_test("contact_editor" tst_ContactEditor.qml)
697 declare_qml_test("contact_avatar" tst_ContactAvatar.qml)
698+ declare_qml_test("list_with_actions" tst_ListWithActions.qml)
699 else()
700 if (NOT QMLTESTRUNNER_BIN)
701 message(WARNING "Qml tests disabled: qmltestrunner not found")
702@@ -30,5 +36,6 @@
703 ContactUtil.js
704 tst_ContactEditor.qml
705 tst_ContactAvatar.qml
706+ tst_ListWithActions.qml
707 )
708 add_custom_target(tst_QmlFiles ALL SOURCES ${QML_TST_FILES})
709
710=== added file 'tests/qml/tst_ListWithActions.qml'
711--- tests/qml/tst_ListWithActions.qml 1970-01-01 00:00:00 +0000
712+++ tests/qml/tst_ListWithActions.qml 2014-07-23 23:51:06 +0000
713@@ -0,0 +1,281 @@
714+/*
715+ * Copyright (C) 2014 Canonical, Ltd.
716+ *
717+ * This program is free software; you can redistribute it and/or modify
718+ * it under the terms of the GNU General Public License as published by
719+ * the Free Software Foundation; version 3.
720+ *
721+ * This program is distributed in the hope that it will be useful,
722+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
723+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
724+ * GNU General Public License for more details.
725+ *
726+ * You should have received a copy of the GNU General Public License
727+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
728+ */
729+
730+import QtQuick 2.2
731+import Ubuntu.Components 0.1
732+import QtTest 1.0
733+import Ubuntu.Test 0.1
734+import Ubuntu.Contacts 0.1
735+
736+Item {
737+ id: root
738+
739+ property var itemList: null
740+
741+ width: units.gu(40)
742+ height: units.gu(80)
743+
744+ Component {
745+ id: itemListComponent
746+
747+ Column {
748+ id: itemList
749+
750+ readonly property int rightActionsLength: 3
751+
752+ signal actionTriggered(var action)
753+
754+ property var signalSpy: SignalSpy {
755+ target: itemList
756+ signalName: "actionTriggered"
757+ }
758+
759+ anchors.fill: parent
760+
761+ Repeater {
762+ model: 5
763+
764+ ListItemWithActions {
765+ id: listWithActions
766+ objectName: "listWithActions" + index
767+
768+ anchors {
769+ left: parent.left
770+ right: parent.right
771+ }
772+ height: units.gu(8)
773+ triggerActionOnMouseRelease: true
774+ Rectangle {
775+ anchors.fill: parent
776+ color: "blue"
777+ }
778+
779+ leftSideAction: Action {
780+ id: deleteAction
781+ objectName: "deleteAction"
782+
783+ iconName: "delete"
784+ onTriggered: itemList.actionTriggered(deleteAction, value)
785+ }
786+
787+ rightSideActions: [
788+ Action {
789+ id: messageAction
790+
791+ iconName: "message"
792+ onTriggered: itemList.actionTriggered(messageAction)
793+ },
794+ Action {
795+ id: shareAction
796+
797+ iconName: "share"
798+ onTriggered: itemList.actionTriggered(shareAction)
799+ },
800+ Action {
801+ id: contactAction
802+
803+ iconName: "stock_contact"
804+ onTriggered: itemList.actionTriggered(contactAction)
805+ }
806+ ]
807+ }
808+ }
809+
810+ Repeater {
811+ model: 5
812+
813+ ListItemWithActions {
814+ id: listWithNoRightActions
815+ objectName: "listWithNoRightActions" + index
816+
817+ anchors {
818+ left: parent.left
819+ right: parent.right
820+ }
821+ height: units.gu(8)
822+ triggerActionOnMouseRelease: true
823+ Rectangle {
824+ anchors.fill: parent
825+ color: "blue"
826+ }
827+
828+ leftSideAction: Action {
829+ objectName: "deleteAction2"
830+
831+ iconName: "delete"
832+ onTriggered: itemList.actionTriggered(deleteAction, value)
833+ }
834+ }
835+ }
836+ }
837+ }
838+
839+ UbuntuTestCase {
840+ id: listWithActionsTestCase
841+ name: 'listWithActionsTestCase'
842+
843+ when: windowShown
844+
845+ function init()
846+ {
847+ itemList = itemListComponent.createObject(root)
848+ }
849+
850+ function cleanup()
851+ {
852+ itemList.destroy()
853+ }
854+
855+ function mouseMoveSlowly(item, x, y, dx, dy, steps, stepdelay) {
856+ mouseMove(item, x, y);
857+ var abs_dx = Math.abs(dx)
858+ var abs_dy = Math.abs(dy)
859+ var step_dx = dx / steps;
860+ var step_dy = dy /steps;
861+
862+ var ix = 0;
863+ var iy = 0;
864+
865+ for (var step=0; step < steps; step++) {
866+ if (ix < abs_dx) {
867+ ix += step_dx;
868+ }
869+ if (iy < abs_dy) {
870+ iy += step_dy;
871+ }
872+ mouseMove(item, x + ix, y + iy, stepdelay);
873+ }
874+ }
875+
876+
877+ function swipeToDeleteItem(itemName)
878+ {
879+ var item = findChild(itemList, itemName)
880+ var startX = item.threshold
881+ var startY = item.height / 2
882+ var endX = item.width
883+ var endY = startY
884+ mousePress(item, startX, startY)
885+ mouseMoveSlowly(item,
886+ startX, startY,
887+ endX - startX, endY - startY,
888+ 10, 100)
889+ mouseRelease(item, endX, endY)
890+ tryCompare(item, "swipeState", "LeftToRight")
891+ return item
892+ }
893+
894+ function swipeToLeft(itemName, actionIndex, release)
895+ {
896+ var item = findChild(itemList, itemName)
897+ var startX = item.width - item.threshold
898+ var startY = item.height / 2
899+ var endX = 0
900+ var endY = startY
901+
902+ if (actionIndex !== -1)
903+ endX = startX - ((actionIndex * (item.actionWidth + units.gu(2))) + item.actionThreshold + units.gu(1))
904+ else
905+ endX = 0
906+
907+ mousePress(item, startX, startY)
908+ mouseMoveSlowly(item,
909+ startX, startY,
910+ endX - startX, endY - startY,
911+ 10, 100)
912+ if (release)
913+ mouseRelease(item, endX, endY)
914+
915+ tryCompare(item, "swipeState", "RightToLeft")
916+ return item
917+ }
918+
919+ function commom_data()
920+ {
921+ var data = []
922+ data.push({actionIndex: 1, iconName: "message"})
923+ data.push({actionIndex: 2, iconName: "share"})
924+ data.push({actionIndex: 3, iconName: "stock_contact"})
925+ return data
926+ }
927+
928+ function test_cancelSwipeToDelete()
929+ {
930+ var item = swipeToDeleteItem("listWithActions2")
931+ mouseClick(item, item.width / 2, item.height / 2)
932+ compare(itemList.signalSpy.count, 0)
933+ }
934+
935+ function test_swipeToDelete()
936+ {
937+ var item = swipeToDeleteItem("listWithActions2")
938+ mouseClick(item, item.actionThreshold, item.height / 2)
939+ itemList.signalSpy.wait()
940+ compare(itemList.signalSpy.count, 1)
941+ compare(itemList.signalSpy.signalArguments[0][0].iconName, "delete")
942+ }
943+
944+ function test_activeRightActions_data()
945+ {
946+ return commom_data()
947+ }
948+
949+ function test_activeRightActions(data)
950+ {
951+ var item = swipeToLeft("listWithActions2", data.actionIndex, false)
952+ compare(itemList.signalSpy.count, 0)
953+ compare(item.activeAction.iconName, data.iconName)
954+ mouseRelease(item, 0, 0)
955+ itemList.signalSpy.wait()
956+ compare(itemList.signalSpy.count, 1)
957+ compare(itemList.signalSpy.signalArguments[0][0].iconName, data.iconName)
958+ }
959+
960+ function test_lockOnFullSwipe()
961+ {
962+ var item = swipeToLeft("listWithActions2", -1, true)
963+ compare(itemList.signalSpy.count, 0)
964+ tryCompare(item, "swipeState", "RightToLeft")
965+ }
966+
967+ function test_fullSwipeAndClickOnAction_data()
968+ {
969+ return commom_data()
970+ }
971+
972+ function test_fullSwipeAndClickOnAction(data)
973+ {
974+ var item = swipeToLeft("listWithActions2", -1, true)
975+ var actionOffset = (itemList.rightActionsLength - data.actionIndex) + 1
976+ var clickX = item.width - ((actionOffset * (item.actionWidth + units.gu(2))) + item.actionWidth / 2)
977+ mouseClick(item, clickX, item.height / 2)
978+ itemList.signalSpy.wait()
979+ compare(itemList.signalSpy.count, 1)
980+ compare(itemList.signalSpy.signalArguments[0][0].iconName, data.iconName)
981+ }
982+
983+ function test_noSwipeWithEmptyRightActions()
984+ {
985+ var item = findChild(itemList, "listWithNoRightActions2")
986+ var startX = item.width - item.threshold
987+ var y = item.height / 2
988+ mousePress(item, startX, y)
989+ mouseMoveSlowly(item, startX, y, -startX, y, 10, 100)
990+ var mainItem = findChild(item, "mainItem")
991+ compare(mainItem.x, 0)
992+ }
993+ }
994+}

Subscribers

People subscribed via source and target branches