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

Proposed by Tim Peeters on 2015-10-01
Status: Merged
Approved by: Zsombor Egri on 2015-10-02
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 2015-10-01 Approve on 2015-10-02
Zsombor Egri (community) 2015-10-01 Approve on 2015-10-02
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 on 2015-10-01

clean MainView.qml

1670. By Tim Peeters on 2015-10-01

sync staging

1671. By Tim Peeters on 2015-10-01

fix page positioning with locked header

1672. By Tim Peeters on 2015-10-01

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

1673. By Tim Peeters on 2015-10-01

update header flickable when page flickable is updated.

1674. By Tim Peeters on 2015-10-01

clean

1675. By Tim Peeters on 2015-10-01

better contentY computation

Zsombor Egri (zsombi) wrote :

No complains! Starts to shape up nicely!

review: Approve
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