Merge lp:~tpeeters/ubuntu-ui-toolkit/10-headAnimate into lp:ubuntu-ui-toolkit/staging
- 10-headAnimate
- Merge into staging
Status: | Merged |
---|---|
Approved by: | Zsombor Egri |
Approved revision: | 1213 |
Merged at revision: | 1218 |
Proposed branch: | lp:~tpeeters/ubuntu-ui-toolkit/10-headAnimate |
Merge into: | lp:ubuntu-ui-toolkit/staging |
Prerequisite: | lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/sourceOverflow |
Diff against target: |
1044 lines (+391/-124) 16 files modified
modules/Ubuntu/Components/AppHeader.qml (+5/-0) modules/Ubuntu/Components/Icon10.qml (+1/-1) modules/Ubuntu/Components/MainView.qml (+1/-0) modules/Ubuntu/Components/PageStack.qml (+7/-6) modules/Ubuntu/Components/PageWrapperUtils.js (+3/-1) modules/Ubuntu/Components/Styles/PageHeadStyle.qml (+2/-0) modules/Ubuntu/Components/Themes/Ambiance/PageHeadStyle.qml (+166/-29) tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py (+19/-0) tests/autopilot/ubuntuuitoolkit/tests/components/test_header.py (+2/-0) tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.TabsTestCase.deprecated_TabBar.qml (+61/-0) tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.TabsTestCase.new_header.qml (+43/-0) tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.py (+14/-56) tests/resources/header/header.qml (+4/-6) tests/resources/navigation/MyCustomPage.qml (+17/-25) tests/unit_x11/tst_components/tst_headActions.qml (+13/-0) tests/unit_x11/tst_components/tst_pagestack_new_header.qml (+33/-0) |
To merge this branch: | bzr merge lp:~tpeeters/ubuntu-ui-toolkit/10-headAnimate |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Zsombor Egri | Pending | ||
Review via email: mp+232201@code.launchpad.net |
This proposal supersedes a proposal from 2014-08-22.
Commit message
Description of the change
Add header animations
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
Zsombor Egri (zsombi) wrote : Posted in a previous version of this proposal | # |
Looks good, can go in.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1212
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'modules/Ubuntu/Components/AppHeader.qml' |
2 | --- modules/Ubuntu/Components/AppHeader.qml 2014-07-17 10:59:18 +0000 |
3 | +++ modules/Ubuntu/Components/AppHeader.qml 2014-08-26 11:42:43 +0000 |
4 | @@ -37,6 +37,11 @@ |
5 | */ |
6 | property bool animate: true |
7 | |
8 | + /*! |
9 | + Animate changing to new title/actions inside the header. |
10 | + */ |
11 | + property bool animateContents: false |
12 | + |
13 | Behavior on y { |
14 | enabled: animate && !(header.flickable && header.flickable.moving) |
15 | SmoothedAnimation { |
16 | |
17 | === modified file 'modules/Ubuntu/Components/Icon10.qml' |
18 | --- modules/Ubuntu/Components/Icon10.qml 2014-07-31 14:14:56 +0000 |
19 | +++ modules/Ubuntu/Components/Icon10.qml 2014-08-26 11:42:43 +0000 |
20 | @@ -83,7 +83,7 @@ |
21 | visible: active |
22 | |
23 | // Whether or not a color has been set. |
24 | - property bool active: keyColorOut != Qt.rgba(0.0, 0.0, 0.0, 0.0) |
25 | + property bool active: keyColorOut != Qt.rgba(0.0, 0.0, 0.0, 0.0) && source |
26 | |
27 | property Image source: active && image.status == Image.Ready ? image : null |
28 | property color keyColorOut: Qt.rgba(0.0, 0.0, 0.0, 0.0) |
29 | |
30 | === modified file 'modules/Ubuntu/Components/MainView.qml' |
31 | --- modules/Ubuntu/Components/MainView.qml 2014-08-18 13:34:29 +0000 |
32 | +++ modules/Ubuntu/Components/MainView.qml 2014-08-26 11:42:43 +0000 |
33 | @@ -341,6 +341,7 @@ |
34 | id: headerItem |
35 | property real bottomY: headerItem.y + headerItem.height |
36 | animate: canvas.animate |
37 | + animateContents: canvas.animate |
38 | |
39 | title: internal.activePage ? internal.activePage.title : "" |
40 | flickable: internal.activePage ? internal.activePage.flickable : null |
41 | |
42 | === modified file 'modules/Ubuntu/Components/PageStack.qml' |
43 | --- modules/Ubuntu/Components/PageStack.qml 2014-08-12 10:03:13 +0000 |
44 | +++ modules/Ubuntu/Components/PageStack.qml 2014-08-26 11:42:43 +0000 |
45 | @@ -163,7 +163,6 @@ |
46 | function push(page, properties) { |
47 | if (internal.stack.size() > 0) internal.stack.top().active = false; |
48 | internal.stack.push(internal.createWrapper(page, properties)); |
49 | - internal.stack.top().active = true; |
50 | internal.stackUpdated(); |
51 | } |
52 | |
53 | @@ -181,8 +180,6 @@ |
54 | if (internal.stack.top().canDestroy) internal.stack.top().destroyObject(); |
55 | internal.stack.pop(); |
56 | internal.stackUpdated(); |
57 | - |
58 | - if (internal.stack.size() > 0) internal.stack.top().active = true; |
59 | } |
60 | |
61 | /*! |
62 | @@ -216,9 +213,13 @@ |
63 | } |
64 | |
65 | function stackUpdated() { |
66 | - pageStack.depth =+ stack.size(); |
67 | - if (pageStack.depth > 0) currentPage = stack.top().object; |
68 | - else currentPage = null; |
69 | + pageStack.depth = stack.size(); |
70 | + if (pageStack.depth > 0) { |
71 | + internal.stack.top().active = true; |
72 | + currentPage = stack.top().object; |
73 | + } else { |
74 | + currentPage = null; |
75 | + } |
76 | } |
77 | } |
78 | |
79 | |
80 | === modified file 'modules/Ubuntu/Components/PageWrapperUtils.js' |
81 | --- modules/Ubuntu/Components/PageWrapperUtils.js 2013-05-24 13:51:12 +0000 |
82 | +++ modules/Ubuntu/Components/PageWrapperUtils.js 2014-08-26 11:42:43 +0000 |
83 | @@ -101,8 +101,10 @@ |
84 | */ |
85 | function destroyObject(pageWrapper) { |
86 | if (pageWrapper.canDestroy) { |
87 | - pageWrapper.object.destroy(); |
88 | pageWrapper.object = null; |
89 | + // Rely on garbage collector to destroy the object after all |
90 | + // (other) references are gone. PageHeadStyle uses actions etc. |
91 | + // of the page to show a fade-out animation after it was popped. |
92 | pageWrapper.canDestroy = false; |
93 | } |
94 | } |
95 | |
96 | === modified file 'modules/Ubuntu/Components/Styles/PageHeadStyle.qml' |
97 | --- modules/Ubuntu/Components/Styles/PageHeadStyle.qml 2014-06-26 14:24:41 +0000 |
98 | +++ modules/Ubuntu/Components/Styles/PageHeadStyle.qml 2014-08-26 11:42:43 +0000 |
99 | @@ -53,7 +53,9 @@ |
100 | property int fontWeight |
101 | |
102 | /*! |
103 | + \deprecated |
104 | The color of the title text. |
105 | + Use \l Page.head.foregroundColor instead. |
106 | */ |
107 | property color textColor |
108 | |
109 | |
110 | === modified file 'modules/Ubuntu/Components/Themes/Ambiance/PageHeadStyle.qml' |
111 | --- modules/Ubuntu/Components/Themes/Ambiance/PageHeadStyle.qml 2014-08-26 11:42:42 +0000 |
112 | +++ modules/Ubuntu/Components/Themes/Ambiance/PageHeadStyle.qml 2014-08-26 11:42:43 +0000 |
113 | @@ -29,9 +29,127 @@ |
114 | textColor: styledItem.config.foregroundColor |
115 | textLeftMargin: units.gu(2) |
116 | maximumNumberOfActions: 3 |
117 | + objectName: "PageHeadStyle" |
118 | + |
119 | + // workaround because autopilot cannot select the SequentalAnimation |
120 | + // Needed in AppHeader.wait_for_animation() autopilot proxy object and |
121 | + // in tst_pagestack_new_header.qml unit test. |
122 | + property bool animating: changeAnimation.running |
123 | |
124 | implicitHeight: headerStyle.contentHeight + separator.height + separatorBottom.height |
125 | |
126 | + Component.onCompleted: buffer.update() |
127 | + |
128 | + Object { |
129 | + id: buffer |
130 | + |
131 | + property PageHeadConfiguration config |
132 | + property string title |
133 | + property Item pageStack: null |
134 | + property int pageStackDepth: 0 |
135 | + property var tabsModel: null |
136 | + |
137 | + function update() { |
138 | + buffer.config = styledItem.config; |
139 | + buffer.title = styledItem.title; |
140 | + buffer.pageStack = styledItem.pageStack; |
141 | + buffer.pageStackDepth = buffer.pageStack ? buffer.pageStack.depth : 0; |
142 | + buffer.tabsModel = styledItem.tabsModel ? styledItem.tabsModel : null; |
143 | + } |
144 | + |
145 | + // Calling changeAnimation.start() a second time has no effect, |
146 | + // so below we can call it whenever something changes. |
147 | + Connections { |
148 | + target: styledItem |
149 | + onConfigChanged: buffer.updateConfigAndTitle() |
150 | + onTitleChanged: buffer.updateConfigAndTitle() |
151 | + onPageStackChanged: buffer.updateConfigAndTitle() |
152 | + onTabsModelChanged: buffer.updateConfigAndTitle() |
153 | + } |
154 | + |
155 | + function updateConfigAndTitle() { |
156 | + if (styledItem.animateContents) { |
157 | + changeAnimation.start(); |
158 | + } else { |
159 | + buffer.update(); |
160 | + } |
161 | + } |
162 | + |
163 | + SequentialAnimation { |
164 | + id: changeAnimation |
165 | + objectName: "changeAnimation" |
166 | + ParallelAnimation { |
167 | + UbuntuNumberAnimation { |
168 | + target: foreground |
169 | + property: "opacity" |
170 | + from: 1.0 |
171 | + to: 0.0 |
172 | + } |
173 | + UbuntuNumberAnimation { |
174 | + target: leftButtonContainer |
175 | + property: "opacity" |
176 | + from: 1.0 |
177 | + to: 0.0 |
178 | + } |
179 | + UbuntuNumberAnimation { |
180 | + target: actionsContainer |
181 | + property: "opacity" |
182 | + from: 1.0 |
183 | + to: 0.0 |
184 | + } |
185 | + UbuntuNumberAnimation { |
186 | + target: leftAnchor |
187 | + properties: "anchors.leftMargin" |
188 | + from: 0.0 |
189 | + to: -units.gu(5) |
190 | + } |
191 | + UbuntuNumberAnimation { |
192 | + target: rightAnchor |
193 | + properties: "anchors.rightMargin" |
194 | + from: 0 |
195 | + to: -units.gu(5) |
196 | + } |
197 | + } |
198 | + ScriptAction { |
199 | + script: { |
200 | + buffer.update(); |
201 | + } |
202 | + } |
203 | + ParallelAnimation { |
204 | + UbuntuNumberAnimation { |
205 | + target: foreground |
206 | + property: "opacity" |
207 | + from: 0.0 |
208 | + to: 1.0 |
209 | + } |
210 | + UbuntuNumberAnimation { |
211 | + target: leftButtonContainer |
212 | + property: "opacity" |
213 | + from: 0.0 |
214 | + to: 1.0 |
215 | + } |
216 | + UbuntuNumberAnimation { |
217 | + target: actionsContainer |
218 | + property: "opacity" |
219 | + from: 0.0 |
220 | + to: 1.0 |
221 | + } |
222 | + UbuntuNumberAnimation { |
223 | + target: leftAnchor |
224 | + properties: "anchors.leftMargin" |
225 | + from: -units.gu(5) |
226 | + to: 0 |
227 | + } |
228 | + UbuntuNumberAnimation { |
229 | + target: rightAnchor |
230 | + properties: "anchors.rightMargin" |
231 | + from: -units.gu(5) |
232 | + to: 0 |
233 | + } |
234 | + } |
235 | + } |
236 | + } |
237 | + |
238 | // FIXME: Workaround to get sectionsRepeater.count in autopilot tests, |
239 | // see also FIXME in AppHeader where this property is used. |
240 | property alias __sections_repeater_for_autopilot: sectionsRepeater |
241 | @@ -46,7 +164,7 @@ |
242 | source: headerStyle.separatorSource |
243 | height: sectionsRow.visible ? units.gu(3) : units.gu(2) |
244 | |
245 | - property PageHeadSections sections: styledItem.config.sections |
246 | + property PageHeadSections sections: buffer.config.sections |
247 | |
248 | Row { |
249 | id: sectionsRow |
250 | @@ -121,9 +239,30 @@ |
251 | } |
252 | |
253 | Item { |
254 | + id: leftAnchor |
255 | + anchors { |
256 | + top: parent.top |
257 | + bottom: parent.bottom |
258 | + left: parent.left |
259 | + leftMargin: 0 |
260 | + } |
261 | + width: 0 |
262 | + } |
263 | + Item { |
264 | + id: rightAnchor |
265 | + anchors { |
266 | + top: parent.top |
267 | + bottom: parent.bottom |
268 | + right: parent.right |
269 | + rightMargin: 0 |
270 | + } |
271 | + width: 0 |
272 | + } |
273 | + |
274 | + Item { |
275 | id: leftButtonContainer |
276 | anchors { |
277 | - left: parent.left |
278 | + left: leftAnchor.right |
279 | top: parent.top |
280 | leftMargin: width > 0 ? units.gu(1) : 0 |
281 | } |
282 | @@ -133,10 +272,10 @@ |
283 | PageHeadButton { |
284 | id: customBackButton |
285 | objectName: "customBackButton" |
286 | - action: styledItem.config.backAction |
287 | - visible: null !== styledItem.config.backAction && |
288 | - styledItem.config.backAction.visible |
289 | - color: styledItem.config.foregroundColor |
290 | + action: buffer.config.backAction |
291 | + visible: null !== buffer.config.backAction && |
292 | + buffer.config.backAction.visible |
293 | + color: buffer.config.foregroundColor |
294 | } |
295 | |
296 | PageHeadButton { |
297 | @@ -144,16 +283,14 @@ |
298 | objectName: "backButton" |
299 | |
300 | iconName: "back" |
301 | - visible: styledItem.pageStack !== null && |
302 | - styledItem.pageStack !== undefined && |
303 | - styledItem.pageStack.depth > 1 && |
304 | - !styledItem.config.backAction |
305 | + visible: buffer.pageStackDepth > 1 && |
306 | + !buffer.config.backAction |
307 | |
308 | text: "back" |
309 | - color: styledItem.config.foregroundColor |
310 | + color: buffer.config.foregroundColor |
311 | |
312 | onTriggered: { |
313 | - styledItem.pageStack.pop(); |
314 | + buffer.pageStack.pop(); |
315 | } |
316 | } |
317 | |
318 | @@ -162,12 +299,11 @@ |
319 | objectName: "tabsButton" |
320 | |
321 | iconName: "navigation-menu" |
322 | - visible: styledItem.tabsModel !== null && |
323 | - styledItem.tabsModel !== undefined && |
324 | + visible: buffer.tabsModel !== null && |
325 | !backButton.visible && |
326 | !customBackButton.visible |
327 | - text: visible ? styledItem.tabsModel.count + " tabs" : "" |
328 | - color: styledItem.config.foregroundColor |
329 | + text: visible ? buffer.tabsModel.count + " tabs" : "" |
330 | + color: buffer.config.foregroundColor |
331 | |
332 | onTriggered: PopupUtils.open(tabsPopoverComponent, tabsButton) |
333 | |
334 | @@ -187,11 +323,11 @@ |
335 | right: parent.right |
336 | } |
337 | Repeater { |
338 | - model: styledItem.tabsModel |
339 | + model: buffer.tabsModel |
340 | AbstractButton { |
341 | objectName: "tabButton" + index |
342 | onClicked: { |
343 | - styledItem.tabsModel.selectedIndex = index; |
344 | + buffer.tabsModel.selectedIndex = index; |
345 | tabsPopover.hide(); |
346 | } |
347 | implicitHeight: units.gu(6) + bottomDividerLine.height |
348 | @@ -224,7 +360,7 @@ |
349 | ListItem.ThinDivider { |
350 | id: bottomDividerLine |
351 | anchors.bottom: parent.bottom |
352 | - visible: index < styledItem.tabsModel.count - 1 |
353 | + visible: index < buffer.tabsModel.count - 1 |
354 | } |
355 | } |
356 | } |
357 | @@ -238,12 +374,12 @@ |
358 | id: foreground |
359 | anchors { |
360 | left: leftButtonContainer.right |
361 | - right: actionsContainer.left |
362 | top: parent.top |
363 | // don't keep a margin if there is already a button with spacing |
364 | leftMargin: leftButtonContainer.width > 0 ? 0 : headerStyle.textLeftMargin |
365 | } |
366 | height: headerStyle.contentHeight |
367 | + width: parent.width - leftButtonContainer.width - actionsContainer.width |
368 | |
369 | Label { |
370 | objectName: "header_title_label" |
371 | @@ -254,10 +390,10 @@ |
372 | right: parent.right |
373 | verticalCenter: parent.verticalCenter |
374 | } |
375 | - text: styledItem.title |
376 | + text: buffer.title |
377 | font.weight: headerStyle.fontWeight |
378 | fontSize: headerStyle.fontSize |
379 | - color: headerStyle.textColor |
380 | + color: buffer.config.foregroundColor |
381 | elide: Text.ElideRight |
382 | } |
383 | |
384 | @@ -267,7 +403,7 @@ |
385 | // when the bindings below is no longer active |
386 | id: contentsContainer |
387 | anchors.fill: parent |
388 | - visible: styledItem.contents || styledItem.config.contents |
389 | + visible: styledItem.contents || buffer.config.contents |
390 | } |
391 | Binding { |
392 | target: styledItem.contents |
393 | @@ -282,17 +418,17 @@ |
394 | when: styledItem.contents |
395 | } |
396 | Binding { |
397 | - target: styledItem.config.contents |
398 | + target: buffer.config.contents |
399 | property: "parent" |
400 | value: contentsContainer |
401 | - when: styledItem.config.contents && !styledItem.contents |
402 | + when: buffer.config.contents && !styledItem.contents |
403 | } |
404 | } |
405 | |
406 | Row { |
407 | id: actionsContainer |
408 | |
409 | - property var visibleActions: getVisibleActions(styledItem.config.actions) |
410 | + property var visibleActions: getVisibleActions(buffer.config.actions) |
411 | function getVisibleActions(actions) { |
412 | var visibleActionList = []; |
413 | for (var i in actions) { |
414 | @@ -316,7 +452,7 @@ |
415 | |
416 | anchors { |
417 | top: parent.top |
418 | - right: parent.right |
419 | + right: rightAnchor.left |
420 | rightMargin: units.gu(1) |
421 | } |
422 | width: childrenRect.width |
423 | @@ -328,7 +464,7 @@ |
424 | id: actionButton |
425 | objectName: action.objectName + "_header_button" |
426 | action: actionsContainer.visibleActions[index] |
427 | - color: styledItem.config.foregroundColor |
428 | + color: buffer.config.foregroundColor |
429 | } |
430 | } |
431 | |
432 | @@ -337,8 +473,9 @@ |
433 | objectName: "actions_overflow_button" |
434 | visible: numberOfSlots.requested > numberOfSlots.right |
435 | iconName: "contextual-menu" |
436 | - color: styledItem.config.foregroundColor |
437 | + color: buffer.config.foregroundColor |
438 | height: actionsContainer.height |
439 | + |
440 | onTriggered: PopupUtils.open(actionsOverflowPopoverComponent, actionsOverflowButton) |
441 | |
442 | Component { |
443 | |
444 | === modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py' |
445 | --- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py 2014-08-20 06:45:28 +0000 |
446 | +++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py 2014-08-26 11:42:43 +0000 |
447 | @@ -67,6 +67,7 @@ |
448 | raise _common.ToolkitException('Old header has no sections') |
449 | |
450 | try: |
451 | + self.wait_for_animation() |
452 | object_name = "section_button_" + str(index) |
453 | button = self.select_single(objectName=object_name) |
454 | except dbus.StateNotFoundError: |
455 | @@ -79,6 +80,7 @@ |
456 | if self.useDeprecatedToolbar: |
457 | raise _common.ToolkitException('Old header has no sections') |
458 | |
459 | + self.wait_for_animation() |
460 | sectionsProperties = self.select_single( |
461 | 'QQuickItem', objectName='sectionsProperties') |
462 | return sectionsProperties.selectedIndex |
463 | @@ -89,12 +91,14 @@ |
464 | if self.useDeprecatedToolbar: |
465 | raise _common.ToolkitException('Old header has no back button') |
466 | try: |
467 | + self.wait_for_animation() |
468 | back_button = self.select_single(objectName='backButton') |
469 | except dbus.StateNotFoundError: |
470 | raise _common.ToolkitException('Missing back button in header') |
471 | if not back_button.visible: |
472 | raise _common.ToolkitException('Back button in header not visible') |
473 | self.pointing_device.click_object(back_button) |
474 | + self.wait_for_animation() |
475 | |
476 | def click_custom_back_button(self): |
477 | self._show_if_not_visible() |
478 | @@ -103,6 +107,7 @@ |
479 | raise _common.ToolkitException( |
480 | 'Old header has no custom back button') |
481 | try: |
482 | + self.wait_for_animation() |
483 | custom_back_button = self.select_single( |
484 | objectName='customBackButton') |
485 | except dbus.StateNotFoundError: |
486 | @@ -112,6 +117,7 @@ |
487 | raise _common.ToolkitException( |
488 | 'Custom back button in header not visible') |
489 | self.pointing_device.click_object(custom_back_button) |
490 | + self.wait_for_animation() |
491 | |
492 | def _get_animating(self): |
493 | if self.useDeprecatedToolbar: |
494 | @@ -120,6 +126,14 @@ |
495 | else: |
496 | return False |
497 | |
498 | + def wait_for_animation(self): |
499 | + try: |
500 | + style = self.select_single(objectName='PageHeadStyle') |
501 | + style.animating.wait_for(False) |
502 | + except dbus.StateNotFoundError: |
503 | + raise _common.ToolkitException( |
504 | + 'AppHeader is not using the new PageHeadStyle') |
505 | + |
506 | @autopilot_logging.log_action(logger.info) |
507 | def switch_to_next_tab(self): |
508 | """Open the next tab. |
509 | @@ -143,6 +157,7 @@ |
510 | self._get_animating().wait_for(False) |
511 | |
512 | def _switch_to_next_tab_in_drawer(self): |
513 | + self.wait_for_animation() |
514 | tabs_model_properties = self.select_single( |
515 | 'QQuickItem', objectName='tabsModelProperties') |
516 | next_tab_index = (tabs_model_properties.selectedIndex |
517 | @@ -167,6 +182,7 @@ |
518 | self._switch_to_tab_in_drawer_by_index(index) |
519 | |
520 | def _switch_to_tab_in_drawer_by_index(self, index): |
521 | + self.wait_for_animation() |
522 | try: |
523 | tabs_drawer_button = self.select_single(objectName='tabsButton') |
524 | except dbus.StateNotFoundError: |
525 | @@ -187,6 +203,7 @@ |
526 | "Tab button {0} not found.".format(index)) |
527 | |
528 | self.pointing_device.click_object(tab_button) |
529 | + self.wait_for_animation() |
530 | |
531 | def click_action_button(self, action_object_name): |
532 | """Click an action button of the header. |
533 | @@ -200,8 +217,10 @@ |
534 | |
535 | button = self._get_action_button(action_object_name) |
536 | self.pointing_device.click_object(button) |
537 | + self.wait_for_animation() |
538 | |
539 | def _get_action_button(self, action_object_name): |
540 | + self.wait_for_animation() |
541 | try: |
542 | object_name = action_object_name + "_header_button" |
543 | button = self.select_single(objectName=object_name) |
544 | |
545 | === modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_header.py' |
546 | --- tests/autopilot/ubuntuuitoolkit/tests/components/test_header.py 2014-07-31 08:21:14 +0000 |
547 | +++ tests/autopilot/ubuntuuitoolkit/tests/components/test_header.py 2014-08-26 11:42:43 +0000 |
548 | @@ -81,6 +81,7 @@ |
549 | objectName='push_button') |
550 | self.pointing_device.move_to_object(pushButton) |
551 | self.pointing_device.click() |
552 | + self.header.wait_for_animation() |
553 | |
554 | self.assertEqual(label.visible, False) |
555 | headerContents = self.header.select_single( |
556 | @@ -94,6 +95,7 @@ |
557 | objectName='push_button') |
558 | self.pointing_device.move_to_object(pushButton) |
559 | self.pointing_device.click() |
560 | + self.header.wait_for_animation() |
561 | |
562 | headerContents = self.header.select_single( |
563 | objectName='orange_header_contents') |
564 | |
565 | === added file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.TabsTestCase.deprecated_TabBar.qml' |
566 | --- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.TabsTestCase.deprecated_TabBar.qml 1970-01-01 00:00:00 +0000 |
567 | +++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.TabsTestCase.deprecated_TabBar.qml 2014-08-26 11:42:43 +0000 |
568 | @@ -0,0 +1,61 @@ |
569 | +/* |
570 | + * Copyright 2014 Canonical Ltd. |
571 | + * |
572 | + * This program is free software; you can redistribute it and/or modify |
573 | + * it under the terms of the GNU Lesser General Public License as published by |
574 | + * the Free Software Foundation; version 3. |
575 | + * |
576 | + * This program is distributed in the hope that it will be useful, |
577 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
578 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
579 | + * GNU Lesser General Public License for more details. |
580 | + * |
581 | + * You should have received a copy of the GNU Lesser General Public License |
582 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
583 | + */ |
584 | + |
585 | +import QtQuick 2.2 |
586 | +import Ubuntu.Components 1.1 |
587 | + |
588 | +MainView { |
589 | + width: units.gu(70) |
590 | + height: units.gu(60) |
591 | + useDeprecatedToolbar: true |
592 | + |
593 | + Tabs { |
594 | + id: tabs |
595 | + Tab { |
596 | + objectName: "tab1" |
597 | + title: "Tab1" |
598 | + Page { |
599 | + tools: ToolbarItems { |
600 | + ToolbarButton { |
601 | + text: "Test1" |
602 | + } |
603 | + } |
604 | + } |
605 | + } |
606 | + Tab { |
607 | + objectName: "tab2" |
608 | + title: "Tab2" |
609 | + Page { |
610 | + tools: ToolbarItems { |
611 | + ToolbarButton { |
612 | + text: "Test2" |
613 | + } |
614 | + } |
615 | + } |
616 | + } |
617 | + Tab { |
618 | + objectName: "tab3" |
619 | + title: "Tab3" |
620 | + Page { |
621 | + tools: ToolbarItems { |
622 | + ToolbarButton { |
623 | + text: "Test3" |
624 | + } |
625 | + } |
626 | + } |
627 | + } |
628 | + } |
629 | +} |
630 | |
631 | === added file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.TabsTestCase.new_header.qml' |
632 | --- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.TabsTestCase.new_header.qml 1970-01-01 00:00:00 +0000 |
633 | +++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.TabsTestCase.new_header.qml 2014-08-26 11:42:43 +0000 |
634 | @@ -0,0 +1,43 @@ |
635 | +/* |
636 | + * Copyright 2014 Canonical Ltd. |
637 | + * |
638 | + * This program is free software; you can redistribute it and/or modify |
639 | + * it under the terms of the GNU Lesser General Public License as published by |
640 | + * the Free Software Foundation; version 3. |
641 | + * |
642 | + * This program is distributed in the hope that it will be useful, |
643 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
644 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
645 | + * GNU Lesser General Public License for more details. |
646 | + * |
647 | + * You should have received a copy of the GNU Lesser General Public License |
648 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
649 | + */ |
650 | + |
651 | +import QtQuick 2.2 |
652 | +import Ubuntu.Components 1.1 |
653 | + |
654 | +MainView { |
655 | + width: units.gu(70) |
656 | + height: units.gu(60) |
657 | + useDeprecatedToolbar: false |
658 | + |
659 | + Tabs { |
660 | + id: tabs |
661 | + Tab { |
662 | + objectName: "tab1" |
663 | + title: "Tab1" |
664 | + Page { } |
665 | + } |
666 | + Tab { |
667 | + objectName: "tab2" |
668 | + title: "Tab2" |
669 | + Page { } |
670 | + } |
671 | + Tab { |
672 | + objectName: "tab3" |
673 | + title: "Tab3" |
674 | + Page { } |
675 | + } |
676 | + } |
677 | +} |
678 | |
679 | === modified file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.py' |
680 | --- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.py 2014-06-02 23:21:48 +0000 |
681 | +++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_tabs.py 2014-08-26 11:42:43 +0000 |
682 | @@ -14,6 +14,8 @@ |
683 | # You should have received a copy of the GNU Lesser General Public License |
684 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
685 | |
686 | +import os |
687 | + |
688 | try: |
689 | from unittest import mock |
690 | except ImportError: |
691 | @@ -23,64 +25,20 @@ |
692 | from ubuntuuitoolkit import tests |
693 | |
694 | |
695 | -TEST_TABS_QML_FORMAT = (""" |
696 | -import QtQuick 2.0 |
697 | -import Ubuntu.Components 1.0 |
698 | - |
699 | -MainView {{ |
700 | - width: units.gu(70) |
701 | - height: units.gu(60) |
702 | - useDeprecatedToolbar: {use_deprecated_toolbar} |
703 | - |
704 | - Tabs {{ |
705 | - id: tabs |
706 | - Tab {{ |
707 | - objectName: "tab1" |
708 | - title: "Tab1" |
709 | - Page {{ |
710 | - tools: ToolbarItems {{ |
711 | - ToolbarButton {{ |
712 | - text: "Test1" |
713 | - }} |
714 | - }} |
715 | - }} |
716 | - }} |
717 | - Tab {{ |
718 | - objectName: "tab2" |
719 | - title: "Tab2" |
720 | - Page {{ |
721 | - tools: ToolbarItems {{ |
722 | - ToolbarButton {{ |
723 | - text: "Test2" |
724 | - }} |
725 | - }} |
726 | - }} |
727 | - }} |
728 | - Tab {{ |
729 | - objectName: "tab3" |
730 | - title: "Tab3" |
731 | - Page {{ |
732 | - tools: ToolbarItems {{ |
733 | - ToolbarButton {{ |
734 | - text: "Test3" |
735 | - }} |
736 | - }} |
737 | - }} |
738 | - }} |
739 | - }} |
740 | -}} |
741 | -""") |
742 | - |
743 | - |
744 | -class TabsTestCase(tests.QMLStringAppTestCase): |
745 | +class TabsTestCase(tests.QMLFileAppTestCase): |
746 | + |
747 | + path = os.path.abspath(__file__) |
748 | + dir_path = os.path.dirname(path) |
749 | + deprecated_tabbar_test_qml_file_path = os.path.join( |
750 | + dir_path, 'test_tabs.TabsTestCase.deprecated_TabBar.qml') |
751 | + new_header_test_qml_file_path = os.path.join( |
752 | + dir_path, 'test_tabs.TabsTestCase.new_header.qml') |
753 | |
754 | scenarios = [ |
755 | - ('deprecated tabs', dict( |
756 | - test_qml=TEST_TABS_QML_FORMAT.format( |
757 | - use_deprecated_toolbar='true'))), |
758 | - ('drawer tabs', dict( |
759 | - test_qml=TEST_TABS_QML_FORMAT.format( |
760 | - use_deprecated_toolbar='false'))) |
761 | + ('deprecated TabBar', |
762 | + dict(test_qml_file_path=deprecated_tabbar_test_qml_file_path)), |
763 | + ('new header', |
764 | + dict(test_qml_file_path=new_header_test_qml_file_path)) |
765 | ] |
766 | |
767 | def test_tabs_custom_proxy_object(self): |
768 | |
769 | === modified file 'tests/resources/header/header.qml' |
770 | --- tests/resources/header/header.qml 2014-07-31 14:09:45 +0000 |
771 | +++ tests/resources/header/header.qml 2014-08-26 11:42:43 +0000 |
772 | @@ -206,12 +206,10 @@ |
773 | anchors.centerIn: parent |
774 | text: "Use back button to return" |
775 | } |
776 | - tools: ToolbarItems { |
777 | - ToolbarButton { |
778 | - action: Action { |
779 | - iconName: "settings" |
780 | - text: "settings" |
781 | - } |
782 | + head { |
783 | + actions: Action { |
784 | + iconName: "settings" |
785 | + text: "settings" |
786 | } |
787 | } |
788 | } |
789 | |
790 | === modified file 'tests/resources/navigation/MyCustomPage.qml' |
791 | --- tests/resources/navigation/MyCustomPage.qml 2014-08-26 11:42:42 +0000 |
792 | +++ tests/resources/navigation/MyCustomPage.qml 2014-08-26 11:42:43 +0000 |
793 | @@ -15,7 +15,7 @@ |
794 | */ |
795 | |
796 | import QtQuick 2.0 |
797 | -import Ubuntu.Components 1.0 |
798 | +import Ubuntu.Components 1.1 |
799 | |
800 | Page { |
801 | title: i18n.tr("My custom page") |
802 | @@ -30,32 +30,24 @@ |
803 | horizontalCenter: parent.horizontalCenter |
804 | } |
805 | |
806 | - text: i18n.tr("This is an external page\nwith a locked toolbar.") |
807 | + text: i18n.tr("This is an external page.") |
808 | color: "#757373" |
809 | } |
810 | } |
811 | |
812 | - tools: ToolbarItems { |
813 | - ToolbarButton { |
814 | - action: Action { |
815 | - text: "action 1" |
816 | - iconName: "outgoing-call" |
817 | - } |
818 | - } |
819 | - ToolbarButton { |
820 | - action: Action { |
821 | - text: "action 2" |
822 | - iconName: "missed-call" |
823 | - } |
824 | - } |
825 | - ToolbarButton { |
826 | - action: Action { |
827 | - text: "another one" |
828 | - iconSource: "call_icon.png" |
829 | - } |
830 | - } |
831 | - |
832 | - opened: true |
833 | - locked: true |
834 | - } |
835 | + head.actions: [ |
836 | + Action { |
837 | + text: "action 1" |
838 | + iconName: "outgoing-call" |
839 | + }, |
840 | + Action { |
841 | + text: "action 2" |
842 | + iconSource: "call_icon.png" |
843 | + iconName: "missed-call" |
844 | + }, |
845 | + Action { |
846 | + text: "another one" |
847 | + iconName: "contact" |
848 | + } |
849 | + ] |
850 | } |
851 | |
852 | === modified file 'tests/unit_x11/tst_components/tst_headActions.qml' |
853 | --- tests/unit_x11/tst_components/tst_headActions.qml 2014-07-28 18:41:55 +0000 |
854 | +++ tests/unit_x11/tst_components/tst_headActions.qml 2014-08-26 11:42:43 +0000 |
855 | @@ -64,39 +64,52 @@ |
856 | property var app_header |
857 | property var back_button |
858 | property var custom_back_button |
859 | + property var head_animation |
860 | |
861 | function initTestCase() { |
862 | testCase.app_header = findChild(mainView, "MainView_Header"); |
863 | testCase.back_button = findChild(app_header, "backButton"); |
864 | testCase.custom_back_button = findChild(app_header, "customBackButton"); |
865 | + testCase.head_animation = findChild(app_header, "PageHeadStyle"); |
866 | |
867 | + waitHeadAnimation(); |
868 | compare(page2.head.backAction, null, "Back action set by default."); |
869 | compare(back_button.visible, false, "Back button visible with only 1 page on the stack."); |
870 | compare(custom_back_button.visible, false, "Custom back button visible without custom back action.") |
871 | } |
872 | |
873 | + function waitHeadAnimation() { |
874 | + tryCompareFunction(function(){return testCase.head_animation.animating}, false); |
875 | + } |
876 | + |
877 | function test_default_back_button() { |
878 | pageStack.push(page2); |
879 | + waitHeadAnimation(); |
880 | compare(back_button.visible, true, "Back button not visible with 2 pages on stack."); |
881 | compare(custom_back_button.visible, false, "Showing custom back button without custom back action."); |
882 | pageStack.pop(); |
883 | + waitHeadAnimation(); |
884 | } |
885 | |
886 | function test_custom_back_button() { |
887 | page2.head.backAction = customBackAction; |
888 | pageStack.push(page2); |
889 | + waitHeadAnimation(); |
890 | compare(back_button.visible, false, "Default back button visible with custom back action."); |
891 | compare(custom_back_button.visible, true, "Custom back button invisible with back action."); |
892 | pageStack.pop(); |
893 | + waitHeadAnimation(); |
894 | page2.head.backAction = null; |
895 | } |
896 | |
897 | function test_no_back_button() { |
898 | page2.head.backAction = invisibleAction; |
899 | pageStack.push(page2); |
900 | + waitHeadAnimation(); |
901 | compare(back_button.visible, false, "Default back button visible with invisible custom back action."); |
902 | compare(custom_back_button.visible, false, "Custom back button visible with invisible custom back action."); |
903 | pageStack.pop(); |
904 | + waitHeadAnimation(); |
905 | page2.head.backAction = null; |
906 | } |
907 | } |
908 | |
909 | === modified file 'tests/unit_x11/tst_components/tst_pagestack_new_header.qml' |
910 | --- tests/unit_x11/tst_components/tst_pagestack_new_header.qml 2014-08-18 10:40:45 +0000 |
911 | +++ tests/unit_x11/tst_components/tst_pagestack_new_header.qml 2014-08-26 11:42:43 +0000 |
912 | @@ -27,6 +27,7 @@ |
913 | |
914 | MainView { |
915 | id: mainView |
916 | + anchors.fill: parent |
917 | useDeprecatedToolbar: false |
918 | PageStack { |
919 | id: pageStack |
920 | @@ -65,7 +66,13 @@ |
921 | when: windowShown |
922 | id: testCase |
923 | |
924 | + function waitPageHeadAnimation() { |
925 | + var pageHeadStyle = findChild(mainView, "PageHeadStyle"); |
926 | + tryCompare(pageHeadStyle, "animating", false); |
927 | + } |
928 | + |
929 | function initTestCase() { |
930 | + waitPageHeadAnimation(); |
931 | compare(pageStack.currentPage, null, "is not set by default"); |
932 | compare(pageStack.__propagated, mainView.__propagated, "propagated property of pageStack equals mainView.__propagated") |
933 | compare(mainView.__propagated.header.title, "", "empty title by default"); |
934 | @@ -74,55 +81,73 @@ |
935 | function test_depth() { |
936 | compare(pageStack.depth, 0, "depth is 0 by default"); |
937 | pageStack.push(page1); |
938 | + waitPageHeadAnimation(); |
939 | compare(pageStack.depth, 1, "depth is correctly increased when pushing a page"); |
940 | pageStack.push(page2); |
941 | + waitPageHeadAnimation(); |
942 | compare(pageStack.depth, 2, "depth is correctly updated when pushing a page"); |
943 | pageStack.pop(); |
944 | + waitPageHeadAnimation(); |
945 | compare(pageStack.depth, 1, "depth is correctly decreased when popping a page"); |
946 | pageStack.clear(); |
947 | + waitPageHeadAnimation(); |
948 | compare(pageStack.depth, 0, "depth is after clearing"); |
949 | } |
950 | |
951 | function test_currentPage() { |
952 | compare(pageStack.currentPage, null, "currentPage is null by default"); |
953 | pageStack.push(page1); |
954 | + waitPageHeadAnimation(); |
955 | compare(pageStack.currentPage, page1, "currentPage properly updated"); |
956 | pageStack.clear(); |
957 | + waitPageHeadAnimation(); |
958 | compare(pageStack.currentPage, null, "currentPage properly reset"); |
959 | } |
960 | |
961 | function test_active_bug1260116() { |
962 | pageStack.push(page1); |
963 | + waitPageHeadAnimation(); |
964 | compare(page1.active, true, "Page is active after pushing"); |
965 | pageStack.push(page2); |
966 | + waitPageHeadAnimation(); |
967 | compare(page1.active, false, "Page no longer active after pushing a new page"); |
968 | compare(page2.active, true, "New page is active after pushing"); |
969 | pageStack.pop(); |
970 | + waitPageHeadAnimation(); |
971 | compare(page1.active, true, "Page re-activated when on top of the stack"); |
972 | compare(page2.active, false, "Page no longer active after being popped"); |
973 | pageStack.clear(); |
974 | + waitPageHeadAnimation(); |
975 | |
976 | compare(pageInStack.active, false, "Page defined inside PageStack is not active by default"); |
977 | pageStack.push(pageInStack); |
978 | + waitPageHeadAnimation(); |
979 | compare(pageInStack.active, true, "Pushing a page on PageStack makes it active"); |
980 | pageStack.pop(); |
981 | + waitPageHeadAnimation(); |
982 | compare(pageInStack.active, false, "Popping a page from PageStack makes it inactive"); |
983 | pageStack.clear(); |
984 | + waitPageHeadAnimation(); |
985 | } |
986 | |
987 | function test_title_bug1143345_bug1317902() { |
988 | pageStack.push(page1); |
989 | + waitPageHeadAnimation(); |
990 | compare(mainView.__propagated.header.title, "Title 1", "Header title is correctly set by page"); |
991 | page1.title = "New title"; |
992 | compare(mainView.__propagated.header.title, "New title", "Header title correctly updated by page"); |
993 | pageStack.push(page2); |
994 | + waitPageHeadAnimation(); |
995 | compare(mainView.__propagated.header.title, "Title 2", "Header title is correctly set by page"); |
996 | pageStack.clear(); |
997 | + waitPageHeadAnimation(); |
998 | page1.title = "Title 1"; |
999 | |
1000 | pageStack.push(pageWithPage); |
1001 | + waitPageHeadAnimation(); |
1002 | compare(mainView.__propagated.header.title, pageWithPage.title, "Embedded page sets title of outer page"); |
1003 | pageStack.clear(); |
1004 | + waitPageHeadAnimation(); |
1005 | } |
1006 | |
1007 | function get_tabs_button() { |
1008 | @@ -134,28 +159,36 @@ |
1009 | function test_tabs_inside_stack_bug1187850() { |
1010 | compare(get_tabs_button(), null, "Without tabs there is no visible tabs button."); |
1011 | pageStack.push(tabs); |
1012 | + waitPageHeadAnimation(); |
1013 | compare(pageStack.currentPage, tabs, "Tabs can be pushed on a PageStack"); |
1014 | compare(tabs.active, true, "Tabs on top of a PageStack are active"); |
1015 | compare(get_tabs_button().visible, true, "Pushing tabs on pagestack enables the tabs button"); |
1016 | pageStack.push(page1); |
1017 | + waitPageHeadAnimation(); |
1018 | compare(pageStack.currentPage, page1, "A page can be pushed on top of a Tabs"); |
1019 | compare(tabs.active, false, "Tabs on a PageStack, but not on top, are inactive"); |
1020 | compare(get_tabs_button(), null, "Contents of inactive Tabs is not applied to header"); |
1021 | pageStack.pop(); |
1022 | + waitPageHeadAnimation(); |
1023 | compare(tabs.active, true, "Tabs on top of PageStack is active"); |
1024 | compare(get_tabs_button().visible, true, "Active Tabs controls header contents"); |
1025 | pageStack.clear(); |
1026 | + waitPageHeadAnimation(); |
1027 | } |
1028 | |
1029 | function test_pop_to_tabs_bug1316736() { |
1030 | pageStack.push(tabs); |
1031 | + waitPageHeadAnimation(); |
1032 | tabs.selectedTabIndex = 1; |
1033 | pageStack.push(page1); |
1034 | + waitPageHeadAnimation(); |
1035 | compare(tabs.active, false, "Tabs on a PageStack, but not on top, are inactive"); |
1036 | pageStack.pop(); |
1037 | + waitPageHeadAnimation(); |
1038 | compare(tabs.active, true, "Tabs on top of PageStack is active"); |
1039 | compare(tabs.selectedTabIndex, 1, "Pushing and popping another page on top of Tabs does not change selectedTabsIndex"); |
1040 | pageStack.clear(); |
1041 | + waitPageHeadAnimation(); |
1042 | } |
1043 | } |
1044 | } |
PASSED: Continuous integration, rev:1210 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/889/ jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- utopic- amd64-ci/ 721 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- utopic- armhf-ci/ 721 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- utopic- armhf-ci/ 721/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- utopic- i386-ci/ 721
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/889/ rebuild
http://