Add shared mobile shell motion primitives

Introduce a central Motion singleton for animation durations, easing, and press scale tokens. Add typed NumberAnimation/ColorAnimation wrappers and a reusable state-layer component so runtime QML can share the same animation policy.
This commit is contained in:
Marco Allegretti 2026-05-21 11:12:20 +02:00
parent 75b9049a8c
commit 8767df8b10
5 changed files with 171 additions and 0 deletions

View file

@ -25,6 +25,7 @@ target_sources(mobileshellplugin PRIVATE ${mobileshellplugin_SRCS})
set_source_files_properties(
qml/components/AppLaunch.qml
qml/components/Constants.qml
qml/components/Motion.qml
qml/dataproviders/AudioInfo.qml
qml/dataproviders/BatteryInfo.qml
qml/dataproviders/BluetoothInfo.qml
@ -51,6 +52,10 @@ ecm_target_qml_sources(mobileshellplugin SOURCES
qml/components/HapticsEffect.qml
qml/components/ListView.qml
qml/components/MarqueeLabel.qml
qml/components/Motion.qml
qml/components/MotionColorAnimation.qml
qml/components/MotionNumberAnimation.qml
qml/components/MotionStateLayer.qml
qml/components/PanelBackground.qml
qml/components/ScreenEdgeDragEffect.qml
qml/components/StartupFeedbackPanelFill.qml

View file

@ -0,0 +1,103 @@
import QtQuick
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
pragma Singleton
QtObject {
id: root
enum Type {
Press,
Standard,
StandardAccel,
StandardDecel,
Emphasized,
EmphasizedAccel,
EmphasizedDecel,
SpatialFast,
SpatialDefault,
SpatialSlow,
SpatialExtended,
SpatialVerySlow,
EffectsFast,
EffectsDefault,
EffectsSlow
}
readonly property bool enabled: ShellSettings.Settings.animationsEnabled
readonly property int pressDuration: enabled ? Math.round(Kirigami.Units.shortDuration / 2) : 0
readonly property int standardDuration: enabled ? Kirigami.Units.longDuration : 0
readonly property int emphasizedDuration: enabled ? Kirigami.Units.longDuration + Kirigami.Units.shortDuration : 0
readonly property int spatialFastDuration: enabled ? Kirigami.Units.shortDuration : 0
readonly property int spatialDefaultDuration: enabled ? Kirigami.Units.longDuration : 0
readonly property int spatialSlowDuration: enabled ? Kirigami.Units.veryLongDuration : 0
readonly property int spatialExtendedDuration: enabled ? Kirigami.Units.longDuration * 2 : 0
readonly property int spatialVerySlowDuration: enabled ? Kirigami.Units.longDuration * 4 : 0
readonly property int effectsFastDuration: enabled ? Kirigami.Units.shortDuration : 0
readonly property int effectsDefaultDuration: enabled ? Kirigami.Units.longDuration : 0
readonly property int effectsSlowDuration: enabled ? Kirigami.Units.veryLongDuration : 0
readonly property real pressScaleIn: enabled ? 0.94 : 1
readonly property real pressScaleOut: enabled ? 1.08 : 1
readonly property real previewPressScale: enabled ? 0.95 : 1
readonly property real hiddenScale: enabled ? 0.72 : 1
readonly property real closeScaleOut: enabled ? 0.9 : 1
function duration(type: int): int {
switch (type) {
case Motion.Press:
return pressDuration;
case Motion.Emphasized:
case Motion.EmphasizedAccel:
case Motion.EmphasizedDecel:
return emphasizedDuration;
case Motion.SpatialFast:
return spatialFastDuration;
case Motion.SpatialDefault:
return spatialDefaultDuration;
case Motion.SpatialSlow:
return spatialSlowDuration;
case Motion.SpatialExtended:
return spatialExtendedDuration;
case Motion.SpatialVerySlow:
return spatialVerySlowDuration;
case Motion.EffectsFast:
return effectsFastDuration;
case Motion.EffectsDefault:
return effectsDefaultDuration;
case Motion.EffectsSlow:
return effectsSlowDuration;
default:
return standardDuration;
}
}
function easing(type: int): int {
switch (type) {
case Motion.StandardAccel:
case Motion.EmphasizedAccel:
return Easing.InQuart;
case Motion.StandardDecel:
case Motion.EmphasizedDecel:
return Easing.OutQuart;
case Motion.Emphasized:
return Easing.OutQuint;
case Motion.SpatialFast:
case Motion.SpatialDefault:
case Motion.SpatialSlow:
case Motion.SpatialExtended:
case Motion.SpatialVerySlow:
return Easing.OutExpo;
case Motion.Press:
case Motion.EffectsFast:
case Motion.EffectsDefault:
case Motion.EffectsSlow:
return Easing.OutCubic;
default:
return Easing.InOutQuad;
}
}
}

View file

@ -0,0 +1,8 @@
import QtQuick
ColorAnimation {
property int type: Motion.EffectsFast
duration: Motion.duration(type)
easing.type: Motion.easing(type)
}

View file

@ -0,0 +1,8 @@
import QtQuick
NumberAnimation {
property int type: Motion.Standard
duration: Motion.duration(type)
easing.type: Motion.easing(type)
}

View file

@ -0,0 +1,47 @@
import QtQuick
import org.kde.kirigami as Kirigami
Item {
id: root
property bool hovered: false
property bool pressed: false
property bool active: false
property bool stateLayerEnabled: true
property color color: Kirigami.Theme.textColor
property color activeColor: Kirigami.Theme.highlightColor
property real hoverOpacity: 0.08
property real pressedOpacity: 0.14
property real activeOpacity: 0.12
property real activeHoverOpacity: 0.18
property real radius: Kirigami.Units.cornerRadius
readonly property real layerOpacity: {
if (!stateLayerEnabled) {
return 0;
}
if (pressed) {
return pressedOpacity;
}
if (active) {
return hovered ? activeHoverOpacity : activeOpacity;
}
return hovered ? hoverOpacity : 0;
}
Rectangle {
anchors.fill: parent
radius: root.radius
color: root.active ? root.activeColor : root.color
opacity: root.layerOpacity
Behavior on color {
MotionColorAnimation { type: Motion.EffectsFast }
}
Behavior on opacity {
MotionNumberAnimation { type: Motion.EffectsFast }
}
}
}