Merge lp:~tpeeters/ubuntu-ui-toolkit/20-AppHeader-use-cppHeader into lp:ubuntu-ui-toolkit/staging

Proposed by Tim Peeters
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1675
Merged at revision: 1670
Proposed branch: lp:~tpeeters/ubuntu-ui-toolkit/20-AppHeader-use-cppHeader
Merge into: lp:ubuntu-ui-toolkit/staging
Prerequisite: lp:~tpeeters/ubuntu-ui-toolkit/fix-header-AP2
Diff against target: 623 lines (+96/-251)
10 files modified
components.api (+1/-0)
src/Ubuntu/Components/1.3/AppHeader.qml (+27/-225)
src/Ubuntu/Components/1.3/MainView.qml (+1/-2)
src/Ubuntu/Components/1.3/Page.qml (+1/-0)
src/Ubuntu/Components/1.3/PageHeadConfiguration.qml (+2/-1)
src/Ubuntu/Components/plugin/ucheader.cpp (+29/-9)
src/Ubuntu/Components/plugin/ucheader.h (+2/-2)
tests/unit_x11/tst_components/tst_header.qml (+22/-4)
tests/unit_x11/tst_components/tst_page13.qml (+2/-2)
tests/unit_x11/tst_components/tst_pagehead_visible.qml (+9/-6)
To merge this branch: bzr merge lp:~tpeeters/ubuntu-ui-toolkit/20-AppHeader-use-cppHeader
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Zsombor Egri Approve
Review via email: mp+273096@code.launchpad.net

Commit message

Use the new cpp Header in the internal AppHeader.

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

clean MainView.qml

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: Needs Fixing (continuous-integration)
1670. By Tim Peeters

sync staging

1671. By Tim Peeters

fix page positioning with locked header

1672. By Tim Peeters

restore contentY value when unsetting flickable to pass test_flickableY_bug1201452() of tst_page13

1673. By Tim Peeters

update header flickable when page flickable is updated.

1674. By Tim Peeters

clean

1675. By Tim Peeters

better contentY computation

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

No complains! Starts to shape up nicely!

