on xenial help sign in
Adds rating preview widget. Work on the rating widget
a10ecd9Andrea Cimitan
po/unity8.pot+18−10
@@ -8,7 +8,7 @@ msgid ""
8msgstr ""
8msgstr ""
9"Project-Id-Version: unity8\n"
9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"
10"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2014-02-04 15:43+0000\n"
11+"POT-Creation-Date: 2014-02-13 18:37+0000\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -73,19 +73,19 @@ msgid ""
73"phone<br><br>Tap on the screen to start"
73"phone<br><br>Tap on the screen to start"
74msgstr ""
74msgstr ""
75
75
76−#: qml/Components/PageHeader.qml:339
76+#: qml/Components/PageHeader.qml:340
77msgid "Recent searches"
77msgid "Recent searches"
78msgstr ""
78msgstr ""
79
79
80−#: qml/Components/SeeMore.qml:32
80+#: qml/Components/SeeMore.qml:35
81msgid "See more"
81msgid "See more"
82msgstr ""
82msgstr ""
83
83
84−#: qml/Components/SeeMore.qml:61
84+#: qml/Components/SeeMore.qml:57
85msgid "See less"
85msgid "See less"
86msgstr ""
86msgstr ""
87
87
88−#: qml/Dash/Apps/AppPreview.qml:136
88+#: qml/Dash/Apps/AppPreview.qml:136 qml/Dash/Previews/PreviewRating.qml:70
89msgid "Rate this"
89msgid "Rate this"
90msgstr ""
90msgstr ""
91
91
@@ -103,18 +103,26 @@ msgid_plural "%1 reviews"
103msgstr[0] ""
103msgstr[0] ""
104msgstr[1] ""
104msgstr[1] ""
105
105
106−#: qml/Dash/Previews/Reviews.qml:74
106+#: qml/Dash/Previews/PreviewActionCombo.qml:34
107−msgid "Add a review"
107+msgid "More..."
108msgstr ""
108msgstr ""
109
109
110−#: qml/Dash/Previews/Reviews.qml:86
110+#: qml/Dash/Previews/PreviewActionCombo.qml:34
111−msgid "Review"
111+msgid "Less..."
112+msgstr ""
113+
114+#: qml/Dash/Previews/PreviewRating.qml:114 qml/Dash/Previews/Reviews.qml:74
115+msgid "Add a review"
112msgstr ""
116msgstr ""
113
117
114−#: qml/Dash/Previews/Reviews.qml:121
118+#: qml/Dash/Previews/PreviewRating.qml:153 qml/Dash/Previews/Reviews.qml:121
115msgid "Send"
119msgid "Send"
116msgstr ""
120msgstr ""
117
121
122+#: qml/Dash/Previews/Reviews.qml:86
123+msgid "Review"
124+msgstr ""
125+
118#: qml/Dash/Previews/Reviews.qml:139
126#: qml/Dash/Previews/Reviews.qml:139
119msgid "Comments:"
127msgid "Comments:"
120msgstr ""
128msgstr ""
qml/Components/Rating.qmlnew file+48
@@ -0,0 +1,48 @@
1+/*
2+ * Copyright (C) 2014 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.0
18+import Ubuntu.Components 0.1
19+
20+/*! Rating widget bar. */
21+
22+StyledItem {
23+ id: root
24+
25+ //! True if it accepts user input.
26+ property bool interactive: true
27+
28+ //! Maximum rating.
29+ property real maximumValue: 5
30+
31+ //! Number of rating icons.
32+ property int size: 5
33+
34+ //! Current rating.
35+ property real value: -1
36+
37+ readonly property real effectiveValue: MathUtils.clamp(size * value / maximumValue, 0, maximumValue)
38+
39+ style: RatingStyle {}
40+
41+ MouseArea {
42+ anchors.fill: parent
43+ enabled: root.interactive
44+ onClicked: root.value = Math.ceil(mouse.x / averageIconWidth) * root.maximumValue / root.size
45+
46+ readonly property int averageIconWidth: width / root.size
47+ }
48+}
qml/Components/RatingStyle.qmlnew file+47
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright (C) 2014 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.0
18+import Ubuntu.Components 0.1
19+
20+Row {
21+ anchors.fill: parent
22+
23+ Repeater {
24+ id: repeater
25+ model: styledItem.size
26+
27+ property int indexHalfValue: {
28+ var integerPart = Math.floor(styledItem.effectiveValue);
29+ var fractionalPart = styledItem.effectiveValue - integerPart;
30+
31+ if (fractionalPart < 0.5) return -1;
32+ else return integerPart;
33+ }
34+ property url urlIconEmpty: styledItem.urlIconEmpty || "graphics/icon_star_empty.png"
35+ property url urlIconFull: styledItem.urlIconFull || "graphics/icon_star_full.png"
36+ property url urlIconHalf: styledItem.urlIconHalf || "graphics/icon_star_half.png"
37+
38+ Image {
39+ opacity: styledItem.value < 0 ? 0.4 : 1 // Let's make the stars look inactive for a not-set value
40+ source: {
41+ if (index === repeater.indexHalfValue) return repeater.urlIconHalf;
42+ else if (index < styledItem.effectiveValue) return repeater.urlIconFull;
43+ else return repeater.urlIconEmpty;
44+ }
45+ }
46+ }
47+}
qml/Components/graphics/icon_star_empty@20.pngnew file

