feat: add anim for dash media cover
This commit is contained in:
parent
1eac4e4bcb
commit
9cd9d7facd
2 changed files with 151 additions and 2 deletions
79
components/controls/LoadingIndicator.qml
Normal file
79
components/controls/LoadingIndicator.qml
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
import QtQuick
|
||||||
|
import M3Shapes
|
||||||
|
import Caelestia.Config
|
||||||
|
import qs.components
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
MaterialShape {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property list<int> shapes: {
|
||||||
|
if (containsIcon)
|
||||||
|
return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval];
|
||||||
|
return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pentagon, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval];
|
||||||
|
}
|
||||||
|
property int shapeIndex
|
||||||
|
property real cRotation
|
||||||
|
property real lRotation
|
||||||
|
property bool containsIcon
|
||||||
|
|
||||||
|
property bool animated: true
|
||||||
|
property int morphAnimRotation: 60
|
||||||
|
property alias morphAnimDelay: morphAnimDelay.duration
|
||||||
|
property alias rotateAnimDuration: rotateAnim.duration
|
||||||
|
|
||||||
|
readonly property easingCurve scaleCurve: [0.00, 0.56, 0.55, 1.29, 1, 1]
|
||||||
|
|
||||||
|
implicitSize: 38
|
||||||
|
rotation: cRotation + lRotation
|
||||||
|
|
||||||
|
shape: shapes[shapeIndex]
|
||||||
|
color: Colours.palette.m3primary
|
||||||
|
|
||||||
|
animationDuration: Tokens.anim.durations.expressiveSlowSpatial
|
||||||
|
animationEasing: Tokens.anim.expressiveSlowSpatial
|
||||||
|
|
||||||
|
scale: {
|
||||||
|
const t = scaleCurve.valueForProgress(morphProgress);
|
||||||
|
return 1 + 0.15 * Math.sin(t * Math.PI) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
running: root.animated
|
||||||
|
loops: Animation.Infinite
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
target: root
|
||||||
|
property: "shapeIndex"
|
||||||
|
value: (root.shapeIndex + 1) % root.shapes.length
|
||||||
|
}
|
||||||
|
RotationAnimation {
|
||||||
|
target: root
|
||||||
|
property: "lRotation"
|
||||||
|
to: (root.lRotation + root.morphAnimRotation) % 360
|
||||||
|
duration: Tokens.anim.durations.expressiveSlowSpatial
|
||||||
|
easing: Tokens.anim.expressiveSlowSpatial
|
||||||
|
direction: RotationAnimation.Shortest
|
||||||
|
}
|
||||||
|
PauseAnimation {
|
||||||
|
id: morphAnimDelay
|
||||||
|
|
||||||
|
duration: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RotationAnimation on cRotation {
|
||||||
|
id: rotateAnim
|
||||||
|
|
||||||
|
running: root.animated
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
easing.type: Easing.Linear
|
||||||
|
loops: Animation.Infinite
|
||||||
|
duration: 10000
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property real arcCoverGap: Tokens.spacing.extraSmall
|
readonly property real arcCoverGap: Tokens.spacing.extraSmall
|
||||||
|
property bool coverHadPrevious
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
@ -110,9 +111,35 @@ Item {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
grade: 200
|
grade: 200
|
||||||
text: "art_track"
|
text: image.status === Image.Error ? "broken_image" : "art_track"
|
||||||
color: Colours.palette.m3onSurfaceVariant
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
fontStyle: Tokens.font.icon.size((parent.width * 0.4) || 1).build()
|
fontStyle: Tokens.font.icon.size((parent.width * 0.35) || 1).build()
|
||||||
|
opacity: image.status === Image.Null || image.status === Image.Error ? 1 : 0
|
||||||
|
animate: true
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
asynchronous: true
|
||||||
|
active: opacity > 0
|
||||||
|
opacity: image.status === Image.Loading ? 1 : 0
|
||||||
|
|
||||||
|
sourceComponent: LoadingIndicator {
|
||||||
|
implicitSize: cover.width * 0.3
|
||||||
|
color: Colours.palette.m3primaryContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
|
|
@ -130,6 +157,49 @@ Item {
|
||||||
layer.effect: Mask {
|
layer.effect: Mask {
|
||||||
maskSource: coverShape
|
maskSource: coverShape
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retainWhileLoading: true
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
onStatusChanged: {
|
||||||
|
if (!opacityInAnim.running && image.status === Image.Ready) {
|
||||||
|
opacityInAnim.type = root.coverHadPrevious ? Anim.DefaultEffects : Anim.StandardLarge;
|
||||||
|
opacityInAnim.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim on opacity {
|
||||||
|
id: opacityInAnim
|
||||||
|
|
||||||
|
running: false
|
||||||
|
to: 1
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on source {
|
||||||
|
SequentialAnimation {
|
||||||
|
Anim {
|
||||||
|
target: image
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
type: Anim.FastEffects
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: root
|
||||||
|
property: "coverHadPrevious"
|
||||||
|
value: image.source
|
||||||
|
}
|
||||||
|
PropertyAction {}
|
||||||
|
ScriptAction {
|
||||||
|
script: {
|
||||||
|
if (!opacityInAnim.running && image.status === Image.Ready) {
|
||||||
|
opacityInAnim.type = root.coverHadPrevious ? Anim.DefaultEffects : Anim.StandardLarge;
|
||||||
|
opacityInAnim.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue