Unity 8
PreviewRatingDisplay.qml
1 /*
2  * Copyright (C) 2014,2015 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.4
18 import Ubuntu.Components 1.3
19 import "../../Components"
20 
21 /*! \brief Preview widget for rating display.
22 
23  The widget can show a rating widget and a field showing a comment.
24  The icons used in the rating widget can be customised with
25  widgetData["rating-icon-empty"], widgetData["rating-icon-full"]
26  and widgetData["rating-icon-half"].
27 
28  This widget shows reviews contained in widgetData["reviews"], each of which should be of the form:
29 
30  \code{.json}
31  {
32  "rating": null,
33  "review": null,
34  "author": null
35  }
36  \endcode
37  */
38 
39 PreviewWidget {
40  id: root
41  implicitHeight: childrenRect.height
42 
43  onIsCurrentPreviewChanged: ratingsList.updateRanges();
44  onParentFlickableChanged: ratingsList.updateRanges();
45 
46  Connections {
47  target: parentFlickable
48  onOriginYChanged: ratingsList.updateRanges();
49  onContentYChanged: ratingsList.updateRanges();
50  onHeightChanged: ratingsList.updateRanges();
51  onContentHeightChanged: ratingsList.updateRanges();
52  }
53 
54  ListView {
55  id: ratingsList
56  anchors { left: parent.left; right: parent.right; }
57  height: contentHeight
58  interactive: false
59 
60  model: root.widgetData["reviews"]
61 
62  delegate: PreviewRatingSingleDisplay {
63  id: prsd
64  objectName: "reviewItem" + index
65 
66  anchors { left: parent.left; right: parent.right; }
67 
68  rating: modelData["rating"] || -1
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
75  }
76 
77  onContentHeightChanged: ratingsList.updateRanges();
78 
79  function updateRanges() {
80  var baseItem = root.parent;
81  if (!parentFlickable || !baseItem) {
82  ratingsList.displayMarginBeginning = 0;
83  ratingsList.displayMarginEnd = 0;
84  return;
85  }
86 
87  if (parentFlickable.moving) {
88  // Do not update the range if we are overshooting up or down, since we'll come back
89  // to the stable position and delete/create items without any reason
90  if (parentFlickable.contentY < parentFlickable.originY) {
91  return;
92  } else if (parentFlickable.contentHeight - parentFlickable.originY > parentFlickable.height &&
93  parentFlickable.contentY + parentFlickable.height > parentFlickable.contentHeight) {
94  return;
95  }
96  }
97 
98  // A item view creates its delegates synchronously from
99  // -displayMarginBeginning
100  // to
101  // height + displayMarginEnd
102  // Around that area it adds the cacheBuffer area where delegates are created async
103  //
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);
114 
115  ratingsList.displayMarginEnd = displayMarginEnd;
116  }
117  }
118 }