Move shell and KWin surfaces to shared motion

Apply Motion tokens to startup, applet configuration, lockscreen controls, logout and splash transitions, KWin effects, and the mobile task switcher. Preserve timing-specific behavior where it drives runtime state.
This commit is contained in:
Marco Allegretti 2026-05-21 11:14:42 +02:00
parent 88a4f5883b
commit 753909a6ce
17 changed files with 181 additions and 132 deletions

View file

@ -7,6 +7,7 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.mobileinitialstart.initialstart
import org.kde.plasma.mobileinitialstart.prepare 1.0 as Prepare
@ -14,9 +15,13 @@ import org.kde.plasma.mobileinitialstart.prepare 1.0 as Prepare
Item {
id: root
readonly property real scaleStart: 1.4
readonly property real scaleLanding: 1.2
readonly property real scaleStart: 1.16
readonly property real scaleLanding: 1.08
readonly property real scaleSteps: 1
readonly property int initialContentFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsSlow) * 2
readonly property int returnContentFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
readonly property int imageFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsSlow)
readonly property int imageScaleDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialVerySlow)
signal requestNextPage()
@ -27,14 +32,15 @@ Item {
}
property real contentOpacity: 0
NumberAnimation on contentOpacity {
MobileShell.MotionNumberAnimation on contentOpacity {
id: contentOpacityAnim
type: MobileShell.Motion.EffectsSlow
running: true
duration: 1000
duration: root.initialContentFadeDuration
to: 1
// shorten animation after initial run
onFinished: duration = 200
onFinished: duration = root.returnContentFadeDuration
}
Image {
@ -62,11 +68,11 @@ Item {
opacity: 0
NumberAnimation on opacity {
MobileShell.MotionNumberAnimation on opacity {
type: MobileShell.Motion.EffectsSlow
running: true
duration: 400
duration: root.imageFadeDuration
to: 1
easing.type: Easing.InOutQuad
}
// zoom animation
@ -74,9 +80,9 @@ Item {
Component.onCompleted: scale = scaleLanding
Behavior on scale {
NumberAnimation {
duration: 2000
easing.type: Easing.OutExpo
MobileShell.MotionNumberAnimation {
type: MobileShell.Motion.SpatialVerySlow
duration: root.imageScaleDuration
}
}

View file

@ -3,6 +3,7 @@
import QtQuick
import org.kde.kwin.decoration
import org.kde.plasma.private.mobileshell as MobileShell
Decoration {
id: root
@ -19,6 +20,7 @@ Decoration {
readonly property int btnSpacing: 8
readonly property int btnSideMargin: 12
readonly property int cornerRadius: decoration.client.maximized ? 0 : 8
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
Component.onCompleted: {
borders.top = barHeight;
@ -55,7 +57,7 @@ Decoration {
height: root.barHeight
radius: root.cornerRadius
color: decoration.client.active ? root.activeBar : root.inactiveBar
Behavior on color { ColorAnimation { duration: 120 } }
Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
// Square off bottom half only top corners are rounded
Rectangle {
@ -96,7 +98,7 @@ Decoration {
elide: Text.ElideMiddle
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
Behavior on color { ColorAnimation { duration: 120 } }
Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
}
Row {
@ -195,7 +197,7 @@ Decoration {
color: parent.pressed ? Qt.darker(parent.hoverColor, 1.3)
: parent.hovered ? parent.hoverColor
: parent.normalColor
Behavior on color { ColorAnimation { duration: 100 } }
Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
Text {
anchors.centerIn: parent
@ -204,7 +206,7 @@ Decoration {
font.pixelSize: Math.round(parent.width * 0.66)
font.weight: Font.Bold
opacity: 1.0
Behavior on opacity { NumberAnimation { duration: 100 } }
Behavior on opacity { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
}
}
}

View file

@ -14,6 +14,7 @@
import QtQuick
import QtQuick.Layouts
import org.kde.kwin as KWinComponents
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
KWinComponents.SceneEffect {
@ -38,6 +39,7 @@ KWinComponents.SceneEffect {
readonly property int panelScreenMargin: 8
readonly property int panelCursorGap: 12
readonly property int panelCursorRightBias: 34
readonly property int hoverAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
property var hoverWindowId: null
property int hoverTicks: 0
property string hoverWindowStateKey: ""
@ -649,7 +651,7 @@ KWinComponents.SceneEffect {
property bool hovered: false
Behavior on color { ColorAnimation { duration: 80 } }
Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.Press; duration: effect.hoverAnimationDuration } }
Rectangle {
id: previewFrame

View file

@ -3,6 +3,7 @@
import QtQuick
import org.kde.kwin as KWinComponents
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
KWinComponents.SceneEffect {
@ -12,8 +13,8 @@ KWinComponents.SceneEffect {
readonly property int outerGap: 8
readonly property int floatEscapeMargin: 32
readonly property int previewAnimationDuration: 180
readonly property int previewFadeDuration: 110
readonly property int previewAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property int previewFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
property var dragConnectedWindows: ({})
property var draggingWindow: null
@ -290,28 +291,28 @@ KWinComponents.SceneEffect {
Behavior on x {
enabled: effect.animatePreview
NumberAnimation { duration: effect.previewAnimationDuration; easing.type: Easing.OutCubic }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
}
Behavior on y {
enabled: effect.animatePreview
NumberAnimation { duration: effect.previewAnimationDuration; easing.type: Easing.OutCubic }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
}
Behavior on width {
enabled: effect.animatePreview
NumberAnimation { duration: effect.previewAnimationDuration; easing.type: Easing.OutCubic }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
}
Behavior on height {
enabled: effect.animatePreview
NumberAnimation { duration: effect.previewAnimationDuration; easing.type: Easing.OutCubic }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
}
Behavior on opacity {
NumberAnimation { duration: effect.previewFadeDuration; easing.type: Easing.InOutQuad }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
}
Behavior on color {
ColorAnimation { duration: effect.previewFadeDuration; easing.type: Easing.OutCubic }
MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
}
Behavior on border.color {
ColorAnimation { duration: effect.previewFadeDuration; easing.type: Easing.OutCubic }
MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
}
Rectangle {

View file

@ -12,6 +12,7 @@ import org.kde.kirigami as Kirigami
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.kwin 3.0 as KWinComponents
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
Item {
@ -30,6 +31,8 @@ Item {
readonly property real dragOffset: -control.y
readonly property int currentIndex: model.index
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
// whether this task is being interacted with
readonly property bool interactingActive: control.pressed && control.passedDragThreshold
@ -137,11 +140,11 @@ Item {
}
}
NumberAnimation on y {
MobileShell.MotionNumberAnimation on y {
id: yAnimator
type: MobileShell.Motion.Standard
running: !control.pressed
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
duration: delegate.longAnimationDuration
to: 0
onFinished: {
if (to != 0) { // close app
@ -172,7 +175,7 @@ Item {
opacity: delegate.showHeader ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: delegate.shortAnimationDuration }
}
Kirigami.Icon {
@ -216,12 +219,9 @@ Item {
clip: true
// scale animation on press
property real zoomScale: control.pressed ? 0.95 : 1
property real zoomScale: control.pressed ? MobileShell.Motion.previewPressScale : 1
Behavior on zoomScale {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.OutExpo
}
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault }
}
transform: Scale {

View file

@ -9,6 +9,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.kwin 3.0 as KWinComponents
@ -105,7 +106,7 @@ MouseArea {
// dynamic task offset animation duration based off of the touch position and task scale
function dynamicDuration(left = true): int {
// if the close animation is running, use the standard long duration time for consistency
let duration = Kirigami.Units.longDuration * 1.75
let duration = root.taskSwitcherHelpers.longAnimationDuration * 1.75
if (!taskSwitcherHelpers.closeAnim.running && taskSwitcherHelpers.notHomeScreenState && taskSwitcherHelpers.gestureState != TaskSwitcherHelpers.GestureStates.HorizontalSwipe && !taskSwitcherHelpers.isInTaskScrubMode) {
// max out the scale at 1 so it is not too fast when opening the task drawer with the button
let taskScale = Math.min(taskSwitcherHelpers.currentScale, 1)
@ -170,16 +171,17 @@ MouseArea {
// this is the x-position with respect to the list
property real listX: root.taskSwitcherHelpers.xPositionFromTaskIndex(currentIndex)
Behavior on listX {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
MobileShell.MotionNumberAnimation {
type: MobileShell.Motion.Standard
duration: root.taskSwitcherHelpers.longAnimationDuration
}
}
// the animated task offset value (always will be 0 if it is the current task in the task drawer)
property real taskOffsetNormalized: (root.baseTaskOffset * ((root.taskSwitcherHelpers.taskDrawerOpened && isCurrentTask) ? 0 : 1))
Behavior on taskOffsetNormalized {
NumberAnimation {
MobileShell.MotionNumberAnimation {
type: MobileShell.Motion.Standard
duration: root.taskSwitcherHelpers.currentDisplayTask > task.currentIndex ? root.taskOffsetDurationRight : root.taskOffsetDurationLeft
easing.type: root.taskOffsetEasing
easing.overshoot: 0.85

View file

@ -38,6 +38,9 @@ FocusScope {
readonly property real bottomMargin: ShellSettings.Settings.autoHidePanelsEnabled ? 0 : navBottomMargin
readonly property real leftMargin: 0
readonly property real rightMargin: ShellSettings.Settings.autoHidePanelsEnabled ? 0 : navRightMargin
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int veryLongAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsSlow)
readonly property real disabledScrubArrowOpacity: 0.38
property var taskSwitcherHelpers: TaskSwitcherHelpers {
taskSwitcher: root
@ -64,7 +67,7 @@ FocusScope {
state.currentTaskIndex -= 1;
// animated at the same speed as the task x position in the TaskList so that the task appears not to move from the perspective of the user.
taskSwitcherHelpers.animateGoToTaskIndex(state.currentTaskIndex, Kirigami.Units.longDuration, Easing.InOutQuad);
taskSwitcherHelpers.animateGoToTaskIndex(state.currentTaskIndex, taskSwitcherHelpers.longAnimationDuration, Easing.InOutQuad);
taskSwitcherHelpers.lastClosedTask = -1;
}
@ -73,10 +76,10 @@ FocusScope {
} else if (tasksCount < oldTasksCount) {
if (state.currentTaskIndex < 0) {
// if the user is on the first task, and it is closed, scroll right
taskSwitcherHelpers.animateGoToTaskIndex(0, Kirigami.Units.longDuration);
taskSwitcherHelpers.animateGoToTaskIndex(0, taskSwitcherHelpers.longAnimationDuration);
} else if (state.currentTaskIndex >= tasksCount) {
// if the user is on the last task, and it is closed, scroll left
taskSwitcherHelpers.animateGoToTaskIndex(tasksCount - 1, Kirigami.Units.longDuration);
taskSwitcherHelpers.animateGoToTaskIndex(tasksCount - 1, taskSwitcherHelpers.longAnimationDuration);
}
}
@ -350,7 +353,7 @@ FocusScope {
if (!root.taskSwitcherHelpers.taskDrawerOpened && unmodifiedYposition < root.taskSwitcherHelpers.openedYPosition) {
// if in a app, switch it to the new task when it is under the openedYPosition
taskList.setTaskOffsetValue(0, unmodifiedYposition < root.taskSwitcherHelpers.openedYPosition && root.taskSwitcherHelpers.notHomeScreenState);
root.taskSwitcherHelpers.openApp(newIndex, Kirigami.Units.longDuration * 4, Easing.OutExpo);
root.taskSwitcherHelpers.openApp(newIndex, root.taskSwitcherHelpers.extendedAnimationDuration, Easing.OutExpo);
} else {
// if already in the task switcher or above the openedYPosition, only change the focus to the new task
root.taskSwitcherHelpers.animateGoToTaskIndex(newIndex);
@ -463,8 +466,9 @@ FocusScope {
property real backgroundColorOpacity: 1
Behavior on backgroundColorOpacity {
id: backgroundColorOpacityAn
NumberAnimation {
duration: Kirigami.Units.longDuration
MobileShell.MotionNumberAnimation {
type: MobileShell.Motion.SpatialDefault
duration: root.taskSwitcherHelpers.longAnimationDuration
}
}
@ -643,12 +647,12 @@ FocusScope {
anchors.bottomMargin: root.bottomMargin
anchors.topMargin: root.topMargin
NumberAnimation on opacity {
MobileShell.MotionNumberAnimation on opacity {
id: closeAnim
type: MobileShell.Motion.Standard
running: false
to: 0
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
duration: root.taskSwitcherHelpers.longAnimationDuration
onFinished: {
closeAllButton.closeRequested = false;
@ -664,7 +668,7 @@ FocusScope {
let baseOpacity = ((root.tasksCount === 0 && !root.taskSwitcherHelpers.currentlyBeingClosed) ? 0.9 : 0);
return root.taskSwitcherHelpers.gestureState == TaskSwitcherHelpers.GestureStates.TaskSwitcher ? baseOpacity : 0;
}
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.veryLongDuration } }
Behavior on opacity { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsSlow; duration: root.veryLongAnimationDuration } }
anchors.centerIn: container
@ -692,7 +696,7 @@ FocusScope {
RowLayout {
id: scrubIconList
opacity: root.taskSwitcherHelpers.isInTaskScrubMode ? 1 : 0
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration } }
Behavior on opacity { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.taskSwitcherHelpers.longAnimationDuration } }
anchors.bottom: container.bottom
anchors.right: container.horizontalCenter
@ -704,7 +708,8 @@ FocusScope {
return -offset;
}
Behavior on anchors.rightMargin {
NumberAnimation {
MobileShell.MotionNumberAnimation {
type: MobileShell.Motion.SpatialDefault
duration: root.taskSwitcherHelpers.xAnimDuration;
easing.type: root.taskSwitcherHelpers.xAnimEasingType;
}
@ -735,7 +740,7 @@ FocusScope {
RowLayout {
id: scrubIndicator
opacity: root.taskSwitcherHelpers.isInTaskScrubMode ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 200 } }
Behavior on opacity { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.taskSwitcherHelpers.longAnimationDuration } }
anchors.bottom: container.bottom
anchors.horizontalCenter: container.horizontalCenter
@ -743,8 +748,8 @@ FocusScope {
Kirigami.Icon {
id: iconScrubBack
opacity: root.state.currentTaskIndex == 0 ? 0.3 : 1
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration * 2; easing.type: Easing.OutExpo } }
opacity: root.state.currentTaskIndex == 0 ? root.disabledScrubArrowOpacity : 1
Behavior on opacity { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialExtended; duration: root.taskSwitcherHelpers.taskScrubAnimationDuration } }
Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
@ -758,8 +763,8 @@ FocusScope {
Kirigami.Icon {
id: iconScrubFront
opacity: root.state.currentTaskIndex == root.tasksCount - 1 ? 0.3 : 1
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration * 2; easing.type: Easing.OutExpo } }
opacity: root.state.currentTaskIndex == root.tasksCount - 1 ? root.disabledScrubArrowOpacity : 1
Behavior on opacity { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialExtended; duration: root.taskSwitcherHelpers.taskScrubAnimationDuration } }
Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
@ -809,7 +814,7 @@ FocusScope {
}
opacity: (root.taskSwitcherHelpers.currentlyBeingClosed || root.state.gestureInProgress || !root.taskSwitcherHelpers.taskDrawerOpened) ? 0.0 : 1.0
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } }
Behavior on opacity { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
icon.name: "edit-clear-history"
font.bold: true

View file

@ -7,6 +7,7 @@ pragma ComponentBehavior: Bound
import QtQuick 2.15
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.taskswitcherplugin as TaskSwitcherPlugin
import org.kde.kwin 3.0 as KWinComponents
@ -97,7 +98,13 @@ QtObject {
property bool reachedHeightThreshold: false
// made as variables to keep x anim in task list and task scrub icon list in sync
property int xAnimDuration: Kirigami.Units.longDuration * 2
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialFast)
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property int primaryAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Emphasized)
readonly property int taskScrubAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialExtended)
readonly property int extendedAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialVerySlow)
readonly property real closeScaleOut: MobileShell.Motion.closeScaleOut
property int xAnimDuration: taskScrubAnimationDuration
property int xAnimEasingType: Easing.OutExpo
// ~~ measurement constants ~~
@ -232,12 +239,12 @@ QtObject {
closeFactorAnim.restart();
}
function openApp(index: int, duration = Kirigami.Units.shortDuration, horizontalEasing = Easing.OutBack): void {
function openApp(index: int, duration = root.shortAnimationDuration, horizontalEasing = Easing.OutCubic): void {
// cancel any opening animations ongoing
openAnim.stop();
cancelAnimations();
animateGoToTaskIndex(index, duration);
animateGoToTaskIndex(index, duration, horizontalEasing);
openAppAnim.restart();
KWinComponents.Workspace.activeWindow = taskList.getTaskAt(index).window;
}
@ -253,8 +260,8 @@ QtObject {
}
// go to the task index, animated
function animateGoToTaskIndex(index: int, duration = Kirigami.Units.longDuration * 2, easing = Easing.OutExpo): void {
xAnimDuration = duration;
function animateGoToTaskIndex(index: int, duration = root.taskScrubAnimationDuration, easing = Easing.OutExpo): void {
xAnimDuration = MobileShell.Motion.enabled ? duration : 0;
xAnimEasingType = easing;
xAnim.to = xPositionFromTaskIndex(index) - (gestureState == TaskSwitcherHelpers.GestureStates.HorizontalSwipe && !state.gestureInProgress && notHomeScreenState ? taskSpacing / 2 : 0);
xAnim.restart();
@ -309,19 +316,20 @@ QtObject {
// ~~ property animators ~~
property var xAnim: NumberAnimation {
property var xAnim: MobileShell.MotionNumberAnimation {
target: root.state
property: "xPosition"
type: MobileShell.Motion.SpatialDefault
duration: root.xAnimDuration
easing.type: root.xAnimEasingType
}
property var openAnim: NumberAnimation {
property var openAnim: MobileShell.MotionNumberAnimation {
target: root.state
property: "yPosition"
to: root.openedYPosition
duration: 250
easing.type: Easing.OutQuart
type: MobileShell.Motion.EmphasizedDecel
duration: root.primaryAnimationDuration
onFinished: {
if (!root.isInTaskScrubMode) {
@ -330,15 +338,13 @@ QtObject {
}
}
// TODO: This animation should ideally be replaced by some
// speed tracking to track finger movement better. Until then
// InBack at least pretends to go in the finger move direction
property var closeAnim: NumberAnimation {
// Mirror the opening deceleration with an accelerating exit, without overshooting the gesture path.
property var closeAnim: MobileShell.MotionNumberAnimation {
target: root.state
property: "yPosition"
to: 0
duration: Kirigami.Units.longDuration
easing.type: Easing.InBack
type: MobileShell.Motion.EmphasizedAccel
duration: root.primaryAnimationDuration
onFinished: {
root.inLastFrame = true;
@ -347,32 +353,32 @@ QtObject {
}
}
property var closeScaleAnim: NumberAnimation {
property var closeScaleAnim: MobileShell.MotionNumberAnimation {
target: root
property: "closingScalingFactor"
to: 0.1
duration: Kirigami.Units.longDuration
easing.type: Easing.InQuad
to: root.closeScaleOut
type: MobileShell.Motion.EmphasizedAccel
duration: root.primaryAnimationDuration
onStopped: {
root.closingScalingFactor = 1;
}
}
property var closeFactorAnim: NumberAnimation {
property var closeFactorAnim: MobileShell.MotionNumberAnimation {
target: root
property: "closingFactor"
to: 0
duration: Kirigami.Units.longDuration
easing.type: Easing.InQuad
type: MobileShell.Motion.EmphasizedAccel
duration: root.primaryAnimationDuration
}
property var openAppAnim: NumberAnimation {
property var openAppAnim: MobileShell.MotionNumberAnimation {
target: root.state
property: "yPosition"
to: 0
duration: 300
easing.type: Easing.OutQuint
type: MobileShell.Motion.Emphasized
duration: root.primaryAnimationDuration
onFinished: {
root.inLastFrame = true;
root.state.status = TaskSwitcherPlugin.MobileTaskSwitcherState.Inactive;

View file

@ -21,6 +21,7 @@ Item {
property alias circleOpacity: buttonRect.opacity
property alias circleVisiblity: buttonRect.visible
readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software
readonly property color buttonBorderColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.65)
signal clicked
@ -39,7 +40,7 @@ Item {
color: Kirigami.Theme.backgroundColor
opacity: mouseArea.containsPress ? 1 : 0.6
border {
color: Qt.rgba(255, 255, 255, 0.8)
color: root.buttonBorderColor
width: 1
}
}

View file

@ -15,10 +15,13 @@ import org.kde.kirigami as Kirigami
import org.kde.coreaddons 1.0 as KCoreAddons
import org.kde.plasma.private.sessions 2.0
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
Item {
id: root
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
readonly property real backgroundDimOpacity: 0.6
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
Kirigami.Theme.inherit: false
@ -71,15 +74,15 @@ Item {
target: buttons
from: 0
to: 1
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
duration: root.longAnimationDuration
easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
}
OpacityAnimator {
target: background
from: 0
to: 0.6
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
to: root.backgroundDimOpacity
duration: root.longAnimationDuration
easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
}
}
@ -98,22 +101,22 @@ Item {
target: buttons
from: 1
to: 0
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
duration: root.longAnimationDuration
easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
}
OpacityAnimator {
target: background
from: 0.6
from: root.backgroundDimOpacity
to: 0
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
duration: root.longAnimationDuration
easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
}
OpacityAnimator {
target: blackOverlay
from: 0
to: closeAnim.closeToBlack ? 1 : 0
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
duration: root.longAnimationDuration
easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
}
}
ScriptAction {
@ -122,7 +125,7 @@ Item {
closeAnim.callback();
}
buttons.opacity = 1;
background.opacity = 0.6;
background.opacity = root.backgroundDimOpacity;
}
}
}

View file

@ -6,6 +6,7 @@
import QtQuick
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
Rectangle {
id: root
@ -15,6 +16,9 @@ Rectangle {
property int stage
readonly property bool busy: stage > 1 && stage < 6
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
readonly property int veryLongAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsSlow)
readonly property int spinnerAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.EffectsSlow) * 3.5)
Item {
id: content
@ -25,8 +29,8 @@ Rectangle {
Behavior on opacity {
OpacityAnimator {
duration: Kirigami.Units.veryLongDuration
easing.type: Easing.InOutQuad
duration: root.veryLongAnimationDuration
easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsSlow)
}
}
@ -63,8 +67,8 @@ Rectangle {
Behavior on opacity {
OpacityAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
duration: root.longAnimationDuration
easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
}
}
@ -89,9 +93,9 @@ Rectangle {
RotationAnimator on rotation {
from: 0
to: 360
duration: 1400
duration: root.spinnerAnimationDuration
loops: Animation.Infinite
running: root.busy && Kirigami.Units.longDuration > 1
running: root.busy && MobileShell.Motion.enabled
}
}
}

View file

@ -11,6 +11,7 @@ import org.kde.plasma.plasmoid
import org.kde.kirigami as Kirigami
import org.kde.plasma.configuration 2.0
import org.kde.kitemmodels 1.0 as KItemModels
import org.kde.plasma.private.mobileshell as MobileShell
import './private'
@ -28,6 +29,7 @@ Item {
property bool isContainment: false
property alias app: appLoader.item
property bool loadApp: true
readonly property int appAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
signal appLoaded()
@ -132,10 +134,10 @@ Item {
opacity: 0
scale: 0.7 + 0.3 * app.opacity
NumberAnimation on opacity {
MobileShell.MotionNumberAnimation on opacity {
id: opacityAnim
duration: Kirigami.Units.longDuration
easing.type: Easing.OutCubic
type: MobileShell.Motion.EffectsDefault
duration: root.appAnimationDuration
onFinished: {
if (app.opacity === 0) {
root.Window.window.close();

View file

@ -47,10 +47,10 @@ MobileShell.SwipeArea {
}
}
NumberAnimation on position {
MobileShell.MotionNumberAnimation on position {
id: positionAnim
type: MobileShell.Motion.SpatialSlow
duration: root.animationDuration
easing.type: Easing.OutExpo
onFinished: {
if (root.position === keypadHeight) {

View file

@ -17,6 +17,8 @@ Item {
id: root
required property real openProgress
required property var lockScreenState
readonly property int layoutAnimationDuration: openProgress > 0.5 ? MobileShell.Motion.duration(MobileShell.Motion.Emphasized) : 0
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
property alias passwordBar: passwordBar
@ -63,8 +65,8 @@ Item {
transitions: Transition {
AnchorAnimation {
easing.type: Easing.OutCirc
duration: openProgress > 0.5 ? 300 : 0
easing.type: MobileShell.Motion.easing(MobileShell.Motion.Emphasized)
duration: root.layoutAnimationDuration
}
}
}
@ -102,8 +104,8 @@ Item {
transitions: Transition {
AnchorAnimation {
easing.type: Easing.OutCirc
duration: openProgress > 0.5 ? 300 : 0
easing.type: MobileShell.Motion.easing(MobileShell.Motion.Emphasized)
duration: root.layoutAnimationDuration
}
}
}
@ -126,7 +128,7 @@ Item {
Layout.topMargin: keypadVerticalContainer.visible ? Kirigami.Units.gridUnit * 3 : 0
Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
}
}
@ -172,8 +174,8 @@ Item {
opacity: enabled
Behavior on opacity {
SequentialAnimation {
PauseAnimation { duration: 20 * index }
NumberAnimation { duration: 300 }
PauseAnimation { duration: MobileShell.Motion.enabled ? 20 * index : 0 }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Emphasized; duration: root.layoutAnimationDuration }
}
}

View file

@ -108,7 +108,7 @@ Item {
property alias passwordBar: keypad.passwordBar
// Speed up animation when passwordless
animationDuration: Kirigami.Units.veryLongDuration
animationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow)
// Distance to swipe to fully open keypad
keypadHeight: Kirigami.Units.gridUnit * 20

View file

@ -7,6 +7,7 @@ import QtQuick.Layouts
import org.kde.plasma.workspace.keyboardlayout 1.0
import org.kde.plasma.workspace.keyboardlayout 1.0 as Keyboards
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.kirigami as Kirigami
@ -23,9 +24,12 @@ Rectangle {
readonly property color headerTextColor: Qt.rgba(255, 255, 255, 1)
readonly property color headerTextInactiveColor: Qt.rgba(255, 255, 255, 0.4)
readonly property color passwordBarSurfaceColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.18)
readonly property int quickAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.Press) * 2 / 3)
readonly property int previewAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
radius: Kirigami.Units.largeSpacing
color: Qt.rgba(255, 255, 255, 0.2)
color: root.passwordBarSurfaceColor
// model for shown dots
// we need to use a listmodel to avoid all delegates from reloading
@ -223,7 +227,7 @@ Rectangle {
model: dotDisplayModel
Behavior on implicitWidth {
NumberAnimation { duration: 50 }
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Press; duration: root.quickAnimationDuration }
}
onImplicitWidthChanged: {
@ -242,7 +246,7 @@ Rectangle {
Component.onCompleted: {
if (showChar) {
charAnimation.to = 1;
charAnimation.duration = 75;
charAnimation.duration = root.previewAnimationDuration;
charAnimation.restart();
} else {
dotAnimation.to = 1;
@ -253,7 +257,7 @@ Rectangle {
onShowCharChanged: {
if (!showChar) {
charAnimation.to = 0;
charAnimation.duration = 50;
charAnimation.duration = root.quickAnimationDuration;
charAnimation.restart();
dotAnimation.to = 1;
dotAnimation.start();
@ -269,11 +273,12 @@ Rectangle {
radius: width
color: lockScreenState.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth
PropertyAnimation {
MobileShell.MotionNumberAnimation {
id: dotAnimation
target: dot;
property: "scale";
duration: 50
type: MobileShell.Motion.Press
duration: root.quickAnimationDuration
}
}
@ -285,10 +290,11 @@ Rectangle {
text: model.char
font.pointSize: 12
PropertyAnimation {
MobileShell.MotionNumberAnimation {
id: charAnimation
target: charLabel;
property: "scale";
type: MobileShell.Motion.Press
}
}
}

View file

@ -16,13 +16,18 @@ AbstractButton {
property int buttonAction
property bool buttonHeld: false
property double scale: pressed ? (buttonHeld ? 1.7 : 1.5) : 1
property double scale: pressed ? (buttonHeld ? heldScale : pressedScale) : 1
property real fillAmount: 0.0
readonly property int visualAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Standard)
readonly property real pressedScale: MobileShell.Motion.pressScaleOut
readonly property real heldScale: MobileShell.Motion.enabled ? 1.14 : 1
readonly property color actionSurfaceColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.16)
readonly property color actionFillColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.32)
Behavior on scale {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.OutBack
MobileShell.MotionNumberAnimation {
type: MobileShell.Motion.Standard
duration: root.visualAnimationDuration
}
}
@ -42,14 +47,14 @@ AbstractButton {
background: Rectangle {
radius: width
color: Qt.rgba(255, 255, 255, 0.2)
color: root.actionSurfaceColor
Rectangle {
anchors.centerIn: parent
width: parent.width * root.fillAmount
height: parent.height * root.fillAmount
radius: Math.min(width, height)
color: Qt.rgba(255, 255, 255, 0.2) // Use the same background rectangle color
color: root.actionFillColor
}
}
@ -117,19 +122,21 @@ AbstractButton {
}
}
PropertyAnimation {
MobileShell.MotionNumberAnimation {
id: fillAnimation
target: root
property: "fillAmount"
duration: Kirigami.Units.longDuration
type: MobileShell.Motion.Standard
duration: root.visualAnimationDuration
to: 1.0
}
PropertyAnimation {
MobileShell.MotionNumberAnimation {
id: emptyAnimation
target: root
property: "fillAmount"
duration: Kirigami.Units.longDuration
type: MobileShell.Motion.Standard
duration: root.visualAnimationDuration
to: 0.0
}
}