From daf6ec3fd623ba882d86304d2e2ba5792d36fd24 Mon Sep 17 00:00:00 2001 From: Marco Allegretti Date: Wed, 6 May 2026 13:33:25 +0200 Subject: [PATCH] Smooth convergence mode transitions Animate dock item sizing and button opacity when toggling convergence mode so the dock does not snap abruptly between states. FavouritesBar: promote cell/icon/nav/pager/trash sizing properties to writable and attach NumberAnimation Behaviors (InOutCubic, longDuration). Home, Overview, and trash buttons fade in/out with an InOutQuad opacity Behavior so they appear gradually rather than popping. Dock overlay (main.qml): introduce an `active` guard property so the window can be driven by opacity (InOutQuad, shortDuration) rather than toggling visibility directly. Switch the dockOffset slide easing from a directional InExpo/OutExpo pair to a single InOutCubic so the motion feels symmetrical. StatusBar: smooth the background colour and convergence affordance transitions. --- .../mobileshell/qml/statusbar/StatusBar.qml | 15 +++++-- .../homescreens/folio/qml/FavouritesBar.qml | 45 ++++++++++++++----- containments/homescreens/folio/qml/main.qml | 11 ++++- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/components/mobileshell/qml/statusbar/StatusBar.qml b/components/mobileshell/qml/statusbar/StatusBar.qml index 80c6619e..8f287bb5 100644 --- a/components/mobileshell/qml/statusbar/StatusBar.qml +++ b/components/mobileshell/qml/statusbar/StatusBar.qml @@ -36,6 +36,10 @@ Item { */ property color backgroundColor: "transparent" + Behavior on backgroundColor { + ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } + } + /** * Whether to show a second row of the status bar, with more information. */ @@ -93,7 +97,12 @@ Item { Rectangle { anchors.fill: parent color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.1) - visible: ShellSettings.Settings.convergenceModeEnabled && statusBarHover.hovered + visible: opacity > 0 + opacity: ShellSettings.Settings.convergenceModeEnabled && statusBarHover.hovered ? 1 : 0 + + Behavior on opacity { + NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } + } } HoverHandler { @@ -223,8 +232,8 @@ Item { anchors.bottom: parent.bottom anchors.bottomMargin: Kirigami.Units.smallSpacing - visible: ShellSettings.Settings.convergenceModeEnabled - opacity: statusBarHover.hovered ? 0.6 : 0.2 + visible: ShellSettings.Settings.convergenceModeEnabled || opacity > 0 + opacity: ShellSettings.Settings.convergenceModeEnabled ? (statusBarHover.hovered ? 0.6 : 0.2) : 0 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } diff --git a/containments/homescreens/folio/qml/FavouritesBar.qml b/containments/homescreens/folio/qml/FavouritesBar.qml index b715982c..9be92676 100644 --- a/containments/homescreens/folio/qml/FavouritesBar.qml +++ b/containments/homescreens/folio/qml/FavouritesBar.qml @@ -36,13 +36,18 @@ MouseArea { readonly property int totalItemCount: repeater.count + (showRunningTasks ? taskRepeater.count : 0) // In convergence mode, size icons to fit the dock bar instead of using page grid cells - readonly property real dockCellWidth: convergenceMode ? root.height : folio.HomeScreenState.pageCellWidth - readonly property real dockCellHeight: convergenceMode ? root.height : folio.HomeScreenState.pageCellHeight + property real dockCellWidth: convergenceMode ? root.height : folio.HomeScreenState.pageCellWidth + property real dockCellHeight: convergenceMode ? root.height : folio.HomeScreenState.pageCellHeight + Behavior on dockCellWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } + Behavior on dockCellHeight { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } // Navigation buttons width (used to offset center positioning) - readonly property real navButtonWidth: convergenceMode ? root.height : 0 - readonly property real dockItemInset: convergenceMode ? Math.max(2, Kirigami.Units.smallSpacing / 2) : 0 - readonly property real dockIconSize: Math.min(root.height * 0.56, Kirigami.Units.iconSizes.large) + property real navButtonWidth: convergenceMode ? root.height : 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) + Behavior on navButtonWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } + Behavior on dockItemInset { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } + Behavior on dockIconSize { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } function dockItemColor(pressed, hovered, active) { if (pressed) { @@ -90,10 +95,12 @@ MouseArea { // Virtual desktop pager (convergence mode, 2+ desktops) readonly property bool showPager: convergenceMode && virtualDesktopInfo.numberOfDesktops > 1 - readonly property real pagerButtonWidth: showPager ? Math.min(root.height, Kirigami.Units.gridUnit * 2.5) : 0 + property real pagerButtonWidth: showPager ? Math.min(root.height, Kirigami.Units.gridUnit * 2.5) : 0 readonly property int pagerLeftCount: showPager ? Math.ceil(virtualDesktopInfo.numberOfDesktops / 2) : 0 readonly property int pagerRightCount: showPager ? virtualDesktopInfo.numberOfDesktops - pagerLeftCount : 0 - readonly property real trashButtonWidth: convergenceMode ? root.height : 0 + property real trashButtonWidth: convergenceMode ? root.height : 0 + Behavior on pagerButtonWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } + Behavior on trashButtonWidth { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic } } function pagerDesktopName(index) { let names = virtualDesktopInfo.desktopNames @@ -204,7 +211,9 @@ MouseArea { // Home button (convergence mode, left end) Rectangle { id: homeButton - visible: root.convergenceMode + visible: root.convergenceMode || opacity > 0 + enabled: root.convergenceMode + opacity: root.convergenceMode ? 1 : 0 activeFocusOnTab: root.convergenceMode anchors.left: parent.left anchors.top: parent.top @@ -212,6 +221,10 @@ MouseArea { width: root.navButtonWidth color: "transparent" + Behavior on opacity { + NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } + } + Accessible.role: Accessible.Button Accessible.name: i18n("Home") Accessible.onPressAction: MobileShellState.ShellDBusClient.openHomeScreen() @@ -263,7 +276,9 @@ MouseArea { // Overview button (convergence mode, right end) Rectangle { id: overviewButton - visible: root.convergenceMode + visible: root.convergenceMode || opacity > 0 + enabled: root.convergenceMode + opacity: root.convergenceMode ? 1 : 0 activeFocusOnTab: root.convergenceMode anchors.right: parent.right anchors.top: parent.top @@ -271,6 +286,10 @@ MouseArea { width: root.navButtonWidth color: "transparent" + Behavior on opacity { + NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } + } + Accessible.role: Accessible.Button Accessible.name: i18n("Overview") Accessible.onPressAction: root.folio.triggerOverview() @@ -480,7 +499,9 @@ MouseArea { Rectangle { id: trashButton - visible: root.convergenceMode + visible: root.convergenceMode || opacity > 0 + enabled: root.convergenceMode + opacity: root.convergenceMode ? 1 : 0 activeFocusOnTab: root.convergenceMode x: root.width - root.navButtonWidth - root.trashButtonWidth y: 0 @@ -488,6 +509,10 @@ MouseArea { height: root.height color: "transparent" + Behavior on opacity { + NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } + } + Accessible.role: Accessible.Button Accessible.name: i18n("Trash") Accessible.onPressAction: Qt.openUrlExternally("trash:/") diff --git a/containments/homescreens/folio/qml/main.qml b/containments/homescreens/folio/qml/main.qml index b27346e6..3d4637fb 100644 --- a/containments/homescreens/folio/qml/main.qml +++ b/containments/homescreens/folio/qml/main.qml @@ -276,7 +276,10 @@ ContainmentItem { // task panel containment; this window only provides the visible dock. Window { id: dockOverlay - visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled + readonly property bool active: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled + + visible: active + opacity: active ? 1 : 0 color: "transparent" width: Screen.width height: MobileShell.Constants.convergenceDockHeight @@ -346,11 +349,15 @@ ContainmentItem { Behavior on dockOffset { NumberAnimation { - easing.type: dockOverlay.shouldHide ? Easing.InExpo : Easing.OutExpo + easing.type: Easing.InOutCubic duration: Kirigami.Units.longDuration } } + Behavior on opacity { + NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } + } + Rectangle { anchors.fill: parent visible: !dockOverlay.shouldHide || dockOverlay.dockOffset < dockOverlay.dockHeight