on 7.84+14.04.20140228-0ubuntu1 help sign in
unity8/qml/Greeter/Infographics.qml
461 lines 15 kB history raw
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 */
17import "../Components"
18import "Gradient.js" as Gradient
19import QtQuick 2.0
20import Ubuntu.Components 0.1
22Item {
23 id: infographic
25 property var model
27 property int animDuration: 10
29 Connections {
30 target: model
32 onDataAboutToAppear: startHideAnimation() // hide "no data" label
33 onDataAppeared: startShowAnimation()
35 onDataAboutToChange: startHideAnimation()
36 onDataChanged: startShowAnimation()
38 onDataAboutToDisappear: startHideAnimation()
39 onDataDisappeared: startShowAnimation() // show "no data" label
40 }
42 function startShowAnimation() {
43 dotHideAnimTimer.stop()
44 circleShrinkAnimTimer.stop()
45 notification.hideAnim.stop()
47 dotShowAnimTimer.startFromBeginning()
48 notification.showAnim.start()
49 }
51 function startHideAnimation() {
52 dotShowAnimTimer.stop()
53 circleGrowAnimTimer.stop()
54 notification.showAnim.stop()
56 dotHideAnimTimer.startFromBeginning()
57 notification.hideAnim.start()
58 }
60 visible: model.label !== ""
62 Component.onCompleted: startShowAnimation()
64 Item {
65 id: dataCircle
66 objectName: "dataCircle"
68 property real divisor: 1.5
70 width: Math.min(parent.height, parent.width) / divisor
71 height: width
73 anchors.centerIn: parent
75 Timer {
76 id: circleGrowAnimTimer
78 property int pastCircleCounter
79 property int presentCircleCounter
81 interval: animDuration
82 running: false
83 repeat: true
84 onTriggered: {
85 if (pastCircleCounter < pastCircles.count) {
86 var nextCircle = pastCircles.itemAt(pastCircleCounter++)
87 if (nextCircle !== null) nextCircle.pastCircleGrowAnim.start()
88 }
89 if (pastCircleCounter > pastCircles.count / 2) {
90 var nextCircle = presentCircles.itemAt(presentCircleCounter++)
91 if (nextCircle !== null) nextCircle.presentCircleGrowAnim.start()
92 }
93 if (presentCircleCounter > infographic.model.currentDay && pastCircleCounter >= pastCircles.count) {
94 stop()
95 }
96 }
98 function startFromBeginning() {
99 circleGrowAnimTimer.pastCircleCounter = 0
100 circleGrowAnimTimer.presentCircleCounter = 0
101 start()
102 }
103 }
105 Timer {
106 id: circleShrinkAnimTimer
108 property int pastCircleCounter
109 property int presentCircleCounter
111 interval: animDuration
112 running: false
113 repeat: true
114 onTriggered: {
115 if (pastCircleCounter >= 0) {
116 var nextCircle = pastCircles.itemAt(pastCircleCounter--)
117 if (nextCircle !== null) nextCircle.pastCircleShrinkAnim.start()
118 }
119 if (pastCircleCounter < pastCircles.count / 2) {
120 var nextCircle = presentCircles.itemAt(presentCircleCounter--)
121 if (nextCircle !== null) nextCircle.presentCircleShrinkAnim.start()
122 }
123 if (presentCircleCounter < 0) {
124 stop()
125 infographic.model.readyForDataChange()
126 }
127 }
129 function startFromBeginning() {
130 pastCircleCounter = pastCircles.count - 1
131 presentCircleCounter = model.currentDay
132 start()
133 }
134 }
136 Repeater {
137 id: pastCircles
138 objectName: "pastCircles"
139 model: infographic.model.secondMonth
141 delegate: ObjectPositioner {
142 property alias pastCircleGrowAnim: pastCircleGrowAnim
143 property alias pastCircleShrinkAnim: pastCircleShrinkAnim
145 index: model.index
146 count: pastCircles.count
147 radius: parent.width / 2
148 halfSize: pastCircle.width / 2
149 posOffset: 0.0
151 Circle {
152 id: pastCircle
153 objectName: "pastCircle" + index
155 property real divisor: 1.8
156 property real circleOpacity: 0.1
158 width: dataCircle.width / divisor
159 height: dataCircle.height / divisor
160 opacity: 0.0
161 scale: 0.0
162 visible: modelData !== undefined
163 color: Gradient.threeColorByIndex(index, count, infographic.model.secondColor)
165 SequentialAnimation {
166 id: pastCircleGrowAnim
168 loops: 1
169 ParallelAnimation {
170 PropertyAnimation {
171 target: pastCircle
172 property: "opacity"
173 from: 0.0
174 to: pastCircle.circleOpacity
175 easing.type: Easing.OutCurve
176 duration: circleGrowAnimTimer.interval * 4
177 }
178 PropertyAnimation {
179 target: pastCircle
180 property: "scale"
181 from: 0.0
182 to: modelData
183 easing.type: Easing.OutCurve
184 duration: circleGrowAnimTimer.interval * 4
185 }
186 }
187 }
189 SequentialAnimation {
190 id: pastCircleShrinkAnim
192 loops: 1
193 ParallelAnimation {
194 PropertyAnimation {
195 target: pastCircle
196 property: "opacity"
197 from: pastCircle.circleOpacity
198 to: 0.0
199 easing.type: Easing.OutCurve
200 duration: circleShrinkAnimTimer.interval * 4
201 }
202 PropertyAnimation {
203 target: pastCircle
204 property: "scale"
205 from: modelData
206 to: 0.0
207 easing.type: Easing.OutCurve
208 duration: circleShrinkAnimTimer.interval * 4
209 }
210 }
211 }
212 }
213 }
214 }
216 Repeater {
217 id: presentCircles
218 objectName: "presentCircles"
219 model: infographic.model.firstMonth
221 delegate: ObjectPositioner {
222 property alias presentCircleGrowAnim: presentCircleGrowAnim
223 property alias presentCircleShrinkAnim: presentCircleShrinkAnim
225 index: model.index
226 count: presentCircles.count
227 radius: parent.width / 2
228 halfSize: presentCircle.width / 2
229 posOffset: 0.0
231 Circle {
232 id: presentCircle
233 objectName: "presentCircle" + index
235 property real divisor: 1.8
236 property real circleOpacity: 0.3
238 width: dataCircle.width / divisor
239 height: dataCircle.height / divisor
240 opacity: 0.0
241 scale: 0.0
242 visible: modelData !== undefined
243 color: Gradient.threeColorByIndex(index, infographic.model.currentDay, infographic.model.firstColor)
245 SequentialAnimation {
246 id: presentCircleGrowAnim
248 loops: 1
250 ParallelAnimation {
251 PropertyAnimation {
252 target: presentCircle
253 property: "opacity"
254 to: presentCircle.circleOpacity
255 easing.type: Easing.OutCurve
256 duration: circleGrowAnimTimer.interval * 4
257 }
258 PropertyAnimation {
259 target: presentCircle
260 property: "scale"
261 to: modelData
262 easing.type: Easing.OutCurve
263 duration: circleGrowAnimTimer.interval * 4
264 }
265 }
266 }
268 SequentialAnimation {
269 id: presentCircleShrinkAnim
271 loops: 1
272 ParallelAnimation {
273 PropertyAnimation {
274 target: presentCircle
275 property: "opacity"
276 to: 0.0
277 easing.type: Easing.OutCurve
278 duration: circleShrinkAnimTimer.interval * 4
279 }
280 PropertyAnimation {
281 target: presentCircle
282 property: "scale"
283 to: 0.0
284 easing.type: Easing.OutCurve
285 duration: circleShrinkAnimTimer.interval * 4
286 }
287 }
288 }
289 }
290 }
291 }
293 Image {
294 id: backgroundCircle
295 objectName: "backgroundCircle"
297 anchors.fill: parent
299 source: "graphics/infographic_circle_back.png"
300 }
302 Timer {
303 id: dotShowAnimTimer
305 property int dotCounter: 0
307 interval: animDuration * 0.5; running: false; repeat: true
308 onTriggered: {
309 if (dotCounter < dots.count) {
310 var nextDot = dots.itemAt(dotCounter++)
311 nextDot.unlockAnimation.start()
312 } else {
313 stop()
314 }
315 if (dotCounter == Math.round(dots.count / 2)) {
316 circleGrowAnimTimer.startFromBeginning()
317 }
318 }
320 function startFromBeginning() {
321 if (!dotShowAnimTimer.running)
322 dotCounter = 0
324 start()
325 }
326 }
328 Timer {
329 id: dotHideAnimTimer
331 property int dotCounter
333 interval: animDuration * 0.5
334 running: false
335 repeat: true
336 onTriggered: {
337 if (dotCounter >= 0) {
338 var nextDot = dots.itemAt(dotCounter--)
339 nextDot.changeAnimation.start()
340 } else {
341 stop()
342 }
343 if (dotCounter == Math.round(dots.count / 2)) {
344 circleShrinkAnimTimer.startFromBeginning()
345 }
346 }
348 function startFromBeginning() {
349 if (!dotHideAnimTimer.running)
350 dotCounter = dots.count - 1
352 start()
353 }
354 }
356 Repeater {
357 id: dots
358 objectName: "dots"
360 model: infographic.model.firstMonth
362 delegate: ObjectPositioner {
363 property alias unlockAnimation: dotUnlockAnim
364 property alias changeAnimation: dotChangeAnim
366 property int currentDay: infographic.model.currentDay
368 index: model.index
369 count: dots.count
370 radius: backgroundCircle.width / 2
371 halfSize: dot.width / 2
372 posOffset: radius / dot.width / 3
373 state: dot.state
375 Dot {
376 id: dot
377 objectName: "dot" + index
379 property real baseOpacity: 0.4
381 width: units.dp(5) * parent.radius / 200
382 height: units.dp(5) * parent.radius / 200
383 opacity: 0.0
384 smooth: true
385 state: index < currentDay ? "filled" : index == currentDay ? "pointer" : "unfilled"
387 PropertyAnimation {
388 id: dotUnlockAnim
390 target: dot
391 property: "opacity"
392 to: dot.baseOpacity
393 duration: dotShowAnimTimer.interval
394 }
396 PropertyAnimation {
397 id: dotChangeAnim
399 target: dot
400 property: "opacity"
401 to: 0.0
402 duration: dotHideAnimTimer.interval
403 }
404 }
405 }
406 }
408 Label {
409 id: notification
410 objectName: "label"
412 property alias hideAnim: decreaseOpacity
413 property alias showAnim: increaseOpacity
415 property real baseOpacity: 0.6
417 height: 0.7 * backgroundCircle.width
418 width: notification.height
419 anchors.centerIn: parent
421 text: infographic.model.label
423 wrapMode: Text.WordWrap
424 horizontalAlignment: Text.AlignHCenter
425 verticalAlignment: Text.AlignVCenter
426 color: "white"
428 PropertyAnimation {
429 id: increaseOpacity
431 target: notification
432 property: "opacity"
433 from: 0.0
434 to: notification.baseOpacity
435 duration: dotShowAnimTimer.interval * dots.count * 5
436 }
438 PropertyAnimation {
439 id: decreaseOpacity
441 target: notification
442 property: "opacity"
443 from: notification.baseOpacity
444 to: 0.0
445 duration: dotShowAnimTimer.interval * dots.count * 5
446 }
447 }
448 }
450 MouseArea {
451 anchors.fill: dataCircle
453 onDoubleClicked: {
454 if (!dotHideAnimTimer.running &&
455 !dotShowAnimTimer.running &&
456 !circleShrinkAnimTimer.running &&
457 !circleGrowAnimTimer.running)
458 infographic.model.nextDataSource()
459 }
460 }