on xenial help sign in
Refactor carousel item activation.
0591307Michał Sawicz
qml/Components/BaseCarouselDelegate.qml+19
@@ -17,7 +17,26 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19
19
20+/*!
21+ \brief Base delegate for use with the Carousel component
22+
23+ Use this as the base of your component in a Carousel, the properties
24+ will get updated and signals emitted accordingly.
25+*/
26+
20Item {
27Item {
28+ /// True if this item is currently "focused" in the carousel.
21 property bool explicitlyScaled
29 property bool explicitlyScaled
30+
31+ /// Model index for this delegate.
32+ property int index
33+
34+ /// Model data for this delegate.
22 property var model
35 property var model
36+
37+ /// Will be emitted when the item is tapped.
38+ signal clicked
39+
40+ /// Will be emitted when the item is long-pressed.
41+ signal pressAndHold
23}
42}
qml/Components/Carousel.qml+5−14
@@ -52,16 +52,6 @@ Item {
52 /// exposes the distance to the next row (only one row in carousel, so it's the topMargins)
52 /// exposes the distance to the next row (only one row in carousel, so it's the topMargins)
53 readonly property alias verticalSpacing: listView.verticalMargin
53 readonly property alias verticalSpacing: listView.verticalMargin
54
54
55− /// Emitted when the user clicked on an item
56− /// @param index is the index of the clicked item
57− /// @param itemY is y of the clicked delegate
58− signal clicked(int index, real itemY)
59−
60− /// Emitted when the user pressed and held on an item
61− /// @param index is the index of the held item
62− /// @param itemY is y of the held delegate
63− signal pressAndHold(int index, real itemY)
64−
65 implicitHeight: listView.tileHeight * selectedItemScaleFactor
55 implicitHeight: listView.tileHeight * selectedItemScaleFactor
66 opacity: listView.highlightIndex === -1 ? 1 : 0.6
56 opacity: listView.highlightIndex === -1 ? 1 : 0.6
67
57
@@ -167,7 +157,7 @@ Item {
167 /* We're clicking the selected item and
157 /* We're clicking the selected item and
168 we're in the neighbourhood of radius 1 pixel from it.
158 we're in the neighbourhood of radius 1 pixel from it.
169 Let's emit the clicked signal. */
159 Let's emit the clicked signal. */
170− carousel.clicked(index, delegateItem.y)
160+ delegateItem.clicked()
171 return
161 return
172 }
162 }
173
163
@@ -185,7 +175,7 @@ Item {
185 /* We're pressAndHold the selected item and
175 /* We're pressAndHold the selected item and
186 we're in the neighbourhood of radius 1 pixel from it.
176 we're in the neighbourhood of radius 1 pixel from it.
187 Let's emit the pressAndHold signal. */
177 Let's emit the pressAndHold signal. */
188− carousel.pressAndHold(index, delegateItem.y);
178+ delegateItem.pressAndHold();
189 return;
179 return;
190 }
180 }
191
181
@@ -316,8 +306,9 @@ Item {
316 }
306 }
317
307
318 onLoaded: {
308 onLoaded: {
319− item.explicitlyScaled = Qt.binding(function() { return explicitlyScaled; })
309+ item.explicitlyScaled = Qt.binding(function() { return explicitlyScaled; });
310+ item.index = Qt.binding(function() { return index; });
320− item.model = Qt.binding(function() { return model; })
311+ item.model = Qt.binding(function() { return model; });
321 }
312 }
322
313
323 MouseArea {
314 MouseArea {
qml/Dash/CardCarousel.qml+6−4
@@ -40,9 +40,6 @@ DashRenderer {
40 cacheBuffer: 1404 // 18px * 13gu * 6
40 cacheBuffer: 1404 // 18px * 13gu * 6
41 model: cardCarousel.model
41 model: cardCarousel.model
42
42
43− onClicked: cardCarousel.clicked(index, null)
44− onPressAndHold: cardCarousel.pressAndHold(index)
45−
46 property real fontScale: 1 / selectedItemScaleFactor
43 property real fontScale: 1 / selectedItemScaleFactor
47 property real headerHeight: cardTool.headerHeight / selectedItemScaleFactor
44 property real headerHeight: cardTool.headerHeight / selectedItemScaleFactor
48
45
@@ -51,11 +48,16 @@ DashRenderer {
51
48
52 property bool explicitlyScaled
49 property bool explicitlyScaled
53 property var model
50 property var model
51+ property int index
54 enabled: false
52 enabled: false
55
53
54+ objectName: "carouselDelegate" + index
55+
56+ function clicked() { cardCarousel.clicked(index, model.result) }
57+ function pressAndHold() { cardCarousel.pressAndHold(index, model.result) }
58+
56 sourceComponent: cardTool.cardComponent
59 sourceComponent: cardTool.cardComponent
57 onLoaded: {
60 onLoaded: {
58− item.objectName = "carouselDelegate" + index;
59 item.fixedHeaderHeight = Qt.binding(function() { return carousel.headerHeight; });
61 item.fixedHeaderHeight = Qt.binding(function() { return carousel.headerHeight; });
60 item.height = Qt.binding(function() { return cardTool.cardHeight; });
62 item.height = Qt.binding(function() { return cardTool.cardHeight; });
61 item.cardData = Qt.binding(function() { return model; });
63 item.cardData = Qt.binding(function() { return model; });
tests/qmltests/Components/tst_Carousel.qml+48−2
@@ -27,12 +27,13 @@ Item {
27 Carousel {
27 Carousel {
28 anchors.fill: parent
28 anchors.fill: parent
29 id: carousel
29 id: carousel
30− model: 40
31
30
32 property int createdDelegates: 0
31 property int createdDelegates: 0
33 property int destroyedDelegates: 0
32 property int destroyedDelegates: 0
34
33
35 itemComponent: BaseCarouselDelegate {
34 itemComponent: BaseCarouselDelegate {
35+ objectName: "carouselDelegate" + index
36+
36 Rectangle {
37 Rectangle {
37 anchors.fill: parent
38 anchors.fill: parent
38 border.color: "black"
39 border.color: "black"
@@ -42,6 +43,11 @@ Item {
42 }
43 }
43 }
44 }
44 }
45 }
46+
47+ SignalSpy {
48+ id: spy
49+ }
50+
45 UT.UnityTestCase {
51 UT.UnityTestCase {
46 id: root
52 id: root
47 name: "Carousel"
53 name: "Carousel"
@@ -51,6 +57,8 @@ Item {
51 property int itemCount
57 property int itemCount
52 property real tileWidth
58 property real tileWidth
53
59
60+ property Item listView: findChild(carousel, "listView")
61+
54 property real contentWidth: itemCount * tileWidth
62 property real contentWidth: itemCount * tileWidth
55 // following variables are copied from Carousel.qml
63 // following variables are copied from Carousel.qml
56 // I'm not using the variables directly from there, as then tileWidth and others would be affected as well
64 // I'm not using the variables directly from there, as then tileWidth and others would be affected as well
@@ -60,11 +68,25 @@ Item {
60 property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
68 property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
61 property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
69 property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
62
70
71+ function init() {
72+ carousel.model = 40;
73+ waitForRendering(carousel)
74+ listView.positionViewAtBeginning();
75+ }
76+
77+ function cleanup() {
78+ carousel.model = 0;
79+ carousel.createdDelegates = 0;
80+ carousel.destroyedDelegates = 0;
81+ spy.target = null;
82+ spy.signalName = "";
83+ }
84+
63 // This test needs to run first since it tests a corner case condition
85 // This test needs to run first since it tests a corner case condition
64 // to where the carousel is just being created
86 // to where the carousel is just being created
65 // That is why it has a 1 in the name
87 // That is why it has a 1 in the name
66 function test_1onlyNeededItemsCreated() {
88 function test_1onlyNeededItemsCreated() {
67− tryCompare(carousel, "createdDelegates", 10);
89+ tryCompare(carousel, "createdDelegates", 9);
68 compare(carousel.destroyedDelegates, 0);
90 compare(carousel.destroyedDelegates, 0);
69 }
91 }
70
92
@@ -243,5 +265,29 @@ Item {
243 var x = carouselList.getXFromContinuousIndex(carousel.model - 1);
265 var x = carouselList.getXFromContinuousIndex(carousel.model - 1);
244 verify(Math.abs(x - carouselList.contentX) < 1);
266 verify(Math.abs(x - carouselList.contentX) < 1);
245 }
267 }
268+
269+ function test_activate() {
270+ var carouselList = findChild(carousel, "listView");
271+ tryCompareFunction(function() { return findChild(carouselList, "carouselDelegate3") ? true : false; }, true);
272+ var carouselItem = findChild(carousel, "carouselDelegate3")
273+ verify(carouselItem, "Could not find delegate");
274+
275+ spy.signalName = "clicked";
276+ spy.target = carouselItem;
277+ mouseClick(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
278+ tryCompare(carouselList, "moving", false);
279+ tryCompare(carouselItem, "explicitlyScaled", true);
280+ mouseClick(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
281+ spy.wait();
282+
283+ spy.signalName = "pressAndHold";
284+ spy.target = carouselItem;
285+ mouseClick(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
286+ tryCompare(carouselList, "moving", false);
287+ tryCompare(carouselItem, "explicitlyScaled", true);
288+ mousePress(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
289+ spy.wait();
290+ mouseRelease(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
291+ }
246 }
292 }
247}
293}
tests/qmltests/Dash/tst_DashContent.qml+4−2
@@ -279,7 +279,7 @@ Item {
279 if (scope != null) {
279 if (scope != null) {
280 var dashCategory1 = findChild(scope, "dashCategory1");
280 var dashCategory1 = findChild(scope, "dashCategory1");
281 if (dashCategory1 != null) {
281 if (dashCategory1 != null) {
282− var tile = findChild(dashCategory1, "carouselDelegate1");
282+ var tile = findChild(dashCategory1, "carouselDelegate3");
283 return tile != null;
283 return tile != null;
284 }
284 }
285 }
285 }
@@ -292,7 +292,9 @@ Item {
292
292
293 var scope = findChild(dashContent, "MockScope1 loader");
293 var scope = findChild(dashContent, "MockScope1 loader");
294 var dashCategory1 = findChild(scope, "dashCategory1");
294 var dashCategory1 = findChild(scope, "dashCategory1");
295− var tile = findChild(dashCategory1, "carouselDelegate1");
295+ var tile = findChild(dashCategory1, "carouselDelegate3");
296+ mouseClick(tile, tile.width / 2, tile.height / 2);
297+ tryCompare(tile, "explicitlyScaled", true);
296 mouseClick(tile, tile.width / 2, tile.height / 2);
298 mouseClick(tile, tile.width / 2, tile.height / 2);
297 tryCompare(previewListView, "open", true);
299 tryCompare(previewListView, "open", true);
298 tryCompare(previewListView, "x", 0);
300 tryCompare(previewListView, "x", 0);