// SPDX-FileCopyrightText: 2023 Devin Lin // SPDX-License-Identifier: GPL-2.0-or-later import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.kirigami 2.20 as Kirigami import org.kde.plasma.private.mobileshell 1.0 as MobileShell import initialstart 1.0 as InitialStart Kirigami.Page { id: root leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 property int currentIndex: 0 property int stepCount: 0 property bool showingLanding: true // filled by items property var currentStepItem property var nextStepItem property var previousStepItem readonly property bool onFinalPage: currentIndex === (stepCount - 1) // step animation // manually doing the animation is more performant and less glitchy with window resize than a SwipeView property real previousStepItemX: 0 property real currentStepItemX: 0 property real nextStepItemX: 0 NumberAnimation on previousStepItemX { id: previousStepAnim duration: 400 easing.type: Easing.OutExpo onFinished: { if (root.previousStepItemX != 0) { root.previousStepItem.visible = false; } } } NumberAnimation on currentStepItemX { id: currentStepAnim duration: 400 easing.type: Easing.OutExpo } NumberAnimation on nextStepItemX { id: nextStepAnim duration: 400 easing.type: Easing.OutExpo onFinished: { if (root.nextStepItemX != 0) { root.nextStepItem.visible = false; } } } function finishFinalPage() { InitialStart.Wizard.wizardFinished(); applicationWindow().close(); } function requestNextPage() { if (previousStepAnim.running || currentStepAnim.running || nextStepAnim.running) { return; } previousStepItemX = 0; currentIndex++; stepHeading.changeText(currentStepItem.name); currentStepItemX = root.width; currentStepItem.visible = true; previousStepAnim.to = -root.width; previousStepAnim.restart(); currentStepAnim.to = 0; currentStepAnim.restart(); } function requestPreviousPage() { if (previousStepAnim.running || currentStepAnim.running || nextStepAnim.running) { return; } if (currentIndex === 0) { root.showingLanding = true; landingComponent.returnToLanding(); } else { nextStepItemX = 0; currentIndex--; stepHeading.changeText(currentStepItem.name); currentStepItemX = -root.width; currentStepItem.visible = true; nextStepAnim.to = root.width; nextStepAnim.restart(); currentStepAnim.to = 0; currentStepAnim.restart(); } } // top status bar MobileShell.StatusBar { id: statusBar z: 1 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right height: Kirigami.Units.gridUnit * 1.25 colorGroup: PlasmaCore.Theme.ComplementaryColorGroup backgroundColor: "transparent" showSecondRow: false showDropShadow: true showTime: true disableSystemTray: true // prevent SIGABRT, since loading the system tray leads to bad... things } LandingComponent { id: landingComponent anchors.fill: parent onRequestNextPage: { root.showingLanding = false; stepHeading.changeText(root.currentStepItem.name); } } Item { id: stepsComponent anchors.fill: parent // animation when we switch to step stage opacity: root.showingLanding ? 0 : 1 property real translateY: root.showingLanding ? overlaySteps.height : 0 Behavior on opacity { NumberAnimation { duration: 1000 easing.type: Easing.OutExpo } } Behavior on translateY { NumberAnimation { duration: 1000 easing.type: Easing.OutExpo } } transform: Translate { y: stepsComponent.translateY } // heading for all the wizard steps Label { id: stepHeading opacity: 0 color: "white" horizontalAlignment: Text.AlignHCenter font.pointSize: 18 anchors.left: parent.left anchors.leftMargin: Kirigami.Units.gridUnit anchors.right: parent.right anchors.rightMargin: Kirigami.Units.gridUnit anchors.bottom: parent.bottom anchors.bottomMargin: root.height * 0.7 + Kirigami.Units.gridUnit property string toText function changeText(text) { toText = text; toHidden.restart(); } NumberAnimation on opacity { id: toHidden duration: 200 to: 0 onFinished: { stepHeading.text = stepHeading.toText; toShown.restart(); } } NumberAnimation on opacity { id: toShown duration: 200 to: 1 } } Rectangle { id: overlaySteps Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Window color: Kirigami.Theme.backgroundColor anchors.fill: parent anchors.topMargin: root.height * 0.3 // all steps are in this container Item { anchors.fill: parent anchors.bottomMargin: stepFooter.implicitHeight // setup steps Repeater { model: InitialStart.Wizard.steps delegate: MobileShell.BaseItem { id: item visible: model.index === 0 // the binding is broken later contentItem: modelData transform: Translate { x: { if (item.currentIndex === root.currentIndex - 1) { return previousStepItemX; } else if (item.currentIndex === root.currentIndex + 1) { return nextStepItemX; } else if (item.currentIndex === root.currentIndex) { return currentStepItemX; } return 0; } } anchors.fill: parent // pass up the property property string name: contentItem.name property int currentIndex: model.index function updateRootItems() { if (model.index === root.currentIndex) { root.currentStepItem = item; } else if (model.index === root.currentIndex - 1) { root.previousStepItem = item; } else if (model.index === root.currentIndex + 1) { root.nextStepItem = item; } } Component.onCompleted: { root.stepCount++ updateRootItems(); } // keep root properties updated Connections { target: root function onCurrentIndexChanged() { item.updateRootItems(); } } } } } // bottom footer RowLayout { id: stepFooter anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right Button { Layout.alignment: Qt.AlignLeft Layout.leftMargin: Kirigami.Units.gridUnit Layout.bottomMargin: Kirigami.Units.gridUnit topPadding: Kirigami.Units.largeSpacing bottomPadding: Kirigami.Units.largeSpacing leftPadding: Kirigami.Units.gridUnit rightPadding: Kirigami.Units.gridUnit text: i18n("Back") icon.name: "arrow-left" onClicked: root.requestPreviousPage() } Item {} Button { Layout.alignment: Qt.AlignRight Layout.rightMargin: Kirigami.Units.gridUnit Layout.bottomMargin: Kirigami.Units.gridUnit topPadding: Kirigami.Units.largeSpacing bottomPadding: Kirigami.Units.largeSpacing leftPadding: Kirigami.Units.gridUnit rightPadding: Kirigami.Units.gridUnit visible: !root.onFinalPage text: i18n("Next") icon.name: "arrow-right" onClicked: root.requestNextPage(); } Button { Layout.alignment: Qt.AlignRight Layout.rightMargin: Kirigami.Units.gridUnit Layout.bottomMargin: Kirigami.Units.gridUnit topPadding: Kirigami.Units.largeSpacing bottomPadding: Kirigami.Units.largeSpacing leftPadding: Kirigami.Units.gridUnit rightPadding: Kirigami.Units.gridUnit visible: root.onFinalPage text: i18n("Finish") icon.name: "dialog-ok" onClicked: root.finishFinalPage(); } } } } }