Binary file not shown.

qml/Components/graphics/icon_star_full@20.pngnew file

Binary file not shown.

qml/Components/graphics/icon_star_half@20.pngnew file

Binary file not shown.

qml/Dash/Previews/PreviewRating.qmlnew file+173
@@ -0,0 +1,173 @@
1+/*
2+ * Copyright (C) 2014 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.0
18+import Ubuntu.Components 0.1
19+import "../../Components"
20+
21+/*! \brief Preview widget for rating.
22+
23+ The widget can show a rating widget and a field to enter a comment.
24+ The visibility of the two widgets is specified by widgetData["visible"],
25+ accepting "both", "rating" or "review".
26+ The requirement of the review is specified by widgetData["visible"],
27+ accepting "both", "rating" or "review".
28+ It is possible to customise labels, widgetData["rating-label"] for the rating,
29+ widgetData["rewiew-label"] for the comment field and widgetData["submit-label"]
30+ for the submit button.
31+ The icons used in the rating widget can be customised with
32+ widgetData["rating-icon-empty"] and widgetData["rating-icon-full"].
33+ The successeful submit emits triggered(widgetId, widgetData["required"], data),
34+ with data being {"rating": rating value, "review": review comment, "author": null (for now)}.
35+*/
36+
37+PreviewWidget {
38+ id: root
39+ implicitHeight: {
40+ switch(widgetData["visible"]) {
41+ default:
42+ case "both":
43+ return ratingLabelAndWidgetContainer.implicitHeight + reviewContainer.implicitHeight;
44+ case "rating":
45+ return ratingLabelAndWidgetContainer.implicitHeight;
46+ case "review":
47+ return reviewContainer.implicitHeight;
48+ }
49+ }
50+
51+ function submit() {
52+ // checks rating-input requirements
53+ if (((widgetData["required"] === "both" ||
54+ widgetData["required"] === "rating") &&
55+ rating.value < 0) ||
56+ ((widgetData["required"] === "both" ||
57+ widgetData["required"] === "review") &&
58+ reviewTextArea.text === "")) return;
59+
60+ var data = {"rating": rating.value, "review": reviewTextArea.text, "author": null};
61+ triggered(root.widgetId, widgetData["required"], data);
62+ }
63+
64+ Item {
65+ id: ratingLabelAndWidgetContainer
66+ anchors {
67+ left: parent.left
68+ right: parent.right
69+ }
70+ implicitHeight: rating.height
71+ visible: widgetData["visible"] !== "review"
72+
73+ Label {
74+ objectName: "ratingLabel"
75+ anchors {
76+ verticalCenter: parent.verticalCenter
77+ left: parent.left
78+ }
79+ color: Theme.palette.selected.backgroundText
80+ opacity: .8
81+ text: widgetData["rating-label"] || i18n.tr("Rate this")
82+ }
83+
84+ Rating {
85+ id: rating
86+ objectName: "rating"
87+ anchors {
88+ verticalCenter: parent.verticalCenter
89+ right: parent.right
90+ }
91+ size: 5
92+ onValueChanged: {
93+ if (widgetData["visible"] === "rating") root.submit();
94+ }
95+
96+ property var urlIconEmpty: widgetData["rating-icon-empty"]
97+ property var urlIconFull: widgetData["rating-icon-full"]
98+ }
99+ }
100+
101+ Item {
102+ id: reviewContainer
103+ implicitHeight: reviewLabel.implicitHeight + reviewSubmitContainer.implicitHeight + anchors.topMargin
104+
105+ readonly property real innerMargin: units.gu(1)
106+
107+ anchors {
108+ left: parent.left
109+ right: parent.right
110+ top: ratingLabelAndWidgetContainer.visible ? ratingLabelAndWidgetContainer.bottom : parent.top
111+ bottom: parent.bottom
112+ topMargin: ratingLabelAndWidgetContainer.visible ? reviewContainer.innerMargin : 0
113+ }
114+ visible: widgetData["visible"] !== "rating"
115+
116+ Label {
117+ objectName: "reviewLabel"
118+ id: reviewLabel
119+ anchors {
120+ top: parent.top
121+ left: parent.left
122+ right: parent.right
123+ }
124+ color: Theme.palette.selected.backgroundText
125+ opacity: .8
126+ text: widgetData["review-label"] || i18n.tr("Add a review")
127+ }
128+
129+ Item {
130+ id: reviewSubmitContainer
131+ anchors {
132+ top: reviewLabel.bottom
133+ left: parent.left
134+ right: parent.right
135+ bottom: parent.bottom
136+ topMargin: reviewContainer.innerMargin
137+ }
138+ implicitHeight: reviewTextArea.implicitHeight + anchors.topMargin
139+
140+ TextArea {
141+ id: reviewTextArea
142+ objectName: "reviewTextArea"
143+ anchors {
144+ top: parent.top
145+ left: parent.left
146+ right: submitButton.left
147+ rightMargin: reviewContainer.innerMargin
148+ }
149+ }
150+
151+ Button {
152+ id: submitButton
153+ objectName: "submitButton"
154+
155+ readonly property bool readyToSubmit: {
156+ if (reviewTextArea.text === "" ||
157+ (widgetData["visible"] === "both" && rating.value < 0)) return false;
158+ else return true;
159+ }
160+
161+ anchors {
162+ top: parent.top
163+ right: parent.right
164+ }
165+ color: readyToSubmit ? Theme.palette.selected.base : Theme.palette.normal.base
166+ text: widgetData["submit-label"] || i18n.tr("Send")
167+ onClicked: {
168+ if (readyToSubmit) root.submit()
169+ }
170+ }
171+ }
172+ }
173+}
qml/Dash/Previews/PreviewWidget.qml+1−1
@@ -30,7 +30,7 @@ Item {
30
30
31 /*! \brief This signal should be emitted when a preview action was triggered.
31 /*! \brief This signal should be emitted when a preview action was triggered.
32 *
32 *
33− * \param widgetId,actionId Respective identifiers from widgetData.
33+ * \param widgetId, actionId Respective identifiers from widgetData.
34 * \param data Optional widget-specific data sent to the scope.
34 * \param data Optional widget-specific data sent to the scope.
35 */
35 */
36 signal triggered(string widgetId, string actionId, var data)
36 signal triggered(string widgetId, string actionId, var data)
qml/Dash/Previews/PreviewWidgetFactory.qml+1
@@ -48,6 +48,7 @@ Loader {
48 case "header": return "PreviewHeader.qml";
48 case "header": return "PreviewHeader.qml";
49 case "image": return "PreviewZoomableImage.qml"
49 case "image": return "PreviewZoomableImage.qml"
50 case "progress": return "PreviewProgress.qml";
50 case "progress": return "PreviewProgress.qml";
51+ case "rating-input": return "PreviewRating.qml";
51 case "text": return "PreviewTextSummary.qml";
52 case "text": return "PreviewTextSummary.qml";
52 case "video": return "PreviewVideoPlayback.qml";
53 case "video": return "PreviewVideoPlayback.qml";
53 default: return "";
54 default: return "";
tests/qmltests/CMakeLists.txt+4−2
@@ -29,6 +29,7 @@ add_qml_test(Components DraggingArea)
29add_qml_test(Components EdgeDemoOverlay)
29add_qml_test(Components EdgeDemoOverlay)
30add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
30add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
31add_qml_test(Components LazyImage)
31add_qml_test(Components LazyImage)
32+add_qml_test(Components Rating)
32add_qml_test(Components ResponsiveFlowView)
33add_qml_test(Components ResponsiveFlowView)
33add_qml_test(Components ResponsiveGridView)
34add_qml_test(Components ResponsiveGridView)
34add_qml_test(Components Revealer)
35add_qml_test(Components Revealer)
@@ -56,14 +57,15 @@ add_qml_test(Dash/Apps AppPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} $
56add_qml_test(Dash/Movie MoviePreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
57add_qml_test(Dash/Movie MoviePreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
57add_qml_test(Dash/Music MusicPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
58add_qml_test(Dash/Music MusicPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
58add_qml_test(Dash/Previews Preview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
59add_qml_test(Dash/Previews Preview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
59−add_qml_test(Dash/Previews PreviewWidgetFactory IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
60add_qml_test(Dash/Previews PreviewActions IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
60add_qml_test(Dash/Previews PreviewActions IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
61add_qml_test(Dash/Previews PreviewAudioPlayback IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
61add_qml_test(Dash/Previews PreviewAudioPlayback IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
62−add_qml_test(Dash/Previews PreviewImageGallery IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
63add_qml_test(Dash/Previews PreviewHeader IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
62add_qml_test(Dash/Previews PreviewHeader IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
63+add_qml_test(Dash/Previews PreviewImageGallery IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
64add_qml_test(Dash/Previews PreviewProgress IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
64add_qml_test(Dash/Previews PreviewProgress IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
65+add_qml_test(Dash/Previews PreviewRating IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
65add_qml_test(Dash/Previews PreviewTextSummary IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
66add_qml_test(Dash/Previews PreviewTextSummary IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
66add_qml_test(Dash/Previews PreviewVideoPlayback IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
67add_qml_test(Dash/Previews PreviewVideoPlayback IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
68+add_qml_test(Dash/Previews PreviewWidgetFactory IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
67add_qml_test(Dash/Previews PreviewZoomableImage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
69add_qml_test(Dash/Previews PreviewZoomableImage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
68add_qml_test(Greeter Lockscreen IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
70add_qml_test(Greeter Lockscreen IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
69 PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
71 PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
tests/qmltests/Components/tst_Rating.qmlnew file+86
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright 2013 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.0
18+import QtTest 1.0
19+import "../../../qml/Components"
20+import Ubuntu.Components 0.1
21+import Unity.Test 0.1 as UT
22+
23+Rectangle {
24+ id: root
25+ width: units.gu(40)
26+ height: units.gu(10)
27+ color: Theme.palette.selected.background
28+
29+ Rating {
30+ id: rating
31+ anchors.centerIn: parent
32+ maximumValue: 5
33+ size: 5
34+ value: 3
35+ }
36+
37+ UT.UnityTestCase {
38+ name: "RatingTest"
39+ when: windowShown
40+
41+ function init() {
42+ rating.maximumValue = 5;
43+ rating.size = 5
44+ rating.value = 3;
45+ }
46+
47+ function test_interactive_rating_data() {
48+ return [
49+ {tag: "1st icon without interactive", interactive: false, size: 5, maximumValue: 5, index: 0, value: 3},
50+ {tag: "1st icon", interactive: true, size: 5, maximumValue: 5, index: 0, value: 1},
51+ {tag: "1st icon size 10", interactive: true, size: 10, maximumValue: 10, index: 0, value: 1},
52+ {tag: "3rd icon size 10 small maximumValue", interactive: true, size: 10, maximumValue: 5, index: 2, value: 1.5},
53+ {tag: "2nd icon with big maximumValue", interactive: true, size: 5, maximumValue: 100, index: 1, value: 40},
54+ {tag: "last icon", interactive: true, size: 5, maximumValue: 5, index: 4, value: 5},
55+ ];
56+ }
57+
58+ function test_interactive_rating(data) {
59+ rating.interactive = data.interactive;
60+ rating.maximumValue = data.maximumValue;
61+ rating.size = data.size;
62+
63+ var averageIconWidth = rating.width / rating.size;
64+ mouseClick(rating, averageIconWidth * data.index + averageIconWidth / 2, rating.height / 2);
65+ compare(rating.value, data.value);
66+
67+ rating.interactive = false;
68+ }
69+
70+ function test_effectiveValue_data() {
71+ return [
72+ {tag: "negative", value: -3, expectedValue: 0},
73+ {tag: "ranged value", value: 2, expectedValue: 2},
74+ {tag: "big", value: 200, expectedValue: rating.maximumValue},
75+ {tag: "min", value: 0, expectedValue: 0},
76+ {tag: "max", value: rating.maximumValue, expectedValue: rating.maximumValue},
77+ {tag: "half", value: 2.5, expectedValue: 2.5}
78+ ];
79+ }
80+
81+ function test_effectiveValue(data) {
82+ rating.value = data.value;
83+ compare(rating.effectiveValue, data.expectedValue, "effectiveValue not calculated correctly")
84+ }
85+ }
86+}
tests/qmltests/Dash/Previews/tst_PreviewRating.qmlnew file+183
@@ -0,0 +1,183 @@
1+/*
2+ * Copyright 2014 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.0
18+import QtTest 1.0
19+import Ubuntu.Components 0.1
20+import "../../../../qml/Dash/Previews"
21+import Unity.Test 0.1 as UT
22+
23+Rectangle {
24+ id: root
25+ width: units.gu(40)
26+ height: units.gu(80)
27+ color: Theme.palette.selected.background
28+
29+ property real validInputRating: 1
30+ property real invalidInputRating: -1
31+ property string validInputText: "Great!"
32+ property string invalidInputText: ""
33+
34+ property var triggeredDataBoth: { "rating": validInputRating, "review": validInputText, "author": null }
35+ property var triggeredDataRatingOnly: { "rating": validInputRating, "review": invalidInputText, "author": null }
36+ property var triggeredDataReviewOnly: { "rating": invalidInputRating, "review": validInputText, "author": null }
37+
38+ property var widgetDataBoth: { "visible": "both", "required": "both" }
39+ property var widgetDataRating: { "visible": "rating", "required": "rating" }
40+ property var widgetDataRatingBroken: { "visible": "rating", "required": "review" }
41+ property var widgetDataReview: { "visible": "review", "required": "review" }
42+ property var widgetDataReviewBroken: { "visible": "review", "required": "rating" }
43+
44+ property var widgetDataNewLabels: { "visible": "both", "required": "both", "rating-label": "TestRatingLabel", "review-label": "TestReviewLabel", "submit-label": "TestSubmitLabel" }
45+
46+ PreviewRating {
47+ id: previewRating
48+ anchors.left: parent.left
49+ anchors.right: parent.right
50+ widgetData: widgetDataBoth
51+ widgetId: "previewRating"
52+ }
53+
54+ SignalSpy {
55+ id: spy
56+ signalName: "triggered"
57+ }
58+
59+ UT.UnityTestCase {
60+ name: "PreviewRatingTest"
61+ when: windowShown
62+
63+ property var rating: findChild(previewRating, "rating")
64+ property var reviewTextArea: findChild(previewRating, "reviewTextArea")
65+ property var submitButton: findChild(previewRating, "submitButton")
66+
67+ function init() {
68+ rating.value = -1;
69+ reviewTextArea.text = "";
70+ }
71+
72+ function test_labels() {
73+ var ratingLabel = findChild(previewRating, "ratingLabel");
74+ var reviewLabel = findChild(previewRating, "reviewLabel");
75+
76+ previewRating.widgetData = widgetDataNewLabels;
77+ compare(ratingLabel.text, widgetDataNewLabels["rating-label"]);
78+ compare(reviewLabel.text, widgetDataNewLabels["review-label"]);
79+ compare(submitButton.text, widgetDataNewLabels["submit-label"]);
80+ }
81+
82+ function test_submit_and_visibility_data() {
83+ return [
84+ {tag: "both, null review", widgetData: widgetDataBoth, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
85+ {tag: "both, rating-only review", widgetData: widgetDataBoth, inputRating: validInputRating, inputText: invalidInputText, emitted: false},
86+ {tag: "both, review-only review", widgetData: widgetDataBoth, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
87+ {tag: "both, complete review", widgetData: widgetDataBoth, inputRating: validInputRating, inputText: validInputText, emitted: true},
88+ {tag: "rating, null review", widgetData: widgetDataRating, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
89+ {tag: "rating, rating-only review", widgetData: widgetDataRating, inputRating: validInputRating, inputText: invalidInputText, emitted: true},
90+ {tag: "rating, review-only review", widgetData: widgetDataRating, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
91+ {tag: "rating, complete review", widgetData: widgetDataRating, inputRating: validInputRating, inputText: validInputText, emitted: true},
92+ {tag: "rating broken, null review", widgetData: widgetDataRatingBroken, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
93+ {tag: "rating broken, rating-only review", widgetData: widgetDataRatingBroken, inputRating: validInputRating, inputText: invalidInputText, emitted: false},
94+ {tag: "rating broken, review-only review", widgetData: widgetDataRatingBroken, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
95+ {tag: "rating broken, complete review", widgetData: widgetDataRatingBroken, inputRating: validInputRating, inputText: validInputText, emitted: false},
96+ {tag: "review, null review", widgetData: widgetDataReview, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
97+ {tag: "review, rating-only review", widgetData: widgetDataReview, inputRating: validInputRating, inputText: invalidInputText, emitted: false},
98+ {tag: "review, review-only review", widgetData: widgetDataReview, inputRating: invalidInputRating, inputText: validInputText, emitted: true},
99+ {tag: "review, complete review", widgetData: widgetDataReview, inputRating: validInputRating, inputText: validInputText, emitted: true},
100+ {tag: "review broken, null review", widgetData: widgetDataReviewBroken, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
101+ {tag: "review broken, rating-only review", widgetData: widgetDataReviewBroken, inputRating: validInputRating, inputText: invalidInputText, emitted: false},
102+ {tag: "review broken, review-only review", widgetData: widgetDataReviewBroken, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
103+ {tag: "review broken, complete review", widgetData: widgetDataReviewBroken, inputRating: validInputRating, inputText: validInputText, emitted: false},
104+ ];
105+ }
106+
107+ function test_submit_and_visibility(data) {
108+ spy.clear();
109+ spy.target = previewRating;
110+
111+ previewRating.widgetData = data.widgetData;
112+
113+ if (data.widgetData["visible"] !== "review") {
114+ verify(rating.visible === true);
115+
116+ rating.value = data.inputRating;
117+ if (data.widgetData["required"] !== "rating" || data.inputRating < 0) {
118+ compare(spy.count, 0);
119+ } else {
120+ compare(spy.count, 1);
121+ }
122+ } else {
123+ verify(rating.visible === false);
124+ }
125+
126+ if (data.widgetData["visible"] !== "rating") {
127+ verify(reviewTextArea.visible === true);
128+
129+ reviewTextArea.text = data.inputText;
130+ mouseClick(submitButton, submitButton.width / 2, submitButton.height / 2);
131+ switch (data.widgetData["required"]) {
132+ case "rating": compare(spy.count, 0); break;
133+ case "both":
134+ default: {
135+ if (data.inputRating < 0 || data.inputText === "") {
136+ compare(spy.count, 0); break;
137+ }
138+ }
139+ case "review": {
140+ if (data.inputText === "") {
141+ compare(spy.count, 0); break;
142+ } else {
143+ compare(spy.count, 1); break;
144+ }
145+ }
146+ }
147+ } else {
148+ verify(reviewTextArea.visible === false);
149+ }
150+
151+ compare(spy.count === 1, data.emitted);
152+ }
153+
154+ function test_triggered_data() {
155+ return [
156+ {tag: "complete review", widgetData: widgetDataBoth, inputRating: validInputRating, inputText: validInputText, triggeredData: triggeredDataBoth},
157+ {tag: "rating-only review", widgetData: widgetDataRating, inputRating: validInputRating, inputText: invalidInputText, triggeredData: triggeredDataRatingOnly},
158+ {tag: "review-only review", widgetData: widgetDataReview, inputRating: invalidInputRating, inputText: validInputText, triggeredData: triggeredDataReviewOnly}
159+ ];
160+ }
161+
162+ function test_triggered(data) {
163+ spy.clear();
164+ spy.target = previewRating;
165+
166+ previewRating.widgetData = data.widgetData;
167+
168+ if (data.inputRating > 0) rating.value = data.inputRating;
169+ if (data.inputText !== "") {
170+ reviewTextArea.text = data.inputText;
171+ mouseClick(submitButton, submitButton.width / 2, submitButton.height / 2);
172+ }
173+
174+ compare(spy.count, 1);
175+ var args = spy.signalArguments[0];
176+ compare(args[0], previewRating.widgetId);
177+ compare(args[1], data.widgetData["required"]);
178+ compare(args[2]["rating"], data.triggeredData["rating"]);
179+ compare(args[2]["review"], data.triggeredData["review"]);
180+ verify(args[2]["author"]); // Just verifying it exists now
181+ }
182+ }
183+}
tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml+1
@@ -81,6 +81,7 @@ Rectangle {
81 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
81 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
82 { tag: "Image", type: "image", source: "PreviewZoomableImage.qml" },
82 { tag: "Image", type: "image", source: "PreviewZoomableImage.qml" },
83 { tag: "Progress", type: "progress", source: "PreviewProgress.qml" },
83 { tag: "Progress", type: "progress", source: "PreviewProgress.qml" },
84+ { tag: "Rating Input", type: "rating-input", source: "PreviewRating.qml" },
84 { tag: "Text", type: "text", source: "PreviewTextSummary.qml" },
85 { tag: "Text", type: "text", source: "PreviewTextSummary.qml" },
85 { tag: "Video", type: "video", source: "PreviewVideoPlayback.qml" },
86 { tag: "Video", type: "video", source: "PreviewVideoPlayback.qml" },
86 ];
87 ];