From 17b4b774a3c29497e3db5cc968354803b1c9eada Mon Sep 17 00:00:00 2001 From: Devin Lin Date: Thu, 17 Mar 2022 15:34:27 -0400 Subject: [PATCH] kcm: Add ability to reorder quicksettings Implements #75, reordering of quick settings, and also includes the mobile form components into the kcm. --- kcms/mobileshell/package/contents/ui/main.qml | 117 +++++++++++++++--- .../ui/mobileform/AbstractFormDelegate.qml | 64 ++++++++++ .../ui/mobileform/FormButtonDelegate.qml | 57 +++++++++ .../contents/ui/mobileform/FormCard.qml | 80 ++++++++++++ .../contents/ui/mobileform/FormCardHeader.qml | 52 ++++++++ .../ui/mobileform/FormCheckBoxDelegate.qml | 36 ++++++ .../ui/mobileform/FormComboBoxDelegate.qml | 59 +++++++++ .../ui/mobileform/FormRadioButtonDelegate.qml | 37 ++++++ .../ui/mobileform/FormSectionText.qml | 23 ++++ .../ui/mobileform/FormSwitchDelegate.qml | 50 ++++++++ .../ui/mobileform/FormTextDelegate.qml | 53 ++++++++ libmobileshell/mobileshellsettings.cpp | 7 +- libmobileshell/quicksettingsmodel.cpp | 8 +- libmobileshell/savedquicksettings.cpp | 31 +++-- libmobileshell/savedquicksettings.h | 11 +- libmobileshell/savedquicksettingsmodel.cpp | 18 +-- libmobileshell/savedquicksettingsmodel.h | 10 +- quicksettings/mobiledata/metadata.desktop | 2 +- quicksettings/wifi/metadata.desktop | 2 +- 19 files changed, 670 insertions(+), 47 deletions(-) create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/AbstractFormDelegate.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormButtonDelegate.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormCard.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormCardHeader.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormCheckBoxDelegate.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormComboBoxDelegate.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormRadioButtonDelegate.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormSectionText.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormSwitchDelegate.qml create mode 100644 kcms/mobileshell/package/contents/ui/mobileform/FormTextDelegate.qml diff --git a/kcms/mobileshell/package/contents/ui/main.qml b/kcms/mobileshell/package/contents/ui/main.qml index 227270c6..11135c02 100644 --- a/kcms/mobileshell/package/contents/ui/main.qml +++ b/kcms/mobileshell/package/contents/ui/main.qml @@ -9,34 +9,119 @@ import QtQuick.Controls 2.15 as QQC2 import org.kde.kirigami 2.19 as Kirigami import org.kde.kcm 1.3 as KCM +import org.kde.plasma.private.mobileshell 1.0 as MobileShell + +import "mobileform" as MobileForm KCM.SimpleKCM { id: root title: i18n("Shell") - leftPadding: Kirigami.Units.largeSpacing - rightPadding: Kirigami.Units.largeSpacing + leftPadding: 0 + rightPadding: 0 + topPadding: Kirigami.Units.gridUnit + bottomPadding: Kirigami.Units.gridUnit - Kirigami.FormLayout { - id: form - wideMode: false + ColumnLayout { + spacing: 0 + width: root.width - Item { + MobileForm.FormCard { Layout.fillWidth: true - Kirigami.FormData.label: i18n("Navigation Panel") - Kirigami.FormData.isSection: true + + contentItem: ColumnLayout { + spacing: 0 + + MobileForm.FormCardHeader { + title: i18n("Navigation Panel") + } + + MobileForm.FormSwitchDelegate { + text: i18n("Gesture-only Mode") + description: i18n("Whether to hide the navigation panel.") + checked: !kcm.navigationPanelEnabled + switchControl.onCheckStateChanged: { + if (checked != !kcm.navigationPanelEnabled) { + kcm.navigationPanelEnabled = !checked; + } + } + } + } } - QQC2.CheckBox { - Kirigami.FormData.label: i18n("Remove panel (only use gestures):") - Layout.maximumWidth: form.width - text: checked ? i18n("On") : i18n("Off") - checked: !kcm.navigationPanelEnabled - onCheckStateChanged: { - if (checked != !kcm.navigationPanelEnabled) { - kcm.navigationPanelEnabled = !checked; + MobileForm.FormCard { + Layout.fillWidth: true + Layout.topMargin: Kirigami.Units.largeSpacing + + contentItem: ColumnLayout { + spacing: 0 + + MobileForm.FormCardHeader { + title: i18n("Quick Settings") + subtitle: i18n("Customize the order of quick settings in the pull-down panel.") } + + ListView { + id: enabledQSListView + Layout.fillWidth: true + Layout.preferredHeight: contentHeight + interactive: false + + model: savedQuickSettings.enabledModel + + moveDisplaced: Transition { + YAnimator { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + } + + Component { + id: listItemComponent + + MobileForm.AbstractFormDelegate { + id: qsDelegate + + contentItem: RowLayout { + Kirigami.ListItemDragHandle { + Layout.rightMargin: Kirigami.Units.largeSpacing + listItem: qsDelegate + listView: enabledQSListView + onMoveRequested: savedQuickSettings.enabledModel.moveRow(oldIndex, newIndex) + } + + Kirigami.Icon { + visible: model.icon !== "" + source: model.icon + Layout.rightMargin: (model.icon !== "") ? Kirigami.Units.largeSpacing : 0 + implicitWidth: (model.icon !== "") ? Kirigami.Units.iconSizes.small : 0 + implicitHeight: (model.icon !== "") ? Kirigami.Units.iconSizes.small : 0 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Kirigami.Units.smallSpacing + + QQC2.Label { + Layout.fillWidth: true + text: model.name + elide: Text.ElideRight + } + } + } + } + } + + delegate: Kirigami.DelegateRecycler { + width: enabledQSListView.width + sourceComponent: listItemComponent + } + } + } + + MobileShell.SavedQuickSettings { + id: savedQuickSettings } } } diff --git a/kcms/mobileshell/package/contents/ui/mobileform/AbstractFormDelegate.qml b/kcms/mobileshell/package/contents/ui/mobileform/AbstractFormDelegate.qml new file mode 100644 index 00000000..3afc9987 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/AbstractFormDelegate.qml @@ -0,0 +1,64 @@ +/* + * Copyright 2022 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.kirigami 2.12 as Kirigami + +Control { + id: root + + property bool showSeparator: false + + readonly property bool controlHovered: hoverHandler.hovered + + signal clicked() + signal rightClicked() + + leftPadding: Kirigami.Units.gridUnit + topPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing + bottomPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing + rightPadding: Kirigami.Units.gridUnit + + hoverEnabled: true + background: Rectangle { + color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, mouseArea.pressed ? 0.2 : hoverHandler.hovered ? 0.07 : 0) + + Behavior on color { + ColorAnimation { duration: 70 } + } + + HoverHandler { + id: hoverHandler + } + + Kirigami.Separator { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: root.leftPadding + anchors.rightMargin: root.rightPadding + visible: root.showSeparator + opacity: 0.5 + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: { + if (mouse.button === Qt.RightButton) { + root.rightClicked(); + } else if (mouse.button === Qt.LeftButton) { + root.clicked(); + } + } + } +} + diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormButtonDelegate.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormButtonDelegate.qml new file mode 100644 index 00000000..9605a6b6 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormButtonDelegate.qml @@ -0,0 +1,57 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +AbstractFormDelegate { + id: root + + property string text: "" + property string description: "" + property string iconName: "" + + Layout.fillWidth: true + + contentItem: RowLayout { + Kirigami.Icon { + visible: root.iconName !== "" + source: root.iconName + Layout.rightMargin: (root.iconName !== "") ? Kirigami.Units.largeSpacing : 0 + implicitWidth: (root.iconName !== "") ? Kirigami.Units.iconSizes.small : 0 + implicitHeight: (root.iconName !== "") ? Kirigami.Units.iconSizes.small : 0 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Kirigami.Units.smallSpacing + + Label { + Layout.fillWidth: true + text: root.text + elide: Text.ElideRight + } + + Label { + Layout.fillWidth: true + text: root.description + color: Kirigami.Theme.disabledTextColor + font: Kirigami.Theme.smallFont + elide: Text.ElideRight + visible: root.description !== "" + } + } + + Kirigami.Icon { + Layout.alignment: Qt.AlignRight + source: "arrow-right" + implicitWidth: Kirigami.Units.iconSizes.small + implicitHeight: Kirigami.Units.iconSizes.small + } + } +} diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormCard.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormCard.qml new file mode 100644 index 00000000..a81c0361 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormCard.qml @@ -0,0 +1,80 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +/** + * A single card that is contained in a form. + * + * The height will take the implicit height of the contentItem, while the width + * is expected to be given by the parent. + */ +Item { + id: root + + /** + * The contents of the form card. + */ + property Item contentItem: Item {} + + /** + * The maximum width of the card. + */ + property real maximumWidth: Kirigami.Units.gridUnit * 30 + + property real padding: 0 + property real verticalPadding: padding + property real horizontalPadding: padding + property real topPadding: verticalPadding + property real bottomPadding: verticalPadding + property real leftPadding: horizontalPadding + property real rightPadding: horizontalPadding + + readonly property bool cardWidthRestricted: root.width > root.maximumWidth + + Kirigami.Theme.colorSet: Kirigami.Theme.View + Kirigami.Theme.inherit: false + + implicitHeight: topPadding + bottomPadding + contentItem.implicitHeight + + onContentItemChanged: { + // clear old items + contentItemLoader.children = ""; + + contentItem.parent = contentItemLoader; + contentItem.anchors.fill = contentItemLoader; + contentItemLoader.children.push(contentItem); + } + + Rectangle { + border.color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.15) + border.width: 1 + + // only have card radius if it isn't filling the entire width + radius: root.cardWidthRestricted ? Kirigami.Units.smallSpacing : 0 + color: Kirigami.Theme.backgroundColor + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + anchors.leftMargin: root.cardWidthRestricted ? Math.round((root.width - root.maximumWidth) / 2) : -1 + anchors.rightMargin: root.cardWidthRestricted ? Math.round((root.width - root.maximumWidth) / 2) : -1 + + Item { + id: contentItemLoader + anchors.fill: parent + anchors.leftMargin: root.leftPadding + anchors.rightMargin: root.rightPadding + anchors.topMargin: root.topPadding + anchors.bottomMargin: root.bottomPadding + } + } +} diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormCardHeader.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormCardHeader.qml new file mode 100644 index 00000000..1ebc86a2 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormCardHeader.qml @@ -0,0 +1,52 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +ColumnLayout { + id: root + spacing: 0 + + property string title: "" + property string subtitle: "" + + ColumnLayout { + visible: title !== "" || subtitle !== "" + + Layout.fillWidth: true + Layout.bottomMargin: Kirigami.Units.largeSpacing + Layout.topMargin: Kirigami.Units.largeSpacing + Layout.leftMargin: Kirigami.Units.gridUnit + Layout.rightMargin: Kirigami.Units.gridUnit + + spacing: Kirigami.Units.smallSpacing + + Label { + Layout.fillWidth: true + font.weight: Font.Bold + text: title + visible: title !== "" + wrapMode: Text.Wrap + } + + Label { + color: Kirigami.Theme.disabledTextColor + font: Kirigami.Theme.smallFont + text: subtitle + visible: subtitle !== "" + wrapMode: Text.Wrap + Layout.fillWidth: true + } + } + + Kirigami.Separator { + opacity: 0.5 + Layout.fillWidth: true + } +} diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormCheckBoxDelegate.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormCheckBoxDelegate.qml new file mode 100644 index 00000000..65e63c97 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormCheckBoxDelegate.qml @@ -0,0 +1,36 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +AbstractFormDelegate { + id: root + + property string text: "" + property alias checked: checkBoxItem.checked + property alias checkBox: checkBoxItem + + onClicked: checked = !checked; + + Layout.fillWidth: true + + contentItem: RowLayout { + CheckBox { + id: checkBoxItem + Layout.rightMargin: Kirigami.Units.largeSpacing + } + + Label { + text: root.text + elide: Text.ElideRight + Layout.fillWidth: true + } + } +} + diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormComboBoxDelegate.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormComboBoxDelegate.qml new file mode 100644 index 00000000..068fcc66 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormComboBoxDelegate.qml @@ -0,0 +1,59 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +AbstractFormDelegate { + id: root + + property string text: "" + property string description: "" + + // TODO + property string currentValue: "" + + Layout.fillWidth: true + + contentItem: RowLayout { + ColumnLayout { + Layout.fillWidth: true + spacing: Kirigami.Units.smallSpacing + + Label { + Layout.fillWidth: true + text: root.text + elide: Text.ElideRight + } + + Label { + visible: root.description !== "" + Layout.fillWidth: true + text: root.description + color: Kirigami.Theme.disabledTextColor + font: Kirigami.Theme.smallFont + elide: Text.ElideRight + } + } + + Label { + Layout.alignment: Qt.AlignRight + Layout.rightMargin: Kirigami.Units.smallSpacing + color: Kirigami.Theme.disabledTextColor + text: root.currentValue + } + + Kirigami.Icon { + Layout.alignment: Qt.AlignRight + source: "arrow-down" + implicitWidth: Kirigami.Units.iconSizes.small + implicitHeight: Kirigami.Units.iconSizes.small + } + } +} + diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormRadioButtonDelegate.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormRadioButtonDelegate.qml new file mode 100644 index 00000000..4d6f2386 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormRadioButtonDelegate.qml @@ -0,0 +1,37 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +AbstractFormDelegate { + id: root + + property string text: "" + property alias checked: radioButtonItem.checked + property alias radioButton: radioButtonItem + + onClicked: checked = true; + + Layout.fillWidth: true + + contentItem: RowLayout { + RadioButton { + id: radioButtonItem + Layout.rightMargin: Kirigami.Units.largeSpacing + } + + Label { + text: root.text + elide: Text.ElideRight + Layout.fillWidth: true + } + } +} + + diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormSectionText.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormSectionText.qml new file mode 100644 index 00000000..41b43e60 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormSectionText.qml @@ -0,0 +1,23 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +Label { + color: Kirigami.Theme.disabledTextColor + wrapMode: Label.Wrap + + Layout.maximumWidth: Kirigami.Units.gridUnit * 30 + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Kirigami.Units.gridUnit + Layout.rightMargin: Kirigami.Units.gridUnit + Layout.bottomMargin: Kirigami.Units.largeSpacing + Layout.topMargin: Kirigami.Units.largeSpacing + Layout.fillWidth: true +} diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormSwitchDelegate.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormSwitchDelegate.qml new file mode 100644 index 00000000..229e7631 --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormSwitchDelegate.qml @@ -0,0 +1,50 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +AbstractFormDelegate { + id: root + + property string text: "" + property string description: "" + property alias checked: switchItem.checked + property alias switchControl: switchItem + + onClicked: checked = !checked; + + Layout.fillWidth: true + + contentItem: RowLayout { + ColumnLayout { + Layout.fillWidth: true + spacing: Kirigami.Units.smallSpacing + + Label { + Layout.fillWidth: true + text: root.text + elide: Text.ElideRight + } + + Label { + visible: root.description !== "" + Layout.fillWidth: true + text: root.description + color: Kirigami.Theme.disabledTextColor + font: Kirigami.Theme.smallFont + elide: Text.ElideRight + } + } + + Switch { + id: switchItem + Layout.leftMargin: Kirigami.Units.largeSpacing + } + } +} diff --git a/kcms/mobileshell/package/contents/ui/mobileform/FormTextDelegate.qml b/kcms/mobileshell/package/contents/ui/mobileform/FormTextDelegate.qml new file mode 100644 index 00000000..75df84bc --- /dev/null +++ b/kcms/mobileshell/package/contents/ui/mobileform/FormTextDelegate.qml @@ -0,0 +1,53 @@ +/* + * Copyright 2022 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.kirigami 2.19 as Kirigami + +AbstractFormDelegate { + id: root + + property string text: "" + property string description: "" + property string iconName: "" + + Layout.fillWidth: true + + background: Item {} + + contentItem: RowLayout { + Kirigami.Icon { + visible: root.iconName !== "" + source: root.iconName + Layout.rightMargin: (root.iconName !== "") ? Kirigami.Units.largeSpacing : 0 + implicitWidth: (root.iconName !== "") ? Kirigami.Units.iconSizes.small : 0 + implicitHeight: (root.iconName !== "") ? Kirigami.Units.iconSizes.small : 0 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Kirigami.Units.smallSpacing + + Label { + Layout.fillWidth: true + text: root.text + elide: Text.ElideRight + } + + Label { + Layout.fillWidth: true + text: root.description + color: Kirigami.Theme.disabledTextColor + font: Kirigami.Theme.smallFont + elide: Text.ElideRight + visible: root.description !== "" + } + } + } +} + diff --git a/libmobileshell/mobileshellsettings.cpp b/libmobileshell/mobileshellsettings.cpp index f12adb68..32433859 100644 --- a/libmobileshell/mobileshellsettings.cpp +++ b/libmobileshell/mobileshellsettings.cpp @@ -6,6 +6,8 @@ #include "mobileshellsettings.h" +#include + using namespace MobileShell; const QString CONFIG_FILE = QStringLiteral("plasmamobilerc"); @@ -25,6 +27,7 @@ MobileShellSettings::MobileShellSettings(QObject *parent) m_configWatcher = KConfigWatcher::create(m_config); connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) -> void { + qDebug() << "config changed"; // TODO if (group.name() == GENERAL_CONFIG_GROUP) { Q_EMIT navigationPanelEnabledChanged(); } else if (group.name() == QUICKSETTINGS_CONFIG_GROUP) { @@ -74,7 +77,7 @@ QList MobileShellSettings::enabledQuickSettings() const void MobileShellSettings::setEnabledQuickSettings(QList &list) { - auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP}; + auto group = KConfigGroup{m_config, QUICKSETTINGS_CONFIG_GROUP}; group.writeEntry("enabledQuickSettings", list, KConfigGroup::Notify); m_config->sync(); } @@ -87,7 +90,7 @@ QList MobileShellSettings::disabledQuickSettings() const void MobileShellSettings::setDisabledQuickSettings(QList &list) { - auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP}; + auto group = KConfigGroup{m_config, QUICKSETTINGS_CONFIG_GROUP}; group.writeEntry("disabledQuickSettings", list, KConfigGroup::Notify); m_config->sync(); } diff --git a/libmobileshell/quicksettingsmodel.cpp b/libmobileshell/quicksettingsmodel.cpp index b98b15e9..889ca393 100644 --- a/libmobileshell/quicksettingsmodel.cpp +++ b/libmobileshell/quicksettingsmodel.cpp @@ -61,6 +61,8 @@ void QuickSettingsModel::loadQuickSettings() return; } + beginResetModel(); + for (auto *quickSetting : m_quickSettings) { quickSetting->deleteLater(); } @@ -72,7 +74,7 @@ void QuickSettingsModel::loadQuickSettings() // loop through enabled quick settings metadata for (const auto &metaData : m_savedQuickSettings->enabledQuickSettingsModel()->list()) { // load kpackage - KPackage::Package package = KPackage::PackageLoader::self()->loadPackage("KPackage/GenericQML", QFileInfo(metaData.fileName()).path()); + KPackage::Package package = KPackage::PackageLoader::self()->loadPackage("KPackage/GenericQML", QFileInfo(metaData->fileName()).path()); if (!package.isValid()) { continue; } @@ -91,10 +93,12 @@ void QuickSettingsModel::loadQuickSettings() } delete created; } else { - qDebug() << "Loaded quicksetting" << metaData.fileName(); + qDebug() << "Loaded quicksetting" << metaData->fileName(); m_quickSettings.push_back(createdSetting); } } delete c; + + endResetModel(); } diff --git a/libmobileshell/savedquicksettings.cpp b/libmobileshell/savedquicksettings.cpp index 31ad143e..6492995e 100644 --- a/libmobileshell/savedquicksettings.cpp +++ b/libmobileshell/savedquicksettings.cpp @@ -17,7 +17,14 @@ SavedQuickSettings::SavedQuickSettings(QObject *parent) , m_disabledPackages{} , m_enabledQSModel{new SavedQuickSettingsModel{this}} , m_disabledQSModel{new SavedQuickSettingsModel{this}} + , m_updateTimer{new QTimer{this}} { + // throttle model updates from config, to avoid performance issues with fast reloading + m_updateTimer->setInterval(2000); + connect(m_updateTimer, &QTimer::timeout, this, [this]() { + refreshModel(); + }); + // load quicksettings packages auto packages = KPackage::PackageLoader::self()->listPackages(QStringLiteral("KPackage/GenericQML"), "plasma/quicksettings"); @@ -27,29 +34,33 @@ SavedQuickSettings::SavedQuickSettings(QObject *parent) qWarning() << "Quick setting package invalid:" << metaData.fileName(); continue; } - m_validPackages.push_back(metaData); + m_validPackages.push_back(new KPluginMetaData{metaData}); } // subscribe to config changes connect(m_settings, &MobileShellSettings::enabledQuickSettingsChanged, this, [this]() { - refreshModel(); + m_updateTimer->start(); }); connect(m_settings, &MobileShellSettings::disabledQuickSettingsChanged, this, [this]() { - refreshModel(); + m_updateTimer->start(); }); // subscribe to model changes - connect(m_enabledQSModel, &SavedQuickSettingsModel::dataUpdated, this, [this](QList data) -> void { + connect(m_enabledQSModel, &SavedQuickSettingsModel::dataUpdated, this, [this](QList data) -> void { m_enabledPackages.clear(); for (auto metaData : data) { m_enabledPackages.push_back(metaData); } + + saveModel(); }); - connect(m_disabledQSModel, &SavedQuickSettingsModel::dataUpdated, this, [this](QList data) -> void { + connect(m_disabledQSModel, &SavedQuickSettingsModel::dataUpdated, this, [this](QList data) -> void { m_disabledPackages.clear(); for (auto metaData : data) { m_disabledPackages.push_back(metaData); } + + saveModel(); }); // load @@ -77,7 +88,7 @@ void SavedQuickSettings::refreshModel() // add enabled quick settings in order for (const QString &pluginId : enabledQS) { for (auto &metaData : m_validPackages) { - if (pluginId == metaData.pluginId()) { + if (pluginId == metaData->pluginId()) { m_enabledPackages.push_back(metaData); break; } @@ -87,7 +98,7 @@ void SavedQuickSettings::refreshModel() // add disabled quick settings in order for (const QString &pluginId : disabledQS) { for (auto &metaData : m_validPackages) { - if (pluginId == metaData.pluginId()) { + if (pluginId == metaData->pluginId()) { m_disabledPackages.push_back(metaData); break; } @@ -96,7 +107,7 @@ void SavedQuickSettings::refreshModel() // add undefined quick settings to the back of enabled quick settings for (auto &metaData : m_validPackages) { - if (!enabledQS.contains(metaData.pluginId()) && !disabledQS.contains(metaData.pluginId())) { + if (!enabledQS.contains(metaData->pluginId()) && !disabledQS.contains(metaData->pluginId())) { m_enabledPackages.push_back(metaData); } } @@ -111,10 +122,10 @@ void SavedQuickSettings::saveModel() QList disabledQS; for (auto &metaData : m_enabledPackages) { - enabledQS.push_back(metaData.pluginId()); + enabledQS.push_back(metaData->pluginId()); } for (auto &metaData : m_disabledPackages) { - disabledQS.push_back(metaData.pluginId()); + disabledQS.push_back(metaData->pluginId()); } m_settings->setEnabledQuickSettings(enabledQS); diff --git a/libmobileshell/savedquicksettings.h b/libmobileshell/savedquicksettings.h index 1d828850..3a2a1c86 100644 --- a/libmobileshell/savedquicksettings.h +++ b/libmobileshell/savedquicksettings.h @@ -13,6 +13,7 @@ #include #include +#include #include "mobileshell_export.h" @@ -22,6 +23,8 @@ namespace MobileShell class MOBILESHELL_EXPORT SavedQuickSettings : public QObject { Q_OBJECT + Q_PROPERTY(SavedQuickSettingsModel *enabledModel READ enabledQuickSettingsModel CONSTANT) + Q_PROPERTY(SavedQuickSettingsModel *disabledModel READ disabledQuickSettingsModel CONSTANT) public: SavedQuickSettings(QObject *parent = nullptr); @@ -34,12 +37,14 @@ private: void saveModel(); MobileShellSettings *m_settings; - QList m_validPackages; - QList m_enabledPackages; - QList m_disabledPackages; + QList m_validPackages; + QList m_enabledPackages; + QList m_disabledPackages; SavedQuickSettingsModel *m_enabledQSModel; SavedQuickSettingsModel *m_disabledQSModel; + + QTimer *m_updateTimer; }; } // namespace MobileShell diff --git a/libmobileshell/savedquicksettingsmodel.cpp b/libmobileshell/savedquicksettingsmodel.cpp index c824e20a..807b89ae 100644 --- a/libmobileshell/savedquicksettingsmodel.cpp +++ b/libmobileshell/savedquicksettingsmodel.cpp @@ -17,11 +17,11 @@ QVariant SavedQuickSettingsModel::data(const QModelIndex &index, int role) const } if (role == NameRole) { - return m_data[index.row()].name(); + return m_data[index.row()]->name(); } else if (role == IconRole) { - return QString(); // TODO m_data[index.row()].icon(); + return m_data[index.row()]->iconName(); } else if (role == IdRole) { - return m_data[index.row()].pluginId(); + return m_data[index.row()]->pluginId(); } return QVariant(); } @@ -43,14 +43,18 @@ void SavedQuickSettingsModel::moveRow(int oldIndex, int newIndex) return; } + if (oldIndex < newIndex) { + ++newIndex; + } + Q_EMIT beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex); - std::iter_swap(m_data.begin() + oldIndex, m_data.end() + newIndex); + std::iter_swap(m_data.begin() + oldIndex, m_data.begin() + newIndex); Q_EMIT endMoveRows(); Q_EMIT dataUpdated(m_data); } -void SavedQuickSettingsModel::insertRow(KPluginMetaData metaData, int index) +void SavedQuickSettingsModel::insertRow(KPluginMetaData *metaData, int index) { Q_EMIT beginInsertRows(QModelIndex(), index, index); m_data.insert(index, metaData); @@ -72,12 +76,12 @@ void SavedQuickSettingsModel::removeRow(int index) Q_EMIT dataUpdated(m_data); } -QList SavedQuickSettingsModel::list() const +QList SavedQuickSettingsModel::list() const { return m_data; } -void SavedQuickSettingsModel::updateData(QList data) +void SavedQuickSettingsModel::updateData(QList data) { Q_EMIT beginResetModel(); diff --git a/libmobileshell/savedquicksettingsmodel.h b/libmobileshell/savedquicksettingsmodel.h index 0cc6003e..e0110adc 100644 --- a/libmobileshell/savedquicksettingsmodel.h +++ b/libmobileshell/savedquicksettingsmodel.h @@ -35,19 +35,19 @@ public: QHash roleNames() const override; Q_INVOKABLE void moveRow(int oldIndex, int newIndex); - Q_INVOKABLE void insertRow(KPluginMetaData metaData, int index); + Q_INVOKABLE void insertRow(KPluginMetaData *metaData, int index); Q_INVOKABLE void removeRow(int index); - QList list() const; + QList list() const; public Q_SLOTS: - void updateData(QList data); + void updateData(QList data); Q_SIGNALS: - void dataUpdated(QList data); + void dataUpdated(QList data); private: - QList m_data; + QList m_data; }; } // namespace MobileShell diff --git a/quicksettings/mobiledata/metadata.desktop b/quicksettings/mobiledata/metadata.desktop index 02e95198..0abc5e87 100644 --- a/quicksettings/mobiledata/metadata.desktop +++ b/quicksettings/mobiledata/metadata.desktop @@ -3,7 +3,7 @@ [Desktop Entry] Name=Mobile Data -Icon=flashlight-on +Icon=network-modem Description=Location quick setting Type=Service diff --git a/quicksettings/wifi/metadata.desktop b/quicksettings/wifi/metadata.desktop index ba81116d..6900bebe 100644 --- a/quicksettings/wifi/metadata.desktop +++ b/quicksettings/wifi/metadata.desktop @@ -3,7 +3,7 @@ [Desktop Entry] Name=Wi-Fi -Icon=flashlight-on +Icon=network-wireless-signal Description=Wi-Fi quick setting Type=Service