From c8209b723a8e5f4a8169a2b89eb2ef7bcabad0a9 Mon Sep 17 00:00:00 2001
From: Digital Artifex <7929434+DigitalArtifex@users.noreply.github.com>
Date: Tue, 25 Aug 2026 19:21:53 -0400
Subject: [PATCH] Added application settings page
---
KomplexHubContent/pages/CMakeLists.txt | 1 +
.../pages/KomplexSettingsPage.qml | 476 ++++++++++++++++++
KomplexHubContent/pages/SettingsPage.qml | 177 ++++++-
3 files changed, 635 insertions(+), 19 deletions(-)
create mode 100644 KomplexHubContent/pages/KomplexSettingsPage.qml
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()
+ }
}
}