Merge lp:~tpeeters/ubuntu-ui-toolkit/panel-hideTimer into lp:ubuntu-ui-toolkit

Proposed by Tim Peeters
Status: Merged
Approved by: Cris Dywan
Approved revision: 892
Merged at revision: 879
Proposed branch: lp:~tpeeters/ubuntu-ui-toolkit/panel-hideTimer
Merge into: lp:ubuntu-ui-toolkit
Diff against target: 305 lines (+104/-36)
6 files modified
CHANGES (+1/-0)
components.api (+1/-0)
modules/Ubuntu/Components/Panel.qml (+54/-6)
modules/Ubuntu/Components/Toolbar.qml (+1/-22)
tests/unit_x11/tst_components/tst_panel.qml (+33/-7)
tests/unit_x11/tst_components/tst_toolbar.qml (+14/-1)
To merge this branch: bzr merge lp:~tpeeters/ubuntu-ui-toolkit/panel-hideTimer
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Cris Dywan Approve
Review via email: mp+197442@code.launchpad.net

Commit message

Reset hide timer when user interacts with toolbar or toolbar buttons.

Description of the change

Move the hide timer from Toolbar to Panel, trigger it when open() is called, and restart it on user interaction.

The timer was moved because open() is defined in Panel, and user interaction (pressing and releasing on top of the panel) are dealt with in Panel, not Toolbar, and open() and user interactions need to reset the timer. To keep backwards UX compatibility for Panel, the default hideTimeout was set to -1 ==> no timer.

To post a comment you must log in.
887. By Tim Peeters

fix conditional restart

888. By Tim Peeters

clean

889. By Tim Peeters

update panel unit tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

Tested gallery-app and webbrowser-app on maguro, and executed ubuntuuitoolkit AP tests on same device. All good.

Revision history for this message
Tim Peeters (tpeeters) wrote :

Webbrowser AP tests also pass on device

Revision history for this message
Cris Dywan (kalikiana) wrote :

What's the motivation behind these numbers? "wait(3*panel.hideTimeout/4);"

review: Needs Information
890. By Tim Peeters

improved test and explained it better

891. By Tim Peeters

improve toolbar tests

Revision history for this message
Tim Peeters (tpeeters) wrote :

> What's the motivation behind these numbers? "wait(3*panel.hideTimeout/4);"

I simplified it to *0.6, and added explanation in the code.
Basically, in total you want to wait > 1.0*hideTimeout, but with user interaction inbetween, so you wait twice < hideTimeout, and you check that because of the user interaction the toolbar/panel is not closed.

Revision history for this message
Cris Dywan (kalikiana) wrote :

That makes sense. I guessed it would be something like that but it's good to be clear so everyone doesn't have to ponder what it does. Thanks for adding the explanations.

> + compare(panel.opened, false, "Toolbar automatically closes after timeout");
s/Toolbar/Panel
> + the panel frmo detecting interaction and the timer will not be reset.
s/frmo/from

review: Needs Fixing
892. By Tim Peeters

fix typos

Revision history for this message
Cris Dywan (kalikiana) wrote :

Nice!

