Merge lp:~renatofilho/dialer-app/swipe-item-demo into lp:dialer-app

Proposed by Renato Araujo Oliveira Filho on 2015-02-26
Status: Merged
Approved by: Gustavo Pichorim Boiko on 2015-05-07
Approved revision: 385
Merged at revision: 402
Proposed branch: lp:~renatofilho/dialer-app/swipe-item-demo
Merge into: lp:dialer-app
Diff against target: 552 lines (+485/-1)
5 files modified
src/qml/HistoryPage/HistoryPage.qml (+16/-0)
src/qml/HistoryPage/SwipeItemDemo.qml (+397/-0)
src/qml/assets/swipe_arrow.svg (+17/-0)
tests/autopilot/dialer_app/tests/__init__.py (+23/-1)
tests/autopilot/dialer_app/tests/test_logs.py (+32/-0)
To merge this branch: bzr merge lp:~renatofilho/dialer-app/swipe-item-demo
Reviewer Review Type Date Requested Status
Gustavo Pichorim Boiko (community) 2015-02-26 Approve on 2015-05-07
PS Jenkins bot continuous-integration Needs Fixing on 2015-05-07
Review via email: mp+251085@code.launchpad.net

Commit Message

Create a swipe item demo. To demonstrate how to swipe items to revel actions.

Description of the Change

To post a comment you must log in.
374. By Renato Araujo Oliveira Filho on 2015-02-26

Show a fake missed call on Swipe demo.
Only shows the demo if the list is populated.

375. By Renato Araujo Oliveira Filho on 2015-04-27

Trunk merged.

376. By Renato Araujo Oliveira Filho on 2015-04-28

Updated visuals.

377. By Renato Araujo Oliveira Filho on 2015-04-28

Update visuals.

378. By Renato Araujo Oliveira Filho on 2015-04-29

Disable click outside the ok button while the swipe item demo is running.

379. By Renato Araujo Oliveira Filho on 2015-04-29

Added missing svg file.

380. By Renato Araujo Oliveira Filho on 2015-04-29

Created auto pilot tests.

Gustavo Pichorim Boiko (boiko) wrote :

I think it would be a good idea to have the view fading in when appearing and fading out when dismissing.

review: Needs Fixing
381. By Renato Araujo Oliveira Filho on 2015-05-01

Created animations for the tutorial appear and desapear

382. By Renato Araujo Oliveira Filho on 2015-05-01

Added a fade out in the texts.

Are there any related MPs required for this MP to build/function as expected?
 - lp:~renatofilho/address-book-app/list-with-actions-animated

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 UI labels, did you update the pot file?
 NO, Will be updated in a diff MR

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

Gustavo Pichorim Boiko (boiko) wrote :

If I open the recents view without having any item on it, and then I receive a call (no need to answer the call, just let it show as missed), the demo is not displayed.

Can you fix that?

review: Needs Fixing
383. By Renato Araujo Oliveira Filho on 2015-05-06

Show swipe demo if receive a call while the recents is open.

384. By Renato Araujo Oliveira Filho on 2015-05-07

Fix autopilot.

385. By Renato Araujo Oliveira Filho on 2015-05-07

