Compare commits

..

21 commits

Author SHA1 Message Date
d9943d2e7a Let symbolic icons follow the color scheme
Declare FollowsColorScheme=true for the Shift icon theme so KDE apps recolor symbolic Places glyphs against dark and light surfaces. Document the requirement and guard it in the icon theme coverage test.
2026-05-23 09:30:21 +02:00
6cc92b7fa2 Add SPDX headers to motion QML components
Add missing SPDX copyright and license tags to Motion.qml,
MotionColorAnimation.qml, MotionNumberAnimation.qml, and
MotionStateLayer.qml to satisfy REUSE lint in CI.
2026-05-23 09:18:53 +02:00
36d9004473 Round normal window decorations
Reserve side and bottom decoration borders for normal windows and draw a rounded decoration frame so windows match the convergence workspace shape. Add static guards for the decoration and existing workspace-frame corner geometry.
2026-05-23 08:53:02 +02:00
d03f3585a3 Block native window menu during tiling 2026-05-22 09:39:45 +02:00
e951690c91 Route Folio task actions through tiling 2026-05-22 09:39:28 +02:00
5311dc8fe8 Own dynamic tiling window workflows 2026-05-22 09:39:11 +02:00
24e410c733 Respect animation settings in navigation tutorial
Gate the navigation KCM tutorial timings on ShellSettings animationsEnabled so the demo stops animating when the user disables shell animations.
2026-05-21 11:15:01 +02:00
753909a6ce 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.
2026-05-21 11:14:42 +02:00
88a4f5883b Move Folio gaming surfaces to shared motion
Use Motion tokens for the Game Center overlay, gaming HUD, quick settings drawer, and running-games panel. Keep gaming mode settings and gamepad behavior unchanged.
2026-05-21 11:14:00 +02:00
a37734b74a Move homescreens to shared motion
Use Motion wrappers and state layers across Folio and Halcyon delegates, drawers, folders, resize handles, and dock feedback. Also align Folio edit/drop highlights with theme colors instead of fixed white overlays.
2026-05-21 11:13:36 +02:00
7f9087f342 Move shell popups to shared motion
Apply Motion tokens to notification drag and stack transitions, volume OSD feedback, KRunner field state, media controls height changes, and action-button popup affordances. Leave timeout and marquee animations as timing behavior.
2026-05-21 11:13:06 +02:00
1074b86225 Move shell chrome to shared motion
Use the Motion wrappers for action-drawer transitions, status bar feedback, panel reveal motion, startup feedback, and shell homescreen chrome. Keep non-animation settings reads in ShellSettings where they still control behavior.
2026-05-21 11:12:44 +02:00
8767df8b10 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.
2026-05-21 11:12:20 +02:00
75b9049a8c Page dynamic tiles by workspace
Keep one layout per output and virtual desktop. Move new windows to another existing desktop when the current page is full.

When a user moves a window onto a full page, replace the last focused window on that page and send it back to the source desktop. Use stable slot swaps instead of insert splits so the layout shape does not change during moves.
2026-05-20 09:38:37 +02:00
40beabede9 Keep tile preview effect inert
Nested KWin blacks out when this scene effect becomes visible. Leave the effect disabled and let the tiling script own swap and restore outlines.
2026-05-20 09:38:22 +02:00
f2f6f6f890 Stabilize nested preview startup
Use a concrete wallpaper image in generated shell config. Disable KSycoca watches when preview opts out, and keep the convergent window connection target nullable.
2026-05-20 09:38:08 +02:00
d2b3445f98 Ignore preview runtime state 2026-05-20 09:37:38 +02:00
cb4d842de3 Add primary tile promotion 2026-05-19 10:01:45 +02:00
7c51f76cc0 Reduce dynamic tile drag jitter 2026-05-19 10:00:43 +02:00
c6bd37dfc3 Stabilize automatic tile layouts 2026-05-19 09:55:25 +02:00
e0e51d7ffd Add dynamic tile drag preview 2026-05-19 09:47:45 +02:00
106 changed files with 3039 additions and 751 deletions

2
.gitignore vendored
View file

@ -21,6 +21,8 @@ build
*.kdev4 *.kdev4
/build* /build*
.prefix/ .prefix/
.preview-ab/
.preview-cache/
.preview-config/ .preview-config/
.preview-data/ .preview-data/
preview.sh preview.sh

View file

@ -138,7 +138,7 @@ include(CheckIncludeFiles)
ecm_find_qmlmodule(org.kde.pipewire 0.1) ecm_find_qmlmodule(org.kde.pipewire 0.1)
set(SHIFT_DEFAULT_WALLPAPER_URL "file://${KDE_INSTALL_FULL_WALLPAPERDIR}/SHIFT/") set(SHIFT_DEFAULT_WALLPAPER_URL "file://${KDE_INSTALL_FULL_WALLPAPERDIR}/SHIFT/contents/images_dark/5120x2880.png")
set(SHIFT_SHELL_PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/shell") set(SHIFT_SHELL_PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/shell")
file(REMOVE_RECURSE "${SHIFT_SHELL_PACKAGE_DIR}") file(REMOVE_RECURSE "${SHIFT_SHELL_PACKAGE_DIR}")
file(COPY shell/ DESTINATION "${SHIFT_SHELL_PACKAGE_DIR}" PATTERN "layout.js.in" EXCLUDE) file(COPY shell/ DESTINATION "${SHIFT_SHELL_PACKAGE_DIR}" PATTERN "layout.js.in" EXCLUDE)

View file

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

View file

