// SPDX-FileCopyrightText: 2023 Devin Lin // SPDX-License-Identifier: GPL-2.0-or-later import QtQuick import QtQuick.Controls import QtQuick.Layouts import org.kde.kirigami as Kirigami import org.kde.plasma.private.mobileshell as MobileShell import initialstart as InitialStart Kirigami.Page { id: root leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 property int currentIndex: 0 readonly property int stepCount: InitialStart.Wizard.stepsCount property bool showingLanding: true // filled by items property var currentStepItem property var nextStepItem property var previousStepItem readonly property bool onFinalPage: currentIndex === (stepCount - 1) function updateStepItems() { if (stepRepeater.count === 0) { return; } root.previousStepItem = currentIndex > 0 ? stepRepeater.itemAt(currentIndex - 1) : null; root.currentStepItem = stepRepeater.itemAt(currentIndex); root.nextStepItem = currentIndex < stepRepeater.count - 1 ? stepRepeater.itemAt(currentIndex + 1) : null; } // step animation // manually doing the animation is more performant and less glitchy with window resize than a SwipeView property real previousStepItemX: -root.width property real currentStepItemX: 0 property real nextStepItemX: root.width onStepCountChanged: { // reset position updateStepItems(); requestPreviousPage(); } function finishFinalPage() { // the app exits InitialStart.Wizard.wizardFinished(); } function requestNextPage() { if (currentIndex >= stepCount - 1) { return; } currentIndex++; updateStepItems(); stepHeading.changeText(currentStepItem.name); previousStepItemX = -root.width; currentStepItemX = 0; nextStepItemX = root.width; } function requestPreviousPage() { if (currentIndex === 0) { root.showingLanding = true; landingComponent.returnToLanding(); } else { currentIndex--; updateStepItems(); stepHeading.changeText(currentStepItem.name); previousStepItemX = -root.width; currentStepItemX = 0; nextStepItemX = root.width; } } LandingComponent { id: landingComponent anchors.fill: parent enabled: root.showingLanding visible: root.showingLanding onRequestNextPage: { root.showingLanding = false; root.updateStepItems(); stepHeading.changeText(root.currentStepItem.name); } } Item { id: stepsComponent width: parent.width height: parent.height // animation when we switch to step stage opacity: root.showingLanding ? 0 : 1 x: 0 y: root.showingLanding ? overlaySteps.height : 0 // 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) { stepHeading.text = text; stepHeading.opacity = 1; } } Rectangle { id: overlaySteps clip: true Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Window color: Kirigami.Theme.backgroundColor topLeftRadius: Kirigami.Units.gridUnit topRightRadius: Kirigami.Units.gridUnit anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter height: root.height * 0.7 width: Math.min(parent.width, Kirigami.Units.gridUnit * 30) // all steps are in this container Item { anchors.fill: parent anchors.bottomMargin: stepFooter.implicitHeight // setup steps Repeater { id: stepRepeater model: InitialStart.Wizard.steps delegate: MobileShell.BaseItem { id: item visible: !root.showingLanding && Math.abs(item.currentIndex - root.currentIndex) <= 1 contentItem: modelData.contentItem 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: modelData.name property int currentIndex: model.index Component.onCompleted: { root.updateStepItems(); } } } } // 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(); } } } } }