shift-shell/kcms/navigation/ui/main.qml
Marco Allegretti 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

260 lines
10 KiB
QML

/*
* SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
* SPDX-FileCopyrightText: 2025 Luis Büchi <luis.buechi@kdemail.net>
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as Controls
import org.kde.kirigami as Kirigami
import org.kde.kcmutils as KCM
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
KCM.SimpleKCM {
id: root
readonly property int longAnimationDuration: ShellSettings.Settings.animationsEnabled ? Kirigami.Units.longDuration : 0
title: i18n("Navigation")
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0
ColumnLayout {
FormCard.FormHeader {
title: i18nc("@label", "Navigation Mode")
}
FormCard.FormCard {
id: gestureSelectionCard
Controls.ButtonGroup {
id: positionGroup
buttons: [navPanelRadio, gesturesRadio]
}
FormCard.FormRadioDelegate {
id: navPanelRadio
text: i18nc("Nav Panel Navigation Mode", "Panel")
checked: ShellSettings.Settings.navigationPanelEnabled
onClicked: ShellSettings.Settings.navigationPanelEnabled = true;
}
FormCard.FormRadioDelegate {
id: gesturesRadio
text: i18nc("Gestures Navigation Mode", "Gestures")
checked: !ShellSettings.Settings.navigationPanelEnabled
onClicked: ShellSettings.Settings.navigationPanelEnabled = false;
}
FormCard.FormDelegateSeparator {
visible: !ShellSettings.Settings.navigationPanelEnabled
above: gesturesRadio
below: tutorialContainer
}
Item {
id: tutorialContainer
visible: !ShellSettings.Settings.navigationPanelEnabled
property int phoneWidth: Math.min(Window.width * 0.4, gestureSelectionCard.maximumWidth * 0.9)
property int phoneHeight: phoneWidth * Window.height / Window.width
property int count: 3
property int fingerSize: 20
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: phoneWidth
Layout.preferredHeight: phoneHeight + fingerSize / 2
Layout.topMargin: Kirigami.Units.largeSpacing * 2
clip: true
MouseArea {
id: tutorialSwitcherInput
anchors.fill: tutorialContainer
preventStealing: true
property int activeTutorialIndex: 0
property real lastX
property real lastDelta
onPressedChanged: {
if (pressed) {
lastX = mouseX;
}
else {
let moveOffset = lastDelta > 0 ? -0.45 : 0.45
let candidateIndex = Math.round(-tutorialLayout.offset / (tutorialLayout.spacing + tutorialContainer.phoneWidth) + moveOffset);
activeTutorialIndex = Math.max(0, Math.min(tutorialContainer.count - 1, candidateIndex));
updateActiveTutorial();
releaseAnim.start()
}
}
function updateActiveTutorial(): void {
switch (activeTutorialIndex) {
case 0:
switchTutorial.loopSwitcherAnimation();
flickTutorial.stopAnimation();
scrubTutorial.stopAnimation();
break;
case 1:
switchTutorial.stopAnimation();
flickTutorial.loopFlickAnimation();
scrubTutorial.stopAnimation();
break;
case 2:
switchTutorial.stopAnimation();
flickTutorial.stopAnimation();
scrubTutorial.loopScrubAnimation();
break;
}
}
onPositionChanged: (mouse) => {
let delta = mouse.x - lastX;
let endOffset = -(tutorialContainer.count - 1) * (tutorialContainer.phoneWidth + tutorialLayout.spacing);
if (activeTutorialIndex == 0 && tutorialLayout.offset > 0 && delta > 0) {
// handle overshoot on the left
delta /= tutorialLayout.x;
}
else if (activeTutorialIndex == tutorialContainer.count - 1 && tutorialLayout.offset < endOffset) {
// handle overhoot on the right
delta /= Math.abs(tutorialLayout.x - endOffset);
}
tutorialLayout.offset += delta
lastDelta = delta;
lastX = mouse.x
}
NumberAnimation {
id: releaseAnim
target: tutorialLayout
property: "offset"
to: -tutorialSwitcherInput.activeTutorialIndex * (tutorialContainer.phoneWidth + tutorialLayout.spacing)
duration: root.longAnimationDuration
easing.type: Easing.InOutQuad
}
}
Item {
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: tutorialContainer.phoneWidth
Layout.preferredHeight: tutorialContainer.phoneHeight + tutorialContainer.fingerSize / 2
RowLayout {
id: tutorialLayout
property int offset: 0
x: offset
width: tutorialContainer.phoneWidth * tutorialContainer.count + Kirigami.Units.largeSpacing * (tutorialContainer.count - 1)
height: tutorialContainer.phoneHeight
spacing: Kirigami.Units.largeSpacing
TutorialPhone {
id: switchTutorial
phoneWidth: tutorialContainer.phoneWidth
phoneHeight: tutorialContainer.phoneHeight
fingerSize: tutorialContainer.fingerSize
showBackground: false
Layout.alignment: Qt.AlignCenter
Component.onCompleted: {
loopSwitcherAnimation();
}
}
TutorialPhone {
id: flickTutorial
phoneWidth: tutorialContainer.phoneWidth
phoneHeight: tutorialContainer.phoneHeight
fingerSize: tutorialContainer.fingerSize
Layout.alignment: Qt.AlignCenter
}
TutorialPhone {
id: scrubTutorial
phoneWidth: tutorialContainer.phoneWidth
phoneHeight: tutorialContainer.phoneHeight
fingerSize: tutorialContainer.fingerSize
showBackground: false
Layout.alignment: Qt.AlignCenter
}
}
}
}
Controls.PageIndicator {
visible: !ShellSettings.Settings.navigationPanelEnabled
currentIndex: tutorialSwitcherInput.activeTutorialIndex
count: tutorialContainer.count
Layout.alignment: Qt.AlignCenter
}
FormCard.FormSectionText {
visible: !ShellSettings.Settings.navigationPanelEnabled && tutorialSwitcherInput.activeTutorialIndex == 0
text: i18n("Swipe up, hold then release to enter Task Switcher")
}
FormCard.FormSectionText {
visible: !ShellSettings.Settings.navigationPanelEnabled && tutorialSwitcherInput.activeTutorialIndex == 1
text: i18n("Swipe up and release to go to Home Screen")
}
FormCard.FormSectionText {
visible: !ShellSettings.Settings.navigationPanelEnabled && tutorialSwitcherInput.activeTutorialIndex == 2
text: i18n("Swipe left and right near the bottom screen edge to scrub through open tasks. Release to select a task to focus")
}
FormCard.FormDelegateSeparator { visible: keyboardToggleDelegate.visible; above: gesturesRadio; below: keyboardToggleDelegate }
FormCard.FormSwitchDelegate {
id: keyboardToggleDelegate
visible: ShellSettings.Settings.navigationPanelEnabled
text: i18n("Always show keyboard toggle")
description: i18n("Whether to always show the keyboard toggle button on the navigation panel.")
checked: ShellSettings.Settings.alwaysShowKeyboardToggleOnNavigationPanel
onCheckedChanged: {
if (checked != ShellSettings.Settings.alwaysShowKeyboardToggleOnNavigationPanel) {
ShellSettings.Settings.alwaysShowKeyboardToggleOnNavigationPanel = checked;
}
}
}
FormCard.FormDelegateSeparator { visible: gesturePanelToggleDelegate.visible }
FormCard.FormSwitchDelegate {
id: gesturePanelToggleDelegate
visible: !ShellSettings.Settings.navigationPanelEnabled
text: i18n("Show gesture handle")
description: i18n("Whether to add a panel on the bottom with a gesture handle.")
checked: ShellSettings.Settings.gesturePanelEnabled
onCheckedChanged: {
if (checked != ShellSettings.Settings.gesturePanelEnabled) {
ShellSettings.Settings.gesturePanelEnabled = checked;
}
}
}
}
}
}