@ -269,11 +269,11 @@ Item {
transitions: Transition { transitions: Transition {
SequentialAnimation { SequentialAnimation {
PropertyAnimation { MobileShell.MotionNumberAnimation {
id: drawerAnimation id: drawerAnimation
properties: "offset" properties: "offset"
easing.type: Easing.OutExpo type: MobileShell.Motion.SpatialSlow
duration: root.state != "" ? Kirigami.Units.veryLongDuration : 0 duration: root.state != "" ? MobileShell.Motion.duration(type) : 0
} }
ScriptAction { ScriptAction {
script: { script: {

View file

@ -22,10 +22,7 @@ Item {
property double brightnessPressedValue: 1 property double brightnessPressedValue: 1
Behavior on brightnessPressedValue { Behavior on brightnessPressedValue {
NumberAnimation { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialExtended }
duration: Kirigami.Units.longDuration * 2
easing.type: Easing.InOutQuad
}
} }
ScreenBrightness.ScreenBrightnessUtil { ScreenBrightness.ScreenBrightnessUtil {

View file

@ -70,7 +70,7 @@ Item {
Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.g,
Kirigami.Theme.backgroundColor.b, Kirigami.Theme.backgroundColor.b,
0.9) 0.9)
Behavior on color { ColorAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.OutQuad } } Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.StandardDecel } }
opacity: { opacity: {
let base = Math.max(0, Math.min(brightnessPressedValue, actionDrawer.offset / root.minimizedQuickSettingsOffset)); let base = Math.max(0, Math.min(brightnessPressedValue, actionDrawer.offset / root.minimizedQuickSettingsOffset));
return ShellSettings.Settings.convergenceModeEnabled ? base * 0.3 : base; return ShellSettings.Settings.convergenceModeEnabled ? base * 0.3 : base;

View file

@ -27,6 +27,7 @@ QQC2.Popup {
padding: Kirigami.Units.smallSpacing padding: Kirigami.Units.smallSpacing
readonly property int popupAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
property string currentPluginId: "" property string currentPluginId: ""
property Item __currentItem: null property Item __currentItem: null
@ -72,11 +73,11 @@ QQC2.Popup {
} }
enter: Transition { enter: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { property: "opacity"; from: 0; to: 1; type: MobileShell.Motion.EffectsFast }
NumberAnimation { property: "scale"; from: 0.9; to: 1; duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { property: "scale"; from: 0.9; to: 1; type: MobileShell.Motion.EffectsFast }
} }
exit: Transition { exit: Transition {
NumberAnimation { property: "opacity"; from: 1; to: 0; duration: Kirigami.Units.shortDuration; easing.type: Easing.InCubic } MobileShell.MotionNumberAnimation { property: "opacity"; from: 1; to: 0; type: MobileShell.Motion.StandardAccel; duration: popup.popupAnimationDuration }
} }
background: Kirigami.ShadowedRectangle { background: Kirigami.ShadowedRectangle {

View file

@ -47,6 +47,8 @@ MobileShell.BaseItem {
readonly property color disabledButtonColor: Kirigami.Theme.alternateBackgroundColor readonly property color disabledButtonColor: Kirigami.Theme.alternateBackgroundColor
readonly property color disabledButtonHoverColor: mixColor(Kirigami.Theme.alternateBackgroundColor, Kirigami.Theme.textColor, 0.06) readonly property color disabledButtonHoverColor: mixColor(Kirigami.Theme.alternateBackgroundColor, Kirigami.Theme.textColor, 0.06)
readonly property color disabledButtonPressedColor: Qt.darker(disabledButtonColor, 1.1) readonly property color disabledButtonPressedColor: Qt.darker(disabledButtonColor, 1.1)
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
readonly property real pressedScale: MobileShell.Motion.pressScaleIn
function mixColor(base, overlay, ratio) { function mixColor(base, overlay, ratio) {
return Qt.rgba( return Qt.rgba(
@ -67,10 +69,7 @@ MobileShell.BaseItem {
// scale animation on press // scale animation on press
property real zoomScale: 1 property real zoomScale: 1
Behavior on zoomScale { Behavior on zoomScale {
NumberAnimation { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Press }
duration: Kirigami.Units.longDuration
easing.type: Easing.OutExpo
}
} }
transform: Scale { transform: Scale {

View file

@ -12,7 +12,6 @@ import org.kde.kirigami as Kirigami
import org.kde.plasma.core as PlasmaCore import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.private.mobileshell as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
QuickSettingsDelegate { QuickSettingsDelegate {
@ -23,7 +22,7 @@ QuickSettingsDelegate {
readonly property int tileRadius: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing readonly property int tileRadius: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
// scale animation on press // scale animation on press
zoomScale: (ShellSettings.Settings.animationsEnabled && mouseArea.pressed) ? 0.9 : 1 zoomScale: mouseArea.pressed ? root.pressedScale : 1
background: Item { background: Item {
// very simple shadow for performance // very simple shadow for performance
@ -61,7 +60,7 @@ QuickSettingsDelegate {
} }
Behavior on color { Behavior on color {
ColorAnimation { duration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.shortDuration : 0; easing.type: Easing.OutCubic } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast }
} }
} }
} }

View file

@ -12,7 +12,6 @@ import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.core as PlasmaCore import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.private.nanoshell 2.0 as NanoShell import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
QuickSettingsDelegate { QuickSettingsDelegate {
@ -21,7 +20,7 @@ QuickSettingsDelegate {
iconItem: icon iconItem: icon
// scale animation on press // scale animation on press
zoomScale: (ShellSettings.Settings.animationsEnabled && mouseArea.pressed) ? 0.9 : 1 zoomScale: mouseArea.pressed ? root.pressedScale : 1
background: Item { background: Item {
// very simple shadow for performance // very simple shadow for performance
@ -58,7 +57,7 @@ QuickSettingsDelegate {
} }
Behavior on color { Behavior on color {
ColorAnimation { duration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.shortDuration : 0; easing.type: Easing.OutCubic } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast }
} }
} }
} }

View file

@ -6,7 +6,6 @@ import QtQuick.Layouts 1.1
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
/** /**
* Management/detail row shown in convergence mode. Two interaction zones: * Management/detail row shown in convergence mode. Two interaction zones:
@ -49,6 +48,9 @@ Item {
return Kirigami.ColorUtils.linearInterpolation(bg, fg, 0.1); return Kirigami.ColorUtils.linearInterpolation(bg, fg, 0.1);
} }
} }
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
readonly property real pressedScale: MobileShell.Motion.pressScaleIn
function mixColor(base, overlay, ratio) { function mixColor(base, overlay, ratio) {
return Qt.rgba( return Qt.rgba(
@ -117,14 +119,14 @@ Item {
} }
Behavior on color { Behavior on color {
ColorAnimation { duration: Kirigami.Units.shortDuration } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast }
} }
} }
// Scale on press // Scale on press
property real zoomScale: (ShellSettings.Settings.animationsEnabled && toggleMouse.pressed) ? 0.9 : 1 property real zoomScale: toggleMouse.pressed ? root.pressedScale : 1
Behavior on zoomScale { Behavior on zoomScale {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.OutExpo } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Press }
} }
transform: Scale { transform: Scale {
origin.x: togglePill.width / 2 origin.x: togglePill.width / 2
@ -160,7 +162,7 @@ Item {
opacity: root.enabled ? 1.0 : 0.4 opacity: root.enabled ? 1.0 : 0.4
Behavior on width { Behavior on width {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast }
} }
} }
} }
@ -186,17 +188,13 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
// Hover/press highlight MobileShell.MotionStateLayer {
Rectangle {
anchors.fill: parent anchors.fill: parent
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: detailMouse.pressed ? Qt.rgba(Kirigami.Theme.textColor.r, hovered: detailMouse.containsMouse
Kirigami.Theme.textColor.g, pressed: detailMouse.pressed
Kirigami.Theme.textColor.b, 0.06) hoverOpacity: 0.03
: detailMouse.containsMouse ? Qt.rgba(Kirigami.Theme.textColor.r, pressedOpacity: 0.06
Kirigami.Theme.textColor.g,
Kirigami.Theme.textColor.b, 0.03)
: "transparent"
} }
MouseArea { MouseArea {

View file

@ -26,6 +26,7 @@ QQC2.Popup {
padding: Kirigami.Units.smallSpacing padding: Kirigami.Units.smallSpacing
readonly property int popupAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int trayItemCount: trayList.count readonly property int trayItemCount: trayList.count
function show() { function show() {
@ -147,17 +148,20 @@ QQC2.Popup {
anchors.leftMargin: Kirigami.Units.smallSpacing anchors.leftMargin: Kirigami.Units.smallSpacing
anchors.rightMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: trayMouse.pressed ? Qt.rgba(Kirigami.Theme.textColor.r, color: Kirigami.Theme.alternateBackgroundColor
Kirigami.Theme.textColor.g,
Kirigami.Theme.textColor.b, 0.08)
: trayMouse.containsMouse ? Qt.rgba(Kirigami.Theme.textColor.r,
Kirigami.Theme.textColor.g,
Kirigami.Theme.textColor.b, 0.04)
: Kirigami.Theme.alternateBackgroundColor
border.width: 1 border.width: 1
border.color: Kirigami.ColorUtils.linearInterpolation( border.color: Kirigami.ColorUtils.linearInterpolation(
Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, trayItem.itemActive ? 0.16 : 0.08) Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, trayItem.itemActive ? 0.16 : 0.08)
opacity: trayItem.itemActive ? 1 : 0.72 opacity: trayItem.itemActive ? 1 : 0.72
MobileShell.MotionStateLayer {
anchors.fill: parent
radius: parent.radius
hovered: trayMouse.containsMouse
pressed: trayMouse.pressed
hoverOpacity: 0.04
pressedOpacity: 0.08
}
} }
RowLayout { RowLayout {
@ -237,11 +241,11 @@ QQC2.Popup {
} }
enter: Transition { enter: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { property: "opacity"; from: 0; to: 1; type: MobileShell.Motion.EffectsFast }
NumberAnimation { property: "scale"; from: 0.9; to: 1; duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { property: "scale"; from: 0.9; to: 1; type: MobileShell.Motion.EffectsFast }
} }
exit: Transition { exit: Transition {
NumberAnimation { property: "opacity"; from: 1; to: 0; duration: Kirigami.Units.shortDuration; easing.type: Easing.InCubic } MobileShell.MotionNumberAnimation { property: "opacity"; from: 1; to: 0; type: MobileShell.Motion.StandardAccel; duration: popup.popupAnimationDuration }
} }
QQC2.Overlay.modal: Rectangle { QQC2.Overlay.modal: Rectangle {

View file

@ -0,0 +1,106 @@
// SPDX-FileCopyrightText: 2026 Marco Allegretti
// SPDX-License-Identifier: EUPL-1.2
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,11 @@
// SPDX-FileCopyrightText: 2026 Marco Allegretti
// SPDX-License-Identifier: EUPL-1.2
import QtQuick
ColorAnimation {
property int type: Motion.EffectsFast
duration: Motion.duration(type)
easing.type: Motion.easing(type)
}

View file

@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2026 Marco Allegretti
// SPDX-License-Identifier: EUPL-1.2
import QtQuick
NumberAnimation {
property int type: Motion.Standard
duration: Motion.duration(type)
easing.type: Motion.easing(type)
}

View file

@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: 2026 Marco Allegretti
// SPDX-License-Identifier: EUPL-1.2
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 }
}
}
}

View file

@ -62,9 +62,9 @@ Item {
// for example, popup notifition when opening the popup notifition drawer // for example, popup notifition when opening the popup notifition drawer
// in these incidents, we animate the color to prevent harsh transitions // in these incidents, we animate the color to prevent harsh transitions
Behavior on panelColor { Behavior on panelColor {
ColorAnimation { MotionColorAnimation {
duration: animate ? Kirigami.Units.veryLongDuration * 1.5 : 0 type: Motion.SpatialSlow
easing.type: Easing.OutExpo duration: animate ? Math.round(Motion.duration(type) * 1.5) : 0
} }
} }

View file

@ -3,6 +3,8 @@
import QtQuick import QtQuick
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState import org.kde.plasma.private.mobileshell.state as MobileShellState
// Component to supplement the StartupFeedback window maximization animation for panel backgrounds. // Component to supplement the StartupFeedback window maximization animation for panel backgrounds.
@ -15,14 +17,16 @@ Rectangle {
property var maximizedTracker property var maximizedTracker
readonly property bool isShowing: height > 0 readonly property bool isShowing: height > 0
readonly property int heightAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property int autoClearDelay: heightAnimationDuration + Kirigami.Units.veryLongDuration
// Smooth animation for colored rectangle // Smooth animation for colored rectangle
NumberAnimation on height { MobileShell.MotionNumberAnimation on height {
id: heightAnim id: heightAnim
from: 0 from: 0
to: root.fullHeight to: root.fullHeight
duration: 200 type: MobileShell.Motion.SpatialDefault
easing.type: Easing.OutExpo duration: root.heightAnimationDuration
} }
// Auto-clear safety net. // Auto-clear safety net.
@ -38,7 +42,7 @@ Rectangle {
// the original mobile behaviour while fixing the convergence path. // the original mobile behaviour while fixing the convergence path.
Timer { Timer {
id: autoClearTimer id: autoClearTimer
interval: 600 // animation duration (200) + settle time interval: root.autoClearDelay
repeat: false repeat: false
onTriggered: { onTriggered: {
if (!root.maximizedTracker || !root.maximizedTracker.showingWindow) { if (!root.maximizedTracker || !root.maximizedTracker.showingWindow) {

View file

@ -7,7 +7,7 @@ import QtQuick.Effects
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.nanoshell 2.0 as NanoShell import org.kde.plasma.private.nanoshell 2.0 as NanoShell
@ -39,6 +39,8 @@ Item {
id: window id: window
property var startupFeedback: model.delegate property var startupFeedback: model.delegate
readonly property int simpleOpenDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
readonly property int loadingIndicatorFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
visibility: Window.Maximized visibility: Window.Maximized
flags: Qt.FramelessWindowHint flags: Qt.FramelessWindowHint
@ -62,7 +64,7 @@ Item {
backgroundParent.y = -realHeight/2 + startupFeedback.iconStartY - root.topMargin; backgroundParent.y = -realHeight/2 + startupFeedback.iconStartY - root.topMargin;
} }
if (ShellSettings.Settings.animationsEnabled) { if (MobileShell.Motion.enabled) {
openAnimComplex.restart(); openAnimComplex.restart();
} else { } else {
openAnimSimple.restart(); openAnimSimple.restart();
@ -78,35 +80,35 @@ Item {
ParallelAnimation { ParallelAnimation {
id: parallelAnim id: parallelAnim
property real animationDuration: Kirigami.Units.longDuration + Kirigami.Units.shortDuration property real animationDuration: MobileShell.Motion.duration(MobileShell.Motion.Emphasized)
ScaleAnimator { ScaleAnimator {
target: background target: background
from: background.scale from: background.scale
to: 1 to: 1
duration: parallelAnim.animationDuration duration: parallelAnim.animationDuration
easing.type: Easing.OutCubic easing.type: MobileShell.Motion.easing(MobileShell.Motion.Emphasized)
} }
ScaleAnimator { ScaleAnimator {
target: iconParent target: iconParent
from: iconParent.scale from: iconParent.scale
to: 1 to: 1
duration: parallelAnim.animationDuration duration: parallelAnim.animationDuration
easing.type: Easing.OutCubic easing.type: MobileShell.Motion.easing(MobileShell.Motion.Emphasized)
} }
XAnimator { XAnimator {
target: backgroundParent target: backgroundParent
from: backgroundParent.x from: backgroundParent.x
to: 0 to: 0
duration: parallelAnim.animationDuration duration: parallelAnim.animationDuration
easing.type: Easing.OutCubic easing.type: MobileShell.Motion.easing(MobileShell.Motion.Emphasized)
} }
YAnimator { YAnimator {
target: backgroundParent target: backgroundParent
from: backgroundParent.y from: backgroundParent.y
to: 0 to: 0
duration: parallelAnim.animationDuration duration: parallelAnim.animationDuration
easing.type: Easing.OutCubic easing.type: MobileShell.Motion.easing(MobileShell.Motion.Emphasized)
} }
} }
@ -134,13 +136,13 @@ Item {
} }
} }
NumberAnimation { MobileShell.MotionNumberAnimation {
target: windowRoot target: windowRoot
properties: "opacity" properties: "opacity"
from: 0 from: 0
to: 1 to: 1
duration: Kirigami.Units.longDuration type: MobileShell.Motion.EffectsDefault
easing.type: Easing.OutCubic duration: window.simpleOpenDuration
} }
ScriptAction { ScriptAction {
@ -212,7 +214,10 @@ Item {
opacity: 0 opacity: 0
Behavior on opacity { Behavior on opacity {
NumberAnimation {} MobileShell.MotionNumberAnimation {
type: MobileShell.Motion.EffectsFast
duration: window.loadingIndicatorFadeDuration
}
} }
implicitHeight: Kirigami.Units.iconSizes.smallMedium implicitHeight: Kirigami.Units.iconSizes.smallMedium

View file

@ -4,6 +4,8 @@
import QtQuick import QtQuick
import QtQuick.Window import QtQuick.Window
import org.kde.kirigami as Kirigami
import org.kde.plasma.plasmoid import org.kde.plasma.plasmoid
import org.kde.taskmanager as TaskManager import org.kde.taskmanager as TaskManager
@ -142,7 +144,9 @@ Item {
opacity: 0 opacity: 0
property real scaleAmount: 1 property real scaleAmount: 1
readonly property real zoomScaleOut: 0.8 readonly property real zoomScaleOut: 0.9
readonly property int opacityAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
readonly property int scaleAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow)
function zoomIn() { function zoomIn() {
// don't use check animationsEnabled here, so we ensure the scale and opacity is always 1 when disabled // don't use check animationsEnabled here, so we ensure the scale and opacity is always 1 when disabled
@ -166,17 +170,18 @@ Item {
opacity = 0; opacity = 0;
} }
NumberAnimation on opacity { MobileShell.MotionNumberAnimation on opacity {
id: opacityAnim id: opacityAnim
duration: 300 type: MobileShell.Motion.EffectsDefault
duration: itemContainer.opacityAnimationDuration
running: false running: false
} }
NumberAnimation on scaleAmount { MobileShell.MotionNumberAnimation on scaleAmount {
id: scaleAnim id: scaleAnim
duration: 600 type: MobileShell.Motion.SpatialSlow
duration: itemContainer.scaleAnimationDuration
running: false running: false
easing.type: Easing.OutExpo
} }
function evaluateAnimChange() { function evaluateAnimChange() {

View file

@ -19,6 +19,7 @@ Controls.Drawer {
property MobileShell.MaskManager maskManager property MobileShell.MaskManager maskManager
required property bool horizontal required property bool horizontal
readonly property int previewAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
signal wallpaperSettingsRequested() signal wallpaperSettingsRequested()
@ -100,15 +101,15 @@ Controls.Drawer {
padding: Kirigami.Units.largeSpacing - (wallpapersView.currentIndex === index ? Kirigami.Units.smallSpacing : 0) padding: Kirigami.Units.largeSpacing - (wallpapersView.currentIndex === index ? Kirigami.Units.smallSpacing : 0)
property real scaleAmount: wallpapersView.currentIndex === index ? 0 : Kirigami.Units.smallSpacing property real scaleAmount: wallpapersView.currentIndex === index ? 0 : Kirigami.Units.smallSpacing
Behavior on scaleAmount { Behavior on scaleAmount {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.longDuration type: MobileShell.Motion.EffectsDefault
easing.type: Easing.InOutQuad duration: imageWallpaperDrawer.previewAnimationDuration
} }
} }
Behavior on padding { Behavior on padding {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.longDuration type: MobileShell.Motion.EffectsDefault
easing.type: Easing.InOutQuad duration: imageWallpaperDrawer.previewAnimationDuration
} }
} }

View file

@ -22,6 +22,7 @@ Controls.AbstractButton {
property int shrinkSize: 0 property int shrinkSize: 0
property alias iconSource: icon.source property alias iconSource: icon.source
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
MobileShell.HapticsEffect { MobileShell.HapticsEffect {
id: haptics id: haptics
@ -56,10 +57,10 @@ Controls.AbstractButton {
} }
} }
NumberAnimation on opacity { MobileShell.MotionNumberAnimation on opacity {
id: opacityAnimator id: opacityAnimator
duration: Kirigami.Units.shortDuration type: MobileShell.Motion.Press
easing.type: Easing.InOutQuad duration: button.pressAnimationDuration
onFinished: { onFinished: {
// animate the state back // animate the state back
if (rect.buttonHeld && opacityAnimator.to === 0) { if (rect.buttonHeld && opacityAnimator.to === 0) {

View file

@ -26,6 +26,9 @@ Window {
property int angle: 0 property int angle: 0
property string iconSource property string iconSource
property bool active: false property bool active: false
readonly property int buttonAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Standard)
readonly property real hiddenScale: MobileShell.Motion.hiddenScale
readonly property real pressedScale: MobileShell.Motion.pressScaleOut
signal triggered() signal triggered()
@ -82,7 +85,7 @@ Window {
// Hide the root window after the button disappearing animation finishes. // Hide the root window after the button disappearing animation finishes.
Timer { Timer {
id: hideButton id: hideButton
interval: Kirigami.Units.longDuration interval: root.buttonAnimationDuration
repeat: false repeat: false
onTriggered: if (!active) root.visible = false; onTriggered: if (!active) root.visible = false;
} }
@ -101,20 +104,14 @@ Window {
height: root.size height: root.size
opacity: root.active ? 1 : 0 opacity: root.active ? 1 : 0
property double scale: !root.active ? 0.5 : (button.pressed ? 1.5 : 1) property double scale: !root.active ? root.hiddenScale : (button.pressed ? root.pressedScale : 1)
Behavior on scale { Behavior on scale {
NumberAnimation { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.StandardDecel }
duration: Kirigami.Units.longDuration
easing.type: Easing.OutBack
}
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.StandardDecel }
duration: Kirigami.Units.longDuration
easing.type: Easing.OutCirc
}
} }
transform: Scale { transform: Scale {
@ -133,12 +130,20 @@ Window {
Controls.AbstractButton { Controls.AbstractButton {
id: button id: button
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
MobileShell.HapticsEffect { MobileShell.HapticsEffect {
id: haptics id: haptics
} }
contentItem: Item { contentItem: Item {
MobileShell.MotionStateLayer {
anchors.fill: parent
radius: root.size
hovered: button.hovered
pressed: button.pressed
}
Kirigami.Icon { Kirigami.Icon {
anchors.centerIn: parent anchors.centerIn: parent
width: Kirigami.Units.iconSizes.small width: Kirigami.Units.iconSizes.small

View file

@ -28,6 +28,10 @@ Item {
property int popupWidth property int popupWidth
property real openOffset property real openOffset
property bool isConvergence: false property bool isConvergence: false
readonly property int primaryAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow) * 1.5)
readonly property int secondaryAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow)
readonly property int stackAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow) * 1.25)
readonly property int stackMomentumAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow) * 0.5)
// In convergence the popup enters from the bottom-right corner // In convergence the popup enters from the bottom-right corner
readonly property real effectiveOpenOffset: isConvergence readonly property real effectiveOpenOffset: isConvergence
@ -54,7 +58,7 @@ Item {
// due to it not looking great to have a notification sliding up while another one is sliding down // due to it not looking great to have a notification sliding up while another one is sliding down
// we use a timer so that the current notification can know to use "closeWithScale" instead // we use a timer so that the current notification can know to use "closeWithScale" instead
property Timer queueTimer: Timer { property Timer queueTimer: Timer {
interval: Kirigami.Units.veryLongDuration interval: notificationPopup.secondaryAnimationDuration
running: true running: true
onTriggered: { onTriggered: {
visible = true; visible = true;
@ -113,9 +117,9 @@ Item {
// animate the notifications entering and exiting the expanded drawer // animate the notifications entering and exiting the expanded drawer
property real fullOffsetAn: fullOpenOffset property real fullOffsetAn: fullOpenOffset
Behavior on fullOffsetAn { Behavior on fullOffsetAn {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.veryLongDuration * 1.5 duration: notificationPopup.primaryAnimationDuration
easing.type: Easing.OutExpo type: MobileShell.Motion.SpatialSlow
} }
} }
@ -125,21 +129,21 @@ Item {
// animate this value so that the popup in some situations will not jump around // animate this value so that the popup in some situations will not jump around
property real scaleOriginY: inPopupDrawer && !popupDrawerOpened ? popupNotifications.currentPopupHeight : Math.round(popupHeight / 2) property real scaleOriginY: inPopupDrawer && !popupDrawerOpened ? popupNotifications.currentPopupHeight : Math.round(popupHeight / 2)
Behavior on scaleOriginY { Behavior on scaleOriginY {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.veryLongDuration duration: notificationPopup.secondaryAnimationDuration
easing.type: Easing.OutExpo type: MobileShell.Motion.SpatialSlow
} }
} }
// the vertical drag offset for the notification popup // the vertical drag offset for the notification popup
// we drag is released, animate back to 0 // we drag is released, animate back to 0
property real dragOffset: 0 property real dragOffset: 0
NumberAnimation on dragOffset { MobileShell.MotionNumberAnimation on dragOffset {
id: dragOffsetAn id: dragOffsetAn
running: false running: false
to: 0 to: 0
duration: Kirigami.Units.veryLongDuration * 1.5 type: MobileShell.Motion.SpatialSlow
easing.type: Easing.OutExpo duration: notificationPopup.primaryAnimationDuration
} }
// if the popup height ever changes, update the notification below with new height // if the popup height ever changes, update the notification below with new height
@ -385,21 +389,21 @@ Item {
} }
} }
Behavior on drawerScale { Behavior on drawerScale {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.veryLongDuration * 1.25 duration: notificationPopup.stackAnimationDuration
easing.type: Easing.OutQuint type: MobileShell.Motion.Emphasized
} }
} }
Behavior on drawerAddedOffset { Behavior on drawerAddedOffset {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.veryLongDuration * 1.25 duration: notificationPopup.stackAnimationDuration
easing.type: Easing.OutQuint type: MobileShell.Motion.Emphasized
} }
} }
Behavior on drawerOpacity { Behavior on drawerOpacity {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.veryLongDuration * 1.25 duration: notificationPopup.stackAnimationDuration
easing.type: Easing.OutQuint type: MobileShell.Motion.Emphasized
} }
} }
@ -487,27 +491,30 @@ Item {
if (notificationPopup.closedWithSwipe || (topPopup && popupClosing && popupBelow)) { if (notificationPopup.closedWithSwipe || (topPopup && popupClosing && popupBelow)) {
// make sure the speed it faster when closed with a swipe or if there is a popup below when closing // make sure the speed it faster when closed with a swipe or if there is a popup below when closing
// as to make sure the speed feels comparable with the easing type is set to linear // as to make sure the speed feels comparable with the easing type is set to linear
return Kirigami.Units.veryLongDuration * 0.5; return notificationPopup.stackMomentumAnimationDuration;
} else { } else {
return Kirigami.Units.veryLongDuration * 1.25; return notificationPopup.stackAnimationDuration;
} }
} }
transitions: Transition { transitions: Transition {
SequentialAnimation { SequentialAnimation {
ParallelAnimation { ParallelAnimation {
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "offset" properties: "offset"
type: MobileShell.Motion.SpatialSlow
easing.type: notificationItem.notificationEasing easing.type: notificationItem.notificationEasing
duration: notificationItem.notificationDuration duration: notificationItem.notificationDuration
} }
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "scale" properties: "scale"
type: MobileShell.Motion.SpatialSlow
easing.type: notificationItem.notificationEasing easing.type: notificationItem.notificationEasing
duration: notificationItem.notificationDuration duration: notificationItem.notificationDuration
} }
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "popupOpacity" properties: "popupOpacity"
type: MobileShell.Motion.SpatialSlow
easing.type: notificationItem.notificationEasing easing.type: notificationItem.notificationEasing
duration: notificationItem.notificationDuration duration: notificationItem.notificationDuration
} }

View file

@ -36,6 +36,7 @@ Window {
// Margin between popup and screen edge in convergence mode; used in both // Margin between popup and screen edge in convergence mode; used in both
// the delegate x position and the input-region calculation so they stay in sync. // the delegate x position and the input-region calculation so they stay in sync.
readonly property real convergencePopupMargin: Kirigami.Units.gridUnit * 2 readonly property real convergencePopupMargin: Kirigami.Units.gridUnit * 2
readonly property int popupAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow) * 1.5)
property var keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone property var keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
LayerShell.Window.scope: "notification" LayerShell.Window.scope: "notification"
@ -60,9 +61,9 @@ Window {
readonly property color backgroundColor: Qt.darker(Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.95), 1.05) readonly property color backgroundColor: Qt.darker(Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.95), 1.05)
color: popupDrawerOpened && visible ? backgroundColor : "transparent" color: popupDrawerOpened && visible ? backgroundColor : "transparent"
Behavior on color { Behavior on color {
ColorAnimation { MobileShell.MotionColorAnimation {
duration: Kirigami.Units.veryLongDuration * 1.5 duration: notificationPopupManager.popupAnimationDuration
easing.type: Easing.OutExpo type: MobileShell.Motion.SpatialSlow
} }
} }
@ -82,7 +83,7 @@ Window {
// hide on timeout to give time to finish animations // hide on timeout to give time to finish animations
Timer { Timer {
id: hideTimeout id: hideTimeout
interval: Kirigami.Units.veryLongDuration * 1.5 interval: notificationPopupManager.popupAnimationDuration
repeat: false repeat: false
onTriggered: if (notifications.count == 0) notificationPopupManager.visible = false; onTriggered: if (notifications.count == 0) notificationPopupManager.visible = false;
} }
@ -153,12 +154,12 @@ Window {
resetContentY.running = true; resetContentY.running = true;
} }
NumberAnimation on contentY { MobileShell.MotionNumberAnimation on contentY {
id: resetContentY id: resetContentY
running: false running: false
to: 0 to: 0
duration: Kirigami.Units.veryLongDuration * 1.5 type: MobileShell.Motion.SpatialSlow
easing.type: Easing.OutExpo duration: notificationPopupManager.popupAnimationDuration
} }
MouseArea { MouseArea {

View file

@ -16,6 +16,7 @@ import org.kde.kquickcontrolsaddons
import org.kde.plasma.core as PlasmaCore import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components as PlasmaComponents import org.kde.plasma.components as PlasmaComponents
import org.kde.plasma.extras as PlasmaExtras import org.kde.plasma.extras as PlasmaExtras
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.volume import org.kde.plasma.private.volume
import "icon.js" as Icon import "icon.js" as Icon
@ -24,6 +25,8 @@ import "icon.js" as Icon
Controls.AbstractButton { Controls.AbstractButton {
id: baseItem id: baseItem
hoverEnabled: true
property string label property string label
property alias listIcon: clientIcon.source property alias listIcon: clientIcon.source
property string type // sink, source, source-output property string type // sink, source, source-output
@ -46,9 +49,15 @@ Controls.AbstractButton {
background: Rectangle { background: Rectangle {
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: (baseItem.down) color: "transparent"
? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.3)
: 'transparent' MobileShell.MotionStateLayer {
anchors.fill: parent
radius: parent.radius
hovered: baseItem.hovered
pressed: baseItem.down
active: baseItem.selected
}
} }
contentItem: RowLayout { contentItem: RowLayout {
@ -193,12 +202,11 @@ Controls.AbstractButton {
SequentialAnimation { SequentialAnimation {
id: seqAnimation id: seqAnimation
NumberAnimation { MobileShell.MotionNumberAnimation {
id: toAnimation id: toAnimation
target: slider target: slider
property: "to" property: "to"
duration: Kirigami.Units.shortDuration type: MobileShell.Motion.EffectsFast
easing.type: Easing.InOutQuad
} }
ScriptAction { ScriptAction {
script: slider.updateVolume() script: slider.updateVolume()

View file

@ -39,6 +39,7 @@ Window {
Kirigami.Theme.inherit: false Kirigami.Theme.inherit: false
color: "transparent" color: "transparent"
readonly property int popupAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow) * 1.25)
function showOverlay() { function showOverlay() {
if (cards.state == "closed") { if (cards.state == "closed") {
@ -116,8 +117,10 @@ Window {
transitions: Transition { transitions: Transition {
SequentialAnimation { SequentialAnimation {
ParallelAnimation { ParallelAnimation {
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "offset"; easing.type: cards.state == "open" ? Easing.OutQuint : Easing.InQuint; duration: Kirigami.Units.veryLongDuration * 1.25 properties: "offset"
type: cards.state == "open" ? MobileShell.Motion.Emphasized : MobileShell.Motion.EmphasizedAccel
duration: window.popupAnimationDuration
} }
} }
ScriptAction { ScriptAction {

View file

@ -35,6 +35,7 @@ Window {
LayerShell.Window.exclusionZone: -1 LayerShell.Window.exclusionZone: -1
readonly property color backgroundColor: Qt.darker(Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.95), 1.05) readonly property color backgroundColor: Qt.darker(Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.95), 1.05)
readonly property int overlayAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow) * 1.25)
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
Kirigami.Theme.inherit: false Kirigami.Theme.inherit: false
@ -83,7 +84,7 @@ Window {
pressDelay: 50 pressDelay: 50
property real offset: -Kirigami.Units.gridUnit property real offset: -Kirigami.Units.gridUnit
property real scale: 0.95 property real cardScale: 0.95
state: "closed" state: "closed"
@ -94,7 +95,7 @@ Window {
target: flickable; offset: 0 target: flickable; offset: 0
} }
PropertyChanges { PropertyChanges {
target: flickable; scale: 1.0 target: flickable; cardScale: 1.0
} }
PropertyChanges { PropertyChanges {
target: flickable; opacity: 1.0 target: flickable; opacity: 1.0
@ -109,7 +110,7 @@ Window {
target: flickable; offset: -Kirigami.Units.gridUnit * 3 target: flickable; offset: -Kirigami.Units.gridUnit * 3
} }
PropertyChanges { PropertyChanges {
target: flickable; scale: 0.95 target: flickable; cardScale: 0.95
} }
PropertyChanges { PropertyChanges {
target: flickable; opacity: 0.0 target: flickable; opacity: 0.0
@ -123,17 +124,17 @@ Window {
transitions: Transition { transitions: Transition {
SequentialAnimation { SequentialAnimation {
ParallelAnimation { ParallelAnimation {
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "offset"; easing.type: Easing.OutQuint; duration: Kirigami.Units.veryLongDuration * 1.25 properties: "offset"; type: MobileShell.Motion.Emphasized; duration: window.overlayAnimationDuration
} }
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "scale"; easing.type: Easing.OutQuint; duration: Kirigami.Units.veryLongDuration * 1.25 properties: "cardScale"; type: MobileShell.Motion.Emphasized; duration: window.overlayAnimationDuration
} }
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "opacity"; easing.type: Easing.OutQuint; duration: Kirigami.Units.veryLongDuration * 1.25 properties: "opacity"; type: MobileShell.Motion.Emphasized; duration: window.overlayAnimationDuration
} }
PropertyAnimation { MobileShell.MotionColorAnimation {
properties: "color"; easing.type: Easing.OutQuint; duration: Kirigami.Units.veryLongDuration * 1.25 properties: "color"; type: MobileShell.Motion.Emphasized; duration: window.overlayAnimationDuration
} }
} }
ScriptAction { ScriptAction {
@ -172,7 +173,7 @@ Window {
Layout.topMargin: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3 Layout.topMargin: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: cards.width Layout.preferredWidth: cards.width
scale: flickable.scale scale: flickable.cardScale
} }
PopupCard { PopupCard {
@ -180,7 +181,7 @@ Window {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: Kirigami.Units.gridUnit Layout.bottomMargin: Kirigami.Units.gridUnit
scaleFactor: flickable.scale scaleFactor: flickable.cardScale
contentItem: PlasmaComponents.ToolButton { contentItem: PlasmaComponents.ToolButton {
id: audioSettingsButton id: audioSettingsButton

View file

@ -12,6 +12,7 @@ import org.kde.kquickcontrolsaddons
import org.kde.plasma.components as PC3 import org.kde.plasma.components as PC3
import org.kde.ksvg as KSvg import org.kde.ksvg as KSvg
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.volume import org.kde.plasma.private.volume
// Audio volume slider. Value represents desired volume level in // Audio volume slider. Value represents desired volume level in
@ -21,6 +22,7 @@ PC3.Slider {
id: control id: control
property VolumeObject volumeObject property VolumeObject volumeObject
readonly property real mutedOpacity: 0.55
// When muted, the whole slider will appear slightly faded, but remain // When muted, the whole slider will appear slightly faded, but remain
// functional and interactive. // functional and interactive.
@ -37,22 +39,20 @@ PC3.Slider {
} }
Behavior on volume { Behavior on volume {
NumberAnimation { MobileShell.MotionNumberAnimation {
id: animate id: animate
duration: Kirigami.Units.shortDuration type: MobileShell.Motion.EffectsFast
easing.type: Easing.OutQuad
} }
} }
// When a maximum volume limit is raised/lower, animate the change. // When a maximum volume limit is raised/lower, animate the change.
Behavior on to { Behavior on to {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.shortDuration type: MobileShell.Motion.EffectsFast
easing.type: Easing.InOutQuad
} }
} }
opacity: muted ? 0.5 : 1 opacity: muted ? mutedOpacity : 1
// Prevents the groove from showing through the handle // Prevents the groove from showing through the handle
layer.enabled: opacity < 1 layer.enabled: opacity < 1

View file

@ -37,7 +37,7 @@ Item {
property color backgroundColor: "transparent" property color backgroundColor: "transparent"
Behavior on backgroundColor { Behavior on backgroundColor {
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast }
} }
/** /**
@ -101,7 +101,7 @@ Item {
opacity: ShellSettings.Settings.convergenceModeEnabled && statusBarHover.hovered ? 1 : 0 opacity: ShellSettings.Settings.convergenceModeEnabled && statusBarHover.hovered ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast }
} }
} }
@ -240,7 +240,7 @@ Item {
opacity: ShellSettings.Settings.convergenceModeEnabled ? (statusBarHover.hovered ? 0.6 : 0.2) : 0 opacity: ShellSettings.Settings.convergenceModeEnabled ? (statusBarHover.hovered ? 0.6 : 0.2) : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast }
} }
} }
} }

View file

@ -7,20 +7,22 @@
import QtQuick import QtQuick
import QtQuick.Controls as Controls import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
Item { Item {
id: taskIcon id: taskIcon
width: parent.height width: parent.height
height: width height: width
readonly property int opacityAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
// Hide ApplicationStatus and Passive items // Hide ApplicationStatus and Passive items
opacity: (model.category !== "ApplicationStatus" && model.status !== "Passive") ? 1 : 0 opacity: (model.category !== "ApplicationStatus" && model.status !== "Passive") ? 1 : 0
onOpacityChanged: visible = opacity onOpacityChanged: visible = opacity
Behavior on opacity { Behavior on opacity {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.longDuration type: MobileShell.Motion.EffectsDefault
easing.type: Easing.InOutQuad duration: taskIcon.opacityAnimationDuration
} }
} }

View file

@ -17,9 +17,18 @@ import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.milou as Milou import org.kde.milou as Milou
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
MouseArea { MouseArea {
id: root id: root
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
readonly property color fieldColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
readonly property color fieldActiveColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.20)
readonly property color resultHoverColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.16)
readonly property color resultPressedColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.28)
onClicked: root.requestedClose(false) onClicked: root.requestedClose(false)
function requestFocus() { function requestFocus() {
@ -54,9 +63,9 @@ MouseArea {
background: Rectangle { background: Rectangle {
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: Qt.rgba(255, 255, 255, (queryField.hovered || queryField.focus) ? 0.2 : 0.1) color: (queryField.hovered || queryField.focus) ? root.fieldActiveColor : root.fieldColor
Behavior on color { ColorAnimation {} } Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast } }
} }
Kirigami.Theme.inherit: false Kirigami.Theme.inherit: false
@ -66,8 +75,8 @@ MouseArea {
bottomPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing bottomPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
placeholderText: i18nc("@info:placeholder", "Search…") placeholderText: i18nc("@info:placeholder", "Search…")
placeholderTextColor: Qt.rgba(255, 255, 255, 0.8) placeholderTextColor: Kirigami.Theme.disabledTextColor
color: 'white' color: Kirigami.Theme.textColor
inputMethodHints: Qt.ImhNoPredictiveText // don't need to press "enter" to update text inputMethodHints: Qt.ImhNoPredictiveText // don't need to press "enter" to update text
font.weight: Font.Bold font.weight: Font.Bold
@ -133,7 +142,7 @@ MouseArea {
type: Kirigami.Heading.Primary type: Kirigami.Heading.Primary
text: sectionHeader.section text: sectionHeader.section
elide: Text.ElideRight elide: Text.ElideRight
color: 'white' color: Kirigami.Theme.textColor
// we override the Primary type's font weight (DemiBold) for Bold for contrast with small text // we override the Primary type's font weight (DemiBold) for Bold for contrast with small text
font.weight: Font.Bold font.weight: Font.Bold
@ -176,7 +185,7 @@ MouseArea {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: delegate.pressed ? Qt.rgba(255, 255, 255, 0.3) : (delegate.containsMouse ? Qt.rgba(255, 255, 255, 0.1) : "transparent") color: delegate.pressed ? root.resultPressedColor : (delegate.containsMouse ? root.resultHoverColor : "transparent")
} }
RowLayout { RowLayout {
@ -211,7 +220,7 @@ MouseArea {
maximumLineCount: 1 maximumLineCount: 1
elide: Text.ElideRight elide: Text.ElideRight
text: typeof modelData !== "undefined" ? modelData : model.display text: typeof modelData !== "undefined" ? modelData : model.display
color: "white" color: Kirigami.Theme.textColor
font.pointSize: Kirigami.Theme.defaultFont.pointSize font.pointSize: Kirigami.Theme.defaultFont.pointSize
} }
@ -224,7 +233,7 @@ MouseArea {
maximumLineCount: 1 maximumLineCount: 1
elide: Text.ElideRight elide: Text.ElideRight
text: model.subtext || "" text: model.subtext || ""
color: "white" color: Kirigami.Theme.textColor
opacity: 0.8 opacity: 0.8
font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 0.8) font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 0.8)

View file

@ -32,9 +32,9 @@ Item {
implicitHeight: visible ? padding * 2 + contentHeight : 0 implicitHeight: visible ? padding * 2 + contentHeight : 0
Behavior on implicitHeight { Behavior on implicitHeight {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: implicitHeight == 0 ? 0 : Kirigami.Units.longDuration type: MobileShell.Motion.StandardDecel
easing.type: Easing.OutQuart duration: implicitHeight == 0 ? 0 : MobileShell.Motion.duration(type)
} }
} }

View file

@ -68,6 +68,8 @@ Item {
* The current drag offset for this notification. * The current drag offset for this notification.
*/ */
property real dragOffset: 0 property real dragOffset: 0
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Standard)
readonly property int veryLongAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow)
signal tapped() signal tapped()
signal dismissRequested() signal dismissRequested()
@ -84,10 +86,10 @@ Item {
implicitHeight: contentParent.implicitHeight implicitHeight: contentParent.implicitHeight
NumberAnimation on dragOffset { MobileShell.MotionNumberAnimation on dragOffset {
id: dragAnim id: dragAnim
duration: Kirigami.Units.longDuration type: MobileShell.Motion.StandardDecel
easing.type: Easing.OutCubic duration: root.longAnimationDuration
onFinished: { onFinished: {
if (to !== 0) { if (to !== 0) {
root.dismissRequested(); root.dismissRequested();
@ -112,9 +114,9 @@ Item {
implicitHeight: inPopupDrawer ? currentPopupHeight : contentParent.implicitHeight implicitHeight: inPopupDrawer ? currentPopupHeight : contentParent.implicitHeight
Behavior on implicitHeight { Behavior on implicitHeight {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.veryLongDuration duration: root.veryLongAnimationDuration
easing.type: Easing.OutExpo type: MobileShell.Motion.SpatialSlow
} }
} }
@ -129,9 +131,9 @@ Item {
opacity: closeTimerRunning ? 1 : 0 opacity: closeTimerRunning ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.OutQuad type: MobileShell.Motion.StandardDecel
} }
} }

View file

@ -10,12 +10,14 @@ import QtQuick.Layouts 1.1
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.private.mobileshell as MobileShell
Item { Item {
id: actionContainer id: actionContainer
required property BaseNotificationItem notification required property BaseNotificationItem notification
property bool popupNotification: false property bool popupNotification: false
readonly property int transitionDuration: MobileShell.Motion.duration(MobileShell.Motion.Standard)
implicitHeight: Math.max(actionFlow.implicitHeight, replyLoader.height) implicitHeight: Math.max(actionFlow.implicitHeight, replyLoader.height)
visible: actionRepeater.count > 0 visible: actionRepeater.count > 0
@ -31,9 +33,9 @@ Item {
opacity: replyLoader.active ? 0 : 1 opacity: replyLoader.active ? 0 : 1
Behavior on opacity { Behavior on opacity {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.longDuration duration: actionContainer.transitionDuration
easing.type: Easing.InOutQuad type: MobileShell.Motion.Standard
} }
} }
@ -94,15 +96,15 @@ Item {
property bool replying: false property bool replying: false
Behavior on x { Behavior on x {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.longDuration duration: actionContainer.transitionDuration
easing.type: Easing.InOutQuad type: MobileShell.Motion.Standard
} }
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.longDuration duration: actionContainer.transitionDuration
easing.type: Easing.InOutQuad type: MobileShell.Motion.Standard
} }
} }

View file

@ -31,6 +31,7 @@ BaseNotificationItem {
property bool inLockScreen: false property bool inLockScreen: false
property int panelType: MobileShell.PanelBackground.PanelType.Drawer property int panelType: MobileShell.PanelBackground.PanelType.Drawer
readonly property int popupFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow)
signal dragStart() signal dragStart()
signal dragEnd() signal dragEnd()
@ -69,9 +70,9 @@ BaseNotificationItem {
opacity: notificationItem.inPopupDrawer ? 0 : 1 opacity: notificationItem.inPopupDrawer ? 0 : 1
Behavior on opacity { Behavior on opacity {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.veryLongDuration duration: notificationItem.popupFadeDuration
easing.type: Easing.OutExpo type: MobileShell.Motion.SpatialSlow
} }
} }

View file

@ -14,7 +14,6 @@ import org.kde.kirigami as Kirigami
import org.kde.plasma.clock import org.kde.plasma.clock
import org.kde.plasma.private.mobileshell as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.plasma.private.mobileshell.state as MobileShellState import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.components 3.0 as PlasmaComponents3
@ -190,7 +189,7 @@ Item {
property NotificationItem pendingNotificationWithAction: null property NotificationItem pendingNotificationWithAction: null
readonly property int animationDuration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.longDuration : 0 readonly property int animationDuration: MobileShell.Motion.duration(MobileShell.Motion.Standard)
// If a screen overflow occurs, fix height in order to maintain tool buttons in place. // If a screen overflow occurs, fix height in order to maintain tool buttons in place.
readonly property bool listOverflowing: listHeight + spacing >= root.height readonly property bool listOverflowing: listHeight + spacing >= root.height
@ -271,11 +270,11 @@ Item {
// Run every time an item is visually added to the list, thus when `Show n more` button is clicked as well. // Run every time an item is visually added to the list, thus when `Show n more` button is clicked as well.
add: Transition { add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: list.animationDuration } MobileShell.MotionNumberAnimation { property: "opacity"; from: 0; to: 1; duration: list.animationDuration; type: MobileShell.Motion.Standard }
} }
// Run every time an item is displaced, such as when the order is scrambled due to a group expansion. // Run every time an item is displaced, such as when the order is scrambled due to a group expansion.
displaced: Transition { displaced: Transition {
NumberAnimation { properties: "y"; duration: list.animationDuration } MobileShell.MotionNumberAnimation { properties: "y"; duration: list.animationDuration; type: MobileShell.Motion.Standard }
} }
function isRowExpanded(row) { function isRowExpanded(row) {
@ -325,7 +324,7 @@ Item {
// We have to do this here in order to control the animation before the item is completely removed // We have to do this here in order to control the animation before the item is completely removed
ListView.onRemove: SequentialAnimation { ListView.onRemove: SequentialAnimation {
PropertyAction { target: delegateLoader; property: "ListView.delayRemove"; value: true } PropertyAction { target: delegateLoader; property: "ListView.delayRemove"; value: true }
NumberAnimation { target: delegateLoader; property: "opacity"; to: 0.0; duration: list.animationDuration } MobileShell.MotionNumberAnimation { target: delegateLoader; property: "opacity"; to: 0.0; duration: list.animationDuration; type: MobileShell.Motion.Standard }
PropertyAction { target: delegateLoader; property: "ListView.delayRemove"; value: false } PropertyAction { target: delegateLoader; property: "ListView.delayRemove"; value: false }
} }
@ -420,7 +419,7 @@ Item {
to: "VISIBLE" to: "VISIBLE"
SequentialAnimation { SequentialAnimation {
PauseAnimation { duration: list.animationDuration * 2 } PauseAnimation { duration: list.animationDuration * 2 }
NumberAnimation { properties: "opacity"; duration: list.animationDuration } MobileShell.MotionNumberAnimation { properties: "opacity"; duration: list.animationDuration; type: MobileShell.Motion.Standard }
} }
} }

View file

@ -48,6 +48,7 @@ MobileShellSettings::MobileShellSettings(QObject *parent)
Q_EMIT gamingDismissHintEnabledChanged(); Q_EMIT gamingDismissHintEnabledChanged();
Q_EMIT dynamicTilingEnabledChanged(); Q_EMIT dynamicTilingEnabledChanged();
Q_EMIT dynamicTilingWindowRequestChanged(); Q_EMIT dynamicTilingWindowRequestChanged();
Q_EMIT dynamicTilingWindowStateChanged();
Q_EMIT snapLayoutsEnabledChanged(); Q_EMIT snapLayoutsEnabledChanged();
Q_EMIT allowLogoutChanged(); Q_EMIT allowLogoutChanged();
} }
@ -326,6 +327,50 @@ void MobileShellSettings::requestDynamicTilingWindowAction(const QString &window
Q_EMIT dynamicTilingWindowRequestChanged(); Q_EMIT dynamicTilingWindowRequestChanged();
} }
QStringList MobileShellSettings::dynamicTilingMaximizedWindowIds() const
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
return group.readEntry("dynamicTilingMaximizedWindowIds", QStringList{});
}
int MobileShellSettings::dynamicTilingWindowStateSerial() const
{
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
return group.readEntry("dynamicTilingWindowStateSerial", 0);
}
bool MobileShellSettings::isDynamicTilingWindowMaximized(const QString &windowId) const
{
if (windowId.isEmpty()) {
return false;
}
return dynamicTilingMaximizedWindowIds().contains(windowId);
}
void MobileShellSettings::reportDynamicTilingWindowState(const QStringList &maximizedWindowIds)
{
QStringList normalizedIds;
for (const QString &windowId : maximizedWindowIds) {
if (!windowId.isEmpty() && !normalizedIds.contains(windowId)) {
normalizedIds.push_back(windowId);
}
}
normalizedIds.sort(Qt::CaseSensitive);
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
if (group.readEntry("dynamicTilingMaximizedWindowIds", QStringList{}) == normalizedIds) {
return;
}
const int serial = group.readEntry("dynamicTilingWindowStateSerial", 0) + 1;
group.writeEntry("dynamicTilingMaximizedWindowIds", normalizedIds, KConfigGroup::Notify);
group.writeEntry("dynamicTilingWindowStateSerial", serial, KConfigGroup::Notify);
m_config->sync();
Q_EMIT dynamicTilingWindowStateChanged();
}
bool MobileShellSettings::snapLayoutsEnabled() const bool MobileShellSettings::snapLayoutsEnabled() const
{ {
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP}; auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};

View file

@ -11,6 +11,7 @@
#include <KSharedConfig> #include <KSharedConfig>
#include <QDBusConnection> #include <QDBusConnection>
#include <QObject> #include <QObject>
#include <QStringList>
#include <qqmlregistration.h> #include <qqmlregistration.h>
/** /**
@ -62,6 +63,8 @@ class MobileShellSettings : public QObject
Q_PROPERTY(QString dynamicTilingWindowRequestAction READ dynamicTilingWindowRequestAction NOTIFY dynamicTilingWindowRequestChanged) Q_PROPERTY(QString dynamicTilingWindowRequestAction READ dynamicTilingWindowRequestAction NOTIFY dynamicTilingWindowRequestChanged)
Q_PROPERTY(QString dynamicTilingWindowRequestId READ dynamicTilingWindowRequestId NOTIFY dynamicTilingWindowRequestChanged) Q_PROPERTY(QString dynamicTilingWindowRequestId READ dynamicTilingWindowRequestId NOTIFY dynamicTilingWindowRequestChanged)
Q_PROPERTY(int dynamicTilingWindowRequestSerial READ dynamicTilingWindowRequestSerial NOTIFY dynamicTilingWindowRequestChanged) Q_PROPERTY(int dynamicTilingWindowRequestSerial READ dynamicTilingWindowRequestSerial NOTIFY dynamicTilingWindowRequestChanged)
Q_PROPERTY(QStringList dynamicTilingMaximizedWindowIds READ dynamicTilingMaximizedWindowIds NOTIFY dynamicTilingWindowStateChanged)
Q_PROPERTY(int dynamicTilingWindowStateSerial READ dynamicTilingWindowStateSerial NOTIFY dynamicTilingWindowStateChanged)
// Snap layout picker — only meaningful in convergence mode when dynamic tiling is off. // Snap layout picker — only meaningful in convergence mode when dynamic tiling is off.
Q_PROPERTY(bool snapLayoutsEnabled READ snapLayoutsEnabled WRITE setSnapLayoutsEnabled NOTIFY snapLayoutsEnabledChanged) Q_PROPERTY(bool snapLayoutsEnabled READ snapLayoutsEnabled WRITE setSnapLayoutsEnabled NOTIFY snapLayoutsEnabledChanged)
@ -295,6 +298,10 @@ public:
QString dynamicTilingWindowRequestId() const; QString dynamicTilingWindowRequestId() const;
int dynamicTilingWindowRequestSerial() const; int dynamicTilingWindowRequestSerial() const;
Q_INVOKABLE void requestDynamicTilingWindowAction(const QString &windowId, const QString &action); Q_INVOKABLE void requestDynamicTilingWindowAction(const QString &windowId, const QString &action);
QStringList dynamicTilingMaximizedWindowIds() const;
int dynamicTilingWindowStateSerial() const;
Q_INVOKABLE bool isDynamicTilingWindowMaximized(const QString &windowId) const;
Q_INVOKABLE void reportDynamicTilingWindowState(const QStringList &maximizedWindowIds);
/** /**
* Whether the SHIFT snap layout picker is enabled. * Whether the SHIFT snap layout picker is enabled.
@ -354,6 +361,7 @@ Q_SIGNALS:
void gamingDismissHintEnabledChanged(); void gamingDismissHintEnabledChanged();
void dynamicTilingEnabledChanged(); void dynamicTilingEnabledChanged();
void dynamicTilingWindowRequestChanged(); void dynamicTilingWindowRequestChanged();
void dynamicTilingWindowStateChanged();
void snapLayoutsEnabledChanged(); void snapLayoutsEnabledChanged();
void allowLogoutChanged(); void allowLogoutChanged();
void lockscreenLeftButtonActionChanged(); void lockscreenLeftButtonActionChanged();

View file

@ -31,7 +31,9 @@ ApplicationListModel::ApplicationListModel(HomeScreen *parent)
m_reloadAppsTimer->setInterval(100ms); m_reloadAppsTimer->setInterval(100ms);
connect(m_reloadAppsTimer, &QTimer::timeout, this, &ApplicationListModel::sycocaDbChanged); connect(m_reloadAppsTimer, &QTimer::timeout, this, &ApplicationListModel::sycocaDbChanged);
connect(KSycoca::self(), &KSycoca::databaseChanged, m_reloadAppsTimer, static_cast<void (QTimer::*)()>(&QTimer::start)); if (!qEnvironmentVariableIsSet("SHIFT_PREVIEW_DISABLE_SYCOCA_WATCH")) {
connect(KSycoca::self(), &KSycoca::databaseChanged, m_reloadAppsTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
}
// initialize wayland window checking // initialize wayland window checking
KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(this); KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(this);

View file

@ -32,6 +32,7 @@ MobileShell.GridView {
property real headerHeight property real headerHeight
readonly property int reservedSpaceForLabel: folio.HomeScreenState.pageDelegateLabelHeight readonly property int reservedSpaceForLabel: folio.HomeScreenState.pageDelegateLabelHeight
readonly property int scrollBarAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialExtended)
readonly property real effectiveContentWidth: width - leftMargin - rightMargin readonly property real effectiveContentWidth: width - leftMargin - rightMargin
readonly property real horizontalMargin: Math.round(width * 0.05) readonly property real horizontalMargin: Math.round(width * 0.05)
@ -139,8 +140,8 @@ MobileShell.GridView {
Behavior on opacity { Behavior on opacity {
OpacityAnimator { OpacityAnimator {
duration: Kirigami.Units.longDuration * 2 duration: root.scrollBarAnimationDuration
easing.type: Easing.InOutQuad easing.type: MobileShell.Motion.easing(MobileShell.Motion.Standard)
} }
} }

View file

@ -8,6 +8,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.private.mobileshell as MobileShell
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
import './delegate' import './delegate'
@ -64,7 +65,7 @@ Item {
Kirigami.Theme.textColor.b, Kirigami.Theme.textColor.b,
(searchField.hovered || searchField.focus) ? 0.2 : 0.1) (searchField.hovered || searchField.focus) ? 0.2 : 0.1)
Behavior on color { ColorAnimation {} } Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast } }
} }
topPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing topPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing

View file

@ -22,6 +22,7 @@ Item {
height: folio.HomeScreenState.pageCellHeight height: folio.HomeScreenState.pageCellHeight
readonly property real dropAnimationRunning: dragXAnim.running || dragYAnim.running readonly property real dropAnimationRunning: dragXAnim.running || dragYAnim.running
readonly property int dropAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
// ignore widget dragging, that is not handled by this component // ignore widget dragging, that is not handled by this component
readonly property bool isWidgetDrag: folio.HomeScreenState.dragState.dropDelegate && folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Widget readonly property bool isWidgetDrag: folio.HomeScreenState.dragState.dropDelegate && folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Widget
@ -38,11 +39,11 @@ Item {
} }
// animate drop x // animate drop x
NumberAnimation on x { MobileShell.MotionNumberAnimation on x {
id: dragXAnim id: dragXAnim
type: MobileShell.Motion.EffectsDefault
running: false running: false
duration: Kirigami.Units.longDuration duration: root.dropAnimationDuration
easing.type: Easing.OutCubic
onFinished: { onFinished: {
root.visible = false; root.visible = false;
root.setXBinding(); root.setXBinding();
@ -50,11 +51,11 @@ Item {
} }
// animate drop y // animate drop y
NumberAnimation on y { MobileShell.MotionNumberAnimation on y {
id: dragYAnim id: dragYAnim
type: MobileShell.Motion.EffectsDefault
running: false running: false
duration: Kirigami.Units.longDuration duration: root.dropAnimationDuration
easing.type: Easing.OutCubic
onFinished: { onFinished: {
root.visible = false; root.visible = false;
root.setYBinding(); root.setYBinding();
@ -66,8 +67,8 @@ Item {
id: scaleAnim id: scaleAnim
to: 0 to: 0
running: false running: false
duration: Kirigami.Units.longDuration duration: root.dropAnimationDuration
easing.type: Easing.InOutCubic easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
} }
Connections { Connections {

View file

@ -35,20 +35,22 @@ MouseArea {
readonly property bool convergenceMode: ShellSettings.Settings.convergenceModeEnabled readonly property bool convergenceMode: ShellSettings.Settings.convergenceModeEnabled
readonly property bool showRunningTasks: convergenceMode && !suppressRunningTasks readonly property bool showRunningTasks: convergenceMode && !suppressRunningTasks
readonly property int totalItemCount: repeater.count + (showRunningTasks ? taskRepeater.count : 0) readonly property int totalItemCount: repeater.count + (showRunningTasks ? taskRepeater.count : 0)
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
// In convergence mode, size icons to fit the dock bar instead of using page grid cells // In convergence mode, size icons to fit the dock bar instead of using page grid cells
property real dockCellWidth: convergenceMode ? root.height : folio.HomeScreenState.pageCellWidth property real dockCellWidth: convergenceMode ? root.height : folio.HomeScreenState.pageCellWidth
property real dockCellHeight: convergenceMode ? root.height : folio.HomeScreenState.pageCellHeight property real dockCellHeight: convergenceMode ? root.height : folio.HomeScreenState.pageCellHeight
Behavior on dockCellWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on dockCellWidth { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
Behavior on dockCellHeight { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on dockCellHeight { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
// Navigation buttons width (used to offset center positioning) // Navigation buttons width (used to offset center positioning)
property real navButtonWidth: convergenceMode ? root.height : 0 property real navButtonWidth: convergenceMode ? root.height : 0
property real dockItemInset: convergenceMode ? Math.max(2, Kirigami.Units.smallSpacing / 2) : 0 property real dockItemInset: convergenceMode ? Math.max(2, Kirigami.Units.smallSpacing / 2) : 0
property real dockIconSize: Math.min(root.height * 0.56, Kirigami.Units.iconSizes.large) property real dockIconSize: Math.min(root.height * 0.56, Kirigami.Units.iconSizes.large)
Behavior on navButtonWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on navButtonWidth { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
Behavior on dockItemInset { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on dockItemInset { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
Behavior on dockIconSize { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on dockIconSize { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
function dockItemColor(pressed, hovered, active) { function dockItemColor(pressed, hovered, active) {
if (pressed) { if (pressed) {
@ -67,7 +69,7 @@ MouseArea {
readonly property bool showSpacer: showRunningTasks && repeater.count > 0 && taskRepeater.count > 0 readonly property bool showSpacer: showRunningTasks && repeater.count > 0 && taskRepeater.count > 0
property real spacerWidth: showSpacer ? Kirigami.Units.largeSpacing * 2 : 0 property real spacerWidth: showSpacer ? Kirigami.Units.largeSpacing * 2 : 0
Behavior on spacerWidth { Behavior on spacerWidth {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration }
} }
// Thumbnail popup hover tracking // Thumbnail popup hover tracking
@ -102,10 +104,10 @@ MouseArea {
readonly property real dockCenterX: convergenceMode readonly property real dockCenterX: convergenceMode
? leftControlsWidth + (root.width - leftControlsWidth - rightControlsWidth) / 2 ? leftControlsWidth + (root.width - leftControlsWidth - rightControlsWidth) / 2
: root.width / 2 : root.width / 2
Behavior on pagerButtonWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on pagerButtonWidth { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
Behavior on desktopButtonWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on desktopButtonWidth { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
Behavior on trashButtonWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on trashButtonWidth { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
Behavior on searchButtonWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } Behavior on searchButtonWidth { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
property Item pendingDockToolTipItem: null property Item pendingDockToolTipItem: null
property Item activeDockToolTipItem: null property Item activeDockToolTipItem: null
@ -177,6 +179,27 @@ MouseArea {
return result return result
} }
function desktopIndexForId(desktopId) {
let ids = virtualDesktopInfo.desktopIds
if (!ids) {
return -1
}
for (let i = 0; i < ids.length; ++i) {
if (String(ids[i]) === String(desktopId)) {
return i
}
}
return -1
}
function dynamicTilingMoveToDesktopAction(desktopId) {
let index = root.desktopIndexForId(desktopId)
if (index < 0) {
return ""
}
return "move-to-desktop:" + String(desktopId) + "|" + String(index + 1)
}
function taskActivities(taskModel) { function taskActivities(taskModel) {
let activities = taskModel.Activities let activities = taskModel.Activities
return activities ? activities : [] return activities ? activities : []
@ -294,7 +317,7 @@ MouseArea {
color: "transparent" color: "transparent"
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
Accessible.role: Accessible.Button Accessible.role: Accessible.Button
@ -313,15 +336,13 @@ MouseArea {
visible: homeButton.activeFocus visible: homeButton.activeFocus
} }
Rectangle { MobileShell.MotionStateLayer {
anchors.fill: parent anchors.fill: parent
anchors.margins: root.dockItemInset anchors.margins: root.dockItemInset
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: root.dockItemColor(homeMouseArea.containsPress, homeMouseArea.containsMouse, false) hovered: homeMouseArea.containsMouse
pressed: homeMouseArea.containsPress
Behavior on color { pressedOpacity: 0.18
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic }
}
} }
Kirigami.Icon { Kirigami.Icon {
@ -361,7 +382,7 @@ MouseArea {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
Accessible.role: Accessible.Button Accessible.role: Accessible.Button
@ -385,15 +406,14 @@ MouseArea {
visible: desktopButton.activeFocus visible: desktopButton.activeFocus
} }
Rectangle { MobileShell.MotionStateLayer {
anchors.fill: parent anchors.fill: parent
anchors.margins: root.dockItemInset anchors.margins: root.dockItemInset
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: root.dockItemColor(desktopMouseArea.containsPress, desktopMouseArea.containsMouse, WindowPlugin.WindowUtil.isShowingDesktop) hovered: desktopMouseArea.containsMouse
pressed: desktopMouseArea.containsPress
Behavior on color { active: WindowPlugin.WindowUtil.isShowingDesktop
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } pressedOpacity: 0.18
}
} }
Kirigami.Icon { Kirigami.Icon {
@ -476,7 +496,7 @@ MouseArea {
color: "transparent" color: "transparent"
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
Accessible.role: Accessible.Button Accessible.role: Accessible.Button
@ -495,15 +515,13 @@ MouseArea {
visible: overviewButton.activeFocus visible: overviewButton.activeFocus
} }
Rectangle { MobileShell.MotionStateLayer {
anchors.fill: parent anchors.fill: parent
anchors.margins: root.dockItemInset anchors.margins: root.dockItemInset
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: root.dockItemColor(overviewMouseArea.containsPress, overviewMouseArea.containsMouse, false) hovered: overviewMouseArea.containsMouse
pressed: overviewMouseArea.containsPress
Behavior on color { pressedOpacity: 0.18
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic }
}
} }
Kirigami.Icon { Kirigami.Icon {
@ -539,7 +557,7 @@ MouseArea {
color: "transparent" color: "transparent"
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
Accessible.role: Accessible.Button Accessible.role: Accessible.Button
@ -563,15 +581,13 @@ MouseArea {
visible: searchButton.activeFocus visible: searchButton.activeFocus
} }
Rectangle { MobileShell.MotionStateLayer {
anchors.fill: parent anchors.fill: parent
anchors.margins: root.dockItemInset anchors.margins: root.dockItemInset
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: root.dockItemColor(searchMouseArea.containsPress, searchMouseArea.containsMouse, false) hovered: searchMouseArea.containsMouse
pressed: searchMouseArea.containsPress
Behavior on color { pressedOpacity: 0.18
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic }
}
} }
Kirigami.Icon { Kirigami.Icon {
@ -638,15 +654,16 @@ MouseArea {
width: root.pagerButtonWidth width: root.pagerButtonWidth
height: root.height height: root.height
Rectangle { MobileShell.MotionStateLayer {
anchors.fill: parent anchors.fill: parent
anchors.margins: root.dockItemInset anchors.margins: root.dockItemInset
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: leftDesktopBtn.isCurrent || leftDesktopBtn.isDragTarget hovered: leftPagerHover.containsMouse
? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, pressed: leftPagerHover.containsPress
leftPagerHover.containsMouse || leftDesktopBtn.isDragTarget ? 0.25 : 0.18) active: leftDesktopBtn.isCurrent || leftDesktopBtn.isDragTarget
: root.dockItemColor(leftPagerHover.containsPress, leftPagerHover.containsMouse, false) pressedOpacity: 0.18
Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration } } activeOpacity: 0.18
activeHoverOpacity: 0.25
} }
PC3.Label { PC3.Label {
@ -746,15 +763,16 @@ MouseArea {
width: root.pagerButtonWidth width: root.pagerButtonWidth
height: root.height height: root.height
Rectangle { MobileShell.MotionStateLayer {
anchors.fill: parent anchors.fill: parent
anchors.margins: root.dockItemInset anchors.margins: root.dockItemInset
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: rightDesktopBtn.isCurrent || rightDesktopBtn.isDragTarget hovered: rightPagerHover.containsMouse
? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, pressed: rightPagerHover.containsPress
rightPagerHover.containsMouse || rightDesktopBtn.isDragTarget ? 0.25 : 0.18) active: rightDesktopBtn.isCurrent || rightDesktopBtn.isDragTarget
: root.dockItemColor(rightPagerHover.containsPress, rightPagerHover.containsMouse, false) pressedOpacity: 0.18
Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration } } activeOpacity: 0.18
activeHoverOpacity: 0.25
} }
PC3.Label { PC3.Label {
@ -875,7 +893,7 @@ MouseArea {
color: "transparent" color: "transparent"
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
Accessible.role: Accessible.Button Accessible.role: Accessible.Button
@ -891,14 +909,13 @@ MouseArea {
visible: trashButton.activeFocus visible: trashButton.activeFocus
} }
Rectangle { MobileShell.MotionStateLayer {
anchors.fill: parent anchors.fill: parent
anchors.margins: root.dockItemInset anchors.margins: root.dockItemInset
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: root.dockItemColor(trashMouseArea.containsPress, trashMouseArea.containsMouse, false) hovered: trashMouseArea.containsMouse
Behavior on color { pressed: trashMouseArea.containsPress
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } pressedOpacity: 0.18
}
} }
Kirigami.Icon { Kirigami.Icon {
@ -1049,7 +1066,7 @@ MouseArea {
// get the normalized index position value from the center so we can animate it // get the normalized index position value from the center so we can animate it
property double fromCenterValue: model.index - (root.totalItemCount / 2) property double fromCenterValue: model.index - (root.totalItemCount / 2)
Behavior on fromCenterValue { Behavior on fromCenterValue {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad; } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration }
} }
// multiply the 'fromCenterValue' by the cell size to get the actual position // multiply the 'fromCenterValue' by the cell size to get the actual position
@ -1070,7 +1087,7 @@ MouseArea {
} }
Behavior on dragVisualShift { Behavior on dragVisualShift {
enabled: root.dragReorderIndex !== -1 && delegate.index !== root.dragReorderIndex enabled: root.dragReorderIndex !== -1 && delegate.index !== root.dragReorderIndex
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration }
} }
property real taskPinVisualShift: root.taskPinCanDrop && delegate.index >= root.taskPinTargetIndex ? root.dockCellWidth : 0 property real taskPinVisualShift: root.taskPinCanDrop && delegate.index >= root.taskPinTargetIndex ? root.dockCellWidth : 0
@ -1426,10 +1443,10 @@ MouseArea {
visible: showing || fadeAnim.running visible: showing || fadeAnim.running
opacity: showing ? 1 : 0 opacity: showing ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { MobileShell.MotionNumberAnimation {
id: fadeAnim id: fadeAnim
duration: Kirigami.Units.shortDuration type: MobileShell.Motion.EffectsFast
easing.type: Easing.InOutQuad duration: root.shortAnimationDuration
} }
} }
@ -1674,8 +1691,15 @@ MouseArea {
readonly property bool dynamicTilingActive: root.convergenceMode && ShellSettings.Settings.dynamicTilingEnabled readonly property bool dynamicTilingActive: root.convergenceMode && ShellSettings.Settings.dynamicTilingEnabled
readonly property bool showFreeGeometryActions: !taskDelegate.isGroupParent && !taskDelegate.dynamicTilingActive readonly property bool showFreeGeometryActions: !taskDelegate.isGroupParent && !taskDelegate.dynamicTilingActive
readonly property bool canRequestDynamicTiling: taskDelegate.dynamicTilingActive && !taskDelegate.isGroupParent && root.taskWindowId(taskDelegate.model) !== "" readonly property bool canRequestDynamicTiling: taskDelegate.dynamicTilingActive && !taskDelegate.isGroupParent && root.taskWindowId(taskDelegate.model) !== ""
readonly property int dynamicTilingWindowStateSerial: ShellSettings.Settings.dynamicTilingWindowStateSerial
readonly property bool dynamicTilingMaximized: taskDelegate.canRequestDynamicTiling
&& taskDelegate.dynamicTilingWindowStateSerial >= 0
&& ShellSettings.Settings.isDynamicTilingWindowMaximized(root.taskWindowId(taskDelegate.model))
readonly property bool canChangeVirtualDesktops: taskDelegate.model.IsVirtualDesktopsChangeable === true readonly property bool canChangeVirtualDesktops: taskDelegate.model.IsVirtualDesktopsChangeable === true
readonly property bool canChangeActivities: activityInfo.numberOfRunningActivities > 1 && !taskDelegate.isGroupParent readonly property bool canChangeActivities: activityInfo.numberOfRunningActivities > 1 && !taskDelegate.isGroupParent
readonly property bool dynamicTilingAllActivities: taskDelegate.canRequestDynamicTiling && root.taskActivities(taskDelegate.model).length === 0
readonly property bool canShowActivityScopeAction: taskDelegate.canChangeActivities && (!taskDelegate.canRequestDynamicTiling || taskDelegate.dynamicTilingAllActivities)
readonly property bool canShowActivityMoveActions: taskDelegate.canChangeActivities && !taskDelegate.canRequestDynamicTiling
Accessible.role: Accessible.Button Accessible.role: Accessible.Button
Accessible.name: taskDelegate.model.display || "" Accessible.name: taskDelegate.model.display || ""
@ -1699,6 +1723,25 @@ MouseArea {
} }
} }
function requestMoveToDesktop(desktopId) {
if (taskDelegate.canRequestDynamicTiling) {
let action = root.dynamicTilingMoveToDesktopAction(desktopId)
if (action !== "") {
ShellSettings.Settings.requestDynamicTilingWindowAction(root.taskWindowId(taskDelegate.model), action)
return
}
}
tasksModel.requestVirtualDesktops(tasksModel.makeModelIndex(taskDelegate.index), [desktopId])
}
function requestMoveToNewDesktop() {
if (taskDelegate.canRequestDynamicTiling) {
ShellSettings.Settings.requestDynamicTilingWindowAction(root.taskWindowId(taskDelegate.model), "move-to-new-desktop")
return
}
tasksModel.requestNewVirtualDesktop(tasksModel.makeModelIndex(taskDelegate.index))
}
Keys.onReturnPressed: taskDelegate.activateTask() Keys.onReturnPressed: taskDelegate.activateTask()
Keys.onEnterPressed: taskDelegate.activateTask() Keys.onEnterPressed: taskDelegate.activateTask()
Keys.onSpacePressed: taskDelegate.activateTask() Keys.onSpacePressed: taskDelegate.activateTask()
@ -1718,7 +1761,7 @@ MouseArea {
// Position after all favourites // Position after all favourites
property double fromCenterValue: (repeater.count + taskDelegate.index) - (root.totalItemCount / 2) property double fromCenterValue: (repeater.count + taskDelegate.index) - (root.totalItemCount / 2)
Behavior on fromCenterValue { Behavior on fromCenterValue {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad; } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration }
} }
readonly property int centerPosition: (isLocationBottom ? root.dockCellWidth : root.dockCellHeight) * fromCenterValue readonly property int centerPosition: (isLocationBottom ? root.dockCellWidth : root.dockCellHeight) * fromCenterValue
@ -1740,7 +1783,7 @@ MouseArea {
color: root.dockItemColor(taskMouseArea.containsPress, taskMouseArea.containsMouse, taskDelegate.model.IsActive === true) color: root.dockItemColor(taskMouseArea.containsPress, taskMouseArea.containsMouse, taskDelegate.model.IsActive === true)
Behavior on color { Behavior on color {
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
} }
@ -1758,6 +1801,22 @@ MouseArea {
active: taskMouseArea.containsMouse active: taskMouseArea.containsMouse
} }
Rectangle {
visible: opacity > 0
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: Kirigami.Units.smallSpacing
width: Kirigami.Units.smallSpacing * 3
height: Math.max(2, Math.round(Kirigami.Units.devicePixelRatio))
radius: height / 2
color: Kirigami.Theme.highlightColor
opacity: taskDelegate.dynamicTilingMaximized ? 0.95 : 0
Behavior on opacity {
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
}
}
DragHandler { DragHandler {
id: taskDragHandler id: taskDragHandler
target: null target: null
@ -1782,7 +1841,7 @@ MouseArea {
let finalCenterX = root.taskBaseX(taskDelegate.index) + root.dockCellWidth / 2 + root.taskPinDragOffset let finalCenterX = root.taskBaseX(taskDelegate.index) + root.dockCellWidth / 2 + root.taskPinDragOffset
let pagerDesktop = root.pagerButtonDesktopAt(finalCenterX) let pagerDesktop = root.pagerButtonDesktopAt(finalCenterX)
if (pagerDesktop && taskDelegate.model.IsVirtualDesktopsChangeable === true) { if (pagerDesktop && taskDelegate.model.IsVirtualDesktopsChangeable === true) {
tasksModel.requestVirtualDesktops(tasksModel.makeModelIndex(taskDelegate.index), [pagerDesktop]) taskDelegate.requestMoveToDesktop(pagerDesktop)
} else if (root.taskPinCanDrop && !folio.FavouritesModel.containsApplication(root.taskPinStorageId)) { } else if (root.taskPinCanDrop && !folio.FavouritesModel.containsApplication(root.taskPinStorageId)) {
folio.FavouritesModel.addApplicationAt(root.taskPinTargetIndex, root.taskPinStorageId) folio.FavouritesModel.addApplicationAt(root.taskPinTargetIndex, root.taskPinStorageId)
} }
@ -1825,7 +1884,7 @@ MouseArea {
opacity: taskDelegate.model.IsActive === true ? 1.0 : 0.45 opacity: taskDelegate.model.IsActive === true ? 1.0 : 0.45
Behavior on width { Behavior on width {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
} }
} }
@ -1922,6 +1981,15 @@ MouseArea {
onClicked: ShellSettings.Settings.requestDynamicTilingWindowAction(root.taskWindowId(taskDelegate.model), "tile") onClicked: ShellSettings.Settings.requestDynamicTilingWindowAction(root.taskWindowId(taskDelegate.model), "tile")
} }
PC3.MenuItem {
icon.name: taskDelegate.dynamicTilingMaximized ? "window-restore" : "window-maximize"
text: taskDelegate.dynamicTilingMaximized ? i18n("Restore") : i18n("Maximize")
visible: taskDelegate.canRequestDynamicTiling
height: visible ? implicitHeight : 0
enabled: taskDelegate.model.IsMaximizable === true
onClicked: ShellSettings.Settings.requestDynamicTilingWindowAction(root.taskWindowId(taskDelegate.model), "maximize-toggle")
}
PC3.MenuItem { PC3.MenuItem {
icon.name: "transform-move" icon.name: "transform-move"
text: i18n("Move") text: i18n("Move")
@ -1992,10 +2060,18 @@ MouseArea {
PC3.MenuItem { PC3.MenuItem {
icon.name: "virtual-desktops" icon.name: "virtual-desktops"
text: taskDelegate.model.IsOnAllVirtualDesktops ? i18n("Show Only on Current Desktop") : i18n("Show on All Desktops") text: taskDelegate.model.IsOnAllVirtualDesktops ? i18n("Show Only on Current Desktop") : i18n("Show on All Desktops")
visible: taskDelegate.canChangeVirtualDesktops && virtualDesktopInfo.numberOfDesktops > 1 visible: taskDelegate.canChangeVirtualDesktops
&& virtualDesktopInfo.numberOfDesktops > 1
&& (!taskDelegate.dynamicTilingActive || taskDelegate.model.IsOnAllVirtualDesktops === true)
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
onClicked: tasksModel.requestVirtualDesktops(tasksModel.makeModelIndex(taskDelegate.index), onClicked: {
taskDelegate.model.IsOnAllVirtualDesktops ? [virtualDesktopInfo.currentDesktop] : []) if (taskDelegate.dynamicTilingActive && taskDelegate.model.IsOnAllVirtualDesktops === true) {
taskDelegate.requestMoveToDesktop(virtualDesktopInfo.currentDesktop)
return
}
tasksModel.requestVirtualDesktops(tasksModel.makeModelIndex(taskDelegate.index),
taskDelegate.model.IsOnAllVirtualDesktops ? [virtualDesktopInfo.currentDesktop] : [])
}
} }
Instantiator { Instantiator {
@ -2003,8 +2079,7 @@ MouseArea {
delegate: PC3.MenuItem { delegate: PC3.MenuItem {
required property var modelData required property var modelData
text: i18n("Move to %1", root.pagerDesktopNameForId(modelData)) text: i18n("Move to %1", root.pagerDesktopNameForId(modelData))
onTriggered: tasksModel.requestVirtualDesktops( onTriggered: taskDelegate.requestMoveToDesktop(modelData)
tasksModel.makeModelIndex(taskDelegate.index), [modelData])
} }
onObjectAdded: (idx, obj) => taskContextMenu.insertItem(taskContextMenu.count, obj) onObjectAdded: (idx, obj) => taskContextMenu.insertItem(taskContextMenu.count, obj)
onObjectRemoved: (idx, obj) => taskContextMenu.removeItem(obj) onObjectRemoved: (idx, obj) => taskContextMenu.removeItem(obj)
@ -2014,25 +2089,25 @@ MouseArea {
text: i18n("Move to New Desktop") text: i18n("Move to New Desktop")
visible: taskDelegate.canChangeVirtualDesktops visible: taskDelegate.canChangeVirtualDesktops
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
onClicked: tasksModel.requestNewVirtualDesktop(tasksModel.makeModelIndex(taskDelegate.index)) onClicked: taskDelegate.requestMoveToNewDesktop()
} }
Controls.MenuSeparator { Controls.MenuSeparator {
visible: taskDelegate.canChangeActivities visible: taskDelegate.canShowActivityScopeAction || taskDelegate.canShowActivityMoveActions
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
} }
PC3.MenuItem { PC3.MenuItem {
icon.name: "activities" icon.name: "activities"
text: root.taskActivities(taskDelegate.model).length === 0 ? i18n("Show Only on Current Activity") : i18n("Show on All Activities") text: root.taskActivities(taskDelegate.model).length === 0 ? i18n("Show Only on Current Activity") : i18n("Show on All Activities")
visible: taskDelegate.canChangeActivities visible: taskDelegate.canShowActivityScopeAction
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
onClicked: tasksModel.requestActivities(tasksModel.makeModelIndex(taskDelegate.index), onClicked: tasksModel.requestActivities(tasksModel.makeModelIndex(taskDelegate.index),
root.taskActivities(taskDelegate.model).length === 0 ? [activityInfo.currentActivity] : []) root.taskActivities(taskDelegate.model).length === 0 ? [activityInfo.currentActivity] : [])
} }
Instantiator { Instantiator {
model: taskDelegate.canChangeActivities ? root.menuActivityIds(root.taskActivities(taskDelegate.model)) : [] model: taskDelegate.canShowActivityMoveActions ? root.menuActivityIds(root.taskActivities(taskDelegate.model)) : []
delegate: PC3.MenuItem { delegate: PC3.MenuItem {
required property var modelData required property var modelData
icon.name: activityInfo.activityIcon(modelData) icon.name: activityInfo.activityIcon(modelData)

View file

@ -25,6 +25,9 @@ Folio.DelegateTouchArea {
property real folderPositionY property real folderPositionY
property Folio.FolioApplicationFolder folder: folio.HomeScreenState.currentFolder property Folio.FolioApplicationFolder folder: folio.HomeScreenState.currentFolder
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property color folderFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.24)
MobileShell.HapticsEffect { MobileShell.HapticsEffect {
id: haptics id: haptics
@ -83,7 +86,7 @@ Folio.DelegateTouchArea {
opacity: (root.opacity === 1) ? 1 : 0 opacity: (root.opacity === 1) ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
} }
@ -177,7 +180,7 @@ Folio.DelegateTouchArea {
Rectangle { Rectangle {
id: folderBackground id: folderBackground
color: Qt.rgba(255, 255, 255, 0.3) color: root.folderFeedbackColor
radius: Kirigami.Units.gridUnit radius: Kirigami.Units.gridUnit
readonly property int gridLength: folio.HomeScreenState.folderGridLength readonly property int gridLength: folio.HomeScreenState.folderGridLength
@ -282,9 +285,9 @@ Folio.DelegateTouchArea {
property double rowValue: model.rowIndex property double rowValue: model.rowIndex
property double pageValue: model.pageIndex property double pageValue: model.pageIndex
Behavior on columnValue { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } } Behavior on columnValue { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
Behavior on rowValue { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } } Behavior on rowValue { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
Behavior on pageValue { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } } Behavior on pageValue { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: root.longAnimationDuration } }
// multiply the index values by the cell size to get the actual position // multiply the index values by the cell size to get the actual position
readonly property int columnPosition: cellWidth * columnValue readonly property int columnPosition: cellWidth * columnValue

View file

@ -31,6 +31,7 @@ Item {
property real rightMargin: 0 property real rightMargin: 0
property bool interactive: true property bool interactive: true
readonly property color favouritesBarScrimColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.14)
// non-widget drop animation // non-widget drop animation
readonly property bool dropAnimationRunning: delegateDragItem.dropAnimationRunning || widgetDragItem.dropAnimationRunning readonly property bool dropAnimationRunning: delegateDragItem.dropAnimationRunning || widgetDragItem.dropAnimationRunning
@ -350,7 +351,7 @@ Item {
Rectangle { Rectangle {
id: favouritesBarScrim id: favouritesBarScrim
color: Qt.rgba(255, 255, 255, 0.2) color: root.favouritesBarScrimColor
Component.onCompleted: maskManager.assignToMask(this) Component.onCompleted: maskManager.assignToMask(this)

View file

@ -24,6 +24,8 @@ Item {
property var pageModel property var pageModel
property var homeScreen property var homeScreen
readonly property color editFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.24)
readonly property color dropFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.28)
onActiveFocusChanged: { onActiveFocusChanged: {
if (activeFocus) { if (activeFocus) {
@ -107,7 +109,7 @@ Item {
Rectangle { Rectangle {
id: settingsViewBackground id: settingsViewBackground
anchors.fill: parent anchors.fill: parent
color: Qt.rgba(255, 255, 255, 0.2) color: root.editFeedbackColor
opacity: folio.HomeScreenState.settingsOpenProgress opacity: folio.HomeScreenState.settingsOpenProgress
radius: Kirigami.Units.largeSpacing radius: Kirigami.Units.largeSpacing
} }
@ -152,7 +154,7 @@ Item {
pageModel.canAddDelegate(dropPosition.pageRow, dropPosition.pageColumn, dropDelegate) pageModel.canAddDelegate(dropPosition.pageRow, dropPosition.pageColumn, dropDelegate)
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: Qt.rgba(255, 255, 255, 0.3) color: root.dropFeedbackColor
x: dropPosition.pageColumn * folio.HomeScreenState.pageCellWidth x: dropPosition.pageColumn * folio.HomeScreenState.pageCellWidth
y: dropPosition.pageRow * folio.HomeScreenState.pageCellHeight y: dropPosition.pageRow * folio.HomeScreenState.pageCellHeight

View file

@ -12,6 +12,7 @@ import "./delegate"
Item { Item {
id: root id: root
property Folio.HomeScreen folio property Folio.HomeScreen folio
readonly property color placeholderColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.28)
width: folio.HomeScreenState.pageCellWidth width: folio.HomeScreenState.pageCellWidth
height: folio.HomeScreenState.pageCellHeight height: folio.HomeScreenState.pageCellHeight
@ -24,7 +25,7 @@ Item {
// icon position placement // icon position placement
Rectangle { Rectangle {
id: loader id: loader
color: Qt.rgba(255, 255, 255, 0.3) color: root.placeholderColor
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom

View file

@ -6,6 +6,8 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.taskmanager as TaskManager import org.kde.taskmanager as TaskManager
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
@ -16,6 +18,7 @@ Item {
required property var folio required property var folio
readonly property bool hasTasks: allTasksModel.count > 0 readonly property bool hasTasks: allTasksModel.count > 0
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
property bool sortByName: false property bool sortByName: false
property int dragTargetDesktopIndex: -1 property int dragTargetDesktopIndex: -1
property string pendingMoveTaskKey: "" property string pendingMoveTaskKey: ""
@ -44,6 +47,18 @@ Item {
return String(taskModel ? taskModel.AppId || "" : "") + "|" + String(taskModel ? taskModel.display || "" : "") return String(taskModel ? taskModel.AppId || "" : "") + "|" + String(taskModel ? taskModel.display || "" : "")
} }
function taskWindowId(taskModel) {
const winIds = taskModel && taskModel.WinIdList ? taskModel.WinIdList : []
return winIds.length === 1 ? String(winIds[0]) : ""
}
function dynamicTilingMoveToDesktopAction(desktopId, desktopIndex) {
if (String(desktopId).length === 0 || desktopIndex < 0) {
return ""
}
return "move-to-desktop:" + String(desktopId) + "|" + String(desktopIndex + 1)
}
function markTaskMove(taskKey, desktopIndex) { function markTaskMove(taskKey, desktopIndex) {
pendingMoveTaskKey = taskKey pendingMoveTaskKey = taskKey
pendingMoveTargetName = desktopName(desktopIndex) pendingMoveTargetName = desktopName(desktopIndex)
@ -280,10 +295,10 @@ Item {
: root.mixColor(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.14) : root.mixColor(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.14)
Behavior on color { Behavior on color {
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
} }
@ -371,11 +386,18 @@ Item {
readonly property int previewCount: Math.max(1, Math.min(2, winIds.length)) readonly property int previewCount: Math.max(1, Math.min(2, winIds.length))
readonly property bool activeTask: model.IsActive === true readonly property bool activeTask: model.IsActive === true
readonly property bool minimizedTask: model.IsMinimized === true readonly property bool minimizedTask: model.IsMinimized === true
readonly property bool maximizedTask: model.IsMaximized === true
readonly property bool groupTask: model.IsGroupParent === true readonly property bool groupTask: model.IsGroupParent === true
readonly property bool desktopsChangeable: model.IsVirtualDesktopsChangeable === true readonly property bool desktopsChangeable: model.IsVirtualDesktopsChangeable === true
readonly property string storageId: root.taskStorageId(model) readonly property string storageId: root.taskStorageId(model)
readonly property string taskKey: root.taskKey(model) readonly property string taskKey: root.taskKey(model)
readonly property string windowId: root.taskWindowId(model)
readonly property bool dynamicTilingActive: ShellSettings.Settings.convergenceModeEnabled && ShellSettings.Settings.dynamicTilingEnabled
readonly property bool canRequestDynamicTiling: dynamicTilingActive && !groupTask && windowId !== ""
readonly property int dynamicTilingWindowStateSerial: ShellSettings.Settings.dynamicTilingWindowStateSerial
readonly property bool dynamicTilingMaximized: canRequestDynamicTiling
&& dynamicTilingWindowStateSerial >= 0
&& ShellSettings.Settings.isDynamicTilingWindowMaximized(windowId)
readonly property bool maximizedTask: model.IsMaximized === true || dynamicTilingMaximized
readonly property bool pinned: storageId !== "" && root.folio.FavouritesModel.containsApplication(storageId) readonly property bool pinned: storageId !== "" && root.folio.FavouritesModel.containsApplication(storageId)
readonly property bool pendingMove: root.pendingMoveTaskKey === taskKey readonly property bool pendingMove: root.pendingMoveTaskKey === taskKey
@ -403,6 +425,13 @@ Item {
} }
root.markTaskMove(taskCard.taskKey, desktopIndex) root.markTaskMove(taskCard.taskKey, desktopIndex)
if (taskCard.canRequestDynamicTiling) {
const action = root.dynamicTilingMoveToDesktopAction(desktopId, desktopIndex)
if (action !== "") {
ShellSettings.Settings.requestDynamicTilingWindowAction(taskCard.windowId, action)
return
}
}
tasksModel.requestVirtualDesktops(taskCard.modelIndex, [desktopId]) tasksModel.requestVirtualDesktops(taskCard.modelIndex, [desktopId])
} }
@ -509,7 +538,7 @@ Item {
: root.mixColor(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.12) : root.mixColor(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.12)
Behavior on color { Behavior on color {
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
} }
@ -663,7 +692,13 @@ Item {
iconName: taskCard.maximizedTask ? "window-restore" : "window-maximize" iconName: taskCard.maximizedTask ? "window-restore" : "window-maximize"
toolTipText: taskCard.maximizedTask ? i18n("Restore") : i18n("Maximize") toolTipText: taskCard.maximizedTask ? i18n("Restore") : i18n("Maximize")
enabled: !taskCard.groupTask enabled: !taskCard.groupTask
onTriggered: tasksModel.requestToggleMaximized(taskCard.modelIndex) onTriggered: {
if (taskCard.canRequestDynamicTiling) {
ShellSettings.Settings.requestDynamicTilingWindowAction(taskCard.windowId, "maximize-toggle")
return
}
tasksModel.requestToggleMaximized(taskCard.modelIndex)
}
} }
RunningAppsPanelButton { RunningAppsPanelButton {

View file

@ -5,6 +5,7 @@ import QtQuick
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.mobileshell as MobileShell
MouseArea { MouseArea {
id: button id: button
@ -12,6 +13,7 @@ MouseArea {
property string iconName property string iconName
property string toolTipText property string toolTipText
property bool checked: false property bool checked: false
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
signal triggered() signal triggered()
@ -43,7 +45,7 @@ MouseArea {
: "transparent" : "transparent"
Behavior on color { Behavior on color {
ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: button.shortAnimationDuration }
} }
} }

View file

@ -11,6 +11,7 @@ import org.kde.plasma.core as PlasmaCore
import org.kde.ksvg 1.0 as KSvg import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.mobileshell as MobileShell
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
import './delegate' import './delegate'
@ -31,6 +32,7 @@ Item {
&& folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Widget && folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Widget
&& folio.HomeScreenState.dragState.dropDelegate.widget.visualApplet && folio.HomeScreenState.dragState.dropDelegate.widget.visualApplet
readonly property bool dropAnimationRunning: dragXAnim.running || dragYAnim.running readonly property bool dropAnimationRunning: dragXAnim.running || dragYAnim.running
readonly property int dropAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
visible: false visible: false
x: Math.round(folio.HomeScreenState.delegateDragX) x: Math.round(folio.HomeScreenState.delegateDragX)
@ -52,8 +54,8 @@ Item {
XAnimator on x { XAnimator on x {
id: dragXAnim id: dragXAnim
running: false running: false
duration: Kirigami.Units.longDuration duration: root.dropAnimationDuration
easing.type: Easing.OutCubic easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
onFinished: { onFinished: {
root.visible = false; root.visible = false;
root.widget = null; root.widget = null;
@ -65,8 +67,8 @@ Item {
YAnimator on y { YAnimator on y {
id: dragYAnim id: dragYAnim
running: false running: false
duration: Kirigami.Units.longDuration duration: root.dropAnimationDuration
easing.type: Easing.OutCubic easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
onFinished: { onFinished: {
root.visible = false; root.visible = false;
root.widget = null; root.widget = null;

View file

@ -32,16 +32,19 @@ Folio.DelegateTouchArea {
// grow/shrink animation // grow/shrink animation
property real scaleAmount: 1 property real scaleAmount: 1
property bool clickRequested: false property bool clickRequested: false
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
readonly property real pressedScale: MobileShell.Motion.pressScaleIn
function keyboardFocus() { function keyboardFocus() {
delegateWrapper.forceActiveFocus(); delegateWrapper.forceActiveFocus();
} }
NumberAnimation on scaleAmount { MobileShell.MotionNumberAnimation on scaleAmount {
id: shrinkAnim id: shrinkAnim
type: MobileShell.Motion.Press
running: false running: false
duration: ShellSettings.Settings.animationsEnabled ? 80 : 1 duration: root.pressAnimationDuration
to: ShellSettings.Settings.animationsEnabled ? 0.8 : 1 to: root.pressedScale
onFinished: { onFinished: {
if (!root.pressed) { if (!root.pressed) {
growAnim.restart(); growAnim.restart();
@ -49,10 +52,11 @@ Folio.DelegateTouchArea {
} }
} }
NumberAnimation on scaleAmount { MobileShell.MotionNumberAnimation on scaleAmount {
id: growAnim id: growAnim
type: MobileShell.Motion.Press
running: false running: false
duration: ShellSettings.Settings.animationsEnabled ? 80 : 1 duration: root.pressAnimationDuration
to: 1 to: 1
onFinished: { onFinished: {
if (root.clickRequested) { if (root.clickRequested) {

View file

@ -26,6 +26,8 @@ AbstractDelegate {
property bool turnToFolder: false property bool turnToFolder: false
property bool turnToFolderAnimEnabled: false property bool turnToFolderAnimEnabled: false
readonly property int turnToFolderAnimationDuration: root.turnToFolderAnimEnabled ? MobileShell.Motion.duration(MobileShell.Motion.Standard) : 0
readonly property color folderFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.28)
function launchApp() { function launchApp() {
if (!application) { if (!application) {
@ -59,7 +61,7 @@ AbstractDelegate {
Rectangle { Rectangle {
id: rect id: rect
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: Qt.rgba(255, 255, 255, 0.3) color: root.folderFeedbackColor
anchors.fill: parent anchors.fill: parent
Component.onCompleted: { Component.onCompleted: {
@ -69,15 +71,15 @@ AbstractDelegate {
} }
opacity: root.turnToFolder ? 1 : 0 opacity: root.turnToFolder ? 1 : 0
property real scaleAmount: root.turnToFolder ? 1.2 : 1.0 property real scaleAmount: root.turnToFolder ? 1.08 : 1.0
Behavior on scaleAmount { Behavior on scaleAmount {
enabled: root.turnToFolderAnimEnabled enabled: root.turnToFolderAnimEnabled
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Standard; duration: root.turnToFolderAnimationDuration }
} }
Behavior on opacity { Behavior on opacity {
enabled: root.turnToFolderAnimEnabled enabled: root.turnToFolderAnimEnabled
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Standard; duration: root.turnToFolderAnimationDuration }
} }
transform: Scale { transform: Scale {
@ -95,10 +97,10 @@ AbstractDelegate {
anchors.fill: parent anchors.fill: parent
source: root.application ? root.application.icon : "" source: root.application ? root.application.icon : ""
property real scaleAmount: root.turnToFolder ? 0.3 : 1.0 property real scaleAmount: root.turnToFolder ? 0.42 : 1.0
Behavior on scaleAmount { Behavior on scaleAmount {
enabled: root.turnToFolderAnimEnabled enabled: root.turnToFolderAnimEnabled
NumberAnimation { duration: root.turnToFolderAnimEnabled ? Kirigami.Units.longDuration : 0; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Standard; duration: root.turnToFolderAnimationDuration }
} }
transform: Scale { transform: Scale {

View file

@ -19,6 +19,8 @@ Item {
property Folio.FolioApplicationFolder folder property Folio.FolioApplicationFolder folder
property bool expandBackground: false property bool expandBackground: false
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Standard)
readonly property color folderFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.28)
height: folio.FolioSettings.delegateIconSize height: folio.FolioSettings.delegateIconSize
width: folio.FolioSettings.delegateIconSize width: folio.FolioSettings.delegateIconSize
@ -26,7 +28,7 @@ Item {
Rectangle { Rectangle {
id: rect id: rect
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
color: Qt.rgba(255, 255, 255, 0.3) color: root.folderFeedbackColor
anchors.fill: parent anchors.fill: parent
Component.onCompleted: { Component.onCompleted: {
@ -35,9 +37,9 @@ Item {
} }
} }
property real scaleAmount: root.expandBackground ? 1.2 : 1.0 property real scaleAmount: root.expandBackground ? 1.08 : 1.0
Behavior on scaleAmount { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } } Behavior on scaleAmount { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Standard; duration: root.longAnimationDuration } }
transform: Scale { transform: Scale {
origin.x: root.width / 2 origin.x: root.width / 2

View file

@ -28,6 +28,7 @@ Folio.WidgetContainer {
readonly property real bottomWidgetBackgroundPadding: widgetBackground.margins.bottom readonly property real bottomWidgetBackgroundPadding: widgetBackground.margins.bottom
readonly property real leftWidgetBackgroundPadding: widgetBackground.margins.left readonly property real leftWidgetBackgroundPadding: widgetBackground.margins.left
readonly property real rightWidgetBackgroundPadding: widgetBackground.margins.right readonly property real rightWidgetBackgroundPadding: widgetBackground.margins.right
readonly property color placeholderColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.28)
implicitWidth: (widget ? widget.gridWidth : 0) * folio.HomeScreenState.pageCellWidth implicitWidth: (widget ? widget.gridWidth : 0) * folio.HomeScreenState.pageCellWidth
implicitHeight: (widget ? widget.gridHeight : 0) * folio.HomeScreenState.pageCellHeight implicitHeight: (widget ? widget.gridHeight : 0) * folio.HomeScreenState.pageCellHeight
@ -94,7 +95,7 @@ Folio.WidgetContainer {
id: temporaryBackground id: temporaryBackground
anchors.fill: parent anchors.fill: parent
visible: root.widget && !root.widget.applet visible: root.widget && !root.widget.applet
color: Qt.rgba(255, 255, 255, 0.3) color: root.placeholderColor
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
} }

View file

@ -8,6 +8,7 @@ import Qt5Compat.GraphicalEffects
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.core as PlasmaCore import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.ksvg 1.0 as KSvg import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.components 3.0 as PC3
@ -41,6 +42,7 @@ Item {
signal removeRequested() signal removeRequested()
signal closed() signal closed()
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
function startOpen() { function startOpen() {
// prevent config overlay if lock layout is enabled // prevent config overlay if lock layout is enabled
@ -69,7 +71,7 @@ Item {
// in case this gets stuck open over the homescreen, just close on tap // in case this gets stuck open over the homescreen, just close on tap
onClicked: close() onClicked: close()
NumberAnimation on opacity { id: configOverlayOpacityAnim; duration: Kirigami.Units.longDuration } MobileShell.MotionNumberAnimation on opacity { id: configOverlayOpacityAnim; type: MobileShell.Motion.EffectsDefault; duration: root.longAnimationDuration }
function open() { function open() {
configOverlayOpacityAnim.to = 1; configOverlayOpacityAnim.to = 1;
@ -133,7 +135,7 @@ Item {
QQC2.Overlay.modal: Item {} QQC2.Overlay.modal: Item {}
exit: Transition { exit: Transition {
NumberAnimation { property: "opacity"; duration: Kirigami.Units.longDuration; from: 1.0; to: 0.0 } MobileShell.MotionNumberAnimation { property: "opacity"; type: MobileShell.Motion.EffectsDefault; duration: root.longAnimationDuration; from: 1.0; to: 0.0 }
} }
Connections { Connections {

View file

@ -37,6 +37,9 @@ Window {
readonly property string rightShoulderLabel: GamingShell.GamepadManager.buttonLabel(GamingShell.GamepadManager.ButtonRightShoulder) readonly property string rightShoulderLabel: GamingShell.GamepadManager.buttonLabel(GamingShell.GamepadManager.ButtonRightShoulder)
readonly property string quickSettingsButtonLabel: GamingShell.GamepadManager.buttonLabel(GamingShell.GamepadManager.ButtonBack) readonly property string quickSettingsButtonLabel: GamingShell.GamepadManager.buttonLabel(GamingShell.GamepadManager.ButtonBack)
readonly property string searchButtonLabel: GamingShell.GamepadManager.buttonLabel(GamingShell.GamepadManager.ButtonStart) readonly property string searchButtonLabel: GamingShell.GamepadManager.buttonLabel(GamingShell.GamepadManager.ButtonStart)
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
readonly property int launchFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.StandardAccel)
function pulsePrimaryGamepad(lowIntensity, highIntensity, durationMs) { function pulsePrimaryGamepad(lowIntensity, highIntensity, durationMs) {
var pad = GamingShell.GamepadManager.primaryGamepad var pad = GamingShell.GamepadManager.primaryGamepad
@ -161,7 +164,7 @@ Window {
// Animate opacity on show/hide // Animate opacity on show/hide
opacity: visible ? 1 : 0 opacity: visible ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsDefault; duration: root.longAnimationDuration }
} }
Connections { Connections {
@ -960,7 +963,7 @@ Window {
scale: parent.parent.parent.isCurrent ? 1.08 : 1.0 scale: parent.parent.parent.isCurrent ? 1.08 : 1.0
Behavior on scale { Behavior on scale {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
} }
@ -1116,7 +1119,7 @@ Window {
z: 100 z: 100
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: 250; easing.type: Easing.InQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.StandardAccel; duration: root.launchFadeDuration }
} }
} }

View file

@ -7,7 +7,7 @@ import QtQuick.Layouts
import QtQuick.Window import QtQuick.Window
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.gamingshellplugin as GamingShell import org.kde.plasma.private.mobileshell.gamingshellplugin as GamingShell
import org.kde.layershell 1.0 as LayerShell import org.kde.layershell 1.0 as LayerShell
@ -23,6 +23,8 @@ Window {
property string toastMessage: "" property string toastMessage: ""
property bool toastError: false property bool toastError: false
readonly property bool toastActive: toastMessage.length > 0 readonly property bool toastActive: toastMessage.length > 0
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
// Most-recently-played game for quick resume. Populated from recentGames(1) // Most-recently-played game for quick resume. Populated from recentGames(1)
// and refreshed whenever the recent list changes. // and refreshed whenever the recent list changes.
@ -39,10 +41,10 @@ Window {
flags: Qt.FramelessWindowHint flags: Qt.FramelessWindowHint
Behavior on width { Behavior on width {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
Behavior on height { Behavior on height {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
LayerShell.Window.scope: "gaming-hud" LayerShell.Window.scope: "gaming-hud"
@ -57,7 +59,7 @@ Window {
opacity: showing ? 1 : 0 opacity: showing ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsDefault; duration: root.longAnimationDuration }
} }
Timer { Timer {
@ -183,7 +185,7 @@ Window {
opacity: root.toastActive ? 1.0 : 0.0 opacity: root.toastActive ? 1.0 : 0.0
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
RowLayout { RowLayout {

View file

@ -135,7 +135,7 @@ Item {
color: "black" color: "black"
opacity: root.opened ? 0.4 : 0 opacity: root.opened ? 0.4 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsDefault }
} }
} }
@ -150,7 +150,7 @@ Item {
x: root.opened ? root.width - width : root.width x: root.opened ? root.width - width : root.width
Behavior on x { Behavior on x {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault }
} }
Kirigami.Theme.inherit: false Kirigami.Theme.inherit: false

View file

@ -7,6 +7,7 @@ import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.taskmanager as TaskManager import org.kde.taskmanager as TaskManager
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
@ -17,6 +18,8 @@ Item {
implicitHeight: taskList.count > 0 ? column.implicitHeight : 0 implicitHeight: taskList.count > 0 ? column.implicitHeight : 0
readonly property bool hasTasks: taskList.count > 0 readonly property bool hasTasks: taskList.count > 0
readonly property int taskCount: taskList.count readonly property int taskCount: taskList.count
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Standard)
signal taskActivated() signal taskActivated()
signal moveDownRequested() signal moveDownRequested()
@ -59,7 +62,7 @@ Item {
} }
Behavior on implicitHeight { Behavior on implicitHeight {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Standard; duration: root.longAnimationDuration }
} }
ColumnLayout { ColumnLayout {
@ -152,7 +155,7 @@ Item {
: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g,
Kirigami.Theme.textColor.b, 0.06) Kirigami.Theme.textColor.b, 0.06)
Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration } } Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
} }
ColumnLayout { ColumnLayout {

View file

@ -34,6 +34,7 @@ import "./private"
ContainmentItem { ContainmentItem {
id: root id: root
property var folio: root.plasmoid property var folio: root.plasmoid
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
// Tracks whether the Game Center grid is visible within gaming mode. // Tracks whether the Game Center grid is visible within gaming mode.
// If gaming mode is already enabled at startup, open it immediately so // If gaming mode is already enabled at startup, open it immediately so
@ -295,6 +296,8 @@ ContainmentItem {
// maximized. The reveal strip at the screen edge brings it back. // maximized. The reveal strip at the screen edge brings it back.
property real dockOffset: 0 property real dockOffset: 0
readonly property real dockHeight: MobileShell.Constants.convergenceDockHeight readonly property real dockHeight: MobileShell.Constants.convergenceDockHeight
readonly property int dockAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property int dockFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
// Height of the input-receive strip kept at the screen edge when // Height of the input-receive strip kept at the screen edge when
// the dock is hidden. Matches the navigation panel convention. // the dock is hidden. Matches the navigation panel convention.
@ -365,14 +368,14 @@ ContainmentItem {
} }
Behavior on dockOffset { Behavior on dockOffset {
NumberAnimation { MobileShell.MotionNumberAnimation {
easing.type: Easing.InOutCubic type: MobileShell.Motion.SpatialDefault
duration: Kirigami.Units.longDuration duration: dockOverlay.dockAnimationDuration
} }
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: dockOverlay.dockFadeDuration }
} }
Rectangle { Rectangle {
@ -847,7 +850,7 @@ ContainmentItem {
border.color: Qt.rgba(1, 1, 1, 0.2) border.color: Qt.rgba(1, 1, 1, 0.2)
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
} }
implicitWidth: hintText.implicitWidth + Kirigami.Units.gridUnit * 2 implicitWidth: hintText.implicitWidth + Kirigami.Units.gridUnit * 2

View file

@ -4,6 +4,7 @@
import QtQuick import QtQuick
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
import '../delegate' import '../delegate'
@ -13,6 +14,8 @@ MouseArea {
width: 10 + touchPadding * 2 width: 10 + touchPadding * 2
readonly property real touchPadding: 20 readonly property real touchPadding: 20
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsSlow)
readonly property color resizeHandleColor: Kirigami.Theme.highlightColor
property int orientation property int orientation
@ -79,14 +82,14 @@ MouseArea {
id: rect id: rect
anchors.fill: parent anchors.fill: parent
anchors.margins: root.touchPadding anchors.margins: root.touchPadding
color: 'white' color: root.resizeHandleColor
radius: width / 2 radius: width / 2
transform: Scale { transform: Scale {
property real scaleFactor: root.pressed ? 1.2 : 1.0 property real scaleFactor: root.pressed ? MobileShell.Motion.pressScaleOut : 1.0
Behavior on scaleFactor { Behavior on scaleFactor {
NumberAnimation { duration: Kirigami.Units.veryLongDuration; easing.type: Easing.OutExpo } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsSlow; duration: root.pressAnimationDuration }
} }
xScale: scaleFactor xScale: scaleFactor

View file

@ -7,6 +7,7 @@ import QtQuick.Controls as QQC2
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
import '../delegate' import '../delegate'
@ -41,6 +42,8 @@ Item {
property int widgetGridHeightAfterDrag: 0 property int widgetGridHeightAfterDrag: 0
property var lockDrag: null property var lockDrag: null
readonly property int resizeAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property color resizeAccentColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.85)
property alias handleContainer: handleContainer property alias handleContainer: handleContainer
@ -142,35 +145,35 @@ Item {
Item { Item {
id: handleContainer id: handleContainer
NumberAnimation on width { MobileShell.MotionNumberAnimation on width {
id: widthAnim id: widthAnim
duration: Kirigami.Units.longDuration type: MobileShell.Motion.SpatialDefault
easing.type: Easing.InOutQuad duration: root.resizeAnimationDuration
} }
NumberAnimation on height { MobileShell.MotionNumberAnimation on height {
id: heightAnim id: heightAnim
duration: Kirigami.Units.longDuration type: MobileShell.Motion.SpatialDefault
easing.type: Easing.InOutQuad duration: root.resizeAnimationDuration
} }
NumberAnimation on x { MobileShell.MotionNumberAnimation on x {
id: xAnim id: xAnim
duration: Kirigami.Units.longDuration type: MobileShell.Motion.SpatialDefault
easing.type: Easing.InOutQuad duration: root.resizeAnimationDuration
} }
NumberAnimation on y { MobileShell.MotionNumberAnimation on y {
id: yAnim id: yAnim
duration: Kirigami.Units.longDuration type: MobileShell.Motion.SpatialDefault
easing.type: Easing.InOutQuad duration: root.resizeAnimationDuration
} }
} }
Rectangle { Rectangle {
id: resizeOutline id: resizeOutline
color: 'transparent' color: 'transparent'
border.color: 'white' border.color: root.resizeAccentColor
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
border.width: 1 border.width: 1

View file

@ -18,8 +18,11 @@ Item {
property Folio.HomeScreen folio property Folio.HomeScreen folio
readonly property string pluginName: model.pluginName readonly property string pluginName: model.pluginName
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
readonly property real pressedScale: MobileShell.Motion.pressScaleIn
readonly property color hoverColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.22)
property real zoomScale: (model.isSupported && mouseArea.pressed) ? 0.8 : 1 property real zoomScale: (model.isSupported && mouseArea.pressed) ? pressedScale : 1
transform: Scale { transform: Scale {
origin.x: delegate.width / 2; origin.x: delegate.width / 2;
origin.y: delegate.height / 2; origin.y: delegate.height / 2;
@ -27,7 +30,7 @@ Item {
yScale: delegate.zoomScale yScale: delegate.zoomScale
} }
Behavior on zoomScale { NumberAnimation { duration: 80 } } Behavior on zoomScale { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Press; duration: delegate.pressAnimationDuration } }
// Placeholder item used for implement drag & drop // Placeholder item used for implement drag & drop
Item { Item {
@ -72,7 +75,7 @@ Item {
Rectangle { Rectangle {
id: background id: background
color: Qt.rgba(255, 255, 255, 0.3) color: root.hoverColor
visible: model.isSupported && mouseArea.containsMouse visible: model.isSupported && mouseArea.containsMouse
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
anchors.fill: parent anchors.fill: parent

View file

@ -12,7 +12,6 @@ import org.kde.kquickcontrolsaddons 2.0
import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
import org.kde.plasma.private.mobileshell as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.plasma.private.mobileshell.state as MobileShellState import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.plasmoid import org.kde.plasma.plasmoid
@ -39,6 +38,9 @@ Item {
readonly property string applicationName: application ? application.name : "" readonly property string applicationName: application ? application.name : ""
readonly property string applicationStorageId: application ? application.storageId : "" readonly property string applicationStorageId: application ? application.storageId : ""
readonly property string applicationIcon: application ? application.icon : "" readonly property string applicationIcon: application ? application.icon : ""
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
readonly property color pressFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.18)
readonly property color folderFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.24)
signal folderOpenRequested() signal folderOpenRequested()
@ -142,11 +144,12 @@ Item {
property bool launchAppRequested: false property bool launchAppRequested: false
NumberAnimation on zoomScale { MobileShell.MotionNumberAnimation on zoomScale {
id: shrinkAnim id: shrinkAnim
type: MobileShell.Motion.Press
running: false running: false
duration: ShellSettings.Settings.animationsEnabled ? 80 : 1 duration: delegate.pressAnimationDuration
to: ShellSettings.Settings.animationsEnabled ? 0.95 : 1 to: MobileShell.Motion.pressScaleIn
onFinished: { onFinished: {
if (!mouseArea.pressed) { if (!mouseArea.pressed) {
growAnim.restart(); growAnim.restart();
@ -154,10 +157,11 @@ Item {
} }
} }
NumberAnimation on zoomScale { MobileShell.MotionNumberAnimation on zoomScale {
id: growAnim id: growAnim
type: MobileShell.Motion.Press
running: false running: false
duration: ShellSettings.Settings.animationsEnabled ? 80 : 1 duration: delegate.pressAnimationDuration
to: 1 to: 1
onFinished: { onFinished: {
if (mouseArea.launchAppRequested) { if (mouseArea.launchAppRequested) {
@ -188,7 +192,7 @@ Item {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: height / 2 radius: height / 2
color: mouseArea.pressed ? Qt.rgba(255, 255, 255, 0.2) : "transparent" color: mouseArea.pressed ? delegate.pressFeedbackColor : "transparent"
} }
RowLayout { RowLayout {
@ -263,7 +267,7 @@ Item {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing anchors.margins: Kirigami.Units.smallSpacing
color: Qt.rgba(255, 255, 255, 0.2) color: delegate.folderFeedbackColor
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
opacity: delegate.dragFolderAnimationProgress opacity: delegate.dragFolderAnimationProgress
@ -317,7 +321,7 @@ Item {
id: rect id: rect
anchors.fill: parent anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing anchors.margins: Kirigami.Units.smallSpacing
color: Qt.rgba(255, 255, 255, 0.2) color: delegate.folderFeedbackColor
radius: Kirigami.Units.cornerRadius radius: Kirigami.Units.cornerRadius
transform: Scale { transform: Scale {

View file

@ -18,6 +18,7 @@ MobileShell.GridView {
id: root id: root
property MobileShell.MaskManager maskManager property MobileShell.MaskManager maskManager
required property var searchWidget required property var searchWidget
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialFast)
// don't set anchors.margins since we want everywhere to be draggable // don't set anchors.margins since we want everywhere to be draggable
required property bool twoColumn required property bool twoColumn
@ -198,11 +199,12 @@ MobileShell.GridView {
folderAnim.restart(); folderAnim.restart();
} }
NumberAnimation { MobileShell.MotionNumberAnimation {
id: folderAnim id: folderAnim
target: appDelegate target: appDelegate
properties: "dragFolderAnimationProgress" properties: "dragFolderAnimationProgress"
duration: Kirigami.Units.shortDuration type: MobileShell.Motion.SpatialFast
duration: root.shortAnimationDuration
} }
} }
@ -253,10 +255,11 @@ MobileShell.GridView {
// animations // animations
displaced: Transition { displaced: Transition {
NumberAnimation { MobileShell.MotionNumberAnimation {
id: transitionAnim id: transitionAnim
properties: "x,y" properties: "x,y"
easing.type: Easing.OutQuad type: MobileShell.Motion.SpatialFast
duration: root.shortAnimationDuration
} }
} }

View file

@ -11,7 +11,6 @@ import org.kde.draganddrop 2.0 as DragDrop
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
Item { Item {
id: root id: root
@ -26,6 +25,7 @@ Item {
readonly property real cellWidth: twoColumn ? (root.width - leftMargin - rightMargin) / 2 : (root.width - leftMargin - rightMargin) readonly property real cellWidth: twoColumn ? (root.width - leftMargin - rightMargin) / 2 : (root.width - leftMargin - rightMargin)
readonly property real cellHeight: delegateHeight readonly property real cellHeight: delegateHeight
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property real leftMargin: Math.round(width * 0.1) readonly property real leftMargin: Math.round(width * 0.1)
readonly property real rightMargin: Math.round(width * 0.1) readonly property real rightMargin: Math.round(width * 0.1)
@ -150,35 +150,35 @@ Item {
} }
} }
NumberAnimation { MobileShell.MotionNumberAnimation {
id: goToBeginningAnim id: goToBeginningAnim
target: favoritesGrid target: favoritesGrid
properties: 'contentY' properties: 'contentY'
to: favoritesGrid.originY to: favoritesGrid.originY
duration: Kirigami.Units.longDuration type: MobileShell.Motion.SpatialDefault
easing.type: Easing.InOutQuad duration: root.longAnimationDuration
} }
SequentialAnimation { SequentialAnimation {
id: openFolderAnim id: openFolderAnim
ParallelAnimation { ParallelAnimation {
NumberAnimation { MobileShell.MotionNumberAnimation {
target: favoritesGrid target: favoritesGrid
properties: 'openFolderProgress' properties: 'openFolderProgress'
duration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.longDuration : 0 type: MobileShell.Motion.SpatialDefault
duration: root.longAnimationDuration
to: 1 to: 1
easing.type: Easing.InOutQuad
} }
} }
ParallelAnimation { ParallelAnimation {
NumberAnimation { MobileShell.MotionNumberAnimation {
target: folderGrid target: folderGrid
properties: 'openProgress' properties: 'openProgress'
duration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.longDuration : 0 type: MobileShell.Motion.SpatialDefault
duration: root.longAnimationDuration
to: 1 to: 1
easing.type: Easing.InOutQuad
} }
} }
} }
@ -187,22 +187,22 @@ Item {
id: closeFolderAnim id: closeFolderAnim
ParallelAnimation { ParallelAnimation {
NumberAnimation { MobileShell.MotionNumberAnimation {
target: folderGrid target: folderGrid
properties: 'openProgress' properties: 'openProgress'
duration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.longDuration : 0 type: MobileShell.Motion.SpatialDefault
duration: root.longAnimationDuration
to: 0 to: 0
easing.type: Easing.InOutQuad
} }
} }
ParallelAnimation { ParallelAnimation {
NumberAnimation { MobileShell.MotionNumberAnimation {
target: favoritesGrid target: favoritesGrid
properties: 'openFolderProgress' properties: 'openFolderProgress'
duration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.longDuration : 0 type: MobileShell.Motion.SpatialDefault
duration: root.longAnimationDuration
to: 0 to: 0
easing.type: Easing.InOutQuad
} }
} }
} }

View file

@ -17,6 +17,7 @@ import plasma.applet.org.kde.plasma.mobile.homescreen.halcyon as Halcyon
MobileShell.GridView { MobileShell.GridView {
id: root id: root
property Halcyon.ApplicationFolder folder: null property Halcyon.ApplicationFolder folder: null
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialFast)
property string folderName: folder ? folder.name : "" property string folderName: folder ? folder.name : ""
property var folderModel: folder ? folder.applications : [] property var folderModel: folder ? folder.applications : []
@ -223,9 +224,10 @@ MobileShell.GridView {
// animations // animations
displaced: Transition { displaced: Transition {
NumberAnimation { MobileShell.MotionNumberAnimation {
properties: "x,y" properties: "x,y"
easing.type: Easing.OutQuad type: MobileShell.Motion.SpatialFast
duration: root.shortAnimationDuration
} }
} }
} }

View file

@ -15,7 +15,6 @@ import org.kde.kquickcontrolsaddons
import org.kde.plasma.plasmoid import org.kde.plasma.plasmoid
import org.kde.plasma.private.mobileshell as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import plasma.applet.org.kde.plasma.mobile.homescreen.halcyon as Halcyon import plasma.applet.org.kde.plasma.mobile.homescreen.halcyon as Halcyon
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
@ -31,6 +30,8 @@ MouseArea {
property alias iconItem: icon property alias iconItem: icon
readonly property real margins: Math.floor(width * 0.2) readonly property real margins: Math.floor(width * 0.2)
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
readonly property real pressedScale: MobileShell.Motion.pressScaleIn
signal launch(int x, int y, var source, string title, string storageId) signal launch(int x, int y, var source, string title, string storageId)
@ -82,11 +83,12 @@ MouseArea {
property bool launchAppRequested: false property bool launchAppRequested: false
NumberAnimation on zoomScale { MobileShell.MotionNumberAnimation on zoomScale {
id: shrinkAnim id: shrinkAnim
type: MobileShell.Motion.Press
running: false running: false
duration: ShellSettings.Settings.animationsEnabled ? 80 : 1 duration: delegate.pressAnimationDuration
to: ShellSettings.Settings.animationsEnabled ? 0.8 : 1 to: delegate.pressedScale
onFinished: { onFinished: {
if (!delegate.pressed) { if (!delegate.pressed) {
growAnim.restart(); growAnim.restart();
@ -94,10 +96,11 @@ MouseArea {
} }
} }
NumberAnimation on zoomScale { MobileShell.MotionNumberAnimation on zoomScale {
id: growAnim id: growAnim
type: MobileShell.Motion.Press
running: false running: false
duration: ShellSettings.Settings.animationsEnabled ? 80 : 1 duration: delegate.pressAnimationDuration
to: 1 to: 1
onFinished: { onFinished: {
if (delegate.launchAppRequested) { if (delegate.launchAppRequested) {

View file

@ -35,6 +35,7 @@ MobileShell.GridView {
readonly property int reservedSpaceForLabel: metrics.height readonly property int reservedSpaceForLabel: metrics.height
readonly property real effectiveContentWidth: width - leftMargin - rightMargin readonly property real effectiveContentWidth: width - leftMargin - rightMargin
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
cellWidth: gridView.effectiveContentWidth / Math.min(Math.floor(effectiveContentWidth / (Kirigami.Units.iconSizes.huge + Kirigami.Units.largeSpacing * 2)), 8) cellWidth: gridView.effectiveContentWidth / Math.min(Math.floor(effectiveContentWidth / (Kirigami.Units.iconSizes.huge + Kirigami.Units.largeSpacing * 2)), 8)
cellHeight: cellWidth + reservedSpaceForLabel cellHeight: cellWidth + reservedSpaceForLabel
@ -46,11 +47,11 @@ MobileShell.GridView {
goToBeginningAnim.restart(); goToBeginningAnim.restart();
} }
NumberAnimation on contentY { MobileShell.MotionNumberAnimation on contentY {
id: goToBeginningAnim id: goToBeginningAnim
type: MobileShell.Motion.SpatialDefault
to: gridView.originY to: gridView.originY
duration: Kirigami.Units.longDuration duration: gridView.longAnimationDuration
easing.type: Easing.InOutQuad
} }
model: Halcyon.ApplicationListModel model: Halcyon.ApplicationListModel

View file

@ -20,6 +20,7 @@ import "settings" as Settings
Item { Item {
id: root id: root
property MobileShell.MaskManager maskManager property MobileShell.MaskManager maskManager
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
required property real topMargin required property real topMargin
required property real bottomMargin required property real bottomMargin
@ -37,7 +38,7 @@ Item {
signal wallpaperSelectorTriggered() signal wallpaperSelectorTriggered()
Behavior on settingsOpenFactor { Behavior on settingsOpenFactor {
NumberAnimation { duration: Kirigami.Units.longDuration } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsDefault; duration: root.longAnimationDuration }
} }
function triggerHomescreen() { function triggerHomescreen() {

View file

@ -21,6 +21,7 @@ Item {
property real bottomPadding: 0 property real bottomPadding: 0
property real leftPadding: 0 property real leftPadding: 0
property real rightPadding: 0 property real rightPadding: 0
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
// Call when the gesture has started // Call when the gesture has started
function startGesture() { function startGesture() {
@ -110,10 +111,10 @@ Item {
} }
} }
NumberAnimation on contentY { MobileShell.MotionNumberAnimation on contentY {
id: anim id: anim
duration: Kirigami.Units.longDuration type: MobileShell.Motion.SpatialDefault
easing.type: Easing.OutQuad duration: root.longAnimationDuration
running: false running: false
onFinished: { onFinished: {
if (anim.to === flickable.openedContentY) { if (anim.to === flickable.openedContentY) {

View file

@ -17,6 +17,7 @@ import plasma.applet.org.kde.plasma.mobile.homescreen.halcyon as Halcyon
ContainmentItem { ContainmentItem {
id: root id: root
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
Component.onCompleted: { Component.onCompleted: {
Plasmoid.settings.load(); Plasmoid.settings.load();
@ -88,7 +89,7 @@ ContainmentItem {
property real darkenBackgroundFactor: halcyonHomeScreen.page == 1 ? 1 : 0 property real darkenBackgroundFactor: halcyonHomeScreen.page == 1 ? 1 : 0
Behavior on darkenBackgroundFactor { Behavior on darkenBackgroundFactor {
NumberAnimation { duration: Kirigami.Units.longDuration } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsDefault; duration: root.longAnimationDuration }
} }
Rectangle { Rectangle {
@ -103,7 +104,7 @@ ContainmentItem {
opacity: halcyonHomeScreen.settingsOpenFactor opacity: halcyonHomeScreen.settingsOpenFactor
anchors.fill: parent anchors.fill: parent
Behavior on color { Behavior on color {
ColorAnimation { duration: Kirigami.Units.longDuration } MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsDefault; duration: root.longAnimationDuration }
} }
} }

View file

@ -27,6 +27,8 @@ Item {
// Request the panel itself to reapply settings (ex. for updating touch area). // Request the panel itself to reapply settings (ex. for updating touch area).
signal updatePanelPropertiesRequested() signal updatePanelPropertiesRequested()
readonly property int panelAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
Kirigami.Theme.colorSet: forcedComplementary ? Kirigami.Theme.Complementary : Kirigami.Theme.Header Kirigami.Theme.colorSet: forcedComplementary ? Kirigami.Theme.Complementary : Kirigami.Theme.Header
Kirigami.Theme.inherit: false Kirigami.Theme.inherit: false
@ -60,6 +62,7 @@ Item {
State { State {
// Panel is forced to be visible and overlaid over content (will be automatically hidden after a duration). // Panel is forced to be visible and overlaid over content (will be automatically hidden after a duration).
name: "visible" name: "visible"
PropertyChanges { PropertyChanges {
target: root; offset: 0 target: root; offset: 0
} }
@ -76,10 +79,10 @@ Item {
transitions: Transition { transitions: Transition {
SequentialAnimation { SequentialAnimation {
ParallelAnimation { ParallelAnimation {
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "offset" properties: "offset"
easing.type: root.state === "hidden" ? Easing.InExpo : Easing.OutExpo type: root.state === "hidden" ? MobileShell.Motion.EmphasizedAccel : MobileShell.Motion.SpatialDefault
duration: Kirigami.Units.longDuration duration: root.panelAnimationDuration
} }
} }
ScriptAction { ScriptAction {

View file

@ -39,6 +39,8 @@ ContainmentItem {
readonly property bool inLandscape: MobileShell.Constants.navigationPanelOnSide(Screen.width, Screen.height) readonly property bool inLandscape: MobileShell.Constants.navigationPanelOnSide(Screen.width, Screen.height)
readonly property bool gamingMode: ShellSettings.Settings.gamingModeEnabled readonly property bool gamingMode: ShellSettings.Settings.gamingModeEnabled
readonly property int navigationAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
readonly property int resetAnimationDuration: Math.round(MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault) * 1.5)
readonly property real navigationPanelHeight: gamingMode ? 0 : MobileShell.Constants.navigationPanelThickness readonly property real navigationPanelHeight: gamingMode ? 0 : MobileShell.Constants.navigationPanelThickness
readonly property real convergenceWorkspaceFrameThickness: ShellSettings.Settings.convergenceModeEnabled && !gamingMode readonly property real convergenceWorkspaceFrameThickness: ShellSettings.Settings.convergenceModeEnabled && !gamingMode
@ -326,10 +328,10 @@ ContainmentItem {
transitions: Transition { transitions: Transition {
SequentialAnimation { SequentialAnimation {
ParallelAnimation { ParallelAnimation {
PropertyAnimation { MobileShell.MotionNumberAnimation {
properties: "offset" properties: "offset"
easing.type: navigationPanel.state === "hidden" ? Easing.InExpo : Easing.OutExpo type: navigationPanel.state === "hidden" ? MobileShell.Motion.EmphasizedAccel : MobileShell.Motion.SpatialDefault
duration: Kirigami.Units.longDuration duration: root.navigationAnimationDuration
} }
} }
ScriptAction { ScriptAction {
@ -377,14 +379,14 @@ ContainmentItem {
} }
} }
NumberAnimation { MobileShell.MotionNumberAnimation {
id: resetAn id: resetAn
running: false running: false
target: dragEffect target: dragEffect
property: "offsetPoint" property: "offsetPoint"
to: 0 to: 0
duration: Kirigami.Units.longDuration * 1.5 type: MobileShell.Motion.SpatialDefault
easing.type: Easing.OutExpo duration: root.resetAnimationDuration
onRunningChanged: { onRunningChanged: {
if (!running && navigationPanel.state == "hidden") { if (!running && navigationPanel.state == "hidden") {
root.setWindowProperties(); root.setWindowProperties();

View file

@ -59,7 +59,9 @@ QMap<QString, QMap<QString, QVariant>> getKwinrcSettings(KSharedConfig::Ptr m_mo
{"convergentwindowsEnabled", true}, // enable our convergent window plugin {"convergentwindowsEnabled", true}, // enable our convergent window plugin
{"mobiletaskswitcherEnabled", !convergenceModeEnabled}, // mobile task switcher on phone only; convergence uses standard Alt-Tab tabbox {"mobiletaskswitcherEnabled", !convergenceModeEnabled}, // mobile task switcher on phone only; convergence uses standard Alt-Tab tabbox
{"overviewEnabled", convergenceModeEnabled}, // enable KWin Overview effect in convergence mode for desktop-style task switching {"overviewEnabled", convergenceModeEnabled}, // enable KWin Overview effect in convergence mode for desktop-style task switching
{"screenedgeEnabled", convergenceModeEnabled} // enable screen edge visual feedback in convergence mode (mouse hot corners) {"screenedgeEnabled", convergenceModeEnabled}, // enable screen edge visual feedback in convergence mode (mouse hot corners)
{"shift-tilingEnabled", convergenceModeEnabled},
{"shift-tile-previewEnabled", convergenceModeEnabled}
}}, }},
{"Wayland", {"Wayland",
{ {
@ -78,8 +80,8 @@ QMap<QString, QMap<QString, QVariant>> getKwinrcSettings(KSharedConfig::Ptr m_mo
// Have a separate list here because we need to trigger DBus calls to load/unload each effect/script. // Have a separate list here because we need to trigger DBus calls to load/unload each effect/script.
// Make sure that the effect/script is added to the kwinrc "Plugins" section above! // Make sure that the effect/script is added to the kwinrc "Plugins" section above!
const QList<QString> KWIN_EFFECTS = {"blur", "mobiletaskswitcher", "overview", "screenedge"}; const QList<QString> KWIN_EFFECTS = {"blur", "mobiletaskswitcher", "overview", "screenedge", "shift-tile-preview"};
const QList<QString> KWIN_SCRIPTS = {"convergentwindows"}; const QList<QString> KWIN_SCRIPTS = {"convergentwindows", "shift-tiling"};
// .config/plasma-mobile/ksmserver - immutable settings: // .config/plasma-mobile/ksmserver - immutable settings:
const QMap<QString, QMap<QString, QVariant>> KSMSERVER_SETTINGS = {{"General", {{"loginMode", "emptySession"}}}}; const QMap<QString, QMap<QString, QVariant>> KSMSERVER_SETTINGS = {{"General", {{"loginMode", "emptySession"}}}};

View file

@ -3,6 +3,7 @@
`org.shift.icons` is the icon theme selected by `lookandfeel/contents/defaults`. `org.shift.icons` is the icon theme selected by `lookandfeel/contents/defaults`.
It inherits only `hicolor`, so shell-owned glyphs used by the Shift UI need to exist in this theme or in the local hicolor source icon set. It inherits only `hicolor`, so shell-owned glyphs used by the Shift UI need to exist in this theme or in the local hicolor source icon set.
The SVG glyphs are adapted from Phosphor Icons and licensed through the scoped REUSE metadata in `.reuse/dep5`. The SVG glyphs are adapted from Phosphor Icons and licensed through the scoped REUSE metadata in `.reuse/dep5`.
The theme sets `FollowsColorScheme=true`; symbolic SVGs use `.ColorScheme-Text` and `currentColor` so KDE applications recolor them for both dark and light color schemes.
Theme paths used here: Theme paths used here:

View file

@ -2,6 +2,7 @@
Name=SHIFT Name=SHIFT
Comment=SHIFT icon theme Comment=SHIFT icon theme
Inherits=hicolor Inherits=hicolor
FollowsColorScheme=true
Example=folder Example=folder
DisplayDepth=32 DisplayDepth=32
DesktopDefault=48 DesktopDefault=48

View file

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

View file

@ -8,6 +8,7 @@ import QtQuick.Layouts
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
Item { Item {
id: root id: root
@ -20,7 +21,16 @@ Item {
property bool showBackground: true property bool showBackground: true
property int fingerSize: 20 property int fingerSize: 20
property int _endTimeout: 2000 readonly property bool animationsEnabled: ShellSettings.Settings.animationsEnabled
readonly property int longAnimationDuration: animationsEnabled ? Kirigami.Units.longDuration : 0
readonly property int switcherDragDuration: animationsEnabled ? Math.round(Kirigami.Units.veryLongDuration * 3.75) : 0
readonly property int switcherSlideDuration: animationsEnabled ? Math.round(Kirigami.Units.veryLongDuration * 1.25) : 0
readonly property int flickDragDuration: animationsEnabled ? Math.round(Kirigami.Units.veryLongDuration * 2.25) : 0
readonly property int scrubSettleDuration: animationsEnabled ? Math.round(Kirigami.Units.veryLongDuration * 1.75) : 0
readonly property int quickAnimationDuration: animationsEnabled ? Math.round(Kirigami.Units.longDuration * 1.2) : 0
readonly property int sequencePauseDuration: animationsEnabled ? Math.round(Kirigami.Units.veryLongDuration * 1.25) : 0
readonly property int scrubLeadInDelay: animationsEnabled ? Kirigami.Units.veryLongDuration : 0
readonly property int _endTimeout: animationsEnabled ? Kirigami.Units.veryLongDuration * 5 : 0
Rectangle { Rectangle {
id: phone id: phone
@ -213,7 +223,7 @@ Item {
root.touchOnAnim.start() root.touchOnAnim.start()
} }
duration: 1500 duration: root.switcherDragDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
}, },
NumberAnimation { NumberAnimation {
@ -222,7 +232,7 @@ Item {
to: 0 to: 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InQuad easing.type: Easing.InQuad
}, },
NumberAnimation { NumberAnimation {
@ -236,7 +246,7 @@ Item {
touchPoint.yPosition = 2; touchPoint.yPosition = 2;
root.touchOnAnim.start() root.touchOnAnim.start()
} }
duration: 500 duration: root.switcherSlideDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
}, },
NumberAnimation { NumberAnimation {
@ -245,14 +255,14 @@ Item {
to: 0 to: 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InQuad easing.type: Easing.InQuad
} }
] ]
delays: [ delays: [
500, root.sequencePauseDuration,
500, root.sequencePauseDuration,
-Kirigami.Units.longDuration * 2, -root.longAnimationDuration * 2,
] ]
} }
@ -288,7 +298,7 @@ Item {
to: 0.55 to: 0.55
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
}, },
NumberAnimation { NumberAnimation {
@ -297,7 +307,7 @@ Item {
to: 0 to: 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
}, },
NumberAnimation { NumberAnimation {
@ -339,7 +349,7 @@ Item {
root.touchOnAnim.start() root.touchOnAnim.start()
} }
duration: 900 duration: root.flickDragDuration
easing.type: Easing.InQuart easing.type: Easing.InQuart
}, },
NumberAnimation { NumberAnimation {
@ -348,12 +358,12 @@ Item {
to: 0 to: 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InQuad easing.type: Easing.InQuad
} }
] ]
delays: [ delays: [
-Kirigami.Units.longDuration, -root.longAnimationDuration,
] ]
} }
@ -390,7 +400,7 @@ Item {
to: 0.1 to: 0.1
duration: 300 duration: root.quickAnimationDuration
easing.type: Easing.InQuad easing.type: Easing.InQuad
}, },
NumberAnimation { NumberAnimation {
@ -399,7 +409,7 @@ Item {
to: 0 to: 0
duration: 300 duration: root.quickAnimationDuration
easing.type: Easing.Linear easing.type: Easing.Linear
} }
] ]
@ -433,7 +443,7 @@ Item {
root.touchOnAnim.start() root.touchOnAnim.start()
} }
duration: 900 duration: root.flickDragDuration
easing.type: Easing.InOutQuart easing.type: Easing.InOutQuart
}, },
NumberAnimation { NumberAnimation {
@ -443,7 +453,7 @@ Item {
from: 0 from: 0
to: 1 to: 1
duration: 1500 duration: root.switcherDragDuration
easing.type: Easing.InOutQuart easing.type: Easing.InOutQuart
}, },
NumberAnimation { NumberAnimation {
@ -452,7 +462,7 @@ Item {
to: 0.5 to: 0.5
duration: 700 duration: root.scrubSettleDuration
easing.type: Easing.InOutCubic easing.type: Easing.InOutCubic
}, },
NumberAnimation { NumberAnimation {
@ -461,14 +471,14 @@ Item {
to: 0 to: 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InQuad easing.type: Easing.InQuad
} }
] ]
delays: [ delays: [
0, 0,
0, 0,
500 root.sequencePauseDuration
] ]
} }
@ -505,7 +515,7 @@ Item {
to: 0.55 to: 0.55
duration: 300 duration: root.quickAnimationDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
}, },
NumberAnimation { NumberAnimation {
@ -514,7 +524,7 @@ Item {
to: 0 to: 0
duration: 300 duration: root.quickAnimationDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
}, },
NumberAnimation { NumberAnimation {
@ -541,7 +551,7 @@ Item {
to: 1 to: 1
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
}, },
NumberAnimation { // move leftmost window out of the way, otherwise it overlaps NumberAnimation { // move leftmost window out of the way, otherwise it overlaps
@ -550,7 +560,7 @@ Item {
to: 1.8 to: 1.8
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
}, },
NumberAnimation { // move middle window (that's to be focused) a bit to the side to counteract moving of the first window NumberAnimation { // move middle window (that's to be focused) a bit to the side to counteract moving of the first window
@ -559,7 +569,7 @@ Item {
to: 0.4 to: 0.4
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.Linear easing.type: Easing.Linear
}, },
NumberAnimation { // move first (rightmost) window to get a bit more space between it and the middle one during the animation NumberAnimation { // move first (rightmost) window to get a bit more space between it and the middle one during the animation
@ -568,14 +578,14 @@ Item {
to: 1 to: 1
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.Linear easing.type: Easing.Linear
} }
] ]
delays: [ delays: [
400, root.scrubLeadInDelay,
immediate, immediate,
scrubAnimation.animations[0].duration - 300 - 400, scrubAnimation.animations[0].duration - root.quickAnimationDuration - root.scrubLeadInDelay,
scrubAnimation.delays[1], scrubAnimation.delays[1],
scrubAnimation.delays[2], scrubAnimation.delays[2],
immediate, immediate,
@ -655,7 +665,7 @@ Item {
to: 0 to: 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InQuad easing.type: Easing.InQuad
} }
@ -665,7 +675,7 @@ Item {
to: root.fingerSize to: root.fingerSize
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.OutQuad easing.type: Easing.OutQuad
} }
} }

View file

@ -15,6 +15,7 @@ import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
KCM.SimpleKCM { KCM.SimpleKCM {
id: root id: root
readonly property int longAnimationDuration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.longDuration : 0
title: i18n("Navigation") title: i18n("Navigation")
@ -140,7 +141,7 @@ KCM.SimpleKCM {
to: -tutorialSwitcherInput.activeTutorialIndex * (tutorialContainer.phoneWidth + tutorialLayout.spacing) to: -tutorialSwitcherInput.activeTutorialIndex * (tutorialContainer.phoneWidth + tutorialLayout.spacing)
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
} }

View file

@ -2,7 +2,10 @@
// SPDX-License-Identifier: EUPL-1.2 // SPDX-License-Identifier: EUPL-1.2
import QtQuick import QtQuick
import QtQuick.Shapes
import org.kde.kwin.decoration import org.kde.kwin.decoration
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
Decoration { Decoration {
id: root id: root
@ -18,13 +21,19 @@ Decoration {
readonly property int btnSize: 16 readonly property int btnSize: 16
readonly property int btnSpacing: 8 readonly property int btnSpacing: 8
readonly property int btnSideMargin: 12 readonly property int btnSideMargin: 12
readonly property int cornerRadius: decoration.client.maximized ? 0 : 8 readonly property int normalCornerRadius: 8
readonly property int cornerRadius: decoration.client.maximized ? 0 : normalCornerRadius
readonly property int frameThickness: decoration.client.maximized ? 0 : normalCornerRadius
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property bool windowMenuAllowed: !ShellSettings.Settings.convergenceModeEnabled
|| ShellSettings.Settings.gamingModeEnabled
|| !ShellSettings.Settings.dynamicTilingEnabled
Component.onCompleted: { Component.onCompleted: {
borders.top = barHeight; borders.top = barHeight;
borders.left = 0; borders.left = normalCornerRadius;
borders.right = 0; borders.right = normalCornerRadius;
borders.bottom = 0; borders.bottom = normalCornerRadius;
// Keep titlebar controls available for maximized windows in desktop // Keep titlebar controls available for maximized windows in desktop
// convergence mode. Mobile mode uses noBorder=true and bypasses this. // convergence mode. Mobile mode uses noBorder=true and bypasses this.
@ -39,6 +48,36 @@ Decoration {
deco: decoration deco: decoration
} }
readonly property color frameColor: decoration.client.active ? root.activeBar : root.inactiveBar
Shape {
anchors.fill: parent
visible: !decoration.client.maximized
ShapePath {
fillColor: root.frameColor
fillRule: ShapePath.OddEvenFill
strokeWidth: 0
startX: root.cornerRadius
startY: 0
PathLine { x: root.width - root.cornerRadius; y: 0 }
PathArc { x: root.width; y: root.cornerRadius; radiusX: root.cornerRadius; radiusY: root.cornerRadius }
PathLine { x: root.width; y: root.height - root.cornerRadius }
PathArc { x: root.width - root.cornerRadius; y: root.height; radiusX: root.cornerRadius; radiusY: root.cornerRadius }
PathLine { x: root.cornerRadius; y: root.height }
PathArc { x: 0; y: root.height - root.cornerRadius; radiusX: root.cornerRadius; radiusY: root.cornerRadius }
PathLine { x: 0; y: root.cornerRadius }
PathArc { x: root.cornerRadius; y: 0; radiusX: root.cornerRadius; radiusY: root.cornerRadius }
PathMove { x: root.frameThickness; y: root.barHeight }
PathLine { x: root.width - root.frameThickness; y: root.barHeight }
PathLine { x: root.width - root.frameThickness; y: root.height - root.frameThickness }
PathLine { x: root.frameThickness; y: root.height - root.frameThickness }
PathLine { x: root.frameThickness; y: root.barHeight }
}
}
// Faint window outline // Faint window outline
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
@ -55,7 +94,7 @@ Decoration {
height: root.barHeight height: root.barHeight
radius: root.cornerRadius radius: root.cornerRadius
color: decoration.client.active ? root.activeBar : root.inactiveBar 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 // Square off bottom half only top corners are rounded
Rectangle { Rectangle {
@ -96,7 +135,7 @@ Decoration {
elide: Text.ElideMiddle elide: Text.ElideMiddle
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering renderType: Text.NativeRendering
Behavior on color { ColorAnimation { duration: 120 } } Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
} }
Row { Row {
@ -113,6 +152,14 @@ Decoration {
} }
} }
MouseArea {
anchors.fill: parent
z: 1
enabled: !root.windowMenuAllowed
acceptedButtons: Qt.RightButton
onPressed: (mouse) => { mouse.accepted = true }
}
Component.onCompleted: decoration.installTitleItem(titleRow) Component.onCompleted: decoration.installTitleItem(titleRow)
} }
} }
@ -127,9 +174,10 @@ Decoration {
case DecorationOptions.DecorationButtonClose: case DecorationOptions.DecorationButtonClose:
case DecorationOptions.DecorationButtonMinimize: case DecorationOptions.DecorationButtonMinimize:
case DecorationOptions.DecorationButtonMaximizeRestore: case DecorationOptions.DecorationButtonMaximizeRestore:
return true;
case DecorationOptions.DecorationButtonMenu: case DecorationOptions.DecorationButtonMenu:
case DecorationOptions.DecorationButtonApplicationMenu: case DecorationOptions.DecorationButtonApplicationMenu:
return true; return root.windowMenuAllowed;
default: default:
return false; return false;
} }
@ -195,7 +243,7 @@ Decoration {
color: parent.pressed ? Qt.darker(parent.hoverColor, 1.3) color: parent.pressed ? Qt.darker(parent.hoverColor, 1.3)
: parent.hovered ? parent.hoverColor : parent.hovered ? parent.hoverColor
: parent.normalColor : parent.normalColor
Behavior on color { ColorAnimation { duration: 100 } } Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
@ -204,7 +252,7 @@ Decoration {
font.pixelSize: Math.round(parent.width * 0.66) font.pixelSize: Math.round(parent.width * 0.66)
font.weight: Font.Bold font.weight: Font.Bold
opacity: 1.0 opacity: 1.0
Behavior on opacity { NumberAnimation { duration: 100 } } Behavior on opacity { MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration } }
} }
} }
} }

View file

@ -8,3 +8,4 @@ function(add_kwin_effect name source)
endfunction() endfunction()
add_kwin_effect(shift-snap-assist shift-snap-assist) add_kwin_effect(shift-snap-assist shift-snap-assist)
add_kwin_effect(shift-tile-preview shift-tile-preview)

View file

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

View file

@ -0,0 +1,331 @@
// SPDX-FileCopyrightText: 2026 Marco Allegretti
// SPDX-License-Identifier: EUPL-1.2
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 {
id: effect
visible: false
readonly property int outerGap: 8
readonly property int floatEscapeMargin: 32
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
property rect dragSourceGeometry: Qt.rect(0, 0, 0, 0)
property bool animatePreview: false
property bool previewVisible: false
property string previewMode: ""
property string previewScreenName: ""
property rect previewGeometry: Qt.rect(0, 0, 0, 0)
function isActive() {
return ShellSettings.Settings.convergenceModeEnabled
&& !ShellSettings.Settings.gamingModeEnabled
&& ShellSettings.Settings.dynamicTilingEnabled;
}
function windowKey(window) {
return window && window.internalId !== undefined ? String(window.internalId) : "";
}
function shouldIgnore(window) {
if (!window || window.deleted) {
return true;
}
if (!window.normalWindow || !window.maximizable || window.fullScreen) {
return true;
}
return window.resourceClass === "xwaylandvideobridge";
}
function validRect(geometry) {
return geometry && geometry.width > 0 && geometry.height > 0;
}
function rectContainsPoint(geometry, point) {
return validRect(geometry)
&& point.x >= geometry.x
&& point.x <= geometry.x + geometry.width
&& point.y >= geometry.y
&& point.y <= geometry.y + geometry.height;
}
function workRect(window) {
if (!window || !window.output || window.desktops.length === 0) {
return null;
}
return KWinComponents.Workspace.clientArea(
KWinComponents.Workspace.MaximizeArea,
window.output,
window.desktops[0]
);
}
function outsideWorkArea(window, cursor) {
const area = workRect(window);
if (!area) {
return false;
}
const expandedArea = Qt.rect(
area.x - floatEscapeMargin,
area.y - floatEscapeMargin,
area.width + floatEscapeMargin * 2,
area.height + floatEscapeMargin * 2
);
return !rectContainsPoint(expandedArea, cursor);
}
function findTileAtCursor(cursor, ignoredWindow) {
const ignoredKey = windowKey(ignoredWindow);
const windows = KWinComponents.Workspace.windows;
let bestWindow = null;
let bestGeometry = Qt.rect(0, 0, 0, 0);
let bestArea = 0;
for (let index = 0; index < windows.length; index++) {
const candidate = windows[index];
if (shouldIgnore(candidate) || windowKey(candidate) === ignoredKey) {
continue;
}
if (!ignoredWindow || !candidate.output || !ignoredWindow.output || candidate.output.name !== ignoredWindow.output.name) {
continue;
}
const geometry = candidate.frameGeometry;
if (!rectContainsPoint(geometry, cursor)) {
continue;
}
const area = geometry.width * geometry.height;
if (!bestWindow || area < bestArea) {
bestWindow = candidate;
bestGeometry = geometry;
bestArea = area;
}
}
return bestWindow ? bestGeometry : null;
}
function insetPreviewGeometry(geometry) {
const inset = Math.max(2, Math.round(outerGap / 2));
return Qt.rect(
geometry.x + inset,
geometry.y + inset,
Math.max(1, geometry.width - inset * 2),
Math.max(1, geometry.height - inset * 2)
);
}
function showPreview(mode, geometry, screenName) {
hidePreview();
}
function hidePreview() {
previewVisible = false;
draggingWindow = null;
dragSourceGeometry = Qt.rect(0, 0, 0, 0);
disableEffectTimer.restart();
}
function updatePreview(window, dragGeometry) {
if (!isActive() || draggingWindow !== window || !window.output) {
hidePreview();
return;
}
const cursor = KWinComponents.Workspace.cursorPos;
const targetGeometry = findTileAtCursor(cursor, window);
if (targetGeometry) {
showPreview("swap", targetGeometry, window.output.name);
return;
}
if (outsideWorkArea(window, cursor)) {
showPreview("float", validRect(dragGeometry) ? dragGeometry : window.frameGeometry, window.output.name);
return;
}
showPreview("restore", dragSourceGeometry, window.output.name);
}
function connectDragHandlers(window) {
const key = windowKey(window);
if (!key || dragConnectedWindows[key]) {
return;
}
dragConnectedWindows[key] = true;
window.interactiveMoveResizeStarted.connect(function() {
if (!isActive() || shouldIgnore(window)) {
return;
}
draggingWindow = window;
dragSourceGeometry = window.frameGeometry;
showPreview("restore", dragSourceGeometry, window.output ? window.output.name : "");
});
window.interactiveMoveResizeStepped.connect(function(geometry) {
updatePreview(window, geometry);
});
window.interactiveMoveResizeFinished.connect(function() {
if (draggingWindow === window) {
hidePreview();
}
});
}
function connectExistingWindows() {
const windows = KWinComponents.Workspace.windows;
for (let index = 0; index < windows.length; index++) {
connectDragHandlers(windows[index]);
}
}
function previewFillColor(mode) {
if (mode === "float") {
return Qt.rgba(1.0, 0.62, 0.24, 0.18);
}
if (mode === "restore") {
return Qt.rgba(1.0, 1.0, 1.0, 0.10);
}
return Qt.rgba(0.18, 0.72, 0.66, 0.22);
}
function previewBorderColor(mode) {
if (mode === "float") {
return Qt.rgba(1.0, 0.72, 0.36, 0.72);
}
if (mode === "restore") {
return Qt.rgba(1.0, 1.0, 1.0, 0.36);
}
return Qt.rgba(0.64, 0.90, 0.86, 0.82);
}
Timer {
id: enableAnimationTimer
interval: 1
repeat: false
onTriggered: effect.animatePreview = true
}
Timer {
id: disableEffectTimer
interval: effect.previewFadeDuration
repeat: false
onTriggered: {
if (!effect.previewVisible) {
effect.visible = false;
}
}
}
Connections {
target: KWinComponents.Workspace
function onWindowAdded(window) {
effect.connectDragHandlers(window);
}
function onWindowRemoved(window) {
const key = effect.windowKey(window);
if (key) {
delete effect.dragConnectedWindows[key];
}
if (effect.draggingWindow === window) {
effect.hidePreview();
}
}
}
Connections {
target: ShellSettings.Settings
function onConvergenceModeEnabledChanged() {
if (!effect.isActive()) {
effect.hidePreview();
}
}
function onGamingModeEnabledChanged() {
if (!effect.isActive()) {
effect.hidePreview();
}
}
function onDynamicTilingEnabledChanged() {
if (!effect.isActive()) {
effect.hidePreview();
}
}
}
delegate: Rectangle {
id: screenDelegate
readonly property var targetScreen: KWinComponents.SceneView.screen
readonly property bool previewOnScreen: effect.previewScreenName === targetScreen.name
color: "transparent"
Rectangle {
id: previewSurface
visible: opacity > 0
x: effect.previewGeometry.x - screenDelegate.targetScreen.geometry.x
y: effect.previewGeometry.y - screenDelegate.targetScreen.geometry.y
width: effect.previewGeometry.width
height: effect.previewGeometry.height
radius: 14
opacity: effect.previewVisible && screenDelegate.previewOnScreen ? 1 : 0
color: effect.previewFillColor(effect.previewMode)
border.width: 2
border.color: effect.previewBorderColor(effect.previewMode)
Behavior on x {
enabled: effect.animatePreview
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
}
Behavior on y {
enabled: effect.animatePreview
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
}
Behavior on width {
enabled: effect.animatePreview
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
}
Behavior on height {
enabled: effect.animatePreview
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
}
Behavior on opacity {
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
}
Behavior on color {
MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
}
Behavior on border.color {
MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
}
Rectangle {
anchors.fill: parent
anchors.margins: 5
radius: Math.max(0, parent.radius - anchors.margins)
color: "transparent"
border.width: 1
border.color: Qt.rgba(1, 1, 1, 0.14)
opacity: effect.previewMode === "insert" ? 1 : 0.45
}
}
}
Component.onCompleted: connectExistingWindows()
}

View file

@ -0,0 +1,20 @@
{
"KPackageStructure": "KWin/Effect",
"KPlugin": {
"Authors": [
{
"Email": "marcoa@example.com",
"Name": "Marco Allegretti"
}
],
"Category": "Appearance",
"Description": "Animated drag preview for SHIFT dynamic tiling in convergence mode.",
"EnabledByDefault": false,
"Id": "shift-tile-preview",
"License": "EUPL-1.2",
"Name": "SHIFT Tile Preview",
"Version": "1.0"
},
"X-KDE-Ordering": 61,
"X-Plasma-API": "declarativescript"
}

View file

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

View file

@ -9,6 +9,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PlasmaComponents 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 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 // dynamic task offset animation duration based off of the touch position and task scale
function dynamicDuration(left = true): int { function dynamicDuration(left = true): int {
// if the close animation is running, use the standard long duration time for consistency // 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) { 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 // 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) let taskScale = Math.min(taskSwitcherHelpers.currentScale, 1)
@ -170,16 +171,17 @@ MouseArea {
// this is the x-position with respect to the list // this is the x-position with respect to the list
property real listX: root.taskSwitcherHelpers.xPositionFromTaskIndex(currentIndex) property real listX: root.taskSwitcherHelpers.xPositionFromTaskIndex(currentIndex)
Behavior on listX { Behavior on listX {
NumberAnimation { MobileShell.MotionNumberAnimation {
duration: Kirigami.Units.longDuration type: MobileShell.Motion.Standard
easing.type: Easing.InOutQuad duration: root.taskSwitcherHelpers.longAnimationDuration
} }
} }
// the animated task offset value (always will be 0 if it is the current task in the task drawer) // 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)) property real taskOffsetNormalized: (root.baseTaskOffset * ((root.taskSwitcherHelpers.taskDrawerOpened && isCurrentTask) ? 0 : 1))
Behavior on taskOffsetNormalized { Behavior on taskOffsetNormalized {
NumberAnimation { MobileShell.MotionNumberAnimation {
type: MobileShell.Motion.Standard
duration: root.taskSwitcherHelpers.currentDisplayTask > task.currentIndex ? root.taskOffsetDurationRight : root.taskOffsetDurationLeft duration: root.taskSwitcherHelpers.currentDisplayTask > task.currentIndex ? root.taskOffsetDurationRight : root.taskOffsetDurationLeft
easing.type: root.taskOffsetEasing easing.type: root.taskOffsetEasing
easing.overshoot: 0.85 easing.overshoot: 0.85

View file

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

View file

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

View file

@ -9,7 +9,7 @@ import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
Loader { Loader {
id: root id: root
property var currentWindow property var currentWindow: null
// Windows awaiting geometry clamping after un-maximize in convergence // Windows awaiting geometry clamping after un-maximize in convergence
// mode. Using an array so concurrent un-maximizes are not lost. // mode. Using an array so concurrent un-maximizes are not lost.
@ -28,6 +28,7 @@ Loader {
root.pendingConstrainWindows = [] root.pendingConstrainWindows = []
for (const window of windows) { for (const window of windows) {
if (!window || window.deleted || !window.normalWindow) continue if (!window || window.deleted || !window.normalWindow) continue
if (root.dynamicTilingOwnsWindowPlacement()) continue
if (!ShellSettings.Settings.convergenceModeEnabled) continue if (!ShellSettings.Settings.convergenceModeEnabled) continue
if (ShellSettings.Settings.gamingModeEnabled) continue if (ShellSettings.Settings.gamingModeEnabled) continue
@ -52,11 +53,22 @@ Loader {
} }
} }
function dynamicTilingOwnsWindowPlacement() {
return ShellSettings.Settings.convergenceModeEnabled
&& ShellSettings.Settings.dynamicTilingEnabled
&& !ShellSettings.Settings.gamingModeEnabled;
}
function run(window) { function run(window) {
if (!window || window.deleted || !window.normalWindow) { if (!window || window.deleted || !window.normalWindow) {
return; return;
} }
if (root.dynamicTilingOwnsWindowPlacement()) {
window.noBorder = false;
return;
}
// HACK: don't maximize xwaylandvideobridge // HACK: don't maximize xwaylandvideobridge
// see: https://invent.kde.org/plasma/plasma-mobile/-/issues/324 // see: https://invent.kde.org/plasma/plasma-mobile/-/issues/324
if (window.resourceClass === 'xwaylandvideobridge') { if (window.resourceClass === 'xwaylandvideobridge') {
@ -97,7 +109,7 @@ Loader {
} }
Connections { Connections {
target: currentWindow target: root.currentWindow
function onFullScreenChanged() { function onFullScreenChanged() {
if (!currentWindow) { if (!currentWindow) {
@ -153,6 +165,16 @@ Loader {
} }
} }
} }
function onDynamicTilingEnabledChanged() {
const windows = KWinComponents.Workspace.windows;
for (let i = 0; i < windows.length; i++) {
if (windows[i].normalWindow) {
root.run(windows[i]);
}
}
}
} }
Connections { Connections {

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@ Item {
property alias circleOpacity: buttonRect.opacity property alias circleOpacity: buttonRect.opacity
property alias circleVisiblity: buttonRect.visible property alias circleVisiblity: buttonRect.visible
readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software 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 signal clicked
@ -39,7 +40,7 @@ Item {
color: Kirigami.Theme.backgroundColor color: Kirigami.Theme.backgroundColor
opacity: mouseArea.containsPress ? 1 : 0.6 opacity: mouseArea.containsPress ? 1 : 0.6
border { border {
color: Qt.rgba(255, 255, 255, 0.8) color: root.buttonBorderColor
width: 1 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.coreaddons 1.0 as KCoreAddons
import org.kde.plasma.private.sessions 2.0 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 import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
Item { Item {
id: root 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.colorSet: Kirigami.Theme.Complementary
Kirigami.Theme.inherit: false Kirigami.Theme.inherit: false
@ -71,15 +74,15 @@ Item {
target: buttons target: buttons
from: 0 from: 0
to: 1 to: 1
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
} }
OpacityAnimator { OpacityAnimator {
target: background target: background
from: 0 from: 0
to: 0.6 to: root.backgroundDimOpacity
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
} }
} }
@ -98,22 +101,22 @@ Item {
target: buttons target: buttons
from: 1 from: 1
to: 0 to: 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
} }
OpacityAnimator { OpacityAnimator {
target: background target: background
from: 0.6 from: root.backgroundDimOpacity
to: 0 to: 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
} }
OpacityAnimator { OpacityAnimator {
target: blackOverlay target: blackOverlay
from: 0 from: 0
to: closeAnim.closeToBlack ? 1 : 0 to: closeAnim.closeToBlack ? 1 : 0
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
} }
} }
ScriptAction { ScriptAction {
@ -122,7 +125,7 @@ Item {
closeAnim.callback(); closeAnim.callback();
} }
buttons.opacity = 1; buttons.opacity = 1;
background.opacity = 0.6; background.opacity = root.backgroundDimOpacity;
} }
} }
} }

View file

@ -6,6 +6,7 @@
import QtQuick import QtQuick
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
Rectangle { Rectangle {
id: root id: root
@ -15,6 +16,9 @@ Rectangle {
property int stage property int stage
readonly property bool busy: stage > 1 && stage < 6 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 { Item {
id: content id: content
@ -25,8 +29,8 @@ Rectangle {
Behavior on opacity { Behavior on opacity {
OpacityAnimator { OpacityAnimator {
duration: Kirigami.Units.veryLongDuration duration: root.veryLongAnimationDuration
easing.type: Easing.InOutQuad easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsSlow)
} }
} }
@ -63,8 +67,8 @@ Rectangle {
Behavior on opacity { Behavior on opacity {
OpacityAnimator { OpacityAnimator {
duration: Kirigami.Units.longDuration duration: root.longAnimationDuration
easing.type: Easing.InOutQuad easing.type: MobileShell.Motion.easing(MobileShell.Motion.EffectsDefault)
} }
} }
@ -89,9 +93,9 @@ Rectangle {
RotationAnimator on rotation { RotationAnimator on rotation {
from: 0 from: 0
to: 360 to: 360
duration: 1400 duration: root.spinnerAnimationDuration
loops: Animation.Infinite 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.kirigami as Kirigami
import org.kde.plasma.configuration 2.0 import org.kde.plasma.configuration 2.0
import org.kde.kitemmodels 1.0 as KItemModels import org.kde.kitemmodels 1.0 as KItemModels
import org.kde.plasma.private.mobileshell as MobileShell
import './private' import './private'
@ -28,6 +29,7 @@ Item {
property bool isContainment: false property bool isContainment: false
property alias app: appLoader.item property alias app: appLoader.item
property bool loadApp: true property bool loadApp: true
readonly property int appAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
signal appLoaded() signal appLoaded()
@ -132,10 +134,10 @@ Item {
opacity: 0 opacity: 0
scale: 0.7 + 0.3 * app.opacity scale: 0.7 + 0.3 * app.opacity
NumberAnimation on opacity { MobileShell.MotionNumberAnimation on opacity {
id: opacityAnim id: opacityAnim
duration: Kirigami.Units.longDuration type: MobileShell.Motion.EffectsDefault
easing.type: Easing.OutCubic duration: root.appAnimationDuration
onFinished: { onFinished: {
if (app.opacity === 0) { if (app.opacity === 0) {
root.Window.window.close(); root.Window.window.close();

View file

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

View file

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

View file

@ -108,7 +108,7 @@ Item {
property alias passwordBar: keypad.passwordBar property alias passwordBar: keypad.passwordBar
// Speed up animation when passwordless // Speed up animation when passwordless
animationDuration: Kirigami.Units.veryLongDuration animationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialSlow)
// Distance to swipe to fully open keypad // Distance to swipe to fully open keypad
keypadHeight: Kirigami.Units.gridUnit * 20 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
import org.kde.plasma.workspace.keyboardlayout 1.0 as Keyboards import org.kde.plasma.workspace.keyboardlayout 1.0 as Keyboards
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
@ -23,9 +24,12 @@ Rectangle {
readonly property color headerTextColor: Qt.rgba(255, 255, 255, 1) readonly property color headerTextColor: Qt.rgba(255, 255, 255, 1)
readonly property color headerTextInactiveColor: Qt.rgba(255, 255, 255, 0.4) 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 radius: Kirigami.Units.largeSpacing
color: Qt.rgba(255, 255, 255, 0.2) color: root.passwordBarSurfaceColor
// model for shown dots // model for shown dots
// we need to use a listmodel to avoid all delegates from reloading // we need to use a listmodel to avoid all delegates from reloading
@ -223,7 +227,7 @@ Rectangle {
model: dotDisplayModel model: dotDisplayModel
Behavior on implicitWidth { Behavior on implicitWidth {
NumberAnimation { duration: 50 } MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Press; duration: root.quickAnimationDuration }
} }
onImplicitWidthChanged: { onImplicitWidthChanged: {
@ -242,7 +246,7 @@ Rectangle {
Component.onCompleted: { Component.onCompleted: {
if (showChar) { if (showChar) {
charAnimation.to = 1; charAnimation.to = 1;
charAnimation.duration = 75; charAnimation.duration = root.previewAnimationDuration;
charAnimation.restart(); charAnimation.restart();
} else { } else {
dotAnimation.to = 1; dotAnimation.to = 1;
@ -253,7 +257,7 @@ Rectangle {
onShowCharChanged: { onShowCharChanged: {
if (!showChar) { if (!showChar) {
charAnimation.to = 0; charAnimation.to = 0;
charAnimation.duration = 50; charAnimation.duration = root.quickAnimationDuration;
charAnimation.restart(); charAnimation.restart();
dotAnimation.to = 1; dotAnimation.to = 1;
dotAnimation.start(); dotAnimation.start();
@ -269,11 +273,12 @@ Rectangle {
radius: width radius: width
color: lockScreenState.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth color: lockScreenState.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth
PropertyAnimation { MobileShell.MotionNumberAnimation {
id: dotAnimation id: dotAnimation
target: dot; target: dot;
property: "scale"; property: "scale";
duration: 50 type: MobileShell.Motion.Press
duration: root.quickAnimationDuration
} }
} }
@ -285,10 +290,11 @@ Rectangle {
text: model.char text: model.char
font.pointSize: 12 font.pointSize: 12
PropertyAnimation { MobileShell.MotionNumberAnimation {
id: charAnimation id: charAnimation
target: charLabel; target: charLabel;
property: "scale"; property: "scale";
type: MobileShell.Motion.Press
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show more