on xenial help sign in
Add AppPreview.

Approved by PS Jenkins bot, Albert Astals Cid.

commit4390683762fa462cd267209479e3adc9bb10d4bc authorMichał Sawicz <michal.sawicz@canonical.com> dateTue 13 Aug 2013, 15:32 (13 years ago) parentd1fc0b89bf2db8
33 files changed+1545−75
Dash/Apps/AppInfo.qml+88 Dash/Apps/AppPreview.qml+195 Dash/Apps/AppReviews.qml+191 Dash/DashApps.qml+91 Dash/DashPreview.qml+11−41 Dash/Generic/GenericPreview.qml+17−3 Dash/GenericScopeView.qml+1−1 Dash/PreviewDelegateMapper.qml+2 Dash/Video/VideoPreview.qml+35−3 plugins/Ubuntu/CMakeLists.txt+1 plugins/Ubuntu/DownloadDaemonListener/CMakeLists.txt+22 plugins/Ubuntu/DownloadDaemonListener/DownloadTracker.cpp+84 plugins/Ubuntu/DownloadDaemonListener/DownloadTracker.h+69 plugins/Ubuntu/DownloadDaemonListener/interface/downloadtrackeradaptor.cpp+25 plugins/Ubuntu/DownloadDaemonListener/interface/downloadtrackeradaptor.h+125 plugins/Ubuntu/DownloadDaemonListener/interface/metatypes.h+28 plugins/Ubuntu/DownloadDaemonListener/plugin.cpp+39 plugins/Ubuntu/DownloadDaemonListener/plugin.h+37 plugins/Ubuntu/DownloadDaemonListener/qmldir+3 plugins/Unity/preview.cpp+7 plugins/Unity/preview.h+4 po/unity8.pot+39−4 tests/mocks/Ubuntu/CMakeLists.txt+1 tests/mocks/Ubuntu/DownloadDaemonListener/CMakeLists.txt+18 tests/mocks/Ubuntu/DownloadDaemonListener/MockDownloadTracker.cpp+67 tests/mocks/Ubuntu/DownloadDaemonListener/MockDownloadTracker.h+66 tests/mocks/Ubuntu/DownloadDaemonListener/plugin.cpp+28 tests/mocks/Ubuntu/DownloadDaemonListener/plugin.h+30 tests/mocks/Ubuntu/DownloadDaemonListener/qmldir+2 tests/qmltests/CMakeLists.txt+2 tests/qmltests/Dash/Apps/tst_AppPreview.qml+152 tests/qmltests/Dash/Video/tst_VideoPreview.qml+63 tests/qmltests/Dash/tst_DashPreview.qml+2−23
Dash/Apps/AppInfo.qmlnew file+88
@@ -0,0 +1,88 @@
1+/*
2+ * Copyright (C) 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 Ubuntu.Components 0.1
19+import "../../Components"
20+
21+Row {
22+ id: root
23+ property alias icon: image.source
24+ property alias appName: appNameLabel.text
25+ property alias rating: ratingStars.rating
26+ property int rated: 0
27+ property int reviews: 0
28+
29+ spacing: units.gu(2)
30+
31+ UbuntuShape {
32+ id: imageShape
33+ width: units.gu(6)
34+ height: units.gu(6)
35+ image: Image {
36+ id: image
37+ sourceSize { width: imageShape.width; height: imageShape.height }
38+ asynchronous: true
39+ fillMode: Image.PreserveAspectFit
40+ }
41+ }
42+
43+ Column {
44+ spacing: units.gu(1)
45+
46+ Label {
47+ id: appNameLabel
48+ fontSize: "large"
49+ color: "white"
50+ style: Text.Raised
51+ styleColor: "black"
52+ opacity: .9
53+ }
54+
55+ Row {
56+ spacing: units.gu(1)
57+
58+ RatingStars {
59+ id: ratingStars
60+ maximumRating: 10
61+ }
62+
63+ Label {
64+ id: ratedLabel
65+ objectName: "ratedLabel"
66+ fontSize: "medium"
67+ color: "white"
68+ style: Text.Raised
69+ styleColor: "black"
70+ opacity: .6
71+ //TRANSLATORS: Number of persons who rated this app
72+ text: i18n.tr("(%1)").arg(root.rated)
73+ }
74+
75+ Label {
76+ id: reviewsLabel
77+ objectName: "reviewsLabel"
78+ fontSize: "medium"
79+ color: "white"
80+ style: Text.Raised
81+ styleColor: "black"
82+ opacity: .6
83+ //TRANSLATORS: Number of persons who wrote reviews for this app
84+ text: i18n.tr("%1 review", "%1 reviews", root.reviews).arg(root.reviews)
85+ }
86+ }
87+ }
88+}
Dash/Apps/AppPreview.qmlnew file+195
@@ -0,0 +1,195 @@
1+/*
2+ * Copyright (C) 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 Ubuntu.Components 0.1
19+import Ubuntu.Components.ListItems 0.1 as ListItem
20+import Ubuntu.DownloadDaemonListener 0.1
21+import ".."
22+import "../../Components"
23+import "../../Components/IconUtil.js" as IconUtil
24+
25+DashPreview {
26+ id: root
27+
28+ signal sendUserReview(string review)
29+
30+ title: root.previewData.title
31+
32+ header: ListView {
33+ spacing: units.gu(1)
34+ orientation: ListView.Horizontal
35+ height: units.gu(22)
36+ anchors {
37+ left: parent.left
38+ right: parent.right
39+ margins: units.gu(1)
40+ }
41+ model: previewData.infoMap["more-screenshots"].value
42+
43+ delegate: UbuntuShape {
44+ id: shape
45+ anchors {
46+ top: parent.top
47+ bottom: parent.bottom
48+ }
49+ width: units.gu(12)
50+ radius: "medium"
51+ borderSource: ""
52+ image: Image {
53+ asynchronous: true
54+ sourceSize { width: shape.width; height: shape.height }
55+ source: modelData ? modelData : ""
56+ fillMode: Image.PreserveAspectCrop
57+ }
58+ }
59+ }
60+
61+ Component {
62+ id: buttonsComponent
63+
64+ GridView {
65+ id: buttonsGrid
66+ objectName: "gridButtons"
67+
68+ property int numOfRows: (count + 1) / 2
69+ property int spacing: units.gu(1)
70+ height: Math.max(units.gu(5), units.gu(5)*numOfRows + spacing*(numOfRows - 1))
71+
72+ interactive: false
73+ cellWidth: Math.max(units.gu(9), width / 2)
74+ cellHeight: buttonHeight + spacing
75+ property int buttonWidth: count > 1 ? Math.max(0, width / 2 - spacing) : width
76+ property int buttonHeight: units.gu(5)
77+
78+ delegate: Button {
79+ width: Math.max(units.gu(4), buttonsGrid.buttonWidth)
80+ height: buttonsGrid.buttonHeight
81+ color: Theme.palette.selected.foreground
82+ text: modelData.displayName
83+ iconSource: modelData.iconHint
84+ iconPosition: "right"
85+ onClicked: root.previewData.execute(modelData.id, { })
86+ }
87+ }
88+ }
89+
90+ Component {
91+ id: progressComponent
92+
93+ ProgressBar {
94+ id: progressBar
95+ objectName: "progressBar"
96+ value: 0
97+ maximumValue: 100
98+ height: units.gu(5)
99+
100+ property var model
101+
102+ DownloadTracker {
103+ service: "com.canonical.applications.Downloader"
104+ dbusPath: root.previewData.infoMap["progressbar_source"] ? root.previewData.infoMap["progressbar_source"].value : ""
105+
106+ onProgress: {
107+ var percentage = parseInt(received * 100 / total);
108+ progressBar.value = percentage;
109+ }
110+
111+ onFinished: {
112+ root.previewData.execute(progressBar.model[0].id, { })
113+ }
114+ }
115+
116+ }
117+ }
118+
119+ buttons: Loader {
120+ anchors {
121+ left: parent.left
122+ right: parent.right
123+ }
124+
125+ sourceComponent: root.previewData.infoMap["show_progressbar"] ? progressComponent : buttonsComponent
126+
127+ onLoaded: {
128+ item.model = root.previewData.actions;
129+ }
130+ }
131+
132+ body: Column {
133+ spacing: units.gu(1)
134+
135+ AppInfo {
136+ objectName: "appInfo"
137+ anchors { left: parent.left; right: parent.right }
138+
139+ appName: root.previewData.title
140+ icon: IconUtil.from_gicon(root.previewData.appIcon)
141+ rating: root.previewData.infoMap["rating"] ? root.previewData.infoMap["rating"].value : 0
142+ rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
143+ reviews: root.previewData.infoMap["reviews"] ? root.previewData.infoMap["reviews"].value : 0
144+ }
145+
146+ Label {
147+ anchors { left: parent.left; right: parent.right }
148+ text: root.previewData.description
149+ fontSize: "medium"
150+ color: Theme.palette.selected.backgroundText
151+ opacity: .6
152+ wrapMode: Text.WordWrap
153+ style: Text.Raised
154+ styleColor: "black"
155+ }
156+
157+ ListItem.ThinDivider {}
158+
159+ Item {
160+ anchors { left: parent.left; right: parent.right }
161+ height: rateLabel.height
162+
163+ Label {
164+ id: rateLabel
165+ fontSize: "medium"
166+ color: "white"
167+ style: Text.Raised
168+ styleColor: "black"
169+ opacity: .9
170+ text: i18n.tr("Rate this")
171+
172+ anchors.left: parent.left
173+ anchors.verticalCenter: parent.verticalCenter
174+ }
175+
176+ // FIXME these need to be made interactive and connected to the scope
177+ RatingStars {
178+ anchors.right: parent.right
179+ anchors.verticalCenter: parent.verticalCenter
180+ }
181+ }
182+
183+ ListItem.ThinDivider {}
184+
185+ AppReviews {
186+ objectName: "appReviews"
187+ anchors { left: parent.left; right: parent.right }
188+
189+ model: root.previewData.infoMap["comments"] ? root.previewData.infoMap["comments"].value : undefined
190+
191+ onSendReview: root.sendUserReview(review);
192+ }
193+
194+ }
195+}
Dash/Apps/AppReviews.qmlnew file+191
@@ -0,0 +1,191 @@
1+/*
2+ * Copyright (C) 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 Ubuntu.Components 0.1
19+import Ubuntu.Components.ListItems 0.1 as ListItem
20+import "../../Components"
21+
22+Column {
23+ id: root
24+
25+ property var model
26+
27+ signal sendReview(string review)
28+
29+ spacing: units.gu(2)
30+ state: ""
31+
32+ states: [
33+ State {
34+ name: ""
35+ PropertyChanges { target: reviewField; width: root.width }
36+ PropertyChanges { target: sendButton; opacity: 0 }
37+ PropertyChanges { target: inverseArea; enabled: false }
38+ },
39+ State {
40+ name: "editing"
41+ PropertyChanges { target: reviewField; width: (root.width - row.spacing - sendButton.width) }
42+ PropertyChanges { target: sendButton; opacity: 1 }
43+ PropertyChanges { target: inverseArea; enabled: true }
44+ }
45+ ]
46+
47+ transitions: [
48+ Transition {
49+ from: ""
50+ to: "editing"
51+ SequentialAnimation {
52+ UbuntuNumberAnimation { target: reviewField; properties: "width"; duration: UbuntuAnimation.SlowDuration }
53+ UbuntuNumberAnimation { target: sendButton; properties: "opacity"; duration: UbuntuAnimation.SlowDuration }
54+ }
55+ },
56+ Transition {
57+ from: "editing"
58+ to: ""
59+ SequentialAnimation {
60+ UbuntuNumberAnimation { target: sendButton; properties: "opacity"; duration: UbuntuAnimation.SlowDuration }
61+ UbuntuNumberAnimation { target: reviewField; properties: "width"; duration: UbuntuAnimation.SlowDuration }
62+ }
63+ }
64+ ]
65+
66+ Label {
67+ fontSize: "medium"
68+ color: "white"
69+ style: Text.Raised
70+ styleColor: "black"
71+ opacity: .9
72+ text: i18n.tr("Add a review")
73+ }
74+
75+ Row {
76+ id: row
77+ spacing: units.gu(1)
78+ width: root.width
79+
80+ // FIXME: needs to react to Qt.inputMethod geometry
81+ TextArea {
82+ id: reviewField
83+ objectName: "reviewField"
84+ placeholderText: i18n.tr("Review")
85+ width: parent.width
86+ verticalAlignment: Text.AlignVCenter
87+ autoSize: true
88+ maximumLineCount: 5
89+
90+ Behavior on height { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
91+
92+ onFocusChanged: {
93+ if(reviewField.focus){
94+ root.state = "editing";
95+ reviewField.selectAll();
96+ }
97+ }
98+
99+ // FIXME: not active when in wide mode
100+ InverseMouseArea {
101+ id: inverseArea
102+ anchors.fill: parent
103+ enabled: false
104+ onPressed: {
105+ reviewField.focus = false;
106+ root.state = "";
107+ }
108+ }
109+ }
110+
111+ Button {
112+ id: sendButton
113+ objectName: "sendButton"
114+ width: units.gu(10)
115+ height: units.gu(4)
116+ anchors.bottom: reviewField.bottom
117+ color: Theme.palette.selected.foreground
118+ text: i18n.tr("Send")
119+ opacity: 0
120+
121+ onClicked: {
122+ root.sendReview(reviewField.text);
123+ reviewField.text = ""
124+ }
125+ }
126+ }
127+
128+ ListItem.ThinDivider {}
129+
130+ Label {
131+ fontSize: "medium"
132+ color: "white"
133+ style: Text.Raised
134+ styleColor: "black"
135+ opacity: .9
136+ text: i18n.tr("Comments:")
137+ }
138+
139+ Repeater {
140+ objectName: "commentsArea"
141+ model: root.model
142+
143+ Column {
144+ anchors { left: parent.left; right: parent.right }
145+
146+ Column {
147+ anchors { left: parent.left; right: parent.right }
148+
149+ Label {
150+ anchors { left: parent.left; right: parent.right }
151+ text: modelData[0]
152+ fontSize: "medium"
153+ color: "white"
154+ opacity: .8
155+ wrapMode: Text.WordWrap
156+ style: Text.Raised
157+ styleColor: "black"
158+ }
159+
160+ Row {
161+ spacing: units.gu(1)
162+
163+ RatingStars {
164+ maximumRating: 10
165+ rating: modelData[1]
166+ }
167+
168+ Label {
169+ text: modelData[2]
170+ fontSize: "medium"
171+ color: Theme.palette.selected.backgroundText
172+ opacity: .6
173+ style: Text.Raised
174+ styleColor: "black"
175+ }
176+ }
177+ }
178+
179+ Label {
180+ anchors { left: parent.left; right: parent.right }
181+ text: modelData[3]
182+ fontSize: "medium"
183+ color: Theme.palette.selected.backgroundText
184+ opacity: .6
185+ wrapMode: Text.WordWrap
186+ style: Text.Raised
187+ styleColor: "black"
188+ }
189+ }
190+ }
191+}
Dash/DashApps.qml+91
@@ -170,4 +170,95 @@ ScopeView {
170170 searchHistory: scopeView.searchHistory
171171 }
172172 }
173+
174+ OpenEffect {
175+ id: effect
176+ anchors {
177+ fill: parent
178+ bottomMargin: -bottomOverflow
179+ }
180+ sourceItem: categoryView
181+
182+ enabled: gap > 0.0
183+
184+ topGapPx: (1 - gap) * positionPx
185+ topOpacity: (1 - gap * 1.2)
186+ bottomGapPx: positionPx + gap * (targetBottomGapPx - positionPx)
187+ bottomOverflow: units.gu(20)
188+ bottomOpacity: 1 - (gap * 0.8)
189+
190+ property int targetBottomGapPx: height - units.gu(8) - bottomOverflow
191+ property real gap: previewLoader.open ? 1.0 : 0.0
192+
193+ Behavior on gap {
194+ NumberAnimation {
195+ duration: 200
196+ easing.type: Easing.InOutQuad
197+ onRunningChanged: {
198+ if (!previewLoader.open && !running) {
199+ previewLoader.onScreen = false
200+ }
201+ }
202+ }
203+ }
204+ }
205+
206+ Connections {
207+ target: scopeView.scope
208+ onPreviewReady: {
209+ previewLoader.previewData = preview
210+ previewLoader.open = true
211+ }
212+ }
213+
214+ Connections {
215+ ignoreUnknownSignals: true
216+ target: previewLoader.valid ? previewLoader.item : null
217+ onClose: {
218+ previewLoader.open = false
219+ }
220+ }
221+
222+ PreviewDelegateMapper {
223+ id: previewDelegateMapper
224+ }
225+
226+ Loader {
227+ id: previewLoader
228+ property var previewData
229+ height: effect.bottomGapPx - effect.topGapPx
230+ anchors {
231+ top: parent.top
232+ topMargin: effect.topGapPx
233+ left: parent.left
234+ right: parent.right
235+ }
236+ source: onScreen ? previewDelegateMapper.map("preview-application") : ""
237+
238+ property bool open: false
239+ property bool onScreen: false
240+ property bool valid: item !== null
241+
242+ onOpenChanged: {
243+ if (open) {
244+ onScreen = true
245+ }
246+ }
247+
248+ onLoaded: {
249+ item.previewData = previewLoader.previewData
250+ }
251+ }
252+
253+ // TODO: Move as InverseMouseArea to DashPreview
254+ MouseArea {
255+ enabled: previewLoader.onScreen
256+ anchors {
257+ fill: parent
258+ topMargin: effect.bottomGapPx
259+ }
260+ onClicked: {
261+ previewLoader.open = false;
262+ }
263+ }
173264}
Dash/DashPreview.qml+11−41
@@ -19,14 +19,15 @@ import Ubuntu.Components 0.1
1919
2020Rectangle {
2121 id: root
22+
23+ property var previewData
24+
2225 property string title: ""
23− property url url: ""
2426 property real previewWidthRatio: 0.5
25− property bool playable: false
26− property bool forceSquare: false
27+
28+ property Component header
2729 property Component buttons
28− property Component caption
29− property Component description
30+ property Component body
3031
3132 readonly property bool narrowMode: width <= height
3233 readonly property int contentSpacing: units.gu(3)
@@ -141,38 +142,13 @@ Rectangle {
141142 right: parent.right
142143 }
143144 height: childrenRect.height
144− spacing: root.contentSpacing
145+ spacing: units.gu(1)
145146
146− // TODO: replace this UbuntuShape with the Video component once that lands
147− // with the player.
148− UbuntuShape {
149− id: urlLoader
147+ Loader {
148+ id: headerLoader
150149 anchors.left: parent.left
151150 anchors.right: parent.right
152− height: root.forceSquare ? width : width * previewImage.sourceSize.height / previewImage.sourceSize.width
153− radius: "medium"
154− image: Image {
155− id: previewImage
156− asynchronous: true
157− source: root.url
158− fillMode: Image.PreserveAspectCrop
159− }
160−
161− Image {
162− objectName: "playButton"
163− anchors.centerIn: parent
164− visible: root.playable
165− readonly property bool bigButton: parent.width > units.gu(40)
166− width: bigButton ? units.gu(8) : units.gu(4.5)
167− height: width
168− source: "graphics/play_button%1%2.png".arg(previewImageMouseArea.pressed ? "_active" : "").arg(bigButton ? "_big" : "")
169− }
170−
171− MouseArea {
172− id: previewImageMouseArea
173− anchors.fill: parent
174− onClicked: root.previewImageClicked()
175− }
151+ sourceComponent: root.header
176152 }
177153 Loader {
178154 id: buttonLoader
@@ -180,12 +156,6 @@ Rectangle {
180156 anchors.right: parent.right
181157 sourceComponent: root.buttons
182158 }
183− Loader {
184− id: captionLoader
185− anchors.left: parent.left
186− anchors.right: parent.right
187− sourceComponent: root.caption
188− }
189159 }
190160 }
191161
@@ -213,6 +183,6 @@ Rectangle {
213183 parent: root.narrowMode ? leftColumn : rightColumn
214184 anchors.left: parent.left
215185 anchors.right: parent.right
216− sourceComponent: root.description
186+ sourceComponent: root.body
217187 }
218188}
Dash/Generic/GenericPreview.qml+17−3
@@ -23,12 +23,26 @@ import ".."
2323
2424DashPreview {
2525 id: genericPreview
26− property var previewData
2726
2827 title: previewData.title
29− url: IconUtil.from_gicon(previewData.image)
3028 previewWidthRatio: 0.6
3129
30+ property url url: IconUtil.from_gicon(previewData.image)
31+
32+ header: UbuntuShape {
33+ id: urlLoader
34+ anchors.left: parent.left
35+ anchors.right: parent.right
36+ height: width * previewImage.sourceSize.height / previewImage.sourceSize.width
37+ radius: "medium"
38+ image: Image {
39+ id: previewImage
40+ asynchronous: true
41+ source: genericPreview.url
42+ fillMode: Image.PreserveAspectCrop
43+ }
44+ }
45+
3246 buttons: GridView {
3347 id: buttons
3448 model: genericPreview.previewData.actions
@@ -56,7 +70,7 @@ DashPreview {
5670 }
5771 focus: false
5872 }
59− description: Column {
73+ body: Column {
6074 spacing: units.gu(2)
6175
6276 Label {
Dash/GenericScopeView.qml+1−1
@@ -211,7 +211,7 @@ ScopeView {
211211 }
212212
213213 onLoaded: {
214− item.previewData = previewLoader.previewData
214+ item.previewData = Qt.binding(function() { return previewLoader.previewData })
215215 }
216216 }
217217
Dash/PreviewDelegateMapper.qml+2
@@ -19,7 +19,9 @@ import QtQuick 2.0
1919QtObject {
2020 property var d: QtObject {
2121 readonly property string genericPreview: "Generic/GenericPreview.qml"
22+ readonly property string appPreview: "Apps/AppPreview.qml"
2223 property var previewDelegateMapping: {"preview-generic": genericPreview,
24+ "preview-application": appPreview,
2325 }
2426 }
2527
Dash/Video/VideoPreview.qml+35−3
@@ -24,7 +24,9 @@ DashPreview {
2424
2525 property var item
2626 property alias ready: nfo.ready
27+ property bool playable: fileUri != ""
2728 readonly property url fileUri: item ? item.fileUri : ""
29+ property url url: item ? item.nfoUri.replace(/\.nfo$/, "-fanart.jpg") : ""
2830
2931 VideoInfo {
3032 id: nfo
@@ -32,9 +34,7 @@ DashPreview {
3234 }
3335
3436 title: nfo.ready ? nfo.video.title : ""
35− url: item ? item.nfoUri.replace(/\.nfo$/, "-fanart.jpg") : ""
3637 previewWidthRatio: 0.6
37− playable: fileUri != ""
3838
3939 onPreviewImageClicked: {
4040 if (playable) {
@@ -42,6 +42,38 @@ DashPreview {
4242 }
4343 }
4444
45+ // TODO: replace this UbuntuShape with the Video component once that lands
46+ // with the player.
47+ header: UbuntuShape {
48+ id: urlLoader
49+ anchors.left: parent.left
50+ anchors.right: parent.right
51+ height: width * previewImage.sourceSize.height / previewImage.sourceSize.width
52+ radius: "medium"
53+ image: Image {
54+ id: previewImage
55+ asynchronous: true
56+ source: root.url
57+ fillMode: Image.PreserveAspectCrop
58+ }
59+
60+ Image {
61+ objectName: "playButton"
62+ anchors.centerIn: parent
63+ visible: root.playable
64+ readonly property bool bigButton: parent.width > units.gu(40)
65+ width: bigButton ? units.gu(8) : units.gu(4.5)
66+ height: width
67+ source: "../graphics/play_button%1%2.png".arg(previewImageMouseArea.pressed ? "_active" : "").arg(bigButton ? "_big" : "")
68+ }
69+
70+ MouseArea {
71+ id: previewImageMouseArea
72+ anchors.fill: parent
73+ onClicked: root.previewImageClicked()
74+ }
75+ }
76+
4577 buttons: Row {
4678 spacing: units.gu(2)
4779
@@ -64,7 +96,7 @@ DashPreview {
6496 }
6597 }
6698
67− description: Column {
99+ body: Column {
68100 spacing: units.gu(2)
69101 RatingStars {
70102 maximumRating: 10 // FIXME: this should happen on the backend side
plugins/Ubuntu/CMakeLists.txt+1
@@ -1 +1,2 @@
11add_subdirectory(Gestures)
2+add_subdirectory(DownloadDaemonListener)
plugins/Ubuntu/DownloadDaemonListener/CMakeLists.txtnew file+22
@@ -0,0 +1,22 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
4+include_directories(
5+ ${CMAKE_CURRENT_SOURCE_DIR}
6+ ${CMAKE_CURRENT_BINARY_DIR}
7+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
8+)
9+
10+set(DOWNLOADDAEMONLISTENER_SOURCES
11+ plugin.cpp
12+ DownloadTracker.cpp
13+ interface/downloadtrackeradaptor.cpp
14+ )
15+
16+add_library(DownloadDaemonListener MODULE ${DOWNLOADDAEMONLISTENER_SOURCES})
17+
18+qt5_use_modules(DownloadDaemonListener Qml Quick DBus Core)
19+
20+# export the qmldir qmltypes and plugin files
21+export_qmlfiles(Ubuntu.DownloadDaemonListener Ubuntu/DownloadDaemonListener)
22+export_qmlplugin(Ubuntu.DownloadDaemonListener 0.1 Ubuntu/DownloadDaemonListener TARGETS DownloadDaemonListener)
plugins/Ubuntu/DownloadDaemonListener/DownloadTracker.cppnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (C) 2013 - Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ *
18+ * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com>
19+ */
20+
21+
22+#include "DownloadTracker.h"
23+
24+DownloadTracker::DownloadTracker(QObject *parent)
25+ : QObject(parent)
26+ , m_adaptor(nullptr)
27+{
28+}
29+
30+bool DownloadTracker::isServiceReady() const
31+{
32+ bool ready = false;
33+ if(m_adaptor != nullptr) {
34+ ready = m_adaptor->isValid();
35+ }
36+
37+ return ready;
38+}
39+
40+QString DownloadTracker::dbusPath() const
41+{
42+ return m_dbusPath;
43+}
44+
45+void DownloadTracker::setDbusPath(const QString& path)
46+{
47+ if(m_dbusPath != path){
48+ m_dbusPath = path;
49+ startService();
50+ Q_EMIT dbusPathChanged(m_dbusPath);
51+ }
52+}
53+
54+QString DownloadTracker::service() const
55+{
56+ return m_service;
57+}
58+
59+void DownloadTracker::setService(const QString& service)
60+{
61+ if(m_service != service){
62+ m_service = service;
63+ startService();
64+ Q_EMIT serviceChanged(m_service);
65+ }
66+}
67+
68+void DownloadTracker::startService()
69+{
70+ // FIXME update dbus path and service on changes
71+ if(!m_service.isEmpty() && !m_dbusPath.isEmpty()) {
72+ m_adaptor = new DownloadTrackerAdaptor(m_service, m_dbusPath, QDBusConnection::sessionBus(), this);
73+
74+ connect(m_adaptor, SIGNAL(canceled(bool)), this, SIGNAL(canceled(bool)));
75+ connect(m_adaptor, SIGNAL(error(const QString &)), this, SIGNAL(error(const QString &)));
76+ connect(m_adaptor, SIGNAL(finished(const QString &)), this, SIGNAL(finished(const QString &)));
77+ connect(m_adaptor, SIGNAL(paused(bool)), this, SIGNAL(paused(bool)));
78+ connect(m_adaptor, SIGNAL(progress(qulonglong, qulonglong)), this, SIGNAL(progress(qulonglong, qulonglong)));
79+ connect(m_adaptor, SIGNAL(resumed(bool)), this, SIGNAL(resumed(bool)));
80+ connect(m_adaptor, SIGNAL(started(bool)), this, SIGNAL(started(bool)));
81+ }
82+ // FIXME find a better way of determining if the service is ready
83+ Q_EMIT serviceReadyChanged(m_adaptor && m_adaptor->isValid());
84+}
plugins/Ubuntu/DownloadDaemonListener/DownloadTracker.hnew file+69
@@ -0,0 +1,69 @@
1+/*
2+ * Copyright (C) 2013 - Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ *
18+ * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com>
19+ */
20+
21+
22+#ifndef DOWNLOADTRACKER_H
23+#define DOWNLOADTRACKER_H
24+
25+#include <interface/downloadtrackeradaptor.h>
26+
27+#include <QObject>
28+#include <QDBusObjectPath>
29+
30+class DownloadTracker : public QObject
31+{
32+ Q_OBJECT
33+ Q_DISABLE_COPY(DownloadTracker)
34+ Q_PROPERTY(QString service READ service WRITE setService NOTIFY serviceChanged)
35+ Q_PROPERTY(QString dbusPath READ dbusPath WRITE setDbusPath NOTIFY dbusPathChanged)
36+ Q_PROPERTY(bool serviceReady READ isServiceReady NOTIFY serviceReadyChanged)
37+
38+public:
39+ explicit DownloadTracker(QObject *parent = 0);
40+
41+ QString service() const;
42+ QString dbusPath() const;
43+ bool isServiceReady() const;
44+
45+ void setDbusPath(const QString& path);
46+ void setService(const QString& service);
47+
48+Q_SIGNALS:
49+ void serviceChanged(const QString &service);
50+ void dbusPathChanged(const QString &dbusPath);
51+ void serviceReadyChanged(const bool &serviceReady);
52+
53+ void canceled(bool success);
54+ void error(const QString &error);
55+ void finished(const QString &path);
56+ void paused(bool success);
57+ void progress(qulonglong received, qulonglong total);
58+ void resumed(bool success);
59+ void started(bool success);
60+
61+private:
62+ QString m_dbusPath;
63+ QString m_service;
64+ DownloadTrackerAdaptor* m_adaptor;
65+
66+ void startService();
67+};
68+
69+#endif // DOWNLOADTRACKER_H
plugins/Ubuntu/DownloadDaemonListener/interface/downloadtrackeradaptor.cppnew file+25
@@ -0,0 +1,25 @@
1+/*
2+ * This file was generated by qdbusxml2cpp version 0.8
3+ * Command line was: qdbusxml2cpp -v -c DownloadTrackerAdaptor -p downloadtrackeradaptor.h:downloadtrackeradaptor.cpp -i metatypes.h com.canonical.applications.download.xml
4+ *
5+ * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
6+ *
7+ * This is an auto-generated file.
8+ * This file may have been hand-edited. Look for HAND-EDIT comments
9+ * before re-generating it.
10+ */
11+
12+#include "downloadtrackeradaptor.h"
13+
14+/*
15+ * Implementation of interface class DownloadTrackerAdaptor
16+ */
17+
18+DownloadTrackerAdaptor::DownloadTrackerAdaptor(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
19+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
20+{
21+}
22+
23+DownloadTrackerAdaptor::~DownloadTrackerAdaptor()
24+{
25+}
plugins/Ubuntu/DownloadDaemonListener/interface/downloadtrackeradaptor.hnew file+125
@@ -0,0 +1,125 @@
1+/*
2+ * This file was generated by qdbusxml2cpp version 0.8
3+ * Command line was: qdbusxml2cpp -v -c DownloadTrackerAdaptor -p downloadtrackeradaptor.h:downloadtrackeradaptor.cpp -i metatypes.h com.canonical.applications.download.xml
4+ *
5+ * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
6+ *
7+ * This is an auto-generated file.
8+ * Do not edit! All changes made to it will be lost.
9+ */
10+
11+#ifndef DOWNLOADTRACKERADAPTOR_H_1374434371
12+#define DOWNLOADTRACKERADAPTOR_H_1374434371
13+
14+#include <QtCore/QObject>
15+#include <QtCore/QByteArray>
16+#include <QtCore/QList>
17+#include <QtCore/QMap>
18+#include <QtCore/QString>
19+#include <QtCore/QStringList>
20+#include <QtCore/QVariant>
21+#include <QtDBus/QtDBus>
22+#include "metatypes.h"
23+
24+/*
25+ * Proxy class for interface com.canonical.applications.Download
26+ */
27+class DownloadTrackerAdaptor: public QDBusAbstractInterface
28+{
29+ Q_OBJECT
30+public:
31+ static inline const char *staticInterfaceName()
32+ { return "com.canonical.applications.Download"; }
33+
34+public:
35+ DownloadTrackerAdaptor(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
36+
37+ ~DownloadTrackerAdaptor();
38+
39+public Q_SLOTS: // METHODS
40+ inline QDBusPendingReply<> allowGSMDownload(bool allowed)
41+ {
42+ QList<QVariant> argumentList;
43+ argumentList << QVariant::fromValue(allowed);
44+ return asyncCallWithArgumentList(QLatin1String("allowGSMDownload"), argumentList);
45+ }
46+
47+ inline QDBusPendingReply<> cancel()
48+ {
49+ QList<QVariant> argumentList;
50+ return asyncCallWithArgumentList(QLatin1String("cancel"), argumentList);
51+ }
52+
53+ inline QDBusPendingReply<bool> isGSMDownloadAllowed()
54+ {
55+ QList<QVariant> argumentList;
56+ return asyncCallWithArgumentList(QLatin1String("isGSMDownloadAllowed"), argumentList);
57+ }
58+
59+ inline QDBusPendingReply<QVariantMap> metadata()
60+ {
61+ QList<QVariant> argumentList;
62+ return asyncCallWithArgumentList(QLatin1String("metadata"), argumentList);
63+ }
64+
65+ inline QDBusPendingReply<> pause()
66+ {
67+ QList<QVariant> argumentList;
68+ return asyncCallWithArgumentList(QLatin1String("pause"), argumentList);
69+ }
70+
71+ inline QDBusPendingReply<qulonglong> progress()
72+ {
73+ QList<QVariant> argumentList;
74+ return asyncCallWithArgumentList(QLatin1String("progress"), argumentList);
75+ }
76+
77+ inline QDBusPendingReply<> resume()
78+ {
79+ QList<QVariant> argumentList;
80+ return asyncCallWithArgumentList(QLatin1String("resume"), argumentList);
81+ }
82+
83+ inline QDBusPendingReply<> setThrottle(qulonglong speed)
84+ {
85+ QList<QVariant> argumentList;
86+ argumentList << QVariant::fromValue(speed);
87+ return asyncCallWithArgumentList(QLatin1String("setThrottle"), argumentList);
88+ }
89+
90+ inline QDBusPendingReply<> start()
91+ {
92+ QList<QVariant> argumentList;
93+ return asyncCallWithArgumentList(QLatin1String("start"), argumentList);
94+ }
95+
96+ inline QDBusPendingReply<qulonglong> throttle()
97+ {
98+ QList<QVariant> argumentList;
99+ return asyncCallWithArgumentList(QLatin1String("throttle"), argumentList);
100+ }
101+
102+ inline QDBusPendingReply<qulonglong> totalSize()
103+ {
104+ QList<QVariant> argumentList;
105+ return asyncCallWithArgumentList(QLatin1String("totalSize"), argumentList);
106+ }
107+
108+Q_SIGNALS: // SIGNALS
109+ void canceled(bool success);
110+ void error(const QString &error);
111+ void finished(const QString &path);
112+ void paused(bool success);
113+ void progress(qulonglong received, qulonglong total);
114+ void resumed(bool success);
115+ void started(bool success);
116+};
117+
118+namespace com {
119+ namespace canonical {
120+ namespace applications {
121+ typedef ::DownloadTrackerAdaptor Download;
122+ }
123+ }
124+}
125+#endif
plugins/Ubuntu/DownloadDaemonListener/interface/metatypes.hnew file+28
@@ -0,0 +1,28 @@
1+/*
2+ * Copyright 2013 2013 Canonical Ltd.
3+ *
4+ * This library is free software; you can redistribute it and/or
5+ * modify it under the terms of version 3 of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation.
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 GNU
11+ * General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public
14+ * License along with this library; if not, write to the
15+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16+ * Boston, MA 02110-1301, USA.
17+ */
18+
19+#ifndef DOWNLOADER_LIB_APP_METATYPES_H
20+#define DOWNLOADER_LIB_APP_METATYPES_H
21+
22+#include <QMap>
23+
24+typedef QMap<QString, QString> StringMap;
25+
26+Q_DECLARE_METATYPE(StringMap)
27+
28+#endif // METATYPES_H
plugins/Ubuntu/DownloadDaemonListener/plugin.cppnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2013 - Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ *
18+ * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com>
19+ */
20+
21+
22+#include "plugin.h"
23+#include "DownloadTracker.h"
24+
25+#include <QtQml>
26+#include <QtQml/QQmlContext>
27+
28+
29+void BackendPlugin::registerTypes(const char *uri)
30+{
31+ Q_ASSERT(uri == QLatin1String("Ubuntu.DownloadDaemonListener"));
32+
33+ qmlRegisterType<DownloadTracker>(uri, 0, 1, "DownloadTracker");
34+}
35+
36+void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
37+{
38+ QQmlExtensionPlugin::initializeEngine(engine, uri);
39+}
plugins/Ubuntu/DownloadDaemonListener/plugin.hnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright (C) 2013 - Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ *
18+ * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com>
19+ */
20+
21+
22+#ifndef BACKEND_PLUGIN_H
23+#define BACKEND_PLUGIN_H
24+
25+#include <QQmlEngine>
26+#include <QQmlExtensionPlugin>
27+
28+class BackendPlugin : public QQmlExtensionPlugin
29+{
30+ Q_OBJECT
31+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
32+
33+public:
34+ void registerTypes(const char *uri);
35+ void initializeEngine(QQmlEngine *engine, const char *uri);
36+};
37+#endif // BACKEND_PLUGIN_H
plugins/Ubuntu/DownloadDaemonListener/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Ubuntu.DownloadDaemonListener
2+plugin DownloadDaemonListener
3+typeinfo plugins.qmltypes
plugins/Unity/preview.cpp+7
@@ -94,6 +94,11 @@ QVariant Preview::infoHints()
9494 return QVariant::fromValue(m_infoHints);
9595}
9696
97+QVariantMap Preview::infoHintsHash() const
98+{
99+ return m_infoHintsHash;
100+}
101+
97102QString Preview::image() const
98103{
99104 if (m_unityPreview) {
@@ -145,6 +150,7 @@ void Preview::setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview)
145150
146151 qDeleteAll(m_infoHints);
147152 m_infoHints.clear();
153+ m_infoHintsHash.clear();
148154 qDeleteAll(m_actions);
149155 m_actions.clear();
150156
@@ -152,6 +158,7 @@ void Preview::setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview)
152158 auto hint = new PreviewInfoHint(this);
153159 hint->setUnityInfoHint(unityInfoHint);
154160 m_infoHints.append(hint);
161+ m_infoHintsHash[hint->id()] = QVariant::fromValue(hint);
155162 }
156163
157164 for (auto unityAction: m_unityPreview->GetActions()) {
plugins/Unity/preview.h+4
@@ -25,6 +25,7 @@
2525#include <QString>
2626#include <QMetaType>
2727#include <QList>
28+#include <QVariantMap>
2829
2930// libunity-core
3031#include <UnityCore/Preview.h>
@@ -42,6 +43,7 @@ class Q_DECL_EXPORT Preview : public QObject
4243 Q_PROPERTY(QString description READ description NOTIFY previewChanged)
4344 Q_PROPERTY(QVariant actions READ actions NOTIFY previewChanged)
4445 Q_PROPERTY(QVariant infoHints READ infoHints NOTIFY previewChanged)
46+ Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
4547 Q_PROPERTY(QString image READ image NOTIFY previewChanged)
4648 Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
4749
@@ -55,6 +57,7 @@ public:
5557 QString description() const;
5658 QVariant actions();
5759 QVariant infoHints();
60+ QVariantMap infoHintsHash() const;
5861 QString image() const;
5962 QString imageSourceUri() const;
6063
@@ -73,6 +76,7 @@ private:
7376
7477 QList<QObject *> m_actions;
7578 QList<QObject *> m_infoHints;
79+ QVariantMap m_infoHintsHash;
7680};
7781
7882Q_DECLARE_METATYPE(Preview *)
po/unity8.pot+39−4
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2013-08-09 10:12+0200\n"
11+"POT-Creation-Date: 2013-08-09 12:18+0200\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,6 +16,7 @@ msgstr ""
1616"MIME-Version: 1.0\n"
1717"Content-Type: text/plain; charset=CHARSET\n"
1818"Content-Transfer-Encoding: 8bit\n"
19+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
1920
2021#: Applications/applications.js:23
2122msgid "Phone"
@@ -89,6 +90,40 @@ msgstr ""
8990msgid "Recent searches"
9091msgstr ""
9192
93+#. TRANSLATORS: Number of persons who rated this app
94+#: Dash/Apps/AppInfo.qml:72
95+#, qt-format
96+msgid "(%1)"
97+msgstr ""
98+
99+#. TRANSLATORS: Number of persons who wrote reviews for this app
100+#: Dash/Apps/AppInfo.qml:84 tests/qmltests/Dash/Apps/tst_AppPreview.qml:115
101+#, qt-format
102+msgid "%1 review"
103+msgid_plural "%1 reviews"
104+msgstr[0] ""
105+msgstr[1] ""
106+
107+#: Dash/Apps/AppPreview.qml:181
108+msgid "Rate this"
109+msgstr ""
110+
111+#: Dash/Apps/AppReviews.qml:72
112+msgid "Add a review"
113+msgstr ""
114+
115+#: Dash/Apps/AppReviews.qml:84
116+msgid "Review"
117+msgstr ""
118+
119+#: Dash/Apps/AppReviews.qml:118
120+msgid "Send"
121+msgstr ""
122+
123+#: Dash/Apps/AppReviews.qml:136
124+msgid "Comments:"
125+msgstr ""
126+
92127#: Dash/DashApps.qml:65
93128msgid "Running apps"
94129msgstr ""
@@ -153,15 +188,15 @@ msgstr ""
153188msgid "Videos"
154189msgstr ""
155190
156−#: Dash/Video/VideoPreview.qml:98
191+#: Dash/Video/VideoPreview.qml:130
157192msgid "Directed by:"
158193msgstr ""
159194
160−#: Dash/Video/VideoPreview.qml:121
195+#: Dash/Video/VideoPreview.qml:153
161196msgid "Starring:"
162197msgstr ""
163198
164−#: Dash/Video/VideoPreview.qml:144
199+#: Dash/Video/VideoPreview.qml:176
165200msgid "Author:"
166201msgstr ""
167202
tests/mocks/Ubuntu/CMakeLists.txt+1
@@ -1 +1,2 @@
11add_subdirectory(Application)
2+add_subdirectory(DownloadDaemonListener)
tests/mocks/Ubuntu/DownloadDaemonListener/CMakeLists.txtnew file+18
@@ -0,0 +1,18 @@
1+set(FakeUbuntuDownloadDaemonListenerQml_SOURCES
2+ plugin.cpp
3+ MockDownloadTracker.cpp
4+)
5+
6+add_library(FakeUbuntuDownloadDaemonListenerQml MODULE ${FakeUbuntuDownloadDaemonListenerQml_SOURCES})
7+
8+qt5_use_modules(FakeUbuntuDownloadDaemonListenerQml Core Quick)
9+
10+# copy files into build directory for shadow builds
11+add_custom_target(UbuntuDownloadQmlDirFile ALL
12+ COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" ${CMAKE_CURRENT_BINARY_DIR}
13+ DEPENDS qmldir
14+)
15+
16+install(TARGETS FakeUbuntuDownloadDaemonListenerQml
17+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Ubuntu/DownloadDaemonListener
18+ )
tests/mocks/Ubuntu/DownloadDaemonListener/MockDownloadTracker.cppnew file+67
@@ -0,0 +1,67 @@
1+/*
2+ * Copyright (C) 2013 - Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ *
18+ * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com>
19+ */
20+
21+
22+#include "MockDownloadTracker.h"
23+
24+MockDownloadTracker::MockDownloadTracker(QObject *parent)
25+ : QObject(parent)
26+ , m_active(false)
27+{
28+}
29+
30+bool MockDownloadTracker::isServiceReady() const
31+{
32+ return m_active;
33+}
34+
35+QString MockDownloadTracker::dbusPath() const
36+{
37+ return m_dbusPath;
38+}
39+
40+void MockDownloadTracker::setDbusPath(const QString& path)
41+{
42+ if(m_dbusPath != path){
43+ m_dbusPath = path;
44+ startService();
45+ }
46+}
47+
48+QString MockDownloadTracker::service() const
49+{
50+ return m_service;
51+}
52+
53+void MockDownloadTracker::setService(const QString& service)
54+{
55+ if(m_service != service){
56+ m_service = service;
57+ startService();
58+ }
59+}
60+
61+void MockDownloadTracker::startService()
62+{
63+ if(!m_service.isEmpty() && !m_dbusPath.isEmpty()) {
64+ m_active = true;
65+ Q_EMIT serviceReadyChanged(m_active);
66+ }
67+}
tests/mocks/Ubuntu/DownloadDaemonListener/MockDownloadTracker.hnew file+66
@@ -0,0 +1,66 @@
1+/*
2+ * Copyright (C) 2013 - Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ *
18+ * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com>
19+ */
20+
21+
22+#ifndef MOCKDOWNLOADTRACKER_H
23+#define MOCKDOWNLOADTRACKER_H
24+
25+#include <QObject>
26+
27+class MockDownloadTracker : public QObject
28+{
29+ Q_OBJECT
30+ Q_DISABLE_COPY(MockDownloadTracker)
31+ Q_PROPERTY(QString service READ service WRITE setService NOTIFY serviceChanged)
32+ Q_PROPERTY(QString dbusPath READ dbusPath WRITE setDbusPath NOTIFY dbusPathChanged)
33+ Q_PROPERTY(bool serviceReady READ isServiceReady NOTIFY serviceReadyChanged)
34+
35+public:
36+ explicit MockDownloadTracker(QObject *parent = 0);
37+
38+ QString service() const;
39+ QString dbusPath() const;
40+ bool isServiceReady() const;
41+
42+ void setDbusPath(const QString& path);
43+ void setService(const QString& service);
44+
45+Q_SIGNALS:
46+ void serviceChanged(const QString &service);
47+ void dbusPathChanged(const QString &dbusPath);
48+ void serviceReadyChanged(const bool &serviceReady);
49+
50+ void canceled(bool success);
51+ void error(const QString &error);
52+ void finished(const QString &path);
53+ void paused(bool success);
54+ void progress(qulonglong received, qulonglong total);
55+ void resumed(bool success);
56+ void started(bool success);
57+
58+private:
59+ QString m_dbusPath;
60+ QString m_service;
61+ bool m_active;
62+
63+ void startService();
64+};
65+
66+#endif // MOCKDOWNLOADTRACKER_H
tests/mocks/Ubuntu/DownloadDaemonListener/plugin.cppnew file+28
@@ -0,0 +1,28 @@
1+/*
2+ * Copyright (C) 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+#include "plugin.h"
18+#include "MockDownloadTracker.h"
19+
20+#include <QtQml>
21+#include <QtQml/QQmlContext>
22+#include <qqml.h>
23+
24+
25+void FakeUbuntuDownloadDaemonListenerQmlPlugin::registerTypes(const char *uri)
26+{
27+ qmlRegisterType<MockDownloadTracker>(uri, 0, 1, "DownloadTracker");
28+}
tests/mocks/Ubuntu/DownloadDaemonListener/plugin.hnew file+30
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (C) 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+#ifndef PLUGIN_H
18+#define PLUGIN_H
19+
20+#include <QQmlExtensionPlugin>
21+
22+class FakeUbuntuDownloadDaemonListenerQmlPlugin : public QQmlExtensionPlugin
23+{
24+ Q_OBJECT
25+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26+public:
27+ void registerTypes(const char *uri);
28+};
29+
30+#endif
tests/mocks/Ubuntu/DownloadDaemonListener/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Ubuntu.DownloadDaemonListener
2+plugin FakeUbuntuDownloadDaemonListenerQml
tests/qmltests/CMakeLists.txt+2
@@ -49,6 +49,8 @@ add_qml_test(Dash ScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_D
4949add_qml_test(Dash FilterGrids IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins
5050 ${CMAKE_BINARY_DIR}/tests/mocks)
5151add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
52+add_qml_test(Dash/Apps AppPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
53+add_qml_test(Dash/Video VideoPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
5254add_qml_test(Greeter Lockscreen IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
5355 PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
5456add_qml_test(Greeter Tablet IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
tests/qmltests/Dash/Apps/tst_AppPreview.qmlnew file+152
@@ -0,0 +1,152 @@
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 Ubuntu.Components 0.1
20+import "../../../../Dash/Apps"
21+import Unity.Test 0.1 as UT
22+
23+Item {
24+ id: root
25+ width: units.gu(60)
26+ height: units.gu(80)
27+
28+ property var calls: []
29+
30+ SignalSpy {
31+ id: sendPreviewSpy
32+ target: appPreview
33+ signalName: "sendUserReview"
34+ }
35+
36+ property string commentary: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus a mi vitae augue rhoncus lobortis ut rutrum metus. Curabitur tortor leo, tristique sed mollis quis, condimentum venenatis nibh.";
37+ QtObject { id: screenshots; property var value: ["fake_image1.png", "fake_image2.png", "fake_image3.png"] }
38+ QtObject { id: rating; property int value: 8 }
39+ QtObject { id: rated; property int value: 120 }
40+ QtObject { id: reviews; property int value: 8 }
41+ QtObject { id: progress; property string value: "source" }
42+ QtObject { id: comments; property var value: [
43+ ["Unity User", 4, "08/20/2013", root.commentary],
44+ ["Unity User", 8, "01/15/2013", root.commentary],
45+ ["Unity User", 10, "10/02/2013", root.commentary],
46+ ]
47+ }
48+
49+ QtObject {
50+ id: data
51+ property string title: "Unity App"
52+ property string appIcon: "fake_image.png"
53+ property string description: "This is an Application description"
54+ property var execute: root.fake_call
55+ property var infoMap: {
56+ "more-screenshots": screenshots,
57+ "rating": rating,
58+ "rated": rated,
59+ "reviews": reviews,
60+ "comments": comments
61+ }
62+ property var actions: [
63+ { "id": 123, "displayName": "action1" },
64+ { "id": 456, "displayName": "action2" },
65+ { "id": 789, "displayName": "action3" },
66+ ]
67+ }
68+
69+ function fake_call(id, data){
70+ root.calls[root.calls.length] = id;
71+ }
72+
73+ // The component under test
74+ AppPreview {
75+ id: appPreview
76+ anchors.fill: parent
77+
78+ previewData: data
79+ }
80+
81+ UT.UnityTestCase {
82+ name: "AppPreview"
83+ when: windowShown
84+
85+ function cleanup() {
86+ root.calls = new Array();
87+ sendPreviewSpy.clear();
88+ var reviewField = findChild(appPreview, "reviewField");
89+ reviewField.focus = false;
90+ reviewField.text = "";
91+ }
92+
93+ function test_actions() {
94+ var buttons = findChild(appPreview, "gridButtons");
95+ compare(buttons.count, 3, "Not the proper amount of actions detected.");
96+
97+ for(var i = 0; i < buttons.count; i++) {
98+ buttons.currentIndex = i;
99+ buttons.currentItem.clicked();
100+ }
101+
102+ var actions = data.actions;
103+ for(var i = 0; i < actions.length; i++) {
104+ compare(root.calls[i], actions[i].id, "Id of action not found.");
105+ }
106+ }
107+
108+ function test_rated() {
109+ var rated = findChild(appPreview, "ratedLabel");
110+ compare(rated.text, "(120)", "Rates not equal");
111+ }
112+
113+ function test_reviews() {
114+ var rated = findChild(appPreview, "reviewsLabel");
115+ compare(rated.text, "8 reviews", "Reviews don't match");
116+ }
117+
118+ function test_send_review() {
119+ var appReviews = findChild(appPreview, "appReviews");
120+ appReviews.sendReview("review");
121+ sendPreviewSpy.wait();
122+ }
123+
124+ function test_review_focus() {
125+ var appReviews = findChild(appPreview, "appReviews");
126+ var sendButton = findChild(appReviews, "sendButton");
127+ var reviewField = findChild(appReviews, "reviewField");
128+
129+ compare(reviewField.focus, false, "ReviewField shouldn't have focus");
130+ compare(appReviews.state, "", "State should be empty");
131+
132+ mouseClick(reviewField, reviewField.width/2, reviewField.height/2);
133+ compare(reviewField.focus, true, "Review Field should have focus");
134+ compare(appReviews.state, "editing", "State should be 'editing'");
135+ }
136+
137+ function test_comments() {
138+ var commentsArea = findChild(appPreview, "commentsArea");
139+ compare(commentsArea.count, 3);
140+ for(var i = 0; i < 3; i++) {
141+ var username = commentsArea.itemAt(i).children[0].children[0].text
142+ var rate = commentsArea.itemAt(i).children[0].children[1].children[0].rating
143+ var date = commentsArea.itemAt(i).children[0].children[1].children[1].text
144+ var comment = commentsArea.itemAt(i).children[1].text
145+ compare(username, comments.value[i][0], "Username don't match");
146+ compare(rate, comments.value[i][1], "Rating don't match");
147+ compare(date, comments.value[i][2], "Date don't match");
148+ compare(comment, comments.value[i][3], "Comment don't match");
149+ }
150+ }
151+ }
152+}
tests/qmltests/Dash/Video/tst_VideoPreview.qmlnew file+63
@@ -0,0 +1,63 @@
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 "../../../../Dash/Video"
20+import Unity.Test 0.1 as UT
21+
22+Item {
23+ id: root
24+ width: units.gu(60)
25+ height: units.gu(80)
26+
27+ SignalSpy {
28+ id: previewClickedSpy
29+ target: preview
30+ signalName: "previewImageClicked"
31+ }
32+
33+ // The component under test
34+ VideoPreview {
35+ id: preview
36+ anchors.fill: parent
37+ }
38+
39+ UT.UnityTestCase {
40+ name: "VideoPreview"
41+ when: windowShown
42+
43+ function test_play_button_data() {
44+ return [
45+ {tag: "playable", playable: true},
46+ {tag: "not playable", playable: false}
47+ ]
48+ }
49+
50+ function test_play_button(data) {
51+ var playButton = findChild(preview, "playButton")
52+ preview.playable = data.playable
53+ compare(playButton.visible, data.playable)
54+ }
55+
56+ function test_play_button_click() {
57+ preview.playable = true
58+ var playButton = findChild(preview, "playButton")
59+ mouseClick(playButton, 1, 1)
60+ tryCompare(previewClickedSpy, "count", 1)
61+ }
62+ }
63+}
tests/qmltests/Dash/tst_DashPreview.qml+2−23
@@ -32,7 +32,6 @@ Item {
3232 id: preview
3333 anchors.fill: parent
3434 title: "Testing rocks, debugging sucks!"
35− forceSquare: true
3635
3736 buttons: Row {
3837 width: parent.width
@@ -55,9 +54,9 @@ Item {
5554 }
5655 }
5756
58− caption: Label { text: "Caption label" }
57+ header: Label { text: "Caption label" }
5958
60− description: Column {
59+ body: Column {
6160 id: testContent
6261 objectName: "testContent"
6362 width: parent.width
@@ -102,26 +101,6 @@ Item {
102101 compare(closeSpy.count, 1, "Close signal not emitted")
103102 }
104103
105− function test_play_button_data() {
106− return [
107− {tag: "playable", playable: true},
108− {tag: "not playable", playable: false}
109− ]
110− }
111−
112− function test_play_button(data) {
113− var playButton = findChild(preview, "playButton")
114− preview.playable = data.playable
115− compare(playButton.visible, data.playable)
116− }
117−
118− function test_play_button_click() {
119− preview.playable = true
120− var playButton = findChild(preview, "playButton")
121− mouseClick(playButton, 1, 1)
122− tryCompare(previewClickedSpy, "count", 1)
123− }
124−
125104 function test_columns_data() {
126105 return [
127106 {tag: "1 columns", width: units.gu(5), height: units.gu(10), columns: 1},