diff --git a/KomplexHubContent/pages/CMakeLists.txt b/KomplexHubContent/pages/CMakeLists.txt index 0b51fe9..d7842de 100644 --- a/KomplexHubContent/pages/CMakeLists.txt +++ b/KomplexHubContent/pages/CMakeLists.txt @@ -17,4 +17,5 @@ qt6_add_qml_module(KomplexHubPages "FeaturedPacksPage.qml" "FeaturedImagesPage.qml" "NewestPacksPage.qml" + QML_FILES KomplexSettingsPage.qml ) \ No newline at end of file diff --git a/KomplexHubContent/pages/KomplexSettingsPage.qml b/KomplexHubContent/pages/KomplexSettingsPage.qml new file mode 100644 index 0000000..fa07d91 --- /dev/null +++ b/KomplexHubContent/pages/KomplexSettingsPage.qml @@ -0,0 +1,476 @@ +/* + * Komplex Wallpaper Engine + * Copyright (C) 2026 @DigitalArtifex + * https://digitalartifex.dev - https://github.com/DigitalArtifex + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +import QtCore +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import KomplexHub + +Item +{ + property bool updated: updates.length > 0 + property var updates: [] + + ColumnLayout + { + anchors.fill: parent + anchors.margins: Constants.largeMargin + + Text + { + Layout.fillWidth: true + + text: qsTr("Animation Settings") + font: Constants.h1Font + color: palette.text + } + + Rectangle + { + Layout.fillWidth: true + Layout.preferredHeight: 320 + Layout.margins: Constants.largeMargin + + color: palette.base + border.color: palette.midlight + + ColumnLayout + { + id: animationSettingsLayout + + anchors.fill: parent + anchors.margins: Constants.largeMargin + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 36 + + CheckBox + { + Layout.preferredHeight: 36 + property bool value: settings.animationsEnabled + + id: animationsEnabledCheckbox + text: qsTr("Enable Animations") + font: Constants.h3Font + checked: value + + onCheckStateChanged: + { + if(updates.indexOf("enable")) + { + updates.splice(updates.indexOf("enable"), 1) + } + else + { + updates.push("enable") + } + + value = checked + } + } + } + Rectangle + { + Layout.fillHeight: true + Layout.fillWidth: true + + color: "transparent" + + Rectangle + { + anchors.centerIn: parent + anchors.right: parent.right + anchors.left: parent.left + height: 2 + color: palette.midlight + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 36 + + Text + { + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Slow Animation Duration (Ms)") + font: Constants.h3Font + color: palette.text + verticalAlignment: Qt.AlignVCenter + } + + TextField + { + property int value: settings.slowAnimationDuration + + Layout.fillHeight: true + Layout.preferredWidth: 36 * 3 + + id: slowAnimationDurationField + inputMethodHints: Qt.ImhFormattedNumbersOnly + horizontalAlignment: Text.AlignRight + enabled: animationsEnabledCheckbox.value + text: value + + onEditingFinished: () => + { + if(updates.indexOf("slowAnimationDuration")) + { + updates.splice(updates.indexOf("slowAnimationDuration"), 1) + } + else + { + updates.push("slowAnimationDuration") + } + + value = parseInt(text) + } + + Keys.onPressed: (event) => + { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) + { + slowAnimationDurationField.focus = false; // Unfocus the TextField + event.accepted = true; // Prevent further propagation of the key event + } + } + + background: Rectangle + { + color: slowAnimationDurationField.activeFocus ? palette.base : "transparent" + border.color: slowAnimationDurationField.activeFocus ? palette.highlight : "transparent" + border.width: 1 + radius: 4 + anchors.fill: slowAnimationDurationField + anchors.margins: -2 + } + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 36 + + Text + { + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Normal Animation Duration (Ms)") + font: Constants.h3Font + color: palette.text + verticalAlignment: Qt.AlignVCenter + } + + TextField + { + property int value: settings.normalAnimationDuration + + Layout.fillHeight: true + Layout.preferredWidth: 36 * 3 + + id: normalAnimationDurationField + inputMethodHints: Qt.ImhFormattedNumbersOnly + horizontalAlignment: Text.AlignRight + enabled: animationsEnabledCheckbox.value + text: value + + onEditingFinished: () => + { + if(updates.indexOf("normalAnimationDuration")) + { + updates.splice(updates.indexOf("normalAnimationDuration"), 1) + } + else + { + updates.push("normalAnimationDuration") + } + + value = parseInt(text) + } + + Keys.onPressed: (event) => + { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) + { + normalAnimationDurationField.focus = false; // Unfocus the TextField + event.accepted = true; // Prevent further propagation of the key event + } + } + + background: Rectangle + { + color: normalAnimationDurationField.activeFocus ? palette.base : "transparent" + border.color: normalAnimationDurationField.activeFocus ? palette.highlight : "transparent" + border.width: 1 + radius: 4 + anchors.fill: normalAnimationDurationField + anchors.margins: -2 + } + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 36 + + Text + { + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Fast Animation Duration (Ms)") + font: Constants.h3Font + color: palette.text + verticalAlignment: Qt.AlignVCenter + } + + TextField + { + property int value: settings.fastAnimationDuration + + Layout.fillHeight: true + Layout.preferredWidth: 36 * 3 + + id: fastAnimationDurationField + inputMethodHints: Qt.ImhFormattedNumbersOnly + horizontalAlignment: Text.AlignRight + enabled: animationsEnabledCheckbox.value + text: value + + onEditingFinished: () => + { + if(updates.indexOf("normalAnimationDuration")) + { + updates.splice(updates.indexOf("normalAnimationDuration"), 1) + } + else + { + updates.push("normalAnimationDuration") + } + value = parseInt(text) + } + + Keys.onPressed: (event) => + { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) + { + fastAnimationDurationField.focus = false; // Unfocus the TextField + event.accepted = true; // Prevent further propagation of the key event + } + } + + background: Rectangle + { + color: fastAnimationDurationField.activeFocus ? palette.base : "transparent" + border.color: fastAnimationDurationField.activeFocus ? palette.highlight : "transparent" + border.width: 1 + radius: 4 + anchors.fill: fastAnimationDurationField + anchors.margins: -2 + } + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 36 + + Text + { + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Page Change Animation Duration (Ms)") + font: Constants.h3Font + color: palette.text + verticalAlignment: Qt.AlignVCenter + } + + TextField + { + property int value: settings.pageChangeAnimationDuration + + Layout.fillHeight: true + Layout.preferredWidth: 36 * 3 + + id: pageChangeAnimationDurationField + inputMethodHints: Qt.ImhFormattedNumbersOnly + horizontalAlignment: Text.AlignRight + enabled: animationsEnabledCheckbox.value + text: value + + onEditingFinished: () => + { + if(updates.indexOf("pageChangeAnimationDuration")) + { + updates.splice(updates.indexOf("pageChangeAnimationDuration"), 1) + } + else + { + updates.push("pageChangeAnimationDuration") + } + value = parseInt(text) + } + + Keys.onPressed: (event) => + { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) + { + pageChangeAnimationDurationField.focus = false; // Unfocus the TextField + event.accepted = true; // Prevent further propagation of the key event + } + } + + background: Rectangle + { + color: pageChangeAnimationDurationField.activeFocus ? palette.base : "transparent" + border.color: pageChangeAnimationDurationField.activeFocus ? palette.highlight : "transparent" + border.width: 1 + radius: 4 + anchors.fill: pageChangeAnimationDurationField + anchors.margins: -2 + } + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 36 + + Text + { + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Page Fade Animation Duration (Ms)") + font: Constants.h3Font + color: palette.text + verticalAlignment: Qt.AlignVCenter + } + + TextField + { + property int value: settings.pageFadeAnimationDuration + + Layout.fillHeight: true + Layout.preferredWidth: 36 * 3 + + id: pageFadeAnimationDurationField + inputMethodHints: Qt.ImhFormattedNumbersOnly + horizontalAlignment: Text.AlignRight + text: value + enabled: animationsEnabledCheckbox.value + + onEditingFinished: () => + { + if(updates.indexOf("pageChangeAnimationDuration")) + { + updates.splice(updates.indexOf("pageChangeAnimationDuration"), 1) + } + else + { + updates.push("pageChangeAnimationDuration") + } + value = parseInt(text) + } + + Keys.onPressed: (event) => + { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) + { + pageFadeAnimationDurationField.focus = false; // Unfocus the TextField + event.accepted = true; // Prevent further propagation of the key event + } + } + + background: Rectangle + { + color: pageFadeAnimationDurationField.activeFocus ? palette.base : "transparent" + border.color: pageFadeAnimationDurationField.activeFocus ? palette.highlight : "transparent" + border.width: 1 + radius: 4 + anchors.fill: pageFadeAnimationDurationField + anchors.margins: -2 + } + } + } + } + } + + Item + { + Layout.fillHeight: true + Layout.fillWidth: true + } + } + + Settings + { + id: settings + property bool animationsEnabled: true + + //ms length of page change + property int pageChangeAnimationDuration: 250 + property int pageFadeAnimationDuration: 250 + + property int slowAnimationDuration: 750 + property int normalAnimationDuration: 250 + property int fastAnimationDuration: 125 + } + + function apply() + { + if(updated) + { + settings.animationsEnabled = animationsEnabledCheckbox.value + settings.slowAnimationDuration = slowAnimationDurationField.value + settings.normalAnimationDuration = normalAnimationDurationField.value + settings.fastAnimationDuration = fastAnimationDurationField.value + settings.pageChangeAnimationDuration = pageChangeAnimationDurationField.value + settings.pageFadeAnimationDuration = pageFadeAnimationDurationField.value + + updates.splice(0, updates.length) + } + } + + function reset() + { + if(updated) + { + animationsEnabledCheckbox.value = settings.animationsEnabled + slowAnimationDurationField.value = settings.slowAnimationDuration + normalAnimationDurationField.value = settings.normalAnimationDuration + fastAnimationDurationField.value = settings.fastAnimationDuration + pageChangeAnimationDurationField.value = settings.pageChangeAnimationDuration + pageFadeAnimationDurationField.value = settings.pageFadeAnimationDuration + + updates.splice(0, updates.length) + } + } +} diff --git a/KomplexHubContent/pages/SettingsPage.qml b/KomplexHubContent/pages/SettingsPage.qml index 5067921..96d815b 100644 --- a/KomplexHubContent/pages/SettingsPage.qml +++ b/KomplexHubContent/pages/SettingsPage.qml @@ -1,3 +1,22 @@ +/* + * Komplex Wallpaper Engine + * Copyright (C) 2026 @DigitalArtifex + * https://digitalartifex.dev - https://github.com/DigitalArtifex + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +import QtCore import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -11,6 +30,9 @@ import KomplexHub.Pages Item { readonly property bool searchable: false + property bool settingsUpdated: wallpaperSettingsUpdated || komplexSettingsUpdated + property bool wallpaperSettingsUpdated: wallpaperSettingsPage.updated && pageStack.currentIndex === 0 + property bool komplexSettingsUpdated: komplexSettingsPage.updated && pageStack.currentIndex === 1 id: settingsPageRoot @@ -29,6 +51,9 @@ Item { TabButton { text: qsTr("Wallpaper") } + TabButton { + text: qsTr("Komplex") + } TabButton { text: qsTr("Account") } @@ -37,33 +62,53 @@ Item { } } - StackLayout { - + StackLayout + { + id: pageStack Layout.fillHeight: true Layout.fillWidth: true currentIndex: bar.currentIndex - Item { + Item + { id: wallpaperTab Layout.fillHeight: true Layout.fillWidth: true - WallpaperSettingsPage { + WallpaperSettingsPage + { + id: wallpaperSettingsPage anchors.fill: parent } } - Item { + Item + { + id: komplexTab + + Layout.fillHeight: true + Layout.fillWidth: true + + KomplexSettingsPage + { + id: komplexSettingsPage + anchors.fill: parent + } + } + Item + { id: accountTab Layout.fillHeight: true Layout.fillWidth: true - UserProfilePage { + UserProfilePage + { anchors.fill: parent } } - Item { + Item + { Layout.fillHeight: true Layout.fillWidth: true property string title: qsTr("Hello!") @@ -78,14 +123,17 @@ Pexels") id: keroHelloAvatarRoot - Rectangle { + Rectangle + { anchors.fill: parent color: "transparent" - ColumnLayout { + ColumnLayout + { anchors.fill: parent - KeroHelloAvatar { + KeroHelloAvatar + { Layout.fillHeight: true Layout.fillWidth: true antialiasing: true @@ -93,7 +141,8 @@ Pexels") Item { Layout.preferredHeight: 36 } - Text { + Text + { Layout.fillHeight: false Layout.fillWidth: true Layout.margins: Constants.largeMargin @@ -106,7 +155,8 @@ Pexels") textFormat: Text.MarkdownText } - Text { + Text + { Layout.fillHeight: false Layout.fillWidth: true Layout.margins: Constants.largeMargin @@ -121,16 +171,19 @@ Pexels") Item { Layout.fillHeight: true } - RowLayout { + RowLayout + { Layout.fillWidth: true Layout.alignment: Qt.AlignTop | Qt.AlignRight - ColumnLayout { + ColumnLayout + { Layout.alignment: Qt.AlignTop | Qt.AlignRight Layout.margins: Constants.largeMargin Layout.fillHeight: true - Text { + Text + { text: qsTr("Contributors") color: palette.text.darker() font: Constants.h5Font @@ -141,7 +194,8 @@ Pexels") textFormat: Text.MarkdownText } - Text { + Text + { id: contributorText text: keroHelloAvatarRoot.contributors color: palette.text.darker() @@ -153,12 +207,14 @@ Pexels") } } - ColumnLayout { + ColumnLayout + { Layout.alignment: Qt.AlignTop | Qt.AlignRight Layout.margins: Constants.largeMargin Layout.fillHeight: true - Text { + Text + { text: qsTr("Special Thanks") color: palette.text.darker() font: Constants.h5Font @@ -169,7 +225,8 @@ Pexels") textFormat: Text.MarkdownText } - Text { + Text + { id: thanksText text: keroHelloAvatarRoot.thanks color: palette.text.darker() @@ -183,10 +240,92 @@ Pexels") } } } + } + } + Rectangle + { + Layout.fillWidth: true + Layout.preferredHeight: settingsUpdated ? 64 : 0 + color: palette.base + border.color: palette.midlight + opacity: settingsUpdated ? 1 : 0 + + RowLayout + { + anchors.fill: parent + anchors.rightMargin: Constants.mediumMargin + + Item + { + Layout.fillHeight: true + Layout.fillWidth: true + } + + SquareButton + { + Layout.preferredHeight: 50 + Layout.preferredWidth: 160 + + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + icon.source: "qrc:/images/icons/icons8-reply-arrow.svg" + text: qsTr("Reset") + } + + SquareButton + { + Layout.preferredHeight: 50 + Layout.preferredWidth: 160 + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + icon.source: "qrc:/images/icons/icons8-check-mark.svg" + text: qsTr("Apply") + } + } + + Behavior on opacity + { + NumberAnimation + { + duration: settings.animationsEnabled ? + settings.normalAnimationDuration : 0 + } + } + + Behavior on height + { + NumberAnimation + { + duration: settings.animationsEnabled ? + settings.normalAnimationDuration : 0 + } } } } + } + function applyCurrentSettings() + { + if(pageStack.currentIndex === 0 && wallpaperSettingsPage.updated) + { + wallpaperSettingsPage.apply() + } + + else if(pageStack.currentIndex === 1 && komplexSettingsPage.updated) + { + komplexSettingsPage.apply() + } + } + + function resetCurrentSettings() + { + if(pageStack.currentIndex === 0 && wallpaperSettingsPage.updated) + { + wallpaperSettingsPage.reset() + } + + else if(pageStack.currentIndex === 1 && komplexSettingsPage.updated) + { + komplexSettingsPage.reset() + } } }