Unity 8
PreviewRatingInput.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 import "PreviewSingleton"
21 
22 /*! \brief Preview widget for rating.
23 
24  The widget can show a rating widget and a field to enter a comment.
25  The visibility of the two widgets is specified by widgetData["visible"],
26  accepting "both", "rating" or "review".
27  The requirement of the review is specified by widgetData["visible"],
28  accepting "both", "rating" or "review".
29  It is possible to customise labels, widgetData["rating-label"] for the rating,
30  widgetData["rewiew-label"] for the comment field and widgetData["submit-label"]
31  for the submit button.
32  The icons used in the rating widget can be customised with
33  widgetData["rating-icon-empty"] and widgetData["rating-icon-full"].
34  The successeful submit emits triggered(widgetId, widgetData["required"], data),
35  with data being {"rating": rating value, "review": review comment, "author": null (for now)}.
36 */
37 
38 PreviewWidget {
39  id: root
40  implicitHeight: {
41  switch(widgetData["visible"]) {
42  default:
43  case "both":
44  return ratingLabelAndWidgetContainer.implicitHeight + (reviewContainer.visible ? reviewContainer.implicitHeight : 0);
45  case "rating":
46  return ratingLabelAndWidgetContainer.implicitHeight;
47  case "review":
48  return reviewContainer.implicitHeight;
49  }
50  }
51 
52  clip: reviewContainer.visible
53 
54  property alias ratingValue: rating.value
55  property alias reviewText: reviewTextArea.text
56 
57  onRatingValueChanged: storeRatingState()
58  onReviewTextChanged: storeTextState()
59  onWidgetIdChanged: restoreReviewState()
60 
61  function initializeWidgetExtraData() {
62  if (typeof(PreviewSingleton.widgetExtraData[widgetId]) == "undefined") PreviewSingleton.widgetExtraData[widgetId] = [];
63  }
64 
65  function storeRatingState() {
66  initializeWidgetExtraData();
67  PreviewSingleton.widgetExtraData[widgetId][0] = ratingValue;
68  }
69 
70  function storeTextState() {
71  initializeWidgetExtraData();
72  PreviewSingleton.widgetExtraData[widgetId][1] = reviewText;
73  }
74 
75  function restoreReviewState() {
76  if (!PreviewSingleton.widgetExtraData[widgetId]) return;
77  if (PreviewSingleton.widgetExtraData[widgetId][0] > 0) ratingValue = PreviewSingleton.widgetExtraData[widgetId][0];
78  if (typeof(PreviewSingleton.widgetExtraData[widgetId][1]) != "undefined" &&
79  PreviewSingleton.widgetExtraData[widgetId][1] != "") reviewText = PreviewSingleton.widgetExtraData[widgetId][1];
80  }
81 
82  function submit() {
83  // checks rating-input requirements
84  if (((widgetData["required"] === "both" ||
85  widgetData["required"] === "rating") &&
86  rating.value < 0) ||
87  ((widgetData["required"] === "both" ||
88  widgetData["required"] === "review") &&
89  reviewTextArea.text === "")) return;
90 
91  var data = {"rating": rating.value, "review": reviewTextArea.text, "author": null};
92  triggered(root.widgetId, "rated", data);
93  }
94 
95  Column {
96  id: ratingLabelAndWidgetContainer
97  anchors { left: parent.left; right: parent.right; }
98  spacing: units.gu(0.5)
99  visible: widgetData["visible"] !== "review"
100 
101  Label {
102  id: ratingLabel
103  objectName: "ratingLabel"
104  anchors { left: parent.left; right: parent.right; }
105  fontSize: "large"
106  color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText
107  opacity: .8
108  text: widgetData["rating-label"] || i18n.tr("Rate this")
109  }
110 
111  Rating {
112  id: rating
113  objectName: "rating"
114  anchors.left: parent.left
115  size: 5
116  height: units.gu(4)
117  onValueChanged: {
118  if (widgetData && widgetData["visible"] === "rating") root.submit();
119  }
120 
121  property var urlIconEmpty: widgetData["rating-icon-empty"] || "image://theme/non-starred"
122  property var urlIconFull: widgetData["rating-icon-full"] || "image://theme/starred"
123  }
124  }
125 
126  Item {
127  id: reviewContainer
128  objectName: "reviewContainer"
129  implicitHeight: visible ? reviewSubmitContainer.implicitHeight + anchors.topMargin : 0
130 
131  readonly property real innerMargin: units.gu(1)
132 
133  anchors {
134  left: parent.left
135  right: parent.right
136  top: ratingLabelAndWidgetContainer.visible ? ratingLabelAndWidgetContainer.bottom : parent.top
137  bottom: parent.bottom
138  topMargin: ratingLabelAndWidgetContainer.visible ? innerMargin : 0
139  }
140  visible: {
141  switch(widgetData["visible"]) {
142  default:
143  case "both":
144  return widgetData["required"] === "review" || rating.value > 0;
145  case "rating":
146  return false;
147  case "review":
148  return true;
149  }
150  }
151 
152  Behavior on implicitHeight {
153  UbuntuNumberAnimation {
154  duration: UbuntuAnimation.FastDuration
155  easing.type: Easing.OutCubic
156  }
157  }
158 
159  Item {
160  id: reviewSubmitContainer
161  objectName: "reviewSubmitContainer"
162  anchors.fill: parent
163  implicitHeight: reviewTextArea.implicitHeight + anchors.topMargin
164 
165  TextArea {
166  id: reviewTextArea
167  objectName: "reviewTextArea"
168  property bool inputMethodVisible: Qt.inputMethod.visible
169  onInputMethodVisibleChanged: {
170  if(inputMethodVisible && activeFocus)
171  root.makeSureVisible(reviewTextArea);
172  }
173  onVisibleChanged: {
174  if (visible && widgetData["visible"] !== "review")
175  focus = true;
176  }
177  anchors {
178  top: parent.top
179  left: parent.left
180  right: submitButton.left
181  rightMargin: reviewContainer.innerMargin
182  }
183  placeholderText: widgetData["review-label"] || i18n.tr("Add a review")
184  }
185 
186  Button {
187  id: submitButton
188  objectName: "submitButton"
189 
190  readonly property bool readyToSubmit: {
191  if ((widgetData["required"] !== "review" && rating.value < 0) ||
192  (widgetData["required"] !== "rating" && reviewTextArea.text === "")) return false;
193  else return true;
194  }
195 
196  anchors {
197  top: parent.top
198  right: parent.right
199  }
200  enabled: readyToSubmit
201  text: widgetData["submit-label"] || i18n.tr("Send")
202  onClicked: root.submit()
203  }
204  }
205  }
206 }