@@ -40,28 +40,79 @@ PreviewWidget {
41 implicitHeight: childrenRect.height
41 implicitHeight: childrenRect.height
43− Column {
43+ onIsCurrentPreviewChanged: ratingsList.updateRanges();
44+ onParentFlickableChanged: ratingsList.updateRanges();
47+ target: parentFlickable
48+ onOriginYChanged: ratingsList.updateRanges();
49+ onContentYChanged: ratingsList.updateRanges();
50+ onHeightChanged: ratingsList.updateRanges();
51+ onContentHeightChanged: ratingsList.updateRanges();
44 anchors { left: parent.left; right: parent.right; }
56 anchors { left: parent.left; right: parent.right; }
45− visible: reviewsRepeater.count > 0
57+ height: contentHeight
60+ model: root.widgetData["reviews"]
62+ delegate: PreviewRatingSingleDisplay {
64+ objectName: "reviewItem" + index
47− Repeater {
66+ anchors { left: parent.left; right: parent.right; }
49− objectName: "reviewsRepeater"
50− model: root.widgetData["reviews"]
52− delegate: PreviewRatingSingleDisplay {
68+ rating: modelData["rating"] || -1
53− objectName: "reviewItem" + index
69+ author: modelData["author"] || ""
70+ review: modelData["review"] || ""
71+ urlIconEmpty: widgetData["rating-icon-empty"]
72+ urlIconFull: widgetData["rating-icon-full"]
73+ urlIconHalf: widgetData["rating-icon-half"]
74+ labelColor: scopeStyle ? scopeStyle.foreground : theme.palette.normal.baseText
77+ onContentHeightChanged: ratingsList.updateRanges();
55− anchors { left: parent.left; right: parent.right; }
79+ function updateRanges() {
80+ var baseItem = root.parent;
81+ if (!parentFlickable || !baseItem) {
82+ ratingsList.displayMarginBeginning = 0;
83+ ratingsList.displayMarginEnd = 0;
57− rating: modelData["rating"] || -1
87+ if (parentFlickable.moving) {
58− author: modelData["author"] || ""
88+ // Do not update the range if we are overshooting up or down, since we'll come back
59− review: modelData["review"] || ""
89+ // to the stable position and delete/create items without any reason
60− urlIconEmpty: widgetData["rating-icon-empty"]
90+ if (parentFlickable.contentY < parentFlickable.originY) {
61− urlIconFull: widgetData["rating-icon-full"]
91+ return;
62− urlIconHalf: widgetData["rating-icon-half"]
92+ } else if (parentFlickable.contentHeight - parentFlickable.originY > parentFlickable.height &&
63− labelColor: scopeStyle ? scopeStyle.foreground : theme.palette.normal.baseText
93+ parentFlickable.contentY + parentFlickable.height > parentFlickable.contentHeight) {
98+ // A item view creates its delegates synchronously from
99+ // -displayMarginBeginning
101+ // height + displayMarginEnd
102+ // Around that area it adds the cacheBuffer area where delegates are created async
104+ // We adjust displayMarginEnd to be negative so that the range of created delegates matches
105+ // from the beginning of the list to the end of the viewport.
106+ // Ideally we would also use displayMarginBeginning
107+ // so that delegates at the beginning get destroyed but that causes issues with
108+ // listview and is not really necessary to provide the better experience we're after
109+ var itemYOnViewPort = baseItem.y - parentFlickable.contentY;
110+ var displayMarginEnd = -ratingsList.contentHeight + parentFlickable.height - itemYOnViewPort;
111+ displayMarginEnd = -Math.max(-displayMarginEnd, 0);
112+ displayMarginEnd = -Math.min(-displayMarginEnd, ratingsList.contentHeight);
113+ displayMarginEnd = Math.round(displayMarginEnd);
115+ ratingsList.displayMarginEnd = displayMarginEnd;