on xenial help sign in
improved the whole animation a lot
44f7ef5Michael Zanetti
plugins/Utils/CMakeLists.txt+2−1
@@ -18,6 +18,7 @@ set(QMLPLUGIN_SRC
18 qsortfilterproxymodelqml.cpp
18 qsortfilterproxymodelqml.cpp
19 timeformatter.cpp
19 timeformatter.cpp
20 unitymenumodelpaths.cpp
20 unitymenumodelpaths.cpp
21+ easingcurve.cpp
21 plugin.cpp
22 plugin.cpp
22 )
23 )
23
24
@@ -33,7 +34,7 @@ target_link_libraries(Utils-qml ${GIO_LDFLAGS})
33# files directly in targets.
34# files directly in targets.
34set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
35set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
35
36
36−qt5_use_modules(Utils-qml Qml Quick DBus Network XmlPatterns)
37+qt5_use_modules(Utils-qml Qml Quick DBus Network XmlPatterns Gui)
37
38
38# export the qmldir qmltypes and plugin files
39# export the qmldir qmltypes and plugin files
39export_qmlfiles(Utils Utils)
40export_qmlfiles(Utils Utils)
plugins/Utils/easingcurve.cppnew file+49
@@ -0,0 +1,49 @@
1+#include "easingcurve.h"
2+
3+
4+EasingCurve::EasingCurve(QObject *parent):
5+ QObject(parent)
6+{
7+
8+}
9+
10+QEasingCurve::Type EasingCurve::type() const
11+{
12+ return m_easingCurve.type();
13+}
14+
15+void EasingCurve::setType(const QEasingCurve::Type &type)
16+{
17+ m_easingCurve.setType(type);
18+ Q_EMIT typeChanged();
19+}
20+
21+qreal EasingCurve::period() const
22+{
23+ return m_easingCurve.period();
24+}
25+
26+void EasingCurve::setPeriod(qreal period)
27+{
28+ m_easingCurve.setPeriod(period);
29+ Q_EMIT periodChanged();
30+}
31+
32+qreal EasingCurve::progress() const
33+{
34+ return m_progress;
35+}
36+
37+void EasingCurve::setProgress(qreal progress)
38+{
39+ if (m_progress != progress) {
40+ m_progress = progress;
41+ m_value = m_easingCurve.valueForProgress(m_progress);
42+ Q_EMIT progressChanged();
43+ }
44+}
45+
46+qreal EasingCurve::value() const
47+{
48+ return m_value;
49+}
plugins/Utils/easingcurve.hnew file+42
@@ -0,0 +1,42 @@
1+#ifndef EASINGCURVE_H
2+#define EASINGCURVE_H
3+
4+#include <QObject>
5+#include <QEasingCurve>
6+
7+class EasingCurve: public QObject
8+{
9+ Q_OBJECT
10+ Q_ENUMS(QEasingCurve::Type)
11+ Q_PROPERTY(QEasingCurve::Type type READ type WRITE setType NOTIFY typeChanged)
12+ Q_PROPERTY(qreal period READ period WRITE setPeriod NOTIFY periodChanged)
13+ Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
14+ Q_PROPERTY(qreal value READ value NOTIFY progressChanged)
15+
16+public:
17+ EasingCurve(QObject *parent = 0);
18+
19+ QEasingCurve::Type type() const;
20+ void setType(const QEasingCurve::Type &type);
21+
22+ qreal period() const;
23+ void setPeriod(qreal period);
24+
25+ qreal progress() const;
26+ void setProgress(qreal progress);
27+
28+ qreal value() const;
29+
30+Q_SIGNALS:
31+ void typeChanged();
32+ void periodChanged();
33+ void progressChanged();
34+
35+private:
36+ QEasingCurve m_easingCurve;
37+ qreal m_progress;
38+ qreal m_value;
39+};
40+
41+#endif
42+
plugins/Utils/plugin.cpp+2
@@ -32,6 +32,7 @@
32#include "qsortfilterproxymodelqml.h"
32#include "qsortfilterproxymodelqml.h"
33#include "timeformatter.h"
33#include "timeformatter.h"
34#include "unitymenumodelpaths.h"
34#include "unitymenumodelpaths.h"
35+#include "easingcurve.h"
35
36
36static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator";
37static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator";
37static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator";
38static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator";
@@ -46,6 +47,7 @@ void UtilsPlugin::registerTypes(const char *uri)
46 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
47 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
47 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
48 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
48 qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
49 qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
50+ qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
49}
51}
50
52
51void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
53void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
qml/Stages/PhoneStage.qml+172−101
@@ -2,6 +2,7 @@ import QtQuick 2.0
2import Ubuntu.Components 0.1
2import Ubuntu.Components 0.1
3import Ubuntu.Gestures 0.1
3import Ubuntu.Gestures 0.1
4import Unity.Application 0.1
4import Unity.Application 0.1
5+import Utils 0.1
5import "../Components"
6import "../Components"
6
7
7/*
8/*
@@ -18,6 +19,7 @@ Item {
18
19
19 // State information propagated to the outside
20 // State information propagated to the outside
20 readonly property bool painting: mainScreenshotImage.visible || fadeInScreenshotImage.visible || appSplash.visible
21 readonly property bool painting: mainScreenshotImage.visible || fadeInScreenshotImage.visible || appSplash.visible
22+ onPaintingChanged: print("**********************+ painting changed", painting)
21
23
22 onMovingChanged: {
24 onMovingChanged: {
23 if (moving) {
25 if (moving) {
@@ -230,8 +232,8 @@ Item {
230 onContentXChanged: {
232 onContentXChanged: {
231// print("contentX changed", contentX)
233// print("contentX changed", contentX)
232 var progress = contentX / width
234 var progress = contentX / width
233− if (progress > .5) {
235+ if (progress > coverFlip.progressMarker1) {
234− progress += progress - .5
236+ progress += progress - coverFlip.progressMarker1
235 }
237 }
236
238
237 coverFlip.progress = progress;
239 coverFlip.progress = progress;
@@ -256,6 +258,8 @@ Item {
256 // marks the line where first application is finished moving in from the right
258 // marks the line where first application is finished moving in from the right
257 property real progressMarker1: 0.5
259 property real progressMarker1: 0.5
258
260
261+ property real tileDistance: 0.1
262+
259 property bool animatingBack: false
263 property bool animatingBack: false
260
264
261 property real tileWidth: root.width
265 property real tileWidth: root.width
@@ -311,10 +315,6 @@ Item {
311 height: parent.height
315 height: parent.height
312 width: coverFlip.tileWidth
316 width: coverFlip.tileWidth
313
317
314− function select() {
315− switchToAppAnimation.start();
316− }
317−
318 Image {
318 Image {
319 id: appImage
319 id: appImage
320 anchors { left: parent.left; bottom: parent.bottom }
320 anchors { left: parent.left; bottom: parent.bottom }
@@ -322,7 +322,30 @@ Item {
322 source: ApplicationManager.get(index).screenshot
322 source: ApplicationManager.get(index).screenshot
323 scale: 1
323 scale: 1
324
324
325+ // This is the main progress, of the gesture, the same for every tile
325 property real progress: coverFlip.progress
326 property real progress: coverFlip.progress
327+ // The progress, translated for the second stage of the animation, after the first app switch has happened
328+ // Additionally it speeds it up a bit, depending on the distance of the tile
329+ property real translatedProgress: appImage.progress - coverFlip.progressMarker1 - (coverFlip.tileDistance * (index-1))
330+
331+ // Is this tile selected by a click?
332+ property bool isSelected: false
333+ // We need to remember some values when app is selected to be able to animate it to the foreground
334+ property real selectedXTranslation: 0
335+ property real selectedTranslatedProgress: 0
336+ property real selectedAngle: 0
337+ property real selectedXScale: 0
338+
339+ function select() {
340+ print("selecting item, current translation:", appImage.xTranslation)
341+ appImage.selectedXTranslation = appImage.xTranslation;
342+ appImage.selectedAngle = appImage.angle;
343+ appImage.selectedXScale = appImage.xScale;
344+ appImage.selectedTranslatedProgress = appImage.translatedProgress;
345+ print("set selected x translation", appImage.selectedXTranslation)
346+ appImage.isSelected = true;
347+ switchToAppAnimation.start();
348+ }
326
349
327 property int xTranslation: {
350 property int xTranslation: {
328 var xTranslate = 0;
351 var xTranslate = 0;
@@ -349,113 +372,165 @@ Item {
349 // Intentionally no break here...
372 // Intentionally no break here...
350 default:
373 default:
351 if (appImage.progress > coverFlip.progressMarker1) {
374 if (appImage.progress > coverFlip.progressMarker1) {
352− // Used to move all tiles directly to the right of the screen as starting position
375+ xTranslate = xTranslateEasing.value * xTranslateEasing.period;
353− var mainTranslate = -root.width * (index - 1)
354− // Used to add the offset to each tile so they are not on one stack
355− var indexTranslate = (index - 1) * root.width / 4
356
376
357− var progress = appImage.progress - coverFlip.progressMarker1
377+ // make sure we stop at the left screen edge
358− var progressDiff = 1 - coverFlip.progressMarker1
378+// xTranslate = Math.max(xTranslate, minXTranslate)
359− var translateDiff = -root.width * coverFlip.progressMarker1// -(coverFlip.progressMarker1 + index * root.width * 0.25 + root.width * 0.25)
379+ break;
380+ }
381+ }
382+ if (appImage.isSelected) {
383+ var newTranslate = selectedXTranslateEasing.value * selectedXTranslateEasing.period
384+ xTranslate = appImage.selectedXTranslation + newTranslate;
385+ }
360
386
361− // progress : progressDiff = translate : translateDiff
387+ return xTranslate;
362− xTranslate = progress * translateDiff / progressDiff;
388+ }
363
389
364− // Add starting point and index translate
390+ property real angle: {
365− xTranslate += mainTranslate + indexTranslate;
391+ var newAngle = 0;
392+ switch (index) {
393+ case 0:
394+ if (appImage.progress <= coverFlip.progressMarker1) {
395+ var progress = appImage.progress;
396+ var angleDiff = coverFlip.endAngle;
397+ var progressDiff = coverFlip.progressMarker1;
398+ // progress : progressDiff = angle : angleDiff
399+ newAngle = progress * angleDiff / progressDiff;
400+ } else {
401+ var progress = appImage.progress - coverFlip.progressMarker1;
402+ var angleDiff = coverFlip.endAngle;
403+ var progressDiff = 1 - coverFlip.progressMarker1;
404+ // progress : progressDiff = angle : angleDiff
405+ newAngle = progress * angleDiff / progressDiff;
406+ newAngle = Math.min(coverFlip.endAngle, newAngle);
407+ }
408+ break;
409+ case 1:
410+ if (appImage.progress < coverFlip.progressMarker1) {
411+ var progress = coverFlip.progress;
412+ var angleDiff = coverFlip.startAngle;
413+ var progressDiff = coverFlip.progressMarker1;
414+ // progress : progressDiff = angle : angleDiff
415+ var angle = progress * angleDiff / progressDiff;
416+ newAngle = coverFlip.startAngle - angle;
417+ break;
418+ }
419+ // Intentionally no break here...
420+ default:
421+// var progress = appImage.progress;
422+// var angleDiff = coverFlip.startAngle - coverFlip.endAngle;
423+//// var progressDiff = coverFlip.progressMarker1 + index * 0.25 + 0.25
424+// var progressDiff = index
425+// // progress : progressDiff = angle : angleDiff
426+// newAngle = progress * angleDiff / progressDiff;
427+// newAngle = Math.max(coverFlip.endAngle, coverFlip.startAngle - newAngle)
366
428
429+ newAngle = coverFlip.startAngle - (angleEasing.value * angleEasing.period);
430+
367− // make sure we stop at the left screen edge
431+ // make sure we stop at the left screen edge
368− xTranslate = Math.max(xTranslate, minXTranslate)
432+ newAngle = Math.max(newAngle, coverFlip.endAngle);
433+
434+ }
435+ if (appImage.isSelected) {
436+ var selectedAngleTranslate = selectedAngleEasing.value * selectedAngleEasing.period
437+ print("selectedAngle", appImage.selectedAngle, "translate", selectedAngleTranslate)
438+ newAngle = appImage.selectedAngle - selectedAngleTranslate;
439+ }
440+
441+ return newAngle;
442+ }
443+
444+ property real xScale: {
445+ var scale = 1;
446+
447+ switch (index) {
448+ case 0:
449+ if (appImage.progress > coverFlip.progressMarker1) {
450+ var scaleDiff = coverFlip.maxScale - 1;
451+ var progressDiff = 1.5 - coverFlip.progressMarker1;
452+ // progress : progressDiff = scale : scaleDiff
453+ scale = 1 - (appImage.progress - coverFlip.progressMarker1) * scaleDiff / progressDiff;
454+ }
455+ break;
456+ case 1:
457+ if (appImage.progress < coverFlip.progressMarker1) {
458+ var scaleDiff = coverFlip.maxScale - 1
459+ var progressDiff = coverFlip.progressMarker1
460+ // progress : progressDiff = scale : scaleDiff
461+ scale = coverFlip.maxScale - (appImage.progress * scaleDiff / progressDiff);
369 break;
462 break;
370 }
463 }
464+ // Intentionally no break
465+ default:
466+// var scaleDiff = coverFlip.maxScale - coverFlip.minScale
467+//// var progressDiff = coverFlip.progressMarker1 + index * 0.25 + 0.25
468+// var progressDiff = index
469+// // progress : progressDiff = scale : scaleDiff
470+// scale = coverFlip.maxScale - (appImage.progress - coverFlip.progressMarker1) * scaleDiff / progressDiff
471+// break;
472+
473+ scale = coverFlip.maxScale - scaleEasing.value * scaleEasing.period;
371 }
474 }
372− return xTranslate;
475+
476+ if (appImage.isSelected) {
477+ var selectedScaleTranslate = selectedScaleEasing.value * selectedScaleEasing.period
478+ scale = appImage.selectedXScale + selectedScaleTranslate;
479+ }
480+
481+ return Math.min(coverFlip.maxScale, Math.max(coverFlip.minScale, scale));
482+ }
483+
484+
485+ EasingCurve {
486+ id: xTranslateEasing
487+ type: EasingCurve.OutQuad
488+ period: index * -width
489+ progress: appImage.translatedProgress
490+ }
491+ EasingCurve {
492+ id: selectedXTranslateEasing
493+ type: EasingCurve.Linear
494+ period: xTranslateEasing.period - appImage.selectedXTranslation
495+ progress: appImage.selectedTranslatedProgress - xTranslateEasing.progress
496+ }
497+ EasingCurve {
498+ id: angleEasing
499+ type: EasingCurve.InQuad
500+ period: coverFlip.startAngle - coverFlip.endAngle
501+ progress: appImage.translatedProgress
502+ }
503+ EasingCurve {
504+ id: selectedAngleEasing
505+ type: EasingCurve.Linear
506+ period: appImage.selectedAngle
507+ progress: appImage.selectedTranslatedProgress - angleEasing.progress
508+ }
509+ EasingCurve {
510+ id: scaleEasing
511+ type: EasingCurve.Linear
512+ period: coverFlip.maxScale - coverFlip.minScale
513+ progress: appImage.translatedProgress
514+ }
515+ EasingCurve {
516+ id: selectedScaleEasing
517+ type: EasingCurve.Linear
518+ period: 1 - appImage.selectedXScale
519+ progress: appImage.selectedTranslatedProgress - scaleEasing.progress
373 }
520 }
374
521
375 transform: [
522 transform: [
376 Rotation {
523 Rotation {
377 origin { x: 0; y: coverFlip.height / 2 }
524 origin { x: 0; y: coverFlip.height / 2 }
378 axis { x: 0; y: 1; z: 0 }
525 axis { x: 0; y: 1; z: 0 }
379− angle: {
526+ angle: appImage.angle
380− var newAngle = 0;
381− if (coverFlip.animatingBack) {
382− newAngle = Math.min(appImage.progress, .75) * coverFlip.endAngle;
383− } else {
384− switch (index) {
385− case 0:
386− if (appImage.progress <= coverFlip.progressMarker1) {
387− var progress = appImage.progress;
388− var angleDiff = coverFlip.endAngle;
389− var progressDiff = coverFlip.progressMarker1;
390− // progress : progressDiff = angle : angleDiff
391− newAngle = progress * angleDiff / progressDiff;
392− } else {
393− var progress = appImage.progress - coverFlip.progressMarker1;
394− var angleDiff = coverFlip.endAngle;
395− var progressDiff = 1 - coverFlip.progressMarker1;
396− // progress : progressDiff = angle : angleDiff
397− newAngle = progress * angleDiff / progressDiff;
398− newAngle = Math.min(coverFlip.endAngle, newAngle);
399− }
400− break;
401− case 1:
402− if (appImage.progress < coverFlip.progressMarker1) {
403− var progress = coverFlip.progress;
404− var angleDiff = coverFlip.startAngle;
405− var progressDiff = coverFlip.progressMarker1;
406− // progress : progressDiff = angle : angleDiff
407− var angle = progress * angleDiff / progressDiff;
408− newAngle = coverFlip.startAngle - angle;
409− break;
410− }
411− // Intentionally no break here...
412− default:
413− var progress = appImage.progress;
414− var angleDiff = coverFlip.startAngle - coverFlip.endAngle;
415− var progressDiff = coverFlip.progressMarker1 + index * 0.25 + 0.25
416− // progress : progressDiff = angle : angleDiff
417− newAngle = progress * angleDiff / progressDiff;
418− newAngle = Math.max(coverFlip.endAngle, coverFlip.startAngle - newAngle)
419− }
420− }
421− return newAngle;
422− }
423 },
527 },
424 Translate {
528 Translate {
425 x: appImage.xTranslation
529 x: appImage.xTranslation
426 },
530 },
427 Scale {
531 Scale {
428 origin { x: appImage.xTranslation; y: root.height / 2 - (root.height - appImage.height)}
532 origin { x: appImage.xTranslation; y: root.height / 2 - (root.height - appImage.height)}
429− xScale: {
533+ xScale: appImage.xScale
430− var scale = 1;
431−
432− switch (index) {
433− case 0:
434− if (appImage.progress > coverFlip.progressMarker1) {
435− var scaleDiff = coverFlip.maxScale - 1;
436− var progressDiff = 1.5 - coverFlip.progressMarker1;
437− // progress : progressDiff = scale : scaleDiff
438− scale = 1 - (appImage.progress - coverFlip.progressMarker1) * scaleDiff / progressDiff;
439− }
440− break;
441− case 1:
442− if (appImage.progress < coverFlip.progressMarker1) {
443− var scaleDiff = coverFlip.maxScale - 1
444− var progressDiff = coverFlip.progressMarker1
445− // progress : progressDiff = scale : scaleDiff
446− scale = coverFlip.maxScale - (appImage.progress * scaleDiff / progressDiff);
447− break;
448− }
449− // Intentionally no break
450− default:
451− var scaleDiff = coverFlip.maxScale - coverFlip.minScale
452− var progressDiff = coverFlip.progressMarker1 + index * 0.25 + 0.25
453− // progress : progressDiff = scale : scaleDiff
454− scale = coverFlip.maxScale - (appImage.progress - coverFlip.progressMarker1) * scaleDiff / progressDiff
455− break;
456− }
457− return Math.min(coverFlip.maxScale, Math.max(coverFlip.minScale, scale));
458− }
459 yScale: xScale
534 yScale: xScale
460 }
535 }
461 ]
536 ]
@@ -464,25 +539,21 @@ Item {
464 anchors.fill: parent
539 anchors.fill: parent
465 onClicked: {
540 onClicked: {
466 print("clicked on index", index)
541 print("clicked on index", index)
467− select()
542+ appImage.select()
468 }
543 }
469 }
544 }
470 }
545 }
471
546
472 SequentialAnimation {
547 SequentialAnimation {
473 id: switchToAppAnimation
548 id: switchToAppAnimation
474− PropertyAction { target: coverFlip; property: "animatingBack"; value: true }
475 ParallelAnimation {
549 ParallelAnimation {
476− UbuntuNumberAnimation { target: coverFlickable; property: "contentX"; to: 0; duration: 5000 }
550+ UbuntuNumberAnimation { target: coverFlickable; property: "contentX"; to: 0}
477− UbuntuNumberAnimation { target: coverFlip; property: "x"; to: -root.width * index; duration: 5000 }
478 }
551 }
479 ScriptAction {
552 ScriptAction {
480 script: {
553 script: {
481 ApplicationManager.focusApplication(ApplicationManager.get(index).appId);
554 ApplicationManager.focusApplication(ApplicationManager.get(index).appId);
555+ appImage.isSelected = false;
482 coverFlip.progress = 0;
556 coverFlip.progress = 0;
483− coverFlip.x = 0;
484− coverFlip.animatingBack = false;
485− appImage.x = 0;
486 }
557 }
487 }
558 }
488 }
559 }