review: Approve
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) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CHANGES'
2--- CHANGES 2013-11-28 15:07:31 +0000
3+++ CHANGES 2013-12-03 18:38:40 +0000
4@@ -79,6 +79,7 @@
5 * CHANGED IN Header: property Component contents TO property Item contents
6 * ADDED IN Panel: function open()
7 * ADDED IN Panel: function close()
8+* ADDED IN Panel: property int hideTimeout
9 * DEPRECATED IN Panel: writable property opened. Will be made read-only.
10 * ADDED IN: Empty: property bool waitingConfirmationForRemoval
11 * ADDED IN: Empty: function cancelItemRemoval()
12
13=== modified file 'components.api'
14--- components.api 2013-12-02 19:14:03 +0000
15+++ components.api 2013-12-03 18:38:40 +0000
16@@ -234,6 +234,7 @@
17 property bool opened
18 function open()
19 function close()
20+ property int hideTimeout
21 property bool locked
22 property real hintSize
23 property real triggerSize
24
25=== modified file 'modules/Ubuntu/Components/Panel.qml'
26--- modules/Ubuntu/Components/Panel.qml 2013-11-27 14:54:05 +0000
27+++ modules/Ubuntu/Components/Panel.qml 2013-12-03 18:38:40 +0000
28@@ -103,8 +103,7 @@
29 Any Items can be placed inside the Panel, but MouseAreas can block mouse events from reaching
30 the panel and thus obstruct the swiping behavior for hiding the panel. As a result, the user cannot
31 start swiping on the buttons in the examples above in order to hide the panel. To remedy this, clicked()
32- signals are forwarded from the panel to its children. The children's clicked() signal does not have
33- a mouse parameter. Example:
34+ signals are forwarded from the panel by calling the child's trigger() function. Example:
35 \qml
36 import QtQuick 2.0
37 import Ubuntu.Components 0.1
38@@ -130,15 +129,17 @@
39 width: units.gu(8)
40 height: units.gu(4)
41 anchors.centerIn: parent
42- color: Theme.palette.normal.foreground
43- signal clicked()
44- onClicked: print("The red rectangle was clicked");
45+ color: "red"
46+ function trigger() {
47+ print("The red rectangle was clicked");
48+ }
49 }
50 }
51 }
52+ Component.onCompleted: panel.open();
53 }
54 \endqml
55- Like this, the red rectangle accepts clicked() events, but the user can still swipe down on top
56+ Like this, the red rectangle accepts click events, but the user can still swipe down on top
57 of the rectangle in order to hide the panel.
58 */
59 Item {
60@@ -208,6 +209,7 @@
61 // FIXME: When opened is made readonly, openedChangedWarning must be removed
62 internal.openedChangedWarning = false;
63 panel.state = "spread";
64+ hideTimer.conditionalRestart();
65 }
66
67 /*!
68@@ -217,9 +219,21 @@
69 // FIXME: When opened is made readonly, openedChangedWarning must be removed.
70 internal.openedChangedWarning = false;
71 panel.state = "";
72+ hideTimer.stop();
73 }
74
75 /*!
76+ The time in milliseconds before the panel automatically hides after inactivity
77+ when it is not locked. Interacting with the panel resets the timer.
78+ Note that adding contents to the panel that accepts mouse events will prevent
79+ the panel from detecting interaction and the timer will not be reset.
80+ Setting a negative value will disable automatic hiding.
81+ Default value: -1 (automatic hiding is disabled).
82+ \qmlproperty int hideTimeout
83+ */
84+ property alias hideTimeout: hideTimer.interval
85+
86+ /*!
87 Disable edge swipe to open/close the panel. False by default.
88 */
89 property bool locked: false
90@@ -228,6 +242,35 @@
91 if (state == "hint" || state == "moving") {
92 draggingArea.finishMoving();
93 }
94+ if (!hideTimer.conditionalRestart()) {
95+ hideTimer.stop();
96+ }
97+ }
98+
99+ Timer {
100+ id: hideTimer
101+ interval: -1
102+ running: panel.opened && !panel.locked && interval >= 0
103+
104+ function conditionalRestart() {
105+ if (hideTimer.interval >= 0) {
106+ if (!panel.locked && panel.opened) {
107+ hideTimer.restart();
108+ return true;
109+ }
110+ }
111+ return false;
112+ }
113+ onIntervalChanged: {
114+ if (!conditionalRestart()) {
115+ hideTimer.stop();
116+ }
117+ }
118+ onTriggered: {
119+ if (!panel.locked) {
120+ panel.close();
121+ }
122+ }
123 }
124
125 /*!
126@@ -485,6 +528,7 @@
127
128 property int initialPosition
129 onPressed: {
130+ hideTimer.stop();
131 pressedItem = getTriggerableItem(mouse);
132 if (panel.locked) return;
133 initialPosition = getMousePosition();
134@@ -514,12 +558,16 @@
135 onReleased: {
136 if (panel.state == "moving" || panel.state == "hint") {
137 finishMoving();
138+ } else {
139+ hideTimer.conditionalRestart();
140 }
141 }
142 // Mouse cursor moving out of the window while pressed on desktop
143 onCanceled: {
144 if (panel.state == "moving" || panel.state == "hint") {
145 finishMoving();
146+ } else {
147+ hideTimer.conditionalRestart();
148 }
149 }
150
151
152=== modified file 'modules/Ubuntu/Components/Toolbar.qml'
153--- modules/Ubuntu/Components/Toolbar.qml 2013-11-08 18:38:25 +0000
154+++ modules/Ubuntu/Components/Toolbar.qml 2013-12-03 18:38:40 +0000
155@@ -42,12 +42,7 @@
156 */
157 property Item tools: null
158
159- /*!
160- \preliminary
161- The time in milliseconds before the toolbar automatically hides after inactivity
162- when it is not locked.
163- */
164- property int hideTimeout: 5000
165+ hideTimeout: 5000
166
167 /*! \internal */
168 onToolsChanged: {
169@@ -66,10 +61,6 @@
170 if (tools && tools.hasOwnProperty("opened")) {
171 tools.opened = toolbar.opened;
172 }
173-
174- if (!toolbar.locked) {
175- hideTimer.restart();
176- }
177 } else { // no tools
178 locked = true;
179 toolbar.close();
180@@ -79,22 +70,10 @@
181 // if tools is not specified, lock the toolbar in closed position
182 locked: tools && tools.hasOwnProperty("locked") ? tools.locked : false
183
184- Timer {
185- id: hideTimer
186- interval: toolbar.hideTimeout
187- running: toolbar.opened && !toolbar.locked
188- onTriggered: {
189- if (!toolbar.locked) {
190- toolbar.close();
191- }
192- }
193- }
194-
195 onOpenedChanged: {
196 if (tools && tools.hasOwnProperty("opened")) {
197 tools.opened = toolbar.opened;
198 }
199- if (!toolbar.locked) hideTimer.restart();
200 }
201
202 Connections {
203
204=== modified file 'tests/unit_x11/tst_components/tst_panel.qml'
205--- tests/unit_x11/tst_components/tst_panel.qml 2013-09-09 18:59:35 +0000
206+++ tests/unit_x11/tst_components/tst_panel.qml 2013-12-03 18:38:40 +0000
207@@ -31,6 +31,10 @@
208 right: parent.right
209 }
210 height: parent.height / 2
211+ Rectangle {
212+ color: "pink"
213+ anchors.fill: parent
214+ }
215 }
216
217 TestCase {
218@@ -162,6 +166,35 @@
219 panel.align = Qt.AlignBottom;
220 }
221
222+ function test_clickToDeactivate() {
223+ panel.open();
224+ compare(panel.opened && panel.align === Qt.AlignBottom, true, "Panel is opened and bottom-aligned");
225+ mouseClick(root, root.width / 2, 5, Qt.LeftButton);
226+ compare(panel.opened, false, "Panel is deactivated by clicking in the view outside of the panel");
227+ }
228+
229+ function test_hideTimeout_bug1249031() {
230+ compare(panel.hideTimeout, -1, "Panel hide timeout is initially negative (no timeout)");
231+ panel.hideTimeout = 2000;
232+ panel.open();
233+ compare(panel.opened, true, "Panel can be made opened");
234+ wait(panel.hideTimeout + 500); // add 500 ms margin
235+ compare(panel.opened, false, "Panel automatically closes after timeout");
236+
237+ // now, wait in total more than hideTimeout, but less than 2*hideTimeout,
238+ // and have user interaction half-way to verify that the interaction
239+ // resets the timer and the panel is not closed.
240+ panel.open();
241+ wait(0.6*panel.hideTimeout);
242+ mouseClick(panel, panel.width/2, panel.height/2);
243+ wait(0.6*panel.hideTimeout);
244+ compare(panel.opened, true, "Interacting with panel contents resets the hide timer");
245+ // verify that the timer is still running by waiting a bit longer:
246+ wait(0.6*panel.hideTimeout);
247+ compare(panel.opened, false, "Interacting with the panel contents does not stop the timer")
248+ panel.hideTimeout = -1;
249+ }
250+
251 QtObject {
252 id: swipeTests
253
254@@ -239,13 +272,6 @@
255 testCase.mouseRelease(panel, x - dx, y - dy, Qt.LeftButton);
256 testCase.compare(panel.opened, false, "Top-aligned panel deactivated by swiping up (delay: "+moveDelay+"");
257 }
258-
259- function test_clickToDeactivate() {
260- panel.open();
261- compare(panel.opened && panel.align === Qt.AlignBottom, true, "Panel is opened and bottom-aligned");
262- mouseClick(root, root.width / 2, 5, Qt.LeftButton);
263- compare(panel.opened, false, "Panel is deactivated by clicking in the view outside of the panel");
264- }
265 }
266 }
267 }
268
269=== modified file 'tests/unit_x11/tst_components/tst_toolbar.qml'
270--- tests/unit_x11/tst_components/tst_toolbar.qml 2013-11-08 18:32:39 +0000
271+++ tests/unit_x11/tst_components/tst_toolbar.qml 2013-12-03 18:38:40 +0000
272@@ -36,6 +36,7 @@
273 tools: ToolbarItems {
274 id: toolbarItems
275 ToolbarButton {
276+ id: toolbarButton
277 text: "action1"
278 }
279 }
280@@ -74,12 +75,24 @@
281 compare(mainView.__propagated.toolbar.opened, false, "Toolbar can be made closed by setting page.tools.opened to false");
282 }
283
284- function test_hideTimeout() {
285+ function test_hideTimeout_bug1249031() {
286 compare(mainView.__propagated.toolbar.hideTimeout, 5000, "Toolbar hide timeout is initially 5 seconds.");
287 mainView.__propagated.toolbar.open();
288 compare(mainView.__propagated.toolbar.opened, true, "Toolbar can be made opened");
289 wait(mainView.__propagated.toolbar.hideTimeout + 500); // add 500 ms margin
290 compare(mainView.__propagated.toolbar.opened, false, "Toolbar automatically closes after timeout");
291+
292+ // now, wait in total more than hideTimeout, but less than 2*hideTimeout,
293+ // and have user interaction half-way to verify that the interaction
294+ // resets the timer and the toolbar is not closed.
295+ mainView.__propagated.toolbar.open();
296+ wait(0.6*mainView.__propagated.toolbar.hideTimeout);
297+ mouseClick(toolbarButton, toolbarButton.width/2, toolbarButton.height/2);
298+ wait(0.6*mainView.__propagated.toolbar.hideTimeout);
299+ compare(mainView.__propagated.toolbar.opened, true, "Interacting with toolbar contents resets the hide timer");
300+ // verify that the timer is still running by waiting a bit longer:
301+ wait(0.6*mainView.__propagated.toolbar.hideTimeout);
302+ compare(mainView.__propagated.toolbar.opened, false, "Interacting with the toolbar contents does not stop the timer")
303 }
304
305 function test_locked() {

Subscribers

People subscribed via source and target branches

to status/vote changes: