Compare commits
61 Commits
a58fdfadc6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
6bea9b32df
|
|||
|
c8209b723a
|
|||
|
e779c8e9b1
|
|||
|
5def93edf2
|
|||
|
abdd49bf52
|
|||
|
871ab8a262
|
|||
|
3ef029aba9
|
|||
|
cf5baa0684
|
|||
| 2ffe0bba88 | |||
|
b4a1e1bbf4
|
|||
|
2fab4f209f
|
|||
|
6541cedc67
|
|||
|
f3adc14a6e
|
|||
|
7b25255126
|
|||
|
1aaff0cd02
|
|||
|
d60cdef637
|
|||
|
97c9ba30f0
|
|||
|
6e94484fac
|
|||
|
1d87abd5af
|
|||
|
0402b0902d
|
|||
|
ac65bbb3ab
|
|||
|
45f293a349
|
|||
|
fa3c6354cb
|
|||
|
f23aada9a5
|
|||
|
0fe189bfde
|
|||
|
bb90186932
|
|||
|
61231a890a
|
|||
|
8e95f66dc3
|
|||
|
b8d5670530
|
|||
|
700de7a757
|
|||
|
5ef7f54cfe
|
|||
|
63e45eb4d4
|
|||
|
1d5bcb9365
|
|||
|
e6d7d908b1
|
|||
|
471c91e622
|
|||
|
9e8b6a70c8
|
|||
|
294a38f26a
|
|||
|
a776997119
|
|||
|
f69ba41046
|
|||
|
6b7812fa50
|
|||
|
bb58c8a9d2
|
|||
|
4a7960177d
|
|||
|
9fbf90b0c9
|
|||
|
bb4e3c7562
|
|||
|
7f86e1105d
|
|||
|
0f2e237fe6
|
|||
|
5deb869c2c
|
|||
|
a1d3f20439
|
|||
|
4157e66557
|
|||
|
4182e2d5a7
|
|||
|
a56532a047
|
|||
|
ab0ab4b4fb
|
|||
|
abd653ef1c
|
|||
|
9db9ed67d8
|
|||
|
990457042a
|
|||
|
2a5e66d68c
|
|||
|
1826209521
|
|||
|
3d0655edd1
|
|||
|
69743883d7
|
|||
|
100c6da3cf
|
|||
|
b64834084e
|
@@ -3,77 +3,89 @@
|
|||||||
|
|
||||||
;Kero
|
;Kero
|
||||||
{
|
{
|
||||||
|
{
|
||||||
images/kero/kero_build_1.png,
|
images/kero/kero_build_1.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_build_2.png,
|
images/kero/kero_build_2.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_build_3.png,
|
images/kero/kero_build_3.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_build_4.png,
|
images/kero/kero_build_4.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_build_error.png,
|
images/kero/kero_build_error.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_choice.png,
|
images/kero/kero_choice.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_hello.png,
|
images/kero/kero_hello.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_login.png,
|
images/kero/kero_login.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_no_results.png,
|
images/kero/kero_no_results.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_run_1.png,
|
images/kero/kero_run_1.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_run_2.png,
|
images/kero/kero_run_2.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_run_3.png,
|
images/kero/kero_run_3.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_run_4.png,
|
images/kero/kero_run_4.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_warning.png,
|
images/kero/kero_warning.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
images/kero/kero_success.png,
|
images/kero/kero_success.png,
|
||||||
placeholders,
|
placeholders,
|
||||||
chatgpt5
|
chatgpt5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
images/kero/kero_spotlight.png,
|
||||||
|
placeholders,
|
||||||
|
chatgpt5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
images/kero/kero_star.png,
|
||||||
|
placeholders,
|
||||||
|
chatgpt5
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+25
-8
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.21.1)
|
|||||||
option(LINK_INSIGHT "Link Qt Insight Tracker library" ON)
|
option(LINK_INSIGHT "Link Qt Insight Tracker library" ON)
|
||||||
option(BUILD_QDS_COMPONENTS "Build design studio components" ON)
|
option(BUILD_QDS_COMPONENTS "Build design studio components" ON)
|
||||||
|
|
||||||
project(KomplexHub LANGUAGES CXX)
|
project(KomplexHub VERSION 1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
@@ -20,11 +20,26 @@ set(QML_IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY}
|
|||||||
FORCE
|
FORCE
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Qt6 6.8 REQUIRED COMPONENTS Core Gui Widgets Qml Quick QuickControls2 QuickTimeline ShaderTools Concurrent)
|
find_package(
|
||||||
|
Qt6
|
||||||
|
REQUIRED COMPONENTS
|
||||||
|
Core
|
||||||
|
Gui
|
||||||
|
Widgets
|
||||||
|
Qml
|
||||||
|
Quick
|
||||||
|
QuickControls2
|
||||||
|
QuickTimeline
|
||||||
|
ShaderTools
|
||||||
|
Concurrent
|
||||||
|
)
|
||||||
|
|
||||||
qt_standard_project_setup()
|
qt_standard_project_setup()
|
||||||
|
|
||||||
qt_add_executable(${CMAKE_PROJECT_NAME}
|
qt_add_executable(${CMAKE_PROJECT_NAME}
|
||||||
)
|
)
|
||||||
|
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES VERSION "1.0")
|
||||||
|
|
||||||
qt_add_resources(${CMAKE_PROJECT_NAME} "configuration"
|
qt_add_resources(${CMAKE_PROJECT_NAME} "configuration"
|
||||||
PREFIX "/"
|
PREFIX "/"
|
||||||
FILES
|
FILES
|
||||||
@@ -83,14 +98,16 @@ qt_add_resources(${CMAKE_PROJECT_NAME} "app_images"
|
|||||||
"images/kero/kero_run_3.png"
|
"images/kero/kero_run_3.png"
|
||||||
"images/kero/kero_run_4.png"
|
"images/kero/kero_run_4.png"
|
||||||
"images/kero/kero_success.png"
|
"images/kero/kero_success.png"
|
||||||
|
"images/kero/kero_spotlight.png"
|
||||||
|
"images/kero/kero_star.png"
|
||||||
"images/kero/kero_warning.png"
|
"images/kero/kero_warning.png"
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(
|
# target_compile_definitions(
|
||||||
${CMAKE_PROJECT_NAME}
|
# ${CMAKE_PROJECT_NAME}
|
||||||
PUBLIC
|
# PUBLIC
|
||||||
KOMPLEX_LOCAL_DEV
|
# KOMPLEX_LOCAL_DEV
|
||||||
)
|
# )
|
||||||
|
|
||||||
include(qds)
|
include(qds)
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Imported 3D assets and components imported from bundles will be created in this folder.
|
|
||||||
@@ -1,21 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
import QtCore
|
||||||
|
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
|
|
||||||
|
id: window
|
||||||
visible: true
|
visible: true
|
||||||
flags: Qt.Window
|
flags: Qt.Window
|
||||||
title: "KomplexHub"
|
title: "KomplexHub"
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
minimumWidth: 720
|
minimumWidth: 720
|
||||||
|
|
||||||
MainScreen {
|
MainScreen
|
||||||
antialiasing: true
|
{
|
||||||
id: mainScreen
|
id: mainScreen
|
||||||
|
|
||||||
|
antialiasing: true
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Settings
|
||||||
|
{
|
||||||
|
property alias x: window.x
|
||||||
|
property alias y: window.y
|
||||||
|
property alias width: window.width
|
||||||
|
property alias height: window.height
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,20 @@ qt6_add_qml_module(KomplexHubContent
|
|||||||
"pages/UserProfilePage.qml"
|
"pages/UserProfilePage.qml"
|
||||||
"pages/WallpaperSettingsPage.qml"
|
"pages/WallpaperSettingsPage.qml"
|
||||||
"pages/VideoSearchPage.qml"
|
"pages/VideoSearchPage.qml"
|
||||||
|
"pages/FeaturedVideosPage.qml"
|
||||||
|
"pages/FeaturedPacksPage.qml"
|
||||||
|
"pages/FeaturedImagesPage.qml"
|
||||||
|
"pages/NewestPacksPage.qml"
|
||||||
|
"views/CompletedView.qml"
|
||||||
|
"views/DownloadView.qml"
|
||||||
|
"views/ErrorView.qml"
|
||||||
|
"views/ImageView.qml"
|
||||||
|
"views/PackView.qml"
|
||||||
|
"views/VideoView.qml"
|
||||||
|
RESOURCES views/CMakeLists.txt
|
||||||
|
RESOURCES pages/CMakeLists.txt
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(pages)
|
||||||
|
add_subdirectory(views)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
|
* Komplex Wallpaper Engine
|
||||||
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
|
* Copyright (C) 2026 @DigitalArtifex
|
||||||
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
|
* https://digitalartifex.dev - https://github.com/DigitalArtifex
|
||||||
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
|
*
|
||||||
*/
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls 2.0
|
import QtQuick.Controls 2.0
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -12,7 +25,8 @@ import KomplexHub.Controls
|
|||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
import KomplexHubContent
|
import KomplexHubContent
|
||||||
|
|
||||||
Rectangle {
|
Rectangle
|
||||||
|
{
|
||||||
property MenuButton currentMenuButton
|
property MenuButton currentMenuButton
|
||||||
property bool popup: false
|
property bool popup: false
|
||||||
|
|
||||||
@@ -20,12 +34,14 @@ Rectangle {
|
|||||||
|
|
||||||
color: palette.window
|
color: palette.window
|
||||||
|
|
||||||
RowLayout {
|
RowLayout
|
||||||
|
{
|
||||||
id: windowRootLayout
|
id: windowRootLayout
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Rectangle {
|
Rectangle
|
||||||
|
{
|
||||||
id: windowMenu
|
id: windowMenu
|
||||||
|
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
@@ -58,10 +74,12 @@ Rectangle {
|
|||||||
selected = false
|
selected = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity
|
||||||
|
{
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,7 +99,7 @@ Rectangle {
|
|||||||
|
|
||||||
height: 64
|
height: 64
|
||||||
width: 100
|
width: 100
|
||||||
text: "Home"
|
text: qsTr("Home")
|
||||||
|
|
||||||
icon.height: 32
|
icon.height: 32
|
||||||
icon.width: 32
|
icon.width: 32
|
||||||
@@ -109,7 +127,7 @@ Rectangle {
|
|||||||
|
|
||||||
height: 64
|
height: 64
|
||||||
width: 100
|
width: 100
|
||||||
text: "Images"
|
text: qsTr("Images")
|
||||||
|
|
||||||
icon.height: 32
|
icon.height: 32
|
||||||
icon.width: 32
|
icon.width: 32
|
||||||
@@ -132,7 +150,7 @@ Rectangle {
|
|||||||
|
|
||||||
height: 64
|
height: 64
|
||||||
width: 100
|
width: 100
|
||||||
text: "Videos"
|
text: qsTr("Videos")
|
||||||
|
|
||||||
icon.height: 32
|
icon.height: 32
|
||||||
icon.width: 32
|
icon.width: 32
|
||||||
@@ -155,7 +173,7 @@ Rectangle {
|
|||||||
|
|
||||||
height: 64
|
height: 64
|
||||||
width: 100
|
width: 100
|
||||||
text: "Live"
|
text: qsTr("Komplex")
|
||||||
|
|
||||||
icon.height: 32
|
icon.height: 32
|
||||||
icon.width: 32
|
icon.width: 32
|
||||||
@@ -178,7 +196,7 @@ Rectangle {
|
|||||||
|
|
||||||
height: 64
|
height: 64
|
||||||
width: 100
|
width: 100
|
||||||
text: "Installed"
|
text: qsTr("Installed")
|
||||||
|
|
||||||
icon.height: 32
|
icon.height: 32
|
||||||
icon.width: 32
|
icon.width: 32
|
||||||
@@ -207,7 +225,7 @@ Rectangle {
|
|||||||
|
|
||||||
height: 64
|
height: 64
|
||||||
width: 100
|
width: 100
|
||||||
text: "Settings"
|
text: qsTr("Settings")
|
||||||
|
|
||||||
icon.height: 32
|
icon.height: 32
|
||||||
icon.width: 32
|
icon.width: 32
|
||||||
@@ -228,7 +246,7 @@ Rectangle {
|
|||||||
{
|
{
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ? settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,8 +284,12 @@ Rectangle {
|
|||||||
pageLoader.setSearchTerm()
|
pageLoader.setSearchTerm()
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on preferredHeight {
|
Behavior on preferredHeight
|
||||||
NumberAnimation { duration: Constants.normalAnimationDuration }
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ? settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +324,7 @@ Rectangle {
|
|||||||
id: pageLoaderAnimation
|
id: pageLoaderAnimation
|
||||||
|
|
||||||
target: pageLoader
|
target: pageLoader
|
||||||
duration: 150
|
duration: settings.animationsEnabled ? settings.pageChangeAnimationDuration : 0
|
||||||
|
|
||||||
onFinished: () => {
|
onFinished: () => {
|
||||||
if(pageLoader.loading && pageLoader.opacity === 0)
|
if(pageLoader.loading && pageLoader.opacity === 0)
|
||||||
@@ -369,7 +391,7 @@ Rectangle {
|
|||||||
|
|
||||||
function isSearchPage()
|
function isSearchPage()
|
||||||
{
|
{
|
||||||
return (
|
return(
|
||||||
pageLoader.item instanceof ImageSearchPage ||
|
pageLoader.item instanceof ImageSearchPage ||
|
||||||
pageLoader.item instanceof LiveSearchPage ||
|
pageLoader.item instanceof LiveSearchPage ||
|
||||||
pageLoader.item instanceof VideoSearchPage
|
pageLoader.item instanceof VideoSearchPage
|
||||||
@@ -381,23 +403,6 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeroBuildingAnimation
|
|
||||||
{
|
|
||||||
id: buildingOverlay
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
KeroLoadingAnimation
|
|
||||||
{
|
|
||||||
id: loadingAnimation
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
visible: opacity > 0
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections
|
Connections
|
||||||
{
|
{
|
||||||
id: popupConnection
|
id: popupConnection
|
||||||
@@ -414,7 +419,6 @@ Rectangle {
|
|||||||
currentMenuButton = homeMenubutton
|
currentMenuButton = homeMenubutton
|
||||||
pageLoader.page = "pages/HomePage.qml"
|
pageLoader.page = "pages/HomePage.qml"
|
||||||
searchContainer.preferredHeight = 0
|
searchContainer.preferredHeight = 0
|
||||||
loadingAnimation.opacity = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
@@ -446,4 +450,17 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
qt_add_library(KomplexHubPages STATIC)
|
||||||
|
qt6_add_qml_module(KomplexHubPages
|
||||||
|
URI "KomplexHub.Pages"
|
||||||
|
VERSION 1.0
|
||||||
|
RESOURCE_PREFIX "/qt/qml"
|
||||||
|
QML_FILES
|
||||||
|
"HomePage.qml"
|
||||||
|
"ImageSearchPage.qml"
|
||||||
|
"InstalledWallpaperPage.qml"
|
||||||
|
"LiveSearchPage.qml"
|
||||||
|
"LoginPage.qml"
|
||||||
|
"SettingsPage.qml"
|
||||||
|
"UserProfilePage.qml"
|
||||||
|
"WallpaperSettingsPage.qml"
|
||||||
|
"VideoSearchPage.qml"
|
||||||
|
"FeaturedVideosPage.qml"
|
||||||
|
"FeaturedPacksPage.qml"
|
||||||
|
"FeaturedImagesPage.qml"
|
||||||
|
"NewestPacksPage.qml"
|
||||||
|
QML_FILES KomplexSettingsPage.qml
|
||||||
|
)
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: rootItem
|
||||||
|
|
||||||
|
property string query
|
||||||
|
readonly property bool searchable: paginator.searchable
|
||||||
|
property bool popup: false
|
||||||
|
property int resultWidth: 256
|
||||||
|
property int resultHeight: 245
|
||||||
|
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
FeaturedImagesModel
|
||||||
|
{
|
||||||
|
id: searchModel
|
||||||
|
resultsPerPage: paginator.resultsPerPage
|
||||||
|
|
||||||
|
Component.onCompleted: () => nextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
id: resultsLayout
|
||||||
|
visible: opacity > 0.01
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Constants.mediumMargin
|
||||||
|
|
||||||
|
KeroHeader
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 180
|
||||||
|
title: qsTr("Featured Images")
|
||||||
|
description: qsTr("A specially curated collection of images, courtesy of Pexels")
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginatorGrid
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
id: paginator
|
||||||
|
model: searchModel
|
||||||
|
loading: model.state === FeaturedImagesModel.Loading
|
||||||
|
|
||||||
|
delegate: ItemDelegate
|
||||||
|
{
|
||||||
|
id: resultDelegate
|
||||||
|
|
||||||
|
width: resultWidth
|
||||||
|
height: resultHeight
|
||||||
|
|
||||||
|
required property string author
|
||||||
|
required property string description
|
||||||
|
required property string uuid
|
||||||
|
required property string thumbnail
|
||||||
|
required property string authorId
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
SearchResultItem
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
title: parent.author
|
||||||
|
description: parent.description
|
||||||
|
thumbnail: parent.thumbnail
|
||||||
|
uuid: parent.uuid
|
||||||
|
pexels: true
|
||||||
|
selected: paginator.currentIndex === parent.index
|
||||||
|
|
||||||
|
onTriggered: () => paginator.currentIndex = parent.index
|
||||||
|
|
||||||
|
onViewMoreTriggered: () =>
|
||||||
|
{
|
||||||
|
showImagePopup(parent.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: popupContainer
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
ImageView
|
||||||
|
{
|
||||||
|
id: viewMoreImagePopup
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showImagePopup(index)
|
||||||
|
{
|
||||||
|
viewMoreImagePopup.author = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.AuthorRole)
|
||||||
|
viewMoreImagePopup.authorUrl = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.AuthorUrlRole)
|
||||||
|
viewMoreImagePopup.description = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.DescriptionRole)
|
||||||
|
viewMoreImagePopup.uuid = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.UuidRole)
|
||||||
|
viewMoreImagePopup.thumbnail = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.LargeThumbnailRole)
|
||||||
|
viewMoreImagePopup.original = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.OriginalUrlRole)
|
||||||
|
viewMoreImagePopup.portrait = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.PortraitUrlRole)
|
||||||
|
viewMoreImagePopup.landscape = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.LandscapeUrlRole)
|
||||||
|
viewMoreImagePopup.backgroundPortrait = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.BackgroundPortraitRole)
|
||||||
|
viewMoreImagePopup.backgroundLandscape = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.BackgroundLandscapeRole)
|
||||||
|
viewMoreImagePopup.fullScreen = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.ScreenUrlRole)
|
||||||
|
viewMoreImagePopup.portraitSize = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.PortraitSizeRole)
|
||||||
|
viewMoreImagePopup.landscapeSize = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.LandscapeSizeRole)
|
||||||
|
viewMoreImagePopup.fullScreenSize = searchModel.data(searchModel.index(index,0), FeaturedImagesModel.ScreenSizeRole)
|
||||||
|
viewMoreImagePopup.opacity = 1
|
||||||
|
popupContainer.opacity = 1
|
||||||
|
resultsLayout.opacity = 0
|
||||||
|
rootItem.popup = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePopup()
|
||||||
|
{
|
||||||
|
viewMoreImagePopup.opacity = 0
|
||||||
|
popupContainer.opacity = 0
|
||||||
|
resultsLayout.opacity = 1
|
||||||
|
rootItem.popup = false
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: rootItem
|
||||||
|
|
||||||
|
property string query
|
||||||
|
readonly property bool searchable: false
|
||||||
|
property bool popup: false
|
||||||
|
property int resultWidth: 256
|
||||||
|
property int resultHeight: 245
|
||||||
|
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
NewestPacksModel
|
||||||
|
{
|
||||||
|
id: packsModel
|
||||||
|
resultsPerPage: paginator.resultsPerPage
|
||||||
|
|
||||||
|
Component.onCompleted: () => nextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
id: resultsLayout
|
||||||
|
visible: opacity > 0.01
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Constants.mediumMargin
|
||||||
|
|
||||||
|
KeroHeader
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 180
|
||||||
|
title: qsTr("Featured Live Wallpapers")
|
||||||
|
description: qsTr("Live Wallpaper Packs from Komplex or ShaderToy")
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginatorGrid
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
id: paginator
|
||||||
|
model: packsModel
|
||||||
|
loading: model.state === NewestPacksModel.Loading
|
||||||
|
|
||||||
|
delegate: ItemDelegate
|
||||||
|
{
|
||||||
|
id: resultDelegate
|
||||||
|
|
||||||
|
width: resultWidth
|
||||||
|
height: resultHeight
|
||||||
|
|
||||||
|
required property string name
|
||||||
|
required property string author
|
||||||
|
required property string description
|
||||||
|
required property string uuid
|
||||||
|
required property string thumbnail
|
||||||
|
required property string authorId
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
SearchResultItem
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
title: parent.name
|
||||||
|
author: parent.author
|
||||||
|
description: parent.description
|
||||||
|
thumbnail: parent.thumbnail
|
||||||
|
uuid: parent.uuid
|
||||||
|
selected: paginator.currentIndex === parent.index
|
||||||
|
|
||||||
|
onTriggered: () => paginator.currentIndex = parent.index
|
||||||
|
|
||||||
|
onViewMoreTriggered: () =>
|
||||||
|
{
|
||||||
|
showWallpaperPopup(parent.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: popupContainer
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
PackView
|
||||||
|
{
|
||||||
|
id: viewMoreWallpaperPopup
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePopup()
|
||||||
|
{
|
||||||
|
viewMoreWallpaperPopup.opacity = 0
|
||||||
|
popupContainer.opacity = 0
|
||||||
|
resultsLayout.opacity = 1
|
||||||
|
rootItem.popup = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWallpaperPopup(index)
|
||||||
|
{
|
||||||
|
viewMoreWallpaperPopup.author = packsModel.data(packsModel.index(index,0), NewestPacksModel.AuthorRole)
|
||||||
|
viewMoreWallpaperPopup.authorId = packsModel.data(packsModel.index(index,0), NewestPacksModel.AuthorIdRole)
|
||||||
|
viewMoreWallpaperPopup.description = packsModel.data(packsModel.index(index,0), NewestPacksModel.DescriptionRole)
|
||||||
|
viewMoreWallpaperPopup.thumbnail = packsModel.data(packsModel.index(index,0), NewestPacksModel.ThumbnailRole)
|
||||||
|
viewMoreWallpaperPopup.uuid = packsModel.data(packsModel.index(index,0), NewestPacksModel.UuidRole)
|
||||||
|
viewMoreWallpaperPopup.opacity = 1
|
||||||
|
popupContainer.opacity = 1
|
||||||
|
resultsLayout.opacity = 0
|
||||||
|
rootItem.popup = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: rootItem
|
||||||
|
|
||||||
|
readonly property bool searchable: false
|
||||||
|
property bool popup: false
|
||||||
|
property int resultWidth: 256
|
||||||
|
property int resultHeight: 245
|
||||||
|
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
FeaturedVideosModel
|
||||||
|
{
|
||||||
|
id: videosModel
|
||||||
|
resultsPerPage: paginator.resultsPerPage
|
||||||
|
windowSize: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
id: resultsLayout
|
||||||
|
visible: opacity > 0.01
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Constants.mediumMargin
|
||||||
|
|
||||||
|
KeroHeader
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 180
|
||||||
|
title: qsTr("Most Popular Videos")
|
||||||
|
description: qsTr("Most popular videos, provided courtesy of Pexels")
|
||||||
|
image: "qrc:/images/kero/kero_star.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginatorGrid
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
id: paginator
|
||||||
|
model: videosModel
|
||||||
|
loading: videosModel.state === FeaturedVideosModel.Loading
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
delegate: ItemDelegate
|
||||||
|
{
|
||||||
|
id: resultDelegate
|
||||||
|
|
||||||
|
width: resultWidth
|
||||||
|
height: resultHeight
|
||||||
|
|
||||||
|
required property string uuid
|
||||||
|
required property string author
|
||||||
|
required property string authorId
|
||||||
|
required property string authorUrl
|
||||||
|
required property string thumbnail
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
SearchResultItem
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
author: parent.author
|
||||||
|
description: qsTr("")
|
||||||
|
thumbnail: parent.thumbnail
|
||||||
|
uuid: parent.uuid
|
||||||
|
pexels: true
|
||||||
|
selected: paginator.currentIndex === parent.index
|
||||||
|
|
||||||
|
onTriggered: () => paginator.currentIndex = parent.index
|
||||||
|
|
||||||
|
onViewMoreTriggered: () =>
|
||||||
|
{
|
||||||
|
showVideoPopup(parent.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: popupContainer
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
VideoView
|
||||||
|
{
|
||||||
|
id: videoDetailsPopup
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: () =>
|
||||||
|
{
|
||||||
|
videosModel.nextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
function showVideoPopup(index)
|
||||||
|
{
|
||||||
|
videosModel.setItem(index)
|
||||||
|
videoDetailsPopup.author = searchModel.data(searchModel.index(index,0), VideoSearchModel.AuthorRole)
|
||||||
|
videoDetailsPopup.authorUrl = searchModel.data(searchModel.index(index,0), VideoSearchModel.AuthorUrlRole)
|
||||||
|
videoDetailsPopup.uuid = searchModel.data(searchModel.index(index,0), VideoSearchModel.UuidRole)
|
||||||
|
videoDetailsPopup.thumbnail = searchModel.data(searchModel.index(index,0), VideoSearchModel.ThumbnailRole)
|
||||||
|
videoDetailsPopup.modelIndex = index
|
||||||
|
videoDetailsPopup.model = searchModel.itemModel
|
||||||
|
videoDetailsPopup.opacity = 1
|
||||||
|
resultsLayout.opacity = 0
|
||||||
|
popupContainer.opacity = 1
|
||||||
|
rootItem.popup = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePopup()
|
||||||
|
{
|
||||||
|
videoDetailsPopup.opacity = 0
|
||||||
|
popupContainer.opacity = 0
|
||||||
|
resultsLayout.opacity = 1
|
||||||
|
rootItem.popup = false
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.0
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
import KomplexHubPlugin
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHubContent
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
@@ -19,15 +39,19 @@ Item
|
|||||||
imagesModel.state === FeaturedImagesModel.Loading ||
|
imagesModel.state === FeaturedImagesModel.Loading ||
|
||||||
videosModel.state === FeaturedVideosModel.Loading;
|
videosModel.state === FeaturedVideosModel.Loading;
|
||||||
|
|
||||||
onWidthChanged:() => {
|
property bool error: packsModel.state === NewestPacksModel.Error ||
|
||||||
|
imagesModel.state === FeaturedImagesModel.Error ||
|
||||||
|
videosModel.state === FeaturedVideosModel.Error;
|
||||||
|
|
||||||
|
onWidthChanged: () =>
|
||||||
|
{
|
||||||
packsModel.resultsPerPage = resultsPerRow
|
packsModel.resultsPerPage = resultsPerRow
|
||||||
imagesModel.resultsPerPage = resultsPerRow
|
imagesModel.resultsPerPage = resultsPerRow
|
||||||
videosModel.resultsPerPage = resultsPerRow
|
videosModel.resultsPerPage = resultsPerRow
|
||||||
}
|
}
|
||||||
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
id: homePageRoot
|
id: homePageRoot
|
||||||
|
clip: true
|
||||||
|
|
||||||
NewestPacksModel
|
NewestPacksModel
|
||||||
{
|
{
|
||||||
@@ -47,37 +71,81 @@ Item
|
|||||||
resultsPerPage: 0
|
resultsPerPage: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Flickable
|
||||||
|
{
|
||||||
|
id: pageArea
|
||||||
|
visible: opacity > 0.01
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
contentHeight: content.height
|
||||||
|
contentWidth: content.width
|
||||||
|
|
||||||
|
Column
|
||||||
|
{
|
||||||
|
id: content
|
||||||
|
width: pageArea.width
|
||||||
|
|
||||||
|
VerticalSpacer{ height: Constants.largeMargin; width: Constants.largeMargin }
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
anchors.fill: parent
|
anchors.left: parent.left
|
||||||
color: palette.base
|
anchors.right: parent.right
|
||||||
|
height: childrenRect.height
|
||||||
|
anchors.margins: Constants.largeMargin
|
||||||
|
|
||||||
ColumnLayout
|
color: palette.base
|
||||||
|
border.color: palette.midlight
|
||||||
|
|
||||||
|
Column
|
||||||
{
|
{
|
||||||
id: resultsLayout
|
anchors.left: parent.left
|
||||||
visible: opacity > 0.01
|
anchors.right: parent.right
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Constants.mediumMargin
|
KeroHeader
|
||||||
|
{
|
||||||
|
height: 180
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
color: palette.window
|
||||||
|
|
||||||
|
Column
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: Constants.largeMargin
|
||||||
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
Layout.alignment: Qt.AlignTop
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: 50
|
anchors.right: parent.right
|
||||||
|
height: 36
|
||||||
|
|
||||||
color: palette.text
|
color: palette.text
|
||||||
font.pixelSize: Constants.h2Font.pixelSize
|
font.pixelSize: Constants.h2Font.pixelSize
|
||||||
font.bold: true
|
font.bold: true
|
||||||
text: qsTr("Newest Wallpaper Packs")
|
text: qsTr("Featured Komplex Wallpapers")
|
||||||
verticalAlignment: Qt.AlignVCenter
|
verticalAlignment: Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
HorizontalPaginator
|
HorizontalPaginator
|
||||||
{
|
{
|
||||||
id: packsPaginator
|
anchors.left: parent.left
|
||||||
Layout.fillWidth: true
|
anchors.right: parent.right
|
||||||
Layout.preferredHeight: 245
|
height: 245
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
|
|
||||||
|
id: packsPaginator
|
||||||
model: packsModel
|
model: packsModel
|
||||||
delegate: ItemDelegate
|
delegate: ItemDelegate
|
||||||
{
|
{
|
||||||
@@ -109,19 +177,20 @@ Item
|
|||||||
{
|
{
|
||||||
showWallpaperPopup(parent.index)
|
showWallpaperPopup(parent.index)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onThumbnailChanged: () =>
|
onViewMoreTriggered: () =>
|
||||||
{
|
{
|
||||||
console.log(index + " " + thumbnail + " " + parent.thumbnail)
|
showFeaturedPacksPage()
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
Layout.alignment: Qt.AlignTop
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: 50
|
anchors.right: parent.right
|
||||||
|
height: 36
|
||||||
|
|
||||||
color: palette.text
|
color: palette.text
|
||||||
font.pixelSize: Constants.h2Font.pixelSize
|
font.pixelSize: Constants.h2Font.pixelSize
|
||||||
@@ -133,9 +202,9 @@ Item
|
|||||||
HorizontalPaginator
|
HorizontalPaginator
|
||||||
{
|
{
|
||||||
id: imagesPaginator
|
id: imagesPaginator
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: 245
|
anchors.right: parent.right
|
||||||
Layout.alignment: Qt.AlignTop
|
height: 245
|
||||||
|
|
||||||
model: imagesModel
|
model: imagesModel
|
||||||
delegate: ItemDelegate
|
delegate: ItemDelegate
|
||||||
@@ -153,7 +222,7 @@ Item
|
|||||||
SearchResultItem
|
SearchResultItem
|
||||||
{
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
title: parent.author
|
author: parent.author
|
||||||
description: parent.description
|
description: parent.description
|
||||||
thumbnail: parent.thumbnail
|
thumbnail: parent.thumbnail
|
||||||
uuid: parent.uuid
|
uuid: parent.uuid
|
||||||
@@ -168,12 +237,124 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onViewMoreTriggered: () =>
|
||||||
|
{
|
||||||
|
showFeaturedImagesPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalSpacer { height: Constants.largeMargin; width: Constants.largeMargin }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalSpacer { height: Constants.largeMargin; width: Constants.largeMargin }
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: childrenRect.height
|
||||||
|
anchors.margins: Constants.largeMargin
|
||||||
|
|
||||||
|
color: palette.base
|
||||||
|
border.color: palette.midlight
|
||||||
|
|
||||||
|
Column
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
KeroHeader
|
||||||
|
{
|
||||||
|
height: 180
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
title: qsTr("New & Popular Wallpapers")
|
||||||
|
image: "qrc:/images/kero/kero_star.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: Constants.largeMargin
|
||||||
|
|
||||||
|
height: childrenRect.height
|
||||||
|
color: palette.window
|
||||||
|
|
||||||
|
Column
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: 36
|
||||||
|
|
||||||
|
color: palette.text
|
||||||
|
font.pixelSize: Constants.h2Font.pixelSize
|
||||||
|
font.bold: true
|
||||||
|
text: qsTr("Newest Wallpaper Packs")
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalPaginator
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: 245
|
||||||
|
|
||||||
|
id: packsPaginator2
|
||||||
|
model: packsModel
|
||||||
|
delegate: ItemDelegate
|
||||||
|
{
|
||||||
|
width: resultWidth
|
||||||
|
height: resultHeight
|
||||||
|
|
||||||
|
required property string name
|
||||||
|
required property string author
|
||||||
|
required property string description
|
||||||
|
required property string uuid
|
||||||
|
required property string thumbnail
|
||||||
|
required property string authorId
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
SearchResultItem
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
title: parent.name
|
||||||
|
author: parent.author
|
||||||
|
description: parent.description
|
||||||
|
thumbnail: parent.thumbnail
|
||||||
|
uuid: parent.uuid
|
||||||
|
|
||||||
|
selected: packsPaginator2.currentIndex === parent.index
|
||||||
|
|
||||||
|
onTriggered: () => packsPaginator2.currentIndex = parent.index
|
||||||
|
|
||||||
|
onViewMoreTriggered: () =>
|
||||||
|
{
|
||||||
|
showWallpaperPopup(parent.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewMoreTriggered: () =>
|
||||||
|
{
|
||||||
|
showFeaturedPacksPage()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
Layout.alignment: Qt.AlignTop
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: 50
|
anchors.right: parent.right
|
||||||
|
height: 36
|
||||||
|
|
||||||
color: palette.text
|
color: palette.text
|
||||||
font.pixelSize: Constants.h2Font.pixelSize
|
font.pixelSize: Constants.h2Font.pixelSize
|
||||||
@@ -185,9 +366,10 @@ Item
|
|||||||
HorizontalPaginator
|
HorizontalPaginator
|
||||||
{
|
{
|
||||||
id: videosPaginator
|
id: videosPaginator
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 245
|
anchors.left: parent.left
|
||||||
Layout.alignment: Qt.AlignTop
|
anchors.right: parent.right
|
||||||
|
height: 245
|
||||||
|
|
||||||
model: videosModel
|
model: videosModel
|
||||||
delegate: ItemDelegate
|
delegate: ItemDelegate
|
||||||
@@ -205,7 +387,7 @@ Item
|
|||||||
SearchResultItem
|
SearchResultItem
|
||||||
{
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
title: parent.author
|
author: parent.author
|
||||||
thumbnail: parent.thumbnail
|
thumbnail: parent.thumbnail
|
||||||
uuid: parent.uuid
|
uuid: parent.uuid
|
||||||
pexels: true
|
pexels: true
|
||||||
@@ -215,10 +397,20 @@ Item
|
|||||||
onViewMoreTriggered:() => showVideoPopup(parent.index)
|
onViewMoreTriggered:() => showVideoPopup(parent.index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onViewMoreTriggered: () =>
|
||||||
|
{
|
||||||
|
showFeaturedVideosPage()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* spacer */
|
VerticalSpacer{ height: Constants.largeMargin; width: Constants.largeMargin }
|
||||||
Item { Layout.fillHeight: true }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalSpacer{ height: Constants.largeMargin; width: Constants.largeMargin }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +428,15 @@ Item
|
|||||||
|
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
opacity: 1
|
opacity: 1
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
@@ -253,10 +454,12 @@ Item
|
|||||||
opacity: 0
|
opacity: 0
|
||||||
visible: opacity > 0.01
|
visible: opacity > 0.01
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity
|
||||||
|
{
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,12 +470,13 @@ Item
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
opacity: 0
|
opacity: 0
|
||||||
visible: opacity > 0.01
|
visible: opacity > 0.01
|
||||||
//model: videosModel.itemModel
|
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity
|
||||||
|
{
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,26 +487,134 @@ Item
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
opacity: 0
|
opacity: 0
|
||||||
visible: opacity > 0.01
|
visible: opacity > 0.01
|
||||||
//model: videosModel.itemModel
|
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity
|
||||||
|
{
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity
|
||||||
|
{
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
states: [
|
Component
|
||||||
State {
|
{
|
||||||
|
id: featuredVideosComponent
|
||||||
|
|
||||||
|
FeaturedVideosPage
|
||||||
|
{
|
||||||
|
id: featuredVideosPage
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: () => featuredVideosPage.opacity = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component
|
||||||
|
{
|
||||||
|
id: featuredPacksComponent
|
||||||
|
|
||||||
|
FeaturedPacksPage
|
||||||
|
{
|
||||||
|
id: featuredPacksPage
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: () => featuredPacksPage.opacity = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component
|
||||||
|
{
|
||||||
|
id: featuredImagesComponent
|
||||||
|
|
||||||
|
FeaturedImagesPage
|
||||||
|
{
|
||||||
|
id: featuredImagesPage
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: () => featuredImagesPage.opacity = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorView
|
||||||
|
{
|
||||||
|
id: errorView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
manager: downloadManager
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
id: featuredLoaderItem
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
enabled: visible
|
||||||
|
|
||||||
|
Loader
|
||||||
|
{
|
||||||
|
id: featuredLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states:
|
||||||
|
[
|
||||||
|
State
|
||||||
|
{
|
||||||
name: "loading"
|
name: "loading"
|
||||||
when: homePageRoot.loading
|
when: homePageRoot.loading
|
||||||
|
|
||||||
@@ -314,7 +626,71 @@ Item
|
|||||||
|
|
||||||
PropertyChanges
|
PropertyChanges
|
||||||
{
|
{
|
||||||
target: resultsLayout
|
target: pageArea
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: popupContainer
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "error"
|
||||||
|
when: homePageRoot.error
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: loadingAnimation
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageArea
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: popupContainer
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "idle"
|
||||||
|
when: !popup && !loading
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: loadingAnimation
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageArea
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
opacity: 0
|
opacity: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,11 +700,16 @@ Item
|
|||||||
opacity: 0
|
opacity: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State
|
||||||
name: "idle"
|
{
|
||||||
when: packsModel.state !== NewestPacksModel.Loading &&
|
name: "popup"
|
||||||
imagesModel.state !== FeaturedImagesModel.Loading &&
|
when: popup
|
||||||
videosModel.state !== FeaturedVideosModel.Loading;
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageArea
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
PropertyChanges
|
PropertyChanges
|
||||||
{
|
{
|
||||||
@@ -338,13 +719,20 @@ Item
|
|||||||
|
|
||||||
PropertyChanges
|
PropertyChanges
|
||||||
{
|
{
|
||||||
target: resultsLayout
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: popupContainer
|
||||||
opacity: 1
|
opacity: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
transitions: [
|
transitions:
|
||||||
|
[
|
||||||
Transition
|
Transition
|
||||||
{
|
{
|
||||||
from: "loading"
|
from: "loading"
|
||||||
@@ -352,18 +740,44 @@ Item
|
|||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
target: loadingAnimation
|
target: loadingAnimation
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
property: "opacity";
|
property: "opacity";
|
||||||
}
|
}
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
target: resultsLayout
|
target: pageArea
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
property: "opacity";
|
property: "opacity";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function showFeaturedVideosPage()
|
||||||
|
{
|
||||||
|
pageArea.opacity = 0
|
||||||
|
featuredLoaderItem.opacity = 1
|
||||||
|
featuredLoader.sourceComponent = featuredVideosComponent
|
||||||
|
popup = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function showFeaturedPacksPage()
|
||||||
|
{
|
||||||
|
pageArea.opacity = 0
|
||||||
|
featuredLoaderItem.opacity = 1
|
||||||
|
featuredLoader.sourceComponent = featuredPacksComponent
|
||||||
|
popup = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function showFeaturedImagesPage()
|
||||||
|
{
|
||||||
|
pageArea.opacity = 0
|
||||||
|
featuredLoaderItem.opacity = 1
|
||||||
|
featuredLoader.sourceComponent = featuredImagesComponent
|
||||||
|
popup = true
|
||||||
|
}
|
||||||
|
|
||||||
function showImagePopup(index)
|
function showImagePopup(index)
|
||||||
{
|
{
|
||||||
viewMoreImagePopup.author = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.AuthorRole)
|
viewMoreImagePopup.author = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.AuthorRole)
|
||||||
@@ -371,7 +785,6 @@ Item
|
|||||||
viewMoreImagePopup.description = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.DescriptionRole)
|
viewMoreImagePopup.description = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.DescriptionRole)
|
||||||
viewMoreImagePopup.uuid = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.UuidRole)
|
viewMoreImagePopup.uuid = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.UuidRole)
|
||||||
viewMoreImagePopup.thumbnail = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.LargeThumbnailRole)
|
viewMoreImagePopup.thumbnail = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.LargeThumbnailRole)
|
||||||
viewMoreImagePopup.original = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.OriginalUrlRole)
|
|
||||||
viewMoreImagePopup.portrait = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.PortraitUrlRole)
|
viewMoreImagePopup.portrait = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.PortraitUrlRole)
|
||||||
viewMoreImagePopup.landscape = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.LandscapeUrlRole)
|
viewMoreImagePopup.landscape = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.LandscapeUrlRole)
|
||||||
viewMoreImagePopup.backgroundPortrait = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.BackgroundPortraitRole)
|
viewMoreImagePopup.backgroundPortrait = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.BackgroundPortraitRole)
|
||||||
@@ -382,7 +795,7 @@ Item
|
|||||||
viewMoreImagePopup.fullScreenSize = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.ScreenSizeRole)
|
viewMoreImagePopup.fullScreenSize = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.ScreenSizeRole)
|
||||||
viewMoreImagePopup.opacity = 1
|
viewMoreImagePopup.opacity = 1
|
||||||
popupContainer.opacity = 1
|
popupContainer.opacity = 1
|
||||||
resultsLayout.opacity = 0
|
pageArea.opacity = 0
|
||||||
homePageRoot.popup = true
|
homePageRoot.popup = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +809,7 @@ Item
|
|||||||
viewMoreVideoPopup.modelIndex = index
|
viewMoreVideoPopup.modelIndex = index
|
||||||
viewMoreVideoPopup.model = videosModel.itemModel
|
viewMoreVideoPopup.model = videosModel.itemModel
|
||||||
viewMoreVideoPopup.opacity = 1
|
viewMoreVideoPopup.opacity = 1
|
||||||
resultsLayout.opacity = 0
|
pageArea.opacity = 0
|
||||||
popupContainer.opacity = 1
|
popupContainer.opacity = 1
|
||||||
homePageRoot.popup = true
|
homePageRoot.popup = true
|
||||||
}
|
}
|
||||||
@@ -407,19 +820,41 @@ Item
|
|||||||
viewMoreWallpaperPopup.authorId = packsModel.data(packsModel.index(index,0), NewestPacksModel.AuthorIdRole)
|
viewMoreWallpaperPopup.authorId = packsModel.data(packsModel.index(index,0), NewestPacksModel.AuthorIdRole)
|
||||||
viewMoreWallpaperPopup.description = packsModel.data(packsModel.index(index,0), NewestPacksModel.DescriptionRole)
|
viewMoreWallpaperPopup.description = packsModel.data(packsModel.index(index,0), NewestPacksModel.DescriptionRole)
|
||||||
viewMoreWallpaperPopup.thumbnail = packsModel.data(packsModel.index(index,0), NewestPacksModel.ThumbnailRole)
|
viewMoreWallpaperPopup.thumbnail = packsModel.data(packsModel.index(index,0), NewestPacksModel.ThumbnailRole)
|
||||||
|
viewMoreWallpaperPopup.name = packsModel.data(packsModel.index(index,0), NewestPacksModel.NameRole)
|
||||||
|
viewMoreWallpaperPopup.uuid = packsModel.data(packsModel.index(index,0), NewestPacksModel.UuidRole)
|
||||||
viewMoreWallpaperPopup.opacity = 1
|
viewMoreWallpaperPopup.opacity = 1
|
||||||
popupContainer.opacity = 1
|
popupContainer.opacity = 1
|
||||||
resultsLayout.opacity = 0
|
pageArea.opacity = 0
|
||||||
homePageRoot.popup = true
|
homePageRoot.popup = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function closePopup()
|
function closePopup()
|
||||||
{
|
{
|
||||||
|
if(featuredLoader.item && featuredLoader.item.popup)
|
||||||
|
{
|
||||||
|
featuredLoader.item.closePopup()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
featuredLoaderItem.opacity = 0
|
||||||
viewMoreImagePopup.opacity = 0
|
viewMoreImagePopup.opacity = 0
|
||||||
viewMoreVideoPopup.opacity = 0
|
viewMoreVideoPopup.opacity = 0
|
||||||
viewMoreWallpaperPopup.opacity = 0
|
viewMoreWallpaperPopup.opacity = 0
|
||||||
popupContainer.opacity = 0
|
popupContainer.opacity = 0
|
||||||
resultsLayout.opacity = 1
|
pageArea.opacity = 1
|
||||||
homePageRoot.popup = false
|
homePageRoot.popup = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -5,7 +24,9 @@ import QtQuick.Layouts
|
|||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
import KomplexHubPlugin
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
@@ -81,7 +102,8 @@ Item
|
|||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +111,8 @@ Item
|
|||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,4 +146,17 @@ Item
|
|||||||
paginator.opacity = 1
|
paginator.opacity = 1
|
||||||
rootItem.popup = false
|
rootItem.popup = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Dialogs
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
import KomplexHubPlugin
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
@@ -135,4 +157,17 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
import KomplexHubPlugin
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
@@ -33,8 +55,8 @@ Item
|
|||||||
{
|
{
|
||||||
id: resultDelegate
|
id: resultDelegate
|
||||||
|
|
||||||
width: 256
|
width: resultWidth
|
||||||
height: 245
|
height: resultHeight
|
||||||
|
|
||||||
required property string name
|
required property string name
|
||||||
required property string author
|
required property string author
|
||||||
@@ -47,7 +69,8 @@ Item
|
|||||||
SearchResultItem
|
SearchResultItem
|
||||||
{
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
title: parent.author
|
title: parent.name
|
||||||
|
author: parent.author
|
||||||
description: parent.description
|
description: parent.description
|
||||||
thumbnail: parent.thumbnail
|
thumbnail: parent.thumbnail
|
||||||
uuid: parent.uuid
|
uuid: parent.uuid
|
||||||
@@ -61,6 +84,15 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
@@ -69,27 +101,20 @@ Item
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
opacity: 0
|
opacity: 0
|
||||||
color: palette.base
|
color: palette.base
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
PackView
|
PackView
|
||||||
{
|
{
|
||||||
id: viewMoreWallpaperPopup
|
id: viewMoreWallpaperPopup
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
opacity: 0
|
|
||||||
visible: opacity > 0.01
|
|
||||||
//model: videosModel.itemModel
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation
|
|
||||||
{
|
|
||||||
duration: 250
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity
|
||||||
|
{
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,9 +133,22 @@ Item
|
|||||||
viewMoreWallpaperPopup.authorId = searchModel.data(searchModel.index(index,0), PackSearchModel.AuthorIdRole)
|
viewMoreWallpaperPopup.authorId = searchModel.data(searchModel.index(index,0), PackSearchModel.AuthorIdRole)
|
||||||
viewMoreWallpaperPopup.description = searchModel.data(searchModel.index(index,0), PackSearchModel.DescriptionRole)
|
viewMoreWallpaperPopup.description = searchModel.data(searchModel.index(index,0), PackSearchModel.DescriptionRole)
|
||||||
viewMoreWallpaperPopup.thumbnail = searchModel.data(searchModel.index(index,0), PackSearchModel.ThumbnailRole)
|
viewMoreWallpaperPopup.thumbnail = searchModel.data(searchModel.index(index,0), PackSearchModel.ThumbnailRole)
|
||||||
viewMoreWallpaperPopup.opacity = 1
|
viewMoreWallpaperPopup.uuid = searchModel.data(searchModel.index(index,0), PackSearchModel.UuidRole)
|
||||||
popupContainer.opacity = 1
|
popupContainer.opacity = 1
|
||||||
paginator.opacity = 0
|
paginator.opacity = 0
|
||||||
rootItem.popup = true
|
rootItem.popup = 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: loginFormRoot
|
id: loginFormRoot
|
||||||
@@ -85,4 +109,17 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: rootItem
|
||||||
|
|
||||||
|
property string query
|
||||||
|
readonly property bool searchable: false
|
||||||
|
property bool popup: false
|
||||||
|
property int resultWidth: 256
|
||||||
|
property int resultHeight: 245
|
||||||
|
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
NewestPacksModel
|
||||||
|
{
|
||||||
|
id: packsModel
|
||||||
|
resultsPerPage: paginator.resultsPerPage
|
||||||
|
|
||||||
|
Component.onCompleted: () => nextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
id: resultsLayout
|
||||||
|
visible: opacity > 0.01
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Constants.mediumMargin
|
||||||
|
|
||||||
|
KeroHeader
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 180
|
||||||
|
title: qsTr("Newest Live Wallpapers")
|
||||||
|
description: qsTr("Live Wallpaper Packs from Komplex or ShaderToy")
|
||||||
|
image: "qrc:/images/kero/kero_star.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginatorGrid
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
id: paginator
|
||||||
|
model: packsModel
|
||||||
|
loading: model.state === NewestPacksModel.Loading
|
||||||
|
|
||||||
|
delegate: ItemDelegate
|
||||||
|
{
|
||||||
|
id: resultDelegate
|
||||||
|
|
||||||
|
width: resultWidth
|
||||||
|
height: resultHeight
|
||||||
|
|
||||||
|
required property string name
|
||||||
|
required property string author
|
||||||
|
required property string description
|
||||||
|
required property string uuid
|
||||||
|
required property string thumbnail
|
||||||
|
required property string authorId
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
SearchResultItem
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
title: parent.name
|
||||||
|
author: parent.author
|
||||||
|
description: parent.description
|
||||||
|
thumbnail: parent.thumbnail
|
||||||
|
uuid: parent.uuid
|
||||||
|
selected: paginator.currentIndex === parent.index
|
||||||
|
|
||||||
|
onTriggered: () => paginator.currentIndex = parent.index
|
||||||
|
|
||||||
|
onViewMoreTriggered: () =>
|
||||||
|
{
|
||||||
|
showWallpaperPopup(parent.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: popupContainer
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
PackView
|
||||||
|
{
|
||||||
|
id: viewMoreWallpaperPopup
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePopup()
|
||||||
|
{
|
||||||
|
viewMoreWallpaperPopup.opacity = 0
|
||||||
|
popupContainer.opacity = 0
|
||||||
|
resultsLayout.opacity = 1
|
||||||
|
rootItem.popup = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWallpaperPopup(index)
|
||||||
|
{
|
||||||
|
viewMoreWallpaperPopup.author = packsModel.data(packsModel.index(index,0), NewestPacksModel.AuthorRole)
|
||||||
|
viewMoreWallpaperPopup.authorId = packsModel.data(packsModel.index(index,0), NewestPacksModel.AuthorIdRole)
|
||||||
|
viewMoreWallpaperPopup.description = packsModel.data(packsModel.index(index,0), NewestPacksModel.DescriptionRole)
|
||||||
|
viewMoreWallpaperPopup.thumbnail = packsModel.data(packsModel.index(index,0), NewestPacksModel.ThumbnailRole)
|
||||||
|
viewMoreWallpaperPopup.opacity = 1
|
||||||
|
popupContainer.opacity = 1
|
||||||
|
resultsLayout.opacity = 0
|
||||||
|
rootItem.popup = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
readonly property bool searchable: false
|
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
|
id: settingsPageRoot
|
||||||
|
|
||||||
@@ -24,6 +51,9 @@ Item {
|
|||||||
TabButton {
|
TabButton {
|
||||||
text: qsTr("Wallpaper")
|
text: qsTr("Wallpaper")
|
||||||
}
|
}
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("Komplex")
|
||||||
|
}
|
||||||
TabButton {
|
TabButton {
|
||||||
text: qsTr("Account")
|
text: qsTr("Account")
|
||||||
}
|
}
|
||||||
@@ -32,33 +62,53 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StackLayout {
|
StackLayout
|
||||||
|
{
|
||||||
|
id: pageStack
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
currentIndex: bar.currentIndex
|
currentIndex: bar.currentIndex
|
||||||
|
|
||||||
Item {
|
Item
|
||||||
|
{
|
||||||
id: wallpaperTab
|
id: wallpaperTab
|
||||||
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
WallpaperSettingsPage {
|
WallpaperSettingsPage
|
||||||
|
{
|
||||||
|
id: wallpaperSettingsPage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item
|
||||||
|
{
|
||||||
|
id: komplexTab
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
KomplexSettingsPage
|
||||||
|
{
|
||||||
|
id: komplexSettingsPage
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item
|
||||||
|
{
|
||||||
id: accountTab
|
id: accountTab
|
||||||
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
UserProfilePage {
|
UserProfilePage
|
||||||
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item
|
||||||
|
{
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
property string title: qsTr("Hello!")
|
property string title: qsTr("Hello!")
|
||||||
@@ -73,14 +123,17 @@ Pexels")
|
|||||||
|
|
||||||
id: keroHelloAvatarRoot
|
id: keroHelloAvatarRoot
|
||||||
|
|
||||||
Rectangle {
|
Rectangle
|
||||||
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout
|
||||||
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
KeroHelloAvatar {
|
KeroHelloAvatar
|
||||||
|
{
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
@@ -88,7 +141,8 @@ Pexels")
|
|||||||
|
|
||||||
Item { Layout.preferredHeight: 36 }
|
Item { Layout.preferredHeight: 36 }
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
Layout.fillHeight: false
|
Layout.fillHeight: false
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: Constants.largeMargin
|
Layout.margins: Constants.largeMargin
|
||||||
@@ -101,7 +155,8 @@ Pexels")
|
|||||||
textFormat: Text.MarkdownText
|
textFormat: Text.MarkdownText
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
Layout.fillHeight: false
|
Layout.fillHeight: false
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: Constants.largeMargin
|
Layout.margins: Constants.largeMargin
|
||||||
@@ -116,16 +171,19 @@ Pexels")
|
|||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
Item { Layout.fillHeight: true }
|
||||||
|
|
||||||
RowLayout {
|
RowLayout
|
||||||
|
{
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout
|
||||||
|
{
|
||||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||||
Layout.margins: Constants.largeMargin
|
Layout.margins: Constants.largeMargin
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
text: qsTr("Contributors")
|
text: qsTr("Contributors")
|
||||||
color: palette.text.darker()
|
color: palette.text.darker()
|
||||||
font: Constants.h5Font
|
font: Constants.h5Font
|
||||||
@@ -136,7 +194,8 @@ Pexels")
|
|||||||
textFormat: Text.MarkdownText
|
textFormat: Text.MarkdownText
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
id: contributorText
|
id: contributorText
|
||||||
text: keroHelloAvatarRoot.contributors
|
text: keroHelloAvatarRoot.contributors
|
||||||
color: palette.text.darker()
|
color: palette.text.darker()
|
||||||
@@ -148,12 +207,14 @@ Pexels")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout
|
||||||
|
{
|
||||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||||
Layout.margins: Constants.largeMargin
|
Layout.margins: Constants.largeMargin
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
text: qsTr("Special Thanks")
|
text: qsTr("Special Thanks")
|
||||||
color: palette.text.darker()
|
color: palette.text.darker()
|
||||||
font: Constants.h5Font
|
font: Constants.h5Font
|
||||||
@@ -164,7 +225,8 @@ Pexels")
|
|||||||
textFormat: Text.MarkdownText
|
textFormat: Text.MarkdownText
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
id: thanksText
|
id: thanksText
|
||||||
text: keroHelloAvatarRoot.thanks
|
text: keroHelloAvatarRoot.thanks
|
||||||
color: palette.text.darker()
|
color: palette.text.darker()
|
||||||
@@ -178,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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -57,4 +82,17 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -5,7 +24,9 @@ import QtQuick.Layouts
|
|||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
import KomplexHubPlugin
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
@@ -64,6 +85,15 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
@@ -78,22 +108,16 @@ Item
|
|||||||
{
|
{
|
||||||
id: viewMoreVideoPopup
|
id: viewMoreVideoPopup
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
visible: opacity > 0.01
|
||||||
opacity: 0
|
opacity: 0
|
||||||
|
|
||||||
Behavior on opacity
|
|
||||||
{
|
|
||||||
NumberAnimation
|
|
||||||
{
|
|
||||||
duration: 250
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on opacity
|
Behavior on opacity
|
||||||
{
|
{
|
||||||
NumberAnimation
|
NumberAnimation
|
||||||
{
|
{
|
||||||
duration: 250
|
duration: settings.animationsEnabled ?
|
||||||
|
settings.normalAnimationDuration : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,4 +144,17 @@ Item
|
|||||||
paginator.opacity = 1
|
paginator.opacity = 1
|
||||||
rootItem.popup = false
|
rootItem.popup = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,17 +23,36 @@
|
|||||||
*/
|
*/
|
||||||
// pragma ComponentBehavior: Bound
|
// pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Dialogs
|
import QtQuick.Dialogs
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
//import org.kde.kirigami as Kirigami
|
|
||||||
//import org.kde.plasma.core as PlasmaCore
|
|
||||||
import QtCore
|
|
||||||
import Qt.labs.folderlistmodel 2.15
|
import Qt.labs.folderlistmodel 2.15
|
||||||
|
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
import KomplexHubPlugin
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Views
|
||||||
|
import KomplexHub.Pages
|
||||||
|
|
||||||
//import com.github.digitalartifex.komplex 1.0 as Komplex
|
//import com.github.digitalartifex.komplex 1.0 as Komplex
|
||||||
|
|
||||||
@@ -49,13 +68,9 @@ Item
|
|||||||
|
|
||||||
id: root
|
id: root
|
||||||
property alias cfg_pauseMode: pauseModeCombo.currentIndex
|
property alias cfg_pauseMode: pauseModeCombo.currentIndex
|
||||||
property alias cfg_isPaused: runningCombo.checked
|
|
||||||
property alias cfg_shaderSpeed: speedSlider.value
|
property alias cfg_shaderSpeed: speedSlider.value
|
||||||
property alias cfg_mouseSpeedBias: mouseBiasSlider.value
|
property alias cfg_mouseSpeedBias: mouseBiasSlider.value
|
||||||
property bool cfg_infoPlasma6Preview_dismissed
|
property alias cfg_enableMouseTracking: mouseTrackingCheckbox.checked
|
||||||
property bool cfg_warningResources_dismissed
|
|
||||||
property bool cfg_emergencyHelp_dismissed
|
|
||||||
property bool cfg_infoiChannelSettings_dismissed
|
|
||||||
property alias cfg_checkActiveScreen: activeScreenOnlyCheckbox.checked
|
property alias cfg_checkActiveScreen: activeScreenOnlyCheckbox.checked
|
||||||
property alias cfg_excludeWindows: excludeWindows.windows
|
property alias cfg_excludeWindows: excludeWindows.windows
|
||||||
property alias cfg_running: runningCombo.checked
|
property alias cfg_running: runningCombo.checked
|
||||||
@@ -74,6 +89,9 @@ Item
|
|||||||
property bool enableMouseTracking: true
|
property bool enableMouseTracking: true
|
||||||
property real mouseTrackingBias: 0.5
|
property real mouseTrackingBias: 0.5
|
||||||
|
|
||||||
|
property bool updated: updates.length > 0
|
||||||
|
property var updates: []
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
@@ -120,19 +138,17 @@ Item
|
|||||||
currentIndex: manager.shaderPackIndex
|
currentIndex: manager.shaderPackIndex
|
||||||
displayText: currentIndex === -1 ? "Custom File" : currentText.replace("_", " ").charAt(0).toUpperCase() + currentText.replace("_", " ").slice(1)
|
displayText: currentIndex === -1 ? "Custom File" : currentText.replace("_", " ").charAt(0).toUpperCase() + currentText.replace("_", " ").slice(1)
|
||||||
|
|
||||||
// onCurrentTextChanged:
|
onCurrentIndexChanged:
|
||||||
// {
|
{
|
||||||
// root.cfg_shader_package_index = currentIndex;
|
if(updates.indexOf("wallpaper") >= 0 && value === manager.shaderPackIndex)
|
||||||
|
{
|
||||||
// if (root.cfg_shader_package_index === -1)
|
updates.slice(updates.indexOf("wallpaper"), 1)
|
||||||
// return;
|
}
|
||||||
|
else
|
||||||
// var source = currentText
|
{
|
||||||
// shaderPackModel.loadMetadata(source)
|
updates.push("wallpaper")
|
||||||
// root.cfg_shader_package = "file://" + shaderPackModel.path(source)
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { Layout.preferredHeight: Constants.smallMargin }
|
Item { Layout.preferredHeight: Constants.smallMargin }
|
||||||
@@ -171,6 +187,15 @@ Item
|
|||||||
onEditingFinished: () =>
|
onEditingFinished: () =>
|
||||||
{
|
{
|
||||||
value = parseInt(text)
|
value = parseInt(text)
|
||||||
|
|
||||||
|
if(updates.indexOf("resolutionX") >= 0 && value === manager.resolutionX)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("resolutionX"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("resolutionX")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onPressed: (event) =>
|
Keys.onPressed: (event) =>
|
||||||
@@ -193,7 +218,8 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
text: qsTr("Y")
|
text: qsTr("Y")
|
||||||
font: Constants.h3Font
|
font: Constants.h3Font
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -202,7 +228,8 @@ Item
|
|||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField
|
||||||
|
{
|
||||||
property int value: manager.resolutionY
|
property int value: manager.resolutionY
|
||||||
|
|
||||||
Layout.preferredHeight: 36
|
Layout.preferredHeight: 36
|
||||||
@@ -216,6 +243,15 @@ Item
|
|||||||
onEditingFinished: () =>
|
onEditingFinished: () =>
|
||||||
{
|
{
|
||||||
value = parseInt(text)
|
value = parseInt(text)
|
||||||
|
|
||||||
|
if(updates.indexOf("resolutionY") >= 0 && value === manager.resolutionY)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("resolutionY"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("resolutionY")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onPressed: (event) =>
|
Keys.onPressed: (event) =>
|
||||||
@@ -245,7 +281,8 @@ Item
|
|||||||
{
|
{
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
text: qsTr("Frame Rate")
|
text: qsTr("Frame Rate")
|
||||||
font: Constants.h3Font
|
font: Constants.h3Font
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -260,7 +297,19 @@ Item
|
|||||||
from: 1
|
from: 1
|
||||||
to: 60
|
to: 60
|
||||||
stepSize: 0.01
|
stepSize: 0.01
|
||||||
onValueChanged: frameRateField.text = String(value.toFixed(2));
|
onValueChanged:
|
||||||
|
{
|
||||||
|
frameRateField.text = String(value.toFixed(2));
|
||||||
|
|
||||||
|
if(updates.indexOf("frameRate") >= 0 && value === manager.targetFramerate)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("frameRate"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("frameRate")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: () => {
|
Component.onCompleted: () => {
|
||||||
value = manager.targetFramerate
|
value = manager.targetFramerate
|
||||||
@@ -310,7 +359,8 @@ Item
|
|||||||
id: speedLayout
|
id: speedLayout
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
text: qsTr("Shader Speed")
|
text: qsTr("Shader Speed")
|
||||||
font: Constants.h3Font
|
font: Constants.h3Font
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -326,9 +376,22 @@ Item
|
|||||||
from: -4.0
|
from: -4.0
|
||||||
to: 4.0
|
to: 4.0
|
||||||
stepSize: 0.01
|
stepSize: 0.01
|
||||||
onValueChanged: shaderSpeedField.text = String(value.toFixed(2));
|
onValueChanged:
|
||||||
|
{
|
||||||
|
if(updates.indexOf("shaderSpeed") >= 0 && value === manager.shaderSpeed)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("shaderSpeed"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("shaderSpeed")
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: () => {
|
shaderSpeedField.text = String(value.toFixed(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: () =>
|
||||||
|
{
|
||||||
value = manager.shaderSpeed
|
value = manager.shaderSpeed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,7 +474,17 @@ Item
|
|||||||
]
|
]
|
||||||
|
|
||||||
textRole: modelData
|
textRole: modelData
|
||||||
//onCurrentIndexChanged: root.cfg_pauseMode = currentIndex
|
onCurrentIndexChanged:
|
||||||
|
{
|
||||||
|
if(updates.indexOf("pauseMode") && currentIndex === manager.pauseMode)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("pauseMode"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("pauseMode")
|
||||||
|
}
|
||||||
|
}
|
||||||
currentIndex: manager.pauseMode
|
currentIndex: manager.pauseMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,7 +504,8 @@ Item
|
|||||||
{
|
{
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
text: qsTr("Excluded Windows")
|
text: qsTr("Excluded Windows")
|
||||||
font: Constants.h3Font
|
font: Constants.h3Font
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -448,6 +522,15 @@ Item
|
|||||||
onEditingFinished: () =>
|
onEditingFinished: () =>
|
||||||
{
|
{
|
||||||
windows = excludeWindows.text.trim().replace(/\s+/g, "").split(",");
|
windows = excludeWindows.text.trim().replace(/\s+/g, "").split(",");
|
||||||
|
|
||||||
|
if(updates.indexOf("excludeWindows") >= 0 && windows === manager.excludedWindows)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("excludeWindows"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("excludeWindows")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
@@ -459,16 +542,27 @@ Item
|
|||||||
|
|
||||||
CheckBox
|
CheckBox
|
||||||
{
|
{
|
||||||
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", cfg_isPaused ? "Playing" : "Paused")
|
|
||||||
|
|
||||||
id: runningCombo
|
id: runningCombo
|
||||||
checked: manager.running
|
checked: manager.running
|
||||||
text: qsTr("Shader Is Running")
|
text: qsTr("Shader Is Running")
|
||||||
|
|
||||||
|
onCheckedChanged:
|
||||||
|
{
|
||||||
|
if(updates.indexOf("shaderRunning") > 0 && checked === manager.running)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("shaderRunning"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("shaderRunning")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { Layout.preferredHeight: Constants.largeMargin }
|
Item { Layout.preferredHeight: Constants.largeMargin }
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
|
{
|
||||||
text: qsTr("Mouse Tracking")
|
text: qsTr("Mouse Tracking")
|
||||||
font: Constants.h2Font
|
font: Constants.h2Font
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -480,14 +574,15 @@ Item
|
|||||||
{
|
{
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
Text {
|
Text
|
||||||
text: qsTr("Mouse Tracking Bias")
|
{
|
||||||
|
text: qsTr("Mouse Speed Bias")
|
||||||
font: Constants.h3Font
|
font: Constants.h3Font
|
||||||
color: palette.text
|
color: palette.text
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
Layout.preferredHeight: 36
|
Layout.preferredHeight: 36
|
||||||
}
|
}
|
||||||
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Mouse bias:")
|
|
||||||
Slider
|
Slider
|
||||||
{
|
{
|
||||||
id: mouseBiasSlider
|
id: mouseBiasSlider
|
||||||
@@ -500,6 +595,15 @@ Item
|
|||||||
onValueChanged: () =>
|
onValueChanged: () =>
|
||||||
{
|
{
|
||||||
mouseBiasField.text = String(value.toFixed(2));
|
mouseBiasField.text = String(value.toFixed(2));
|
||||||
|
|
||||||
|
if(updates.indexOf("mouseSpeedBias") >= 0 && value === manager.mouseTrackingBias)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("mouseSpeedBias"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("mouseSpeedBias")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TextField
|
TextField
|
||||||
@@ -546,19 +650,29 @@ Item
|
|||||||
|
|
||||||
CheckBox
|
CheckBox
|
||||||
{
|
{
|
||||||
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", cfg_isPaused ? "Playing" : "Paused")
|
|
||||||
|
|
||||||
id: mouseTrackingCheckbox
|
id: mouseTrackingCheckbox
|
||||||
checked: manager.mouseTrackingEnabled
|
checked: manager.mouseTrackingEnabled
|
||||||
text: qsTr("Mouse Tracking Enabled")
|
text: qsTr("Mouse Tracking Enabled")
|
||||||
|
|
||||||
|
onCheckedChanged:
|
||||||
|
{
|
||||||
|
if(updates.indexOf("mouseEnabled") >= 0 && currentIndex === manager.mouseTrackingEnabled)
|
||||||
|
{
|
||||||
|
updates.slice(updates.indexOf("mouseEnabled"), 1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updates.push("mouseEnabled")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button
|
// Button
|
||||||
// {
|
// {
|
||||||
// visible: navBar.currentIndex === 2
|
// visible: navBar.currentIndex === 2
|
||||||
// id: kofiButton
|
// id: kofiButton
|
||||||
// Layout.preferredWidth: Kirigami.Units.gridUnit * 5
|
// Layout.preferredWidth: 4 * 5
|
||||||
// Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
// Layout.preferredHeight: 4 * 3
|
||||||
|
|
||||||
// contentItem: RowLayout
|
// contentItem: RowLayout
|
||||||
// {
|
// {
|
||||||
@@ -595,10 +709,9 @@ Item
|
|||||||
|
|
||||||
RowLayout
|
RowLayout
|
||||||
{
|
{
|
||||||
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Author:")
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 11
|
Layout.preferredWidth: 4 * 11
|
||||||
text: shaderPackModel.metadata.author
|
text: shaderPackModel.metadata.author
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -607,10 +720,9 @@ Item
|
|||||||
|
|
||||||
RowLayout
|
RowLayout
|
||||||
{
|
{
|
||||||
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Description:")
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 16
|
Layout.preferredWidth: 4 * 16
|
||||||
text: shaderPackModel.metadata.description
|
text: shaderPackModel.metadata.description
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -622,10 +734,9 @@ Item
|
|||||||
|
|
||||||
RowLayout
|
RowLayout
|
||||||
{
|
{
|
||||||
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "License:")
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 11
|
Layout.preferredWidth: 4 * 11
|
||||||
text: shaderPackModel.metadata.license
|
text: shaderPackModel.metadata.license
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -634,10 +745,9 @@ Item
|
|||||||
|
|
||||||
RowLayout
|
RowLayout
|
||||||
{
|
{
|
||||||
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Version:")
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 11
|
Layout.preferredWidth: 4 * 11
|
||||||
text: shaderPackModel.metadata.version
|
text: shaderPackModel.metadata.version
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
color: palette.text
|
color: palette.text
|
||||||
@@ -646,4 +756,56 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
manager.pauseMode = cfg_pauseMode
|
||||||
|
manager.shaderSpeed = cfg_shaderSpeed
|
||||||
|
manager.mouseTrackingBias = cfg_mouseSpeedBias
|
||||||
|
manager.mouseTrackingEnabled = cfg_enableMouseTracking
|
||||||
|
manager.onlyCheckActiveScreen = cfg_checkActiveScreen
|
||||||
|
manager.excludedWindows = cfg_excludeWindows
|
||||||
|
manager.running = cfg_running
|
||||||
|
manager.resolutionX = cfg_resolution_x
|
||||||
|
manager.resolutionY = cfg_resolution_y
|
||||||
|
manager.targetFramerate = cfg_framerate_limit
|
||||||
|
|
||||||
|
updates.splice(0, updates.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset()
|
||||||
|
{
|
||||||
|
if(updated)
|
||||||
|
{
|
||||||
|
cfg_pauseMode = manager.pauseMode
|
||||||
|
cfg_shaderSpeed = manager.shaderSpeed
|
||||||
|
cfg_mouseSpeedBias = manager.mouseTrackingBias
|
||||||
|
cfg_enableMouseTracking = manager.mouseTrackingEnabled
|
||||||
|
cfg_checkActiveScreen = manager.onlyCheckActiveScreen
|
||||||
|
cfg_excludeWindows = manager.excludedWindows
|
||||||
|
cfg_running = manager.running
|
||||||
|
cfg_resolution_x = manager.resolutionX
|
||||||
|
cfg_resolution_y = manager.resolutionY
|
||||||
|
cfg_framerate_limit = manager.targetFramerate
|
||||||
|
|
||||||
|
updates.splice(0, updates.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
qt_add_library(KomplexHubViews STATIC)
|
||||||
|
qt6_add_qml_module(KomplexHubViews
|
||||||
|
URI "KomplexHub.Views"
|
||||||
|
VERSION 1.0
|
||||||
|
RESOURCE_PREFIX "/qt/qml"
|
||||||
|
QML_FILES
|
||||||
|
"CompletedView.qml"
|
||||||
|
"DownloadView.qml"
|
||||||
|
"ErrorView.qml"
|
||||||
|
"ImageView.qml"
|
||||||
|
"PackView.qml"
|
||||||
|
"VideoView.qml"
|
||||||
|
)
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
property DownloadManager manager: null
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
VerticalSpacer { }
|
||||||
|
|
||||||
|
KeroSuccessAvatar
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredHeight: 512
|
||||||
|
Layout.maximumHeight: 512
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 36
|
||||||
|
Layout.maximumHeight: 36
|
||||||
|
Layout.margins: Constants.largeMargin
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
SquareButton
|
||||||
|
{
|
||||||
|
Layout.preferredWidth: 186
|
||||||
|
Layout.fillHeight: true
|
||||||
|
text: qsTr("Okay")
|
||||||
|
|
||||||
|
onTriggered: () =>
|
||||||
|
{
|
||||||
|
if(manager != null)
|
||||||
|
{
|
||||||
|
manager.reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SquareButton
|
||||||
|
{
|
||||||
|
Layout.preferredWidth: 186
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
text: qsTr("Set Wallpaper")
|
||||||
|
icon.source: "qrc:/images/icons/icons8-download.svg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
import KomplexHub.Kero
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
property string thumbnail
|
||||||
|
property DownloadManager manager
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
BackgroundImage
|
||||||
|
{
|
||||||
|
source: thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Constants.largeMargin
|
||||||
|
|
||||||
|
Item { Layout.preferredHeight: 64; Layout.fillWidth: true }
|
||||||
|
|
||||||
|
KeroBuildingAnimation
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalSpacer {}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: qsTr("Download Progress")
|
||||||
|
font: Constants.h3Font
|
||||||
|
color : palette.text
|
||||||
|
Layout.preferredHeight: Constants.largeMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Constants.largeMargin
|
||||||
|
|
||||||
|
ProgressBar
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
value: manager.downloadProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: manager.downloadedBytes
|
||||||
|
font: Constants.h4Font
|
||||||
|
color : palette.text
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: "/"
|
||||||
|
font: Constants.h4Font
|
||||||
|
color : palette.text
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: manager.downloadSize
|
||||||
|
font: Constants.h4Font
|
||||||
|
color : palette.text
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: qsTr("Install Progress")
|
||||||
|
font: Constants.h3Font
|
||||||
|
color : palette.text
|
||||||
|
height: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Constants.largeMargin
|
||||||
|
|
||||||
|
ProgressBar
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
value: manager.compileProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: manager.compileStepsCompleted
|
||||||
|
font: Constants.h4Font
|
||||||
|
color : palette.text
|
||||||
|
Layout.preferredHeight: Constants.largeMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: "/"
|
||||||
|
font: Constants.h4Font
|
||||||
|
color : palette.text
|
||||||
|
Layout.preferredHeight: Constants.largeMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: manager.compileSteps
|
||||||
|
font: Constants.h4Font
|
||||||
|
color : palette.text
|
||||||
|
Layout.preferredHeight: Constants.largeMargin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.preferredHeight: Constants.largeMargin * 2; Layout.fillWidth: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
property DownloadManager manager: null
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
VerticalSpacer { }
|
||||||
|
|
||||||
|
KeroWarningAvatar
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredHeight: 512
|
||||||
|
Layout.maximumHeight: 512
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 36
|
||||||
|
Layout.maximumHeight: 36
|
||||||
|
Layout.margins: Constants.largeMargin
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
SquareButton
|
||||||
|
{
|
||||||
|
Layout.preferredWidth: 186
|
||||||
|
Layout.fillHeight: true
|
||||||
|
text: qsTr("Okay")
|
||||||
|
|
||||||
|
onTriggered: () =>
|
||||||
|
{
|
||||||
|
if(manager != null)
|
||||||
|
{
|
||||||
|
manager.reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,390 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
property string uuid
|
||||||
|
property string author
|
||||||
|
property string authorUrl
|
||||||
|
property string description
|
||||||
|
property string thumbnail
|
||||||
|
property string portrait
|
||||||
|
property string landscape
|
||||||
|
property string fullScreen
|
||||||
|
property string portraitSize
|
||||||
|
property string landscapeSize
|
||||||
|
property string fullScreenSize
|
||||||
|
property string backgroundPortrait
|
||||||
|
property string backgroundLandscape
|
||||||
|
|
||||||
|
property int imageHeight
|
||||||
|
property int imageWidth
|
||||||
|
|
||||||
|
id: rootItem
|
||||||
|
|
||||||
|
DownloadManager
|
||||||
|
{
|
||||||
|
id: downloadManager
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: pageView
|
||||||
|
anchors.fill: parent
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
BackgroundImage
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
source: width > height ? backgroundLandscape : backgroundPortrait
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Constants.largeMargin
|
||||||
|
spacing: Constants.largeMargin
|
||||||
|
|
||||||
|
ImageFrame
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||||
|
Layout.topMargin: Constants.largeMargin
|
||||||
|
Layout.preferredHeight: width / 1.77777777778
|
||||||
|
Layout.maximumWidth: 800
|
||||||
|
|
||||||
|
source: rootItem.thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: titleText
|
||||||
|
text: rootItem.author
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: Constants.h3Font.pixelSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: descriptionText
|
||||||
|
text: rootItem.description
|
||||||
|
color: palette.text
|
||||||
|
font.pointSize: Constants.h4Font.pixelSize
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Spacer **/
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: qsTr("Available Downloads")
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: Constants.h3Font.pixelSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ComboBox
|
||||||
|
{
|
||||||
|
id: downloadSelector
|
||||||
|
model:[
|
||||||
|
"Screen (" + fullScreenSize + ")",
|
||||||
|
"Portrait (" + portraitSize + ")",
|
||||||
|
"Landscape (" + landscapeSize + ")"
|
||||||
|
]
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 36
|
||||||
|
}
|
||||||
|
SquareButton
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 36
|
||||||
|
Layout.preferredWidth: 128
|
||||||
|
text: qsTr("Download")
|
||||||
|
icon.source: "qrc:/images/icons/icons8-download.svg"
|
||||||
|
|
||||||
|
onTriggered: () => rootItem.download()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Spacer **/
|
||||||
|
Item { Layout.fillWidth: true; Layout.fillHeight: true }
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignBottom
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Images Provided Courtesy of Pexels")
|
||||||
|
elide: Text.ElideLeft
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: Constants.h6Font.pixelSize
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
transform: Image.PreserveAspectFit
|
||||||
|
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.preferredWidth: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states:
|
||||||
|
[
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "downloading"
|
||||||
|
when: downloadManager.state === DownloadManager.Downloading
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "complete"
|
||||||
|
when: downloadManager.state === DownloadManager.Complete
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "error"
|
||||||
|
when: downloadManager.state === DownloadManager.Error
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "idle"
|
||||||
|
when: downloadManager.state === DownloadManager.Idle
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadView
|
||||||
|
{
|
||||||
|
id: downloadView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
manager: downloadManager
|
||||||
|
thumbnail: rootItem.thumbnail
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletedView
|
||||||
|
{
|
||||||
|
id: completedView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
manager: downloadManager
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorView
|
||||||
|
{
|
||||||
|
id: errorView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
manager: downloadManager
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function download()
|
||||||
|
{
|
||||||
|
let url = ""
|
||||||
|
|
||||||
|
switch(downloadSelector.currentIndex)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
url = portrait
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
url = landscape
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
url = fullScreen
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadManager.downloadImage(author, authorUrl, description, url)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
property string uuid
|
||||||
|
property string author
|
||||||
|
property string authorId
|
||||||
|
property string description
|
||||||
|
property string thumbnail
|
||||||
|
property string name
|
||||||
|
|
||||||
|
property int imageHeight
|
||||||
|
property int imageWidth
|
||||||
|
|
||||||
|
id: rootItem
|
||||||
|
|
||||||
|
DownloadManager
|
||||||
|
{
|
||||||
|
id: downloadManager
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: pageView
|
||||||
|
anchors.fill: parent
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
BackgroundImage
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
source: rootItem.thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Constants.largeMargin
|
||||||
|
spacing: Constants.largeMargin
|
||||||
|
|
||||||
|
ImageFrame
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop| Qt.AlignHCenter
|
||||||
|
Layout.topMargin: Constants.largeMargin
|
||||||
|
Layout.preferredHeight: width / 1.77777777778
|
||||||
|
Layout.maximumWidth: 800
|
||||||
|
|
||||||
|
source: rootItem.thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: titleText
|
||||||
|
text: rootItem.name
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: Constants.h3Font.pixelSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: descriptionText
|
||||||
|
text: rootItem.description
|
||||||
|
color: palette.text
|
||||||
|
font.pointSize: Constants.h4Font.pixelSize
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: authorText
|
||||||
|
text: qsTr("By: ") + rootItem.author
|
||||||
|
color: palette.text
|
||||||
|
font.pointSize: Constants.h5Font.pixelSize
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
horizontalAlignment: Qt.AlignRight
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Spacer **/
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
SquareButton
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 36
|
||||||
|
Layout.preferredWidth: 128
|
||||||
|
text: qsTr("Download")
|
||||||
|
icon.source: "qrc:/images/icons/icons8-download.svg"
|
||||||
|
|
||||||
|
onTriggered: () => rootItem.download()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Spacer **/
|
||||||
|
Item { Layout.fillWidth: true; Layout.fillHeight: true }
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignBottom
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Shaders Provided Courtesy of ShaderToy, Komplex and Their Respective Authors")
|
||||||
|
elide: Text.ElideLeft
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: Constants.h6Font.pixelSize
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
transform: Image.PreserveAspectFit
|
||||||
|
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.preferredWidth: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states:
|
||||||
|
[
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "downloading"
|
||||||
|
when: downloadManager.state === DownloadManager.Downloading
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "compiling"
|
||||||
|
when: downloadManager.state === DownloadManager.Compiling
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "installing"
|
||||||
|
when: downloadManager.state === DownloadManager.Installing
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "complete"
|
||||||
|
when: downloadManager.state === DownloadManager.Complete
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "error"
|
||||||
|
when: downloadManager.state === DownloadManager.Error
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "idle"
|
||||||
|
when: downloadManager.state === DownloadManager.Idle
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadView
|
||||||
|
{
|
||||||
|
id: downloadView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
manager: downloadManager
|
||||||
|
thumbnail: rootItem.thumbnail
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletedView
|
||||||
|
{
|
||||||
|
id: completedView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
manager: downloadManager
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorView
|
||||||
|
{
|
||||||
|
id: errorView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
manager: downloadManager
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function download()
|
||||||
|
{
|
||||||
|
downloadManager.downloadPack(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: () => downloadManager.reset()
|
||||||
|
}
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
import KomplexHub.Controls
|
||||||
|
import KomplexHub.Kero
|
||||||
|
import KomplexHub.Plugin
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
property string uuid
|
||||||
|
property string author
|
||||||
|
property string authorUrl
|
||||||
|
property string thumbnail
|
||||||
|
property alias model: downloadSelector.model
|
||||||
|
property int modelIndex
|
||||||
|
|
||||||
|
property int imageHeight
|
||||||
|
property int imageWidth
|
||||||
|
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: model ? model : null
|
||||||
|
|
||||||
|
function onRowCountChanged()
|
||||||
|
{
|
||||||
|
downloadSelector.currentIndex = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadManager
|
||||||
|
{
|
||||||
|
id: downloadManager
|
||||||
|
}
|
||||||
|
|
||||||
|
id: rootItem
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: pageView
|
||||||
|
anchors.fill: parent
|
||||||
|
color: palette.base
|
||||||
|
|
||||||
|
BackgroundImage
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
source: rootItem.thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Constants.largeMargin
|
||||||
|
spacing: Constants.largeMargin
|
||||||
|
|
||||||
|
ImageFrame
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop| Qt.AlignHCenter
|
||||||
|
Layout.topMargin: Constants.largeMargin
|
||||||
|
Layout.preferredHeight: width / 1.77777777778
|
||||||
|
Layout.maximumWidth: 800
|
||||||
|
|
||||||
|
source: rootItem.thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: titleText
|
||||||
|
text: rootItem.author
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: Constants.h3Font.pixelSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Spacer **/
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: qsTr("Available Downloads")
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: Constants.h3Font.pixelSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ComboBox
|
||||||
|
{
|
||||||
|
id: downloadSelector
|
||||||
|
textRole: "text"
|
||||||
|
valueRole: "url"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 36
|
||||||
|
}
|
||||||
|
SquareButton
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 36
|
||||||
|
Layout.preferredWidth: 128
|
||||||
|
text: qsTr("Download")
|
||||||
|
icon.source: "qrc:/images/icons/icons8-download.svg"
|
||||||
|
|
||||||
|
onTriggered: () => rootItem.download()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Spacer **/
|
||||||
|
Item { Layout.fillWidth: true; Layout.fillHeight: true }
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignBottom
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Videos Provided Courtesy of Pexels and Their Respective Authors")
|
||||||
|
elide: Text.ElideLeft
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: Constants.h6Font.pixelSize
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
transform: Image.PreserveAspectFit
|
||||||
|
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.preferredWidth: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states:
|
||||||
|
[
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "downloading"
|
||||||
|
when: downloadManager.state === DownloadManager.Downloading
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "complete"
|
||||||
|
when: downloadManager.state === DownloadManager.Complete
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "error"
|
||||||
|
when: downloadManager.state === DownloadManager.Error
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "idle"
|
||||||
|
when: downloadManager.state === DownloadManager.Idle
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: pageView
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: completedView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: errorView
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadView
|
||||||
|
{
|
||||||
|
id: downloadView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
manager: downloadManager
|
||||||
|
thumbnail: rootItem.thumbnail
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletedView
|
||||||
|
{
|
||||||
|
id: completedView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
manager: downloadManager
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorView
|
||||||
|
{
|
||||||
|
id: errorView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity > 0.01
|
||||||
|
manager: downloadManager
|
||||||
|
|
||||||
|
Behavior on opacity
|
||||||
|
{
|
||||||
|
NumberAnimation
|
||||||
|
{
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function download()
|
||||||
|
{
|
||||||
|
downloadManager.downloadImage(author, authorUrl, downloadSelector.currentValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,10 +13,11 @@ qt6_add_qml_module(KomplexHubModule
|
|||||||
RESOURCE_PREFIX "/qt/qml"
|
RESOURCE_PREFIX "/qt/qml"
|
||||||
QML_FILES
|
QML_FILES
|
||||||
"Constants.qml"
|
"Constants.qml"
|
||||||
"EventListModel.qml"
|
|
||||||
"EventListSimulator.qml"
|
|
||||||
"WallpaperModelData.qml"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(KomplexHubModule PROPERTIES VERSION "1.0")
|
||||||
add_subdirectory("Controls")
|
add_subdirectory("Controls")
|
||||||
add_subdirectory("Kero")
|
add_subdirectory("Kero")
|
||||||
|
|||||||
@@ -1,8 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Studio.Application
|
import QtQuick.Studio.Application
|
||||||
|
|
||||||
QtObject {
|
QtObject
|
||||||
|
{
|
||||||
readonly property int width: 1920
|
readonly property int width: 1920
|
||||||
readonly property int height: 1080
|
readonly property int height: 1080
|
||||||
|
|
||||||
@@ -62,8 +81,4 @@ QtObject {
|
|||||||
readonly property int slowAnimationDuration: 750
|
readonly property int slowAnimationDuration: 750
|
||||||
readonly property int normalAnimationDuration: 250
|
readonly property int normalAnimationDuration: 250
|
||||||
readonly property int fastAnimationDuration: 125
|
readonly property int fastAnimationDuration: 125
|
||||||
|
|
||||||
property StudioApplication application: StudioApplication {
|
|
||||||
fontPath: Qt.resolvedUrl("../KomplexHubContent/" + relativeFontDirectory)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-24
@@ -16,30 +16,36 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
#ifndef NEWESTSHADERSPAGINATOR_H
|
import QtCore
|
||||||
#define NEWESTSHADERSPAGINATOR_H
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
#include <QObject>
|
Item
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QEventLoop>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "wallpaperpaginator.h"
|
|
||||||
|
|
||||||
class KOMPLEX_EXPORT NewestShadersPaginator : public WallpaperPaginator
|
|
||||||
{
|
{
|
||||||
public:
|
property alias source: image.source
|
||||||
explicit NewestShadersPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
property alias imageOpacity: effect.opacity
|
||||||
{
|
property alias blur: effect.blur
|
||||||
setUri(
|
property alias saturation: effect.saturation
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_SHADERS_NEWEST)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // NEWESTSHADERSPAGINATOR_H
|
Image
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
id: image
|
||||||
|
source: thumbnail
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect
|
||||||
|
{
|
||||||
|
id: effect
|
||||||
|
anchors.fill: image
|
||||||
|
source: image
|
||||||
|
blurEnabled: true
|
||||||
|
blurMax: 64
|
||||||
|
blur: 1.0
|
||||||
|
opacity: 0.25
|
||||||
|
saturation: -0.8
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
### This file is automatically generated by Qt Design Studio.
|
### This file is automatically generated by Qt Design Studio.
|
||||||
### Do not change
|
### Do not change
|
||||||
|
|
||||||
qt_add_library(KomplexHubModule_Controls STATIC)
|
qt_add_library(KomplexHubControls STATIC)
|
||||||
qt6_add_qml_module(KomplexHubModule_Controls
|
qt6_add_qml_module(KomplexHubControls
|
||||||
URI "KomplexHub.Controls"
|
URI "KomplexHub.Controls"
|
||||||
VERSION 1.0
|
VERSION 1.0
|
||||||
RESOURCE_PREFIX "/qt/qml"
|
RESOURCE_PREFIX "/qt/qml"
|
||||||
@@ -14,12 +14,12 @@ qt6_add_qml_module(KomplexHubModule_Controls
|
|||||||
"Throbber.qml"
|
"Throbber.qml"
|
||||||
"SearchResultItem.qml"
|
"SearchResultItem.qml"
|
||||||
"SearchResultList.qml"
|
"SearchResultList.qml"
|
||||||
QML_FILES PaginationBox.qml
|
"PaginationBox.qml"
|
||||||
QML_FILES PaginatorGrid.qml
|
"PaginatorGrid.qml"
|
||||||
QML_FILES HorizontalPaginator.qml
|
"HorizontalPaginator.qml"
|
||||||
QML_FILES ImageView.qml
|
"VerticalSpacer.qml"
|
||||||
QML_FILES
|
"ImageFrame.qml"
|
||||||
QML_FILES VideoView.qml
|
"BackgroundImage.qml"
|
||||||
QML_FILES PackView.qml
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#set_target_properties(KomplexHubControls PROPERTIES VERSION "1.0")
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -5,7 +24,7 @@ import QtQuick.Layouts
|
|||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
import KomplexHubPlugin
|
import KomplexHub.Plugin
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
@@ -25,7 +44,10 @@ Item
|
|||||||
|
|
||||||
property Component delegate
|
property Component delegate
|
||||||
|
|
||||||
|
signal viewMoreTriggered()
|
||||||
|
|
||||||
id: rootItem
|
id: rootItem
|
||||||
|
clip: true
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
@@ -45,8 +67,6 @@ Item
|
|||||||
height: 245
|
height: 245
|
||||||
color: palette.accent
|
color: palette.accent
|
||||||
radius: 5
|
radius: 5
|
||||||
// x: resultsView.currentItem.x
|
|
||||||
// y: resultsView.currentItem.y
|
|
||||||
Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } }
|
Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||||
Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } }
|
Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||||
}
|
}
|
||||||
@@ -57,6 +77,7 @@ Item
|
|||||||
id: resultsView
|
id: resultsView
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
clip: true
|
||||||
|
|
||||||
spacing: Constants.mediumMargin
|
spacing: Constants.mediumMargin
|
||||||
|
|
||||||
@@ -132,7 +153,7 @@ Item
|
|||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.preferredWidth: 128
|
Layout.preferredWidth: 64
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
id: gradientMap
|
id: gradientMap
|
||||||
@@ -162,6 +183,8 @@ Item
|
|||||||
icon.source: "qrc:/images/icons/icons8-forward.svg"
|
icon.source: "qrc:/images/icons/icons8-forward.svg"
|
||||||
icon.height: 24
|
icon.height: 24
|
||||||
icon.width: 24
|
icon.width: 24
|
||||||
|
|
||||||
|
onTriggered: () => viewMoreTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-23
@@ -16,32 +16,38 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
#ifndef FEATUREDCUBEMAPSPAGINATOR_H
|
import QtCore
|
||||||
#define FEATUREDCUBEMAPSPAGINATOR_H
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
#include <QObject>
|
Item
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QEventLoop>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "wallpaperpaginator.h"
|
|
||||||
|
|
||||||
class KOMPLEX_EXPORT FeaturedCubemapsPaginator : public WallpaperPaginator
|
|
||||||
{
|
{
|
||||||
public:
|
property alias source: viewImage.source
|
||||||
explicit FeaturedCubemapsPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
id: rootItem
|
||||||
|
|
||||||
|
Rectangle
|
||||||
{
|
{
|
||||||
setUri(
|
anchors.fill: parent
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_CUBEMAPS_FEATURED)
|
Layout.alignment: Qt.AlignCenter
|
||||||
);
|
color: palette.base.darker()
|
||||||
|
border.color: palette.midlight
|
||||||
|
|
||||||
controller()->setWindowSize(20);
|
Throbber
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
id: loadingThrobber
|
||||||
|
visible: viewImage.status === Image.Loading
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
#endif // FEATUREDCUBEMAPSPAGINATOR_H
|
Image
|
||||||
|
{
|
||||||
|
id: viewImage
|
||||||
|
anchors.fill: parent
|
||||||
|
transform: Image.PreserveAspectCrop
|
||||||
|
source: rootItem.source
|
||||||
|
visible: !(status === Image.Loading)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Effects
|
|
||||||
|
|
||||||
import KomplexHub
|
|
||||||
import KomplexHub.Controls
|
|
||||||
import KomplexHub.Kero
|
|
||||||
import KomplexHubPlugin
|
|
||||||
|
|
||||||
Item
|
|
||||||
{
|
|
||||||
property string uuid
|
|
||||||
property string author
|
|
||||||
property string authorUrl
|
|
||||||
property string description
|
|
||||||
property string thumbnail
|
|
||||||
property string portrait
|
|
||||||
property string landscape
|
|
||||||
property string original
|
|
||||||
property string fullScreen
|
|
||||||
property string portraitSize
|
|
||||||
property string landscapeSize
|
|
||||||
property string fullScreenSize
|
|
||||||
property string backgroundPortrait
|
|
||||||
property string backgroundLandscape
|
|
||||||
|
|
||||||
property int imageHeight
|
|
||||||
property int imageWidth
|
|
||||||
|
|
||||||
id: rootItem
|
|
||||||
|
|
||||||
Rectangle
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
color: palette.base
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
id: backgroundImage
|
|
||||||
source: width > height ? backgroundLandscape : backgroundPortrait
|
|
||||||
transform: Image.PreserveAspectCrop
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiEffect
|
|
||||||
{
|
|
||||||
anchors.fill: backgroundImage
|
|
||||||
source: backgroundImage
|
|
||||||
blurEnabled: true
|
|
||||||
blurMax: 64
|
|
||||||
blur: 1.0
|
|
||||||
opacity: 0.25
|
|
||||||
saturation: -0.8
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Constants.largeMargin
|
|
||||||
spacing: Constants.largeMargin
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignHCenter
|
|
||||||
Layout.topMargin: 32
|
|
||||||
|
|
||||||
Rectangle
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: width / 1.77777777778
|
|
||||||
Layout.maximumWidth: 800
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
color: palette.base.darker()
|
|
||||||
|
|
||||||
Throbber
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
id: loadingThrobber
|
|
||||||
visible: viewImage.status === Image.Loading
|
|
||||||
}
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
id: viewImage
|
|
||||||
anchors.fill: parent
|
|
||||||
transform: Image.PreserveAspectCrop
|
|
||||||
source: rootItem.thumbnail
|
|
||||||
visible: !(status === Image.Loading)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text
|
|
||||||
{
|
|
||||||
id: titleText
|
|
||||||
text: rootItem.author
|
|
||||||
color: palette.text
|
|
||||||
font.bold: true
|
|
||||||
font.pixelSize: Constants.h3Font.pixelSize
|
|
||||||
elide: Text.ElideRight
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
Text
|
|
||||||
{
|
|
||||||
id: descriptionText
|
|
||||||
text: rootItem.description
|
|
||||||
color: palette.text
|
|
||||||
font.pointSize: Constants.h4Font.pixelSize
|
|
||||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spacer **/
|
|
||||||
Item
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 32
|
|
||||||
}
|
|
||||||
|
|
||||||
Text
|
|
||||||
{
|
|
||||||
text: qsTr("Available Downloads")
|
|
||||||
color: palette.text
|
|
||||||
font.bold: true
|
|
||||||
font.pixelSize: Constants.h3Font.pixelSize
|
|
||||||
elide: Text.ElideRight
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
ComboBox
|
|
||||||
{
|
|
||||||
id: downloadSelector
|
|
||||||
model:[
|
|
||||||
"Screen (" + fullScreenSize + ")",
|
|
||||||
"Portrait (" + portraitSize + ")",
|
|
||||||
"Landscape (" + landscapeSize + ")"
|
|
||||||
]
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 36
|
|
||||||
}
|
|
||||||
SquareButton
|
|
||||||
{
|
|
||||||
Layout.preferredHeight: 36
|
|
||||||
Layout.preferredWidth: 128
|
|
||||||
text: qsTr("Download")
|
|
||||||
icon.source: "qrc:/images/icons/icons8-download.svg"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spacer **/
|
|
||||||
Item { Layout.fillWidth: true; Layout.fillHeight: true }
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignBottom
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: qsTr("Images Provided Courtesy of Pexels")
|
|
||||||
elide: Text.ElideLeft
|
|
||||||
color: palette.text
|
|
||||||
font.bold: true
|
|
||||||
font.pixelSize: Constants.h6Font.pixelSize
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
transform: Image.PreserveAspectFit
|
|
||||||
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
Layout.preferredHeight: 32
|
|
||||||
Layout.preferredWidth: 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -1,177 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Effects
|
|
||||||
|
|
||||||
import KomplexHub
|
|
||||||
import KomplexHub.Controls
|
|
||||||
import KomplexHub.Kero
|
|
||||||
import KomplexHubPlugin
|
|
||||||
|
|
||||||
Item
|
|
||||||
{
|
|
||||||
property string uuid
|
|
||||||
property string author
|
|
||||||
property string authorId
|
|
||||||
property string description
|
|
||||||
property string thumbnail
|
|
||||||
|
|
||||||
property int imageHeight
|
|
||||||
property int imageWidth
|
|
||||||
|
|
||||||
id: rootItem
|
|
||||||
|
|
||||||
Rectangle
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
color: palette.base
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
id: backgroundImage
|
|
||||||
source: thumbnail
|
|
||||||
transform: Image.PreserveAspectCrop
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiEffect
|
|
||||||
{
|
|
||||||
anchors.fill: backgroundImage
|
|
||||||
source: backgroundImage
|
|
||||||
blurEnabled: true
|
|
||||||
blurMax: 64
|
|
||||||
blur: 1.0
|
|
||||||
opacity: 0.25
|
|
||||||
saturation: -0.8
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Constants.largeMargin
|
|
||||||
spacing: Constants.largeMargin
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignHCenter
|
|
||||||
Layout.topMargin: 32
|
|
||||||
|
|
||||||
Rectangle
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: width / 1.77777777778
|
|
||||||
Layout.maximumWidth: 800
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
color: palette.base.darker()
|
|
||||||
|
|
||||||
Throbber
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
id: loadingThrobber
|
|
||||||
visible: viewImage.status === Image.Loading
|
|
||||||
}
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
id: viewImage
|
|
||||||
anchors.fill: parent
|
|
||||||
transform: Image.PreserveAspectCrop
|
|
||||||
source: rootItem.thumbnail
|
|
||||||
visible: !(status === Image.Loading)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text
|
|
||||||
{
|
|
||||||
id: titleText
|
|
||||||
text: rootItem.author
|
|
||||||
color: palette.text
|
|
||||||
font.bold: true
|
|
||||||
font.pixelSize: Constants.h3Font.pixelSize
|
|
||||||
elide: Text.ElideRight
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
Text
|
|
||||||
{
|
|
||||||
id: descriptionText
|
|
||||||
text: rootItem.description
|
|
||||||
color: palette.text
|
|
||||||
font.pointSize: Constants.h4Font.pixelSize
|
|
||||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spacer **/
|
|
||||||
Item
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text
|
|
||||||
// {
|
|
||||||
// text: qsTr("Available Downloads")
|
|
||||||
// color: palette.text
|
|
||||||
// font.bold: true
|
|
||||||
// font.pixelSize: Constants.h3Font.pixelSize
|
|
||||||
// elide: Text.ElideRight
|
|
||||||
|
|
||||||
// Layout.fillWidth: true
|
|
||||||
// Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
|
||||||
// }
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Item { Layout.fillWidth: true }
|
|
||||||
|
|
||||||
SquareButton
|
|
||||||
{
|
|
||||||
Layout.preferredHeight: 36
|
|
||||||
Layout.preferredWidth: 128
|
|
||||||
text: qsTr("Download")
|
|
||||||
icon.source: "qrc:/images/icons/icons8-download.svg"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spacer **/
|
|
||||||
Item { Layout.fillWidth: true; Layout.fillHeight: true }
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignBottom
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: qsTr("Shaders Provided Courtesy of ShaderToy and Their Respective Authors")
|
|
||||||
elide: Text.ElideLeft
|
|
||||||
color: palette.text
|
|
||||||
font.bold: true
|
|
||||||
font.pixelSize: Constants.h6Font.pixelSize
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
transform: Image.PreserveAspectFit
|
|
||||||
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
Layout.preferredHeight: 32
|
|
||||||
Layout.preferredWidth: 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -5,7 +24,7 @@ import QtQuick.Layouts
|
|||||||
import KomplexHub
|
import KomplexHub
|
||||||
import KomplexHub.Controls
|
import KomplexHub.Controls
|
||||||
import KomplexHub.Kero
|
import KomplexHub.Kero
|
||||||
import KomplexHubPlugin
|
import KomplexHub.Plugin
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
|
* Komplex Wallpaper Engine
|
||||||
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
|
* Copyright (C) 2026 @DigitalArtifex
|
||||||
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
|
* https://digitalartifex.dev - https://github.com/DigitalArtifex
|
||||||
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
|
*
|
||||||
*/
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -16,7 +35,7 @@ Item {
|
|||||||
signal triggered
|
signal triggered
|
||||||
signal viewMoreTriggered
|
signal viewMoreTriggered
|
||||||
|
|
||||||
id: mainItem
|
id: rootItem
|
||||||
width: 256
|
width: 256
|
||||||
height: 256
|
height: 256
|
||||||
clip: true
|
clip: true
|
||||||
@@ -48,7 +67,7 @@ Item {
|
|||||||
onReleased: () => {
|
onReleased: () => {
|
||||||
if(!states.selected)
|
if(!states.selected)
|
||||||
{
|
{
|
||||||
mainItem.triggered()
|
rootItem.triggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,47 +76,13 @@ Item {
|
|||||||
{
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Rectangle
|
ImageFrame
|
||||||
{
|
{
|
||||||
Layout.preferredWidth: 250
|
Layout.preferredWidth: 250
|
||||||
Layout.preferredHeight: 141
|
Layout.preferredHeight: 141
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||||
Layout.topMargin: 3
|
Layout.topMargin: 3
|
||||||
|
source: rootItem.thumbnail
|
||||||
border.color: palette.alternateBase.lighter(1.75)
|
|
||||||
|
|
||||||
color: palette.base.lighter(1.25)
|
|
||||||
|
|
||||||
Throbber
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
id: loadingThrobber
|
|
||||||
visible: viewImage.status === Image.Loading
|
|
||||||
}
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
property int retries: 0
|
|
||||||
id: viewImage
|
|
||||||
anchors.fill: parent
|
|
||||||
source: mainItem.thumbnail
|
|
||||||
visible: !(status === Image.Loading)
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
|
|
||||||
onStatusChanged: () =>
|
|
||||||
{
|
|
||||||
// if(status === Image.Error)
|
|
||||||
// {
|
|
||||||
// if(retries <= 3)
|
|
||||||
// {
|
|
||||||
// ++retries
|
|
||||||
// let src = source
|
|
||||||
// source = ""
|
|
||||||
// source = src
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image
|
Image
|
||||||
{
|
{
|
||||||
@@ -108,18 +93,18 @@ Item {
|
|||||||
|
|
||||||
width: 24
|
width: 24
|
||||||
height: 24
|
height: 24
|
||||||
transform: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
opacity: 0.5
|
opacity: 0.5
|
||||||
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
||||||
|
|
||||||
visible: mainItem.pexels
|
visible: rootItem.pexels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
color: palette.text
|
color: palette.text
|
||||||
text: mainItem.title
|
text: rootItem.title
|
||||||
|
|
||||||
font.pixelSize: 16
|
font.pixelSize: 16
|
||||||
font.bold: true
|
font.bold: true
|
||||||
@@ -131,25 +116,13 @@ Item {
|
|||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
Item { Layout.fillHeight: true }
|
||||||
|
|
||||||
Text
|
|
||||||
{
|
|
||||||
color: palette.text
|
|
||||||
font.pixelSize: 12
|
|
||||||
text: "By: " + mainItem.author
|
|
||||||
leftPadding: 12
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
|
|
||||||
Layout.preferredWidth: 250
|
|
||||||
visible: !mainItem.pexels
|
|
||||||
}
|
|
||||||
|
|
||||||
Text
|
Text
|
||||||
{
|
{
|
||||||
id: descriptionText
|
id: descriptionText
|
||||||
clip: true
|
clip: true
|
||||||
color: palette.text
|
color: palette.text
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
text: mainItem.description
|
text: rootItem.description
|
||||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
textFormat: Text.PlainText
|
textFormat: Text.PlainText
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
@@ -162,6 +135,19 @@ Item {
|
|||||||
Layout.bottomMargin: 3
|
Layout.bottomMargin: 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.text
|
||||||
|
font.pixelSize: 12
|
||||||
|
text: "By: " + rootItem.author
|
||||||
|
leftPadding: Constants.mediumMargin
|
||||||
|
rightPadding: Constants.mediumMargin
|
||||||
|
horizontalAlignment: Qt.AlignRight
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
SquareButton
|
SquareButton
|
||||||
{
|
{
|
||||||
id: viewMoreButton
|
id: viewMoreButton
|
||||||
@@ -176,7 +162,7 @@ Item {
|
|||||||
opacity: 0
|
opacity: 0
|
||||||
|
|
||||||
onTriggered: () => {
|
onTriggered: () => {
|
||||||
mainItem.viewMoreTriggered()
|
rootItem.viewMoreTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +175,7 @@ Item {
|
|||||||
id: states
|
id: states
|
||||||
property bool clicked: false
|
property bool clicked: false
|
||||||
property bool hovered: false
|
property bool hovered: false
|
||||||
property alias selected: mainItem.selected
|
property alias selected: rootItem.selected
|
||||||
property bool idle: true
|
property bool idle: true
|
||||||
|
|
||||||
onIdleChanged: () =>
|
onIdleChanged: () =>
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
|||||||
+7
-24
@@ -16,30 +16,13 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
#ifndef SEARCHSHADERSPAGINATOR_H
|
import QtCore
|
||||||
#define SEARCHSHADERSPAGINATOR_H
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
#include <QObject>
|
Rectangle
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QEventLoop>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "wallpaperpaginator.h"
|
|
||||||
|
|
||||||
class KOMPLEX_EXPORT SearchShadersPaginator : public WallpaperPaginator
|
|
||||||
{
|
{
|
||||||
public:
|
Layout.fillHeight: true
|
||||||
explicit SearchShadersPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
|
||||||
{
|
|
||||||
setUri(
|
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_SHADERS_SEARCH)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SEARCHSHADERSPAGINATOR_H
|
color: "transparent"
|
||||||
|
}
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Effects
|
|
||||||
|
|
||||||
import KomplexHub
|
|
||||||
import KomplexHub.Controls
|
|
||||||
import KomplexHub.Kero
|
|
||||||
import KomplexHubPlugin
|
|
||||||
|
|
||||||
Item
|
|
||||||
{
|
|
||||||
property string uuid
|
|
||||||
property string author
|
|
||||||
property string authorUrl
|
|
||||||
property string thumbnail
|
|
||||||
property alias model: downloadSelector.model
|
|
||||||
property int modelIndex
|
|
||||||
|
|
||||||
property int imageHeight
|
|
||||||
property int imageWidth
|
|
||||||
|
|
||||||
visible: opacity > 0.01
|
|
||||||
onVisibleChanged: () =>
|
|
||||||
{
|
|
||||||
if(!visible)
|
|
||||||
{
|
|
||||||
model = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections
|
|
||||||
{
|
|
||||||
target: model
|
|
||||||
|
|
||||||
function onRowCountChanged()
|
|
||||||
{
|
|
||||||
downloadSelector.currentIndex = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
id: rootItem
|
|
||||||
|
|
||||||
Rectangle
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
color: palette.base
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
id: backgroundImage
|
|
||||||
source: thumbnail
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: false
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiEffect
|
|
||||||
{
|
|
||||||
anchors.fill: backgroundImage
|
|
||||||
source: backgroundImage
|
|
||||||
blurEnabled: true
|
|
||||||
blurMax: 64
|
|
||||||
blur: 1.0
|
|
||||||
opacity: 0.25
|
|
||||||
saturation: -0.8
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Constants.largeMargin
|
|
||||||
spacing: Constants.largeMargin
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignHCenter
|
|
||||||
Layout.topMargin: 32
|
|
||||||
|
|
||||||
Rectangle
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: width / 1.77777777778
|
|
||||||
Layout.maximumWidth: 800
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
color: palette.base.darker()
|
|
||||||
|
|
||||||
Throbber
|
|
||||||
{
|
|
||||||
anchors.fill: parent
|
|
||||||
id: loadingThrobber
|
|
||||||
visible: viewImage.status === Image.Loading
|
|
||||||
}
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
id: viewImage
|
|
||||||
anchors.fill: parent
|
|
||||||
source: rootItem.thumbnail
|
|
||||||
visible: !(status === Image.Loading)
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text
|
|
||||||
{
|
|
||||||
id: titleText
|
|
||||||
text: rootItem.author
|
|
||||||
color: palette.text
|
|
||||||
font.bold: true
|
|
||||||
font.pixelSize: Constants.h3Font.pixelSize
|
|
||||||
elide: Text.ElideRight
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spacer **/
|
|
||||||
Item
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 32
|
|
||||||
}
|
|
||||||
|
|
||||||
Text
|
|
||||||
{
|
|
||||||
text: qsTr("Available Downloads")
|
|
||||||
color: palette.text
|
|
||||||
font.bold: true
|
|
||||||
font.pixelSize: Constants.h3Font.pixelSize
|
|
||||||
elide: Text.ElideRight
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop| Qt.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
ComboBox
|
|
||||||
{
|
|
||||||
id: downloadSelector
|
|
||||||
textRole: "text"
|
|
||||||
valueRole: "url"
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 36
|
|
||||||
}
|
|
||||||
SquareButton
|
|
||||||
{
|
|
||||||
Layout.preferredHeight: 36
|
|
||||||
Layout.preferredWidth: 128
|
|
||||||
text: qsTr("Download")
|
|
||||||
icon.source: "qrc:/images/icons/icons8-download.svg"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spacer **/
|
|
||||||
Item { Layout.fillWidth: true; Layout.fillHeight: true }
|
|
||||||
|
|
||||||
RowLayout
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignBottom
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: qsTr("Videos Provided Courtesy of Pexels and Their Respective Authors")
|
|
||||||
elide: Text.ElideLeft
|
|
||||||
color: palette.text
|
|
||||||
font.bold: true
|
|
||||||
font.pixelSize: Constants.h6Font.pixelSize
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
Image
|
|
||||||
{
|
|
||||||
transform: Image.PreserveAspectFit
|
|
||||||
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
Layout.preferredHeight: 32
|
|
||||||
Layout.preferredWidth: 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
|
|
||||||
ListModel {
|
|
||||||
id: eventListModel
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
eventId: "enterPressed"
|
|
||||||
eventDescription: "Emitted when pressing the enter button"
|
|
||||||
shortcut: "Return"
|
|
||||||
parameters: "Enter"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Studio.EventSimulator
|
|
||||||
import QtQuick.Studio.EventSystem
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: simulator
|
|
||||||
property bool active: true
|
|
||||||
|
|
||||||
property Timer __timer: Timer {
|
|
||||||
id: timer
|
|
||||||
interval: 100
|
|
||||||
onTriggered: {
|
|
||||||
EventSimulator.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
EventSystem.init(Qt.resolvedUrl("EventListModel.qml"))
|
|
||||||
if (simulator.active)
|
|
||||||
timer.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
qt_add_library(KomplexHubModule_Kero STATIC)
|
qt_add_library(KomplexHubKero STATIC)
|
||||||
qt6_add_qml_module(KomplexHubModule_Kero
|
qt6_add_qml_module(KomplexHubKero
|
||||||
URI "KomplexHub.Kero"
|
URI "KomplexHub.Kero"
|
||||||
VERSION 1.0
|
VERSION 1.0
|
||||||
RESOURCE_PREFIX "/qt/qml"
|
RESOURCE_PREFIX "/qt/qml"
|
||||||
@@ -11,4 +11,7 @@ qt6_add_qml_module(KomplexHubModule_Kero
|
|||||||
"KeroLoadingAnimation.qml"
|
"KeroLoadingAnimation.qml"
|
||||||
"KeroNoResultsAvatar.qml"
|
"KeroNoResultsAvatar.qml"
|
||||||
"KeroWarningAvatar.qml"
|
"KeroWarningAvatar.qml"
|
||||||
|
"KeroHeader.qml"
|
||||||
|
"KeroSuccessAvatar.qml"
|
||||||
)
|
)
|
||||||
|
#set_target_properties(KomplexHubKero PROPERTIES VERSION "1.0")
|
||||||
@@ -1,12 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import KomplexHub
|
import KomplexHub
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property string title: qsTr("Loading")
|
property string title: qsTr("Building")
|
||||||
property string description: qsTr("Kero is busy looking for wallpapers..we promise")
|
property string description: qsTr("Kero is getting your wallpaper ready")
|
||||||
property color color: palette.window
|
property color color: "transparent"
|
||||||
|
|
||||||
id: keroLoadingOverlayRoot
|
id: keroLoadingOverlayRoot
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls 2.0
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import KomplexHub
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
property string title: qsTr("Wallpaper Spotlight")
|
||||||
|
property string description: qsTr("Featured Images and Live Wallpaper Packs")
|
||||||
|
property color color: palette.alternateBase
|
||||||
|
property string image: "qrc:/images/kero/kero_spotlight.png"
|
||||||
|
|
||||||
|
id: rootItem
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
color: rootItem.color
|
||||||
|
border.color: palette.midlight
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: height
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
source: image
|
||||||
|
antialiasing: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.text
|
||||||
|
text: rootItem.title
|
||||||
|
font: Constants.h1Font
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: errorText
|
||||||
|
text: rootItem.description
|
||||||
|
color: palette.text.darker()
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||||
|
Layout.bottomMargin: Constants.largeMargin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import KomplexHub
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property string title: qsTr("Success!")
|
||||||
|
property string description: qsTr("Your new wallpaper is ready!")
|
||||||
|
property color color: "transparent"
|
||||||
|
|
||||||
|
id: keroHelloAvatarRoot
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: keroHelloAvatarBackground
|
||||||
|
anchors.fill: parent
|
||||||
|
color: keroHelloAvatarRoot.color
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: 64
|
||||||
|
Layout.minimumHeight: 64
|
||||||
|
Layout.maximumWidth: 512
|
||||||
|
Layout.maximumHeight: 512
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
source: "qrc:/images/kero/kero_success.png"
|
||||||
|
antialiasing: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
Text {
|
||||||
|
color: palette.text
|
||||||
|
text: keroHelloAvatarRoot.title
|
||||||
|
font: Constants.h1Font
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: errorText
|
||||||
|
text: keroHelloAvatarRoot.description
|
||||||
|
color: palette.text.darker()
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||||
|
Layout.bottomMargin: Constants.largeMargin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -6,7 +24,7 @@ import KomplexHub
|
|||||||
Item {
|
Item {
|
||||||
property string title: qsTr("Warning")
|
property string title: qsTr("Warning")
|
||||||
property string description: qsTr("Kero noticed there might be an issue")
|
property string description: qsTr("Kero noticed there might be an issue")
|
||||||
property color color: palette.window
|
property color color: "transparent"
|
||||||
|
|
||||||
id: keroWarningAvatarRoot
|
id: keroWarningAvatarRoot
|
||||||
|
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
|
|
||||||
ListModel {
|
|
||||||
ListElement {
|
|
||||||
author: "Wizmart"
|
|
||||||
name: "Some cool name 1"
|
|
||||||
description: "This is not a real wallpaper or person"
|
|
||||||
thumbnail: ""
|
|
||||||
uuid: "{aafd-311-afaa}"
|
|
||||||
url: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
author: "Wizmart"
|
|
||||||
name: "Some cool name 2"
|
|
||||||
description: "This is not a real wallpaper or person"
|
|
||||||
thumbnail: ""
|
|
||||||
uuid: "{aafd-311-afaa}"
|
|
||||||
url: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
author: "Wizmart"
|
|
||||||
name: "Some cool name 3"
|
|
||||||
description: "This is not a real wallpaper or person"
|
|
||||||
thumbnail: ""
|
|
||||||
uuid: "{aafd-311-afaa}"
|
|
||||||
url: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
author: "Wizmart"
|
|
||||||
name: "Some cool name 4"
|
|
||||||
description: "This is not a real wallpaper or person"
|
|
||||||
thumbnail: ""
|
|
||||||
uuid: "{aafd-311-afaa}"
|
|
||||||
url: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
author: "Wizmart"
|
|
||||||
name: "Some cool name 5"
|
|
||||||
description: "This is not a real wallpaper or person"
|
|
||||||
thumbnail: ""
|
|
||||||
uuid: "{aafd-311-afaa}"
|
|
||||||
url: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
author: "Wizmart"
|
|
||||||
name: "Some cool name 6"
|
|
||||||
description: "This is not a real wallpaper or person"
|
|
||||||
thumbnail: ""
|
|
||||||
uuid: "{aafd-311-afaa}"
|
|
||||||
url: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
author: "Wizmart"
|
|
||||||
name: "Some cool name 7"
|
|
||||||
description: "This is not a real wallpaper or person"
|
|
||||||
thumbnail: ""
|
|
||||||
uuid: "{aafd-311-afaa}"
|
|
||||||
url: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,38 @@
|
|||||||
|
find_package(
|
||||||
|
Qt6
|
||||||
|
REQUIRED COMPONENTS
|
||||||
|
Core
|
||||||
|
Gui
|
||||||
|
GuiPrivate
|
||||||
|
Widgets
|
||||||
|
Qml
|
||||||
|
Quick
|
||||||
|
QuickControls2
|
||||||
|
QuickTimeline
|
||||||
|
ShaderTools
|
||||||
|
ShaderToolsPrivate
|
||||||
|
Concurrent
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(
|
||||||
|
OpenGL REQUIRED COMPONENTS OpenGL
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(
|
||||||
|
Vulkan REQUIRED COMPONENTS glslang SPIRV-Tools
|
||||||
|
)
|
||||||
|
|
||||||
add_library(
|
add_library(
|
||||||
KomplexHubPlugin
|
KomplexHubPlugin
|
||||||
STATIC
|
STATIC
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(KomplexHubPlugin PROPERTIES VERSION "1.0")
|
||||||
|
|
||||||
qt_add_qml_module(
|
qt_add_qml_module(
|
||||||
KomplexHubPlugin
|
KomplexHubPlugin
|
||||||
URI
|
URI
|
||||||
KomplexHubPlugin
|
"KomplexHub.Plugin"
|
||||||
VERSION
|
VERSION
|
||||||
1.0
|
1.0
|
||||||
SOURCES
|
SOURCES
|
||||||
@@ -19,23 +45,17 @@ qt_add_qml_module(
|
|||||||
newestpacksmodel.cpp
|
newestpacksmodel.cpp
|
||||||
common/komplex_global.h
|
common/komplex_global.h
|
||||||
common/slidingcachecontroller.h
|
common/slidingcachecontroller.h
|
||||||
common/paginator.h
|
|
||||||
common/coreservices.h
|
common/coreservices.h
|
||||||
common/coreservices.cpp
|
common/coreservices.cpp
|
||||||
common/logging.h
|
common/logging.h
|
||||||
common/fetchresult.h
|
common/fetchresult.h
|
||||||
|
paginators/paginator.h
|
||||||
paginators/newestpackspaginator.h
|
paginators/newestpackspaginator.h
|
||||||
paginators/featuredpackspaginator.h
|
paginators/featuredpackspaginator.h
|
||||||
paginators/featuredimagespaginator.h
|
paginators/featuredimagespaginator.h
|
||||||
paginators/wallpaperpaginator.h
|
paginators/wallpaperpaginator.h
|
||||||
paginators/packsearchpaginator.h
|
paginators/packsearchpaginator.h
|
||||||
paginators/imagesearchpaginator.h
|
paginators/imagesearchpaginator.h
|
||||||
paginators/newestshaderspaginator.h
|
|
||||||
paginators/newestcubemapspaginator.h
|
|
||||||
paginators/featuredshaderspaginator.h
|
|
||||||
paginators/featuredcubemapspaginator.h
|
|
||||||
paginators/searchshaderspaginator.h
|
|
||||||
paginators/searchcubemapspaginator.h
|
|
||||||
paginators/videosearchpaginator.h
|
paginators/videosearchpaginator.h
|
||||||
featuredpacksmodel.h
|
featuredpacksmodel.h
|
||||||
featuredpacksmodel.cpp
|
featuredpacksmodel.cpp
|
||||||
@@ -60,7 +80,15 @@ qt_add_qml_module(
|
|||||||
common/exceptions.h
|
common/exceptions.h
|
||||||
common/shadertoymetadata.h
|
common/shadertoymetadata.h
|
||||||
common/shaderpack.h
|
common/shaderpack.h
|
||||||
SOURCES packcompiler.h packcompiler.cpp
|
packcompiler.h
|
||||||
|
packcompiler.cpp
|
||||||
|
common/userservices.h
|
||||||
|
common/userservices.cpp
|
||||||
|
common/qwallet.h
|
||||||
|
common/qwallet.cpp
|
||||||
|
usermodel.h
|
||||||
|
usermodel.cpp
|
||||||
|
SOURCES
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
@@ -69,9 +97,17 @@ target_compile_definitions(
|
|||||||
KOMPLEX_PLUGIN
|
KOMPLEX_PLUGIN
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(3rdparty/qtkeychain)
|
||||||
|
|
||||||
target_link_libraries(KomplexHubPlugin PRIVATE
|
target_link_libraries(KomplexHubPlugin PRIVATE
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt6::Core
|
||||||
Qt${QT_VERSION_MAJOR}::Gui
|
Qt6::Concurrent
|
||||||
|
Qt6::Gui
|
||||||
|
Qt6::GuiPrivate
|
||||||
|
Qt6::ShaderTools
|
||||||
|
Qt6::ShaderToolsPrivate
|
||||||
|
Vulkan::Vulkan
|
||||||
|
qt6keychain
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_ASAN)
|
if(ENABLE_ASAN)
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#include "coreservices.h"
|
#include "coreservices.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
#include "userservices.h"
|
||||||
|
|
||||||
QNetworkAccessManager *CoreServices::s_networkAccessManager = new QNetworkAccessManager();
|
QNetworkAccessManager *CoreServices::s_networkAccessManager = nullptr;
|
||||||
QMutex CoreServices::s_networkAccessMutex;
|
QMutex CoreServices::s_networkAccessMutex;
|
||||||
QSharedPointer<QNetworkAccessManager> CoreServices::s_networkAccessPointer;
|
QSharedPointer<QNetworkAccessManager> CoreServices::s_networkAccessPointer;
|
||||||
|
|
||||||
@@ -11,7 +12,9 @@ auto CoreServices::networkAccessManager() -> QWeakPointer<QNetworkAccessManager>
|
|||||||
|
|
||||||
if(!s_networkAccessPointer)
|
if(!s_networkAccessPointer)
|
||||||
{
|
{
|
||||||
s_networkAccessManager = new QNetworkAccessManager;
|
if(!s_networkAccessManager)
|
||||||
|
{
|
||||||
|
s_networkAccessManager = new QNetworkAccessManager(QCoreApplication::instance());
|
||||||
s_networkAccessManager->setAutoDeleteReplies(true);
|
s_networkAccessManager->setAutoDeleteReplies(true);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
@@ -28,11 +31,12 @@ auto CoreServices::networkAccessManager() -> QWeakPointer<QNetworkAccessManager>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef KOMPLEX_LOCAL_DEV
|
#ifdef KOMPLEX_LOCAL_DEV
|
||||||
reply->ignoreSslErrors();
|
reply->ignoreSslErrors();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
s_networkAccessPointer = QSharedPointer<QNetworkAccessManager>(
|
s_networkAccessPointer = QSharedPointer<QNetworkAccessManager>(
|
||||||
s_networkAccessManager,
|
s_networkAccessManager,
|
||||||
@@ -45,11 +49,7 @@ auto CoreServices::networkAccessManager() -> QWeakPointer<QNetworkAccessManager>
|
|||||||
|
|
||||||
auto CoreServices::sessionToken() -> QByteArray
|
auto CoreServices::sessionToken() -> QByteArray
|
||||||
{
|
{
|
||||||
LOG_ERROR_X(true,
|
return UserServices::userCredentials().sessionToken;
|
||||||
"CoreServices::sessionToken",
|
|
||||||
"User services not yet implemented",
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CoreServices::screenSize() -> QSize
|
auto CoreServices::screenSize() -> QSize
|
||||||
|
|||||||
@@ -1,34 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
#ifndef EXCEPTIONS_H
|
#ifndef EXCEPTIONS_H
|
||||||
#define EXCEPTIONS_H
|
#define EXCEPTIONS_H
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <exception>
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
#include "komplex_global.h"
|
#include "komplex_global.h"
|
||||||
|
|
||||||
struct KOMPLEX_EXPORT Exception : std::exception
|
struct KOMPLEX_EXPORT network_exception : std::ios_base::failure
|
||||||
{
|
{
|
||||||
explicit Exception(const QString &message, quint16 errorCode = 0)
|
network_exception(const std::string &message, const std::string &details, const std::error_code &code) :
|
||||||
: std::exception(), message(message), errorCode(errorCode){}
|
details(details),
|
||||||
|
std::ios_base::failure(message, code) { }
|
||||||
|
|
||||||
const QString message;
|
network_exception(const std::string &message, const std::error_code &code) :
|
||||||
const quint16 errorCode;
|
std::ios_base::failure(message, code) { }
|
||||||
|
|
||||||
|
network_exception(const QString &message, const QString &details, const std::error_code &code) :
|
||||||
|
details(details.toStdString()),
|
||||||
|
std::ios_base::failure(message.toStdString(), code) { }
|
||||||
|
|
||||||
|
network_exception(const QString &message, const int code = errno) :
|
||||||
|
std::ios_base::failure
|
||||||
|
(
|
||||||
|
message.toStdString(),
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
) { }
|
||||||
|
|
||||||
|
const std::string details;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NetworkException : Exception
|
struct KOMPLEX_EXPORT file_exception : std::filesystem::filesystem_error
|
||||||
{
|
{
|
||||||
NetworkException(const QString &message, qsizetype errorCode = 0) : Exception(message, errorCode) {}
|
file_exception(const std::string &message, const std::string &details, const std::error_code &code) :
|
||||||
};
|
details(details),
|
||||||
struct FileException : Exception
|
std::filesystem::filesystem_error(message, code) { }
|
||||||
{
|
|
||||||
FileException(const QString &message, qsizetype errorCode = 0) : Exception(message, errorCode) {}
|
file_exception(const std::string &message, const std::error_code &code) :
|
||||||
};
|
std::filesystem::filesystem_error(message, code) { }
|
||||||
struct SqlException : Exception
|
|
||||||
{
|
file_exception(const std::string &message, const int code = errno) :
|
||||||
SqlException(const QString &message, qsizetype errorCode = 0) : Exception(message, errorCode) {}
|
std::filesystem::filesystem_error
|
||||||
|
(
|
||||||
|
message,
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
) { }
|
||||||
|
|
||||||
|
file_exception(const std::string &message, const std::string &details, const int code = errno) :
|
||||||
|
details(details),
|
||||||
|
std::filesystem::filesystem_error
|
||||||
|
(
|
||||||
|
message,
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
) { }
|
||||||
|
|
||||||
|
const std::string details;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT sql_exception : std::ios_base::failure
|
||||||
struct KOMPLEX_EXPORT ShaderCompilerException : Exception
|
|
||||||
{
|
{
|
||||||
ShaderCompilerException(const QString &message, qsizetype errorCode = 0) : Exception(message, errorCode) {}
|
sql_exception(const std::string &message, const std::string &details, const std::error_code &code) :
|
||||||
|
details(details),
|
||||||
|
std::ios_base::failure(message, code) { }
|
||||||
|
|
||||||
|
sql_exception(const std::string &message, const std::error_code &code) :
|
||||||
|
std::ios_base::failure(message, code) { }
|
||||||
|
|
||||||
|
sql_exception(const std::string &message, const int code = errno) :
|
||||||
|
std::ios_base::failure
|
||||||
|
(
|
||||||
|
message,
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
) { }
|
||||||
|
|
||||||
|
const std::string details;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT wallet_exception : std::ios_base::failure
|
||||||
|
{
|
||||||
|
wallet_exception(const std::string &message, const std::string &details, const std::error_code &code) :
|
||||||
|
details(details),
|
||||||
|
std::ios_base::failure(message, code) { }
|
||||||
|
|
||||||
|
wallet_exception(const std::string &message, const std::error_code &code) :
|
||||||
|
std::ios_base::failure(message, code) { }
|
||||||
|
|
||||||
|
wallet_exception(const std::string &message, const std::string &details, const int code = errno) :
|
||||||
|
details(details),
|
||||||
|
std::ios_base::failure
|
||||||
|
(
|
||||||
|
message,
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
) { }
|
||||||
|
|
||||||
|
wallet_exception(const std::string &message, const int code = errno) :
|
||||||
|
std::ios_base::failure
|
||||||
|
(
|
||||||
|
message,
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
) { }
|
||||||
|
|
||||||
|
const std::string details;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT process_exception : std::runtime_error
|
||||||
|
{
|
||||||
|
process_exception(const std::string &message, const std::string &details, const std::error_code &code) :
|
||||||
|
details(details),
|
||||||
|
code(code),
|
||||||
|
std::runtime_error(message) { }
|
||||||
|
|
||||||
|
process_exception(const std::string &message, const std::error_code &code) :
|
||||||
|
code(code),
|
||||||
|
std::runtime_error(message) { }
|
||||||
|
|
||||||
|
process_exception(const std::string &message, const int code = errno) :
|
||||||
|
code
|
||||||
|
(
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
std::runtime_error
|
||||||
|
(
|
||||||
|
message
|
||||||
|
) { }
|
||||||
|
|
||||||
|
process_exception(const std::string &message, const std::string &details, const int code = errno) :
|
||||||
|
details(details),
|
||||||
|
code
|
||||||
|
(
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
std::runtime_error (message) { }
|
||||||
|
|
||||||
|
const std::string details;
|
||||||
|
const std::error_code code;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace shader
|
||||||
|
{
|
||||||
|
struct KOMPLEX_EXPORT logic_error : std::logic_error
|
||||||
|
{
|
||||||
|
logic_error(const std::string &message, const std::string &details, const std::error_code &code) :
|
||||||
|
details(details),
|
||||||
|
code(code),
|
||||||
|
std::logic_error(message) { }
|
||||||
|
|
||||||
|
logic_error(const std::string &message, const std::error_code &code) :
|
||||||
|
code(code),
|
||||||
|
std::logic_error(message) { }
|
||||||
|
|
||||||
|
logic_error(const std::string &message, const std::string &details = {}, const int code = errno) :
|
||||||
|
code
|
||||||
|
(
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
std::logic_error(message) { }
|
||||||
|
|
||||||
|
const std::string details;
|
||||||
|
const std::error_code code;
|
||||||
|
};
|
||||||
|
}
|
||||||
#endif // EXCEPTIONS_H
|
#endif // EXCEPTIONS_H
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
#ifndef IMAGECACHE_H
|
#ifndef IMAGECACHE_H
|
||||||
#define IMAGECACHE_H
|
#define IMAGECACHE_H
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#ifndef KOMPLEX_GLOBAL_H
|
#ifndef KOMPLEX_GLOBAL_H
|
||||||
#define KOMPLEX_GLOBAL_H
|
#define KOMPLEX_GLOBAL_H
|
||||||
#include <QtTypes>
|
#include <QtTypes>
|
||||||
|
#include <QString>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#ifdef KOMPLEX_PLUGIN
|
#ifdef KOMPLEX_PLUGIN
|
||||||
@@ -36,35 +37,41 @@
|
|||||||
#ifdef KOMPLEX_LOCAL_DEV
|
#ifdef KOMPLEX_LOCAL_DEV
|
||||||
#define KOMPLEX_API_HOST "https://komplexapi.hlab"
|
#define KOMPLEX_API_HOST "https://komplexapi.hlab"
|
||||||
#else
|
#else
|
||||||
#define KOMPLEX_API_HOST "https://api.komplex.dev"
|
inline const QString KOMPLEX_API_HOST = QStringLiteral("https://api.komplex.dev");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define KOMPLEX_API_VERSION "v2"
|
inline const QString KOMPLEX_API_VERSION = QStringLiteral("v2");
|
||||||
|
|
||||||
#define KOMPLEX_ENDPOINT_IMAGES_SEARCH "images/search"
|
inline const QString KOMPLEX_ENDPOINT_IMAGES_SEARCH = QStringLiteral("images/search");
|
||||||
#define KOMPLEX_ENDPOINT_IMAGES_FEATURED "featured/images"
|
inline const QString KOMPLEX_ENDPOINT_IMAGES_FEATURED = QStringLiteral("featured/images");
|
||||||
#define KOMPLEX_ENDPOINT_IMAGES_ITEM "images/item"
|
inline const QString KOMPLEX_ENDPOINT_IMAGES_ITEM = QStringLiteral("images/item");
|
||||||
|
|
||||||
#define KOMPLEX_ENDPOINT_VIDEOS_SEARCH "videos/search"
|
inline const QString KOMPLEX_ENDPOINT_VIDEOS_SEARCH = QStringLiteral("videos/search");
|
||||||
#define KOMPLEX_ENDPOINT_VIDEOS_FEATURED "featured/videos"
|
inline const QString KOMPLEX_ENDPOINT_VIDEOS_FEATURED = QStringLiteral("featured/videos");
|
||||||
#define KOMPLEX_ENDPOINT_VIDEOS_ITEM "videos/item"
|
inline const QString KOMPLEX_ENDPOINT_VIDEOS_ITEM = QStringLiteral("videos/item");
|
||||||
|
|
||||||
#define KOMPLEX_ENDPOINT_SHADERS_SEARCH "shaders/search"
|
inline const QString KOMPLEX_ENDPOINT_SHADERS_SEARCH = QStringLiteral("shaders/search");
|
||||||
#define KOMPLEX_ENDPOINT_SHADERS_FEATURED "shaders/featured"
|
inline const QString KOMPLEX_ENDPOINT_SHADERS_FEATURED = QStringLiteral("shaders/featured");
|
||||||
#define KOMPLEX_ENDPOINT_SHADERS_ITEM "shaders/item"
|
inline const QString KOMPLEX_ENDPOINT_SHADERS_ITEM = QStringLiteral("shaders/item");
|
||||||
#define KOMPLEX_ENDPOINT_SHADERS_NEWEST "shaders/newest"
|
inline const QString KOMPLEX_ENDPOINT_SHADERS_NEWEST = QStringLiteral("shaders/newest");
|
||||||
|
|
||||||
#define KOMPLEX_ENDPOINT_CUBEMAPS_SEARCH "cubemaps/search"
|
inline const QString KOMPLEX_ENDPOINT_CUBEMAPS_SEARCH = QStringLiteral("cubemaps/search");
|
||||||
#define KOMPLEX_ENDPOINT_CUBEMAPS_FEATURED "cubemaps/featured"
|
inline const QString KOMPLEX_ENDPOINT_CUBEMAPS_FEATURED = QStringLiteral("cubemaps/featured");
|
||||||
#define KOMPLEX_ENDPOINT_CUBEMAPS_ITEM "cubemaps/item"
|
inline const QString KOMPLEX_ENDPOINT_CUBEMAPS_ITEM = QStringLiteral("cubemaps/item");
|
||||||
#define KOMPLEX_ENDPOINT_CUBEMAPS_NEWEST "cubemaps/newest"
|
inline const QString KOMPLEX_ENDPOINT_CUBEMAPS_NEWEST = QStringLiteral("cubemaps/newest");
|
||||||
|
|
||||||
#define KOMPLEX_ENDPOINT_PACKS_SEARCH "packs/search"
|
inline const QString KOMPLEX_ENDPOINT_PACKS_SEARCH = QStringLiteral("packs/search");
|
||||||
#define KOMPLEX_ENDPOINT_PACKS_FEATURED "packs/featured"
|
inline const QString KOMPLEX_ENDPOINT_PACKS_FEATURED = QStringLiteral("packs/featured");
|
||||||
#define KOMPLEX_ENDPOINT_PACKS_ITEM "packs/item"
|
inline const QString KOMPLEX_ENDPOINT_PACKS_ITEM = QStringLiteral("packs/item");
|
||||||
#define KOMPLEX_ENDPOINT_PACKS_NEWEST "packs/newest"
|
inline const QString KOMPLEX_ENDPOINT_PACKS_NEWEST = QStringLiteral("packs/newest");
|
||||||
|
|
||||||
inline static qsizetype nullsize = std::numeric_limits<qsizetype>::min();
|
inline const QString KOMPLEX_ENDPOINT_USER_AUTH = QStringLiteral("user/auth");
|
||||||
inline static std::chrono::milliseconds KOMPLEX_RATE_LIMIT(500);
|
|
||||||
|
inline const qsizetype nullsize = std::numeric_limits<qsizetype>::min();
|
||||||
|
inline const std::chrono::milliseconds KOMPLEX_RATE_LIMIT(500);
|
||||||
|
inline const QString KOMPLEX_KEYCHAIN_SERVICE_NAME = QStringLiteral
|
||||||
|
(
|
||||||
|
"com.digitalartifex.komplex"
|
||||||
|
);
|
||||||
|
|
||||||
#endif // KOMPLEX_GLOBAL_H
|
#endif // KOMPLEX_GLOBAL_H
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
#include "qwallet.h"
|
||||||
|
#include "../3rdparty/qtkeychain/qtkeychain/keychain.h"
|
||||||
|
#include "common/exceptions.h"
|
||||||
|
|
||||||
|
auto QWallet::read(const QString &service, const QString &key) const -> QFuture<QByteArray>
|
||||||
|
{
|
||||||
|
return QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this, service(service), key(key)]() -> QByteArray
|
||||||
|
{
|
||||||
|
QEventLoop loop;
|
||||||
|
QByteArray value;
|
||||||
|
|
||||||
|
auto readCredentialJob = new QKeychain::ReadPasswordJob(service);
|
||||||
|
readCredentialJob->setAutoDelete(true);
|
||||||
|
readCredentialJob->setKey(key);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
readCredentialJob,
|
||||||
|
&QKeychain::ReadPasswordJob::finished,
|
||||||
|
this,
|
||||||
|
[this, key, &loop, &value](QKeychain::Job *job)
|
||||||
|
{
|
||||||
|
auto j = static_cast<QKeychain::ReadPasswordJob*>(job);
|
||||||
|
if (j->error() == QKeychain::NoError)
|
||||||
|
{
|
||||||
|
value = j->binaryData();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_errorString = qPrintable(j->errorString());
|
||||||
|
throw wallet_exception
|
||||||
|
(
|
||||||
|
QStringLiteral("Wallet read error").toStdString(),
|
||||||
|
errorString().toStdString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.quit();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
readCredentialJob->start();
|
||||||
|
loop.exec();
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto QWallet::write(const QString &service, const QString &key, const QByteArray &value) -> QFuture<void>
|
||||||
|
{
|
||||||
|
return QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this, service(service), key(key), value(value)]() -> void
|
||||||
|
{
|
||||||
|
QEventLoop loop;
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
auto writeCredentialJob = new QKeychain::WritePasswordJob(service);
|
||||||
|
writeCredentialJob->setAutoDelete(true);
|
||||||
|
writeCredentialJob->setKey(key);
|
||||||
|
writeCredentialJob->setBinaryData(value);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
writeCredentialJob,
|
||||||
|
&QKeychain::WritePasswordJob::finished,
|
||||||
|
this,
|
||||||
|
[this, key, &loop, &success](QKeychain::Job *job)
|
||||||
|
{
|
||||||
|
auto j = static_cast<QKeychain::WritePasswordJob*>(job);
|
||||||
|
if (j->error() != QKeychain::NoError)
|
||||||
|
{
|
||||||
|
setErrorString(qPrintable(j->errorString()));
|
||||||
|
throw wallet_exception
|
||||||
|
(
|
||||||
|
QStringLiteral("Wallet write error").toStdString(),
|
||||||
|
errorString().toStdString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.quit();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
writeCredentialJob->start();
|
||||||
|
loop.exec();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto QWallet::remove(const QString &service, const QString &key) -> QFuture<void>
|
||||||
|
{
|
||||||
|
return QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this, service(service), key(key)]() -> void
|
||||||
|
{
|
||||||
|
QEventLoop loop;
|
||||||
|
bool value;
|
||||||
|
|
||||||
|
auto deleteCredentialJob = new QKeychain::DeletePasswordJob(service);
|
||||||
|
deleteCredentialJob->setAutoDelete(true);
|
||||||
|
deleteCredentialJob->setKey(key);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
deleteCredentialJob,
|
||||||
|
&QKeychain::DeletePasswordJob::finished,
|
||||||
|
this,
|
||||||
|
[this, key, &loop, &value](QKeychain::Job *job)
|
||||||
|
{
|
||||||
|
auto j = static_cast<QKeychain::DeletePasswordJob*>(job);
|
||||||
|
if (j->error() != QKeychain::NoError)
|
||||||
|
{
|
||||||
|
m_errorString = qPrintable(j->errorString());
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.quit();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
deleteCredentialJob->start();
|
||||||
|
loop.exec();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWallet::QWallet(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QWallet::~QWallet()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auto QWallet::errorString() const -> const QString &
|
||||||
|
{
|
||||||
|
return m_errorString;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto QWallet::setErrorString(const QString &errorString) const -> void
|
||||||
|
{
|
||||||
|
m_errorString = errorString;
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
#ifndef QWALLET_H
|
||||||
|
#define QWALLET_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
|
#include "komplex_global.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The QWallet class
|
||||||
|
* QWallet is a QFuture wrapper for QtKeychain to make interaction with the keychain easier
|
||||||
|
*/
|
||||||
|
class KOMPLEX_EXPORT QWallet : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QWallet(QObject *parent = nullptr);
|
||||||
|
~QWallet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief read
|
||||||
|
* Reads the provided key from the system keychain/wallet
|
||||||
|
* @param service
|
||||||
|
* Service name of the application making the request
|
||||||
|
* @param key
|
||||||
|
* Key to read
|
||||||
|
* @return
|
||||||
|
* QFuture for the binary value
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
auto read(const QString &service, const QString &key) const -> QFuture<QByteArray>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief write
|
||||||
|
* Writes the provided value to the system kaychain/wallet
|
||||||
|
* @param service
|
||||||
|
* Service name of the application making the request
|
||||||
|
* @param key
|
||||||
|
* Key to read
|
||||||
|
* @param value
|
||||||
|
* Binary data to store
|
||||||
|
* @return
|
||||||
|
* QFuture
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
auto write(const QString &service, const QString &key, const QByteArray &value) -> QFuture<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief write
|
||||||
|
* Removes the provided value from the system kaychain/wallet
|
||||||
|
* @param service
|
||||||
|
* Service name of the application making the request
|
||||||
|
* @param key
|
||||||
|
* Key to read
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
auto remove(const QString &service, const QString &key) -> QFuture<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief errorString
|
||||||
|
* String describing the last encountered error.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
auto errorString() const -> const QString &;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief setErrorString
|
||||||
|
* Sets the error string
|
||||||
|
* @param errorString
|
||||||
|
*/
|
||||||
|
auto setErrorString(const QString &errorString) const -> void;
|
||||||
|
|
||||||
|
mutable QString m_errorString;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QWALLET_H
|
||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
#ifndef SHADERPACK_H
|
#ifndef SHADERPACK_H
|
||||||
#define SHADERPACK_H
|
#define SHADERPACK_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
#ifndef SHADERTOYMETADATA_H
|
#ifndef SHADERTOYMETADATA_H
|
||||||
#define SHADERTOYMETADATA_H
|
#define SHADERTOYMETADATA_H
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|||||||
@@ -337,7 +337,17 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (index >= m_windowOffset + (SLIDING_CACHE_WINDOW_SIZE - SLIDING_CACHE_PREFETCH_THRESHOLD))
|
qsizetype prefetchThreshold = SLIDING_CACHE_PREFETCH_THRESHOLD;
|
||||||
|
|
||||||
|
if(prefetchThreshold >= windowSize())
|
||||||
|
{
|
||||||
|
prefetchThreshold = std::floor
|
||||||
|
(
|
||||||
|
static_cast<qreal>(windowSize()) * 0.8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (index >= m_windowOffset + (windowSize() - prefetchThreshold))
|
||||||
{
|
{
|
||||||
if(!slideForward())
|
if(!slideForward())
|
||||||
{
|
{
|
||||||
@@ -407,7 +417,7 @@ private:
|
|||||||
m_windowOffset = 0;
|
m_windowOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QThread::sleep(KOMPLEX_RATE_LIMIT);
|
// QThread::sleep(KOMPLEX_RATE_LIMIT);
|
||||||
|
|
||||||
FetchResult<T> result = m_fetch(
|
FetchResult<T> result = m_fetch(
|
||||||
m_windowOffset,
|
m_windowOffset,
|
||||||
@@ -490,7 +500,7 @@ private:
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
QThread::sleep(KOMPLEX_RATE_LIMIT);
|
// QThread::sleep(KOMPLEX_RATE_LIMIT);
|
||||||
|
|
||||||
m_windowOffset -= movementSize;
|
m_windowOffset -= movementSize;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,362 @@
|
|||||||
|
#include "userservices.h"
|
||||||
|
#include "common/komplex_global.h"
|
||||||
|
#include "coreservices.h"
|
||||||
|
#include <QtConcurrent/qtconcurrentrun.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qstandardpaths.h>
|
||||||
|
#include <qstringview.h>
|
||||||
|
|
||||||
|
UserServices::UserServices(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
m_wallet = new QWallet(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserServices::~UserServices()
|
||||||
|
{
|
||||||
|
if(m_wallet)
|
||||||
|
{
|
||||||
|
m_wallet->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::setUserCredentials(const UserCredentials &credentials) -> void
|
||||||
|
{
|
||||||
|
s_userCredentials = credentials;
|
||||||
|
Q_EMIT userCredentialsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::errorString() const -> const QString &
|
||||||
|
{
|
||||||
|
return m_errorString;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::setErrorString(const QString &errorString) -> void
|
||||||
|
{
|
||||||
|
if (m_errorString == errorString)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_errorString = errorString;
|
||||||
|
emit errorStringChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::savePassword(const QString &username, const QByteArray &password) -> void
|
||||||
|
{
|
||||||
|
QFuture saveAttempt = m_wallet->write
|
||||||
|
(
|
||||||
|
KOMPLEX_KEYCHAIN_SERVICE_NAME,
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::readPassword(const QString &username) -> QFuture<QByteArray>
|
||||||
|
{
|
||||||
|
return m_wallet->read(KOMPLEX_KEYCHAIN_SERVICE_NAME, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::readToken(const QString &username) -> QFuture<UserCredentials>
|
||||||
|
{
|
||||||
|
return QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this, username] () -> UserCredentials
|
||||||
|
{
|
||||||
|
UserCredentials credentials;
|
||||||
|
|
||||||
|
QFuture readAttempt = m_wallet->read
|
||||||
|
(
|
||||||
|
KOMPLEX_KEYCHAIN_SERVICE_NAME,
|
||||||
|
username + QStringLiteral("_token")
|
||||||
|
);
|
||||||
|
|
||||||
|
QString _username = username;
|
||||||
|
|
||||||
|
readAttempt
|
||||||
|
.then
|
||||||
|
(
|
||||||
|
[this, &credentials, _username] (const QByteArray &value) -> void
|
||||||
|
{
|
||||||
|
auto parts = value.split(PART_SEPARATOR);
|
||||||
|
QDateTime expiry;
|
||||||
|
|
||||||
|
if(parts.count() == 1)
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("Token malformed"));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(parts[0].length() != sizeof(qint64))
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("Token expiry malformed"));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray numericData = parts[0];
|
||||||
|
qint64 numericConversion = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < sizeof(qint64); ++i)
|
||||||
|
{
|
||||||
|
numericConversion |=
|
||||||
|
(
|
||||||
|
static_cast<qint64>
|
||||||
|
(
|
||||||
|
(
|
||||||
|
static_cast<qint8>(numericData[i]) &
|
||||||
|
0xFF
|
||||||
|
)
|
||||||
|
<< (i * sizeof(qint8))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
expiry = QDateTime::fromMSecsSinceEpoch(numericConversion);
|
||||||
|
|
||||||
|
if(parts[1].isEmpty() && parts.count() == 3)
|
||||||
|
{
|
||||||
|
parts[1] = parts[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
credentials = UserCredentials
|
||||||
|
{
|
||||||
|
.username = _username.toUtf8(),
|
||||||
|
.sessionToken = parts[1],
|
||||||
|
.expiry = expiry
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] () -> void
|
||||||
|
{
|
||||||
|
setErrorString(m_wallet->errorString());
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
readAttempt.waitForFinished();
|
||||||
|
|
||||||
|
return credentials;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::saveToken(const QString &username, const QByteArray &token, const QDateTime &expiry) -> void
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
qint64 numericData = expiry.toMSecsSinceEpoch();
|
||||||
|
|
||||||
|
for(int i = 0; i < sizeof(qint64); ++i)
|
||||||
|
{
|
||||||
|
data[i] = 0xFF & static_cast<qint8>(numericData >> (i * sizeof(qint8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
data += PART_SEPARATOR + token;
|
||||||
|
|
||||||
|
QFuture saveAttempt = m_wallet->write
|
||||||
|
(
|
||||||
|
KOMPLEX_KEYCHAIN_SERVICE_NAME,
|
||||||
|
username + QString("_token"),
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::instance() -> QWeakPointer<UserServices>
|
||||||
|
{
|
||||||
|
if(!s_pointer)
|
||||||
|
{
|
||||||
|
s_instance = new UserServices(QCoreApplication::instance());
|
||||||
|
s_pointer = QSharedPointer<UserServices>
|
||||||
|
(
|
||||||
|
s_instance,
|
||||||
|
&UserServices::deleteLater
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_pointer.toWeakRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::userCredentials() -> const UserCredentials &
|
||||||
|
{
|
||||||
|
return s_userCredentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::login(const QString &username, const QByteArray &password) -> QFuture<UserCredentials>
|
||||||
|
{
|
||||||
|
return QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this, username, password] () -> UserCredentials
|
||||||
|
{
|
||||||
|
QSharedPointer<QNetworkAccessManager> manager = CoreServices::networkAccessManager().toStrongRef();
|
||||||
|
|
||||||
|
if(!manager)
|
||||||
|
{
|
||||||
|
Q_EMIT loginFailed();
|
||||||
|
setErrorString(QStringLiteral("Network manager reference deleted"));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveDefaultUsername(username);
|
||||||
|
|
||||||
|
QNetworkRequest request
|
||||||
|
(
|
||||||
|
QUrl
|
||||||
|
(
|
||||||
|
QStringLiteral("%1/%2/%3").arg
|
||||||
|
(
|
||||||
|
KOMPLEX_API_HOST,
|
||||||
|
KOMPLEX_API_VERSION,
|
||||||
|
KOMPLEX_ENDPOINT_USER_AUTH
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
QJsonObject loginRootObject
|
||||||
|
{
|
||||||
|
{
|
||||||
|
QString("username"),
|
||||||
|
QJsonValue::fromVariant(username.toUtf8())
|
||||||
|
},
|
||||||
|
{
|
||||||
|
QString("password"),
|
||||||
|
QJsonValue::fromVariant(password.toBase64())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QJsonDocument loginDocument(loginRootObject);
|
||||||
|
|
||||||
|
QNetworkReply *reply = manager->post(request, loginDocument.toJson(QJsonDocument::Compact));
|
||||||
|
|
||||||
|
while(!reply->isFinished())
|
||||||
|
{
|
||||||
|
std::chrono::milliseconds(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(reply->error() != QNetworkReply::NoError)
|
||||||
|
{
|
||||||
|
setErrorString(reply->errorString());
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
|
||||||
|
QJsonParseError parseError;
|
||||||
|
QJsonDocument document = QJsonDocument::fromJson(data, &parseError);
|
||||||
|
|
||||||
|
if(parseError.error != QJsonParseError::NoError)
|
||||||
|
{
|
||||||
|
setErrorString(parseError.errorString());
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject rootObject = document.object();
|
||||||
|
QJsonObject dataObject = rootObject.value(QStringLiteral("data")).toObject();
|
||||||
|
|
||||||
|
if(!rootObject.value("success").toBool())
|
||||||
|
{
|
||||||
|
setErrorString
|
||||||
|
(
|
||||||
|
QStringLiteral("Login failure (%1): %2").arg
|
||||||
|
(
|
||||||
|
dataObject.value(QStringLiteral("errorCode")).toString(),
|
||||||
|
dataObject.value(QStringLiteral("message")).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString expiryData = dataObject.value(QStringLiteral("expires")).toString();
|
||||||
|
bool converted = false;
|
||||||
|
qint64 secsSinceEpoch = expiryData.toLongLong(&converted);
|
||||||
|
|
||||||
|
if(!converted)
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("Malformed expiry data"));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
UserCredentials credentials
|
||||||
|
{
|
||||||
|
.username = username.toUtf8(),
|
||||||
|
.sessionToken = dataObject.value
|
||||||
|
(
|
||||||
|
QStringLiteral("jwt")
|
||||||
|
).toString().toUtf8(),
|
||||||
|
.expiry = QDateTime::fromSecsSinceEpoch(secsSinceEpoch)
|
||||||
|
};
|
||||||
|
|
||||||
|
savePassword(username, password);
|
||||||
|
saveToken(username, credentials.sessionToken, credentials.expiry);
|
||||||
|
setUserCredentials(credentials);
|
||||||
|
|
||||||
|
Q_EMIT loginComplete();
|
||||||
|
return credentials;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::saveDefaultUsername(const QString &username) -> void
|
||||||
|
{
|
||||||
|
QDir configDirectory(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
|
||||||
|
|
||||||
|
if(!configDirectory.exists())
|
||||||
|
{
|
||||||
|
if(!configDirectory.mkpath(configDirectory.absolutePath()))
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("Could not make config directory"));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile usernameFile(configDirectory.absoluteFilePath(QStringLiteral("uname")));
|
||||||
|
|
||||||
|
if(!usernameFile.open(QFile::ReadWrite | QFile::Truncate))
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("Could not open uname file"));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = username.toUtf8().toBase64();
|
||||||
|
|
||||||
|
if(usernameFile.write(data) != data.length())
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("Could not write uname file"));
|
||||||
|
}
|
||||||
|
|
||||||
|
usernameFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserServices::defaultUsername() -> QFuture<QString>
|
||||||
|
{
|
||||||
|
return QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this] () -> QString
|
||||||
|
{
|
||||||
|
QDir configDirectory(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
|
||||||
|
|
||||||
|
if(!configDirectory.exists())
|
||||||
|
{
|
||||||
|
if(!configDirectory.mkpath(configDirectory.absolutePath()))
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("Could not make config directory"));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile usernameFile(configDirectory.absoluteFilePath(QStringLiteral("uname")));
|
||||||
|
|
||||||
|
if(!usernameFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("Could not open uname file"));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = QByteArray::fromBase64(usernameFile.readAll());
|
||||||
|
|
||||||
|
usernameFile.close();
|
||||||
|
|
||||||
|
return QString(data);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#include "komplex_global.h"
|
||||||
|
#include "qwallet.h"
|
||||||
|
|
||||||
|
struct UserCredentials
|
||||||
|
{
|
||||||
|
QByteArray username;
|
||||||
|
QByteArray sessionToken;
|
||||||
|
QDateTime expiry;
|
||||||
|
|
||||||
|
UserCredentials &operator = (const UserCredentials &other)
|
||||||
|
{
|
||||||
|
username = other.username;
|
||||||
|
sessionToken = other.sessionToken;
|
||||||
|
expiry = other.expiry;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid()
|
||||||
|
{
|
||||||
|
return !username.isEmpty() && username.isValidUtf8() &&
|
||||||
|
!sessionToken.isEmpty() && sessionToken.isValidUtf8();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(UserCredentials)
|
||||||
|
|
||||||
|
class KOMPLEX_EXPORT UserServices : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static auto instance() -> QWeakPointer<UserServices>;
|
||||||
|
static auto userCredentials() -> const UserCredentials &;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
auto login(const QString &username, const QByteArray &password) -> QFuture<UserCredentials>;
|
||||||
|
|
||||||
|
auto errorString() const -> const QString &;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
auto readPassword(const QString &username) -> QFuture<QByteArray>;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
auto readToken(const QString &username) -> QFuture<UserCredentials>;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
auto defaultUsername() -> QFuture<QString>;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
auto loginComplete() -> void;
|
||||||
|
auto loginFailed() -> void;
|
||||||
|
auto userCredentialsChanged() -> void;
|
||||||
|
auto errorStringChanged() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline static UserServices *s_instance = nullptr;
|
||||||
|
inline static QSharedPointer<UserServices> s_pointer;
|
||||||
|
|
||||||
|
explicit UserServices(QObject *parent);
|
||||||
|
~UserServices();
|
||||||
|
|
||||||
|
auto setUserCredentials(const UserCredentials &credentials) -> void;
|
||||||
|
auto setErrorString(const QString &errorString) -> void;
|
||||||
|
auto savePassword(const QString &username, const QByteArray &password) -> void;
|
||||||
|
auto saveToken(const QString &username, const QByteArray &token, const QDateTime &expiry) -> void;
|
||||||
|
auto saveDefaultUsername(const QString &username) -> void;
|
||||||
|
|
||||||
|
QWallet *m_wallet = nullptr;
|
||||||
|
QString m_errorString;
|
||||||
|
inline static UserCredentials s_userCredentials;
|
||||||
|
|
||||||
|
inline const static char PART_SEPARATOR = static_cast<char>('\x1f');
|
||||||
|
|
||||||
|
Q_PROPERTY(UserCredentials userCredentials READ userCredentials NOTIFY userCredentialsChanged FINAL)
|
||||||
|
Q_PROPERTY(QString errorString READ errorString WRITE setErrorString NOTIFY errorStringChanged FINAL)
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(UserServices)
|
||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
#ifndef VIDEOCACHE_H
|
#ifndef VIDEOCACHE_H
|
||||||
#define VIDEOCACHE_H
|
#define VIDEOCACHE_H
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,44 @@ DownloadManager::DownloadManager(QObject *parent)
|
|||||||
this,
|
this,
|
||||||
&DownloadManager::compileStepsChanged
|
&DownloadManager::compileStepsChanged
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
&m_moveProcess,
|
||||||
|
&QProcess::readyReadStandardOutput,
|
||||||
|
this,
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
QByteArray processData = m_moveProcess.readAllStandardOutput();
|
||||||
|
|
||||||
|
if(!processData.isValidUtf8())
|
||||||
|
{
|
||||||
|
qWarning() << QStringLiteral("Process output not valid UTF8 data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCompilerOutput(m_compilerOutput + processData);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
&m_moveProcess,
|
||||||
|
&QProcess::readyReadStandardError,
|
||||||
|
this,
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
QByteArray processData = m_moveProcess.readAllStandardError();
|
||||||
|
|
||||||
|
if(!processData.isValidUtf8())
|
||||||
|
{
|
||||||
|
qWarning() << QStringLiteral("Process output not valid UTF8 data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCompilerOutput(m_compilerOutput + processData);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,30 +77,39 @@ DownloadManager::DownloadManager(QObject *parent)
|
|||||||
* [3] Optionally ask user if they would like to apply manipulative shader
|
* [3] Optionally ask user if they would like to apply manipulative shader
|
||||||
* [4] Install locally
|
* [4] Install locally
|
||||||
*/
|
*/
|
||||||
auto DownloadManager::downloadImage(const QString &author, const QString &authorId, const QString &description, const QUrl &url) noexcept(false) -> void
|
auto DownloadManager::downloadImage(const QString &author, const QString &authorId, const QString &description, const QUrl &url) -> void
|
||||||
{
|
{
|
||||||
QFuture future = QtConcurrent::run
|
|
||||||
(
|
|
||||||
[this, url, author, authorId, description]()
|
|
||||||
{
|
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
|
QString requestUrl = request.url().toString();
|
||||||
QString id = QUuid::createUuidV7().toString(QUuid::WithoutBraces);
|
QString id = QUuid::createUuidV7().toString(QUuid::WithoutBraces);
|
||||||
|
|
||||||
QFuture<QUrl> downloadUri = download(request, id);
|
setState(Downloading);
|
||||||
|
|
||||||
downloadUri
|
//QFuture<QUrl> downloadUri = download(request, id, Get);
|
||||||
|
if(m_downloadFuture.isRunning())
|
||||||
|
{
|
||||||
|
m_downloadFuture.cancelChain();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_downloadFuture = download(request, id, Get);
|
||||||
|
|
||||||
|
m_downloadFuture
|
||||||
.then
|
.then
|
||||||
(
|
(
|
||||||
[this, author, description, id](QUrl result) -> QUrl
|
[this, author, description, id](QUrl result) -> QUrl
|
||||||
{
|
{
|
||||||
|
setState(Installing);
|
||||||
|
|
||||||
ShaderPack metadata;
|
ShaderPack metadata;
|
||||||
metadata.setAuthor(author);
|
metadata.setAuthor(author);
|
||||||
metadata.setDescription(description);
|
metadata.setDescription(description);
|
||||||
metadata.setName(QStringLiteral("Pexels Image (%1)").arg(id));
|
metadata.setName(QStringLiteral("Pexels Image (%1)").arg(id));
|
||||||
|
metadata.setSource(QStringLiteral("./images/%1").arg(result.fileName()));
|
||||||
|
metadata.setId(id);
|
||||||
|
|
||||||
QUrl packUri
|
QUrl packUri
|
||||||
(
|
(
|
||||||
QStringLiteral("%1/%2").arg
|
QStringLiteral("file://%1/%2").arg
|
||||||
(
|
(
|
||||||
QStandardPaths::writableLocation(QStandardPaths::TempLocation),
|
QStandardPaths::writableLocation(QStandardPaths::TempLocation),
|
||||||
id
|
id
|
||||||
@@ -71,7 +118,7 @@ auto DownloadManager::downloadImage(const QString &author, const QString &author
|
|||||||
|
|
||||||
QUrl packImageUri
|
QUrl packImageUri
|
||||||
(
|
(
|
||||||
QStringLiteral("%1/%2/images/%3").arg
|
QStringLiteral("file://%1/%2/images/%3").arg
|
||||||
(
|
(
|
||||||
QStandardPaths::writableLocation(QStandardPaths::TempLocation),
|
QStandardPaths::writableLocation(QStandardPaths::TempLocation),
|
||||||
id,
|
id,
|
||||||
@@ -80,7 +127,12 @@ auto DownloadManager::downloadImage(const QString &author, const QString &author
|
|||||||
);
|
);
|
||||||
|
|
||||||
QDir packDirectory(packUri.toLocalFile());
|
QDir packDirectory(packUri.toLocalFile());
|
||||||
packDirectory.mkpath(packUri.toLocalFile());
|
|
||||||
|
if(!packDirectory.mkpath(packUri.toLocalFile()))
|
||||||
|
{
|
||||||
|
throw file_exception(QStringLiteral("Could not create directory").toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
packDirectory.mkdir(QStringLiteral("images"));
|
packDirectory.mkdir(QStringLiteral("images"));
|
||||||
|
|
||||||
QFile::rename(result.toLocalFile(), packImageUri.toLocalFile());
|
QFile::rename(result.toLocalFile(), packImageUri.toLocalFile());
|
||||||
@@ -96,15 +148,15 @@ auto DownloadManager::downloadImage(const QString &author, const QString &author
|
|||||||
if(!packFile.open(QFile::ReadWrite))
|
if(!packFile.open(QFile::ReadWrite))
|
||||||
{
|
{
|
||||||
setError(QStringLiteral("File Error"), packFile.errorString());
|
setError(QStringLiteral("File Error"), packFile.errorString());
|
||||||
throw FileException(packFile.errorString());
|
throw file_exception(packFile.errorString().toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray data = metadata.json().toJson(QJsonDocument::Compact);
|
QByteArray data = metadata.json().toJson(QJsonDocument::Indented);
|
||||||
|
|
||||||
if(packFile.write(data) != data.length())
|
if(packFile.write(data) != data.length())
|
||||||
{
|
{
|
||||||
setError(QStringLiteral("File Error"), packFile.errorString());
|
setError(QStringLiteral("File Error"), packFile.errorString());
|
||||||
throw FileException(packFile.errorString());
|
throw file_exception(packFile.errorString().toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
packFile.close();
|
packFile.close();
|
||||||
@@ -113,10 +165,18 @@ auto DownloadManager::downloadImage(const QString &author, const QString &author
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then
|
.then
|
||||||
|
(
|
||||||
|
[this](QUrl result) -> QUrl
|
||||||
|
{
|
||||||
|
return install(result);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then
|
||||||
(
|
(
|
||||||
[this](QUrl result)
|
[this](QUrl result)
|
||||||
{
|
{
|
||||||
install(result);
|
setLastInstalledFile(result.toLocalFile());
|
||||||
|
setState(Complete);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.onCanceled
|
.onCanceled
|
||||||
@@ -127,37 +187,66 @@ auto DownloadManager::downloadImage(const QString &author, const QString &author
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.onFailed
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] (const std::filesystem::filesystem_error &e)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Network Exception %1").arg(QString::number(e.code().value())), e.what());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] (const std::logic_error &e)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Logic Exception %1"), e.what());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] (const std::exception &e)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Logic Exception %1"), e.what());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
(
|
(
|
||||||
[this] ()
|
[this] ()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
}
|
setError(QStringLiteral("Unknown Exception"), QString());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DownloadManager::downloadVideo(const QString &author, const QString &authorId, const QString &description, const QUrl &url) noexcept(false) -> void
|
auto DownloadManager::downloadVideo(const QString &author, const QString &authorId, const QUrl &url) -> void
|
||||||
{
|
{
|
||||||
QFuture future = QtConcurrent::run
|
|
||||||
(
|
|
||||||
[this, url, author, authorId, description]()
|
|
||||||
{
|
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
QString id = QUuid::createUuidV7().toString(QUuid::WithoutBraces);
|
QString id = QUuid::createUuidV7().toString(QUuid::WithoutBraces);
|
||||||
|
|
||||||
QFuture<QUrl> downloadUri = download(request, id);
|
setState(Downloading);
|
||||||
|
|
||||||
downloadUri
|
if(m_downloadFuture.isRunning())
|
||||||
|
{
|
||||||
|
m_downloadFuture.cancelChain();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_downloadFuture = download(request, id, Get);
|
||||||
|
|
||||||
|
m_downloadFuture
|
||||||
.then
|
.then
|
||||||
(
|
(
|
||||||
[this, author, description, id](QUrl result) -> QUrl
|
[this, author, id](QUrl result) -> QUrl
|
||||||
{
|
{
|
||||||
|
setState(Installing);
|
||||||
|
|
||||||
ShaderPack metadata;
|
ShaderPack metadata;
|
||||||
metadata.setAuthor(author);
|
metadata.setAuthor(author);
|
||||||
metadata.setDescription(description);
|
|
||||||
metadata.setName(QStringLiteral("Pexels Video (%1)").arg(id));
|
|
||||||
metadata.setType(ShaderPack::Video);
|
metadata.setType(ShaderPack::Video);
|
||||||
|
metadata.setName(QStringLiteral("Pexels Video (%1)").arg(id));
|
||||||
|
metadata.setSource(QStringLiteral("./videos/%1").arg(result.fileName()));
|
||||||
|
metadata.setId(id);
|
||||||
|
|
||||||
QUrl packUri
|
QUrl packUri
|
||||||
(
|
(
|
||||||
@@ -168,9 +257,9 @@ auto DownloadManager::downloadVideo(const QString &author, const QString &author
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
QUrl packImageUri
|
QUrl packVideoUri
|
||||||
(
|
(
|
||||||
QStringLiteral("%1/%2/images/%3").arg
|
QStringLiteral("%1/%2/videos/%3").arg
|
||||||
(
|
(
|
||||||
QStandardPaths::writableLocation(QStandardPaths::TempLocation),
|
QStandardPaths::writableLocation(QStandardPaths::TempLocation),
|
||||||
id,
|
id,
|
||||||
@@ -182,7 +271,7 @@ auto DownloadManager::downloadVideo(const QString &author, const QString &author
|
|||||||
packDirectory.mkpath(packUri.toLocalFile());
|
packDirectory.mkpath(packUri.toLocalFile());
|
||||||
packDirectory.mkdir(QStringLiteral("images"));
|
packDirectory.mkdir(QStringLiteral("images"));
|
||||||
|
|
||||||
QFile::rename(result.toLocalFile(), packImageUri.toLocalFile());
|
QFile::rename(result.toLocalFile(), packVideoUri.toLocalFile());
|
||||||
|
|
||||||
QFile packFile
|
QFile packFile
|
||||||
(
|
(
|
||||||
@@ -195,7 +284,7 @@ auto DownloadManager::downloadVideo(const QString &author, const QString &author
|
|||||||
if(!packFile.open(QFile::ReadWrite))
|
if(!packFile.open(QFile::ReadWrite))
|
||||||
{
|
{
|
||||||
setError(QStringLiteral("File Error"), packFile.errorString());
|
setError(QStringLiteral("File Error"), packFile.errorString());
|
||||||
throw FileException(packFile.errorString());
|
throw file_exception(packFile.errorString().toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray data = metadata.json().toJson(QJsonDocument::Compact);
|
QByteArray data = metadata.json().toJson(QJsonDocument::Compact);
|
||||||
@@ -203,7 +292,7 @@ auto DownloadManager::downloadVideo(const QString &author, const QString &author
|
|||||||
if(packFile.write(data) != data.length())
|
if(packFile.write(data) != data.length())
|
||||||
{
|
{
|
||||||
setError(QStringLiteral("File Error"), packFile.errorString());
|
setError(QStringLiteral("File Error"), packFile.errorString());
|
||||||
throw FileException(packFile.errorString());
|
throw file_exception(packFile.errorString().toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
packFile.close();
|
packFile.close();
|
||||||
@@ -212,10 +301,18 @@ auto DownloadManager::downloadVideo(const QString &author, const QString &author
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then
|
.then
|
||||||
|
(
|
||||||
|
[this](QUrl result) -> QUrl
|
||||||
|
{
|
||||||
|
return install(result);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then
|
||||||
(
|
(
|
||||||
[this](QUrl result)
|
[this](QUrl result)
|
||||||
{
|
{
|
||||||
install(result);
|
setLastInstalledFile(result.toLocalFile());
|
||||||
|
setState(Complete);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.onCanceled
|
.onCanceled
|
||||||
@@ -226,22 +323,41 @@ auto DownloadManager::downloadVideo(const QString &author, const QString &author
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.onFailed
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] (const std::filesystem::filesystem_error &e)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Network Exception %1").arg(QString::number(e.code().value())), e.what());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] (const std::logic_error &e)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Logic Exception %1"), e.what());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] (const std::exception &e)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Logic Exception %1"), e.what());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
(
|
(
|
||||||
[this] ()
|
[this] ()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
}
|
setError(QStringLiteral("Unknown Exception"), QString());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DownloadManager::downloadPack(const QString &id) noexcept(false) -> void
|
auto DownloadManager::downloadPack(const QString &id) -> void
|
||||||
{
|
{
|
||||||
QFuture aether = QtConcurrent::run
|
|
||||||
(
|
|
||||||
[this, id]()
|
|
||||||
{
|
|
||||||
QUrl downloadUrl = QUrl
|
QUrl downloadUrl = QUrl
|
||||||
(
|
(
|
||||||
QStringLiteral("%1/%2/%3").arg
|
QStringLiteral("%1/%2/%3").arg
|
||||||
@@ -254,39 +370,77 @@ auto DownloadManager::downloadPack(const QString &id) noexcept(false) -> void
|
|||||||
|
|
||||||
QNetworkRequest request(downloadUrl);
|
QNetworkRequest request(downloadUrl);
|
||||||
request.setRawHeader(QByteArray("uuid"), id.toUtf8());
|
request.setRawHeader(QByteArray("uuid"), id.toUtf8());
|
||||||
|
QString tempFile(QString("%1.tar.gz").arg(id));
|
||||||
|
setState(Downloading);
|
||||||
|
|
||||||
QFuture<QUrl> downloadUri = download(request, id, Post);
|
QFuture<QUrl> downloadUri = download(request, id, Post, tempFile);
|
||||||
|
|
||||||
downloadUri
|
downloadUri
|
||||||
.then
|
.then
|
||||||
(
|
(
|
||||||
[this](QUrl result) -> QUrl
|
[this](QUrl result) -> QUrl
|
||||||
{
|
{
|
||||||
return m_compiler->process(result).result();
|
setState(Compiling);
|
||||||
|
return m_compiler->build(result);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then
|
||||||
|
(
|
||||||
|
[this](QUrl result) -> QUrl
|
||||||
|
{
|
||||||
|
return install(result);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then
|
.then
|
||||||
(
|
(
|
||||||
[this](QUrl result)
|
[this](QUrl result)
|
||||||
{
|
{
|
||||||
install(result);
|
setLastInstalledFile(result.toLocalFile());
|
||||||
}
|
setState(Complete);
|
||||||
)
|
|
||||||
.onFailed
|
|
||||||
(
|
|
||||||
[this]()
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
setError(m_compiler->errorTitle(), m_compiler->errorMessage());
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.onCanceled
|
.onCanceled
|
||||||
(
|
(
|
||||||
[this]()
|
[this, tempFile]()
|
||||||
{
|
{
|
||||||
|
QFile::remove(QStringLiteral("/tmp/") + tempFile);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this, tempFile] (const std::filesystem::filesystem_error &e)
|
||||||
|
{
|
||||||
|
QFile::remove(QStringLiteral("/tmp/") + tempFile);
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Network Exception %1").arg(QString::number(e.code().value())), e.what());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this, tempFile] (const shader::logic_error &e)
|
||||||
|
{
|
||||||
|
QFile::remove(QStringLiteral("/tmp/") + tempFile);
|
||||||
|
reset();
|
||||||
|
setError(e.what(), QString::fromStdString(e.details));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this, tempFile] (const std::exception &e)
|
||||||
|
{
|
||||||
|
QFile::remove(QStringLiteral("/tmp/") + tempFile);
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Exception %1"), e.what());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this, tempFile] ()
|
||||||
|
{
|
||||||
|
QFile::remove(QStringLiteral("/tmp/") + tempFile);
|
||||||
|
reset();
|
||||||
|
setError(QStringLiteral("Unknown Exception"), QString());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -337,6 +491,8 @@ auto DownloadManager::setError(const QString &title, const QString &message) ->
|
|||||||
m_errorMessage = std::move(message);
|
m_errorMessage = std::move(message);
|
||||||
m_errorTitle = std::move(title);
|
m_errorTitle = std::move(title);
|
||||||
Q_EMIT errorChanged();
|
Q_EMIT errorChanged();
|
||||||
|
|
||||||
|
setState(Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadManager::setCompilerOutput(const QString &compilerOutput)
|
void DownloadManager::setCompilerOutput(const QString &compilerOutput)
|
||||||
@@ -376,106 +532,63 @@ auto DownloadManager::setDownloadProgress(qreal progress) -> void
|
|||||||
|
|
||||||
auto DownloadManager::install(const QUrl &uri) noexcept(false) -> QUrl
|
auto DownloadManager::install(const QUrl &uri) noexcept(false) -> QUrl
|
||||||
{
|
{
|
||||||
if(!uri.isLocalFile())
|
validateUri(uri);
|
||||||
{
|
|
||||||
throw FileException(QStringLiteral("URI is not a local file"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir tempDirectory(uri.toLocalFile());
|
QDir tempDirectory(uri.toLocalFile());
|
||||||
|
|
||||||
QString installLocation = QStringLiteral("%1/.local/share/komplex/packs/%2").arg
|
QUrl installLocation = QStringLiteral("file://%1/.local/share/komplex/packs/%2").arg
|
||||||
(
|
(
|
||||||
QStandardPaths::writableLocation(QStandardPaths::HomeLocation),
|
QStandardPaths::writableLocation(QStandardPaths::HomeLocation),
|
||||||
tempDirectory.dirName()
|
tempDirectory.dirName()
|
||||||
);
|
);
|
||||||
|
|
||||||
QDir installDirectory(installLocation);
|
QDir installDirectory(installLocation.toLocalFile());
|
||||||
|
|
||||||
if(installDirectory.exists())
|
if(installDirectory.exists())
|
||||||
installDirectory.removeRecursively();
|
installDirectory.removeRecursively();
|
||||||
|
|
||||||
QProcess process;
|
|
||||||
|
|
||||||
QObject::connect
|
|
||||||
(
|
|
||||||
&process,
|
|
||||||
&QProcess::readyReadStandardOutput,
|
|
||||||
this,
|
|
||||||
[this, &process]()
|
|
||||||
{
|
|
||||||
QByteArray processData = process.readAllStandardOutput();
|
|
||||||
|
|
||||||
if(!processData.isValidUtf8())
|
|
||||||
{
|
|
||||||
qWarning() << QStringLiteral("Process output not valid UTF8 data");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCompilerOutput(m_compilerOutput + processData);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
QObject::connect
|
|
||||||
(
|
|
||||||
&process,
|
|
||||||
&QProcess::readyReadStandardError,
|
|
||||||
this,
|
|
||||||
[this, &process]()
|
|
||||||
{
|
|
||||||
QByteArray processData = process.readAllStandardError();
|
|
||||||
|
|
||||||
if(!processData.isValidUtf8())
|
|
||||||
{
|
|
||||||
qWarning() << QStringLiteral("Process output not valid UTF8 data");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCompilerOutput(m_compilerOutput + processData);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
QStringList arguments = QStringList
|
QStringList arguments = QStringList
|
||||||
{
|
{
|
||||||
QStringLiteral("-R"),
|
|
||||||
uri.toLocalFile(),
|
uri.toLocalFile(),
|
||||||
installLocation
|
installLocation.toLocalFile()
|
||||||
};
|
};
|
||||||
|
|
||||||
process.start(QStringLiteral("cp"), arguments);
|
m_moveProcess.start(QStringLiteral("mv"), arguments);
|
||||||
|
|
||||||
if(!process.waitForStarted(3000))
|
if(!m_moveProcess.waitForStarted(3000))
|
||||||
{
|
{
|
||||||
qWarning() << QStringLiteral("Could not start copy process: %1").arg(process.readAllStandardError());
|
qWarning() << QStringLiteral("Could not start copy process: %1").arg(m_moveProcess.readAllStandardError());
|
||||||
throw FileException(QStringLiteral("Could not start install process"));
|
throw file_exception(QStringLiteral("Could not start install process").toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!process.waitForFinished())
|
if(!m_moveProcess.waitForFinished())
|
||||||
{
|
{
|
||||||
qWarning() << QStringLiteral("Copy process took longer than expected (>30s)");
|
qWarning() << QStringLiteral("Copy process took longer than expected (>30s)");
|
||||||
throw FileException(QStringLiteral("Install process took longer than expected (>30s)"));
|
throw file_exception(QStringLiteral("Install process took longer than expected (>30s)").toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl installUri(installLocation);
|
return installLocation;
|
||||||
installUri.setScheme(QStringLiteral("file://"));
|
|
||||||
|
|
||||||
return installUri;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DownloadManager::download(const QNetworkRequest &request, const QString &id, RequestType type) -> QFuture<QUrl>
|
auto DownloadManager::download(const QNetworkRequest &request, const QString &id, RequestType type, const QString &filename) -> QFuture<QUrl>
|
||||||
{
|
{
|
||||||
return QtConcurrent::run
|
return QtConcurrent::run
|
||||||
(
|
(
|
||||||
[this, request, id]() -> QUrl
|
[this, request, id, type, _filename = filename]() -> QUrl
|
||||||
{
|
{
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QString filename = id;
|
QString filename = _filename;
|
||||||
|
|
||||||
if(filename.isEmpty())
|
if(filename.isEmpty() && !request.url().fileName().isEmpty())
|
||||||
{
|
{
|
||||||
filename = QUuid::createUuidV7().toString();
|
filename = request.url().fileName();
|
||||||
|
}
|
||||||
|
else if(filename.isEmpty())
|
||||||
|
{
|
||||||
|
filename = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl downloadUri = QStringLiteral("%1/%2").arg
|
QUrl downloadUri = QStringLiteral("file://%1/%2").arg
|
||||||
(
|
(
|
||||||
QStandardPaths::writableLocation(QStandardPaths::TempLocation),
|
QStandardPaths::writableLocation(QStandardPaths::TempLocation),
|
||||||
filename
|
filename
|
||||||
@@ -485,7 +598,7 @@ auto DownloadManager::download(const QNetworkRequest &request, const QString &id
|
|||||||
|
|
||||||
if(manager == nullptr)
|
if(manager == nullptr)
|
||||||
{
|
{
|
||||||
throw NetworkException
|
throw network_exception
|
||||||
{
|
{
|
||||||
QStringLiteral("Network Manager reference has already been deleted")
|
QStringLiteral("Network Manager reference has already been deleted")
|
||||||
};
|
};
|
||||||
@@ -493,20 +606,23 @@ auto DownloadManager::download(const QNetworkRequest &request, const QString &id
|
|||||||
|
|
||||||
QFile downloadFile(downloadUri.toLocalFile());
|
QFile downloadFile(downloadUri.toLocalFile());
|
||||||
|
|
||||||
if(!downloadFile.open(QFile::ReadWrite))
|
if(downloadFile.exists() && !downloadFile.remove())
|
||||||
{
|
{
|
||||||
throw FileException(QStringLiteral("Could not open temp file location"));
|
throw file_exception(downloadFile.errorString().toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
QNetworkReply *reply = manager->post(request, nullptr);
|
QNetworkReply *reply = nullptr;
|
||||||
|
|
||||||
QObject::connect
|
switch(type)
|
||||||
(
|
{
|
||||||
reply,
|
case Post:
|
||||||
&QNetworkReply::finished,
|
reply = manager->post(request, nullptr);
|
||||||
&loop,
|
break;
|
||||||
&QEventLoop::quit
|
default:
|
||||||
);
|
case Get:
|
||||||
|
reply = manager->get(request, nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
QObject::connect
|
QObject::connect
|
||||||
(
|
(
|
||||||
@@ -517,7 +633,7 @@ auto DownloadManager::download(const QNetworkRequest &request, const QString &id
|
|||||||
{
|
{
|
||||||
loop.quit();
|
loop.quit();
|
||||||
|
|
||||||
throw NetworkException
|
throw network_exception
|
||||||
(
|
(
|
||||||
QStringLiteral("Network Error %1").arg
|
QStringLiteral("Network Error %1").arg
|
||||||
(
|
(
|
||||||
@@ -545,40 +661,52 @@ auto DownloadManager::download(const QNetworkRequest &request, const QString &id
|
|||||||
reply,
|
reply,
|
||||||
&QNetworkReply::readyRead,
|
&QNetworkReply::readyRead,
|
||||||
this,
|
this,
|
||||||
[this, &downloadFile, &reply]()
|
[this, downloadUri]()
|
||||||
{
|
{
|
||||||
if(!downloadFile.isOpen())
|
QMutexLocker locker(&m_fileMutex);
|
||||||
|
QFile downloadFile(downloadUri.toLocalFile());
|
||||||
|
|
||||||
|
if(!downloadFile.open(QFile::ReadWrite | QFile::Append))
|
||||||
{
|
{
|
||||||
return;
|
throw file_exception(QStringLiteral("Could not open temp file location").toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
|
if(reply == nullptr)
|
||||||
|
{
|
||||||
|
throw std::system_error
|
||||||
|
{
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
ENOENT,
|
||||||
|
std::system_category()
|
||||||
|
),
|
||||||
|
QStringLiteral("Reply is not a qobject").toStdString()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 bytes = reply->bytesAvailable();
|
quint64 bytes = reply->bytesAvailable();
|
||||||
quint64 bytesWritten = downloadFile.write(reply->read(bytes));
|
QByteArray data = reply->readAll();
|
||||||
|
quint64 bytesWritten = downloadFile.write(data/*bytes)*/);
|
||||||
|
|
||||||
if(bytesWritten != bytes)
|
downloadFile.close();
|
||||||
{
|
|
||||||
throw FileException(QStringLiteral("Could not write temp file data"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
reply,
|
||||||
|
&QNetworkReply::finished,
|
||||||
|
&loop,
|
||||||
|
&QEventLoop::quit
|
||||||
|
);
|
||||||
|
|
||||||
if(!reply->isFinished())
|
if(!reply->isFinished())
|
||||||
{
|
{
|
||||||
loop.exec();
|
loop.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(reply->bytesAvailable() > 0)
|
|
||||||
{
|
|
||||||
quint64 bytes = reply->bytesAvailable();
|
|
||||||
quint64 bytesWritten = downloadFile.write(reply->read(bytes));
|
|
||||||
|
|
||||||
if(bytesWritten != bytes)
|
|
||||||
{
|
|
||||||
throw FileException(QStringLiteral("Could not write temp file data"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadFile.close();
|
|
||||||
manager.clear();
|
manager.clear();
|
||||||
|
|
||||||
return downloadUri;
|
return downloadUri;
|
||||||
@@ -586,29 +714,61 @@ auto DownloadManager::download(const QNetworkRequest &request, const QString &id
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto DownloadManager::validateUri(const QUrl &uri) noexcept(false) -> void
|
||||||
|
{
|
||||||
|
if(!uri.isValid() || !uri.isLocalFile())
|
||||||
|
{
|
||||||
|
throw std::filesystem::filesystem_error
|
||||||
|
(
|
||||||
|
QStringLiteral("URI %1 is not a local file uri").arg
|
||||||
|
(
|
||||||
|
uri.toString()
|
||||||
|
).toStdString(),
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
ENOENT,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto DownloadManager::readShaderToyEntry(const QUrl &uri) noexcept(false) -> ShaderToyEntry
|
auto DownloadManager::readShaderToyEntry(const QUrl &uri) noexcept(false) -> ShaderToyEntry
|
||||||
{
|
{
|
||||||
if(!uri.isLocalFile())
|
validateUri(uri);
|
||||||
{
|
|
||||||
throw FileException(QStringLiteral("URI is not a local file"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir packDir(uri.toLocalFile());
|
QDir packDir(uri.toLocalFile());
|
||||||
|
|
||||||
if(!packDir.exists(QStringLiteral("pack.json")))
|
if(!packDir.exists(QStringLiteral("pack.json")))
|
||||||
{
|
{
|
||||||
throw FileException(QStringLiteral("Pack file not found"));
|
throw std::filesystem::filesystem_error
|
||||||
|
(
|
||||||
|
QStringLiteral("Pack file not found").arg
|
||||||
|
(
|
||||||
|
uri.toString()
|
||||||
|
).toStdString(),
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
ENOENT,
|
||||||
|
std::system_category()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile packFile(packDir.absoluteFilePath(QStringLiteral("pack.json")));
|
QFile packFile(packDir.absoluteFilePath(QStringLiteral("pack.json")));
|
||||||
|
|
||||||
if(!packFile.open(QFile::ReadOnly))
|
if(!packFile.open(QFile::ReadOnly))
|
||||||
{
|
{
|
||||||
throw FileException
|
throw std::filesystem::filesystem_error
|
||||||
(
|
(
|
||||||
QStringLiteral("Could not open pack file: %1").arg
|
QStringLiteral("Could not open pack file").arg
|
||||||
(
|
(
|
||||||
packFile.errorString()
|
uri.toString()
|
||||||
|
).toStdString(),
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
errno,
|
||||||
|
std::system_category()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -620,11 +780,16 @@ auto DownloadManager::readShaderToyEntry(const QUrl &uri) noexcept(false) -> Sha
|
|||||||
|
|
||||||
if(jsonError.error != QJsonParseError::NoError)
|
if(jsonError.error != QJsonParseError::NoError)
|
||||||
{
|
{
|
||||||
throw FileException
|
throw std::filesystem::filesystem_error
|
||||||
(
|
(
|
||||||
QStringLiteral("Could parse pack file: %1").arg
|
QStringLiteral("URI %1 is not a local file uri").arg
|
||||||
(
|
(
|
||||||
jsonError.errorString()
|
uri.toString()
|
||||||
|
).toStdString(),
|
||||||
|
std::error_code
|
||||||
|
(
|
||||||
|
EIO,
|
||||||
|
std::system_category()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -717,6 +882,19 @@ auto DownloadManager::readShaderToyEntry(const QUrl &uri) noexcept(false) -> Sha
|
|||||||
return std::move(entry);
|
return std::move(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto DownloadManager::lastInstalledFile() const -> const QString &
|
||||||
|
{
|
||||||
|
return m_lastInstalledFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto DownloadManager::setLastInstalledFile(const QString &lastInstalledFile) -> void
|
||||||
|
{
|
||||||
|
if (m_lastInstalledFile == lastInstalledFile)
|
||||||
|
return;
|
||||||
|
m_lastInstalledFile = lastInstalledFile;
|
||||||
|
emit lastInstalledFileChanged();
|
||||||
|
}
|
||||||
|
|
||||||
auto DownloadManager::setDownloadedBytes(qint64 downloadedBytes) -> void
|
auto DownloadManager::setDownloadedBytes(qint64 downloadedBytes) -> void
|
||||||
{
|
{
|
||||||
if (m_downloadedBytes == downloadedBytes)
|
if (m_downloadedBytes == downloadedBytes)
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
#ifndef DOWNLOADMANAGER_H
|
#ifndef DOWNLOADMANAGER_H
|
||||||
#define DOWNLOADMANAGER_H
|
#define DOWNLOADMANAGER_H
|
||||||
|
|
||||||
@@ -50,13 +68,13 @@ public:
|
|||||||
* out of it
|
* out of it
|
||||||
* @param url
|
* @param url
|
||||||
*/
|
*/
|
||||||
auto downloadImage
|
Q_INVOKABLE auto downloadImage
|
||||||
(
|
(
|
||||||
const QString &author,
|
const QString &author,
|
||||||
const QString &authorId,
|
const QString &authorId,
|
||||||
const QString &description,
|
const QString &description,
|
||||||
const QUrl &url
|
const QUrl &url
|
||||||
) noexcept(false) -> void;
|
) -> void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief downloadVideo
|
* @brief downloadVideo
|
||||||
@@ -67,13 +85,12 @@ public:
|
|||||||
* @param description
|
* @param description
|
||||||
* @param url
|
* @param url
|
||||||
*/
|
*/
|
||||||
auto downloadVideo
|
Q_INVOKABLE auto downloadVideo
|
||||||
(
|
(
|
||||||
const QString &author,
|
const QString &author,
|
||||||
const QString &authorId,
|
const QString &authorId,
|
||||||
const QString &description,
|
|
||||||
const QUrl &url
|
const QUrl &url
|
||||||
) noexcept(false) -> void;
|
) -> void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief downloadPack
|
* @brief downloadPack
|
||||||
@@ -82,13 +99,13 @@ public:
|
|||||||
* @param id
|
* @param id
|
||||||
* @return File info of the installed pack
|
* @return File info of the installed pack
|
||||||
*/
|
*/
|
||||||
auto downloadPack(const QString &id) noexcept(false) -> void;
|
Q_INVOKABLE auto downloadPack(const QString &id) -> void;
|
||||||
|
|
||||||
auto compilerOutput() const -> const QString & { return m_compilerOutput; }
|
auto compilerOutput() const -> const QString & { return m_compilerOutput; }
|
||||||
auto errorTitle() const -> const QString & { return m_errorTitle; }
|
auto errorTitle() const -> const QString & { return m_errorTitle; }
|
||||||
auto errorMessage() const -> const QString & { return m_errorMessage; }
|
auto errorMessage() const -> const QString & { return m_errorMessage; }
|
||||||
auto state() const -> State { return m_state; }
|
auto state() const -> State { return m_state; }
|
||||||
auto reset() -> void;
|
Q_INVOKABLE auto reset() -> void;
|
||||||
auto downloadProgress() -> qreal { return m_downloadProgress; }
|
auto downloadProgress() -> qreal { return m_downloadProgress; }
|
||||||
auto compileProgress() -> qreal;
|
auto compileProgress() -> qreal;
|
||||||
auto compileSteps() -> qint64;
|
auto compileSteps() -> qint64;
|
||||||
@@ -100,6 +117,9 @@ public:
|
|||||||
auto downloadedBytes() const -> qint64 { return m_downloadedBytes; }
|
auto downloadedBytes() const -> qint64 { return m_downloadedBytes; }
|
||||||
auto setDownloadedBytes(qint64 downloadedBytes) -> void;
|
auto setDownloadedBytes(qint64 downloadedBytes) -> void;
|
||||||
|
|
||||||
|
auto lastInstalledFile() const -> const QString &;
|
||||||
|
auto setLastInstalledFile(const QString &lastInstalledFile) -> void;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
auto setError(const QString &title, const QString &message) -> void;
|
auto setError(const QString &title, const QString &message) -> void;
|
||||||
auto setCompilerOutput(const QString &compilerOutput) -> void;
|
auto setCompilerOutput(const QString &compilerOutput) -> void;
|
||||||
@@ -118,11 +138,16 @@ signals:
|
|||||||
auto compileStepsChanged() -> void;
|
auto compileStepsChanged() -> void;
|
||||||
auto compileStepsCompletedChanged() -> void;
|
auto compileStepsCompletedChanged() -> void;
|
||||||
|
|
||||||
|
auto lastInstalledFileChanged() -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto compile(const QUrl &uri) noexcept(false) -> QUrl;
|
auto compile(const QUrl &uri) noexcept(false) -> QUrl;
|
||||||
auto install(const QUrl &uri) noexcept(false) -> QUrl;
|
auto install(const QUrl &uri) noexcept(false) -> QUrl;
|
||||||
auto download(const QNetworkRequest &request, const QString &id, RequestType type = Get) -> QFuture<QUrl>;
|
auto download(const QNetworkRequest &request, const QString &id, RequestType type = Get, const QString &filename = QString()) -> QFuture<QUrl>;
|
||||||
auto readShaderToyEntry(const QUrl &uri) noexcept(false) -> ShaderToyEntry;
|
auto readShaderToyEntry(const QUrl &uri) noexcept(false) -> ShaderToyEntry;
|
||||||
|
auto validateUri(const QUrl &uri) noexcept(false) -> void;
|
||||||
|
|
||||||
|
QString m_lastInstalledFile;
|
||||||
|
|
||||||
QString m_compilerOutput;
|
QString m_compilerOutput;
|
||||||
QString m_errorTitle;
|
QString m_errorTitle;
|
||||||
@@ -135,9 +160,14 @@ private:
|
|||||||
State m_state;
|
State m_state;
|
||||||
|
|
||||||
QMutex m_downloadMutex;
|
QMutex m_downloadMutex;
|
||||||
|
QMutex m_fileMutex;
|
||||||
|
|
||||||
PackCompiler *m_compiler = nullptr;
|
PackCompiler *m_compiler = nullptr;
|
||||||
|
|
||||||
|
QProcess m_moveProcess;
|
||||||
|
|
||||||
|
QFuture<QUrl> m_downloadFuture;
|
||||||
|
|
||||||
Q_PROPERTY(QString compilerOutput READ compilerOutput WRITE setCompilerOutput NOTIFY compilerOutputChanged FINAL)
|
Q_PROPERTY(QString compilerOutput READ compilerOutput WRITE setCompilerOutput NOTIFY compilerOutputChanged FINAL)
|
||||||
Q_PROPERTY(QString errorTitle READ errorTitle NOTIFY errorChanged FINAL)
|
Q_PROPERTY(QString errorTitle READ errorTitle NOTIFY errorChanged FINAL)
|
||||||
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorChanged FINAL)
|
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorChanged FINAL)
|
||||||
@@ -148,6 +178,7 @@ private:
|
|||||||
Q_PROPERTY(qint64 downloadedBytes READ downloadedBytes WRITE setDownloadedBytes NOTIFY downloadedBytesChanged FINAL)
|
Q_PROPERTY(qint64 downloadedBytes READ downloadedBytes WRITE setDownloadedBytes NOTIFY downloadedBytesChanged FINAL)
|
||||||
Q_PROPERTY(qint64 compileSteps READ compileSteps NOTIFY compileStepsChanged FINAL)
|
Q_PROPERTY(qint64 compileSteps READ compileSteps NOTIFY compileStepsChanged FINAL)
|
||||||
Q_PROPERTY(qint64 compileStepsCompleted READ compileStepsCompleted NOTIFY compileStepsCompletedChanged FINAL)
|
Q_PROPERTY(qint64 compileStepsCompleted READ compileStepsCompleted NOTIFY compileStepsCompletedChanged FINAL)
|
||||||
|
Q_PROPERTY(QString lastInstalledFile READ lastInstalledFile WRITE setLastInstalledFile NOTIFY lastInstalledFileChanged FINAL)
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(DownloadManager)
|
Q_DECLARE_METATYPE(DownloadManager)
|
||||||
|
|
||||||
|
|||||||
@@ -5,49 +5,56 @@ FeaturedImagesModel::FeaturedImagesModel(QObject *parent) : QAbstractListModel{p
|
|||||||
m_paginator = new FeaturedImagesPaginator(this);
|
m_paginator = new FeaturedImagesPaginator(this);
|
||||||
PaginationNotifier *notifier = static_cast<PaginationNotifier*>(m_paginator);
|
PaginationNotifier *notifier = static_cast<PaginationNotifier*>(m_paginator);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect
|
||||||
|
(
|
||||||
notifier,
|
notifier,
|
||||||
&PaginationNotifier::resultsPerPageChanged,
|
&PaginationNotifier::resultsPerPageChanged,
|
||||||
this,
|
this,
|
||||||
&FeaturedImagesModel::resultsPerPageChanged
|
&FeaturedImagesModel::resultsPerPageChanged
|
||||||
);
|
);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect
|
||||||
|
(
|
||||||
notifier,
|
notifier,
|
||||||
&PaginationNotifier::totalResultsChanged,
|
&PaginationNotifier::totalResultsChanged,
|
||||||
this,
|
this,
|
||||||
&FeaturedImagesModel::totalResultsChanged
|
&FeaturedImagesModel::totalResultsChanged
|
||||||
);
|
);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect
|
||||||
|
(
|
||||||
notifier,
|
notifier,
|
||||||
&PaginationNotifier::totalPagesChanged,
|
&PaginationNotifier::totalPagesChanged,
|
||||||
this,
|
this,
|
||||||
&FeaturedImagesModel::totalPagesChanged
|
&FeaturedImagesModel::totalPagesChanged
|
||||||
);
|
);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect
|
||||||
|
(
|
||||||
notifier,
|
notifier,
|
||||||
&PaginationNotifier::pageChanged,
|
&PaginationNotifier::pageChanged,
|
||||||
this,
|
this,
|
||||||
&FeaturedImagesModel::pageChanged
|
&FeaturedImagesModel::pageChanged
|
||||||
);
|
);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect
|
||||||
|
(
|
||||||
notifier,
|
notifier,
|
||||||
&PaginationNotifier::pageChanged,
|
&PaginationNotifier::pageChanged,
|
||||||
this,
|
this,
|
||||||
&FeaturedImagesModel::resetDataModel
|
&FeaturedImagesModel::resetDataModel
|
||||||
);
|
);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect
|
||||||
|
(
|
||||||
notifier,
|
notifier,
|
||||||
&PaginationNotifier::fetchComplete,
|
&PaginationNotifier::fetchComplete,
|
||||||
this,
|
this,
|
||||||
&FeaturedImagesModel::resetState
|
&FeaturedImagesModel::resetState
|
||||||
);
|
);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect
|
||||||
|
(
|
||||||
notifier,
|
notifier,
|
||||||
&PaginationNotifier::fetching,
|
&PaginationNotifier::fetching,
|
||||||
this,
|
this,
|
||||||
@@ -172,6 +179,10 @@ auto FeaturedImagesModel::state() const -> FeaturedImagesModel::State
|
|||||||
|
|
||||||
auto FeaturedImagesModel::setState(State state) -> void
|
auto FeaturedImagesModel::setState(State state) -> void
|
||||||
{
|
{
|
||||||
|
QFuture<void> aether = QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this, state]
|
||||||
|
{
|
||||||
if (m_state == state)
|
if (m_state == state)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -179,6 +190,8 @@ auto FeaturedImagesModel::setState(State state) -> void
|
|||||||
|
|
||||||
m_state = state;
|
m_state = state;
|
||||||
emit stateChanged();
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FeaturedImagesModel::resetState() -> void
|
auto FeaturedImagesModel::resetState() -> void
|
||||||
@@ -245,7 +258,6 @@ auto FeaturedImagesModel::resultsPerPage() const -> qsizetype
|
|||||||
|
|
||||||
auto FeaturedImagesModel::setResultsPerPage(qsizetype resultsPerPage) -> void
|
auto FeaturedImagesModel::setResultsPerPage(qsizetype resultsPerPage) -> void
|
||||||
{
|
{
|
||||||
|
|
||||||
if(m_paginator != nullptr)
|
if(m_paginator != nullptr)
|
||||||
{
|
{
|
||||||
QFuture<void> future = QtConcurrent::run
|
QFuture<void> future = QtConcurrent::run
|
||||||
@@ -344,3 +356,23 @@ auto FeaturedImagesModel::totalPages() const -> qsizetype
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto FeaturedImagesModel::hasNextPage() const -> bool
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->page() < m_paginator->totalPages();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FeaturedImagesModel::hasPreviousPage() const -> bool
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->page() > 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -213,6 +213,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE auto previousPage() -> void;
|
Q_INVOKABLE auto previousPage() -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief hasNextPage
|
||||||
|
* Calculates if there are more pages based on the current page calculation
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto hasNextPage() const -> bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief hasPreviousPage
|
||||||
|
* If page is greater than 1, returns true
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto hasPreviousPage() const -> bool;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief setErrorString
|
* @brief setErrorString
|
||||||
@@ -248,7 +262,6 @@ signals:
|
|||||||
auto stateChanged() -> void;
|
auto stateChanged() -> void;
|
||||||
auto errorStringChanged() -> void;
|
auto errorStringChanged() -> void;
|
||||||
auto resultsPerPageChanged() -> void;
|
auto resultsPerPageChanged() -> void;
|
||||||
|
|
||||||
auto pageChanged() -> void;
|
auto pageChanged() -> void;
|
||||||
auto totalResultsChanged() -> void;
|
auto totalResultsChanged() -> void;
|
||||||
auto totalPagesChanged() -> void;
|
auto totalPagesChanged() -> void;
|
||||||
@@ -344,6 +357,8 @@ private:
|
|||||||
Q_PROPERTY(qsizetype resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
|
Q_PROPERTY(qsizetype resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged FINAL)
|
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged FINAL)
|
||||||
|
Q_PROPERTY(bool hasNextPage READ hasNextPage NOTIFY pageChanged FINAL)
|
||||||
|
Q_PROPERTY(bool hasPreviousPage READ hasPreviousPage NOTIFY pageChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype page READ page NOTIFY pageChanged FINAL)
|
Q_PROPERTY(qsizetype page READ page NOTIFY pageChanged FINAL)
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(FeaturedImagesModel)
|
Q_DECLARE_METATYPE(FeaturedImagesModel)
|
||||||
|
|||||||
@@ -311,6 +311,26 @@ auto FeaturedPacksModel::previousPage() -> void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto FeaturedPacksModel::hasNextPage() const -> bool
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->page() < m_paginator->totalPages();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FeaturedPacksModel::hasPreviousPage() const -> bool
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->page() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
qsizetype FeaturedPacksModel::page() const
|
qsizetype FeaturedPacksModel::page() const
|
||||||
{
|
{
|
||||||
if(m_paginator != nullptr)
|
if(m_paginator != nullptr)
|
||||||
|
|||||||
@@ -208,6 +208,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE auto previousPage() -> void;
|
Q_INVOKABLE auto previousPage() -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief hasNextPage
|
||||||
|
* Calculates if there are more pages based on the current page calculation
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto hasNextPage() const -> bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief hasPreviousPage
|
||||||
|
* If page is greater than 1, returns true
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto hasPreviousPage() const -> bool;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief setErrorString
|
* @brief setErrorString
|
||||||
@@ -310,6 +324,8 @@ private:
|
|||||||
Q_PROPERTY(qsizetype resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
|
Q_PROPERTY(qsizetype resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged FINAL)
|
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged FINAL)
|
||||||
|
Q_PROPERTY(bool hasNextPage READ hasNextPage NOTIFY pageChanged FINAL)
|
||||||
|
Q_PROPERTY(bool hasPreviousPage READ hasPreviousPage NOTIFY pageChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype page READ page NOTIFY pageChanged FINAL)
|
Q_PROPERTY(qsizetype page READ page NOTIFY pageChanged FINAL)
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(FeaturedPacksModel)
|
Q_DECLARE_METATYPE(FeaturedPacksModel)
|
||||||
|
|||||||
@@ -160,6 +160,10 @@ auto FeaturedVideosModel::state() const -> FeaturedVideosModel::State
|
|||||||
|
|
||||||
auto FeaturedVideosModel::setState(State state) -> void
|
auto FeaturedVideosModel::setState(State state) -> void
|
||||||
{
|
{
|
||||||
|
QFuture<void> aether = QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this, state]
|
||||||
|
{
|
||||||
if (m_state == state)
|
if (m_state == state)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -167,6 +171,8 @@ auto FeaturedVideosModel::setState(State state) -> void
|
|||||||
|
|
||||||
m_state = state;
|
m_state = state;
|
||||||
emit stateChanged();
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FeaturedVideosModel::resetState() -> void
|
auto FeaturedVideosModel::resetState() -> void
|
||||||
@@ -205,6 +211,24 @@ auto FeaturedVideosModel::itemModel() const -> VideoItemModel*
|
|||||||
return m_itemModel;
|
return m_itemModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto FeaturedVideosModel::windowSize() const -> qsizetype
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->windowSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FeaturedVideosModel::setWindowSize(qsizetype size) -> void
|
||||||
|
{
|
||||||
|
if(m_paginator != nullptr)
|
||||||
|
{
|
||||||
|
m_paginator->setWindowSize(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto FeaturedVideosModel::roleNames() const -> QHash<int, QByteArray>
|
auto FeaturedVideosModel::roleNames() const -> QHash<int, QByteArray>
|
||||||
{
|
{
|
||||||
return m_dataRoles;
|
return m_dataRoles;
|
||||||
@@ -347,3 +371,23 @@ auto FeaturedVideosModel::totalPages() const -> qsizetype
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto FeaturedVideosModel::hasNextPage() const -> bool
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->page() < m_paginator->totalPages();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FeaturedVideosModel::hasPreviousPage() const -> bool
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->page() > 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -217,6 +217,34 @@ public:
|
|||||||
|
|
||||||
VideoItemModel *itemModel() const;
|
VideoItemModel *itemModel() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief windowSize
|
||||||
|
* Paginator cache size
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto windowSize() const -> qsizetype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setWindowSize
|
||||||
|
* Set the paginator cache size
|
||||||
|
* @param size
|
||||||
|
*/
|
||||||
|
auto setWindowSize(qsizetype size) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief hasNextPage
|
||||||
|
* Calculates if there are more pages based on the current page calculation
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto hasNextPage() const -> bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief hasPreviousPage
|
||||||
|
* If page is greater than 1, returns true
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto hasPreviousPage() const -> bool;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief setErrorString
|
* @brief setErrorString
|
||||||
@@ -243,7 +271,7 @@ signals:
|
|||||||
auto stateChanged() -> void;
|
auto stateChanged() -> void;
|
||||||
auto errorStringChanged() -> void;
|
auto errorStringChanged() -> void;
|
||||||
auto resultsPerPageChanged() -> void;
|
auto resultsPerPageChanged() -> void;
|
||||||
|
auto windowSizeChanged() -> void;
|
||||||
auto pageChanged() -> void;
|
auto pageChanged() -> void;
|
||||||
auto totalResultsChanged() -> void;
|
auto totalResultsChanged() -> void;
|
||||||
auto totalPagesChanged() -> void;
|
auto totalPagesChanged() -> void;
|
||||||
@@ -313,7 +341,10 @@ private:
|
|||||||
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged FINAL)
|
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype page READ page NOTIFY pageChanged FINAL)
|
Q_PROPERTY(qsizetype page READ page NOTIFY pageChanged FINAL)
|
||||||
|
Q_PROPERTY(bool hasNextPage READ hasNextPage NOTIFY pageChanged FINAL)
|
||||||
|
Q_PROPERTY(bool hasPreviousPage READ hasPreviousPage NOTIFY pageChanged FINAL)
|
||||||
Q_PROPERTY(VideoItemModel *itemModel READ itemModel CONSTANT FINAL)
|
Q_PROPERTY(VideoItemModel *itemModel READ itemModel CONSTANT FINAL)
|
||||||
|
Q_PROPERTY(qsizetype windowSize READ windowSize WRITE setWindowSize NOTIFY windowSizeChanged FINAL)
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(FeaturedVideosModel)
|
Q_DECLARE_METATYPE(FeaturedVideosModel)
|
||||||
|
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ auto InstalledPackManager::setState(State state) -> void
|
|||||||
|
|
||||||
auto InstalledPackManager::resetState() -> void
|
auto InstalledPackManager::resetState() -> void
|
||||||
{
|
{
|
||||||
setState(Idle); // TODO: Adapt to use your actual default value
|
setState(Idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto InstalledPackManager::roleNames() const -> QHash<int, QByteArray>
|
auto InstalledPackManager::roleNames() const -> QHash<int, QByteArray>
|
||||||
|
|||||||
@@ -159,6 +159,10 @@ auto NewestPacksModel::state() const -> NewestPacksModel::State
|
|||||||
|
|
||||||
auto NewestPacksModel::setState(State state) -> void
|
auto NewestPacksModel::setState(State state) -> void
|
||||||
{
|
{
|
||||||
|
QFuture<void> aether = QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this, state]
|
||||||
|
{
|
||||||
if (m_state == state)
|
if (m_state == state)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -166,6 +170,8 @@ auto NewestPacksModel::setState(State state) -> void
|
|||||||
|
|
||||||
m_state = state;
|
m_state = state;
|
||||||
emit stateChanged();
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto NewestPacksModel::resetState() -> void
|
auto NewestPacksModel::resetState() -> void
|
||||||
@@ -224,7 +230,7 @@ auto NewestPacksModel::setResultsPerPage(qsizetype resultsPerPage) -> void
|
|||||||
{
|
{
|
||||||
if(m_paginator != nullptr)
|
if(m_paginator != nullptr)
|
||||||
{
|
{
|
||||||
QFuture<void> future = QtConcurrent::run
|
QFuture<void> aether = QtConcurrent::run
|
||||||
(
|
(
|
||||||
[this, resultsPerPage]
|
[this, resultsPerPage]
|
||||||
{
|
{
|
||||||
@@ -277,7 +283,7 @@ auto NewestPacksModel::nextPage() const -> void
|
|||||||
{
|
{
|
||||||
if(m_paginator != nullptr)
|
if(m_paginator != nullptr)
|
||||||
{
|
{
|
||||||
QFuture<void> future = QtConcurrent::run
|
QFuture<void> aether = QtConcurrent::run
|
||||||
(
|
(
|
||||||
[this]
|
[this]
|
||||||
{
|
{
|
||||||
@@ -291,7 +297,7 @@ auto NewestPacksModel::previousPage() const -> void
|
|||||||
{
|
{
|
||||||
if(m_paginator != nullptr)
|
if(m_paginator != nullptr)
|
||||||
{
|
{
|
||||||
QFuture<void> future = QtConcurrent::run
|
QFuture<void> aether = QtConcurrent::run
|
||||||
(
|
(
|
||||||
[this]
|
[this]
|
||||||
{
|
{
|
||||||
@@ -320,3 +326,24 @@ auto NewestPacksModel::totalPages() const -> qsizetype
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto NewestPacksModel::hasNextPage() const -> bool
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->page() < m_paginator->totalPages();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auto NewestPacksModel::hasPreviousPage() const -> bool
|
||||||
|
{
|
||||||
|
if(m_paginator == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_paginator->page() > 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -215,6 +215,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE auto previousPage() const -> void;
|
Q_INVOKABLE auto previousPage() const -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief hasNextPage
|
||||||
|
* Calculates if there are more pages based on the current page calculation
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto hasNextPage() const -> bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief hasPreviousPage
|
||||||
|
* If page is greater than 1, returns true
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto hasPreviousPage() const -> bool;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief setErrorString
|
* @brief setErrorString
|
||||||
@@ -321,6 +335,8 @@ private:
|
|||||||
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged FINAL)
|
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged FINAL)
|
||||||
Q_PROPERTY(qsizetype page READ page NOTIFY pageChanged FINAL)
|
Q_PROPERTY(qsizetype page READ page NOTIFY pageChanged FINAL)
|
||||||
|
Q_PROPERTY(bool hasNextPage READ hasNextPage NOTIFY pageChanged FINAL)
|
||||||
|
Q_PROPERTY(bool hasPreviousPage READ hasPreviousPage NOTIFY pageChanged FINAL)
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(NewestPacksModel)
|
Q_DECLARE_METATYPE(NewestPacksModel)
|
||||||
|
|
||||||
|
|||||||
+417
-763
File diff suppressed because it is too large
Load Diff
+422
-105
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
#ifndef PACKCOMPILER_H
|
#ifndef PACKCOMPILER_H
|
||||||
#define PACKCOMPILER_H
|
#define PACKCOMPILER_H
|
||||||
|
|
||||||
@@ -18,6 +36,8 @@
|
|||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QtShaderTools>
|
||||||
|
#include <QtShaderTools/rhi/qshaderbaker.h>
|
||||||
#include <QtConcurrent/qtconcurrentrun.h>
|
#include <QtConcurrent/qtconcurrentrun.h>
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qmargins.h>
|
#include <qmargins.h>
|
||||||
@@ -25,23 +45,47 @@
|
|||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <qurl.h>
|
#include <qurl.h>
|
||||||
#include "common/komplex_global.h"
|
#include "common/komplex_global.h"
|
||||||
|
|
||||||
|
#if __has_include("vulkan/vulkan_core.h")
|
||||||
|
#define HAS_VULKAN
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_include("GL/gl.h")
|
||||||
|
#define HAS_OPENGL
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT BuildContext
|
||||||
|
{
|
||||||
|
QMap<QByteArray, QByteArray> commonData;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The PackCompiler class
|
* @brief The PackCompiler class
|
||||||
* [1] Extract Pack (GZip)
|
* [1] Extract Pack (GZip)
|
||||||
* [2] Verify directory is a pack and has shaders
|
* [2] Verify directory is a pack and has shaders
|
||||||
* [3] Load shader code
|
* [3] Load Common shader code
|
||||||
* [4] Append Common and Global files, if they exist
|
* [4] Walk the shader directory
|
||||||
* [5] Add uniform and replace variable use
|
* [5] Load shader code
|
||||||
* [6] Run C Preprocessor (cpp -P) to process macros
|
* [6] Append type specific common code and global code
|
||||||
* [7] Append version macro
|
* [7] Replace uniform variable use
|
||||||
* [8] Compile with Qt Shader Baker
|
* [8] Add uniform header
|
||||||
|
* [9] Add uniform footer
|
||||||
|
* [10] Run preprocessor to process macros
|
||||||
|
* [11] Append version macro
|
||||||
|
* [12] Compile with QShaderBaker
|
||||||
|
* [13] Save
|
||||||
*/
|
*/
|
||||||
class KOMPLEX_EXPORT PackCompiler : public QObject
|
class PackCompiler : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The State enum
|
||||||
|
* Enum of the possible states of the compiler
|
||||||
|
*/
|
||||||
enum State
|
enum State
|
||||||
{
|
{
|
||||||
Idle,
|
Idle,
|
||||||
@@ -52,89 +96,334 @@ public:
|
|||||||
Q_ENUM(State)
|
Q_ENUM(State)
|
||||||
|
|
||||||
explicit PackCompiler(QObject *parent = nullptr);
|
explicit PackCompiler(QObject *parent = nullptr);
|
||||||
~PackCompiler() override;
|
|
||||||
|
|
||||||
auto compilerOutput() const -> const QString & { return m_compilerOutput; }
|
/**
|
||||||
|
* @brief progress
|
||||||
|
* Current compiler progress
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
auto progress() -> qreal { return m_progress; }
|
auto progress() -> qreal { return m_progress; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief currentStep
|
||||||
|
* Current compiler step
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
auto currentStep() -> qint64 { return m_currentStep; }
|
auto currentStep() -> qint64 { return m_currentStep; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief totalSteps
|
||||||
|
* Total steps in the current compile
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
auto totalSteps() -> qint64 { return m_totalSteps; }
|
auto totalSteps() -> qint64 { return m_totalSteps; }
|
||||||
auto errorTitle() const -> const QString & { return m_errorTitle; }
|
|
||||||
auto errorMessage() const -> const QString & { return m_errorMessage; }
|
|
||||||
auto reset() -> void;
|
|
||||||
|
|
||||||
auto process(const QUrl &uri) -> QFuture<QUrl>;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief status
|
||||||
|
* Current status message
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
auto status() const -> const QString & { return m_status; }
|
auto status() const -> const QString & { return m_status; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief state
|
||||||
|
* Current compiler state
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
auto state() const -> State { return m_state; }
|
auto state() const -> State { return m_state; }
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
/**
|
||||||
* @brief prepareShaders
|
* @brief reset
|
||||||
* Scans the pack's shader directory and sends each file to
|
* Resets the compiler state
|
||||||
* prepareFile()
|
|
||||||
* @param uri
|
|
||||||
* Directory to prepare
|
|
||||||
*/
|
*/
|
||||||
auto prepareShaders(const QUrl &uri) noexcept(false) -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief prepareFile
|
* @brief build
|
||||||
* Prepares the individual file by appending the header, footer,
|
* Builds a Komplex pack from a tar.gz file
|
||||||
* common files and replacing standard variable names
|
|
||||||
* @param uri
|
* @param uri
|
||||||
|
* Uri of the tar.gz
|
||||||
|
* @return
|
||||||
|
* Uri of the built pack
|
||||||
*/
|
*/
|
||||||
auto prepareFile(const QUrl &uri) noexcept(false) -> void;
|
auto build(const QUrl &uri) -> QUrl;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief validateDirectory
|
|
||||||
*
|
|
||||||
* @param uri
|
|
||||||
* @return true
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
auto validateDirectory(const QUrl &uri) -> bool;
|
|
||||||
|
|
||||||
auto extract(const QUrl &sourceUri, const QUrl &destinationUri) noexcept(false) -> void;
|
|
||||||
auto copyFile(const QUrl &sourceUri, const QUrl &destinationUri) noexcept(false) -> void;
|
|
||||||
auto compile(const QUrl &uri) noexcept(false) -> void;
|
|
||||||
auto preprocess(const QUrl &uri) noexcept(false) -> void;
|
|
||||||
auto appendVersion(const QUrl &uri) noexcept(false) -> void;
|
|
||||||
auto compileShader(const QUrl &uri) noexcept(false) -> void;
|
|
||||||
auto loadCommonFragmentData(const QUrl &uri) -> QByteArray;
|
|
||||||
auto loadCommonVertexData(const QUrl &uri) -> QByteArray;
|
|
||||||
auto loadGlobalData(const QUrl &uri) -> QByteArray;
|
|
||||||
|
|
||||||
auto setError(const QString &title, const QString &message, const QUrl &uri = {}) -> void;
|
|
||||||
auto setCompilerOutput(const QString &compilerOutput) -> void;
|
|
||||||
auto setState(State state) -> void;
|
|
||||||
auto setProgress(qreal progress) -> void;
|
|
||||||
auto setTotalSteps(qint64 steps) -> void;
|
|
||||||
auto setCurrentStep(qint64 step) -> void;
|
|
||||||
|
|
||||||
auto setStatus(const QString &status) -> void;
|
|
||||||
|
|
||||||
auto incrementCompileStep() -> void;
|
|
||||||
|
|
||||||
auto removeDirectory(const QUrl &uri) -> bool;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
auto compilerOutputChanged() -> void;
|
auto compilerOutputChanged() -> void;
|
||||||
auto errorOcurred() -> void;
|
|
||||||
auto errorTitleChanged() -> void;
|
|
||||||
auto errorMessageChanged() -> void;
|
|
||||||
auto stateChanged() -> void;
|
auto stateChanged() -> void;
|
||||||
auto progressChanged() -> void;
|
auto progressChanged() -> void;
|
||||||
auto currentStepChanged() -> void;
|
auto currentStepChanged() -> void;
|
||||||
auto totalStepsChanged() -> void;
|
auto totalStepsChanged() -> void;
|
||||||
|
|
||||||
auto compileComplete(const QUrl &uri) -> void;
|
auto compileComplete(const QUrl &uri) -> void;
|
||||||
|
|
||||||
auto statusChanged() -> void;
|
auto statusChanged() -> void;
|
||||||
auto packReady(const QString &) -> void;
|
auto packReady(const QString &) -> void;
|
||||||
auto errorStepChanged() -> void;
|
auto errorStepChanged() -> void;
|
||||||
auto errorRatingChanged() -> void;
|
auto errorRatingChanged() -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
//[1]
|
||||||
|
/**
|
||||||
|
* @brief extract
|
||||||
|
* Extracts the packfile and deletes the source
|
||||||
|
* @param uri of the tar.gz pack
|
||||||
|
* @return uri of the extracted directory
|
||||||
|
*/
|
||||||
|
auto extract(const QUrl &uri) noexcept(false) -> const QUrl;
|
||||||
|
|
||||||
|
//[2]
|
||||||
|
/**
|
||||||
|
* @brief validatePack
|
||||||
|
* Validates that the directory is a valid pack and has shaders to compile
|
||||||
|
* @param uri of the directory provided by extract
|
||||||
|
*/
|
||||||
|
auto validatePack(const QUrl &uri) const noexcept(false) -> void;
|
||||||
|
|
||||||
|
//[3]
|
||||||
|
/**
|
||||||
|
* @brief loadCommonData
|
||||||
|
* Loads the common and global shader code from the shader directory of the uri
|
||||||
|
* @param uri
|
||||||
|
*/
|
||||||
|
auto loadCommonData(const QUrl &uri) -> QMap<QByteArray,QByteArray>;
|
||||||
|
|
||||||
|
//[4-5]
|
||||||
|
/**
|
||||||
|
* @brief processShaders
|
||||||
|
* Walks the shader directory, loads the code and calls 6-13 for each
|
||||||
|
* @param uri
|
||||||
|
* @param context
|
||||||
|
*/
|
||||||
|
auto processShaders(const QUrl &uri, BuildContext *context) -> void;
|
||||||
|
|
||||||
|
//[6]
|
||||||
|
/**
|
||||||
|
* @brief appendCommonData
|
||||||
|
* Appends the type specific common code to the shader data
|
||||||
|
* @param data
|
||||||
|
* Pointer to shader data
|
||||||
|
* @param suffix
|
||||||
|
* Shader file suffix
|
||||||
|
* @param context
|
||||||
|
* Pointer to build context object
|
||||||
|
*/
|
||||||
|
auto appendCommonData(QByteArray *data, const QByteArray &suffix, BuildContext *context) noexcept(true) -> void;
|
||||||
|
|
||||||
|
//[7]
|
||||||
|
/**
|
||||||
|
* @brief replaceUniformVariables
|
||||||
|
* Replaces standard variables such as iFrame with their uniform buffer name
|
||||||
|
* @param data
|
||||||
|
* Pointer to the shader data
|
||||||
|
*/
|
||||||
|
auto replaceUniformVariables(QByteArray *data) noexcept(true) -> void;
|
||||||
|
|
||||||
|
//[8]
|
||||||
|
/**
|
||||||
|
* @brief appendUniformHeader
|
||||||
|
* Adds header and uniform buffer to the shader data
|
||||||
|
* @param data
|
||||||
|
* Pointer to the shader data
|
||||||
|
*/
|
||||||
|
auto appendUniformHeader(QByteArray *data) noexcept(true) -> void;
|
||||||
|
|
||||||
|
//[9]
|
||||||
|
/**
|
||||||
|
* @brief appendUniformFooter
|
||||||
|
* Adds the uniform footer to the shader data
|
||||||
|
* @param data
|
||||||
|
* Pointer to the shader data
|
||||||
|
*/
|
||||||
|
auto appendUniformFooter(QByteArray *data) noexcept(true) -> void;
|
||||||
|
|
||||||
|
//[10]
|
||||||
|
/**
|
||||||
|
* @brief preprocess
|
||||||
|
* I have had issues with defines in code so passing it to a c/c++
|
||||||
|
* preprocessor is required. I am now using clang for this as clang
|
||||||
|
* is more modern and can use stdin
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
auto preprocess(QByteArray *data) noexcept(false) -> void;
|
||||||
|
|
||||||
|
//[11]
|
||||||
|
/**
|
||||||
|
* @brief appendVersion
|
||||||
|
* The version header confuses the preprocessor, so add it at the end
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
auto appendVersion(QByteArray *data) noexcept(true) -> void;
|
||||||
|
|
||||||
|
//[12]
|
||||||
|
/**
|
||||||
|
* @brief compile
|
||||||
|
* Compiles the shader data in memory and returns the shader object.
|
||||||
|
* @param data
|
||||||
|
* Shader data
|
||||||
|
* @param filename
|
||||||
|
* Filename of the shader
|
||||||
|
* @param stage
|
||||||
|
* Type of shader, based on suffix of original file
|
||||||
|
* @return
|
||||||
|
* Compiled shader object
|
||||||
|
*/
|
||||||
|
auto compile(const QByteArray &data, const QString &filename, const QShader::Stage stage) noexcept(false) -> QShader;
|
||||||
|
|
||||||
|
//[13]
|
||||||
|
/**
|
||||||
|
* @brief save
|
||||||
|
* Saves a serialized version of the shader to the specified uri
|
||||||
|
* @param uri
|
||||||
|
* Uri of the file to create
|
||||||
|
* @param shader
|
||||||
|
* The compiled shader
|
||||||
|
*/
|
||||||
|
auto save(const QUrl &uri, const QShader &shader) noexcept(false) -> void;
|
||||||
|
|
||||||
|
//@BEGIN helpers
|
||||||
|
/**
|
||||||
|
* @brief validateUri
|
||||||
|
* Validates that the uri is a local file or direcotry
|
||||||
|
* @param uri
|
||||||
|
*/
|
||||||
|
auto validateUri(const QUrl &uri) const noexcept(false) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief run
|
||||||
|
* Runs the supplied command with the given arguments as a QProcess. If
|
||||||
|
* data is supplied, it is written to the standard input channel after the
|
||||||
|
* process has started
|
||||||
|
* @param command
|
||||||
|
* System command or program to run
|
||||||
|
* @param arguments
|
||||||
|
* QStringList of the given arguments. Minimal wildcard expansion available.
|
||||||
|
* @param data
|
||||||
|
* Optional data to write
|
||||||
|
* @return
|
||||||
|
* Standard non-error output
|
||||||
|
*/
|
||||||
|
auto run(const QString &command, const QStringList &arguments, const QByteArray &data = {}) noexcept(false) -> QByteArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief readFile
|
||||||
|
* Reads the file at the given uri and returns its data
|
||||||
|
* @param uri
|
||||||
|
* Uri of the file
|
||||||
|
* @return
|
||||||
|
* File contents
|
||||||
|
*/
|
||||||
|
auto readFile(const QUrl &uri) noexcept(false) -> QByteArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief writeFile
|
||||||
|
* Writes the supplied data to the given uri
|
||||||
|
* @param uri
|
||||||
|
* Uri of the file
|
||||||
|
* @param data
|
||||||
|
* Data to write
|
||||||
|
*/
|
||||||
|
auto writeFile(const QUrl &uri, const QByteArray &data) noexcept(false) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief copyFile
|
||||||
|
* Copys file to new uri
|
||||||
|
* @param sourceUri
|
||||||
|
* File to copy
|
||||||
|
* @param destinationUri
|
||||||
|
* New file location/name
|
||||||
|
*/
|
||||||
|
auto copyFile(const QUrl &sourceUri, const QUrl &destinationUri) noexcept(false) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief createDirectory
|
||||||
|
* QDir::mkpath was failing, so this helper function calls mkdir -p
|
||||||
|
* @param uri
|
||||||
|
* Directory path to create
|
||||||
|
*/
|
||||||
|
auto createDirectory(const QUrl &uri) noexcept(false) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief removeDirectory
|
||||||
|
* Calls rm -rf, but should be replaced with an agnostic solution
|
||||||
|
* @param uri
|
||||||
|
* Directory to remove
|
||||||
|
*/
|
||||||
|
auto removeDirectory(const QUrl &uri) noexcept(false) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getStageFromSuffix
|
||||||
|
* Supplies the stage/type of shader based on the shaders file extension
|
||||||
|
* @param suffix
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto getStageFromSuffix(const QString &suffix) const -> QShader::Stage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setState
|
||||||
|
* Sets the current state of the compiler
|
||||||
|
* @param state
|
||||||
|
*/
|
||||||
|
auto setState(State state) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setProgress
|
||||||
|
* Sets the current progress of the compiler
|
||||||
|
* @param progress
|
||||||
|
*/
|
||||||
|
auto setProgress(qreal progress) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setTotalSteps
|
||||||
|
* Sets the total steps pack will take to build
|
||||||
|
* @param steps
|
||||||
|
*/
|
||||||
|
auto setTotalSteps(qint64 steps) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setCurrentStep
|
||||||
|
* Sets the current step
|
||||||
|
* @param step
|
||||||
|
*/
|
||||||
|
auto setCurrentStep(qint64 step) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setStatus
|
||||||
|
* Sets the current status message
|
||||||
|
* @param status
|
||||||
|
*/
|
||||||
|
auto setStatus(const QString &status) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief incrementCompileStep
|
||||||
|
* Increments the current step and updates progress
|
||||||
|
*/
|
||||||
|
auto incrementCompileStep() -> void;
|
||||||
|
|
||||||
|
//@END helpers
|
||||||
|
|
||||||
|
#ifdef HAS_VULKAN
|
||||||
|
/**
|
||||||
|
* @brief vulkanVersion
|
||||||
|
* Returns the current version reported by the vulkan api
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto vulkanVersion() const -> qint32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_OPENGL
|
||||||
|
/**
|
||||||
|
* @brief openGlVersion
|
||||||
|
* Returns the current version reported by the opengl api
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto openGlVersion() const -> qint32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//members
|
||||||
|
/**
|
||||||
|
* @brief m_updateVariables
|
||||||
|
* Standard variables expected by most online shaders, mainly
|
||||||
|
* shadertoy and similar.
|
||||||
|
*/
|
||||||
static inline const QStringList m_updateVariables
|
static inline const QStringList m_updateVariables
|
||||||
{
|
{
|
||||||
QStringLiteral("iTime"),
|
QStringLiteral("iTime"),
|
||||||
@@ -150,12 +439,73 @@ private:
|
|||||||
QStringLiteral("iChannelResolution")
|
QStringLiteral("iChannelResolution")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief m_variableExpressions
|
||||||
|
* Regular expressions of standardized variables. Built at runtime
|
||||||
|
*/
|
||||||
|
static inline QList<QRegularExpression> m_variableExpressions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief m_shaderNameFilters
|
||||||
|
* Name filters for supported shader types
|
||||||
|
*/
|
||||||
|
static inline const QStringList m_shaderNameFilters
|
||||||
|
{
|
||||||
|
QStringLiteral("*.frag"),
|
||||||
|
QStringLiteral("*.vert"),
|
||||||
|
QStringLiteral("*.tese"),
|
||||||
|
QStringLiteral("*.tesc"),
|
||||||
|
QStringLiteral("*.geom"),
|
||||||
|
QStringLiteral("*.comp"),
|
||||||
|
QStringLiteral("*.glsl")
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief m_shaderStages
|
||||||
|
* Map of supported file suffix to their QShader::Stage
|
||||||
|
*/
|
||||||
|
static inline const QMap<QString, QShader::Stage> m_shaderStages
|
||||||
|
{
|
||||||
|
{
|
||||||
|
QStringLiteral("frag"),
|
||||||
|
QShader::FragmentStage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
QStringLiteral("vert"),
|
||||||
|
QShader::VertexStage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
QStringLiteral("tese"),
|
||||||
|
QShader::TessellationEvaluationStage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
QStringLiteral("tesc"),
|
||||||
|
QShader::TessellationControlStage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
QStringLiteral("geom"),
|
||||||
|
QShader::GeometryStage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
QStringLiteral("comp"),
|
||||||
|
QShader::ComputeStage
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief m_version
|
||||||
|
* Version to be appended to the shader before build
|
||||||
|
*/
|
||||||
static inline const QByteArray m_version
|
static inline const QByteArray m_version
|
||||||
{
|
{
|
||||||
R"(#version 450)"
|
R"(#version 450)"
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline const QString m_header
|
/**
|
||||||
|
* @brief m_header
|
||||||
|
* Header to be appended to the shader before build
|
||||||
|
*/
|
||||||
|
static inline const QByteArray m_header
|
||||||
{
|
{
|
||||||
R"(layout(location = 0) in vec2 qt_TexCoord0;
|
R"(layout(location = 0) in vec2 qt_TexCoord0;
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
@@ -184,59 +534,26 @@ layout(binding = 4) uniform sampler2D iChannel3;
|
|||||||
vec2 fragCoord = vec2(qt_TexCoord0.x, 1.0 - qt_TexCoord0.y) * ubuf.iResolution.xy;)"
|
vec2 fragCoord = vec2(qt_TexCoord0.x, 1.0 - qt_TexCoord0.y) * ubuf.iResolution.xy;)"
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline const QString m_footer
|
/**
|
||||||
|
* @brief m_footer
|
||||||
|
* Footer to be appended to the shader before build
|
||||||
|
*/
|
||||||
|
static inline const QByteArray m_footer
|
||||||
{
|
{
|
||||||
R"(void main() {
|
R"(
|
||||||
|
void main() {
|
||||||
vec4 color = vec4(0.0);
|
vec4 color = vec4(0.0);
|
||||||
mainImage(color, fragCoord);
|
mainImage(color, fragCoord);
|
||||||
fragColor = color;
|
fragColor = color;
|
||||||
})"
|
})"
|
||||||
};
|
};
|
||||||
|
|
||||||
QString m_compilerOutput;
|
|
||||||
QString m_errorMessage;
|
|
||||||
QString m_errorTitle;
|
|
||||||
QString m_status;
|
|
||||||
|
|
||||||
State m_state;
|
State m_state;
|
||||||
|
|
||||||
qreal m_currentStep = 0;
|
qreal m_currentStep = 0;
|
||||||
qreal m_progress = 0;
|
qreal m_progress = 0;
|
||||||
qreal m_totalSteps = 0;
|
qreal m_totalSteps = 0;
|
||||||
|
QString m_status;
|
||||||
|
|
||||||
QMutex m_downloadMutex;
|
|
||||||
|
|
||||||
static inline QList<QRegularExpression> m_variableExpressions;
|
|
||||||
|
|
||||||
static inline const QRegularExpression m_commonFragmentExpression = QRegularExpression
|
|
||||||
(
|
|
||||||
QString("^common\\.frag$"),
|
|
||||||
QRegularExpression::CaseInsensitiveOption
|
|
||||||
);
|
|
||||||
|
|
||||||
static inline const QRegularExpression m_commonVertexExpression = QRegularExpression
|
|
||||||
(
|
|
||||||
QString("^common\\.vert$"),
|
|
||||||
QRegularExpression::CaseInsensitiveOption
|
|
||||||
);
|
|
||||||
|
|
||||||
static inline const QRegularExpression m_fragmentExpression = QRegularExpression
|
|
||||||
(
|
|
||||||
QString("^.{1,}\\.frag$"),
|
|
||||||
QRegularExpression::CaseInsensitiveOption |
|
|
||||||
QRegularExpression::DotMatchesEverythingOption
|
|
||||||
);
|
|
||||||
|
|
||||||
static inline const QRegularExpression m_vertexExpression = QRegularExpression
|
|
||||||
(
|
|
||||||
QString("^.{1,}\\.vert$"),
|
|
||||||
QRegularExpression::CaseInsensitiveOption |
|
|
||||||
QRegularExpression::DotMatchesEverythingOption
|
|
||||||
);
|
|
||||||
|
|
||||||
Q_PROPERTY(QString compilerOutput READ compilerOutput WRITE setCompilerOutput NOTIFY compilerOutputChanged FINAL)
|
|
||||||
Q_PROPERTY(QString errorTitle READ errorTitle NOTIFY errorTitleChanged FINAL)
|
|
||||||
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged FINAL)
|
|
||||||
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged FINAL)
|
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged FINAL)
|
||||||
Q_PROPERTY(qint64 totalSteps READ totalSteps NOTIFY totalStepsChanged FINAL)
|
Q_PROPERTY(qint64 totalSteps READ totalSteps NOTIFY totalStepsChanged FINAL)
|
||||||
Q_PROPERTY(qint64 currentStep READ currentStep NOTIFY currentStepChanged FINAL)
|
Q_PROPERTY(qint64 currentStep READ currentStep NOTIFY currentStepChanged FINAL)
|
||||||
|
|||||||
@@ -36,11 +36,8 @@ class KOMPLEX_EXPORT FeaturedImagesPaginator : public ImagePaginator
|
|||||||
public:
|
public:
|
||||||
explicit FeaturedImagesPaginator(QObject *parent = nullptr) : ImagePaginator(parent)
|
explicit FeaturedImagesPaginator(QObject *parent = nullptr) : ImagePaginator(parent)
|
||||||
{
|
{
|
||||||
setUri(
|
setUri(KOMPLEX_ENDPOINT_IMAGES_FEATURED);
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_IMAGES_FEATURED)
|
controller()->setWindowSize(32);
|
||||||
);
|
|
||||||
|
|
||||||
controller()->setWindowSize(20);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,10 +36,7 @@ class KOMPLEX_EXPORT FeaturedPacksPaginator : public WallpaperPaginator
|
|||||||
public:
|
public:
|
||||||
explicit FeaturedPacksPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
explicit FeaturedPacksPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||||
{
|
{
|
||||||
setUri(
|
setUri(KOMPLEX_ENDPOINT_PACKS_FEATURED);
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_PACKS_FEATURED)
|
|
||||||
);
|
|
||||||
|
|
||||||
controller()->setWindowSize(32);
|
controller()->setWindowSize(32);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef FEATUREDSHADERSPAGINATOR_H
|
|
||||||
#define FEATUREDSHADERSPAGINATOR_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QEventLoop>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "wallpaperpaginator.h"
|
|
||||||
|
|
||||||
class KOMPLEX_EXPORT FeaturedShadersPaginator : public WallpaperPaginator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit FeaturedShadersPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
|
||||||
{
|
|
||||||
setUri(
|
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_SHADERS_FEATURED)
|
|
||||||
);
|
|
||||||
|
|
||||||
controller()->setWindowSize(20);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // FEATUREDSHADERSPAGINATOR_H
|
|
||||||
@@ -36,11 +36,8 @@ class KOMPLEX_EXPORT FeaturedVideosPaginator : public VideoPaginator
|
|||||||
public:
|
public:
|
||||||
explicit FeaturedVideosPaginator(QObject *parent = nullptr) : VideoPaginator(parent)
|
explicit FeaturedVideosPaginator(QObject *parent = nullptr) : VideoPaginator(parent)
|
||||||
{
|
{
|
||||||
setUri(
|
setUri(KOMPLEX_ENDPOINT_VIDEOS_FEATURED);
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_VIDEOS_FEATURED)
|
controller()->setWindowSize(32);
|
||||||
);
|
|
||||||
|
|
||||||
controller()->setWindowSize(20);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/paginator.h"
|
|
||||||
#include "common/imagecache.h"
|
#include "common/imagecache.h"
|
||||||
#include "common/coreservices.h"
|
#include "common/coreservices.h"
|
||||||
|
#include "paginator.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The ImagePaginator class
|
* @brief The ImagePaginator class
|
||||||
|
|||||||
@@ -38,10 +38,7 @@ class KOMPLEX_EXPORT ImageSearchPaginator : public ImagePaginator
|
|||||||
public:
|
public:
|
||||||
explicit ImageSearchPaginator(QObject *parent = nullptr) : ImagePaginator(parent)
|
explicit ImageSearchPaginator(QObject *parent = nullptr) : ImagePaginator(parent)
|
||||||
{
|
{
|
||||||
setUri(
|
setUri(KOMPLEX_ENDPOINT_IMAGES_SEARCH);
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_IMAGES_SEARCH)
|
|
||||||
);
|
|
||||||
|
|
||||||
setQueryable(true);
|
setQueryable(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef NEWESTCUBEMAPSPAGINATOR_H
|
|
||||||
#define NEWESTCUBEMAPSPAGINATOR_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QEventLoop>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "wallpaperpaginator.h"
|
|
||||||
|
|
||||||
class KOMPLEX_EXPORT NewestCubemapsPaginator : public WallpaperPaginator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit NewestCubemapsPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
|
||||||
{
|
|
||||||
setUri(
|
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_CUBEMAPS_NEWEST)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // NEWESTCUBEMAPSPAGINATOR_H
|
|
||||||
@@ -36,10 +36,7 @@ class KOMPLEX_EXPORT NewestPacksPaginator : public WallpaperPaginator
|
|||||||
public:
|
public:
|
||||||
explicit NewestPacksPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
explicit NewestPacksPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||||
{
|
{
|
||||||
setUri(
|
setUri(KOMPLEX_ENDPOINT_PACKS_NEWEST);
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_PACKS_NEWEST)
|
|
||||||
);
|
|
||||||
|
|
||||||
controller()->setWindowSize(20);
|
controller()->setWindowSize(20);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,10 +36,7 @@ class KOMPLEX_EXPORT PackSearchPaginator : public WallpaperPaginator
|
|||||||
public:
|
public:
|
||||||
explicit PackSearchPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
explicit PackSearchPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||||
{
|
{
|
||||||
setUri(
|
setUri(KOMPLEX_ENDPOINT_PACKS_SEARCH);
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_PACKS_SEARCH)
|
|
||||||
);
|
|
||||||
|
|
||||||
setQueryable(true);
|
setQueryable(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonParseError>
|
#include <QJsonParseError>
|
||||||
|
|
||||||
#include "komplex_global.h"
|
#include "common/komplex_global.h"
|
||||||
#include "slidingcachecontroller.h"
|
#include "common/slidingcachecontroller.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The PaginationNotifier class
|
* @brief The PaginationNotifier class
|
||||||
@@ -120,6 +120,7 @@ public:
|
|||||||
* @brief resultsPerPage
|
* @brief resultsPerPage
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
auto resultsPerPage() const -> qsizetype
|
auto resultsPerPage() const -> qsizetype
|
||||||
{
|
{
|
||||||
return m_resultsPerPage;
|
return m_resultsPerPage;
|
||||||
@@ -204,6 +205,7 @@ public:
|
|||||||
* @brief data
|
* @brief data
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
auto data() const -> const QList<T>
|
auto data() const -> const QList<T>
|
||||||
{
|
{
|
||||||
if(boundaryCheck(m_resultsPerPage))
|
if(boundaryCheck(m_resultsPerPage))
|
||||||
@@ -219,6 +221,7 @@ public:
|
|||||||
* @brief count
|
* @brief count
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
auto count() const -> qsizetype
|
auto count() const -> qsizetype
|
||||||
{
|
{
|
||||||
if(m_offset == nullsize)
|
if(m_offset == nullsize)
|
||||||
@@ -240,6 +243,7 @@ public:
|
|||||||
* @param index
|
* @param index
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
auto at(qsizetype index) const -> const T&
|
auto at(qsizetype index) const -> const T&
|
||||||
{
|
{
|
||||||
return m_cacheController.at(m_offset + index);
|
return m_cacheController.at(m_offset + index);
|
||||||
@@ -251,6 +255,7 @@ public:
|
|||||||
* The total number of results as reported by the controller
|
* The total number of results as reported by the controller
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
auto totalResults() const -> qsizetype
|
auto totalResults() const -> qsizetype
|
||||||
{
|
{
|
||||||
return m_cacheController.totalCount();
|
return m_cacheController.totalCount();
|
||||||
@@ -261,6 +266,7 @@ public:
|
|||||||
* Calculates the current page
|
* Calculates the current page
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
auto page() const -> qsizetype
|
auto page() const -> qsizetype
|
||||||
{
|
{
|
||||||
return std::floor(
|
return std::floor(
|
||||||
@@ -273,6 +279,7 @@ public:
|
|||||||
* Calculates the total number of pages available
|
* Calculates the total number of pages available
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
auto totalPages() const -> qsizetype
|
auto totalPages() const -> qsizetype
|
||||||
{
|
{
|
||||||
return std::ceil(
|
return std::ceil(
|
||||||
@@ -280,13 +287,29 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
|
* @brief setWindowSize
|
||||||
|
* Sets the controller window size
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
auto setWindowSize(qsizetype size) -> void
|
||||||
|
{
|
||||||
|
m_cacheController.setWindowSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
auto windowSize() const -> qsizetype
|
||||||
|
{
|
||||||
|
return m_cacheController.windowSize();
|
||||||
|
}
|
||||||
|
|
||||||
auto queryable() const -> bool
|
auto queryable() const -> bool
|
||||||
{
|
{
|
||||||
return m_queryable;
|
return m_queryable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
auto setQueryable(bool queryable) -> void
|
auto setQueryable(bool queryable) -> void
|
||||||
{
|
{
|
||||||
m_queryable = queryable;
|
m_queryable = queryable;
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef SEARCHCUBEMAPSPAGINATOR_H
|
|
||||||
#define SEARCHCUBEMAPSPAGINATOR_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QEventLoop>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "wallpaperpaginator.h"
|
|
||||||
|
|
||||||
class KOMPLEX_EXPORT SearchCubemapsPaginator : public WallpaperPaginator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit SearchCubemapsPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
|
||||||
{
|
|
||||||
setUri(
|
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_CUBEMAPS_SEARCH)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SEARCHCUBEMAPSPAGINATOR_H
|
|
||||||
@@ -30,9 +30,9 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/paginator.h"
|
|
||||||
#include "common/videocache.h"
|
#include "common/videocache.h"
|
||||||
#include "common/coreservices.h"
|
#include "common/coreservices.h"
|
||||||
|
#include "paginator.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The VideoPaginator class
|
* @brief The VideoPaginator class
|
||||||
@@ -245,6 +245,8 @@ protected:
|
|||||||
loop.exec();
|
loop.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
manager.clear();
|
||||||
|
|
||||||
LOG_ERROR_X(reply->error() != QNetworkReply::NoError,
|
LOG_ERROR_X(reply->error() != QNetworkReply::NoError,
|
||||||
"NewestPacksPaginator::getNetworkReply",
|
"NewestPacksPaginator::getNetworkReply",
|
||||||
reply->errorString().toStdString().c_str(),
|
reply->errorString().toStdString().c_str(),
|
||||||
|
|||||||
@@ -36,10 +36,7 @@ class KOMPLEX_EXPORT VideoSearchPaginator : public VideoPaginator
|
|||||||
public:
|
public:
|
||||||
explicit VideoSearchPaginator(QObject *parent = nullptr) : VideoPaginator(parent)
|
explicit VideoSearchPaginator(QObject *parent = nullptr) : VideoPaginator(parent)
|
||||||
{
|
{
|
||||||
setUri(
|
setUri(KOMPLEX_ENDPOINT_VIDEOS_SEARCH);
|
||||||
QString::fromUtf8(KOMPLEX_ENDPOINT_VIDEOS_SEARCH)
|
|
||||||
);
|
|
||||||
|
|
||||||
setQueryable(true);
|
setQueryable(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/paginator.h"
|
|
||||||
#include "common/wallpapercache.h"
|
#include "common/wallpapercache.h"
|
||||||
#include "common/coreservices.h"
|
#include "common/coreservices.h"
|
||||||
|
#include "paginator.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The WallpaperPaginator class
|
* @brief The WallpaperPaginator class
|
||||||
@@ -248,6 +248,8 @@ protected:
|
|||||||
loop.exec();
|
loop.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
manager.clear();
|
||||||
|
|
||||||
LOG_ERROR_X(reply->error() != QNetworkReply::NoError,
|
LOG_ERROR_X(reply->error() != QNetworkReply::NoError,
|
||||||
"NewestPacksPaginator::getNetworkReply",
|
"NewestPacksPaginator::getNetworkReply",
|
||||||
reply->errorString().toStdString().c_str(),
|
reply->errorString().toStdString().c_str(),
|
||||||
|
|||||||
@@ -0,0 +1,288 @@
|
|||||||
|
#include "usermodel.h"
|
||||||
|
#include "common/userservices.h"
|
||||||
|
#include <QtConcurrent/qtconcurrentrun.h>
|
||||||
|
#include <qdatetime.h>
|
||||||
|
#include <qfuture.h>
|
||||||
|
#include <qobjectdefs.h>
|
||||||
|
#include <qstringview.h>
|
||||||
|
|
||||||
|
UserModel::UserModel(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
{
|
||||||
|
m_stateResetTimer = new QTimer(this);
|
||||||
|
m_stateResetTimer->setInterval(1000);
|
||||||
|
m_stateResetTimer->setSingleShot(true);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
m_stateResetTimer,
|
||||||
|
&QTimer::timeout,
|
||||||
|
this,
|
||||||
|
&UserModel::resetState
|
||||||
|
);
|
||||||
|
|
||||||
|
setState(Busy);
|
||||||
|
|
||||||
|
QSharedPointer<UserServices> service = UserServices::instance();
|
||||||
|
|
||||||
|
if(service == nullptr)
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("UserServices object deleted"));
|
||||||
|
setState(LoginFailure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFuture<QString> usernameFuture = service->defaultUsername();
|
||||||
|
|
||||||
|
usernameFuture
|
||||||
|
.then
|
||||||
|
(
|
||||||
|
[this] (const QString username)
|
||||||
|
{
|
||||||
|
login(username);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onCanceled
|
||||||
|
(
|
||||||
|
[this] () -> void
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] () -> void
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
service.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel::~UserModel()
|
||||||
|
{
|
||||||
|
if(m_stateResetTimer != nullptr)
|
||||||
|
{
|
||||||
|
m_stateResetTimer->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::login() -> void
|
||||||
|
{
|
||||||
|
QFuture aether = QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this] () -> void
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_loginMutex);
|
||||||
|
setState(LoggingIn);
|
||||||
|
|
||||||
|
QSharedPointer<UserServices> service = UserServices::instance();
|
||||||
|
|
||||||
|
if(service == nullptr)
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("UserServices object deleted"));
|
||||||
|
setState(LoginFailure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_loginAttempt = service->login(username(), password().toUtf8());
|
||||||
|
|
||||||
|
m_loginAttempt
|
||||||
|
.then
|
||||||
|
(
|
||||||
|
[this] (UserCredentials credentials) -> void
|
||||||
|
{
|
||||||
|
setState(LoggedIn);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onCanceled
|
||||||
|
(
|
||||||
|
[this] () -> void
|
||||||
|
{
|
||||||
|
setState(LoginFailure);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onFailed
|
||||||
|
(
|
||||||
|
[this] () -> void
|
||||||
|
{
|
||||||
|
setState(LoginCancelled);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::login(const QString username) -> void
|
||||||
|
{
|
||||||
|
if(username == m_username)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_username = username;
|
||||||
|
Q_EMIT usernameChanged();
|
||||||
|
|
||||||
|
QSharedPointer<UserServices> service = UserServices::instance();
|
||||||
|
|
||||||
|
if(service == nullptr)
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("UserServices object deleted"));
|
||||||
|
setState(LoggedOut);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFuture<UserCredentials> tokenRead = service->readToken(username);
|
||||||
|
|
||||||
|
tokenRead
|
||||||
|
.then
|
||||||
|
(
|
||||||
|
[this] (const UserCredentials credentials) -> void
|
||||||
|
{
|
||||||
|
if(QDateTime::currentDateTime() <= credentials.expiry)
|
||||||
|
{
|
||||||
|
setState(LoggedIn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<UserServices> service = UserServices::instance();
|
||||||
|
|
||||||
|
if(service == nullptr)
|
||||||
|
{
|
||||||
|
setErrorString(QStringLiteral("UserServices object deleted"));
|
||||||
|
setState(LoggedOut);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFuture<QByteArray> passwordRead = service->readPassword(credentials.username);
|
||||||
|
|
||||||
|
passwordRead
|
||||||
|
.then
|
||||||
|
(
|
||||||
|
[this] (const QByteArray password)
|
||||||
|
{
|
||||||
|
if(password.isEmpty())
|
||||||
|
{
|
||||||
|
setState(LoggedOut);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPassword(password);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
service.clear();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
service.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::cancelLogin() -> void
|
||||||
|
{
|
||||||
|
QFuture aether = QtConcurrent::run
|
||||||
|
(
|
||||||
|
[this] () -> void
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_loginMutex);
|
||||||
|
|
||||||
|
if(m_loginAttempt.isRunning())
|
||||||
|
{
|
||||||
|
m_loginAttempt.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::reset() -> void
|
||||||
|
{
|
||||||
|
resetState();
|
||||||
|
setUsername({});
|
||||||
|
setPassword({});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::setUsername(const QString &username) -> void
|
||||||
|
{
|
||||||
|
if(username == m_username)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_username = username;
|
||||||
|
Q_EMIT usernameChanged();
|
||||||
|
|
||||||
|
if(!password().isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(Busy);
|
||||||
|
|
||||||
|
QSharedPointer<UserServices> service = UserServices::instance();
|
||||||
|
|
||||||
|
if(service == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFuture<QByteArray> passwordRead = service->readPassword(username);
|
||||||
|
passwordRead
|
||||||
|
.then
|
||||||
|
(
|
||||||
|
[this] (const QByteArray password) -> void
|
||||||
|
{
|
||||||
|
setPassword(password);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::setPassword(const QString &password) -> void
|
||||||
|
{
|
||||||
|
if(password == m_password)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_password = password;
|
||||||
|
Q_EMIT passwordChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::resetState() -> void
|
||||||
|
{
|
||||||
|
setState(Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::setState(State state) -> void
|
||||||
|
{
|
||||||
|
if(state == m_state)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case LoginFailure:
|
||||||
|
case LoggedOut:
|
||||||
|
case LoginCancelled:
|
||||||
|
m_stateResetTimer->start();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = state;
|
||||||
|
Q_EMIT stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto UserModel::setErrorString(const QString &string) -> void
|
||||||
|
{
|
||||||
|
if(string == m_errorString)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_errorString = string;
|
||||||
|
Q_EMIT errorStringChanged();
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user