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  font.weight: Font.Light
107  color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText
108  opacity: .8
109  text: widgetData["rating-label"] || i18n.tr("Rate this")
110  }
111 
112  Rating {
113  id: rating
114  objectName: "rating"
115  anchors.left: parent.left
116  size: 5
117  height: units.gu(4)
118  onValueChanged: {
119  if (widgetData && widgetData["visible"] === "rating") root.submit();
120  }
121 
122  property var urlIconEmpty: widgetData["rating-icon-empty"] || "image://theme/non-starred"
123  property var urlIconFull: widgetData["rating-icon-full"] || "image://theme/starred"
124  }
125  }
126 
127  Item {
128  id: reviewContainer
129  objectName: "reviewContainer"
130  implicitHeight: visible ? reviewSubmitContainer.implicitHeight + anchors.topMargin : 0
131 
132  readonly property real innerMargin: units.gu(1)
133 
134  anchors {
135  left: parent.left
136  right: parent.right
137  top: ratingLabelAndWidgetContainer.visible ? ratingLabelAndWidgetContainer.bottom : parent.top
138  bottom: parent.bottom
139  topMargin: ratingLabelAndWidgetContainer.visible ? innerMargin : 0
140  }
141  visible: {
142  switch(widgetData["visible"]) {
143  default:
144  case "both":
145  return widgetData["required"] === "review" || rating.value > 0;
146  case "rating":
147  return false;
148  case "review":
149  return true;
150  }
151  }
152 
153  Behavior on implicitHeight {
154  UbuntuNumberAnimation {
155  duration: UbuntuAnimation.FastDuration
156  easing.type: Easing.OutCubic
157  }
158  }
159 
160  Item {
161  id: reviewSubmitContainer
162  objectName: "reviewSubmitContainer"
163  anchors.fill: parent
164  implicitHeight: reviewTextArea.implicitHeight + anchors.topMargin
165 
166  TextArea {
167  id: reviewTextArea
168  objectName: "reviewTextArea"
169  property bool inputMethodVisible: Qt.inputMethod.visible
170  onInputMethodVisibleChanged: {
171  if(inputMethodVisible && activeFocus)
172  root.makeSureVisible(reviewTextArea);
173  }
174  onVisibleChanged: {
175  if (visible && widgetData["visible"] !== "review")
176  focus = true;
177  }
178  anchors {
179  top: parent.top
180  left: parent.left
181  right: submitButton.left
182  rightMargin: reviewContainer.innerMargin
183  }
184  placeholderText: widgetData["review-label"] || i18n.tr("Add a review")
185  }
186 
187  Button {
188  id: submitButton
189  objectName: "submitButton"
190 
191  readonly property bool readyToSubmit: {
192  if ((widgetData["required"] !== "review" && rating.value < 0) ||
193  (widgetData["required"] !== "rating" && reviewTextArea.text === "" && !reviewTextArea.inputMethodComposing)) return false;
194  else return true;
195  }
196 
197  anchors {
198  top: parent.top
199  right: parent.right
200  }
201  enabled: readyToSubmit
202  text: widgetData["submit-label"] || i18n.tr("Send")
203  onClicked: root.submit()
204  }
205  }
206  }
207 }