review: Approve
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 'components.api'
2--- components.api 2015-10-01 12:49:42 +0000
3+++ components.api 2015-10-01 21:23:26 +0000
4@@ -687,6 +687,7 @@
5 readonly property Action actions
6 property Action backAction
7 property Item contents
8+ property Flickable flickable
9 property color foregroundColor
10 property bool locked
11 property string preset
12
13=== modified file 'src/Ubuntu/Components/1.3/AppHeader.qml'
14--- src/Ubuntu/Components/1.3/AppHeader.qml 2015-09-03 13:27:13 +0000
15+++ src/Ubuntu/Components/1.3/AppHeader.qml 2015-10-01 21:23:26 +0000
16@@ -23,19 +23,13 @@
17 \inqmlmodule Ubuntu.Components 1.1
18 \ingroup ubuntu
19 */
20-Components.StyledItem {
21+Components.Header {
22 id: header
23
24 anchors {
25 left: parent.left
26 right: parent.right
27 }
28- y: 0
29-
30- /*!
31- Animate showing and hiding of the header.
32- */
33- property bool animate: true
34
35 /*!
36 The background color of the divider. Value set by MainView.
37@@ -47,79 +41,19 @@
38 */
39 property color panelColor
40
41- Behavior on y {
42- enabled: animate && !(header.flickable && header.flickable.moving)
43- SmoothedAnimation {
44- duration: Components.UbuntuAnimation.BriskDuration
45- }
46- }
47-
48- /*! \internal */
49- onHeightChanged: {
50- internal.checkFlickableMargins();
51- internal.movementEnded();
52- if (header.config.visible) {
53- header.show();
54- } else {
55- header.hide();
56- }
57- }
58-
59- // with PageHeadConfiguration 1.2, always be visible.
60- visible: title || contents || tabsModel || internal.newConfig
61- onVisibleChanged: {
62- internal.checkFlickableMargins();
63- }
64- enabled: header.y === 0
65-
66- /*!
67- Show the header
68- */
69- function show() {
70- if (internal.newConfig) {
71- header.config.visible = true;
72- }
73- // Enable the header as soon as it finished animating
74- // to the fully visible state:
75- header.enabled = Qt.binding(function() { return header.y === 0; });
76- header.y = 0;
77- }
78-
79- /*!
80- Hide the header
81- */
82- function hide() {
83- if (internal.newConfig) {
84- header.config.visible = false;
85- }
86- // Disable the header immediately (the update of the y-value
87- // is delayed because of the Behavior defined on it):
88- header.enabled = false;
89- header.y = -header.height;
90- }
91+ // prevent triggering buttons in the header when it is moving
92+ enabled: header.exposed && !header.moving
93
94 /*!
95 The text to display in the header
96 */
97 property string title: ""
98- onTitleChanged: {
99- // deprecated for new versions of PageHeadConfiguration
100- if (!internal.newConfig) {
101- header.show();
102- }
103- }
104
105 /*!
106 The contents of the header. If this is set, \l title will be ignored.
107 DEPRECATED and replaced by Page.head.contents.
108 */
109 property Item contents: null
110- onContentsChanged: {
111- // deprecated for new versions of PageHeadConfiguration
112- if (!internal.newConfig) {
113- header.show();
114- }
115- }
116
117 /*!
118 A model of tabs to represent in the header.
119@@ -171,19 +105,6 @@
120 }
121
122 /*!
123- The flickable that controls the movement of the header.
124- Will be set automatically by Pages inside a MainView, but can
125- be overridden.
126- */
127- property Flickable flickable: null
128- onFlickableChanged: {
129- internal.connectFlickable();
130- if (!internal.newConfig || !header.config.locked) {
131- header.show();
132- }
133- }
134-
135- /*!
136 Configuration of the header.
137 FIXME: Must be of type PageHeadConfiguration. Setting that as the property type
138 however will use the latest version (1.3) and a Page that uses an older
139@@ -191,160 +112,41 @@
140 */
141 property QtObject config: null
142 onConfigChanged: {
143- // set internal.newConfig because when we rely on the binding,
144- // the value of newConfig may be updated after executing the code below.
145- internal.newConfig = config && config.hasOwnProperty("visible") &&
146- config.hasOwnProperty("locked");
147- internal.connectFlickable();
148+ if (header.config.locked) {
149+ header.flickable = null;
150+ } else {
151+ header.flickable = header.config.flickable;
152+ }
153
154- if (internal.newConfig && header.config.locked &&!header.config.visible) {
155- header.hide();
156+ if (!header.flickable && !header.config.visible) {
157+ // locked.
158+ header.exposed = false;
159 } else {
160- header.show();
161+ header.config.visible = true;
162+ header.exposed = true;
163+ }
164+ }
165+ onExposedChanged: {
166+ if(header.config) {
167+ header.config.visible = exposed;
168 }
169 }
170 Connections {
171 target: header.config
172- ignoreUnknownSignals: true // PageHeadConfiguration <1.2 lacks the signals below
173+ ignoreUnknownSignals: true
174 onVisibleChanged: {
175- if (header.config.visible) {
176- header.show();
177+ header.exposed = header.config.visible;
178+ }
179+ onLockedChanged: {
180+ if (header.config.locked) {
181+ header.flickable = null;
182 } else {
183- header.hide();
184+ header.flickable = header.config.flickable;
185 }
186- internal.checkFlickableMargins();
187 }
188- onLockedChanged: {
189- internal.connectFlickable();
190+ onFlickableChanged: {
191 if (!header.config.locked) {
192- internal.movementEnded();
193- }
194- }
195- }
196-
197- /*!
198- The header is not fully opened or fully closed.
199-
200- This property is true if the header is animating towards a fully
201- opened or fully closed state, or if the header is moving due to user
202- interaction with the flickable.
203-
204- The value of moving is always false when using an old version of
205- PageHeadConfiguration (which does not have the visible property).
206-
207- Used in tst_header_locked_visible.qml.
208- */
209- readonly property bool moving: internal.newConfig &&
210- ((config.visible && header.y !== 0) ||
211- (!config.visible && header.y !== -header.height))
212-
213- QtObject {
214- id: internal
215-
216- // This property is updated in header.onConfigChanged to ensure it
217- // is updated before other functions are called in onConfigChanged.
218- property bool newConfig: header.config &&
219- header.config.hasOwnProperty("locked") &&
220- header.config.hasOwnProperty("visible")
221-
222- /*!
223- Track the y-position inside the flickable.
224- */
225- property real previousContentY: 0
226-
227- /*!
228- The previous flickable to disconnect events
229- */
230- property Flickable previousFlickable: null
231-
232- /*!
233- Disconnect previous flickable, and connect the new one.
234- */
235- function connectFlickable() {
236- // Finish the current header movement in case the current
237- // flickable is disconnected while scrolling:
238- internal.movementEnded();
239-
240- if (previousFlickable) {
241- previousFlickable.contentYChanged.disconnect(internal.scrollContents);
242- previousFlickable.movementEnded.disconnect(internal.movementEnded);
243- previousFlickable.interactiveChanged.disconnect(internal.interactiveChanged);
244- previousFlickable = null;
245- }
246- if (flickable && !(internal.newConfig && header.config.locked)) {
247- // Connect flicking to movements of the header
248- previousContentY = flickable.contentY;
249- flickable.contentYChanged.connect(internal.scrollContents);
250- flickable.movementEnded.connect(internal.movementEnded);
251- flickable.interactiveChanged.connect(internal.interactiveChanged);
252- flickable.contentHeightChanged.connect(internal.contentHeightChanged);
253- previousFlickable = flickable;
254- }
255- internal.checkFlickableMargins();
256- }
257-
258- /*!
259- Update the position of the header to scroll with the flickable.
260- */
261- function scrollContents() {
262- // Avoid updating header.y when rebounding or being dragged over the bounds.
263- if (!flickable.atYBeginning && !flickable.atYEnd) {
264- var deltaContentY = flickable.contentY - previousContentY;
265- // FIXME: MathUtils.clamp is expensive. Fix clamp, or replace it here.
266- header.y = MathUtils.clamp(header.y - deltaContentY, -header.height, 0);
267- }
268- previousContentY = flickable.contentY;
269- }
270-
271- /*!
272- Fully show or hide the header, depending on its current y.
273- */
274- function movementEnded() {
275- if (!(internal.newConfig && header.config.locked)) {
276- if ( (flickable && flickable.contentY < 0) ||
277- (header.y > -header.height/2)) {
278- header.show();
279- } else {
280- header.hide();
281- }
282- }
283- }
284-
285- /*
286- Content height of flickable changed
287- */
288- function contentHeightChanged() {
289- if (flickable && flickable.height >= flickable.contentHeight) header.show();
290- }
291-
292- /*
293- Flickable became interactive or non-interactive.
294- */
295- function interactiveChanged() {
296- if (flickable && !flickable.interactive) header.show();
297- }
298-
299- /*
300- Check the topMargin of the flickable and set it if needed to avoid
301- contents becoming unavailable behind the header.
302- */
303- function checkFlickableMargins() {
304- if (header.flickable) {
305- var headerHeight = 0;
306- if (header.visible && !(internal.newConfig &&
307- header.config.locked &&
308- !header.config.visible)) {
309- headerHeight = header.height;
310- }
311-
312- if (flickable.topMargin !== headerHeight) {
313- var oldContentY = flickable.contentY;
314- var previousHeaderHeight = flickable.topMargin;
315- flickable.topMargin = headerHeight;
316- // push down contents when header grows,
317- // pull up contents when header shrinks.
318- flickable.contentY = oldContentY - headerHeight + previousHeaderHeight;
319- }
320+ header.flickable = header.config.flickable;
321 }
322 }
323 }
324
325=== modified file 'src/Ubuntu/Components/1.3/MainView.qml'
326--- src/Ubuntu/Components/1.3/MainView.qml 2015-09-29 14:15:35 +0000
327+++ src/Ubuntu/Components/1.3/MainView.qml 2015-10-01 21:23:26 +0000
328@@ -161,7 +161,6 @@
329 panelColor: Qt.lighter(mainView.headerColor, 1.1)
330
331 title: internal.activePage ? internal.activePage.title : ""
332- flickable: internal.activePage ? internal.activePage.flickable : null
333 pageStack: internal.activePage ? internal.activePage.pageStack : null
334
335 contents: internal.activePage &&
336@@ -199,7 +198,7 @@
337 if (!(headerItem.config &&
338 headerItem.config.hasOwnProperty("locked") &&
339 headerItem.config.locked)) {
340- headerItem.show();
341+ headerItem.exposed = true;
342 }
343 }
344 }
345
346=== modified file 'src/Ubuntu/Components/1.3/Page.qml'
347--- src/Ubuntu/Components/1.3/Page.qml 2015-07-03 14:53:08 +0000
348+++ src/Ubuntu/Components/1.3/Page.qml 2015-10-01 21:23:26 +0000
349@@ -44,6 +44,7 @@
350 Toolkit13.PageHeadConfiguration {
351 id: headerConfig
352 title: page.title
353+ flickable: page.flickable
354 }
355
356 Toolkit13.Object {
357
358=== modified file 'src/Ubuntu/Components/1.3/PageHeadConfiguration.qml'
359--- src/Ubuntu/Components/1.3/PageHeadConfiguration.qml 2015-06-15 07:45:34 +0000
360+++ src/Ubuntu/Components/1.3/PageHeadConfiguration.qml 2015-10-01 21:23:26 +0000
361@@ -55,7 +55,8 @@
362 property bool locked: false
363
364 // auto-updated by AppHeader, but may be set by the developer
365- property bool visible
366+ property bool visible: true
367
368 property string title
369+ property Flickable flickable
370 }
371
372=== modified file 'src/Ubuntu/Components/plugin/ucheader.cpp'
373--- src/Ubuntu/Components/plugin/ucheader.cpp 2015-09-23 11:35:33 +0000
374+++ src/Ubuntu/Components/plugin/ucheader.cpp 2015-10-01 21:23:26 +0000
375@@ -111,9 +111,12 @@
376 if (m_exposed || (!m_flickable.isNull() && m_flickable->contentY() <= 0.0)) {
377 // Header was exposed before, or the flickable is scrolled up close to
378 // the top so that the header should be visible.
379- show();
380+ // After Header completed, the theming engine updates its implicitHeight
381+ // to that of the style and we do not want to animate then. Other height
382+ // changes also do not need animations.
383+ show(false);
384 } else {
385- hide();
386+ hide(false);
387 }
388 }
389
390@@ -151,11 +154,22 @@
391
392 // Finish the current header movement in case the current
393 // flickable is disconnected while scrolling.
394- _q_flickableMovementEnded();
395+ if (m_exposed) {
396+ show(false);
397+ } else {
398+ hide(false);
399+ }
400 m_flickable->disconnect(this);
401
402+ qreal oldMargin = m_flickable->topMargin();
403+ // store contentY to compensate for Flickable updating the position due to margin change.
404+ qreal oldContentY = m_flickable->contentY();
405 delete m_flickableTopMarginBackup; // Restores previous value/binding for topMargin.
406 m_flickableTopMarginBackup = Q_NULLPTR;
407+
408+ qreal delta = m_flickable->topMargin() - oldMargin + m_flickable->contentY() - oldContentY;
409+ // revert the flickable content Y.
410+ m_flickable->setContentY(m_flickable->contentY() - delta);
411 }
412
413 m_flickable = flickable;
414@@ -164,6 +178,7 @@
415 Q_ASSERT(m_flickableTopMarginBackup == Q_NULLPTR);
416 if (!m_flickable.isNull()) {
417 m_flickableTopMarginBackup = new PropertyChange(m_flickable, "topMargin");
418+ updateFlickableMargins();
419 connect(m_flickable, SIGNAL(contentYChanged()),
420 this, SLOT(_q_scrolledContents()));
421 connect(m_flickable, SIGNAL(movementEnded()),
422@@ -173,8 +188,7 @@
423 connect(m_flickable, SIGNAL(interactiveChanged()),
424 this, SLOT(_q_flickableInteractiveChanged()));
425 m_previous_contentY = m_flickable->contentY();
426- updateFlickableMargins();
427- show();
428+ _q_flickableMovementEnded(); // show or hide depending on y
429 }
430 }
431
432@@ -193,7 +207,7 @@
433 }
434 }
435
436-void UCHeader::show() {
437+void UCHeader::show(bool animate) {
438 if (!m_exposed) {
439 m_exposed = true;
440 Q_EMIT exposedChanged();
441@@ -202,11 +216,14 @@
442 m_showHideAnimation->stop();
443 }
444 }
445- if (isComponentComplete()) {
446+
447+ if (animate && isComponentComplete()) {
448 m_showHideAnimation->setFrom(y());
449 m_showHideAnimation->setTo(0.0);
450 m_showHideAnimation->start();
451 } else {
452+ // If a previous animation was showing the header, stop it.
453+ m_showHideAnimation->stop();
454 this->setY(0.0);
455 if (m_moving) {
456 m_moving = false;
457@@ -215,7 +232,7 @@
458 }
459 }
460
461-void UCHeader::hide() {
462+void UCHeader::hide(bool animate) {
463 if (m_exposed) {
464 m_exposed = false;
465 Q_EMIT exposedChanged();
466@@ -224,11 +241,14 @@
467 m_showHideAnimation->stop();
468 }
469 }
470- if (isComponentComplete()) {
471+
472+ if (animate && isComponentComplete()) {
473 m_showHideAnimation->setFrom(y());
474 m_showHideAnimation->setTo(-1.0*height());
475 m_showHideAnimation->start();
476 } else {
477+ // If a previous animation was hiding the header, stop it.
478+ m_showHideAnimation->stop();
479 this->setY(-1.0*height());
480 if (m_moving) {
481 m_moving = false;
482
483=== modified file 'src/Ubuntu/Components/plugin/ucheader.h'
484--- src/Ubuntu/Components/plugin/ucheader.h 2015-09-22 18:24:27 +0000
485+++ src/Ubuntu/Components/plugin/ucheader.h 2015-10-01 21:23:26 +0000
486@@ -47,8 +47,8 @@
487 void movingChanged();
488
489 protected:
490- void show();
491- void hide();
492+ void show(bool animate = true);
493+ void hide(bool animate = true);
494
495 private Q_SLOTS:
496 void _q_scrolledContents();
497
498=== modified file 'tests/unit_x11/tst_components/tst_header.qml'
499--- tests/unit_x11/tst_components/tst_header.qml 2015-09-22 14:13:36 +0000
500+++ tests/unit_x11/tst_components/tst_header.qml 2015-10-01 21:23:26 +0000
501@@ -46,8 +46,13 @@
502
503 Flickable {
504 id: flickable
505- anchors.fill: parent
506- contentHeight: height * 2
507+ anchors {
508+ top: header.flickable ? parent.top : header.bottom
509+ left: parent.left
510+ right: parent.right
511+ bottom: parent.bottom
512+ }
513+ contentHeight: root.height * 2
514
515 Grid {
516 id: switchGrid
517@@ -56,7 +61,8 @@
518 anchors {
519 top: parent.top
520 left: parent.left
521- margins: units.gu(5)
522+ leftMargin: units.gu(5)
523+ topMargin: 2*root.initialHeaderHeight
524 }
525 Switch {
526 id: lockedSwitch
527@@ -151,6 +157,12 @@
528 id: otherHeader
529 }
530
531+ Header {
532+ id: hiddenHeader
533+ exposed: false
534+ height: root.initialHeaderHeight
535+ }
536+
537 UbuntuTestCase {
538 name: "Header"
539 when: windowShown
540@@ -201,6 +213,12 @@
541 }
542 }
543
544+ function test_0_initially_hidden() {
545+ // Don't show an animation if the header is hidden initially.
546+ compare(hiddenHeader.y, -header.height,
547+ "Hidden header has wrong initial y-value.");
548+ }
549+
550 function test_reparent_width() {
551 // test initial header width:
552 compare(header.parent, root);
553@@ -288,7 +306,7 @@
554 wait_for_exposed(true);
555 }
556
557- function test_scroll_updates_visible() {
558+ function test_scroll_updates_exposed() {
559 scroll_down();
560 wait_for_exposed(false, "Scrolling down does not hide header.");
561 scroll_up();
562
563=== modified file 'tests/unit_x11/tst_components/tst_page13.qml'
564--- tests/unit_x11/tst_components/tst_page13.qml 2015-03-23 16:16:46 +0000
565+++ tests/unit_x11/tst_components/tst_page13.qml 2015-10-01 21:23:26 +0000
566@@ -86,7 +86,7 @@
567 page.flickable = testFlickable;
568 compare(page.flickable, testFlickable, "Flickable could not be set.");
569 compare(header.flickable, testFlickable,
570- "Header flickable was not update correctly.");
571+ "Header flickable was not updated correctly.");
572
573 page.flickable = null;
574 compare(page.flickable, null, "Flickable cannot be unset.");
575@@ -113,7 +113,7 @@
576 compare(page.flickable.contentY, flickableY + headerHeight,
577 "contentY was not updated properly when header was hidden.");
578
579- page.head.locked.locked = false;
580+ page.head.locked = false;
581 page.head.visible = true;
582 waitForHeaderAnimation(mainView);
583
584
585=== modified file 'tests/unit_x11/tst_components/tst_pagehead_visible.qml'
586--- tests/unit_x11/tst_components/tst_pagehead_visible.qml 2015-09-03 11:44:38 +0000
587+++ tests/unit_x11/tst_components/tst_pagehead_visible.qml 2015-10-01 21:23:26 +0000
588@@ -35,10 +35,6 @@
589 id: page
590 title: "Auto-hide"
591 head {
592- locked: lockedSwitch.checked
593- onVisibleChanged: {
594- visibleSwitch.checked = page.head.visible
595- }
596 actions: Action {
597 iconName: "like"
598 text: "Like"
599@@ -71,7 +67,11 @@
600 }
601 Switch {
602 id: lockedSwitch
603- checked: false
604+ checked: page.head.locked
605+ function trigger() {
606+ page.head.locked = !page.head.locked;
607+ print("set page.head.locked to "+page.head.locked)
608+ }
609 }
610 Label {
611 text: "header locked"
612@@ -79,7 +79,10 @@
613 Switch {
614 id: visibleSwitch
615 checked: page.head.visible
616- onClicked: page.head.visible = checked
617+ function trigger() {
618+ page.head.visible = !page.head.visible;
619+ print("set page.head.visible to "+page.head.visible)
620+ }
621 }
622 Label {
623 text: "header visible"

Subscribers

People subscribed via source and target branches