on xenial help sign in
Fix binding loop in FilterGrid height
3d3a8ccAlbert Astals
qml/Components/FilterGrid.qml+34−20
@@ -30,7 +30,7 @@ Item {
30
30
31 /* If true, the number of elements displayed will be limited by collapsedRowCount.
31 /* If true, the number of elements displayed will be limited by collapsedRowCount.
32 If false, all elements will be displayed, effectively looking the same as a regular
32 If false, all elements will be displayed, effectively looking the same as a regular
33− ResponsiveGridView. */
33+ ResponsiveGridView. Manipulate this property through setFilter */
34 property bool filter: true
34 property bool filter: true
35
35
36 /* Whether, when collapsed, a button should be displayed enabling the user to expand
36 /* Whether, when collapsed, a button should be displayed enabling the user to expand
@@ -66,29 +66,35 @@ Item {
66 property alias highlightIndex: iconTileGrid.highlightIndex
66 property alias highlightIndex: iconTileGrid.highlightIndex
67 readonly property alias currentItem: iconTileGrid.currentItem
67 readonly property alias currentItem: iconTileGrid.currentItem
68
68
69− height: !filterAnimation.running ? childrenRect.height : height
69+ height: filter ? root.collapsedHeight : root.uncollapsedHeight
70 clip: filterAnimation.running
70 clip: filterAnimation.running
71
71
72+ Behavior on height {
73+ id: heightBehaviour
74+ enabled: false
72− NumberAnimation {
75+ NumberAnimation {
73− property bool filterEndValue
74− id: filterAnimation
76+ id: filterAnimation
75− target: root
76− property: "height"
77− to: filterEndValue ? root.collapsedHeight : root.uncollapsedHeight
78− // Duration and easing here match the ListViewWithPageHeader::m_contentYAnimation
77+ // Duration and easing here match the ListViewWithPageHeader::m_contentYAnimation
79− // otherwise since both animations can run at the same time you'll get
78+ // otherwise since both animations can run at the same time you'll get
80− // some visual weirdness.
79+ // some visual weirdness.
81− duration: 200
80+ duration: 200
82− easing.type: Easing.InOutQuad
81+ easing.type: Easing.InOutQuad
83− onStopped: {
82+ onRunningChanged: {
83+ if (!running) {
84− root.filter = filterEndValue;
84+ limitModel.filter = root.filter;
85+ }
86+ heightBehaviour.enabled = false;
87+ }
85 }
88 }
86 }
89 }
87
90
88− function startFilterAnimation(filter) {
91+ function setFilter(filter, animate) {
89− filterAnimation.filterEndValue = filter
92+ heightBehaviour.enabled = animate;
90− filterAnimation.start();
93+ root.filter = filter;
94+ if (!animate || !filter) {
95+ limitModel.filter = filter;
96+ }
91− }
97+ }
92
98
93 ResponsiveGridView {
99 ResponsiveGridView {
94 id: iconTileGrid
100 id: iconTileGrid
@@ -104,8 +110,16 @@ Item {
104 verticalSpacing: units.gu(2)
110 verticalSpacing: units.gu(2)
105
111
106 model: LimitProxyModel {
112 model: LimitProxyModel {
113+ id: limitModel
114+ // We do have another filter property here because
115+ // we can't directly use filter from the root since we need to decouple
116+ // the real filtering with the animation since the closing animation
117+ // i.e. filter=false we still need to not be filtering until
118+ // t he animation finishes otherwise we hide the items when the animation
119+ // is still running
120+ property bool filter: true
107 model: root.model
121 model: root.model
108− limit: (filter && !filterAnimation.running) ? rowsWhenCollapsed * iconTileGrid.columns : -1
122+ limit: filter ? rowsWhenCollapsed * iconTileGrid.columns : -1
109 }
123 }
110 }
124 }
111}
125}
qml/Dash/CardFilterGrid.qml+2−8
@@ -29,8 +29,8 @@ DashRenderer {
29 currentItem: filterGrid.currentItem
29 currentItem: filterGrid.currentItem
30 height: filterGrid.height
30 height: filterGrid.height
31
31
32− function startFilterAnimation(filter) {
32+ function setFilter(filter, animate) {
33− filterGrid.startFilterAnimation(filter)
33+ filterGrid.setFilter(filter, animate)
34 }
34 }
35
35
36 FilterGrid {
36 FilterGrid {
@@ -41,7 +41,6 @@ DashRenderer {
41 delegateHeight: cardTool.cardHeight
41 delegateHeight: cardTool.cardHeight
42 verticalSpacing: genericFilterGrid.verticalSpacing
42 verticalSpacing: genericFilterGrid.verticalSpacing
43 model: genericFilterGrid.model
43 model: genericFilterGrid.model
44− filter: genericFilterGrid.filter
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
44 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
45 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
46 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
@@ -66,10 +65,5 @@ DashRenderer {
66 onPressAndHold: genericFilterGrid.pressAndHold(index, card.y)
65 onPressAndHold: genericFilterGrid.pressAndHold(index, card.y)
67 }
66 }
68 }
67 }
69−
70− onFilterChanged: {
71− genericFilterGrid.filter = filter
72− filter = Qt.binding(function() { return genericFilterGrid.filter })
73− }
74 }
68 }
75}
69}
qml/Dash/DashRenderer.qml+1−4
@@ -20,9 +20,6 @@ Item {
20 // Can the item be expanded?
20 // Can the item be expanded?
21 property bool expandable: false
21 property bool expandable: false
22
22
23− // In case it can be expanded, should we filter it
24− property bool filter: true
25−
26 property int collapsedHeight: height
23 property int collapsedHeight: height
27
24
28 property int margins: 0
25 property int margins: 0
@@ -58,6 +55,6 @@ Item {
58 /// @param itemY is y of the held delegate
55 /// @param itemY is y of the held delegate
59 signal pressAndHold(int index, real itemY)
56 signal pressAndHold(int index, real itemY)
60
57
61− function startFilterAnimation(filter) {
58+ function setFilter(filter, animate) {
62 }
59 }
63}
60}
qml/Dash/GenericScopeView.qml+4−9
@@ -121,7 +121,7 @@ FocusScope {
121 showDivider: false
121 showDivider: false
122
122
123 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
123 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
124− readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
124+ readonly property bool filtered: categoryView.expandedCategoryId != categoryId
125 readonly property string category: categoryId
125 readonly property string category: categoryId
126 readonly property var item: rendererLoader.item
126 readonly property var item: rendererLoader.item
127
127
@@ -167,9 +167,7 @@ FocusScope {
167 item.objectName = Qt.binding(function() { return categoryId })
167 item.objectName = Qt.binding(function() { return categoryId })
168 if (item.expandable) {
168 if (item.expandable) {
169 var shouldFilter = categoryId != categoryView.expandedCategoryId;
169 var shouldFilter = categoryId != categoryView.expandedCategoryId;
170− if (shouldFilter != item.filter) {
170+ item.setFilter(shouldFilter, false /*animate*/);
171− item.filter = shouldFilter;
172− }
173 }
171 }
174 updateDelegateCreationRange();
172 updateDelegateCreationRange();
175 item.cardTool = cardTool;
173 item.cardTool = cardTool;
@@ -218,11 +216,8 @@ FocusScope {
218 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
216 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
219 var growingVisible = !shouldFilter && y + height < categoryView.height;
217 var growingVisible = !shouldFilter && y + height < categoryView.height;
220 if (!previewListView.open || !shouldFilter) {
218 if (!previewListView.open || !shouldFilter) {
221− if (shrinkingVisible || growingVisible) {
219+ var animate = shrinkingVisible || growingVisible;
222− item.startFilterAnimation(shouldFilter)
220+ item.setFilter(shouldFilter, animate)
223− } else {
224− item.filter = shouldFilter;
225− }
226 if (!shouldFilter && !previewListView.open) {
221 if (!shouldFilter && !previewListView.open) {
227 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
222 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
228 }
223 }