From e66d88a754359e488939e43a41a928ff495d3fe2 Mon Sep 17 00:00:00 2001 From: Devin Lin Date: Wed, 6 Nov 2024 22:07:50 -0800 Subject: [PATCH] initialstart: Introduce InitialStartModule as top level item for modules Currently modules are initialized as QQuickItems. In order to be able to add custom properties for modules to set in the future, introduce InitialStartModule as the top-level QML object for modules to initialize. Currently only two properties are implemented: `available` for whether to show the module in the wizard, and `contentItem` for the visual module item. --- initialstart/CMakeLists.txt | 2 + initialstart/initialstartmodule.cpp | 42 ++++ initialstart/initialstartmodule.h | 40 ++++ .../cellular/package/contents/ui/main.qml | 202 ++++++++--------- .../modules/finished/contents/ui/main.qml | 41 ++-- .../prepare/package/contents/ui/main.qml | 205 +++++++++--------- .../modules/time/package/contents/ui/main.qml | 149 ++++++------- .../modules/wifi/package/contents/ui/main.qml | 202 ++++++++--------- initialstart/qml/Wizard.qml | 10 +- initialstart/wizard.cpp | 33 ++- initialstart/wizard.h | 15 +- 11 files changed, 537 insertions(+), 404 deletions(-) create mode 100644 initialstart/initialstartmodule.cpp create mode 100644 initialstart/initialstartmodule.h diff --git a/initialstart/CMakeLists.txt b/initialstart/CMakeLists.txt index 9cfd6202..07cead8e 100644 --- a/initialstart/CMakeLists.txt +++ b/initialstart/CMakeLists.txt @@ -14,6 +14,8 @@ add_executable(plasma-mobile-initial-start utils.h initialstartutil.cpp initialstartutil.h + initialstartmodule.cpp + initialstartmodule.h ) qt_add_qml_module(plasma-mobile-initial-start diff --git a/initialstart/initialstartmodule.cpp b/initialstart/initialstartmodule.cpp new file mode 100644 index 00000000..dcaf8770 --- /dev/null +++ b/initialstart/initialstartmodule.cpp @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2024 Devin Lin +// SPDX-License-Identifier: LGPL-2.0-or-later + +#include "initialstartmodule.h" + +InitialStartModule::InitialStartModule(QObject *parent) + : QObject{parent} +{ +} + +bool InitialStartModule::available() const +{ + return m_available; +} + +void InitialStartModule::setAvailable(bool available) +{ + if (m_available == available) { + return; + } + m_available = available; + Q_EMIT availableChanged(); +} + +QQuickItem *InitialStartModule::contentItem() +{ + return m_contentItem; +} + +void InitialStartModule::setContentItem(QQuickItem *contentItem) +{ + if (m_contentItem == contentItem) { + return; + } + m_contentItem = contentItem; + Q_EMIT contentItemChanged(); +} + +QQmlListProperty InitialStartModule::children() +{ + return QQmlListProperty(this, &m_children); +} diff --git a/initialstart/initialstartmodule.h b/initialstart/initialstartmodule.h new file mode 100644 index 00000000..276048e5 --- /dev/null +++ b/initialstart/initialstartmodule.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2024 Devin Lin +// SPDX-License-Identifier: LGPL-2.0-or-later + +#pragma once + +#include "qqml.h" +#include +#include +#include + +class InitialStartModule : public QObject +{ + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(bool available READ available WRITE setAvailable NOTIFY availableChanged) + Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem REQUIRED NOTIFY contentItemChanged) + Q_PROPERTY(QQmlListProperty children READ children CONSTANT) + Q_CLASSINFO("DefaultProperty", "children") + +public: + InitialStartModule(QObject *parent = nullptr); + + bool available() const; + void setAvailable(bool available); + + QQuickItem *contentItem(); + void setContentItem(QQuickItem *contentItem); + + QQmlListProperty children(); + +Q_SIGNALS: + void availableChanged(); + void contentItemChanged(); + +private: + bool m_available{true}; + QQuickItem *m_contentItem{nullptr}; + QList m_children; +}; diff --git a/initialstart/modules/cellular/package/contents/ui/main.qml b/initialstart/modules/cellular/package/contents/ui/main.qml index 67324ad3..1966bb35 100644 --- a/initialstart/modules/cellular/package/contents/ui/main.qml +++ b/initialstart/modules/cellular/package/contents/ui/main.qml @@ -9,129 +9,133 @@ import org.kde.kirigami as Kirigami import org.kde.kirigamiaddons.formcard 1 as FormCard import org.kde.plasma.mm as PlasmaMM -Item { - id: root - property string name: i18n("Cellular") +import org.kde.plasma.mobileinitialstart.initialstart - readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) +InitialStartModule { + contentItem: Item { + id: root + property string name: i18n("Cellular") - function toggleMobileData() { - if (PlasmaMM.SignalIndicator.needsAPNAdded || !PlasmaMM.SignalIndicator.mobileDataSupported) { - // open settings if unable to toggle mobile data - MobileShell.ShellUtil.executeCommand("plasma-open-settings kcm_cellular_network"); - } else { - PlasmaMM.SignalIndicator.mobileDataEnabled = !PlasmaMM.SignalIndicator.mobileDataEnabled; - } - } + readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) - EditProfileDialog { - id: profileDialog - profile: null - } - - ColumnLayout { - anchors { - fill: parent - topMargin: Kirigami.Units.gridUnit - bottomMargin: Kirigami.Units.largeSpacing - } - width: root.width - spacing: Kirigami.Units.gridUnit - - Label { - Layout.leftMargin: Kirigami.Units.gridUnit - Layout.rightMargin: Kirigami.Units.gridUnit - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - text: { - if (!PlasmaMM.SignalIndicator.modemAvailable) { - return i18n("Your device does not have a modem available."); - } else if (PlasmaMM.SignalIndicator.needsAPNAdded) { - return i18n("Please configure your APN below for mobile data, further information will be available with your carrier."); - } else if (PlasmaMM.SignalIndicator.mobileDataSupported) { - return i18n("You are connected to the mobile network."); - } else if (PlasmaMM.SignalIndicator.simEmpty) { - return i18n("Please insert a SIM card into your device."); - } else { - return i18n("Your device does not have a modem available."); - } + function toggleMobileData() { + if (PlasmaMM.SignalIndicator.needsAPNAdded || !PlasmaMM.SignalIndicator.mobileDataSupported) { + // open settings if unable to toggle mobile data + MobileShell.ShellUtil.executeCommand("plasma-open-settings kcm_cellular_network"); + } else { + PlasmaMM.SignalIndicator.mobileDataEnabled = !PlasmaMM.SignalIndicator.mobileDataEnabled; } } - FormCard.FormCard { - visible: PlasmaMM.SignalIndicator.modemAvailable && PlasmaMM.SignalIndicator.mobileDataSupported - maximumWidth: root.cardWidth + EditProfileDialog { + id: profileDialog + profile: null + } - Layout.alignment: Qt.AlignTop | Qt.AlignHCenter + ColumnLayout { + anchors { + fill: parent + topMargin: Kirigami.Units.gridUnit + bottomMargin: Kirigami.Units.largeSpacing + } + width: root.width + spacing: Kirigami.Units.gridUnit - FormCard.FormSwitchDelegate { - text: i18n("Mobile Data") - checked: PlasmaMM.SignalIndicator.mobileDataEnabled - onCheckedChanged: { - if (checked !== PlasmaMM.SignalIndicator.mobileDataEnabled) { - root.toggleMobileData(); + Label { + Layout.leftMargin: Kirigami.Units.gridUnit + Layout.rightMargin: Kirigami.Units.gridUnit + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + text: { + if (!PlasmaMM.SignalIndicator.modemAvailable) { + return i18n("Your device does not have a modem available."); + } else if (PlasmaMM.SignalIndicator.needsAPNAdded) { + return i18n("Please configure your APN below for mobile data, further information will be available with your carrier."); + } else if (PlasmaMM.SignalIndicator.mobileDataSupported) { + return i18n("You are connected to the mobile network."); + } else if (PlasmaMM.SignalIndicator.simEmpty) { + return i18n("Please insert a SIM card into your device."); + } else { + return i18n("Your device does not have a modem available."); } } } - } - FormCard.FormCard { - visible: PlasmaMM.SignalIndicator.modemAvailable && !PlasmaMM.SignalIndicator.simEmpty - maximumWidth: root.cardWidth + FormCard.FormCard { + visible: PlasmaMM.SignalIndicator.modemAvailable && PlasmaMM.SignalIndicator.mobileDataSupported + maximumWidth: root.cardWidth - Layout.fillHeight: true - Layout.alignment: Qt.AlignTop | Qt.AlignHCenter - - ListView { - id: listView - currentIndex: -1 - clip: true - - Layout.fillWidth: true - Layout.fillHeight: true - - model: PlasmaMM.SignalIndicator.profiles - - delegate: FormCard.FormRadioDelegate { - width: listView.width - text: modelData.name - description: modelData.apn - checked: modem.activeConnectionUni == modelData.connectionUni + Layout.alignment: Qt.AlignTop | Qt.AlignHCenter + FormCard.FormSwitchDelegate { + text: i18n("Mobile Data") + checked: PlasmaMM.SignalIndicator.mobileDataEnabled onCheckedChanged: { - if (checked) { - PlasmaMM.SignalIndicator.activateProfile(modelData.connectionUni); - checked = Qt.binding(() => { return modem.activeConnectionUni == modelData.connectionUni }); + if (checked !== PlasmaMM.SignalIndicator.mobileDataEnabled) { + root.toggleMobileData(); } } + } + } - trailing: RowLayout { - ToolButton { - icon.name: "entry-edit" - text: i18n("Edit") - onClicked: { - profileDialog.profile = modelData; - profileDialog.open(); + FormCard.FormCard { + visible: PlasmaMM.SignalIndicator.modemAvailable && !PlasmaMM.SignalIndicator.simEmpty + maximumWidth: root.cardWidth + + Layout.fillHeight: true + Layout.alignment: Qt.AlignTop | Qt.AlignHCenter + + ListView { + id: listView + currentIndex: -1 + clip: true + + Layout.fillWidth: true + Layout.fillHeight: true + + model: PlasmaMM.SignalIndicator.profiles + + delegate: FormCard.FormRadioDelegate { + width: listView.width + text: modelData.name + description: modelData.apn + checked: modem.activeConnectionUni == modelData.connectionUni + + onCheckedChanged: { + if (checked) { + PlasmaMM.SignalIndicator.activateProfile(modelData.connectionUni); + checked = Qt.binding(() => { return modem.activeConnectionUni == modelData.connectionUni }); } } - ToolButton { - icon.name: "delete" - text: i18n("Delete") - onClicked: PlasmaMM.SignalIndicator.removeProfile(modelData.connectionUni) + + trailing: RowLayout { + ToolButton { + icon.name: "entry-edit" + text: i18n("Edit") + onClicked: { + profileDialog.profile = modelData; + profileDialog.open(); + } + } + ToolButton { + icon.name: "delete" + text: i18n("Delete") + onClicked: PlasmaMM.SignalIndicator.removeProfile(modelData.connectionUni) + } } } } - } - FormCard.FormButtonDelegate { - icon.name: "list-add" - text: i18n("Add APN") - onClicked: { - profileDialog.profile = null; - profileDialog.open(); + FormCard.FormButtonDelegate { + icon.name: "list-add" + text: i18n("Add APN") + onClicked: { + profileDialog.profile = null; + profileDialog.open(); + } } } } diff --git a/initialstart/modules/finished/contents/ui/main.qml b/initialstart/modules/finished/contents/ui/main.qml index ff7d29bc..b46ee0fe 100644 --- a/initialstart/modules/finished/contents/ui/main.qml +++ b/initialstart/modules/finished/contents/ui/main.qml @@ -9,31 +9,32 @@ import org.kde.kirigami 2.20 as Kirigami import org.kde.plasma.mobileinitialstart.initialstart -Item { - id: root +InitialStartModule { + contentItem: Item { + id: root - property string name: i18n("Complete!") + property string name: i18n("Complete!") - ColumnLayout { - anchors.fill: parent - anchors.margins: Kirigami.Units.gridUnit + ColumnLayout { + anchors.fill: parent + anchors.margins: Kirigami.Units.gridUnit - Label { - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter | Qt.AlignTop - text: i18n("Your device is now ready.

Enjoy %1!", InitialStartUtil.distroName) - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - } + Label { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + text: i18n("Your device is now ready.

Enjoy %1!", InitialStartUtil.distroName) + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + } - Item { Layout.fillHeight: true } + Item { Layout.fillHeight: true } - Image { - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter - fillMode: Image.PreserveAspectFit - source: "konqi-calling.png" + Image { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + fillMode: Image.PreserveAspectFit + source: "konqi-calling.png" + } } } } - diff --git a/initialstart/modules/prepare/package/contents/ui/main.qml b/initialstart/modules/prepare/package/contents/ui/main.qml index 53a9d47f..8f466e66 100644 --- a/initialstart/modules/prepare/package/contents/ui/main.qml +++ b/initialstart/modules/prepare/package/contents/ui/main.qml @@ -10,132 +10,137 @@ import org.kde.kirigamiaddons.formcard 1.0 as FormCard import org.kde.plasma.mobileinitialstart.prepare 1.0 as Prepare import org.kde.plasma.private.mobileshell.screenbrightnessplugin as ScreenBrightness -Item { - id: root - property string name: i18n("Before we get started…") +import org.kde.plasma.mobileinitialstart.initialstart - readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) +InitialStartModule { + id: module + contentItem: Item { + id: root + property string name: i18n("Before we get started…") - ScreenBrightness.ScreenBrightnessUtil { - id: screenBrightness - } + readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) - ScrollView { - anchors { - fill: parent - topMargin: Kirigami.Units.gridUnit + ScreenBrightness.ScreenBrightnessUtil { + id: screenBrightness } - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - contentWidth: -1 - - ColumnLayout { - width: root.width - spacing: Kirigami.Units.gridUnit - - Label { - Layout.leftMargin: Kirigami.Units.gridUnit - Layout.rightMargin: Kirigami.Units.gridUnit - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - - visible: screenBrightness.brightnessAvailable - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - text: i18n("Adjust the screen brightness to be comfortable for the installation process.") + ScrollView { + anchors { + fill: parent + topMargin: Kirigami.Units.gridUnit } - FormCard.FormCard { - id: brightnessCard - visible: screenBrightness.brightnessAvailable - maximumWidth: root.cardWidth + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + contentWidth: -1 - Layout.alignment: Qt.AlignTop | Qt.AlignHCenter + ColumnLayout { + width: root.width + spacing: Kirigami.Units.gridUnit - FormCard.AbstractFormDelegate { - background: null + Label { + Layout.leftMargin: Kirigami.Units.gridUnit + Layout.rightMargin: Kirigami.Units.gridUnit + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true - contentItem: RowLayout { - spacing: Kirigami.Units.gridUnit + visible: screenBrightness.brightnessAvailable + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + text: i18n("Adjust the screen brightness to be comfortable for the installation process.") + } - Kirigami.Icon { - implicitWidth: Kirigami.Units.iconSizes.smallMedium - implicitHeight: Kirigami.Units.iconSizes.smallMedium - source: "brightness-low" - } + FormCard.FormCard { + id: brightnessCard + visible: screenBrightness.brightnessAvailable + maximumWidth: root.cardWidth - Slider { - id: brightnessSlider - Layout.fillWidth: true - from: 1 - to: screenBrightness.maxBrightness - value: screenBrightness.brightness - onMoved: screenBrightness.brightness = value; + Layout.alignment: Qt.AlignTop | Qt.AlignHCenter - // HACK: for some reason, the slider initial value doesn't set without being done after the component completes loading - Timer { - interval: 0 - running: true - repeat: false - onTriggered: brightnessSlider.value = Qt.binding(() => screenBrightness.brightness) + FormCard.AbstractFormDelegate { + background: null + + contentItem: RowLayout { + spacing: Kirigami.Units.gridUnit + + Kirigami.Icon { + implicitWidth: Kirigami.Units.iconSizes.smallMedium + implicitHeight: Kirigami.Units.iconSizes.smallMedium + source: "brightness-low" + } + + Slider { + id: brightnessSlider + Layout.fillWidth: true + from: 1 + to: screenBrightness.maxBrightness + value: screenBrightness.brightness + onMoved: screenBrightness.brightness = value; + + // HACK: for some reason, the slider initial value doesn't set without being done after the component completes loading + Timer { + interval: 0 + running: true + repeat: false + onTriggered: brightnessSlider.value = Qt.binding(() => screenBrightness.brightness) + } + } + + Kirigami.Icon { + implicitWidth: Kirigami.Units.iconSizes.smallMedium + implicitHeight: Kirigami.Units.iconSizes.smallMedium + source: "brightness-high" } } - - Kirigami.Icon { - implicitWidth: Kirigami.Units.iconSizes.smallMedium - implicitHeight: Kirigami.Units.iconSizes.smallMedium - source: "brightness-high" - } } } - } - Label { - Layout.leftMargin: Kirigami.Units.gridUnit - Layout.rightMargin: Kirigami.Units.gridUnit - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true + Label { + Layout.leftMargin: Kirigami.Units.gridUnit + Layout.rightMargin: Kirigami.Units.gridUnit + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - text: i18n("Adjust the size of elements on the screen.") - } - - FormCard.FormCard { - id: scalingCard - maximumWidth: root.cardWidth - - Layout.alignment: Qt.AlignTop | Qt.AlignHCenter - - FormCard.FormComboBoxDelegate { - id: displayScaling - text: i18n("Display Scaling") - displayMode: FormCard.FormComboBoxDelegate.Dialog - currentIndex: Prepare.PrepareUtil.scalingOptions.indexOf(Prepare.PrepareUtil.scaling.toString() + "%"); - model: Prepare.PrepareUtil.scalingOptions - - // remove % suffix - onCurrentValueChanged: Prepare.PrepareUtil.scaling = parseInt(currentValue.substring(0, currentValue.length - 1)); + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + text: i18n("Adjust the size of elements on the screen.") } - } - FormCard.FormCard { - id: darkThemeCard - maximumWidth: root.cardWidth + FormCard.FormCard { + id: scalingCard + maximumWidth: root.cardWidth - Layout.alignment: Qt.AlignTop | Qt.AlignHCenter + Layout.alignment: Qt.AlignTop | Qt.AlignHCenter - FormCard.FormSwitchDelegate { - id: darkThemeSwitch - text: i18n("Dark Theme") - checked: Prepare.PrepareUtil.usingDarkTheme - onCheckedChanged: { - if (checked !== Prepare.PrepareUtil.usingDarkTheme) { - Prepare.PrepareUtil.usingDarkTheme = checked; + FormCard.FormComboBoxDelegate { + id: displayScaling + text: i18n("Display Scaling") + displayMode: FormCard.FormComboBoxDelegate.Dialog + currentIndex: Prepare.PrepareUtil.scalingOptions.indexOf(Prepare.PrepareUtil.scaling.toString() + "%"); + model: Prepare.PrepareUtil.scalingOptions + + // remove % suffix + onCurrentValueChanged: Prepare.PrepareUtil.scaling = parseInt(currentValue.substring(0, currentValue.length - 1)); + } + } + + FormCard.FormCard { + id: darkThemeCard + maximumWidth: root.cardWidth + + Layout.alignment: Qt.AlignTop | Qt.AlignHCenter + + FormCard.FormSwitchDelegate { + id: darkThemeSwitch + text: i18n("Dark Theme") + checked: Prepare.PrepareUtil.usingDarkTheme + onCheckedChanged: { + if (checked !== Prepare.PrepareUtil.usingDarkTheme) { + Prepare.PrepareUtil.usingDarkTheme = checked; + } } } } } } } -} +} \ No newline at end of file diff --git a/initialstart/modules/time/package/contents/ui/main.qml b/initialstart/modules/time/package/contents/ui/main.qml index c9deaec5..7a5eab52 100644 --- a/initialstart/modules/time/package/contents/ui/main.qml +++ b/initialstart/modules/time/package/contents/ui/main.qml @@ -9,93 +9,97 @@ import org.kde.kirigami 2.20 as Kirigami import org.kde.kirigamiaddons.formcard 1.0 as FormCard import org.kde.plasma.mobileinitialstart.time 1.0 as Time -Item { - id: root - property string name: i18n("Time and Date") +import org.kde.plasma.mobileinitialstart.initialstart - readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) +InitialStartModule { + contentItem: Item { + id: root + property string name: i18n("Time and Date") - ColumnLayout { - anchors { - fill: parent - topMargin: Kirigami.Units.gridUnit - bottomMargin: Kirigami.Units.largeSpacing - } + readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) - width: root.width - spacing: Kirigami.Units.gridUnit - - Label { - Layout.leftMargin: Kirigami.Units.gridUnit - Layout.rightMargin: Kirigami.Units.gridUnit - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - text: i18n("Select your time zone and preferred time format.") - } - - FormCard.FormCard { - maximumWidth: root.cardWidth - - Layout.alignment: Qt.AlignTop | Qt.AlignHCenter - Layout.fillWidth: true - - FormCard.FormSwitchDelegate { - Layout.fillWidth: true - text: i18n("24-Hour Format") - checked: Time.TimeUtil.is24HourTime - onCheckedChanged: { - if (checked !== Time.TimeUtil.is24HourTime) { - Time.TimeUtil.is24HourTime = checked; - } - } + ColumnLayout { + anchors { + fill: parent + topMargin: Kirigami.Units.gridUnit + bottomMargin: Kirigami.Units.largeSpacing } - } - FormCard.FormCard { - maximumWidth: root.cardWidth + width: root.width + spacing: Kirigami.Units.gridUnit - Layout.fillHeight: true - Layout.alignment: Qt.AlignTop | Qt.AlignHCenter - Layout.fillWidth: true - - ListView { - id: listView - - clip: true + Label { + Layout.leftMargin: Kirigami.Units.gridUnit + Layout.rightMargin: Kirigami.Units.gridUnit + Layout.alignment: Qt.AlignTop Layout.fillWidth: true - Layout.fillHeight: true - model: Time.TimeUtil.timeZones - currentIndex: -1 // ensure focus is not on the listview - header: Control { - width: listView.width - leftPadding: Kirigami.Units.largeSpacing - rightPadding: Kirigami.Units.largeSpacing - topPadding: Kirigami.Units.largeSpacing - bottomPadding: Kirigami.Units.largeSpacing + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + text: i18n("Select your time zone and preferred time format.") + } - contentItem: Kirigami.SearchField { - id: searchField + FormCard.FormCard { + maximumWidth: root.cardWidth - onTextChanged: { - Time.TimeUtil.timeZones.filterString = text; + Layout.alignment: Qt.AlignTop | Qt.AlignHCenter + Layout.fillWidth: true + + FormCard.FormSwitchDelegate { + Layout.fillWidth: true + text: i18n("24-Hour Format") + checked: Time.TimeUtil.is24HourTime + onCheckedChanged: { + if (checked !== Time.TimeUtil.is24HourTime) { + Time.TimeUtil.is24HourTime = checked; } } } + } - delegate: FormCard.FormRadioDelegate { - required property string timeZoneId + FormCard.FormCard { + maximumWidth: root.cardWidth - width: ListView.view.width - text: timeZoneId - checked: Time.TimeUtil.currentTimeZone === timeZoneId - onCheckedChanged: { - if (checked && timeZoneId !== Time.TimeUtil.currentTimeZone) { - Time.TimeUtil.currentTimeZone = timeZoneId; - checked = Qt.binding(() => Time.TimeUtil.currentTimeZone === timeZoneId); + Layout.fillHeight: true + Layout.alignment: Qt.AlignTop | Qt.AlignHCenter + Layout.fillWidth: true + + ListView { + id: listView + + clip: true + Layout.fillWidth: true + Layout.fillHeight: true + model: Time.TimeUtil.timeZones + currentIndex: -1 // ensure focus is not on the listview + + header: Control { + width: listView.width + leftPadding: Kirigami.Units.largeSpacing + rightPadding: Kirigami.Units.largeSpacing + topPadding: Kirigami.Units.largeSpacing + bottomPadding: Kirigami.Units.largeSpacing + + contentItem: Kirigami.SearchField { + id: searchField + + onTextChanged: { + Time.TimeUtil.timeZones.filterString = text; + } + } + } + + delegate: FormCard.FormRadioDelegate { + required property string timeZoneId + + width: ListView.view.width + text: timeZoneId + checked: Time.TimeUtil.currentTimeZone === timeZoneId + onCheckedChanged: { + if (checked && timeZoneId !== Time.TimeUtil.currentTimeZone) { + Time.TimeUtil.currentTimeZone = timeZoneId; + checked = Qt.binding(() => Time.TimeUtil.currentTimeZone === timeZoneId); + } } } } @@ -103,4 +107,3 @@ Item { } } } - diff --git a/initialstart/modules/wifi/package/contents/ui/main.qml b/initialstart/modules/wifi/package/contents/ui/main.qml index 24ac4c2c..58ac89f7 100644 --- a/initialstart/modules/wifi/package/contents/ui/main.qml +++ b/initialstart/modules/wifi/package/contents/ui/main.qml @@ -11,121 +11,123 @@ import org.kde.kirigamiaddons.formcard 1.0 as FormCard import org.kde.plasma.networkmanagement as PlasmaNM import org.kde.plasma.mobileinitialstart.wifi 1.0 as WiFi -Item { - id: root - property string name: i18n("Network") +import org.kde.plasma.mobileinitialstart.initialstart - readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) +InitialStartModule { + contentItem: Item { + id: root + property string name: i18n("Network") - PlasmaNM.Handler { - id: handler - } + readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) - PlasmaNM.EnabledConnections { - id: enabledConnections - } - - PlasmaNM.NetworkModel { - id: connectionModel - } - - PlasmaNM.MobileProxyModel { - id: mobileProxyModel - sourceModel: connectionModel - showSavedMode: false - } - - ConnectDialog { - id: connectionDialog - } - - Component.onCompleted: handler.requestScan() - - Timer { - id: scanTimer - interval: 10200 - repeat: true - running: parent.visible - - onTriggered: handler.requestScan() - } - - ColumnLayout { - anchors { - fill: parent - topMargin: Kirigami.Units.gridUnit - bottomMargin: Kirigami.Units.largeSpacing + PlasmaNM.Handler { + id: handler } - width: root.width - spacing: Kirigami.Units.gridUnit - - Label { - Layout.leftMargin: Kirigami.Units.gridUnit - Layout.rightMargin: Kirigami.Units.gridUnit - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - text: i18n("Connect to a WiFi network for network access.") + PlasmaNM.EnabledConnections { + id: enabledConnections } - FormCard.FormCard { - id: savedCard - maximumWidth: root.cardWidth - visible: enabledConnections.wirelessEnabled && count > 0 + PlasmaNM.NetworkModel { + id: connectionModel + } - // number of visible entries - property int count: 0 - function updateCount() { - count = 0; - for (let i = 0; i < connectedRepeater.count; i++) { - let item = connectedRepeater.itemAt(i); - if (item && item.shouldDisplay) { - count++; + PlasmaNM.MobileProxyModel { + id: mobileProxyModel + sourceModel: connectionModel + showSavedMode: false + } + + ConnectDialog { + id: connectionDialog + } + + Component.onCompleted: handler.requestScan() + + Timer { + id: scanTimer + interval: 10200 + repeat: true + running: parent.visible + + onTriggered: handler.requestScan() + } + + ColumnLayout { + anchors { + fill: parent + topMargin: Kirigami.Units.gridUnit + bottomMargin: Kirigami.Units.largeSpacing + } + + width: root.width + spacing: Kirigami.Units.gridUnit + + Label { + Layout.leftMargin: Kirigami.Units.gridUnit + Layout.rightMargin: Kirigami.Units.gridUnit + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + text: i18n("Connect to a WiFi network for network access.") + } + + FormCard.FormCard { + id: savedCard + maximumWidth: root.cardWidth + visible: enabledConnections.wirelessEnabled && count > 0 + + // number of visible entries + property int count: 0 + function updateCount() { + count = 0; + for (let i = 0; i < connectedRepeater.count; i++) { + let item = connectedRepeater.itemAt(i); + if (item && item.shouldDisplay) { + count++; + } + } + } + + Repeater { + id: connectedRepeater + model: mobileProxyModel + delegate: ConnectionItemDelegate { + editMode: false + + // connected or saved + property bool shouldDisplay: (Uuid != "") || ConnectionState === PlasmaNM.Enums.Activated + onShouldDisplayChanged: savedCard.updateCount() + + // separate property for visible since visible is false when the whole card is not visible + visible: (Uuid != "") || ConnectionState === PlasmaNM.Enums.Activated } } } - Repeater { - id: connectedRepeater - model: mobileProxyModel - delegate: ConnectionItemDelegate { - editMode: false - - // connected or saved - property bool shouldDisplay: (Uuid != "") || ConnectionState === PlasmaNM.Enums.Activated - onShouldDisplayChanged: savedCard.updateCount() - - // separate property for visible since visible is false when the whole card is not visible - visible: (Uuid != "") || ConnectionState === PlasmaNM.Enums.Activated - } - } - } - - FormCard.FormCard { - Layout.fillHeight: true - maximumWidth: root.cardWidth - visible: enabledConnections.wirelessEnabled - - ListView { - id: listView - - clip: true - Layout.fillWidth: true + FormCard.FormCard { Layout.fillHeight: true - model: mobileProxyModel + maximumWidth: root.cardWidth + visible: enabledConnections.wirelessEnabled - delegate: ConnectionItemDelegate { - width: ListView.view.width - editMode: false - height: visible ? implicitHeight : 0 - visible: !((Uuid != "") || ConnectionState === PlasmaNM.Enums.Activated) + ListView { + id: listView + + clip: true + Layout.fillWidth: true + Layout.fillHeight: true + model: mobileProxyModel + + delegate: ConnectionItemDelegate { + width: ListView.view.width + editMode: false + height: visible ? implicitHeight : 0 + visible: !((Uuid != "") || ConnectionState === PlasmaNM.Enums.Activated) + } } } } } -} - - +} \ No newline at end of file diff --git a/initialstart/qml/Wizard.qml b/initialstart/qml/Wizard.qml index d463d1a3..25549a14 100644 --- a/initialstart/qml/Wizard.qml +++ b/initialstart/qml/Wizard.qml @@ -19,7 +19,7 @@ Kirigami.Page { bottomPadding: 0 property int currentIndex: 0 - property int stepCount: 0 + readonly property int stepCount: InitialStart.Wizard.stepsCount property bool showingLanding: true // filled by items @@ -63,6 +63,11 @@ Kirigami.Page { } } + onStepCountChanged: { + // reset position + requestPreviousPage(); + } + function finishFinalPage() { // the app exits InitialStart.Wizard.wizardFinished(); @@ -207,7 +212,7 @@ Kirigami.Page { delegate: MobileShell.BaseItem { id: item visible: model.index === 0 // the binding is broken later - contentItem: modelData + contentItem: modelData.contentItem transform: Translate { x: { if (item.currentIndex === root.currentIndex - 1) { @@ -238,7 +243,6 @@ Kirigami.Page { } Component.onCompleted: { - root.stepCount++ updateRootItems(); } diff --git a/initialstart/wizard.cpp b/initialstart/wizard.cpp index da88bf40..f11f0e04 100644 --- a/initialstart/wizard.cpp +++ b/initialstart/wizard.cpp @@ -50,12 +50,12 @@ void Wizard::load() QQmlComponent *c = new QQmlComponent(m_engine, this); // load initialstart QML items - for (auto &pair : m_modulePackages) { + for (const auto &[pluginMetadata, package] : m_modulePackages) { // load QML from kpackage - c->loadUrl(pair.second.fileUrl("mainscript"), QQmlComponent::PreferSynchronous); + c->loadUrl(package.fileUrl("mainscript"), QQmlComponent::PreferSynchronous); auto created = c->create(m_engine->rootContext()); - auto createdItem = qobject_cast(created); + InitialStartModule *createdItem = qobject_cast(created); // print errors if there were issues loading if (!createdItem) { @@ -67,12 +67,16 @@ void Wizard::load() continue; } + connect(createdItem, &InitialStartModule::availableChanged, this, &Wizard::determineAvailableModuleItems); m_moduleItems.push_back(createdItem); - qCDebug(LOGGING_CATEGORY) << "Loaded initialstart module" << pair.first->pluginId(); + qCDebug(LOGGING_CATEGORY) << "Loaded initialstart module" << pluginMetadata->pluginId(); } delete c; + + // Populate model + determineAvailableModuleItems(); } void Wizard::setTestingMode(bool testingMode) @@ -88,9 +92,14 @@ bool Wizard::testingMode() return m_testingMode; } -QList Wizard::steps() +QList Wizard::steps() { - return m_moduleItems; + return m_availableModuleItems; +} + +int Wizard::stepsCount() +{ + return m_availableModuleItems.size(); } void Wizard::wizardFinished() @@ -98,3 +107,15 @@ void Wizard::wizardFinished() Settings::self()->setWizardFinished(); QCoreApplication::quit(); } + +void Wizard::determineAvailableModuleItems() +{ + m_availableModuleItems.clear(); + for (auto *moduleItem : m_moduleItems) { + if (moduleItem->available()) { + m_availableModuleItems.push_back(moduleItem); + } + } + + Q_EMIT stepsChanged(); +} diff --git a/initialstart/wizard.h b/initialstart/wizard.h index b984039e..5b61c3b6 100644 --- a/initialstart/wizard.h +++ b/initialstart/wizard.h @@ -10,10 +10,13 @@ #include #include +#include "initialstartmodule.h" + class Wizard : public QObject { Q_OBJECT - Q_PROPERTY(QList steps READ steps CONSTANT) + Q_PROPERTY(QList steps READ steps NOTIFY stepsChanged) + Q_PROPERTY(int stepsCount READ stepsCount NOTIFY stepsChanged) Q_PROPERTY(bool testingMode READ testingMode NOTIFY testingModeChanged) public: @@ -24,17 +27,23 @@ public: void setTestingMode(bool testingMode); bool testingMode(); - QList steps(); + QList steps(); + int stepsCount(); public Q_SLOTS: void wizardFinished(); Q_SIGNALS: + void stepsChanged(); void testingModeChanged(); +private Q_SLOTS: + void determineAvailableModuleItems(); + private: QList> m_modulePackages; - QList m_moduleItems; + QList m_availableModuleItems; + QList m_moduleItems; bool m_testingMode; QQmlEngine *m_engine;