Compare commits
54 Commits
e9bc016fbb
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
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
|
|||
|
a58fdfadc6
|
|||
|
da24f34bb4
|
@@ -0,0 +1,91 @@
|
||||
;This file is used to denote what files have generative content
|
||||
;Format: {file, class, model/version, ["message"]}
|
||||
|
||||
;Kero
|
||||
{
|
||||
{
|
||||
images/kero/kero_build_1.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_build_2.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_build_3.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_build_4.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_build_error.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_choice.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_hello.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_login.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_no_results.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_run_1.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_run_2.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_run_3.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_run_4.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_warning.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_success.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_spotlight.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
},
|
||||
{
|
||||
images/kero/kero_star.png,
|
||||
placeholders,
|
||||
chatgpt5
|
||||
}
|
||||
}
|
||||
+80
-65
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.21.1)
|
||||
option(LINK_INSIGHT "Link Qt Insight Tracker library" 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")
|
||||
|
||||
@@ -20,79 +20,94 @@ set(QML_IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY}
|
||||
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_add_executable(${CMAKE_PROJECT_NAME}
|
||||
README.md
|
||||
LICENSE
|
||||
)
|
||||
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES VERSION "1.0")
|
||||
|
||||
qt_add_resources(${CMAKE_PROJECT_NAME} "configuration"
|
||||
PREFIX "/"
|
||||
FILES
|
||||
qtquickcontrols2.conf
|
||||
PREFIX "/"
|
||||
FILES
|
||||
qtquickcontrols2.conf
|
||||
)
|
||||
|
||||
qt_add_resources(${CMAKE_PROJECT_NAME} "app_images"
|
||||
FILES
|
||||
"images/icons/icons8-back.svg"
|
||||
"images/icons/icons8-bill.svg"
|
||||
"images/icons/icons8-biotech.svg"
|
||||
"images/icons/icons8-cancel.svg"
|
||||
"images/icons/icons8-check-mark.svg"
|
||||
"images/icons/icons8-close-window.svg"
|
||||
"images/icons/icons8-famous.svg"
|
||||
"images/icons/icons8-filter.svg"
|
||||
"images/icons/icons8-forward.svg"
|
||||
"images/icons/icons8-hdd.svg"
|
||||
"images/icons/icons8-image.svg"
|
||||
"images/icons/icons8-login.svg"
|
||||
"images/icons/icons8-logout-rounded-left.svg"
|
||||
"images/icons/icons8-next.svg"
|
||||
"images/icons/icons8-reply-arrow.svg"
|
||||
"images/icons/icons8-search.svg"
|
||||
"images/icons/icons8-settings.svg"
|
||||
"images/icons/icons8-shopping-cart.svg"
|
||||
"images/icons/icons8-star-filled.svg"
|
||||
"images/icons/icons8-store.svg"
|
||||
"images/icons/icons8-user-account.svg"
|
||||
"images/icons/icons8-view-more.svg"
|
||||
"images/icons/icons8-video.svg"
|
||||
"images/icons/pexels-icon-filled-256.svg"
|
||||
"images/icons/icons8-trash.svg"
|
||||
"images/icons/icons8-download.svg"
|
||||
"images/icons/icons8-play.svg"
|
||||
"images/icons/icons8-stop.svg"
|
||||
"images/icons/icons8-codepen.svg"
|
||||
"images/icons/icons8-cube.svg"
|
||||
"images/icons/icons8-camera.svg"
|
||||
"images/icons/icons8-audio.svg"
|
||||
"images/icons/icons8-3d-model.svg"
|
||||
"images/icons/icons8-3d-glasses.svg"
|
||||
"images/icons/kofi.gif"
|
||||
"images/kero/kero_build_1.png"
|
||||
"images/kero/kero_build_2.png"
|
||||
"images/kero/kero_build_3.png"
|
||||
"images/kero/kero_build_4.png"
|
||||
"images/kero/kero_build_error.png"
|
||||
"images/kero/kero_choice.png"
|
||||
"images/kero/kero_error.png"
|
||||
"images/kero/kero_hello.png"
|
||||
"images/kero/kero_login.png"
|
||||
"images/kero/kero_no_results.png"
|
||||
"images/kero/kero_run_1.png"
|
||||
"images/kero/kero_run_2.png"
|
||||
"images/kero/kero_run_3.png"
|
||||
"images/kero/kero_run_4.png"
|
||||
"images/kero/kero_success.png"
|
||||
"images/kero/kero_warning.png"
|
||||
)
|
||||
FILES
|
||||
"images/icons/icons8-back.svg"
|
||||
"images/icons/icons8-bill.svg"
|
||||
"images/icons/icons8-biotech.svg"
|
||||
"images/icons/icons8-cancel.svg"
|
||||
"images/icons/icons8-check-mark.svg"
|
||||
"images/icons/icons8-close-window.svg"
|
||||
"images/icons/icons8-famous.svg"
|
||||
"images/icons/icons8-filter.svg"
|
||||
"images/icons/icons8-forward.svg"
|
||||
"images/icons/icons8-hdd.svg"
|
||||
"images/icons/icons8-image.svg"
|
||||
"images/icons/icons8-login.svg"
|
||||
"images/icons/icons8-logout-rounded-left.svg"
|
||||
"images/icons/icons8-next.svg"
|
||||
"images/icons/icons8-reply-arrow.svg"
|
||||
"images/icons/icons8-search.svg"
|
||||
"images/icons/icons8-settings.svg"
|
||||
"images/icons/icons8-shopping-cart.svg"
|
||||
"images/icons/icons8-star-filled.svg"
|
||||
"images/icons/icons8-store.svg"
|
||||
"images/icons/icons8-user-account.svg"
|
||||
"images/icons/icons8-view-more.svg"
|
||||
"images/icons/icons8-video.svg"
|
||||
"images/icons/pexels-icon-filled-256.svg"
|
||||
"images/icons/icons8-trash.svg"
|
||||
"images/icons/icons8-download.svg"
|
||||
"images/icons/icons8-play.svg"
|
||||
"images/icons/icons8-stop.svg"
|
||||
"images/icons/icons8-codepen.svg"
|
||||
"images/icons/icons8-cube.svg"
|
||||
"images/icons/icons8-camera.svg"
|
||||
"images/icons/icons8-audio.svg"
|
||||
"images/icons/icons8-3d-model.svg"
|
||||
"images/icons/icons8-3d-glasses.svg"
|
||||
"images/icons/kofi.gif"
|
||||
"images/kero/kero_build_1.png"
|
||||
"images/kero/kero_build_2.png"
|
||||
"images/kero/kero_build_3.png"
|
||||
"images/kero/kero_build_4.png"
|
||||
"images/kero/kero_build_error.png"
|
||||
"images/kero/kero_choice.png"
|
||||
"images/kero/kero_error.png"
|
||||
"images/kero/kero_hello.png"
|
||||
"images/kero/kero_login.png"
|
||||
"images/kero/kero_no_results.png"
|
||||
"images/kero/kero_run_1.png"
|
||||
"images/kero/kero_run_2.png"
|
||||
"images/kero/kero_run_3.png"
|
||||
"images/kero/kero_run_4.png"
|
||||
"images/kero/kero_success.png"
|
||||
"images/kero/kero_spotlight.png"
|
||||
"images/kero/kero_star.png"
|
||||
"images/kero/kero_warning.png"
|
||||
)
|
||||
|
||||
target_compile_definitions(
|
||||
${CMAKE_PROJECT_NAME}
|
||||
PUBLIC
|
||||
KOMPLEX_LOCAL_DEV
|
||||
)
|
||||
target_compile_definitions(
|
||||
${CMAKE_PROJECT_NAME}
|
||||
PUBLIC
|
||||
KOMPLEX_LOCAL_DEV
|
||||
)
|
||||
|
||||
include(qds)
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Imported 3D assets and components imported from bundles will be created in this folder.
|
||||
@@ -18,6 +18,20 @@ qt6_add_qml_module(KomplexHubContent
|
||||
"pages/UserProfilePage.qml"
|
||||
"pages/WallpaperSettingsPage.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)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ Rectangle {
|
||||
|
||||
height: 64
|
||||
width: 100
|
||||
text: "Home"
|
||||
text: qsTr("Home")
|
||||
|
||||
icon.height: 32
|
||||
icon.width: 32
|
||||
@@ -109,7 +109,7 @@ Rectangle {
|
||||
|
||||
height: 64
|
||||
width: 100
|
||||
text: "Images"
|
||||
text: qsTr("Images")
|
||||
|
||||
icon.height: 32
|
||||
icon.width: 32
|
||||
@@ -132,7 +132,7 @@ Rectangle {
|
||||
|
||||
height: 64
|
||||
width: 100
|
||||
text: "Videos"
|
||||
text: qsTr("Videos")
|
||||
|
||||
icon.height: 32
|
||||
icon.width: 32
|
||||
@@ -155,7 +155,7 @@ Rectangle {
|
||||
|
||||
height: 64
|
||||
width: 100
|
||||
text: "Live"
|
||||
text: qsTr("Komplex")
|
||||
|
||||
icon.height: 32
|
||||
icon.width: 32
|
||||
@@ -178,7 +178,7 @@ Rectangle {
|
||||
|
||||
height: 64
|
||||
width: 100
|
||||
text: "Installed"
|
||||
text: qsTr("Installed")
|
||||
|
||||
icon.height: 32
|
||||
icon.width: 32
|
||||
@@ -207,7 +207,7 @@ Rectangle {
|
||||
|
||||
height: 64
|
||||
width: 100
|
||||
text: "Settings"
|
||||
text: qsTr("Settings")
|
||||
|
||||
icon.height: 32
|
||||
icon.width: 32
|
||||
@@ -369,7 +369,7 @@ Rectangle {
|
||||
|
||||
function isSearchPage()
|
||||
{
|
||||
return (
|
||||
return(
|
||||
pageLoader.item instanceof ImageSearchPage ||
|
||||
pageLoader.item instanceof LiveSearchPage ||
|
||||
pageLoader.item instanceof VideoSearchPage
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
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"
|
||||
)
|
||||
@@ -0,0 +1,154 @@
|
||||
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
|
||||
//query: rootItem.query
|
||||
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: 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
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: 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
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: 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Effects
|
||||
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
import KomplexHub.Plugin
|
||||
import KomplexHubContent
|
||||
|
||||
Item
|
||||
{
|
||||
@@ -19,15 +20,15 @@ Item
|
||||
imagesModel.state === FeaturedImagesModel.Loading ||
|
||||
videosModel.state === FeaturedVideosModel.Loading;
|
||||
|
||||
onWidthChanged:() => {
|
||||
onWidthChanged: () =>
|
||||
{
|
||||
packsModel.resultsPerPage = resultsPerRow
|
||||
imagesModel.resultsPerPage = resultsPerRow
|
||||
videosModel.resultsPerPage = resultsPerRow
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
||||
id: homePageRoot
|
||||
clip: true
|
||||
|
||||
NewestPacksModel
|
||||
{
|
||||
@@ -47,178 +48,346 @@ Item
|
||||
resultsPerPage: 0
|
||||
}
|
||||
|
||||
Rectangle
|
||||
Flickable
|
||||
{
|
||||
anchors.fill: parent
|
||||
color: palette.base
|
||||
id: pageArea
|
||||
visible: opacity > 0.01
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
ColumnLayout
|
||||
contentHeight: content.height
|
||||
contentWidth: content.width
|
||||
|
||||
Column
|
||||
{
|
||||
id: resultsLayout
|
||||
visible: opacity > 0.01
|
||||
anchors.fill: parent
|
||||
anchors.margins: Constants.mediumMargin
|
||||
id: content
|
||||
width: pageArea.width
|
||||
|
||||
Text
|
||||
VerticalSpacer{ height: Constants.largeMargin; width: Constants.largeMargin }
|
||||
|
||||
Rectangle
|
||||
{
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredHeight: 50
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: childrenRect.height
|
||||
anchors.margins: Constants.largeMargin
|
||||
|
||||
color: palette.text
|
||||
font.pixelSize: Constants.h2Font.pixelSize
|
||||
font.bold: true
|
||||
text: qsTr("Newest Wallpaper Packs")
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
}
|
||||
color: palette.base
|
||||
border.color: palette.midlight
|
||||
|
||||
HorizontalPaginator
|
||||
{
|
||||
id: packsPaginator
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 245
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
model: packsModel
|
||||
delegate: ItemDelegate
|
||||
Column
|
||||
{
|
||||
width: resultWidth
|
||||
height: resultHeight
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
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
|
||||
KeroHeader
|
||||
{
|
||||
anchors.fill: parent
|
||||
title: parent.name
|
||||
author: parent.author
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
height: 180
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
selected: packsPaginator.currentIndex === parent.index
|
||||
Rectangle
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: childrenRect.height
|
||||
|
||||
onTriggered: () => packsPaginator.currentIndex = parent.index
|
||||
color: palette.window
|
||||
|
||||
onViewMoreTriggered: () =>
|
||||
Column
|
||||
{
|
||||
showWallpaperPopup(parent.index)
|
||||
}
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: Constants.largeMargin
|
||||
|
||||
onThumbnailChanged: () =>
|
||||
{
|
||||
console.log(index + " " + thumbnail + " " + parent.thumbnail)
|
||||
Text
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 36
|
||||
|
||||
color: palette.text
|
||||
font.pixelSize: Constants.h2Font.pixelSize
|
||||
font.bold: true
|
||||
text: qsTr("Featured Komplex Wallpapers")
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
HorizontalPaginator
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 245
|
||||
|
||||
id: packsPaginator
|
||||
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: packsPaginator.currentIndex === parent.index
|
||||
|
||||
onTriggered: () => packsPaginator.currentIndex = parent.index
|
||||
|
||||
onViewMoreTriggered: () =>
|
||||
{
|
||||
showWallpaperPopup(parent.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onViewMoreTriggered: () =>
|
||||
{
|
||||
showFeaturedPacksPage()
|
||||
}
|
||||
}
|
||||
|
||||
Text
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 36
|
||||
|
||||
color: palette.text
|
||||
font.pixelSize: Constants.h2Font.pixelSize
|
||||
font.bold: true
|
||||
text: qsTr("Featured Images")
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
HorizontalPaginator
|
||||
{
|
||||
id: imagesPaginator
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 245
|
||||
|
||||
model: imagesModel
|
||||
delegate: ItemDelegate
|
||||
{
|
||||
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
|
||||
author: parent.author
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
pexels: true
|
||||
selected: imagesPaginator.currentIndex === parent.index
|
||||
|
||||
onTriggered: () => imagesPaginator.currentIndex = parent.index
|
||||
|
||||
onViewMoreTriggered: () =>
|
||||
{
|
||||
showImagePopup(parent.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onViewMoreTriggered: () =>
|
||||
{
|
||||
showFeaturedImagesPage()
|
||||
}
|
||||
}
|
||||
|
||||
VerticalSpacer { height: Constants.largeMargin; width: Constants.largeMargin }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text
|
||||
VerticalSpacer { height: Constants.largeMargin; width: Constants.largeMargin }
|
||||
|
||||
Rectangle
|
||||
{
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredHeight: 50
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: childrenRect.height
|
||||
anchors.margins: Constants.largeMargin
|
||||
|
||||
color: palette.text
|
||||
font.pixelSize: Constants.h2Font.pixelSize
|
||||
font.bold: true
|
||||
text: qsTr("Featured Images")
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
}
|
||||
color: palette.base
|
||||
border.color: palette.midlight
|
||||
|
||||
HorizontalPaginator
|
||||
{
|
||||
id: imagesPaginator
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 245
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
model: imagesModel
|
||||
delegate: ItemDelegate
|
||||
Column
|
||||
{
|
||||
width: resultWidth
|
||||
height: resultHeight
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
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
|
||||
KeroHeader
|
||||
{
|
||||
anchors.fill: parent
|
||||
title: parent.author
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
pexels: true
|
||||
selected: imagesPaginator.currentIndex === parent.index
|
||||
height: 180
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
title: qsTr("New & Popular Wallpapers")
|
||||
image: "qrc:/images/kero/kero_star.png"
|
||||
}
|
||||
|
||||
onTriggered: () => imagesPaginator.currentIndex = parent.index
|
||||
Rectangle
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: Constants.largeMargin
|
||||
|
||||
onViewMoreTriggered: () =>
|
||||
height: childrenRect.height
|
||||
color: palette.window
|
||||
|
||||
Column
|
||||
{
|
||||
showImagePopup(parent.index)
|
||||
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
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 36
|
||||
|
||||
color: palette.text
|
||||
font.pixelSize: Constants.h2Font.pixelSize
|
||||
font.bold: true
|
||||
text: qsTr("Popular Videos")
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
HorizontalPaginator
|
||||
{
|
||||
id: videosPaginator
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 245
|
||||
|
||||
model: videosModel
|
||||
delegate: ItemDelegate
|
||||
{
|
||||
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
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
pexels: true
|
||||
selected: videosPaginator.currentIndex === parent.index
|
||||
|
||||
onTriggered: () => videosPaginator.currentIndex = parent.index
|
||||
onViewMoreTriggered:() => showVideoPopup(parent.index)
|
||||
}
|
||||
}
|
||||
|
||||
onViewMoreTriggered: () =>
|
||||
{
|
||||
showFeaturedVideosPage()
|
||||
}
|
||||
}
|
||||
|
||||
VerticalSpacer{ height: Constants.largeMargin; width: Constants.largeMargin }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text
|
||||
{
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredHeight: 50
|
||||
|
||||
color: palette.text
|
||||
font.pixelSize: Constants.h2Font.pixelSize
|
||||
font.bold: true
|
||||
text: qsTr("Popular Videos")
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
HorizontalPaginator
|
||||
{
|
||||
id: videosPaginator
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 245
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
model: videosModel
|
||||
delegate: ItemDelegate
|
||||
{
|
||||
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
|
||||
title: parent.author
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
pexels: true
|
||||
selected: videosPaginator.currentIndex === parent.index
|
||||
|
||||
onTriggered: () => videosPaginator.currentIndex = parent.index
|
||||
onViewMoreTriggered:() => showVideoPopup(parent.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* spacer */
|
||||
Item { Layout.fillHeight: true }
|
||||
VerticalSpacer{ height: Constants.largeMargin; width: Constants.largeMargin }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +422,8 @@ Item
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
|
||||
Behavior on opacity {
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
@@ -267,9 +437,9 @@ Item
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
//model: videosModel.itemModel
|
||||
|
||||
Behavior on opacity {
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
@@ -283,9 +453,9 @@ Item
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
//model: videosModel.itemModel
|
||||
|
||||
Behavior on opacity {
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
@@ -293,7 +463,8 @@ Item
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
@@ -301,8 +472,91 @@ Item
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
Component
|
||||
{
|
||||
id: featuredVideosComponent
|
||||
|
||||
FeaturedVideosPage
|
||||
{
|
||||
id: featuredVideosPage
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: () => featuredVideosPage.opacity = 1
|
||||
}
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: featuredPacksComponent
|
||||
|
||||
FeaturedPacksPage
|
||||
{
|
||||
id: featuredPacksPage
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: () => featuredPacksPage.opacity = 1
|
||||
}
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: featuredImagesComponent
|
||||
|
||||
FeaturedImagesPage
|
||||
{
|
||||
id: featuredImagesPage
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: () => featuredImagesPage.opacity = 1
|
||||
}
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: featuredLoaderItem
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
enabled: visible
|
||||
|
||||
Loader
|
||||
{
|
||||
id: featuredLoader
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
||||
states:
|
||||
[
|
||||
State
|
||||
{
|
||||
name: "loading"
|
||||
when: homePageRoot.loading
|
||||
|
||||
@@ -314,7 +568,7 @@ Item
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: resultsLayout
|
||||
target: pageArea
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
@@ -324,11 +578,10 @@ Item
|
||||
opacity: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
State
|
||||
{
|
||||
name: "idle"
|
||||
when: packsModel.state !== NewestPacksModel.Loading &&
|
||||
imagesModel.state !== FeaturedImagesModel.Loading &&
|
||||
videosModel.state !== FeaturedVideosModel.Loading;
|
||||
when: !popup && !loading
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
@@ -338,13 +591,31 @@ Item
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: resultsLayout
|
||||
target: pageArea
|
||||
opacity: 1
|
||||
}
|
||||
},
|
||||
State
|
||||
{
|
||||
name: "popup"
|
||||
when: popup
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: pageArea
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
PropertyChanges
|
||||
{
|
||||
target: loadingAnimation
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
transitions:
|
||||
[
|
||||
Transition
|
||||
{
|
||||
from: "loading"
|
||||
@@ -357,13 +628,37 @@ Item
|
||||
}
|
||||
NumberAnimation
|
||||
{
|
||||
target: resultsLayout
|
||||
target: pageArea
|
||||
duration: 250
|
||||
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)
|
||||
{
|
||||
viewMoreImagePopup.author = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.AuthorRole)
|
||||
@@ -371,7 +666,6 @@ Item
|
||||
viewMoreImagePopup.description = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.DescriptionRole)
|
||||
viewMoreImagePopup.uuid = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.UuidRole)
|
||||
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.landscape = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.LandscapeUrlRole)
|
||||
viewMoreImagePopup.backgroundPortrait = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.BackgroundPortraitRole)
|
||||
@@ -382,7 +676,7 @@ Item
|
||||
viewMoreImagePopup.fullScreenSize = imagesModel.data(imagesModel.index(index,0), FeaturedImagesModel.ScreenSizeRole)
|
||||
viewMoreImagePopup.opacity = 1
|
||||
popupContainer.opacity = 1
|
||||
resultsLayout.opacity = 0
|
||||
pageArea.opacity = 0
|
||||
homePageRoot.popup = true
|
||||
}
|
||||
|
||||
@@ -396,7 +690,7 @@ Item
|
||||
viewMoreVideoPopup.modelIndex = index
|
||||
viewMoreVideoPopup.model = videosModel.itemModel
|
||||
viewMoreVideoPopup.opacity = 1
|
||||
resultsLayout.opacity = 0
|
||||
pageArea.opacity = 0
|
||||
popupContainer.opacity = 1
|
||||
homePageRoot.popup = true
|
||||
}
|
||||
@@ -407,19 +701,28 @@ Item
|
||||
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.name = packsModel.data(packsModel.index(index,0), NewestPacksModel.NameRole)
|
||||
viewMoreWallpaperPopup.uuid = packsModel.data(packsModel.index(index,0), NewestPacksModel.UuidRole)
|
||||
viewMoreWallpaperPopup.opacity = 1
|
||||
popupContainer.opacity = 1
|
||||
resultsLayout.opacity = 0
|
||||
pageArea.opacity = 0
|
||||
homePageRoot.popup = true
|
||||
}
|
||||
|
||||
function closePopup()
|
||||
{
|
||||
if(featuredLoader.item && featuredLoader.item.popup)
|
||||
{
|
||||
featuredLoader.item.closePopup()
|
||||
return
|
||||
}
|
||||
|
||||
featuredLoaderItem.opacity = 0
|
||||
viewMoreImagePopup.opacity = 0
|
||||
viewMoreVideoPopup.opacity = 0
|
||||
viewMoreWallpaperPopup.opacity = 0
|
||||
popupContainer.opacity = 0
|
||||
resultsLayout.opacity = 1
|
||||
pageArea.opacity = 1
|
||||
homePageRoot.popup = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ import QtQuick.Layouts
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
import KomplexHub.Plugin
|
||||
import KomplexHub.Views
|
||||
import KomplexHub.Pages
|
||||
|
||||
Item
|
||||
{
|
||||
|
||||
@@ -2,10 +2,13 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
import KomplexHub.Plugin
|
||||
import KomplexHub.Views
|
||||
import KomplexHub.Pages
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
import KomplexHub.Plugin
|
||||
import KomplexHub.Views
|
||||
import KomplexHub.Pages
|
||||
|
||||
Item
|
||||
{
|
||||
@@ -33,8 +36,8 @@ Item
|
||||
{
|
||||
id: resultDelegate
|
||||
|
||||
width: 256
|
||||
height: 245
|
||||
width: resultWidth
|
||||
height: resultHeight
|
||||
|
||||
required property string name
|
||||
required property string author
|
||||
@@ -47,7 +50,8 @@ Item
|
||||
SearchResultItem
|
||||
{
|
||||
anchors.fill: parent
|
||||
title: parent.author
|
||||
title: parent.name
|
||||
author: parent.author
|
||||
description: parent.description
|
||||
thumbnail: parent.thumbnail
|
||||
uuid: parent.uuid
|
||||
@@ -108,6 +112,7 @@ Item
|
||||
viewMoreWallpaperPopup.authorId = searchModel.data(searchModel.index(index,0), PackSearchModel.AuthorIdRole)
|
||||
viewMoreWallpaperPopup.description = searchModel.data(searchModel.index(index,0), PackSearchModel.DescriptionRole)
|
||||
viewMoreWallpaperPopup.thumbnail = searchModel.data(searchModel.index(index,0), PackSearchModel.ThumbnailRole)
|
||||
viewMoreWallpaperPopup.uuid = searchModel.data(searchModel.index(index,0), PackSearchModel.UuidRole)
|
||||
viewMoreWallpaperPopup.opacity = 1
|
||||
popupContainer.opacity = 1
|
||||
paginator.opacity = 0
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
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
|
||||
|
||||
Item {
|
||||
id: loginFormRoot
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
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
|
||||
|
||||
Item {
|
||||
readonly property bool searchable: false
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
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
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
@@ -5,7 +5,9 @@ import QtQuick.Layouts
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
import KomplexHub.Plugin
|
||||
import KomplexHub.Views
|
||||
import KomplexHub.Pages
|
||||
|
||||
Item
|
||||
{
|
||||
|
||||
@@ -31,9 +31,12 @@ import QtQuick.Layouts
|
||||
//import org.kde.plasma.core as PlasmaCore
|
||||
import QtCore
|
||||
import Qt.labs.folderlistmodel 2.15
|
||||
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHubPlugin
|
||||
import KomplexHub.Plugin
|
||||
import KomplexHub.Views
|
||||
import KomplexHub.Pages
|
||||
|
||||
//import com.github.digitalartifex.komplex 1.0 as Komplex
|
||||
|
||||
|
||||
@@ -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,66 @@
|
||||
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,131 @@
|
||||
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,58 @@
|
||||
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,339 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
CompletedView
|
||||
{
|
||||
id: completedView
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
manager: downloadManager
|
||||
}
|
||||
|
||||
ErrorView
|
||||
{
|
||||
id: errorView
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
manager: downloadManager
|
||||
}
|
||||
|
||||
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,309 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
CompletedView
|
||||
{
|
||||
id: completedView
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
manager: downloadManager
|
||||
}
|
||||
|
||||
ErrorView
|
||||
{
|
||||
id: errorView
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
manager: downloadManager
|
||||
}
|
||||
|
||||
function download()
|
||||
{
|
||||
downloadManager.downloadPack(uuid)
|
||||
}
|
||||
|
||||
Component.onCompleted: () => downloadManager.reset()
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
CompletedView
|
||||
{
|
||||
id: completedView
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
manager: downloadManager
|
||||
}
|
||||
|
||||
ErrorView
|
||||
{
|
||||
id: errorView
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0
|
||||
visible: opacity > 0.01
|
||||
manager: downloadManager
|
||||
}
|
||||
|
||||
function download()
|
||||
{
|
||||
downloadManager.downloadImage(author, authorUrl, downloadSelector.currentValue)
|
||||
}
|
||||
}
|
||||
@@ -18,5 +18,6 @@ qt6_add_qml_module(KomplexHubModule
|
||||
"WallpaperModelData.qml"
|
||||
)
|
||||
|
||||
set_target_properties(KomplexHubModule PROPERTIES VERSION "1.0")
|
||||
add_subdirectory("Controls")
|
||||
add_subdirectory("Kero")
|
||||
|
||||
@@ -63,7 +63,7 @@ QtObject {
|
||||
readonly property int normalAnimationDuration: 250
|
||||
readonly property int fastAnimationDuration: 125
|
||||
|
||||
property StudioApplication application: StudioApplication {
|
||||
fontPath: Qt.resolvedUrl("../KomplexHubContent/" + relativeFontDirectory)
|
||||
}
|
||||
// property StudioApplication application: StudioApplication {
|
||||
// fontPath: Qt.resolvedUrl("../KomplexHubContent/" + relativeFontDirectory)
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
|
||||
Item
|
||||
{
|
||||
property alias source: image.source
|
||||
property alias imageOpacity: effect.opacity
|
||||
property alias blur: effect.blur
|
||||
property alias saturation: effect.saturation
|
||||
|
||||
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.
|
||||
### Do not change
|
||||
|
||||
qt_add_library(KomplexHubModule_Controls STATIC)
|
||||
qt6_add_qml_module(KomplexHubModule_Controls
|
||||
qt_add_library(KomplexHubControls STATIC)
|
||||
qt6_add_qml_module(KomplexHubControls
|
||||
URI "KomplexHub.Controls"
|
||||
VERSION 1.0
|
||||
RESOURCE_PREFIX "/qt/qml"
|
||||
@@ -14,12 +14,12 @@ qt6_add_qml_module(KomplexHubModule_Controls
|
||||
"Throbber.qml"
|
||||
"SearchResultItem.qml"
|
||||
"SearchResultList.qml"
|
||||
QML_FILES PaginationBox.qml
|
||||
QML_FILES PaginatorGrid.qml
|
||||
QML_FILES HorizontalPaginator.qml
|
||||
QML_FILES ImageView.qml
|
||||
QML_FILES
|
||||
QML_FILES VideoView.qml
|
||||
QML_FILES PackView.qml
|
||||
"PaginationBox.qml"
|
||||
"PaginatorGrid.qml"
|
||||
"HorizontalPaginator.qml"
|
||||
"VerticalSpacer.qml"
|
||||
"ImageFrame.qml"
|
||||
"BackgroundImage.qml"
|
||||
)
|
||||
|
||||
#set_target_properties(KomplexHubControls PROPERTIES VERSION "1.0")
|
||||
|
||||
@@ -5,7 +5,7 @@ import QtQuick.Layouts
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
import KomplexHub.Plugin
|
||||
|
||||
Item
|
||||
{
|
||||
@@ -25,7 +25,10 @@ Item
|
||||
|
||||
property Component delegate
|
||||
|
||||
signal viewMoreTriggered()
|
||||
|
||||
id: rootItem
|
||||
clip: true
|
||||
|
||||
Item
|
||||
{
|
||||
@@ -45,8 +48,6 @@ Item
|
||||
height: 245
|
||||
color: palette.accent
|
||||
radius: 5
|
||||
// x: resultsView.currentItem.x
|
||||
// y: resultsView.currentItem.y
|
||||
Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||
Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||
}
|
||||
@@ -57,6 +58,7 @@ Item
|
||||
id: resultsView
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
|
||||
spacing: Constants.mediumMargin
|
||||
|
||||
@@ -132,7 +134,7 @@ Item
|
||||
Item
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 128
|
||||
Layout.preferredWidth: 64
|
||||
Rectangle
|
||||
{
|
||||
id: gradientMap
|
||||
@@ -162,6 +164,8 @@ Item
|
||||
icon.source: "qrc:/images/icons/icons8-forward.svg"
|
||||
icon.height: 24
|
||||
icon.width: 24
|
||||
|
||||
onTriggered: () => viewMoreTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item
|
||||
{
|
||||
property alias source: viewImage.source
|
||||
id: rootItem
|
||||
|
||||
Rectangle
|
||||
{
|
||||
anchors.fill: parent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
color: palette.base.darker()
|
||||
border.color: palette.midlight
|
||||
|
||||
Throbber
|
||||
{
|
||||
anchors.fill: parent
|
||||
id: loadingThrobber
|
||||
visible: viewImage.status === Image.Loading
|
||||
}
|
||||
|
||||
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,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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import QtQuick.Layouts
|
||||
import KomplexHub
|
||||
import KomplexHub.Controls
|
||||
import KomplexHub.Kero
|
||||
import KomplexHubPlugin
|
||||
import KomplexHub.Plugin
|
||||
|
||||
Item
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ Item {
|
||||
signal triggered
|
||||
signal viewMoreTriggered
|
||||
|
||||
id: mainItem
|
||||
id: rootItem
|
||||
width: 256
|
||||
height: 256
|
||||
clip: true
|
||||
@@ -48,7 +48,7 @@ Item {
|
||||
onReleased: () => {
|
||||
if(!states.selected)
|
||||
{
|
||||
mainItem.triggered()
|
||||
rootItem.triggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,47 +57,13 @@ Item {
|
||||
{
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle
|
||||
ImageFrame
|
||||
{
|
||||
Layout.preferredWidth: 250
|
||||
Layout.preferredHeight: 141
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||
Layout.topMargin: 3
|
||||
|
||||
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
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
source: rootItem.thumbnail
|
||||
|
||||
Image
|
||||
{
|
||||
@@ -108,18 +74,18 @@ Item {
|
||||
|
||||
width: 24
|
||||
height: 24
|
||||
transform: Image.PreserveAspectFit
|
||||
fillMode: Image.PreserveAspectFit
|
||||
opacity: 0.5
|
||||
source: "qrc:/images/icons/pexels-icon-filled-256.svg"
|
||||
|
||||
visible: mainItem.pexels
|
||||
visible: rootItem.pexels
|
||||
}
|
||||
}
|
||||
|
||||
Text
|
||||
{
|
||||
color: palette.text
|
||||
text: mainItem.title
|
||||
text: rootItem.title
|
||||
|
||||
font.pixelSize: 16
|
||||
font.bold: true
|
||||
@@ -131,25 +97,13 @@ Item {
|
||||
|
||||
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
|
||||
{
|
||||
id: descriptionText
|
||||
clip: true
|
||||
color: palette.text
|
||||
font.pixelSize: 12
|
||||
text: mainItem.description
|
||||
text: rootItem.description
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
textFormat: Text.PlainText
|
||||
elide: Text.ElideRight
|
||||
@@ -162,6 +116,19 @@ Item {
|
||||
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
|
||||
{
|
||||
id: viewMoreButton
|
||||
@@ -176,7 +143,7 @@ Item {
|
||||
opacity: 0
|
||||
|
||||
onTriggered: () => {
|
||||
mainItem.viewMoreTriggered()
|
||||
rootItem.viewMoreTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +156,7 @@ Item {
|
||||
id: states
|
||||
property bool clicked: false
|
||||
property bool hovered: false
|
||||
property alias selected: mainItem.selected
|
||||
property alias selected: rootItem.selected
|
||||
property bool idle: true
|
||||
|
||||
onIdleChanged: () =>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Rectangle
|
||||
{
|
||||
Layout.fillHeight: true
|
||||
|
||||
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,5 +1,5 @@
|
||||
qt_add_library(KomplexHubModule_Kero STATIC)
|
||||
qt6_add_qml_module(KomplexHubModule_Kero
|
||||
qt_add_library(KomplexHubKero STATIC)
|
||||
qt6_add_qml_module(KomplexHubKero
|
||||
URI "KomplexHub.Kero"
|
||||
VERSION 1.0
|
||||
RESOURCE_PREFIX "/qt/qml"
|
||||
@@ -11,4 +11,7 @@ qt6_add_qml_module(KomplexHubModule_Kero
|
||||
"KeroLoadingAnimation.qml"
|
||||
"KeroNoResultsAvatar.qml"
|
||||
"KeroWarningAvatar.qml"
|
||||
"KeroHeader.qml"
|
||||
"KeroSuccessAvatar.qml"
|
||||
)
|
||||
#set_target_properties(KomplexHubKero PROPERTIES VERSION "1.0")
|
||||
@@ -4,9 +4,9 @@ import QtQuick.Layouts
|
||||
import KomplexHub
|
||||
|
||||
Item {
|
||||
property string title: qsTr("Loading")
|
||||
property string description: qsTr("Kero is busy looking for wallpapers..we promise")
|
||||
property color color: palette.window
|
||||
property string title: qsTr("Building")
|
||||
property string description: qsTr("Kero is getting your wallpaper ready")
|
||||
property color color: "transparent"
|
||||
|
||||
id: keroLoadingOverlayRoot
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import KomplexHub
|
||||
Item {
|
||||
property string title: qsTr("Warning")
|
||||
property string description: qsTr("Kero noticed there might be an issue")
|
||||
property color color: palette.window
|
||||
property color color: "transparent"
|
||||
|
||||
id: keroWarningAvatarRoot
|
||||
|
||||
|
||||
@@ -1,66 +1,94 @@
|
||||
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(
|
||||
KomplexHubPlugin
|
||||
STATIC
|
||||
)
|
||||
|
||||
set_target_properties(KomplexHubPlugin PROPERTIES VERSION "1.0")
|
||||
|
||||
qt_add_qml_module(
|
||||
KomplexHubPlugin
|
||||
URI
|
||||
KomplexHubPlugin
|
||||
"KomplexHub.Plugin"
|
||||
VERSION
|
||||
1.0
|
||||
SOURCES
|
||||
settingsmanager.h
|
||||
settingsmanager.cpp
|
||||
installedpackmanager.h
|
||||
installedpackmanager.cpp
|
||||
common/wallpapercache.h
|
||||
newestpacksmodel.h
|
||||
newestpacksmodel.cpp
|
||||
common/komplex_global.h
|
||||
common/slidingcachecontroller.h
|
||||
common/paginator.h
|
||||
common/coreservices.h
|
||||
common/coreservices.cpp
|
||||
common/logging.h
|
||||
common/fetchresult.h
|
||||
paginators/newestpackspaginator.h
|
||||
paginators/featuredpackspaginator.h
|
||||
paginators/featuredimagespaginator.h
|
||||
paginators/wallpaperpaginator.h
|
||||
paginators/packsearchpaginator.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
|
||||
featuredpacksmodel.h
|
||||
featuredpacksmodel.cpp
|
||||
featuredimagesmodel.h
|
||||
featuredimagesmodel.cpp
|
||||
featuredvideosmodel.h
|
||||
featuredvideosmodel.cpp
|
||||
paginators/featuredvideospaginator.h
|
||||
common/imagecache.h
|
||||
paginators/imagepaginator.h
|
||||
common/videocache.h
|
||||
paginators/videopaginator.h
|
||||
imagesearchmodel.cpp
|
||||
imagesearchmodel.h
|
||||
videosearchmodel.h
|
||||
videosearchmodel.cpp
|
||||
packsearchmodel.cpp
|
||||
packsearchmodel.h
|
||||
videoitemmodel.h
|
||||
videoitemmodel.cpp
|
||||
downloadmanager.h downloadmanager.cpp
|
||||
common/exceptions.h
|
||||
common/shadertoymetadata.h
|
||||
common/shaderpack.h
|
||||
SOURCES packcompiler.h packcompiler.cpp
|
||||
settingsmanager.h
|
||||
settingsmanager.cpp
|
||||
installedpackmanager.h
|
||||
installedpackmanager.cpp
|
||||
common/wallpapercache.h
|
||||
newestpacksmodel.h
|
||||
newestpacksmodel.cpp
|
||||
common/komplex_global.h
|
||||
common/slidingcachecontroller.h
|
||||
common/coreservices.h
|
||||
common/coreservices.cpp
|
||||
common/logging.h
|
||||
common/fetchresult.h
|
||||
paginators/paginator.h
|
||||
paginators/newestpackspaginator.h
|
||||
paginators/featuredpackspaginator.h
|
||||
paginators/featuredimagespaginator.h
|
||||
paginators/wallpaperpaginator.h
|
||||
paginators/packsearchpaginator.h
|
||||
paginators/imagesearchpaginator.h
|
||||
paginators/videosearchpaginator.h
|
||||
featuredpacksmodel.h
|
||||
featuredpacksmodel.cpp
|
||||
featuredimagesmodel.h
|
||||
featuredimagesmodel.cpp
|
||||
featuredvideosmodel.h
|
||||
featuredvideosmodel.cpp
|
||||
paginators/featuredvideospaginator.h
|
||||
common/imagecache.h
|
||||
paginators/imagepaginator.h
|
||||
common/videocache.h
|
||||
paginators/videopaginator.h
|
||||
imagesearchmodel.cpp
|
||||
imagesearchmodel.h
|
||||
videosearchmodel.h
|
||||
videosearchmodel.cpp
|
||||
packsearchmodel.cpp
|
||||
packsearchmodel.h
|
||||
videoitemmodel.h
|
||||
videoitemmodel.cpp
|
||||
downloadmanager.h downloadmanager.cpp
|
||||
common/exceptions.h
|
||||
common/shadertoymetadata.h
|
||||
common/shaderpack.h
|
||||
packcompiler.h
|
||||
packcompiler.cpp
|
||||
common/userservices.h
|
||||
common/userservices.cpp
|
||||
common/qwallet.h
|
||||
common/qwallet.cpp
|
||||
usermodel.h
|
||||
usermodel.cpp
|
||||
SOURCES
|
||||
)
|
||||
|
||||
target_compile_definitions(
|
||||
@@ -69,9 +97,17 @@ target_compile_definitions(
|
||||
KOMPLEX_PLUGIN
|
||||
)
|
||||
|
||||
add_subdirectory(3rdparty/qtkeychain)
|
||||
|
||||
target_link_libraries(KomplexHubPlugin PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt6::Core
|
||||
Qt6::Concurrent
|
||||
Qt6::Gui
|
||||
Qt6::GuiPrivate
|
||||
Qt6::ShaderTools
|
||||
Qt6::ShaderToolsPrivate
|
||||
Vulkan::Vulkan
|
||||
qt6keychain
|
||||
)
|
||||
|
||||
if(ENABLE_ASAN)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "coreservices.h"
|
||||
#include "logging.h"
|
||||
#include "userservices.h"
|
||||
|
||||
QNetworkAccessManager *CoreServices::s_networkAccessManager = new QNetworkAccessManager();
|
||||
QNetworkAccessManager *CoreServices::s_networkAccessManager = nullptr;
|
||||
QMutex CoreServices::s_networkAccessMutex;
|
||||
QSharedPointer<QNetworkAccessManager> CoreServices::s_networkAccessPointer;
|
||||
|
||||
@@ -11,28 +12,31 @@ auto CoreServices::networkAccessManager() -> QWeakPointer<QNetworkAccessManager>
|
||||
|
||||
if(!s_networkAccessPointer)
|
||||
{
|
||||
s_networkAccessManager = new QNetworkAccessManager;
|
||||
s_networkAccessManager->setAutoDeleteReplies(true);
|
||||
if(!s_networkAccessManager)
|
||||
{
|
||||
s_networkAccessManager = new QNetworkAccessManager(QCoreApplication::instance());
|
||||
s_networkAccessManager->setAutoDeleteReplies(true);
|
||||
|
||||
QObject::connect(
|
||||
s_networkAccessManager,
|
||||
&QNetworkAccessManager::sslErrors,
|
||||
s_networkAccessManager,
|
||||
[] (QNetworkReply *reply, const QList<QSslError> &errors)
|
||||
{
|
||||
for(const auto &error : errors)
|
||||
QObject::connect(
|
||||
s_networkAccessManager,
|
||||
&QNetworkAccessManager::sslErrors,
|
||||
s_networkAccessManager,
|
||||
[] (QNetworkReply *reply, const QList<QSslError> &errors)
|
||||
{
|
||||
LOG_ERROR(
|
||||
"CoreServices::networkAccessManager",
|
||||
error.errorString().toStdString().c_str()
|
||||
);
|
||||
}
|
||||
for(const auto &error : errors)
|
||||
{
|
||||
LOG_ERROR(
|
||||
"CoreServices::networkAccessManager",
|
||||
error.errorString().toStdString().c_str()
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef KOMPLEX_LOCAL_DEV
|
||||
reply->ignoreSslErrors();
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#ifdef KOMPLEX_LOCAL_DEV
|
||||
reply->ignoreSslErrors();
|
||||
#endif
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
s_networkAccessPointer = QSharedPointer<QNetworkAccessManager>(
|
||||
s_networkAccessManager,
|
||||
@@ -45,11 +49,7 @@ auto CoreServices::networkAccessManager() -> QWeakPointer<QNetworkAccessManager>
|
||||
|
||||
auto CoreServices::sessionToken() -> QByteArray
|
||||
{
|
||||
LOG_ERROR_X(true,
|
||||
"CoreServices::sessionToken",
|
||||
"User services not yet implemented",
|
||||
{}
|
||||
);
|
||||
return UserServices::userCredentials().sessionToken;
|
||||
}
|
||||
|
||||
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
|
||||
#define EXCEPTIONS_H
|
||||
#include <QString>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#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)
|
||||
: std::exception(), message(message), errorCode(errorCode){}
|
||||
network_exception(const std::string &message, const std::string &details, const std::error_code &code) :
|
||||
details(details),
|
||||
std::ios_base::failure(message, code) { }
|
||||
|
||||
const QString message;
|
||||
const quint16 errorCode;
|
||||
network_exception(const std::string &message, const std::error_code &code) :
|
||||
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) {}
|
||||
};
|
||||
struct FileException : Exception
|
||||
{
|
||||
FileException(const QString &message, qsizetype errorCode = 0) : Exception(message, errorCode) {}
|
||||
};
|
||||
struct SqlException : Exception
|
||||
{
|
||||
SqlException(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),
|
||||
std::filesystem::filesystem_error(message, code) { }
|
||||
|
||||
file_exception(const std::string &message, const std::error_code &code) :
|
||||
std::filesystem::filesystem_error(message, code) { }
|
||||
|
||||
file_exception(const std::string &message, const int code = errno) :
|
||||
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 ShaderCompilerException : Exception
|
||||
struct KOMPLEX_EXPORT sql_exception : std::ios_base::failure
|
||||
{
|
||||
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
|
||||
|
||||
@@ -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
|
||||
#define IMAGECACHE_H
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#ifndef KOMPLEX_GLOBAL_H
|
||||
#define KOMPLEX_GLOBAL_H
|
||||
#include <QtTypes>
|
||||
#include <QString>
|
||||
#include <chrono>
|
||||
|
||||
#ifdef KOMPLEX_PLUGIN
|
||||
@@ -36,35 +37,41 @@
|
||||
#ifdef KOMPLEX_LOCAL_DEV
|
||||
#define KOMPLEX_API_HOST "https://komplexapi.hlab"
|
||||
#else
|
||||
#define KOMPLEX_API_HOST "https://api.komplex.dev"
|
||||
inline const QString KOMPLEX_API_HOST = QStringLiteral("https://api.komplex.dev");
|
||||
#endif
|
||||
|
||||
#define KOMPLEX_API_VERSION "v2"
|
||||
inline const QString KOMPLEX_API_VERSION = QStringLiteral("v2");
|
||||
|
||||
#define KOMPLEX_ENDPOINT_IMAGES_SEARCH "images/search"
|
||||
#define KOMPLEX_ENDPOINT_IMAGES_FEATURED "featured/images"
|
||||
#define KOMPLEX_ENDPOINT_IMAGES_ITEM "images/item"
|
||||
inline const QString KOMPLEX_ENDPOINT_IMAGES_SEARCH = QStringLiteral("images/search");
|
||||
inline const QString KOMPLEX_ENDPOINT_IMAGES_FEATURED = QStringLiteral("featured/images");
|
||||
inline const QString KOMPLEX_ENDPOINT_IMAGES_ITEM = QStringLiteral("images/item");
|
||||
|
||||
#define KOMPLEX_ENDPOINT_VIDEOS_SEARCH "videos/search"
|
||||
#define KOMPLEX_ENDPOINT_VIDEOS_FEATURED "featured/videos"
|
||||
#define KOMPLEX_ENDPOINT_VIDEOS_ITEM "videos/item"
|
||||
inline const QString KOMPLEX_ENDPOINT_VIDEOS_SEARCH = QStringLiteral("videos/search");
|
||||
inline const QString KOMPLEX_ENDPOINT_VIDEOS_FEATURED = QStringLiteral("featured/videos");
|
||||
inline const QString KOMPLEX_ENDPOINT_VIDEOS_ITEM = QStringLiteral("videos/item");
|
||||
|
||||
#define KOMPLEX_ENDPOINT_SHADERS_SEARCH "shaders/search"
|
||||
#define KOMPLEX_ENDPOINT_SHADERS_FEATURED "shaders/featured"
|
||||
#define KOMPLEX_ENDPOINT_SHADERS_ITEM "shaders/item"
|
||||
#define KOMPLEX_ENDPOINT_SHADERS_NEWEST "shaders/newest"
|
||||
inline const QString KOMPLEX_ENDPOINT_SHADERS_SEARCH = QStringLiteral("shaders/search");
|
||||
inline const QString KOMPLEX_ENDPOINT_SHADERS_FEATURED = QStringLiteral("shaders/featured");
|
||||
inline const QString KOMPLEX_ENDPOINT_SHADERS_ITEM = QStringLiteral("shaders/item");
|
||||
inline const QString KOMPLEX_ENDPOINT_SHADERS_NEWEST = QStringLiteral("shaders/newest");
|
||||
|
||||
#define KOMPLEX_ENDPOINT_CUBEMAPS_SEARCH "cubemaps/search"
|
||||
#define KOMPLEX_ENDPOINT_CUBEMAPS_FEATURED "cubemaps/featured"
|
||||
#define KOMPLEX_ENDPOINT_CUBEMAPS_ITEM "cubemaps/item"
|
||||
#define KOMPLEX_ENDPOINT_CUBEMAPS_NEWEST "cubemaps/newest"
|
||||
inline const QString KOMPLEX_ENDPOINT_CUBEMAPS_SEARCH = QStringLiteral("cubemaps/search");
|
||||
inline const QString KOMPLEX_ENDPOINT_CUBEMAPS_FEATURED = QStringLiteral("cubemaps/featured");
|
||||
inline const QString KOMPLEX_ENDPOINT_CUBEMAPS_ITEM = QStringLiteral("cubemaps/item");
|
||||
inline const QString KOMPLEX_ENDPOINT_CUBEMAPS_NEWEST = QStringLiteral("cubemaps/newest");
|
||||
|
||||
#define KOMPLEX_ENDPOINT_PACKS_SEARCH "packs/search"
|
||||
#define KOMPLEX_ENDPOINT_PACKS_FEATURED "packs/featured"
|
||||
#define KOMPLEX_ENDPOINT_PACKS_ITEM "packs/item"
|
||||
#define KOMPLEX_ENDPOINT_PACKS_NEWEST "packs/newest"
|
||||
inline const QString KOMPLEX_ENDPOINT_PACKS_SEARCH = QStringLiteral("packs/search");
|
||||
inline const QString KOMPLEX_ENDPOINT_PACKS_FEATURED = QStringLiteral("packs/featured");
|
||||
inline const QString KOMPLEX_ENDPOINT_PACKS_ITEM = QStringLiteral("packs/item");
|
||||
inline const QString KOMPLEX_ENDPOINT_PACKS_NEWEST = QStringLiteral("packs/newest");
|
||||
|
||||
inline static qsizetype nullsize = std::numeric_limits<qsizetype>::min();
|
||||
inline static std::chrono::milliseconds KOMPLEX_RATE_LIMIT(500);
|
||||
inline const QString KOMPLEX_ENDPOINT_USER_AUTH = QStringLiteral("user/auth");
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
#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
|
||||
#define SHADERTOYMETADATA_H
|
||||
#include <QObject>
|
||||
|
||||
@@ -337,7 +337,17 @@ private:
|
||||
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())
|
||||
{
|
||||
@@ -407,7 +417,7 @@ private:
|
||||
m_windowOffset = 0;
|
||||
}
|
||||
|
||||
QThread::sleep(KOMPLEX_RATE_LIMIT);
|
||||
// QThread::sleep(KOMPLEX_RATE_LIMIT);
|
||||
|
||||
FetchResult<T> result = m_fetch(
|
||||
m_windowOffset,
|
||||
@@ -490,7 +500,7 @@ private:
|
||||
false
|
||||
);
|
||||
|
||||
QThread::sleep(KOMPLEX_RATE_LIMIT);
|
||||
// QThread::sleep(KOMPLEX_RATE_LIMIT);
|
||||
|
||||
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
|
||||
#define VIDEOCACHE_H
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
#define DOWNLOADMANAGER_H
|
||||
|
||||
@@ -50,13 +68,13 @@ public:
|
||||
* out of it
|
||||
* @param url
|
||||
*/
|
||||
auto downloadImage
|
||||
Q_INVOKABLE auto downloadImage
|
||||
(
|
||||
const QString &author,
|
||||
const QString &authorId,
|
||||
const QString &description,
|
||||
const QUrl &url
|
||||
) noexcept(false) -> void;
|
||||
) -> void;
|
||||
|
||||
/**
|
||||
* @brief downloadVideo
|
||||
@@ -67,13 +85,12 @@ public:
|
||||
* @param description
|
||||
* @param url
|
||||
*/
|
||||
auto downloadVideo
|
||||
Q_INVOKABLE auto downloadVideo
|
||||
(
|
||||
const QString &author,
|
||||
const QString &authorId,
|
||||
const QString &description,
|
||||
const QUrl &url
|
||||
) noexcept(false) -> void;
|
||||
) -> void;
|
||||
|
||||
/**
|
||||
* @brief downloadPack
|
||||
@@ -82,13 +99,13 @@ public:
|
||||
* @param id
|
||||
* @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 errorTitle() const -> const QString & { return m_errorTitle; }
|
||||
auto errorMessage() const -> const QString & { return m_errorMessage; }
|
||||
auto state() const -> State { return m_state; }
|
||||
auto reset() -> void;
|
||||
Q_INVOKABLE auto reset() -> void;
|
||||
auto downloadProgress() -> qreal { return m_downloadProgress; }
|
||||
auto compileProgress() -> qreal;
|
||||
auto compileSteps() -> qint64;
|
||||
@@ -100,6 +117,9 @@ public:
|
||||
auto downloadedBytes() const -> qint64 { return m_downloadedBytes; }
|
||||
auto setDownloadedBytes(qint64 downloadedBytes) -> void;
|
||||
|
||||
auto lastInstalledFile() const -> const QString &;
|
||||
auto setLastInstalledFile(const QString &lastInstalledFile) -> void;
|
||||
|
||||
protected:
|
||||
auto setError(const QString &title, const QString &message) -> void;
|
||||
auto setCompilerOutput(const QString &compilerOutput) -> void;
|
||||
@@ -118,11 +138,16 @@ signals:
|
||||
auto compileStepsChanged() -> void;
|
||||
auto compileStepsCompletedChanged() -> void;
|
||||
|
||||
auto lastInstalledFileChanged() -> void;
|
||||
|
||||
private:
|
||||
auto compile(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 validateUri(const QUrl &uri) noexcept(false) -> void;
|
||||
|
||||
QString m_lastInstalledFile;
|
||||
|
||||
QString m_compilerOutput;
|
||||
QString m_errorTitle;
|
||||
@@ -135,9 +160,14 @@ private:
|
||||
State m_state;
|
||||
|
||||
QMutex m_downloadMutex;
|
||||
QMutex m_fileMutex;
|
||||
|
||||
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 errorTitle READ errorTitle 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 compileSteps READ compileSteps NOTIFY compileStepsChanged 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)
|
||||
|
||||
|
||||
@@ -5,49 +5,56 @@ FeaturedImagesModel::FeaturedImagesModel(QObject *parent) : QAbstractListModel{p
|
||||
m_paginator = new FeaturedImagesPaginator(this);
|
||||
PaginationNotifier *notifier = static_cast<PaginationNotifier*>(m_paginator);
|
||||
|
||||
QObject::connect(
|
||||
QObject::connect
|
||||
(
|
||||
notifier,
|
||||
&PaginationNotifier::resultsPerPageChanged,
|
||||
this,
|
||||
&FeaturedImagesModel::resultsPerPageChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
QObject::connect
|
||||
(
|
||||
notifier,
|
||||
&PaginationNotifier::totalResultsChanged,
|
||||
this,
|
||||
&FeaturedImagesModel::totalResultsChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
QObject::connect
|
||||
(
|
||||
notifier,
|
||||
&PaginationNotifier::totalPagesChanged,
|
||||
this,
|
||||
&FeaturedImagesModel::totalPagesChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
QObject::connect
|
||||
(
|
||||
notifier,
|
||||
&PaginationNotifier::pageChanged,
|
||||
this,
|
||||
&FeaturedImagesModel::pageChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
QObject::connect
|
||||
(
|
||||
notifier,
|
||||
&PaginationNotifier::pageChanged,
|
||||
this,
|
||||
&FeaturedImagesModel::resetDataModel
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
QObject::connect
|
||||
(
|
||||
notifier,
|
||||
&PaginationNotifier::fetchComplete,
|
||||
this,
|
||||
&FeaturedImagesModel::resetState
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
QObject::connect
|
||||
(
|
||||
notifier,
|
||||
&PaginationNotifier::fetching,
|
||||
this,
|
||||
@@ -172,13 +179,19 @@ auto FeaturedImagesModel::state() const -> FeaturedImagesModel::State
|
||||
|
||||
auto FeaturedImagesModel::setState(State state) -> void
|
||||
{
|
||||
if (m_state == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QFuture<void> aether = QtConcurrent::run
|
||||
(
|
||||
[this, state]
|
||||
{
|
||||
if (m_state == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
auto FeaturedImagesModel::resetState() -> void
|
||||
@@ -245,7 +258,6 @@ auto FeaturedImagesModel::resultsPerPage() const -> qsizetype
|
||||
|
||||
auto FeaturedImagesModel::setResultsPerPage(qsizetype resultsPerPage) -> void
|
||||
{
|
||||
|
||||
if(m_paginator != nullptr)
|
||||
{
|
||||
QFuture<void> future = QtConcurrent::run
|
||||
@@ -344,3 +356,23 @@ auto FeaturedImagesModel::totalPages() const -> qsizetype
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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:
|
||||
/**
|
||||
* @brief setErrorString
|
||||
@@ -248,7 +262,6 @@ signals:
|
||||
auto stateChanged() -> void;
|
||||
auto errorStringChanged() -> void;
|
||||
auto resultsPerPageChanged() -> void;
|
||||
|
||||
auto pageChanged() -> void;
|
||||
auto totalResultsChanged() -> void;
|
||||
auto totalPagesChanged() -> void;
|
||||
@@ -344,6 +357,8 @@ private:
|
||||
Q_PROPERTY(qsizetype resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
|
||||
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged 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_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
|
||||
{
|
||||
if(m_paginator != nullptr)
|
||||
|
||||
@@ -208,6 +208,20 @@ public:
|
||||
*/
|
||||
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:
|
||||
/**
|
||||
* @brief setErrorString
|
||||
@@ -310,6 +324,8 @@ private:
|
||||
Q_PROPERTY(qsizetype resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
|
||||
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged 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_DECLARE_METATYPE(FeaturedPacksModel)
|
||||
|
||||
@@ -160,13 +160,19 @@ auto FeaturedVideosModel::state() const -> FeaturedVideosModel::State
|
||||
|
||||
auto FeaturedVideosModel::setState(State state) -> void
|
||||
{
|
||||
if (m_state == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QFuture<void> aether = QtConcurrent::run
|
||||
(
|
||||
[this, state]
|
||||
{
|
||||
if (m_state == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
auto FeaturedVideosModel::resetState() -> void
|
||||
@@ -205,6 +211,24 @@ auto FeaturedVideosModel::itemModel() const -> VideoItemModel*
|
||||
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>
|
||||
{
|
||||
return m_dataRoles;
|
||||
@@ -347,3 +371,23 @@ auto FeaturedVideosModel::totalPages() const -> qsizetype
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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:
|
||||
/**
|
||||
* @brief setErrorString
|
||||
@@ -243,7 +271,7 @@ signals:
|
||||
auto stateChanged() -> void;
|
||||
auto errorStringChanged() -> void;
|
||||
auto resultsPerPageChanged() -> void;
|
||||
|
||||
auto windowSizeChanged() -> void;
|
||||
auto pageChanged() -> void;
|
||||
auto totalResultsChanged() -> void;
|
||||
auto totalPagesChanged() -> void;
|
||||
@@ -313,7 +341,10 @@ private:
|
||||
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
||||
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged 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(qsizetype windowSize READ windowSize WRITE setWindowSize NOTIFY windowSizeChanged FINAL)
|
||||
};
|
||||
Q_DECLARE_METATYPE(FeaturedVideosModel)
|
||||
|
||||
|
||||
@@ -159,13 +159,19 @@ auto NewestPacksModel::state() const -> NewestPacksModel::State
|
||||
|
||||
auto NewestPacksModel::setState(State state) -> void
|
||||
{
|
||||
if (m_state == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QFuture<void> aether = QtConcurrent::run
|
||||
(
|
||||
[this, state]
|
||||
{
|
||||
if (m_state == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
auto NewestPacksModel::resetState() -> void
|
||||
@@ -224,7 +230,7 @@ auto NewestPacksModel::setResultsPerPage(qsizetype resultsPerPage) -> void
|
||||
{
|
||||
if(m_paginator != nullptr)
|
||||
{
|
||||
QFuture<void> future = QtConcurrent::run
|
||||
QFuture<void> aether = QtConcurrent::run
|
||||
(
|
||||
[this, resultsPerPage]
|
||||
{
|
||||
@@ -277,7 +283,7 @@ auto NewestPacksModel::nextPage() const -> void
|
||||
{
|
||||
if(m_paginator != nullptr)
|
||||
{
|
||||
QFuture<void> future = QtConcurrent::run
|
||||
QFuture<void> aether = QtConcurrent::run
|
||||
(
|
||||
[this]
|
||||
{
|
||||
@@ -291,7 +297,7 @@ auto NewestPacksModel::previousPage() const -> void
|
||||
{
|
||||
if(m_paginator != nullptr)
|
||||
{
|
||||
QFuture<void> future = QtConcurrent::run
|
||||
QFuture<void> aether = QtConcurrent::run
|
||||
(
|
||||
[this]
|
||||
{
|
||||
@@ -320,3 +326,24 @@ auto NewestPacksModel::totalPages() const -> qsizetype
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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:
|
||||
/**
|
||||
* @brief setErrorString
|
||||
@@ -321,6 +335,8 @@ private:
|
||||
Q_PROPERTY(qsizetype totalResults READ totalResults NOTIFY totalResultsChanged FINAL)
|
||||
Q_PROPERTY(qsizetype totalPages READ totalPages NOTIFY totalPagesChanged 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)
|
||||
|
||||
|
||||
+416
-726
File diff suppressed because it is too large
Load Diff
+257
-113
@@ -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
|
||||
#define PACKCOMPILER_H
|
||||
|
||||
@@ -18,6 +36,8 @@
|
||||
#include <qobject.h>
|
||||
#include <qtmetamacros.h>
|
||||
#include <QPainter>
|
||||
#include <QtShaderTools>
|
||||
#include <QtShaderTools/rhi/qshaderbaker.h>
|
||||
#include <QtConcurrent/qtconcurrentrun.h>
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qmargins.h>
|
||||
@@ -25,21 +45,42 @@
|
||||
#include <qtmetamacros.h>
|
||||
#include <qurl.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;
|
||||
QPromise<QUrl> promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The PackCompiler class
|
||||
* [1] Extract Pack (GZip)
|
||||
* [2] Verify directory is a pack and has shaders
|
||||
* [3] Load shader code
|
||||
* [4] Append Common and Global files, if they exist
|
||||
* [5] Add uniform and replace variable use
|
||||
* [6] Run C Preprocessor (cpp -P) to process macros
|
||||
* [7] Append version macro
|
||||
* [8] Compile with Qt Shader Baker
|
||||
* [3] Load Common shader code
|
||||
* [4] Walk the shader directory
|
||||
* [5] Load shader code
|
||||
* [6] Append type specific common code and global code
|
||||
* [7] Replace uniform variable use
|
||||
* [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
|
||||
QML_ELEMENT
|
||||
public:
|
||||
|
||||
enum State
|
||||
@@ -52,7 +93,6 @@ public:
|
||||
Q_ENUM(State)
|
||||
|
||||
explicit PackCompiler(QObject *parent = nullptr);
|
||||
~PackCompiler() override;
|
||||
|
||||
auto compilerOutput() const -> const QString & { return m_compilerOutput; }
|
||||
auto progress() -> qreal { return m_progress; }
|
||||
@@ -60,62 +100,11 @@ public:
|
||||
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>;
|
||||
|
||||
auto status() const -> const QString & { return m_status; }
|
||||
auto state() const -> State { return m_state; }
|
||||
auto reset() -> void;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief prepareShaders
|
||||
* Scans the pack's shader directory and sends each file to
|
||||
* prepareFile()
|
||||
* @param uri
|
||||
* Directory to prepare
|
||||
*/
|
||||
auto prepareShaders(const QUrl &uri) noexcept(false) -> void;
|
||||
|
||||
/**
|
||||
* @brief prepareFile
|
||||
* Prepares the individual file by appending the header, footer,
|
||||
* common files and replacing standard variable names
|
||||
* @param uri
|
||||
*/
|
||||
auto prepareFile(const QUrl &uri) noexcept(false) -> void;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
auto build(const QUrl &uri) -> QUrl;
|
||||
|
||||
signals:
|
||||
auto compilerOutputChanged() -> void;
|
||||
@@ -126,38 +115,213 @@ signals:
|
||||
auto progressChanged() -> void;
|
||||
auto currentStepChanged() -> void;
|
||||
auto totalStepsChanged() -> void;
|
||||
|
||||
auto compileComplete(const QUrl &uri) -> void;
|
||||
|
||||
auto statusChanged() -> void;
|
||||
auto packReady(const QString &) -> void;
|
||||
auto errorStepChanged() -> void;
|
||||
auto errorRatingChanged() -> void;
|
||||
|
||||
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]
|
||||
auto save(const QUrl &uri, const QShader &shader) noexcept(false) -> void;
|
||||
|
||||
//helpers
|
||||
auto validateUri(const QUrl &uri) const noexcept(false) -> void;
|
||||
auto run(const QString &command, const QStringList &arguments, const QByteArray &data = {}) noexcept(false) -> QByteArray;
|
||||
auto readFile(const QUrl &uri) noexcept(false) -> QByteArray;
|
||||
auto writeFile(const QUrl &uri, const QByteArray &data) noexcept(false) -> void;
|
||||
auto copyFile(const QUrl &sourceUri, const QUrl &destinationUri) noexcept(false) -> void;
|
||||
auto createDirectory(const QUrl &uri) noexcept(false) -> void;
|
||||
auto removeDirectory(const QUrl &uri) noexcept(false) -> void;
|
||||
auto getStageFromSuffix(const QString &suffix) const -> QShader::Stage;
|
||||
|
||||
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;
|
||||
|
||||
#ifdef HAS_VULKAN
|
||||
auto vulkanVersion() const -> qint32;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_OPENGL
|
||||
auto openGlVersion() const -> qint32;
|
||||
#endif
|
||||
|
||||
//members
|
||||
static inline const QStringList m_updateVariables
|
||||
{
|
||||
QStringLiteral("iTime"),
|
||||
QStringLiteral("iTimeDelta"),
|
||||
QStringLiteral("iFrameRate"),
|
||||
QStringLiteral("iSampleRate"),
|
||||
QStringLiteral("iFrame"),
|
||||
QStringLiteral("iDate"),
|
||||
QStringLiteral("iMouse"),
|
||||
QStringLiteral("iResolution"),
|
||||
QStringLiteral("iColorTheme"),
|
||||
QStringLiteral("iChannelTime"),
|
||||
QStringLiteral("iChannelResolution")
|
||||
};
|
||||
|
||||
static inline const QStringList m_shaderNameFilters
|
||||
{
|
||||
QStringLiteral("*.frag"),
|
||||
QStringLiteral("*.vert"),
|
||||
QStringLiteral("*.tese"),
|
||||
QStringLiteral("*.tesc"),
|
||||
QStringLiteral("*.geom"),
|
||||
QStringLiteral("*.comp"),
|
||||
QStringLiteral("*.glsl")
|
||||
};
|
||||
|
||||
static inline const QMap<QString, QShader::Stage> m_shaderStages
|
||||
{
|
||||
{
|
||||
QStringLiteral("iTime"),
|
||||
QStringLiteral("iTimeDelta"),
|
||||
QStringLiteral("iFrameRate"),
|
||||
QStringLiteral("iSampleRate"),
|
||||
QStringLiteral("iFrame"),
|
||||
QStringLiteral("iDate"),
|
||||
QStringLiteral("iMouse"),
|
||||
QStringLiteral("iResolution"),
|
||||
QStringLiteral("iColorTheme"),
|
||||
QStringLiteral("iChannelTime"),
|
||||
QStringLiteral("iChannelResolution")
|
||||
};
|
||||
QStringLiteral("frag"),
|
||||
QShader::FragmentStage
|
||||
},
|
||||
{
|
||||
QStringLiteral("vert"),
|
||||
QShader::VertexStage
|
||||
},
|
||||
{
|
||||
QStringLiteral("tese"),
|
||||
QShader::TessellationEvaluationStage
|
||||
},
|
||||
{
|
||||
QStringLiteral("tesc"),
|
||||
QShader::TessellationControlStage
|
||||
},
|
||||
{
|
||||
QStringLiteral("geom"),
|
||||
QShader::GeometryStage
|
||||
},
|
||||
{
|
||||
QStringLiteral("comp"),
|
||||
QShader::ComputeStage
|
||||
}
|
||||
};
|
||||
|
||||
static inline const QByteArray m_version
|
||||
{
|
||||
R"(#version 450)"
|
||||
};
|
||||
{
|
||||
R"(#version 450)"
|
||||
};
|
||||
|
||||
static inline const QString m_header
|
||||
{
|
||||
R"(layout(location = 0) in vec2 qt_TexCoord0;
|
||||
static inline const QByteArray m_header
|
||||
{
|
||||
R"(layout(location = 0) in vec2 qt_TexCoord0;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
@@ -182,16 +346,20 @@ layout(binding = 3) uniform sampler2D iChannel2;
|
||||
layout(binding = 4) uniform sampler2D iChannel3;
|
||||
|
||||
vec2 fragCoord = vec2(qt_TexCoord0.x, 1.0 - qt_TexCoord0.y) * ubuf.iResolution.xy;)"
|
||||
};
|
||||
};
|
||||
|
||||
static inline const QString m_footer
|
||||
{
|
||||
R"(void main() {
|
||||
static inline const QByteArray m_footer
|
||||
{
|
||||
R"(
|
||||
void main() {
|
||||
vec4 color = vec4(0.0);
|
||||
mainImage(color, fragCoord);
|
||||
fragColor = color;
|
||||
})"
|
||||
};
|
||||
};
|
||||
|
||||
QMap<QByteArray, QByteArray> m_commonData;
|
||||
QMap<QByteArray, QShaderBaker> m_shaders;
|
||||
|
||||
QString m_compilerOutput;
|
||||
QString m_errorMessage;
|
||||
@@ -206,34 +374,10 @@ vec2 fragCoord = vec2(qt_TexCoord0.x, 1.0 - qt_TexCoord0.y) * ubuf.iResolution.x
|
||||
|
||||
QMutex m_downloadMutex;
|
||||
|
||||
QFuture<QUrl> m_buildFuture;
|
||||
|
||||
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)
|
||||
|
||||
@@ -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 FEATUREDCUBEMAPSPAGINATOR_H
|
||||
#define FEATUREDCUBEMAPSPAGINATOR_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 FeaturedCubemapsPaginator : public WallpaperPaginator
|
||||
{
|
||||
public:
|
||||
explicit FeaturedCubemapsPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_CUBEMAPS_FEATURED)
|
||||
);
|
||||
|
||||
controller()->setWindowSize(20);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // FEATUREDCUBEMAPSPAGINATOR_H
|
||||
@@ -36,11 +36,8 @@ class KOMPLEX_EXPORT FeaturedImagesPaginator : public ImagePaginator
|
||||
public:
|
||||
explicit FeaturedImagesPaginator(QObject *parent = nullptr) : ImagePaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_IMAGES_FEATURED)
|
||||
);
|
||||
|
||||
controller()->setWindowSize(20);
|
||||
setUri(KOMPLEX_ENDPOINT_IMAGES_FEATURED);
|
||||
controller()->setWindowSize(32);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -36,10 +36,7 @@ class KOMPLEX_EXPORT FeaturedPacksPaginator : public WallpaperPaginator
|
||||
public:
|
||||
explicit FeaturedPacksPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_PACKS_FEATURED)
|
||||
);
|
||||
|
||||
setUri(KOMPLEX_ENDPOINT_PACKS_FEATURED);
|
||||
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:
|
||||
explicit FeaturedVideosPaginator(QObject *parent = nullptr) : VideoPaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_VIDEOS_FEATURED)
|
||||
);
|
||||
|
||||
controller()->setWindowSize(20);
|
||||
setUri(KOMPLEX_ENDPOINT_VIDEOS_FEATURED);
|
||||
controller()->setWindowSize(32);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/paginator.h"
|
||||
#include "common/imagecache.h"
|
||||
#include "common/coreservices.h"
|
||||
#include "paginator.h"
|
||||
|
||||
/**
|
||||
* @brief The ImagePaginator class
|
||||
|
||||
@@ -38,10 +38,7 @@ class KOMPLEX_EXPORT ImageSearchPaginator : public ImagePaginator
|
||||
public:
|
||||
explicit ImageSearchPaginator(QObject *parent = nullptr) : ImagePaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_IMAGES_SEARCH)
|
||||
);
|
||||
|
||||
setUri(KOMPLEX_ENDPOINT_IMAGES_SEARCH);
|
||||
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:
|
||||
explicit NewestPacksPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_PACKS_NEWEST)
|
||||
);
|
||||
|
||||
setUri(KOMPLEX_ENDPOINT_PACKS_NEWEST);
|
||||
controller()->setWindowSize(20);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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 NEWESTSHADERSPAGINATOR_H
|
||||
#define NEWESTSHADERSPAGINATOR_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 NewestShadersPaginator : public WallpaperPaginator
|
||||
{
|
||||
public:
|
||||
explicit NewestShadersPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_SHADERS_NEWEST)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // NEWESTSHADERSPAGINATOR_H
|
||||
@@ -36,10 +36,7 @@ class KOMPLEX_EXPORT PackSearchPaginator : public WallpaperPaginator
|
||||
public:
|
||||
explicit PackSearchPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_PACKS_SEARCH)
|
||||
);
|
||||
|
||||
setUri(KOMPLEX_ENDPOINT_PACKS_SEARCH);
|
||||
setQueryable(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonParseError>
|
||||
|
||||
#include "komplex_global.h"
|
||||
#include "slidingcachecontroller.h"
|
||||
#include "common/komplex_global.h"
|
||||
#include "common/slidingcachecontroller.h"
|
||||
|
||||
/**
|
||||
* @brief The PaginationNotifier class
|
||||
@@ -120,6 +120,7 @@ public:
|
||||
* @brief resultsPerPage
|
||||
* @return
|
||||
*/
|
||||
[[nodiscard]]
|
||||
auto resultsPerPage() const -> qsizetype
|
||||
{
|
||||
return m_resultsPerPage;
|
||||
@@ -204,6 +205,7 @@ public:
|
||||
* @brief data
|
||||
* @return
|
||||
*/
|
||||
[[nodiscard]]
|
||||
auto data() const -> const QList<T>
|
||||
{
|
||||
if(boundaryCheck(m_resultsPerPage))
|
||||
@@ -219,6 +221,7 @@ public:
|
||||
* @brief count
|
||||
* @return
|
||||
*/
|
||||
[[nodiscard]]
|
||||
auto count() const -> qsizetype
|
||||
{
|
||||
if(m_offset == nullsize)
|
||||
@@ -240,6 +243,7 @@ public:
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
[[nodiscard]]
|
||||
auto at(qsizetype index) const -> const T&
|
||||
{
|
||||
return m_cacheController.at(m_offset + index);
|
||||
@@ -251,6 +255,7 @@ public:
|
||||
* The total number of results as reported by the controller
|
||||
* @return
|
||||
*/
|
||||
[[nodiscard]]
|
||||
auto totalResults() const -> qsizetype
|
||||
{
|
||||
return m_cacheController.totalCount();
|
||||
@@ -261,6 +266,7 @@ public:
|
||||
* Calculates the current page
|
||||
* @return
|
||||
*/
|
||||
[[nodiscard]]
|
||||
auto page() const -> qsizetype
|
||||
{
|
||||
return std::floor(
|
||||
@@ -273,6 +279,7 @@ public:
|
||||
* Calculates the total number of pages available
|
||||
* @return
|
||||
*/
|
||||
[[nodiscard]]
|
||||
auto totalPages() const -> qsizetype
|
||||
{
|
||||
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
|
||||
{
|
||||
return m_queryable;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
auto setQueryable(bool queryable) -> void
|
||||
{
|
||||
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
|
||||
@@ -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 SEARCHSHADERSPAGINATOR_H
|
||||
#define SEARCHSHADERSPAGINATOR_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 SearchShadersPaginator : public WallpaperPaginator
|
||||
{
|
||||
public:
|
||||
explicit SearchShadersPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_SHADERS_SEARCH)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SEARCHSHADERSPAGINATOR_H
|
||||
@@ -30,9 +30,9 @@
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/paginator.h"
|
||||
#include "common/videocache.h"
|
||||
#include "common/coreservices.h"
|
||||
#include "paginator.h"
|
||||
|
||||
/**
|
||||
* @brief The VideoPaginator class
|
||||
@@ -245,6 +245,8 @@ protected:
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
manager.clear();
|
||||
|
||||
LOG_ERROR_X(reply->error() != QNetworkReply::NoError,
|
||||
"NewestPacksPaginator::getNetworkReply",
|
||||
reply->errorString().toStdString().c_str(),
|
||||
|
||||
@@ -36,10 +36,7 @@ class KOMPLEX_EXPORT VideoSearchPaginator : public VideoPaginator
|
||||
public:
|
||||
explicit VideoSearchPaginator(QObject *parent = nullptr) : VideoPaginator(parent)
|
||||
{
|
||||
setUri(
|
||||
QString::fromUtf8(KOMPLEX_ENDPOINT_VIDEOS_SEARCH)
|
||||
);
|
||||
|
||||
setUri(KOMPLEX_ENDPOINT_VIDEOS_SEARCH);
|
||||
setQueryable(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/paginator.h"
|
||||
#include "common/wallpapercache.h"
|
||||
#include "common/coreservices.h"
|
||||
#include "paginator.h"
|
||||
|
||||
/**
|
||||
* @brief The WallpaperPaginator class
|
||||
@@ -248,6 +248,8 @@ protected:
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
manager.clear();
|
||||
|
||||
LOG_ERROR_X(reply->error() != QNetworkReply::NoError,
|
||||
"NewestPacksPaginator::getNetworkReply",
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef USERMODEL_H
|
||||
#define USERMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <qqmlintegration.h>
|
||||
#include "common/userservices.h"
|
||||
|
||||
class UserModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
|
||||
enum State
|
||||
{
|
||||
Idle,
|
||||
LoggingIn,
|
||||
LoggedIn,
|
||||
LoginFailure,
|
||||
LoginCancelled,
|
||||
LoggedOut,
|
||||
Busy
|
||||
};
|
||||
Q_ENUM(State)
|
||||
|
||||
explicit UserModel(QObject *parent = nullptr);
|
||||
~UserModel();
|
||||
|
||||
Q_INVOKABLE auto login() -> void;
|
||||
Q_INVOKABLE auto login(const QString username) -> void;
|
||||
Q_INVOKABLE auto cancelLogin() -> void;
|
||||
Q_INVOKABLE auto reset() -> void;
|
||||
|
||||
auto username() const -> const QString & { return m_username; }
|
||||
auto setUsername(const QString &username) -> void;
|
||||
|
||||
auto password() const -> const QString & { return m_password; }
|
||||
auto setPassword(const QString &password) -> void;
|
||||
|
||||
auto state() const -> State { return m_state; }
|
||||
auto errorString() const -> QString { return m_errorString; }
|
||||
|
||||
signals:
|
||||
auto loginSuccessful() -> void;
|
||||
auto loginFailed() -> void;
|
||||
auto stateChanged() -> void;
|
||||
auto usernameChanged() -> void;
|
||||
auto passwordChanged() -> void;
|
||||
auto errorStringChanged() -> void;
|
||||
|
||||
protected slots:
|
||||
auto resetState() -> void;
|
||||
|
||||
private:
|
||||
auto setState(State state) -> void;
|
||||
auto setErrorString(const QString &string) -> void;
|
||||
|
||||
State m_state = Idle;
|
||||
QString m_errorString;
|
||||
QString m_username;
|
||||
QString m_password;
|
||||
QTimer *m_stateResetTimer = nullptr;
|
||||
QMutex m_loginMutex;
|
||||
QFuture<UserCredentials> m_loginAttempt;
|
||||
|
||||
Q_PROPERTY(State state READ state NOTIFY stateChanged FINAL)
|
||||
Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged FINAL)
|
||||
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL)
|
||||
Q_PROPERTY(QString errorString READ errorString WRITE setErrorString NOTIFY errorStringChanged FINAL)
|
||||
};
|
||||
|
||||
#endif // USERMODEL_H
|
||||
+15
-29
@@ -2,7 +2,8 @@
|
||||
|
||||
| Applies To | Effective Date | Revision Date |
|
||||
| ------ | --- | --- |
|
||||
| Internal & Contributors | August 12, 2026 | August 12, 2026
|
||||
| Internal & Contributors | August 12, 2026 | August 12, 2026 |
|
||||
|
||||
This policy may be updated in the future. The updated date will be reflected on this file.
|
||||
|
||||
## Applies to
|
||||
@@ -33,6 +34,12 @@ AI tools may not be used for:
|
||||
- Produce a complete file replacement, complete module, or end-to-end implementation of a feature.
|
||||
- Generate bug report details or where the bug report content would be primarily AI-authored.
|
||||
|
||||
### “Agentic” Automation
|
||||
You may not use AI tools that can take actions on your behalf without intentional invocation. For example browsing, running commands, editing files and repositories, or opening pull requests automatically.
|
||||
|
||||
### Misrepresentation and undisclosed material contribution
|
||||
Misrepresentation of AI-assisted work as human-authored where disclosure is required by this policy is subject to enforcement policies.
|
||||
|
||||
## Acceptable uses of AI
|
||||
AI tools may be used to:
|
||||
- Assist with writing or refactoring code, provided the resulting code changes are implemented, reviewed and verified by a human contributor.
|
||||
@@ -50,48 +57,27 @@ For reporting AI may be used only to:
|
||||
- Reformat or rewrite for clarity while preserving the original factual content
|
||||
- Help translate the human-authored report into a different structure, language, or style
|
||||
|
||||
### Misrepresentation and undisclosed material contribution
|
||||
Misrepresentation of AI-assisted work as purely human-authored where disclosure is required by this policy is subject to enforcement policies.
|
||||
|
||||
### “Agentic” Automation
|
||||
You may not use AI tools that can take actions on your behalf without intentional invocation. For example browsing, running commands, editing files and repositories, or opening pull requests automatically.
|
||||
|
||||
## Allowed AI uses (how to apply the restrictions)
|
||||
|
||||
### Implementation
|
||||
Allowable AI usage still requires human authorship, review and verification.
|
||||
|
||||
- You must implement changes yourself.
|
||||
- You must verify changes via tests, linting/type checks, and/or manual validation consistent with project standards.
|
||||
- Do not copy/paste AI-generated patches as the final solution.
|
||||
|
||||
### Media placeholders (allowed)
|
||||
### Media placeholders
|
||||
AI-generated images/icons may be used only as placeholders with the intention to replace them.
|
||||
|
||||
Placeholder rules:
|
||||
- Placeholder files must be clearly marked in an AI_ASSETS file.
|
||||
- Placeholder files must be clearly marked in the AI_ASSETS file.
|
||||
- Placeholders should be replaced when possible, but may require artist contribution and may not always be immediately feasible.
|
||||
|
||||
### Qt Translation Files
|
||||
AI may be used to generate translation files.
|
||||
- AI may be used to generate translation files.
|
||||
- AI generated translation files must be noted in AI_ASSETS
|
||||
|
||||
## Transparency and disclosure
|
||||
When AI materially contributes to work, you must disclose it in one of:
|
||||
|
||||
- The pull request description
|
||||
- Commit messages
|
||||
- A related comment on the pull request
|
||||
|
||||
Disclosure must cover:
|
||||
|
||||
When disclosing the use of AI generated assets, you must disclose:
|
||||
- The file name and path relative to the project root
|
||||
- Which allowed category was used (e.g., translation file generation, bug report translation, placeholder media)
|
||||
- What tool/version was used for generation
|
||||
|
||||
## Review and verification requirements
|
||||
For changes that include AI-assisted suggestions:
|
||||
- Run the project’s standard checks (tests, linting, formatting, and/or type checks).
|
||||
- Ensure reviewers can understand the human rationale for changes.
|
||||
- Ensure the final code and translations meet project quality standards.
|
||||
- Optionally can include a short message about the asset
|
||||
|
||||
## Enforcement
|
||||
Failure to comply with this policy may result in:
|
||||
|
||||
@@ -34,7 +34,10 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Most of the development of Komplex and it's associated apps will now happen here, instead of Github.
|
||||
<small>Note: Application style is based on your system theme. It will look different than it does in the screenshots. I am using a modified KVantum Glass, Blur and Neon Sunset Wallpaper Pack.</small>
|
||||
|
||||
## Development
|
||||
Most of the development of Komplex and applications under its project umbrella will now happen on https://git.digitalartifex.dev instead of Github.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -51,10 +54,11 @@ Most of the development of Komplex and it's associated apps will now happen here
|
||||
- Qt6 Shader Tools
|
||||
- CMake
|
||||
- clang
|
||||
- C Pre Processor (cpp)
|
||||
|
||||
#### Build
|
||||
```console
|
||||
$ git clone gitea@git.digitalartifex.dev:digitalartifex/komplex-hub.git
|
||||
$ git clone --recursive gitea@git.digitalartifex.dev:digitalartifex/komplex-hub.git
|
||||
$ mkdir build
|
||||
$ cmake -S ./ -B ./build/
|
||||
$ cmake --build ./build
|
||||
@@ -74,4 +78,110 @@ Content purchases will be processed through the website using Paypal as will art
|
||||
|
||||
## Status
|
||||
|
||||
This app is currently under development and is pre-alpha. The API is now being hosted on https://komplex.dev. However, there is no download functionality as of yet. BETA should be here within a few weeks.
|
||||
### Legend
|
||||
|
||||
| Status | Icon | Description |
|
||||
|-------|:-------:|--------|
|
||||
| Not started | ❌ | Either no work has been done yet or so little work that it is unusable in its current state.
|
||||
| In Progress | ✔ | *Some* work has been completed, but is not yet functional and/or feature complete
|
||||
| Complete | ✅ | Planned features completed
|
||||
|
||||
### API Status
|
||||
|
||||
| Feature | Status |
|
||||
|-------|:-------:|
|
||||
| Packs | ✔ | |
|
||||
| - Download Packs | ✅ | |
|
||||
| - Newest Packs | ✅ | |
|
||||
| - Featured Packs | ✔ | |
|
||||
| - Search Packs | ✅ | |
|
||||
| - Submit Packs | ✔ | |
|
||||
| - Thumbnails | ✅ | |
|
||||
| | | |
|
||||
| Cubemaps | ✔ | |
|
||||
| - Download Cubemaps | ✅ | |
|
||||
| - Newest Cubemaps | ✅ | |
|
||||
| - Featured Cubemaps | ✔ | |
|
||||
| - Search Cubemaps | ✅ | |
|
||||
| - Submit Cubemaps | ✔ | - |
|
||||
| | | |
|
||||
| Filter Shaders | ✔ | |
|
||||
| - Download Filter Shaders | ✅ | |
|
||||
| - Newest Filter Shaders | ✅ | |
|
||||
| - Featured Filter Shaders | ✔ | |
|
||||
| - Search Filter Shaders | ✅ | |
|
||||
| - Submit Filter Shaders | ✔ | - |
|
||||
| | | |
|
||||
| Images | ✅ | |
|
||||
| - Featured Images | ✅ | |
|
||||
| - Search Images | ✅ | |
|
||||
| | | |
|
||||
| Videos | ✅ | |
|
||||
| - Popular Videos | ✅ | |
|
||||
| - Search Videos | ✅ | |
|
||||
| | | |
|
||||
| Accounts | ✔ | |
|
||||
| - User Accounts | ✔ | |
|
||||
| - User Authentication | ✔ | |
|
||||
| - User Editing | ❌ | |
|
||||
| - User Configuration | ❌ | |
|
||||
| - User Media | ❌ | |
|
||||
| - Author Profiles | ❌ | |
|
||||
|
||||
### Media Hub Status
|
||||
|
||||
| Feature | Status |
|
||||
|-------|:-------:|
|
||||
| Spotlight/Homepage | ✔ | |
|
||||
| - Newest Packs | ✅ | |
|
||||
| - Featured Packs | ✔ | |
|
||||
| - Featured Images | ✅ | |
|
||||
| - Popular Videos | ✅ | |
|
||||
| - View More | ✅ | |
|
||||
| | | |
|
||||
| Media Search | ✅ | |
|
||||
| - Packs | ✅ | |
|
||||
| - Videos | ✅ | |
|
||||
| - Images | ✅ | |
|
||||
| | | |
|
||||
| Media Downloader | ✅ | |
|
||||
| - Packs | ✅ | |
|
||||
| - Videos | ✅ | |
|
||||
| - Images | ✅ | |
|
||||
| | | |
|
||||
| Detailed Views | ✅ | |
|
||||
| - Packs | ✅ | |
|
||||
| - Videos | ✅ | |
|
||||
| - Images | ✅ | |
|
||||
| | | |
|
||||
| App Management | ✔ | |
|
||||
| Installed Media Manager | ✔ | |
|
||||
| Settings Manager | ✅ | |
|
||||
| | | |
|
||||
| Account Management | ❌ | |
|
||||
| User Accounts | ❌ | |
|
||||
| - User Login | ❌ | |
|
||||
| - User Profile | ❌ | |
|
||||
| - Author Profile | ❌ | |
|
||||
| About Page | ✅ | |
|
||||
|
||||
### Pack Designer
|
||||
|
||||
| Feature | Status |
|
||||
|-------|:-------:|
|
||||
| All Design & Features | ❌ | |
|
||||
|
||||
### Site
|
||||
|
||||
| Feature | Status |
|
||||
|-------|:-------:|
|
||||
| Site Base | ✔ | |
|
||||
| Accounts | ✔ | |
|
||||
| Gallery | ❌ | |
|
||||
| Payment Gateway | ❌ | |
|
||||
| - Artist Payout | ❌ | |
|
||||
| - User Media Purchase | ❌ | |
|
||||
|
||||
This app is currently under development and is currently BETA1 and the new API is live. Please do expect bugs in pack compiling at this stage.
|
||||
|
||||
"Featured" Live wallpapers is currently a duplicated of "Newest". The featured endpoint will take manual curation, so this will take some time.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 2.0 MiB |
@@ -11,8 +11,8 @@ target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
|
||||
KomplexHubModuleplugin
|
||||
KomplexHubContentplugin
|
||||
KomplexHubPluginplugin
|
||||
KomplexHubModule_Controlsplugin
|
||||
KomplexHubModule_Keroplugin
|
||||
KomplexHubControlsplugin
|
||||
KomplexHubKeroplugin
|
||||
Qt6::Quick
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
|
||||
Reference in New Issue
Block a user