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.
This commit is contained in:
Devin Lin 2024-11-06 22:07:50 -08:00
parent 2a5dec9cf0
commit e66d88a754
11 changed files with 537 additions and 404 deletions

View file

@ -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

View file

@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: 2024 Devin Lin <devin@kde.org>
// 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<QObject> InitialStartModule::children()
{
return QQmlListProperty<QObject>(this, &m_children);
}

View file

@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: 2024 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include "qqml.h"
#include <QAbstractListModel>
#include <QQmlListProperty>
#include <QQuickItem>
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<QObject> 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<QObject> children();
Q_SIGNALS:
void availableChanged();
void contentItemChanged();
private:
bool m_available{true};
QQuickItem *m_contentItem{nullptr};
QList<QObject *> m_children;
};

View file

@ -9,7 +9,10 @@ import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard 1 as FormCard
import org.kde.plasma.mm as PlasmaMM
Item {
import org.kde.plasma.mobileinitialstart.initialstart
InitialStartModule {
contentItem: Item {
id: root
property string name: i18n("Cellular")
@ -136,4 +139,5 @@ Item {
}
}
}
}
}

View file

@ -9,7 +9,8 @@ import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.mobileinitialstart.initialstart
Item {
InitialStartModule {
contentItem: Item {
id: root
property string name: i18n("Complete!")
@ -35,5 +36,5 @@ Item {
source: "konqi-calling.png"
}
}
}
}

View file

@ -10,7 +10,11 @@ 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 {
import org.kde.plasma.mobileinitialstart.initialstart
InitialStartModule {
id: module
contentItem: Item {
id: root
property string name: i18n("Before we get started…")
@ -138,4 +142,5 @@ Item {
}
}
}
}
}

View file

@ -9,7 +9,10 @@ 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 {
import org.kde.plasma.mobileinitialstart.initialstart
InitialStartModule {
contentItem: Item {
id: root
property string name: i18n("Time and Date")
@ -102,5 +105,5 @@ Item {
}
}
}
}
}

View file

@ -11,7 +11,10 @@ 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 {
import org.kde.plasma.mobileinitialstart.initialstart
InitialStartModule {
contentItem: Item {
id: root
property string name: i18n("Network")
@ -126,6 +129,5 @@ Item {
}
}
}
}
}

View file

@ -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();
}

View file

@ -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<QQuickItem *>(created);
InitialStartModule *createdItem = qobject_cast<InitialStartModule *>(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<QQuickItem *> Wizard::steps()
QList<InitialStartModule *> 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();
}

View file

@ -10,10 +10,13 @@
#include <KPackage/Package>
#include <KPluginMetaData>
#include "initialstartmodule.h"
class Wizard : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QQuickItem *> steps READ steps CONSTANT)
Q_PROPERTY(QList<InitialStartModule *> 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<QQuickItem *> steps();
QList<InitialStartModule *> steps();
int stepsCount();
public Q_SLOTS:
void wizardFinished();
Q_SIGNALS:
void stepsChanged();
void testingModeChanged();
private Q_SLOTS:
void determineAvailableModuleItems();
private:
QList<std::pair<KPluginMetaData *, KPackage::Package>> m_modulePackages;
QList<QQuickItem *> m_moduleItems;
QList<InitialStartModule *> m_availableModuleItems;
QList<InitialStartModule *> m_moduleItems;
bool m_testingMode;
QQmlEngine *m_engine;