mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
259 lines
10 KiB
QML
259 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
|
|
|
|
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: Kirigami.Units.longDuration
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|