Trunk merged.

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.
No, but not related to the changes.

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

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/qml/HistoryPage/HistoryPage.qml'
2--- src/qml/HistoryPage/HistoryPage.qml 2015-04-09 19:55:20 +0000
3+++ src/qml/HistoryPage/HistoryPage.qml 2015-05-07 13:03:26 +0000
4@@ -94,6 +94,8 @@
5 }
6 historyList.resetSwipe()
7 historyList.positionViewAtBeginning()
8+ } else if (historyList.count > 0){
9+ swipeItemDemo.enable()
10 }
11 }
12
13@@ -354,10 +356,24 @@
14 ]
15 }
16 }
17+
18+ onCountChanged: {
19+ if (historyPage.active && (historyList.count > 0)) {
20+ swipeItemDemo.enable()
21+ }
22+ }
23 }
24
25 Scrollbar {
26 flickableItem: historyList
27 align: Qt.AlignTrailing
28 }
29+
30+ SwipeItemDemo {
31+ id: swipeItemDemo
32+ objectName: "swipeItemDemo"
33+
34+ parent: QuickUtils.rootItem(this)
35+ anchors.fill: parent
36+ }
37 }
38
39=== added file 'src/qml/HistoryPage/SwipeItemDemo.qml'
40--- src/qml/HistoryPage/SwipeItemDemo.qml 1970-01-01 00:00:00 +0000
41+++ src/qml/HistoryPage/SwipeItemDemo.qml 2015-05-07 13:03:26 +0000
42@@ -0,0 +1,397 @@
43+/*
44+ * Copyright 2012-2015 Canonical Ltd.
45+ *
46+ * This file is part of dialer-app.
47+ *
48+ * dialer-app is free software; you can redistribute it and/or modify
49+ * it under the terms of the GNU General Public License as published by
50+ * the Free Software Foundation; version 3.
51+ *
52+ * dialer-app is distributed in the hope that it will be useful,
53+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
54+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55+ * GNU General Public License for more details.
56+ *
57+ * You should have received a copy of the GNU General Public License
58+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
59+ */
60+
61+import QtQuick 2.0
62+import QtQuick.Layouts 1.1
63+import Qt.labs.settings 1.0
64+
65+import Ubuntu.Components 1.1
66+import Ubuntu.Contacts 0.1
67+
68+Loader {
69+ id: root
70+
71+ property bool necessary: true
72+ property bool enabled: false
73+
74+
75+ function enable() {
76+ root.enabled = true;
77+ }
78+
79+ function disable() {
80+ if (root.enabled) {
81+ root.necessary = false;
82+ root.enabled = false;
83+ }
84+ }
85+
86+ sourceComponent: necessary && enabled ? listItemDemoComponent : null
87+
88+ Settings {
89+ property alias hintNecessary: root.necessary
90+ }
91+
92+ Component {
93+ id: listItemDemoComponent
94+
95+ Rectangle {
96+ id: rectangleContents
97+
98+ color: "black"
99+ opacity: 0
100+ anchors.fill: parent
101+
102+ Behavior on opacity {
103+ UbuntuNumberAnimation {
104+ duration: UbuntuAnimation.SlowDuration
105+ }
106+ }
107+
108+ ListItemWithActions {
109+ id: listItem
110+
111+ property int xPos: 0
112+
113+ animated: false
114+ onXPosChanged: listItem.updatePosition(xPos)
115+
116+ anchors {
117+ top: parent.top
118+ topMargin: units.gu(14)
119+ left: parent.left
120+ right: parent.right
121+ }
122+ height: units.gu(8)
123+
124+ color: Theme.palette.normal.background
125+ leftSideAction: Action {
126+ iconName: "delete"
127+ }
128+ rightSideActions: [
129+ Action {
130+ iconName: "info"
131+ },
132+ Action {
133+ iconName: "message"
134+ },
135+ Action {
136+ iconName: "stock_contact"
137+ }
138+ ]
139+
140+ ContactAvatar {
141+ id: avatar
142+ anchors {
143+ left: parent.left
144+ top: parent.top
145+ bottom: parent.bottom
146+ }
147+ width: height
148+ fallbackAvatarUrl: "image://theme/stock_contact"
149+ fallbackDisplayName: "Ubuntu phone"
150+ showAvatarPicture: true
151+ }
152+
153+ Label {
154+ id: titleLabel
155+ anchors {
156+ top: parent.top
157+ topMargin: units.gu(0.5)
158+ left: avatar.right
159+ leftMargin: units.gu(2)
160+ right: time.left
161+ rightMargin: units.gu(1) + (countLabel.visible ? countLabel.width : 0)
162+ }
163+ height: units.gu(2)
164+ verticalAlignment: Text.AlignTop
165+ fontSize: "medium"
166+ text: "(541) 754-3010"
167+ elide: Text.ElideRight
168+ color: UbuntuColors.lightAubergine
169+ }
170+
171+ // this item has the width of the text above. It is used to be able to align
172+ Item {
173+ id: titleLabelArea
174+ anchors {
175+ top: titleLabel.top
176+ left: titleLabel.left
177+ bottom: titleLabel.bottom
178+ }
179+ width: titleLabel.paintedWidth
180+ }
181+
182+ Label {
183+ id: countLabel
184+ anchors {
185+ left: titleLabelArea.right
186+ leftMargin: units.gu(0.5)
187+ top: titleLabel.top
188+ }
189+ height: units.gu(2)
190+ fontSize: "medium"
191+ // TRANSLATORS: this is the count of events grouped into this single item
192+ text: i18n.tr("(%1)").arg(2)
193+ }
194+
195+ Label {
196+ id: phoneLabel
197+ anchors {
198+ top: titleLabel.bottom
199+ topMargin: units.gu(1)
200+ left: avatar.right
201+ leftMargin: units.gu(2)
202+ }
203+ height: units.gu(2)
204+ verticalAlignment: Text.AlignTop
205+ fontSize: "small"
206+ text: i18n.tr("Mobile")
207+ }
208+
209+ // time and duration on the right side of the delegate
210+ Label {
211+ id: time
212+ anchors {
213+ right: parent.right
214+ bottom: titleLabel.bottom
215+ }
216+ height: units.gu(2)
217+ verticalAlignment: Text.AlignBottom
218+ fontSize: "small"
219+ text: Qt.formatTime( new Date(), Qt.DefaultLocaleShortDate)
220+ }
221+
222+ Label {
223+ id: callType
224+ anchors {
225+ right: parent.right
226+ bottom: phoneLabel.bottom
227+ }
228+ height: units.gu(2)
229+ verticalAlignment: Text.AlignBottom
230+ fontSize: "small"
231+ text: i18n.tr("Incoming")
232+ }
233+ }
234+
235+ RowLayout {
236+ id: dragTitle
237+
238+ anchors {
239+ left: parent.left
240+ right: parent.right
241+ top: listItem.bottom
242+ margins: units.gu(1)
243+ //topMargin: units.gu(1)
244+ }
245+ height: units.gu(3)
246+ spacing: units.gu(2)
247+
248+ Image {
249+ visible: listItem.swipeState === "RightToLeft"
250+ source: Qt.resolvedUrl("../assets/swipe_arrow.svg")
251+ rotation: 180
252+ Layout.preferredWidth: sourceSize.width
253+ height: parent.height
254+ verticalAlignment: Image.AlignVCenter
255+ fillMode: Image.Pad
256+ sourceSize {
257+ width: units.gu(7)
258+ height: units.gu(2)
259+ }
260+ }
261+
262+ Label {
263+ id: dragMessage
264+
265+ Layout.fillWidth: true
266+ height: parent.height
267+ verticalAlignment: Image.AlignVCenter
268+ wrapMode: Text.Wrap
269+ fontSize: "large"
270+ color: "#ffffff"
271+ }
272+
273+ Image {
274+ visible: listItem.swipeState === "LeftToRight"
275+ source: Qt.resolvedUrl("../assets/swipe_arrow.svg")
276+ Layout.preferredWidth: sourceSize.width
277+ height: parent.height
278+ verticalAlignment: Image.AlignVCenter
279+ fillMode: Image.Pad
280+ sourceSize {
281+ width: units.gu(7)
282+ height: units.gu(2)
283+ }
284+ }
285+ }
286+
287+ Button {
288+ objectName: "gotItButton"
289+
290+ anchors {
291+ bottom: parent.bottom
292+ horizontalCenter: parent.horizontalCenter
293+ bottomMargin: units.gu(9)
294+ }
295+ width: units.gu(17)
296+ strokeColor: UbuntuColors.green
297+ text: i18n.tr("Got it")
298+ enabled: !dismissAnimation.running
299+ onClicked: dismissAnimation.start()
300+ InverseMouseArea {
301+ anchors.fill: parent
302+ topmostItem: true
303+ }
304+ }
305+
306+ SequentialAnimation {
307+ id: slideAnimation
308+
309+ readonly property real leftToRightXpos: (-3 * (listItem.actionWidth + units.gu(2)))
310+ readonly property real rightToLeftXpos: listItem.leftActionWidth
311+
312+ loops: Animation.Infinite
313+ running: root.enabled
314+
315+ PropertyAction {
316+ target: dragMessage
317+ property: "text"
318+ value: i18n.tr("Swipe to reveal actions")
319+ }
320+
321+ PropertyAction {
322+ target: dragMessage
323+ property: "horizontalAlignment"
324+ value: Text.AlignLeft
325+ }
326+
327+ ParallelAnimation {
328+ PropertyAnimation {
329+ target: listItem
330+ property: "xPos"
331+ from: 0
332+ to: slideAnimation.leftToRightXpos
333+ duration: 2000
334+ }
335+ PropertyAnimation {
336+ target: dragTitle
337+ property: "opacity"
338+ from: 0
339+ to: 1
340+ duration: UbuntuAnimation.SleepyDuration
341+ }
342+ }
343+
344+ PauseAnimation {
345+ duration: UbuntuAnimation.SleepyDuration
346+ }
347+
348+ ParallelAnimation {
349+ PropertyAnimation {
350+ target: dragTitle
351+ property: "opacity"
352+ to: 0
353+ duration: UbuntuAnimation.SlowDuration
354+ }
355+
356+ PropertyAnimation {
357+ target: listItem
358+ property: "xPos"
359+ from: slideAnimation.leftToRightXpos
360+ to: 0
361+ duration: UbuntuAnimation.SleepyDuration
362+ }
363+ }
364+
365+ PropertyAction {
366+ target: dragMessage
367+ property: "text"
368+ value: i18n.tr("Swipe to delete")
369+ }
370+
371+ PropertyAction {
372+ target: dragMessage
373+ property: "horizontalAlignment"
374+ value: Text.AlignRight
375+ }
376+
377+ ParallelAnimation {
378+ PropertyAnimation {
379+ target: listItem
380+ property: "xPos"
381+ from: 0
382+ to: slideAnimation.rightToLeftXpos
383+ duration: UbuntuAnimation.SleepyDuration
384+ }
385+ PropertyAnimation {
386+ target: dragTitle
387+ property: "opacity"
388+ from: 0
389+ to: 1
390+ duration: UbuntuAnimation.SlowDuration
391+ }
392+ }
393+
394+ PauseAnimation {
395+ duration: UbuntuAnimation.SleepyDuration
396+ }
397+
398+ ParallelAnimation {
399+ PropertyAnimation {
400+ target: dragTitle
401+ property: "opacity"
402+ to: 0
403+ duration: UbuntuAnimation.SlowDuration
404+ }
405+
406+ PropertyAnimation {
407+ target: listItem
408+ property: "xPos"
409+ from: slideAnimation.rightToLeftXpos
410+ to: 0
411+ duration: UbuntuAnimation.SleepyDuration
412+ }
413+ }
414+ }
415+
416+ SequentialAnimation {
417+ id: dismissAnimation
418+
419+ alwaysRunToEnd: true
420+ running: false
421+
422+ UbuntuNumberAnimation {
423+ target: rectangleContents
424+ property: "opacity"
425+ to: 0.0
426+ duration: UbuntuAnimation.SlowDuration
427+ }
428+
429+ ScriptAction {
430+ script: root.disable()
431+ }
432+ }
433+
434+ Component.onCompleted: {
435+ opacity = 0.85
436+ }
437+ }
438+ }
439+}
440
441=== added file 'src/qml/assets/swipe_arrow.svg'
442--- src/qml/assets/swipe_arrow.svg 1970-01-01 00:00:00 +0000
443+++ src/qml/assets/swipe_arrow.svg 2015-05-07 13:03:26 +0000
444@@ -0,0 +1,17 @@
445+<?xml version="1.0" encoding="utf-8"?>
446+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
447+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
448+ viewBox="0 0 96.6 36.7" enable-background="new 0 0 96.6 36.7" xml:space="preserve">
449+<g>
450+
451+ <path id="path2194-5_2_" inkscape:connector-curvature="0" sodipodi:nodetypes="ccsssccc" inkscape:transform-center-x="-0.02188882" inkscape:transform-center-y="-31.980969" fill="#DC4B26" d="
452+ M96,18.7c-10.5-7.3-21.3-12-21.3-12l0,24"/>
453+ <circle id="circle4146" fill="#DC4B26" cx="69.2" cy="18.3" r="2.4"/>
454+ <circle id="circle4148" fill="#DC4B26" cx="58.5" cy="18.3" r="2.4"/>
455+ <circle id="circle4150" fill="#DC4B26" cx="47.8" cy="18.3" r="2.4"/>
456+ <circle id="circle4152" fill="#DC4B26" cx="37.1" cy="18.3" r="2.4"/>
457+ <circle id="circle4154" fill="#DC4B26" cx="26.4" cy="18.3" r="2.4"/>
458+ <circle id="circle4156" fill="#DC4B26" cx="15.7" cy="18.3" r="2.4"/>
459+</g>
460+<circle id="circle4156_1_" fill="#DC4B26" cx="4.9" cy="18.3" r="2.4"/>
461+</svg>
462
463=== modified file 'tests/autopilot/dialer_app/tests/__init__.py'
464--- tests/autopilot/dialer_app/tests/__init__.py 2014-08-13 18:08:11 +0000
465+++ tests/autopilot/dialer_app/tests/__init__.py 2015-05-07 13:03:26 +0000
466@@ -11,6 +11,7 @@
467
468 import logging
469 import os
470+import tempfile
471
472 import fixtures
473 import ubuntuuitoolkit
474@@ -40,9 +41,10 @@
475 LOCAL_BINARY_PATH = 'src/dialer-app'
476 # The path to the locally built binary, relative to the build directory.
477
478- def setUp(self):
479+ def setUp(self, firstLaunch=False):
480 super().setUp()
481 self.set_up_locale()
482+ self.create_config_file(firstLaunch)
483 self.launch_application()
484
485 self.assertThat(self.main_view.visible, Eventually(Equals(True)))
486@@ -78,6 +80,26 @@
487 emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase
488 )
489
490+ def create_config_file(self, firstLaunch=False):
491+ self.user_config_dir = tempfile.mkdtemp(suffix='', prefix='dialer-app')
492+ self.app_config_dir = (self.user_config_dir + '/com.ubuntu.dialer-app/')
493+ os.makedirs(self.app_config_dir)
494+ config_file_path = (self.app_config_dir + '/DialerApp.conf')
495+
496+ if firstLaunch:
497+ first_launch_flag = 'true'
498+ else:
499+ first_launch_flag = 'false'
500+ with open(config_file_path, 'w') as config_file:
501+ config_file.write('[General]\nhintNecessary=%s\n' % (first_launch_flag))
502+
503+ self.useFixture(
504+ fixtures.EnvironmentVariable('XDG_CONFIG_HOME', newvalue=self.user_config_dir)
505+ )
506+ self.useFixture(
507+ fixture_setup.InitctlEnvironmentVariable(XDG_CONFIG_HOME=self.user_config_dir)
508+ )
509+
510 @property
511 def main_view(self):
512 return self.app.wait_select_single(dialer_app.MainView)
513
514=== modified file 'tests/autopilot/dialer_app/tests/test_logs.py'
515--- tests/autopilot/dialer_app/tests/test_logs.py 2015-04-15 17:31:01 +0000
516+++ tests/autopilot/dialer_app/tests/test_logs.py 2015-05-07 13:03:26 +0000
517@@ -79,3 +79,35 @@
518 Eventually(Equals(
519 'addressbook:///addnewphone?callback=dialer-app.desktop&'
520 'phone=800')))
521+
522+
523+class TestSwipeItemTutorial(DialerAppTestCase):
524+ """Tests for swipe item tutorial."""
525+
526+ def setUp(self):
527+ # set the fixtures before launching the app
528+ testability_environment = fixture_setup.TestabilityEnvironment()
529+ self.useFixture(testability_environment)
530+ fill_history = fixture_setup.FillCustomHistory()
531+ self.useFixture(fill_history)
532+
533+ # now launch the app
534+ super().setUp(firstLaunch=True)
535+ self.main_view.dialer_page.reveal_bottom_edge_page()
536+
537+ def _get_main_view(self, proxy_object):
538+ return proxy_object.wait_select_single('QQuickView')
539+
540+ def test_swipe_item_tutorial_appears(self):
541+ """Ensure that the swipe item tutorial appears on first launch"""
542+ swipe_item_demo = self.main_view.wait_select_single(
543+ 'SwipeItemDemo', objectName='swipeItemDemo')
544+
545+ self.assertThat(swipe_item_demo.enabled, Eventually(Equals(True)))
546+ self.assertThat(swipe_item_demo.necessary, Eventually(Equals(True)))
547+ got_it_button = swipe_item_demo.select_single(
548+ 'Button',
549+ objectName='gotItButton')
550+ self.main_view._click_button(got_it_button)
551+ self.assertThat(swipe_item_demo.enabled, Eventually(Equals(False)))
552+ self.assertThat(swipe_item_demo.necessary, Eventually(Equals(False)))

Subscribers

People subscribed via source and target branches