diff --git a/shell/contents/configuration/AppletConfiguration.qml b/shell/contents/configuration/AppletConfiguration.qml index a39183a9..2d3f32da 100644 --- a/shell/contents/configuration/AppletConfiguration.qml +++ b/shell/contents/configuration/AppletConfiguration.qml @@ -12,14 +12,18 @@ import org.kde.kirigami 2.19 as Kirigami import org.kde.plasma.configuration 2.0 import org.kde.kitemmodels 1.0 as KItemModels -Rectangle { +import './private' + +/** + * This component is loaded by libplasma when the "configuration window" is requested for an applet. + */ +Item { id: root LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true - color: "transparent" - //BEGIN properties + // Properties filled in or needed by libplasma property bool isContainment: false property alias app: appLoader.item @@ -47,105 +51,46 @@ Rectangle { //END model -//BEGIN functions - - function saveConfig() { - if (app.pageStack.currentItem.saveConfig) { - app.pageStack.currentItem.saveConfig() - } - for (var key in Plasmoid.configuration) { - if (app.pageStack.currentItem["cfg_"+key] !== undefined) { - Plasmoid.configuration[key] = app.pageStack.currentItem["cfg_"+key] - } - } - } - - function configurationHasChanged() { - for (var key in Plasmoid.configuration) { - if (app.pageStack.currentItem["cfg_"+key] !== undefined) { - //for objects == doesn't work - if (typeof Plasmoid.configuration[key] == 'object') { - for (var i in Plasmoid.configuration[key]) { - if (Plasmoid.configuration[key][i] != app.pageStack.currentItem["cfg_"+key][i]) { - return true; - } - } - return false; - } else if (app.pageStack.currentItem["cfg_"+key] != Plasmoid.configuration[key]) { - return true; - } - } - } - return false; - } - - - function settingValueChanged() { - if (app.pageStack.currentItem.saveConfig !== undefined) { - app.pageStack.currentItem.saveConfig(); - } else { - root.saveConfig(); - } - } - - function pushReplace(item, config) { - let page; - if (app.pageStack.depth === 0) { - page = app.pageStack.push(item, config); - } else { - page = app.pageStack.replace(item, config); - } - app.currentConfigPage = page; - } - function open(item) { - app.isAboutPage = false; if (item.source) { - app.isAboutPage = item.source === "AboutPlugin.qml"; - pushReplace(Qt.resolvedUrl("ConfigurationAppletPage.qml"), {configItem: item, title: item.name}); + app.pageStack.push(Qt.resolvedUrl("private/ConfigurationAppletPage.qml"), {configItem: item, title: item.name}); } else if (item.kcm) { - pushReplace(configurationKcmPageComponent, {kcm: item.kcm, internalPage: item.kcm.mainUi}); - } else { - app.pageStack.pop(); + app.pageStack.push(configurationKcmPageComponent, {kcm: item.kcm, internalPage: item.kcm.mainUi}); } } -//END functions - - -//BEGIN connections - - Connections { - target: root.Window.window - function onVisibleChanged() { - if (root.Window.window.visible) { - root.Window.window.showMaximized(); - } - } + Binding { + // Window bindings + root.Window.window.flags: Qt.FramelessWindowHint + root.Window.window.visibility: Window.Maximized } -//END connections - -//BEGIN UI components - Component { id: configurationKcmPageComponent ConfigurationKcmPage {} } + Component { + id: configListPageComponent + ConfigListPage { + onRequestOpen: (delegate) => root.open(delegate); + } + } + Loader { id: appLoader anchors.fill: parent asynchronous: true active: root.loadApp + + // Load first page onLoaded: { - // if we are a containment then the first item will be ConfigurationContainmentAppearance - // if the applet does not have own configs then the first item will be Shortcuts - if (isContainment || !configDialog.configModel || configDialog.configModel.count === 0) { - root.open(root.globalConfigModel.get(0)) - } else { - root.open(configDialog.configModel.get(0)) - } + // Push config list page + app.pageStack.push(configListPageComponent, { + title: i18nc("The title of the applet configuration window", "Configure %1", Plasmoid.metaData.name), + model1: configDialogFilterModel, + model2: root.globalConfigModel + }); root.appLoaded(); } @@ -154,90 +99,50 @@ Rectangle { id: app anchors.fill: parent - // animation on show - opacity: 0 - NumberAnimation on opacity { - to: 1 - running: true - duration: Kirigami.Units.longDuration - easing.type: Easing.InOutQuad + pageStack { + globalToolBar { + canContainHandles: true + style: Kirigami.ApplicationHeaderStyle.ToolBar + showNavigationButtons: Kirigami.ApplicationHeaderStyle.ShowBackButton + } + popHiddenPages: true + columnView.columnResizeMode: Kirigami.ColumnView.SingleColumn } - pageStack.globalToolBar.canContainHandles: true - pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.ToolBar - pageStack.globalToolBar.showNavigationButtons: Kirigami.ApplicationHeaderStyle.ShowBackButton; - - property var currentConfigPage: null - property bool isAboutPage: false - - // pop pages when not in use + // Implement open/close animation Connections { - target: app.pageStack - function onCurrentIndexChanged() { - // wait for animation to finish before popping pages - timer.restart(); - } - } + target: root.Window.window - Timer { - id: timer - interval: 300 - onTriggered: { - let currentIndex = app.pageStack.currentIndex; - while (app.pageStack.depth > (currentIndex + 1) && currentIndex >= 0) { - app.pageStack.pop(); + function onVisibleChanged() { + if (visible) { + opacityAnim.to = 1; + opacityAnim.restart(); + } + } + + function onClosing(close) { + if (app.opacity !== 0) { + close.accepted = false; + opacityAnim.to = 0; + opacityAnim.restart(); } } } - footer: Kirigami.NavigationTabBar { - id: footerBar - visible: count > 1 - height: visible ? implicitHeight : 0 - Repeater { - model: root.isContainment ? globalConfigModel : undefined - delegate: configCategoryDelegate - } - Repeater { - model: configDialogFilterModel - delegate: configCategoryDelegate - } - Repeater { - model: !root.isContainment ? globalConfigModel : undefined - delegate: configCategoryDelegate - } - } + opacity: 0 + scale: 0.7 + 0.3 * app.opacity - Component { - id: configCategoryDelegate - Kirigami.NavigationTabButton { - icon.name: model.icon - text: model.name - width: footerBar.buttonWidth - QQC2.ButtonGroup.group: footerBar.tabGroup - - onClicked: { - if (checked) { - root.open(model); - } - } - - checked: { - if (app.pageStack.currentItem) { - if (model.kcm && app.pageStack.currentItem.kcm) { - return model.kcm == app.pageStack.currentItem.kcm; - } else if (app.pageStack.currentItem.configItem) { - return model.source == app.pageStack.currentItem.configItem.source; - } else { - return app.pageStack.currentItem.source == Qt.resolvedUrl(model.source); - } - } - return false; + NumberAnimation on opacity { + id: opacityAnim + duration: Kirigami.Units.longDuration + easing.type: Easing.OutCubic + onFinished: { + if (app.opacity === 0) { + root.Window.window.close(); } } } } } -//END UI components } diff --git a/shell/contents/configuration/ConfigurationAppletPage.qml b/shell/contents/configuration/ConfigurationAppletPage.qml deleted file mode 100644 index 1eb01339..00000000 --- a/shell/contents/configuration/ConfigurationAppletPage.qml +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-FileCopyrightText: 2020 Nicolas Fella -// SPDX-License-Identifier: GPL-2.0-or-later - -import QtQuick 2.0 - -import org.kde.plasma.plasmoid -import org.kde.kirigami 2.10 as Kirigami - -Kirigami.ScrollablePage { - id: root - - title: configItem.name - - required property var configItem - - signal settingValueChanged() - onSettingValueChanged: saveConfig() // we save config immediately on mobile - - function saveConfig() { - for (let key in Plasmoid.configuration) { - if (loader.item["cfg_" + key] != undefined) { - Plasmoid.configuration[key] = loader.item["cfg_" + key] - } - } - - // For ConfigurationContainmentActions.qml - if (loader.item.hasOwnProperty("saveConfig")) { - loader.item.saveConfig() - } - } - - implicitHeight: loader.height - - padding: Kirigami.Units.largeSpacing - bottomPadding: 0 - - Loader { - id: loader - width: parent.width - // HACK the height of the loader is based on the implicitHeight of the content. - // Unfortunately not all content items have a sensible implicitHeight. - // If it is zero fall back to the height of its children - // Also make it at least as high as the page itself. Some existing configs assume they fill the whole space - // TODO KF6 clean this up by making all configs based on SimpleKCM/ScrollViewKCM/GridViewKCM - height: { - if (item) { - return Math.max(root.availableHeight, item.implicitHeight ? item.implicitHeight : item.childrenRect.height); - } else { - return root.availableHeight; - } - } - - Component.onCompleted: { - const plasmoidConfig = Plasmoid.configuration - - const props = {} - for (let key in plasmoidConfig) { - props["cfg_" + key] = Plasmoid.configuration[key] - } - - setSource(configItem.source, props) - } - - onLoaded: { - const plasmoidConfig = Plasmoid.configuration; - - for (let key in plasmoidConfig) { - const changedSignal = item["cfg_" + key + "Changed"] - if (changedSignal) { - changedSignal.connect(root.settingValueChanged) - } - } - - const configurationChangedSignal = item.configurationChanged - if (configurationChangedSignal) { - configurationChangedSignal.connect(root.settingValueChanged) - } - - var unsavedChangesChangedSignal = item.unsavedChangesChanged - if (unsavedChangesChangedSignal) { - unsavedChangesChangedSignal.connect( () => { - if (item.unsavedChanges) { - root.settingValueChanged() - } - }) - } - } - } -} diff --git a/shell/contents/configuration/ContainmentConfiguration.qml b/shell/contents/configuration/ContainmentConfiguration.qml index b31bc232..9d87f62f 100644 --- a/shell/contents/configuration/ContainmentConfiguration.qml +++ b/shell/contents/configuration/ContainmentConfiguration.qml @@ -13,27 +13,29 @@ import org.kde.plasma.core as PlasmaCore import org.kde.plasma.configuration 2.0 import org.kde.ksvg 1.0 as KSvg +/** + * This component is loaded by libplasma when the "configuration window" is requested for a containment. + */ AppletConfiguration { id: root isContainment: true loadApp: true - readonly property bool horizontal: root.width > root.height - - onAppLoaded: { - app.width = root.width < root.height ? root.width : Math.min(root.width, Math.max(app.implicitWidth, Kirigami.Units.gridUnit * 45)); - app.height = Math.min(root.height, Math.max(app.implicitHeight, Kirigami.Units.gridUnit * 29)); - } - //BEGIN model globalConfigModel: globalContainmentConfigModel ConfigModel { id: globalContainmentConfigModel ConfigCategory { - name: i18nd("plasma_shell_org.kde.plasma.desktop", "Wallpaper") - icon: "preferences-desktop-wallpaper" - source: "ConfigurationContainmentAppearance.qml" + name: i18n("Wallpaper") + icon: "viewimage-symbolic" + source: "ChangeWallpaperModule.qml" // This is a relative path from inside private (since loading is invoked from there) + } + ConfigCategory { + name: i18n("Change Homescreen") + icon: "exchange-positions" + source: "ChangeContainmentModule.qml" // This is a relative path from inside private (since loading is invoked from there) + visible: configDialog.containmentPluginsConfigModel.count > 1 } } //END model diff --git a/shell/contents/configuration/README.md b/shell/contents/configuration/README.md new file mode 100644 index 00000000..c237de86 --- /dev/null +++ b/shell/contents/configuration/README.md @@ -0,0 +1,8 @@ + + +This folder contains source files for implementing the configuration window for applets/containments (including homescreens). + +[libplasma](https://invent.kde.org/frameworks/libplasma) loads either `AppletConfiguration.qml` or `ContainmentConfiguration.qml` (depending on if its an applet or containment) from this folder when requested by the shell, which in turn initializes the config window. diff --git a/shell/contents/configuration/private/ChangeContainmentModule.qml b/shell/contents/configuration/private/ChangeContainmentModule.qml new file mode 100644 index 00000000..70b98f55 --- /dev/null +++ b/shell/contents/configuration/private/ChangeContainmentModule.qml @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2025 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +import QtQuick +import QtQuick.Controls as QQC2 +import QtQuick.Layouts + +import org.kde.plasma.configuration +import org.kde.plasma.plasmoid +import org.kde.kirigami as Kirigami +import org.kde.kirigamiaddons.formcard as FormCard + +ColumnLayout { + id: root + + property string containmentPlugin: configDialog.containmentPlugin + signal configurationChanged // No need to emit, because containment changes apply immediately + +//BEGIN functions + function saveConfig() { + configDialog.containmentPlugin = root.containmentPlugin + } +//END functions + + FormCard.FormHeader { + title: i18n("Select Homescreen") + } + + FormCard.FormCard { + Repeater { + model: configDialog.containmentPluginsConfigModel + delegate: FormCard.FormRadioDelegate { + enabled: !Plasmoid.immutable + text: model.name + checked: configDialog.containmentPlugin === model.pluginName + + // Always restore binding + onCheckedChanged: checked = Qt.binding(() => configDialog.containmentPlugin === model.pluginName); + + onClicked: { + if (root.containmentPlugin === model.pluginName) { + return; + } + root.containmentPlugin = model.pluginName; + confirmationDialog.name = model.name; + confirmationDialog.open(); + } + } + } + } + + Kirigami.PromptDialog { + id: confirmationDialog + standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel + + property string name + + title: i18n("Change homescreen to %1?", name) + subtitle: i18n("Your current homescreen's settings are saved, and will be restored if you switch back.") + + onAccepted: { + root.saveConfig(); + close(); + } + onRejected: { + root.containmentPlugin = configDialog.containmentPlugin; + } + } + + Item { Layout.fillHeight: true } +} + diff --git a/shell/contents/configuration/ConfigurationContainmentAppearance.qml b/shell/contents/configuration/private/ChangeWallpaperModule.qml similarity index 57% rename from shell/contents/configuration/ConfigurationContainmentAppearance.qml rename to shell/contents/configuration/private/ChangeWallpaperModule.qml index 0c62fb04..02d4b1a1 100644 --- a/shell/contents/configuration/ConfigurationContainmentAppearance.qml +++ b/shell/contents/configuration/private/ChangeWallpaperModule.qml @@ -1,8 +1,6 @@ -/* - * SPDX-FileCopyrightText: 2013 Marco Martin - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ +// SPDX-FileCopyrightText: 2013 Marco Martin +// SPDX-FileCopyrightText: 2025 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later import QtQuick 2.15 import org.kde.plasma.configuration 2.0 @@ -19,7 +17,6 @@ ColumnLayout { spacing: 0 property string currentWallpaper: "" - property string containmentPlugin: configDialog.containmentPlugin signal configurationChanged //BEGIN functions @@ -34,59 +31,17 @@ ColumnLayout { } configDialog.currentWallpaper = root.currentWallpaper; configDialog.applyWallpaper() - configDialog.containmentPlugin = root.containmentPlugin } //END functions - Kirigami.InlineMessage { - Layout.alignment: Qt.AlignTop - visible: Plasmoid.immutable || animating - text: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout changes have been restricted by the system administrator") - showCloseButton: true - Layout.fillWidth: true - Layout.leftMargin: Kirigami.Units.smallSpacing - Layout.rightMargin: Kirigami.Units.smallSpacing - Layout.bottomMargin: Kirigami.Units.smallSpacing * 2 // we need this because ColumnLayout's spacing is 0 - } - ColumnLayout { id: generalConfig spacing: 0 - Layout.alignment: Qt.AlignTop Layout.fillWidth: true - - FormCard.FormHeader { - title: i18n("General") - } + Layout.topMargin: Kirigami.Units.largeSpacing + Layout.bottomMargin: Kirigami.Units.largeSpacing FormCard.FormCard { - FormCard.FormComboBoxDelegate { - id: layoutSelectComboBox - enabled: !Plasmoid.immutable - text: i18nd("plasma_shell_org.kde.plasma.desktop", "Homescreen Layout") - description: i18n("The homescreen layout to use.") - visible: model.count > 1 // only show if there are multiple plugins - - model: configDialog.containmentPluginsConfigModel - textRole: "name" - valueRole: "pluginName" - currentIndex: determineCurrentIndex() - onCurrentIndexChanged: { - root.containmentPlugin = configDialog.containmentPluginsConfigModel.get(currentIndex).pluginName; - } - - function determineCurrentIndex() { - for (var i = 0; i < configDialog.containmentPluginsConfigModel.count; ++i) { - var data = configDialog.containmentPluginsConfigModel.get(i); - if (configDialog.containmentPlugin === data.pluginName) { - return i; - } - } - return -1; - } - } - - FormCard.FormDelegateSeparator { above: layoutSelectComboBox; below: wallpaperPluginSelectComboBox } FormCard.FormComboBoxDelegate { id: wallpaperPluginSelectComboBox @@ -138,30 +93,6 @@ ColumnLayout { } } - ColumnLayout { - id: switchContainmentWarning - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - visible: configDialog.containmentPlugin !== root.containmentPlugin - QQC2.Label { - Layout.fillWidth: true - text: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout changes must be applied before other changes can be made") - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - } - QQC2.Button { - Layout.alignment: Qt.AlignHCenter - text: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply now") - onClicked: saveConfig() - } - } - - Item { - Layout.alignment: Qt.AlignTop - Layout.fillHeight: switchContainmentWarning.visible - visible: switchContainmentWarning.visible - } - Item { id: emptyConfig Layout.alignment: Qt.AlignTop @@ -172,11 +103,9 @@ ColumnLayout { Layout.alignment: Qt.AlignTop Layout.fillHeight: true - Layout.maximumHeight: root.height - generalConfig.height - 70 // HACK: wallpaper configs seem to go over the provisioned height + Layout.maximumHeight: root.height - generalConfig.height - Kirigami.Units.smallSpacing // HACK: wallpaper configs seem to go over the provisioned height Layout.fillWidth: true - visible: !switchContainmentWarning.visible - // Bug 360862: if wallpaper has no config, sourceFile will be "" // so we wouldn't load emptyConfig and break all over the place // hence set it to some random value initially diff --git a/shell/contents/configuration/private/ConfigListPage.qml b/shell/contents/configuration/private/ConfigListPage.qml new file mode 100644 index 00000000..35382769 --- /dev/null +++ b/shell/contents/configuration/private/ConfigListPage.qml @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2025 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +import QtQuick +import QtQuick.Controls as QQC2 +import QtQuick.Layouts + +import org.kde.plasma.plasmoid +import org.kde.kirigami as Kirigami +import org.kde.plasma.configuration +import org.kde.kitemmodels as KItemModels + +Kirigami.ScrollablePage { + id: root + property alias model1: repeater1.model + property alias model2: repeater2.model + + topPadding: 0 + leftPadding: 0 + rightPadding: 0 + bottomPadding: 0 + + titleDelegate: RowLayout { + // Add close button + QQC2.ToolButton { + Layout.leftMargin: -Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing + icon.name: "arrow-left" + onClicked: root.Window.window.close() + } + + Kirigami.Heading { + level: 1 + text: root.title + } + } + + signal requestOpen(var delegate) + + ColumnLayout { + spacing: 0 + + Kirigami.InlineMessage { + Layout.alignment: Qt.AlignTop + visible: Plasmoid.immutable + text: i18n("Layout changes have been restricted by the system administrator") + showCloseButton: true + Layout.fillWidth: true + Layout.leftMargin: Kirigami.Units.smallSpacing + Layout.rightMargin: Kirigami.Units.smallSpacing + Layout.bottomMargin: Kirigami.Units.smallSpacing * 2 // we need this because ColumnLayout's spacing is 0 + } + + Repeater { + id: repeater1 + + delegate: QQC2.ItemDelegate { + icon.name: model.icon + text: model.name + Layout.fillWidth: true + + onClicked: root.requestOpen(model) + } + } + + Repeater { + id: repeater2 + + delegate: QQC2.ItemDelegate { + icon.name: model.icon + text: model.name + Layout.fillWidth: true + + onClicked: root.requestOpen(model) + } + } + } +} diff --git a/shell/contents/configuration/private/ConfigurationAppletPage.qml b/shell/contents/configuration/private/ConfigurationAppletPage.qml new file mode 100644 index 00000000..5dde6d37 --- /dev/null +++ b/shell/contents/configuration/private/ConfigurationAppletPage.qml @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2020 Nicolas Fella +// SPDX-License-Identifier: GPL-2.0-or-later + +import QtQuick 2.0 + +import org.kde.plasma.plasmoid +import org.kde.kirigami 2.10 as Kirigami + +Kirigami.Page { + id: root + + required property var configItem + + signal settingValueChanged() + onSettingValueChanged: saveConfig() // we save config immediately on mobile + + title: configItem.name + + topPadding: 0 + leftPadding: 0 + rightPadding: 0 + bottomPadding: 0 + + function saveConfig() { + for (let key in Plasmoid.configuration) { + if (loader.item["cfg_" + key] != undefined) { + Plasmoid.configuration[key] = loader.item["cfg_" + key] + } + } + + // For ConfigurationContainmentActions.qml + if (loader.item.hasOwnProperty("saveConfig")) { + loader.item.saveConfig() + } + } + + data: [ + Loader { + id: loader + + Component.onCompleted: { + const plasmoidConfig = Plasmoid.configuration + + const props = {} + for (let key in plasmoidConfig) { + props["cfg_" + key] = Plasmoid.configuration[key] + } + + // Inject configurable config values + setSource(configItem.source, props) + } + + onLoaded: { + item.parent = root.contentItem; + item.anchors.fill = root.contentItem; + + const plasmoidConfig = Plasmoid.configuration; + + for (let key in plasmoidConfig) { + const changedSignal = item["cfg_" + key + "Changed"] + if (changedSignal) { + changedSignal.connect(root.settingValueChanged) + } + } + + const configurationChangedSignal = item.configurationChanged + if (configurationChangedSignal) { + configurationChangedSignal.connect(root.settingValueChanged) + } + + var unsavedChangesChangedSignal = item.unsavedChangesChanged + if (unsavedChangesChangedSignal) { + unsavedChangesChangedSignal.connect( () => { + if (item.unsavedChanges) { + root.settingValueChanged() + } + }) + } + } + } + ] +} diff --git a/shell/contents/configuration/ConfigurationKcmPage.qml b/shell/contents/configuration/private/ConfigurationKcmPage.qml similarity index 79% rename from shell/contents/configuration/ConfigurationKcmPage.qml rename to shell/contents/configuration/private/ConfigurationKcmPage.qml index 46263612..a5851a91 100644 --- a/shell/contents/configuration/ConfigurationKcmPage.qml +++ b/shell/contents/configuration/private/ConfigurationKcmPage.qml @@ -16,11 +16,13 @@ Kirigami.Page { signal settingValueChanged() onSettingValueChanged: saveConfig(); // we save config immediately on mobile - title: kcm.name + title: internalPage.title ? internalPage.title : kcm.name + topPadding: 0 leftPadding: 0 rightPadding: 0 bottomPadding: 0 + flickable: internalPage.flickable actions: [ internalPage.actions.main, @@ -38,7 +40,7 @@ Kirigami.Page { } Component.onCompleted: { - kcm.load() + kcm.load(); } function saveConfig() { @@ -48,14 +50,21 @@ Kirigami.Page { data: [ Connections { target: kcm - onPagePushed: { + function onPagePushed() { app.pageStack.push(configurationKcmPageComponent.createObject(app.pageStack, {"kcm": kcm, "internalPage": page})); } - onPageRemoved: app.pageStack.pop(); + function onPageRemoved() { + app.pageStack.pop(); + } + function onNeedsSaveChanged() { + if (kcm.needsSave) { + container.settingValueChanged() + } + } }, Connections { target: app.pageStack - onPageRemoved: { + function onPageRemoved() { if (kcm.needsSave) { kcm.save() } @@ -65,12 +74,4 @@ Kirigami.Page { } } ] - Connections { - target: kcm - function onNeedsSaveChanged() { - if (kcm.needsSave) { - container.settingValueChanged() - } - } - } }