on bbbdccd help sign in
unity8/qml/Greeter/Infographics.qml
413 lines 14 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.4
20import Ubuntu.Components 1.3
22Item {
23 id: infographic
25 property var model
27 property int animDuration: 10
29 QtObject {
30 id: d
31 objectName: "infographicPrivate"
32 property bool useDotAnimation: true
33 property int circleModifier: useDotAnimation ? 1 : 2
34 property bool animating: dotHideAnimTimer.running
35 || dotShowAnimTimer.running
36 || circleChangeAnimTimer.running
37 }
39 Connections {
40 target: model
41 ignoreUnknownSignals: model === undefined
43 onDataAboutToAppear: startHideAnimation() // hide "no data" label
44 onDataAppeared: startShowAnimation()
46 onDataAboutToChange: startHideAnimation()
47 onDataChanged: startShowAnimation()
49 onDataAboutToDisappear: startHideAnimation()
50 onDataDisappeared: startShowAnimation() // show "no data" label
51 }
53 function startShowAnimation() {
54 dotHideAnimTimer.stop()
55 notification.hideAnim.stop()
57 if (d.useDotAnimation) {
58 dotShowAnimTimer.startFromBeginning()
59 }
60 notification.showAnim.start()
61 }
63 function startHideAnimation() {
64 dotShowAnimTimer.stop()
65 circleChangeAnimTimer.stop()
66 notification.showAnim.stop()
68 if (d.useDotAnimation) {
69 dotHideAnimTimer.startFromBeginning()
70 } else {
71 circleChangeAnimTimer.startFromBeginning()
72 }
73 notification.hideAnim.start()
74 }
76 visible: model.username !== ""
78 Component.onCompleted: startShowAnimation()
80 Item {
81 id: dataCircle
82 objectName: "dataCircle"
84 property real divisor: 1.5
86 width: Math.min(parent.height, parent.width) / divisor
87 height: width
89 anchors.centerIn: parent
91 Timer {
92 id: circleChangeAnimTimer
94 property int pastCircleCounter
95 property int presentCircleCounter
97 interval: notification.duration
98 running: false
99 repeat: true
100 onTriggered: {
101 if (pastCircleCounter < pastCircles.count) {
102 var nextCircle = pastCircles.itemAt(pastCircleCounter++)
103 if (nextCircle !== null) nextCircle.pastCircleChangeAnim.start()
104 }
105 if (pastCircleCounter > pastCircles.count / 2) {
106 var nextCircle = presentCircles.itemAt(presentCircleCounter++)
107 if (nextCircle !== null) nextCircle.presentCircleChangeAnim.start()
108 }
109 if (presentCircleCounter > infographic.model.currentDay && pastCircleCounter >= pastCircles.count) {
110 stop()
111 }
112 }
114 function startFromBeginning() {
115 circleChangeAnimTimer.pastCircleCounter = 0
116 circleChangeAnimTimer.presentCircleCounter = 0
117 start()
118 }
119 }
121 Repeater {
122 id: pastCircles
123 objectName: "pastCircles"
124 model: infographic.model.secondMonth
126 delegate: ObjectPositioner {
127 property alias pastCircleChangeAnim: pastCircleChangeAnim
129 index: model.index
130 count: pastCircles.count
131 radius: dataCircle.width / 2
132 halfSize: pastCircle.width / 2
133 posOffset: 0.0
135 Circle {
136 id: pastCircle
137 objectName: "pastCircle" + index
139 property real divisor: 1.8
140 property real circleOpacity: 0.1
142 width: dataCircle.width / divisor
143 height: dataCircle.height / divisor
144 opacity: 0.0
145 scale: 0.0
146 visible: modelData !== undefined
147 color: "transparent"
149 SequentialAnimation {
150 id: pastCircleChangeAnim
152 loops: 1
153 ParallelAnimation {
154 PropertyAnimation {
155 target: pastCircle
156 property: "opacity"
157 to: pastCircle.circleOpacity
158 easing.type: Easing.OutCurve
159 duration: circleChangeAnimTimer.interval * d.circleModifier
160 }
161 PropertyAnimation {
162 target: pastCircle
163 property: "scale"
164 to: modelData
165 easing.type: Easing.OutCurve
166 duration: circleChangeAnimTimer.interval * d.circleModifier
167 }
168 ColorAnimation {
169 target: pastCircle
170 property: "color"
171 to: Gradient.threeColorByIndex(index, count, infographic.model.secondColor)
172 easing.type: Easing.OutCurve
173 duration: circleChangeAnimTimer.interval * d.circleModifier
174 }
175 }
176 }
177 }
178 }
179 }
181 Repeater {
182 id: presentCircles
183 objectName: "presentCircles"
184 model: infographic.model.firstMonth
186 delegate: ObjectPositioner {
187 property alias presentCircleChangeAnim: presentCircleChangeAnim
189 index: model.index
190 count: presentCircles.count
191 radius: dataCircle.width / 2
192 halfSize: presentCircle.width / 2
193 posOffset: 0.0
195 Circle {
196 id: presentCircle
197 objectName: "presentCircle" + index
199 property real divisor: 1.8
200 property real circleOpacity: 0.3
202 width: dataCircle.width / divisor
203 height: dataCircle.height / divisor
204 opacity: 0.0
205 scale: 0.0
206 visible: modelData !== undefined
207 color: "transparent"
209 SequentialAnimation {
210 id: presentCircleChangeAnim
212 loops: 1
214 ParallelAnimation {
215 PropertyAnimation {
216 target: presentCircle
217 property: "opacity"
218 to: presentCircle.circleOpacity
219 easing.type: Easing.OutCurve
220 duration: circleChangeAnimTimer.interval * d.circleModifier
221 }
222 PropertyAnimation {
223 target: presentCircle
224 property: "scale"
225 to: modelData
226 easing.type: Easing.OutCurve
227 duration: circleChangeAnimTimer.interval * d.circleModifier
228 }
229 ColorAnimation {
230 target: presentCircle
231 property: "color"
232 to: Gradient.threeColorByIndex(index, infographic.model.currentDay, infographic.model.firstColor)
233 easing.type: Easing.OutCurve
234 duration: circleChangeAnimTimer.interval * d.circleModifier
235 }
236 }
237 }
238 }
239 }
240 }
242 Image {
243 id: backgroundCircle
244 objectName: "backgroundCircle"
246 anchors.fill: parent
248 source: "graphics/infographic_circle_back.png"
249 }
251 Timer {
252 id: dotShowAnimTimer
254 property int dotCounter: 0
256 interval: animDuration * 0.5; running: false; repeat: true
257 onTriggered: {
258 if (dotCounter < dots.count) {
259 var nextDot = dots.itemAt(dotCounter);
260 if (nextDot) {
261 nextDot.unlockAnimation.start();
262 if (++dotCounter == Math.round(dots.count / 2)) {
263 circleChangeAnimTimer.startFromBeginning();
264 }
265 }
266 } else {
267 stop()
268 }
269 }
271 function startFromBeginning() {
272 if (!dotShowAnimTimer.running)
273 dotCounter = 0
275 start()
276 }
277 }
279 Timer {
280 id: dotHideAnimTimer
282 property int dotCounter
284 interval: animDuration * 0.5
285 running: false
286 repeat: true
287 onTriggered: {
288 if (dotCounter >= 0) {
289 var nextDot = dots.itemAt(dotCounter--)
290 nextDot.changeAnimation.start()
291 } else {
292 stop()
293 }
294 if (dotCounter == 0) {
295 infographic.model.readyForDataChange()
296 }
297 }
299 function startFromBeginning() {
300 if (!dotHideAnimTimer.running)
301 dotCounter = dots.count - 1
303 start()
304 }
305 }
307 Repeater {
308 id: dots
309 objectName: "dots"
311 model: infographic.model.firstMonth
313 delegate: ObjectPositioner {
314 property alias unlockAnimation: dotUnlockAnim
315 property alias changeAnimation: dotChangeAnim
317 property int currentDay: infographic.model.currentDay
319 index: model.index
320 count: dots.count
321 radius: backgroundCircle.width / 2
322 halfSize: dot.width / 2
323 posOffset: radius / dot.width / 3
324 state: dot.state
326 Dot {
327 id: dot
328 objectName: "dot" + index
330 property real baseOpacity: 0.4
332 width: units.dp(5) * parent.radius / 200
333 height: units.dp(5) * parent.radius / 200
334 opacity: 0.0
335 smooth: true
336 state: index < currentDay ? "filled" : index == currentDay ? "pointer" : "unfilled"
338 PropertyAnimation {
339 id: dotUnlockAnim
341 target: dot
342 property: "opacity"
343 to: dot.baseOpacity
344 duration: dotShowAnimTimer.interval
345 }
347 PropertyAnimation {
348 id: dotChangeAnim
350 target: dot
351 property: "opacity"
352 to: 0.0
353 duration: dotHideAnimTimer.interval
354 }
355 }
356 }
357 }
359 Label {
360 id: notification
361 objectName: "label"
363 property alias hideAnim: decreaseOpacity
364 property alias showAnim: increaseOpacity
366 property real baseOpacity: 0.6
367 property real duration: dotShowAnimTimer.interval * 5
369 height: 0.7 * backgroundCircle.width
370 width: notification.height
371 anchors.centerIn: parent
373 text: infographic.model.label
375 wrapMode: Text.WordWrap
376 horizontalAlignment: Text.AlignHCenter
377 verticalAlignment: Text.AlignVCenter
378 color: "white"
380 PropertyAnimation {
381 id: increaseOpacity
383 target: notification
384 property: "opacity"
385 from: 0.0
386 to: notification.baseOpacity
387 duration: notification.duration * dots.count
388 }
390 PropertyAnimation {
391 id: decreaseOpacity
393 target: notification
394 property: "opacity"
395 from: notification.baseOpacity
396 to: 0.0
397 duration: notification.duration * dots.count
398 onStopped: if (!d.useDotAnimation) infographic.model.readyForDataChange()
399 }
400 }
401 }
403 MouseArea {
404 anchors.fill: dataCircle
406 onDoubleClicked: {
407 if (!d.animating) {
408 d.useDotAnimation = false
409 infographic.model.nextDataSource()
410 }
411 }
412 }