Compare commits

...

12 Commits

Author SHA1 Message Date
Digital Artifex 3f9b33c74d Updated models and display text 2026-06-16 23:54:24 -04:00
Digital Artifex eb061e9034 Added featured endpoint models and paginators 2026-06-16 23:53:03 -04:00
Digital Artifex 576f9e0f29 Fixed feature endpoint defines 2026-06-16 23:52:10 -04:00
Digital Artifex 5f5c2db53f Added featured videos endpoint definition 2026-06-16 22:50:18 -04:00
Digital Artifex 3137318976 Fixed typo in function name 2026-06-16 21:55:43 -04:00
Digital Artifex 8b497d9496 Fixed key name for wallpaper title 2026-06-16 20:25:31 -04:00
Digital Artifex e0540e5089 Fixed data model issues 2026-06-16 16:58:55 -04:00
Digital Artifex 856797e0f0 Added local dev variable 2026-06-16 16:57:58 -04:00
Digital Artifex 473defcd44 Fixed key names and date format 2026-06-16 16:56:56 -04:00
Digital Artifex bbaefdfe88 General bugfixes and improvements 2026-06-16 16:53:37 -04:00
Digital Artifex d01f880338 Changed constness of some functions 2026-06-16 16:52:06 -04:00
Digital Artifex b3f6e55198 Added copy operator 2026-06-16 16:48:12 -04:00
16 changed files with 2124 additions and 75 deletions
+79 -9
View File
@@ -4,6 +4,7 @@ import QtQuick.Layouts
import KomplexHub
import KomplexHub.Controls
import KomplexHub.Kero
import KomplexHubPlugin
Item {
readonly property bool searchable: false
@@ -11,6 +12,24 @@ Item {
id: homePageRoot
NewestPacksModel
{
id: newestPacksModel
resultsPerPage: homePageRoot.resultsPerRow
}
FeaturedImagesModel
{
id: featuredImagesModel
resultsPerPage: homePageRoot.resultsPerRow
}
FeaturedVideosModel
{
id: featuredVideosModel
resultsPerPage: homePageRoot.resultsPerRow
}
Rectangle {
anchors.fill: parent
color: palette.base
@@ -30,7 +49,7 @@ Item {
Text {
color: palette.text
font.pixelSize: Constants.largeFont.pixelSize
text: "Featured"
text: "Newest Wallpaper Packs"
}
RowLayout {
@@ -40,10 +59,27 @@ Item {
Layout.alignment: Qt.AlignHCenter
Repeater {
model: resultsPerRow
model: newestPacksModel
delegate: SearchResultItem {
delegate: Item {
width: 256
height: 256
required property string name
required property string author
required property string description
required property string uuid
required property string thumbnail
required property string authorId
SearchResultItem
{
anchors.fill: parent
title: parent.name
author: parent.author
description: parent.description
thumbnail: parent.thumbnail
uuid: parent.uuid
}
}
}
@@ -69,7 +105,7 @@ Item {
Text {
color: palette.text
font.pixelSize: Constants.largeFont.pixelSize
text: "Newest"
text: "Featured Images"
}
RowLayout {
@@ -79,10 +115,27 @@ Item {
Layout.alignment: Qt.AlignHCenter
Repeater {
model: resultsPerRow
model: featuredImagesModel
delegate: SearchResultItem {
delegate: Item {
width: 256
height: 256
required property string name
required property string author
required property string description
required property string uuid
required property string thumbnail
required property string authorId
SearchResultItem
{
anchors.fill: parent
title: parent.name
author: parent.author
description: parent.description
thumbnail: parent.thumbnail
uuid: parent.uuid
}
}
}
@@ -108,7 +161,7 @@ Item {
Text {
color: palette.text
font.pixelSize: Constants.largeFont.pixelSize
text: "Popular"
text: "Featured Videos"
}
RowLayout {
@@ -118,10 +171,27 @@ Item {
Layout.alignment: Qt.AlignHCenter
Repeater {
model: resultsPerRow
model: featuredVideosModel
delegate: SearchResultItem {
delegate: Item {
width: 256
height: 256
required property string name
required property string author
required property string description
required property string uuid
required property string thumbnail
required property string authorId
SearchResultItem
{
anchors.fill: parent
title: parent.name
author: parent.author
description: parent.description
thumbnail: parent.thumbnail
uuid: parent.uuid
}
}
}
+8
View File
@@ -39,6 +39,13 @@ qt_add_qml_module(
SOURCES paginators/searchshaderspaginator.h
SOURCES paginators/searchcubemapspaginator.h
SOURCES paginators/searchvideospaginator.h
SOURCES featuredpacksmodel.h
SOURCES featuredpacksmodel.cpp
SOURCES featuredimagesmodel.h
SOURCES featuredimagesmodel.cpp
SOURCES featuredvideosmodel.h
SOURCES featuredvideosmodel.cpp
SOURCES paginators/featuredvideospaginator.h
)
@@ -46,6 +53,7 @@ target_compile_definitions(
KomplexHubPlugin
PUBLIC
KOMPLEX_PLUGIN
KOMPLEX_LOCAL_DEV
)
if(ENABLE_ASAN)
+7
View File
@@ -41,6 +41,13 @@ struct FetchResult
* Results list
*/
QList<T> data;
auto operator=(const FetchResult<T> &other) -> FetchResult<T>
{
total = other.total;
count = other.count;
data = other.data;
}
};
#endif // FETCHRESULT_H
+2 -1
View File
@@ -39,10 +39,11 @@
#define KOMPLEX_API_VERSION "v2"
#define KOMPLEX_ENDPOINT_IMAGES_SEARCH "images/search"
#define KOMPLEX_ENDPOINT_IMAGES_FEATURED "images/featured"
#define KOMPLEX_ENDPOINT_IMAGES_FEATURED "featured/images"
#define KOMPLEX_ENDPOINT_IMAGES_ITEM "images/item"
#define KOMPLEX_ENDPOINT_VIDEOS_SEARCH "videos/search"
#define KOMPLEX_ENDPOINT_VIDEOS_FEATURED "featured/videos"
#define KOMPLEX_ENDPOINT_VIDEOS_ITEM "videos/item"
#define KOMPLEX_ENDPOINT_SHADERS_SEARCH "shaders/search"
+3 -3
View File
@@ -64,7 +64,7 @@ public:
*
* Attempts to get the next page and notifies pageChanged
*/
auto next() const -> void
auto next() -> void
{
setOffset(m_offset + m_resultsPerPage);
}
@@ -74,7 +74,7 @@ public:
*
* Attempts to get the previous page and notifies pageChanged
*/
auto previous() const -> void
auto previous() -> void
{
setOffset(m_offset - m_resultsPerPage);
}
@@ -149,7 +149,7 @@ public:
* The total number of results as reported by the controller
* @return
*/
auto totalResults() -> qsizetype
auto totalResults() const -> qsizetype
{
return m_cacheController.totalCount();
}
@@ -94,7 +94,7 @@ public:
return {};
}
if(!slideWindow(index))
if(!const_cast<SlidingCacheController*>(this)->slideWindow(index))
{
return {};
}
@@ -127,7 +127,7 @@ public:
return {};
}
if(!slideWindow(index))
if(!const_cast<SlidingCacheController*>(this)->slideWindow(index))
{
return {};
}
@@ -148,7 +148,7 @@ public:
for(qsizetype i = index; i < count; ++i)
{
T data = at(i);
T data = m_cache.at(i);
if(data != T{})
{
@@ -184,7 +184,6 @@ public:
QMutexLocker cacheLocker(&m_cacheMutex);
m_cache.clear();
setTotalCount(std::numeric_limits<qsizetype>::infinity());
}
/**
@@ -225,10 +224,10 @@ private:
* @return True if index is within the external dataset boundary
* OR an initial fetch has not been performed.
*/
auto externalBoundaryCheck(qsizetype index) -> bool
auto externalBoundaryCheck(qsizetype index) const -> bool
{
return (
index > 0 &&
index >= 0 &&
(
m_totalCount == std::numeric_limits<qsizetype>::infinity() ||
index < m_totalCount
@@ -243,10 +242,10 @@ private:
* @param index
* @return True if index is within the internal dataset boundary
*/
auto internalBoundaryCheck(qsizetype index) -> bool
auto internalBoundaryCheck(qsizetype index) const -> bool
{
return (
index > 0 &&
index >= 0 &&
index < m_cache.count()
);
}
@@ -281,6 +280,14 @@ private:
}
}
if(m_totalCount == std::numeric_limits<qsizetype>::infinity())
{
if(!slideForward())
{
return false;
}
}
return true;
}
@@ -305,7 +312,14 @@ private:
movementSize -= SLIDING_CACHE_PREFETCH_THRESHOLD;
}
if(m_totalCount != std::numeric_limits<qsizetype>::infinity())
{
m_windowOffset += movementSize;
}
else
{
m_windowOffset = 0;
}
FetchResult<T> result = m_fetch(
m_windowOffset,
@@ -414,7 +428,7 @@ private:
* @param index Global object index
* @return
*/
auto internalIndex(qsizetype index) -> qsizetype
auto internalIndex(qsizetype index) const -> qsizetype
{
return index - m_windowOffset;
}
+254
View File
@@ -0,0 +1,254 @@
#include "featuredimagesmodel.h"
#include "common/wallpapercache.h"
FeaturedImagesModel::FeaturedImagesModel(QObject *parent) : QAbstractListModel{parent}
{
m_paginator = new FeaturedImagesPaginator(this);
PaginationNotifier *notifier = static_cast<PaginationNotifier*>(m_paginator);
QObject::connect(
notifier,
&PaginationNotifier::resultsPerPageChanged,
this,
&FeaturedImagesModel::resultsPerPageChanged
);
QObject::connect(
notifier,
&PaginationNotifier::totalResultsChanged,
this,
&FeaturedImagesModel::totalResultsChanged
);
QObject::connect(
notifier,
&PaginationNotifier::totalPagesChanged,
this,
&FeaturedImagesModel::totalPagesChanged
);
QObject::connect(
notifier,
&PaginationNotifier::pageChanged,
this,
&FeaturedImagesModel::pageChanged
);
QObject::connect(
notifier,
&PaginationNotifier::dataChanged,
this,
&FeaturedImagesModel::resetDataModel
);
}
auto FeaturedImagesModel::rowCount(const QModelIndex &) const -> int
{
if(m_paginator != nullptr)
{
return m_paginator->count();
}
return 0;
}
auto FeaturedImagesModel::data(const QModelIndex &index, int role) const -> QVariant
{
if(index.row() < 0 || m_paginator == nullptr)
{
return {};
}
WallpaperCache dataPoint = m_data.at(index.row());
QVariant data;
switch(static_cast<DataRole>(role))
{
case UuidRole:
data = dataPoint.uuid;
break;
case AuthorRole:
data = dataPoint.author;
break;
case DescriptionRole:
data = dataPoint.description;
break;
case NameRole:
data = dataPoint.name;
break;
case ThumbnailRole:
data = dataPoint.thumbnail;
break;
case CreatedDateRole:
data = dataPoint.createdDate;
break;
case AuthorIdRole:
data = dataPoint.authorId;
break;
case PriceRole:
data = dataPoint.price;
break;
case CurrencyRole:
data = dataPoint.currency;
break;
case DownloadCountRole:
data = dataPoint.downloadCount;
break;
case TypeRole:
data = dataPoint.type;
break;
}
return data;
}
auto FeaturedImagesModel::index(int row, int column, const QModelIndex &parent) const -> QModelIndex
{
Q_UNUSED(parent)
if(row < 0 || row >= m_data.count())
return {};
return createIndex(row, column, &m_data[row]);
}
auto FeaturedImagesModel::columnCount(const QModelIndex &) const -> int
{
return 0;
}
auto FeaturedImagesModel::parent(const QModelIndex &) const -> QModelIndex
{
return {};
}
auto FeaturedImagesModel::setData(const QModelIndex &, const QVariant &, int) -> bool
{
return false;
}
auto FeaturedImagesModel::state() const -> FeaturedImagesModel::State
{
return m_state;
}
auto FeaturedImagesModel::setState(State state) -> void
{
if (m_state == state)
{
return;
}
m_state = state;
emit stateChanged();
}
auto FeaturedImagesModel::resetState() -> void
{
setState(Idle);
}
auto FeaturedImagesModel::resetDataModel() -> void
{
//invalidate previous model data
beginRemoveRows(QModelIndex(), 0, m_data.count());
m_data.clear();
endRemoveRows();
//signal new data
beginInsertRows(QModelIndex(), 0, m_paginator->count() - 1);
auto dataset = m_paginator->data();
for(const WallpaperCache& data : std::as_const(dataset))
{
m_data.append(data);
}
endInsertRows();
}
auto FeaturedImagesModel::roleNames() const -> QHash<int, QByteArray>
{
return m_dataRoles;
}
auto FeaturedImagesModel::errorString() const -> QString
{
return m_errorString;
}
auto FeaturedImagesModel::setErrorString(const QString &errorString) -> void
{
if (m_errorString == errorString)
{
return;
}
m_errorString = errorString;
emit errorStringChanged();
}
auto FeaturedImagesModel::resultsPerPage() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->resultsPerPage();
}
return 0;
}
auto FeaturedImagesModel::setResultsPerPage(qsizetype resultsPerPage) -> void
{
if(m_paginator != nullptr)
{
m_paginator->setResultsPerPage(resultsPerPage);
}
}
auto FeaturedImagesModel::totalResults() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->totalResults();
}
return 0;
}
auto FeaturedImagesModel::nextPage() const -> void
{
if(m_paginator != nullptr)
{
m_paginator->next();
}
}
auto FeaturedImagesModel::previousPage() const -> void
{
if(m_paginator != nullptr)
{
m_paginator->previous();
}
}
qsizetype FeaturedImagesModel::page() const
{
if(m_paginator != nullptr)
{
return m_paginator->page();
}
return 0;
}
auto FeaturedImagesModel::totalPages() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->totalPages();
}
return 0;
}
+303
View File
@@ -0,0 +1,303 @@
/*
* 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 FeaturedImagesModel_H
#define FeaturedImagesModel_H
#include <QObject>
#include <QQmlEngine>
#include <QList>
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QAbstractListModel>
#include <QProcess>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QEventLoop>
#include "paginators/featuredimagespaginator.h"
/**
* @brief The FeaturedImagesModel class
*/
class KOMPLEX_EXPORT FeaturedImagesModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
public:
/**
* @brief Used to control the UI state
*/
enum State
{
Idle,
Loading,
Error
};
Q_ENUM(State)
/**
* @brief Data roles used by the view to request data
*/
enum DataRole {
UuidRole = Qt::UserRole + 1,
AuthorRole,
AuthorIdRole,
DescriptionRole,
NameRole,
ThumbnailRole,
CreatedDateRole,
PriceRole,
CurrencyRole,
DownloadCountRole,
TypeRole
};
Q_ENUM(DataRole)
explicit FeaturedImagesModel(QObject *parent = nullptr);
auto rowCount(const QModelIndex &parent = QModelIndex()) const -> int override;
/**
* @brief data
* Used by the view to pull data from the model.
* Required by QAbstractListModel
* @param index
* @param role
* @return
*/
auto data(
const QModelIndex &index,
int role = Qt::DisplayRole
) const -> QVariant override;
/**
* @brief index
* Used by the view to create an index for the data point.
* Required by QAbstractListModel
* @param row
* @param column
* @param parent
* @return
*/
auto index(
int row,
int column,
const QModelIndex &parent = QModelIndex()
) const -> QModelIndex override;
/**
* @brief columnCount
* Required by QAbstractListModel, but just returns 0
* since we dont use cols
* @param parent
* @return
*/
auto columnCount(
const QModelIndex &parent = QModelIndex()
) const -> int override;
/**
* @brief parent
* @param index
* @return
*/
auto parent(const QModelIndex &index) const -> QModelIndex override;
/**
* @brief setData
* Required by QAbstractListModel but not used
* @param index
* @param value
* @param role
* @return true always
*/
auto setData(
const QModelIndex &index,
const QVariant &value,
int role = Qt::EditRole
) -> bool override;
/**
* @brief state
* Current Model State
* @return
*/
auto state() const -> State;
/**
* @brief roleNames
* Used to tell the view what data roles are available
* and their QML friendly names
* @return
*/
auto roleNames() const -> QHash<int, QByteArray> override;
/**
* @brief errorString
* User-friendly error string to be reported to the user
* @return
*/
auto errorString() const -> QString;
/**
* @brief resultsPerPage
* @return
*/
auto resultsPerPage() const -> qsizetype;
/**
* @brief setResultsPerPage
* @param resultsPerPage
*/
auto setResultsPerPage(qsizetype resultsPerPage) -> void;
/**
* @brief totalResults
* Total number of results available
* @return
*/
auto totalResults() const -> qsizetype;
/**
* @brief page
* @return
*/
auto page() const -> qsizetype;
/**
* @brief totalPages
* Total pages based on the current resultsPerPage
* @return
*/
auto totalPages() const -> qsizetype;
/**
* @brief nextPage
* Function for the QML frontend
*/
Q_INVOKABLE auto nextPage() const -> void;
/**
* @brief previousPage
* Function for the QML frontend
*/
Q_INVOKABLE auto previousPage() const -> void;
protected:
/**
* @brief setErrorString
* @param errorString
*/
auto setErrorString(const QString &errorString) -> void;
/**
* @brief setState
* @param state
*/
auto setState(State state) -> void;
/**
* @brief resetState
*/
auto resetState() -> void;
auto resetDataModel() -> void;
signals:
auto stateChanged() -> void;
auto errorStringChanged() -> void;
auto resultsPerPageChanged() -> void;
auto pageChanged() -> void;
auto totalResultsChanged() -> void;
auto totalPagesChanged() -> void;
private:
static inline const QHash<int, QByteArray> m_dataRoles =
{
{
static_cast<int>(UuidRole),
QByteArray("uuid")
},
{
static_cast<int>(AuthorRole),
QByteArray("author")
},
{
static_cast<int>(AuthorIdRole),
QByteArray("authorId")
},
{
static_cast<int>(DescriptionRole),
QByteArray("description")
},
{
static_cast<int>(NameRole),
QByteArray("name")
},
{
static_cast<int>(ThumbnailRole),
QByteArray("thumbnail")
},
{
static_cast<int>(CreatedDateRole),
QByteArray("createdDate")
},
{
static_cast<int>(PriceRole),
QByteArray("price")
},
{
static_cast<int>(CurrencyRole),
QByteArray("currency")
},
{
static_cast<int>(DownloadCountRole),
QByteArray("downloadCount")
},
{
static_cast<int>(TypeRole),
QByteArray("type")
}
};
State m_state = Idle;
QString m_errorString = QString();
FeaturedImagesPaginator *m_paginator = nullptr;
mutable QList<WallpaperCache> m_data;
Q_PROPERTY(State state READ state WRITE setState RESET resetState NOTIFY stateChanged FINAL)
Q_PROPERTY(QString errorString READ errorString WRITE setErrorString NOTIFY errorStringChanged FINAL)
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(qsizetype page READ page NOTIFY pageChanged FINAL)
};
Q_DECLARE_METATYPE(FeaturedImagesModel)
#endif // FeaturedImagesModel_H
+254
View File
@@ -0,0 +1,254 @@
#include "featuredpacksmodel.h"
#include "common/wallpapercache.h"
FeaturedPacksModel::FeaturedPacksModel(QObject *parent) : QAbstractListModel{parent}
{
m_paginator = new FeaturedPacksPaginator(this);
PaginationNotifier *notifier = static_cast<PaginationNotifier*>(m_paginator);
QObject::connect(
notifier,
&PaginationNotifier::resultsPerPageChanged,
this,
&FeaturedPacksModel::resultsPerPageChanged
);
QObject::connect(
notifier,
&PaginationNotifier::totalResultsChanged,
this,
&FeaturedPacksModel::totalResultsChanged
);
QObject::connect(
notifier,
&PaginationNotifier::totalPagesChanged,
this,
&FeaturedPacksModel::totalPagesChanged
);
QObject::connect(
notifier,
&PaginationNotifier::pageChanged,
this,
&FeaturedPacksModel::pageChanged
);
QObject::connect(
notifier,
&PaginationNotifier::dataChanged,
this,
&FeaturedPacksModel::resetDataModel
);
}
auto FeaturedPacksModel::rowCount(const QModelIndex &) const -> int
{
if(m_paginator != nullptr)
{
return m_paginator->count();
}
return 0;
}
auto FeaturedPacksModel::data(const QModelIndex &index, int role) const -> QVariant
{
if(index.row() < 0 || m_paginator == nullptr)
{
return {};
}
WallpaperCache dataPoint = m_data.at(index.row());
QVariant data;
switch(static_cast<DataRole>(role))
{
case UuidRole:
data = dataPoint.uuid;
break;
case AuthorRole:
data = dataPoint.author;
break;
case DescriptionRole:
data = dataPoint.description;
break;
case NameRole:
data = dataPoint.name;
break;
case ThumbnailRole:
data = dataPoint.thumbnail;
break;
case CreatedDateRole:
data = dataPoint.createdDate;
break;
case AuthorIdRole:
data = dataPoint.authorId;
break;
case PriceRole:
data = dataPoint.price;
break;
case CurrencyRole:
data = dataPoint.currency;
break;
case DownloadCountRole:
data = dataPoint.downloadCount;
break;
case TypeRole:
data = dataPoint.type;
break;
}
return data;
}
auto FeaturedPacksModel::index(int row, int column, const QModelIndex &parent) const -> QModelIndex
{
Q_UNUSED(parent)
if(row < 0 || row >= m_data.count())
return {};
return createIndex(row, column, &m_data[row]);
}
auto FeaturedPacksModel::columnCount(const QModelIndex &) const -> int
{
return 0;
}
auto FeaturedPacksModel::parent(const QModelIndex &) const -> QModelIndex
{
return {};
}
auto FeaturedPacksModel::setData(const QModelIndex &, const QVariant &, int) -> bool
{
return false;
}
auto FeaturedPacksModel::state() const -> FeaturedPacksModel::State
{
return m_state;
}
auto FeaturedPacksModel::setState(State state) -> void
{
if (m_state == state)
{
return;
}
m_state = state;
emit stateChanged();
}
auto FeaturedPacksModel::resetState() -> void
{
setState(Idle);
}
auto FeaturedPacksModel::resetDataModel() -> void
{
//invalidate previous model data
beginRemoveRows(QModelIndex(), 0, m_data.count());
m_data.clear();
endRemoveRows();
//signal new data
beginInsertRows(QModelIndex(), 0, m_paginator->count() - 1);
auto dataset = m_paginator->data();
for(const WallpaperCache& data : std::as_const(dataset))
{
m_data.append(data);
}
endInsertRows();
}
auto FeaturedPacksModel::roleNames() const -> QHash<int, QByteArray>
{
return m_dataRoles;
}
auto FeaturedPacksModel::errorString() const -> QString
{
return m_errorString;
}
auto FeaturedPacksModel::setErrorString(const QString &errorString) -> void
{
if (m_errorString == errorString)
{
return;
}
m_errorString = errorString;
emit errorStringChanged();
}
auto FeaturedPacksModel::resultsPerPage() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->resultsPerPage();
}
return 0;
}
auto FeaturedPacksModel::setResultsPerPage(qsizetype resultsPerPage) -> void
{
if(m_paginator != nullptr)
{
m_paginator->setResultsPerPage(resultsPerPage);
}
}
auto FeaturedPacksModel::totalResults() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->totalResults();
}
return 0;
}
auto FeaturedPacksModel::nextPage() const -> void
{
if(m_paginator != nullptr)
{
m_paginator->next();
}
}
auto FeaturedPacksModel::previousPage() const -> void
{
if(m_paginator != nullptr)
{
m_paginator->previous();
}
}
qsizetype FeaturedPacksModel::page() const
{
if(m_paginator != nullptr)
{
return m_paginator->page();
}
return 0;
}
auto FeaturedPacksModel::totalPages() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->totalPages();
}
return 0;
}
+303
View File
@@ -0,0 +1,303 @@
/*
* 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 FEATUREDPACKSMODEL_H
#define FEATUREDPACKSMODEL_H
#include <QObject>
#include <QQmlEngine>
#include <QList>
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QAbstractListModel>
#include <QProcess>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QEventLoop>
#include "paginators/featuredpackspaginator.h"
/**
* @brief The FeaturedPacksModel class
*/
class KOMPLEX_EXPORT FeaturedPacksModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
public:
/**
* @brief Used to control the UI state
*/
enum State
{
Idle,
Loading,
Error
};
Q_ENUM(State)
/**
* @brief Data roles used by the view to request data
*/
enum DataRole {
UuidRole = Qt::UserRole + 1,
AuthorRole,
AuthorIdRole,
DescriptionRole,
NameRole,
ThumbnailRole,
CreatedDateRole,
PriceRole,
CurrencyRole,
DownloadCountRole,
TypeRole
};
Q_ENUM(DataRole)
explicit FeaturedPacksModel(QObject *parent = nullptr);
auto rowCount(const QModelIndex &parent = QModelIndex()) const -> int override;
/**
* @brief data
* Used by the view to pull data from the model.
* Required by QAbstractListModel
* @param index
* @param role
* @return
*/
auto data(
const QModelIndex &index,
int role = Qt::DisplayRole
) const -> QVariant override;
/**
* @brief index
* Used by the view to create an index for the data point.
* Required by QAbstractListModel
* @param row
* @param column
* @param parent
* @return
*/
auto index(
int row,
int column,
const QModelIndex &parent = QModelIndex()
) const -> QModelIndex override;
/**
* @brief columnCount
* Required by QAbstractListModel, but just returns 0
* since we dont use cols
* @param parent
* @return
*/
auto columnCount(
const QModelIndex &parent = QModelIndex()
) const -> int override;
/**
* @brief parent
* @param index
* @return
*/
auto parent(const QModelIndex &index) const -> QModelIndex override;
/**
* @brief setData
* Required by QAbstractListModel but not used
* @param index
* @param value
* @param role
* @return true always
*/
auto setData(
const QModelIndex &index,
const QVariant &value,
int role = Qt::EditRole
) -> bool override;
/**
* @brief state
* Current Model State
* @return
*/
auto state() const -> State;
/**
* @brief roleNames
* Used to tell the view what data roles are available
* and their QML friendly names
* @return
*/
auto roleNames() const -> QHash<int, QByteArray> override;
/**
* @brief errorString
* User-friendly error string to be reported to the user
* @return
*/
auto errorString() const -> QString;
/**
* @brief resultsPerPage
* @return
*/
auto resultsPerPage() const -> qsizetype;
/**
* @brief setResultsPerPage
* @param resultsPerPage
*/
auto setResultsPerPage(qsizetype resultsPerPage) -> void;
/**
* @brief totalResults
* Total number of results available
* @return
*/
auto totalResults() const -> qsizetype;
/**
* @brief page
* @return
*/
auto page() const -> qsizetype;
/**
* @brief totalPages
* Total pages based on the current resultsPerPage
* @return
*/
auto totalPages() const -> qsizetype;
/**
* @brief nextPage
* Function for the QML frontend
*/
Q_INVOKABLE auto nextPage() const -> void;
/**
* @brief previousPage
* Function for the QML frontend
*/
Q_INVOKABLE auto previousPage() const -> void;
protected:
/**
* @brief setErrorString
* @param errorString
*/
auto setErrorString(const QString &errorString) -> void;
/**
* @brief setState
* @param state
*/
auto setState(State state) -> void;
/**
* @brief resetState
*/
auto resetState() -> void;
auto resetDataModel() -> void;
signals:
auto stateChanged() -> void;
auto errorStringChanged() -> void;
auto resultsPerPageChanged() -> void;
auto pageChanged() -> void;
auto totalResultsChanged() -> void;
auto totalPagesChanged() -> void;
private:
static inline const QHash<int, QByteArray> m_dataRoles =
{
{
static_cast<int>(UuidRole),
QByteArray("uuid")
},
{
static_cast<int>(AuthorRole),
QByteArray("author")
},
{
static_cast<int>(AuthorIdRole),
QByteArray("authorId")
},
{
static_cast<int>(DescriptionRole),
QByteArray("description")
},
{
static_cast<int>(NameRole),
QByteArray("name")
},
{
static_cast<int>(ThumbnailRole),
QByteArray("thumbnail")
},
{
static_cast<int>(CreatedDateRole),
QByteArray("createdDate")
},
{
static_cast<int>(PriceRole),
QByteArray("price")
},
{
static_cast<int>(CurrencyRole),
QByteArray("currency")
},
{
static_cast<int>(DownloadCountRole),
QByteArray("downloadCount")
},
{
static_cast<int>(TypeRole),
QByteArray("type")
}
};
State m_state = Idle;
QString m_errorString = QString();
FeaturedPacksPaginator *m_paginator = nullptr;
mutable QList<WallpaperCache> m_data;
Q_PROPERTY(State state READ state WRITE setState RESET resetState NOTIFY stateChanged FINAL)
Q_PROPERTY(QString errorString READ errorString WRITE setErrorString NOTIFY errorStringChanged FINAL)
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(qsizetype page READ page NOTIFY pageChanged FINAL)
};
Q_DECLARE_METATYPE(FeaturedPacksModel)
#endif // FEATUREDPACKSMODEL_H
+254
View File
@@ -0,0 +1,254 @@
#include "featuredvideosmodel.h"
#include "common/wallpapercache.h"
FeaturedVideosModel::FeaturedVideosModel(QObject *parent) : QAbstractListModel{parent}
{
m_paginator = new FeaturedVideosPaginator(this);
PaginationNotifier *notifier = static_cast<PaginationNotifier*>(m_paginator);
QObject::connect(
notifier,
&PaginationNotifier::resultsPerPageChanged,
this,
&FeaturedVideosModel::resultsPerPageChanged
);
QObject::connect(
notifier,
&PaginationNotifier::totalResultsChanged,
this,
&FeaturedVideosModel::totalResultsChanged
);
QObject::connect(
notifier,
&PaginationNotifier::totalPagesChanged,
this,
&FeaturedVideosModel::totalPagesChanged
);
QObject::connect(
notifier,
&PaginationNotifier::pageChanged,
this,
&FeaturedVideosModel::pageChanged
);
QObject::connect(
notifier,
&PaginationNotifier::dataChanged,
this,
&FeaturedVideosModel::resetDataModel
);
}
auto FeaturedVideosModel::rowCount(const QModelIndex &) const -> int
{
if(m_paginator != nullptr)
{
return m_paginator->count();
}
return 0;
}
auto FeaturedVideosModel::data(const QModelIndex &index, int role) const -> QVariant
{
if(index.row() < 0 || m_paginator == nullptr)
{
return {};
}
WallpaperCache dataPoint = m_data.at(index.row());
QVariant data;
switch(static_cast<DataRole>(role))
{
case UuidRole:
data = dataPoint.uuid;
break;
case AuthorRole:
data = dataPoint.author;
break;
case DescriptionRole:
data = dataPoint.description;
break;
case NameRole:
data = dataPoint.name;
break;
case ThumbnailRole:
data = dataPoint.thumbnail;
break;
case CreatedDateRole:
data = dataPoint.createdDate;
break;
case AuthorIdRole:
data = dataPoint.authorId;
break;
case PriceRole:
data = dataPoint.price;
break;
case CurrencyRole:
data = dataPoint.currency;
break;
case DownloadCountRole:
data = dataPoint.downloadCount;
break;
case TypeRole:
data = dataPoint.type;
break;
}
return data;
}
auto FeaturedVideosModel::index(int row, int column, const QModelIndex &parent) const -> QModelIndex
{
Q_UNUSED(parent)
if(row < 0 || row >= m_data.count())
return {};
return createIndex(row, column, &m_data[row]);
}
auto FeaturedVideosModel::columnCount(const QModelIndex &) const -> int
{
return 0;
}
auto FeaturedVideosModel::parent(const QModelIndex &) const -> QModelIndex
{
return {};
}
auto FeaturedVideosModel::setData(const QModelIndex &, const QVariant &, int) -> bool
{
return false;
}
auto FeaturedVideosModel::state() const -> FeaturedVideosModel::State
{
return m_state;
}
auto FeaturedVideosModel::setState(State state) -> void
{
if (m_state == state)
{
return;
}
m_state = state;
emit stateChanged();
}
auto FeaturedVideosModel::resetState() -> void
{
setState(Idle);
}
auto FeaturedVideosModel::resetDataModel() -> void
{
//invalidate previous model data
beginRemoveRows(QModelIndex(), 0, m_data.count());
m_data.clear();
endRemoveRows();
//signal new data
beginInsertRows(QModelIndex(), 0, m_paginator->count() - 1);
auto dataset = m_paginator->data();
for(const WallpaperCache& data : std::as_const(dataset))
{
m_data.append(data);
}
endInsertRows();
}
auto FeaturedVideosModel::roleNames() const -> QHash<int, QByteArray>
{
return m_dataRoles;
}
auto FeaturedVideosModel::errorString() const -> QString
{
return m_errorString;
}
auto FeaturedVideosModel::setErrorString(const QString &errorString) -> void
{
if (m_errorString == errorString)
{
return;
}
m_errorString = errorString;
emit errorStringChanged();
}
auto FeaturedVideosModel::resultsPerPage() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->resultsPerPage();
}
return 0;
}
auto FeaturedVideosModel::setResultsPerPage(qsizetype resultsPerPage) -> void
{
if(m_paginator != nullptr)
{
m_paginator->setResultsPerPage(resultsPerPage);
}
}
auto FeaturedVideosModel::totalResults() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->totalResults();
}
return 0;
}
auto FeaturedVideosModel::nextPage() const -> void
{
if(m_paginator != nullptr)
{
m_paginator->next();
}
}
auto FeaturedVideosModel::previousPage() const -> void
{
if(m_paginator != nullptr)
{
m_paginator->previous();
}
}
qsizetype FeaturedVideosModel::page() const
{
if(m_paginator != nullptr)
{
return m_paginator->page();
}
return 0;
}
auto FeaturedVideosModel::totalPages() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->totalPages();
}
return 0;
}
+303
View File
@@ -0,0 +1,303 @@
/*
* 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 FEATUREDVIDEOSMODEL_H
#define FEATUREDVIDEOSMODEL_H
#include <QObject>
#include <QQmlEngine>
#include <QList>
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QAbstractListModel>
#include <QProcess>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QEventLoop>
#include "paginators/featuredvideospaginator.h"
/**
* @brief The FeaturedVideosModel class
*/
class KOMPLEX_EXPORT FeaturedVideosModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
public:
/**
* @brief Used to control the UI state
*/
enum State
{
Idle,
Loading,
Error
};
Q_ENUM(State)
/**
* @brief Data roles used by the view to request data
*/
enum DataRole {
UuidRole = Qt::UserRole + 1,
AuthorRole,
AuthorIdRole,
DescriptionRole,
NameRole,
ThumbnailRole,
CreatedDateRole,
PriceRole,
CurrencyRole,
DownloadCountRole,
TypeRole
};
Q_ENUM(DataRole)
explicit FeaturedVideosModel(QObject *parent = nullptr);
auto rowCount(const QModelIndex &parent = QModelIndex()) const -> int override;
/**
* @brief data
* Used by the view to pull data from the model.
* Required by QAbstractListModel
* @param index
* @param role
* @return
*/
auto data(
const QModelIndex &index,
int role = Qt::DisplayRole
) const -> QVariant override;
/**
* @brief index
* Used by the view to create an index for the data point.
* Required by QAbstractListModel
* @param row
* @param column
* @param parent
* @return
*/
auto index(
int row,
int column,
const QModelIndex &parent = QModelIndex()
) const -> QModelIndex override;
/**
* @brief columnCount
* Required by QAbstractListModel, but just returns 0
* since we dont use cols
* @param parent
* @return
*/
auto columnCount(
const QModelIndex &parent = QModelIndex()
) const -> int override;
/**
* @brief parent
* @param index
* @return
*/
auto parent(const QModelIndex &index) const -> QModelIndex override;
/**
* @brief setData
* Required by QAbstractListModel but not used
* @param index
* @param value
* @param role
* @return true always
*/
auto setData(
const QModelIndex &index,
const QVariant &value,
int role = Qt::EditRole
) -> bool override;
/**
* @brief state
* Current Model State
* @return
*/
auto state() const -> State;
/**
* @brief roleNames
* Used to tell the view what data roles are available
* and their QML friendly names
* @return
*/
auto roleNames() const -> QHash<int, QByteArray> override;
/**
* @brief errorString
* User-friendly error string to be reported to the user
* @return
*/
auto errorString() const -> QString;
/**
* @brief resultsPerPage
* @return
*/
auto resultsPerPage() const -> qsizetype;
/**
* @brief setResultsPerPage
* @param resultsPerPage
*/
auto setResultsPerPage(qsizetype resultsPerPage) -> void;
/**
* @brief totalResults
* Total number of results available
* @return
*/
auto totalResults() const -> qsizetype;
/**
* @brief page
* @return
*/
auto page() const -> qsizetype;
/**
* @brief totalPages
* Total pages based on the current resultsPerPage
* @return
*/
auto totalPages() const -> qsizetype;
/**
* @brief nextPage
* Function for the QML frontend
*/
Q_INVOKABLE auto nextPage() const -> void;
/**
* @brief previousPage
* Function for the QML frontend
*/
Q_INVOKABLE auto previousPage() const -> void;
protected:
/**
* @brief setErrorString
* @param errorString
*/
auto setErrorString(const QString &errorString) -> void;
/**
* @brief setState
* @param state
*/
auto setState(State state) -> void;
/**
* @brief resetState
*/
auto resetState() -> void;
auto resetDataModel() -> void;
signals:
auto stateChanged() -> void;
auto errorStringChanged() -> void;
auto resultsPerPageChanged() -> void;
auto pageChanged() -> void;
auto totalResultsChanged() -> void;
auto totalPagesChanged() -> void;
private:
static inline const QHash<int, QByteArray> m_dataRoles =
{
{
static_cast<int>(UuidRole),
QByteArray("uuid")
},
{
static_cast<int>(AuthorRole),
QByteArray("author")
},
{
static_cast<int>(AuthorIdRole),
QByteArray("authorId")
},
{
static_cast<int>(DescriptionRole),
QByteArray("description")
},
{
static_cast<int>(NameRole),
QByteArray("name")
},
{
static_cast<int>(ThumbnailRole),
QByteArray("thumbnail")
},
{
static_cast<int>(CreatedDateRole),
QByteArray("createdDate")
},
{
static_cast<int>(PriceRole),
QByteArray("price")
},
{
static_cast<int>(CurrencyRole),
QByteArray("currency")
},
{
static_cast<int>(DownloadCountRole),
QByteArray("downloadCount")
},
{
static_cast<int>(TypeRole),
QByteArray("type")
}
};
State m_state = Idle;
QString m_errorString = QString();
FeaturedVideosPaginator *m_paginator = nullptr;
mutable QList<WallpaperCache> m_data;
Q_PROPERTY(State state READ state WRITE setState RESET resetState NOTIFY stateChanged FINAL)
Q_PROPERTY(QString errorString READ errorString WRITE setErrorString NOTIFY errorStringChanged FINAL)
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(qsizetype page READ page NOTIFY pageChanged FINAL)
};
Q_DECLARE_METATYPE(FeaturedVideosModel)
#endif // FEATUREDVIDEOSMODEL_H
+121 -25
View File
@@ -1,33 +1,72 @@
#include "newestpacksmodel.h"
#include "common/coreservices.h"
#include "common/logging.h"
#include "common/wallpapercache.h"
NewestPacksModel::NewestPacksModel(QObject *parent) : QAbstractListModel{parent}
{
m_paginator = new NewestPacksPaginator(this);
PaginationNotifier *notifier = static_cast<PaginationNotifier*>(m_paginator);
QObject::connect(
notifier,
&PaginationNotifier::resultsPerPageChanged,
this,
&NewestPacksModel::resultsPerPageChanged
);
QObject::connect(
notifier,
&PaginationNotifier::totalResultsChanged,
this,
&NewestPacksModel::totalResultsChanged
);
QObject::connect(
notifier,
&PaginationNotifier::totalPagesChanged,
this,
&NewestPacksModel::totalPagesChanged
);
QObject::connect(
notifier,
&PaginationNotifier::pageChanged,
this,
&NewestPacksModel::pageChanged
);
QObject::connect(
notifier,
&PaginationNotifier::dataChanged,
this,
&NewestPacksModel::resetDataModel
);
}
auto NewestPacksModel::rowCount(const QModelIndex &) const -> int
{
return m_wallpaperCache.count();
if(m_paginator != nullptr)
{
return m_paginator->count();
}
return 0;
}
auto NewestPacksModel::data(const QModelIndex &index, int role) const -> QVariant
{
if(index.row() < 0)
if(index.row() < 0 || m_paginator == nullptr)
{
return {};
}
WallpaperCache dataPoint = m_wallpaperCache.at(index.row());
WallpaperCache dataPoint = m_data.at(index.row());
QVariant data;
switch(static_cast<DataRole>(role))
{
case UriRole:
data = dataPoint.uri;
case UuidRole:
data = dataPoint.uuid;
break;
case AuthorRole:
data = dataPoint.author;
@@ -68,8 +107,10 @@ auto NewestPacksModel::index(int row, int column, const QModelIndex &parent) con
{
Q_UNUSED(parent)
WallpaperCache data = m_wallpaperCache.at(row);
return createIndex(row, column, &data);
if(row < 0 || row >= m_data.count())
return {};
return createIndex(row, column, &m_data[row]);
}
auto NewestPacksModel::columnCount(const QModelIndex &) const -> int
@@ -108,6 +149,25 @@ auto NewestPacksModel::resetState() -> void
setState(Idle);
}
auto NewestPacksModel::resetDataModel() -> void
{
//invalidate previous model data
beginRemoveRows(QModelIndex(), 0, m_data.count());
m_data.clear();
endRemoveRows();
//signal new data
beginInsertRows(QModelIndex(), 0, m_paginator->count() - 1);
auto dataset = m_paginator->data();
for(const WallpaperCache& data : std::as_const(dataset))
{
m_data.append(data);
}
endInsertRows();
}
auto NewestPacksModel::roleNames() const -> QHash<int, QByteArray>
{
return m_dataRoles;
@@ -129,30 +189,66 @@ auto NewestPacksModel::setErrorString(const QString &errorString) -> void
emit errorStringChanged();
}
auto NewestPacksModel::resultsPerPage() const -> qint64
auto NewestPacksModel::resultsPerPage() const -> qsizetype
{
return m_resultsPerPage;
if(m_paginator != nullptr)
{
return m_paginator->resultsPerPage();
}
return 0;
}
auto NewestPacksModel::setResultsPerPage(qint64 resultsPerPage) -> void
auto NewestPacksModel::setResultsPerPage(qsizetype resultsPerPage) -> void
{
if (m_resultsPerPage == resultsPerPage)
return;
m_resultsPerPage = resultsPerPage;
emit resultsPerPageChanged();
if(m_paginator != nullptr)
{
m_paginator->setResultsPerPage(resultsPerPage);
}
}
qint64 NewestPacksModel::page() const
auto NewestPacksModel::totalResults() const -> qsizetype
{
return m_page;
if(m_paginator != nullptr)
{
return m_paginator->totalResults();
}
return 0;
}
void NewestPacksModel::setPage(qint64 page)
auto NewestPacksModel::nextPage() const -> void
{
if (m_page == page)
return;
m_page = page;
emit pageChanged();
if(m_paginator != nullptr)
{
m_paginator->next();
}
}
auto NewestPacksModel::previousPage() const -> void
{
if(m_paginator != nullptr)
{
m_paginator->previous();
}
}
qsizetype NewestPacksModel::page() const
{
if(m_paginator != nullptr)
{
return m_paginator->page();
}
return 0;
}
auto NewestPacksModel::totalPages() const -> qsizetype
{
if(m_paginator != nullptr)
{
return m_paginator->totalPages();
}
return 0;
}
+156 -22
View File
@@ -38,12 +38,18 @@
#include "paginators/newestpackspaginator.h"
/**
* @brief The NewestPacksModel class
*/
class KOMPLEX_EXPORT NewestPacksModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
public:
/**
* @brief Used to control the UI state
*/
enum State
{
Idle,
@@ -52,8 +58,11 @@ public:
};
Q_ENUM(State)
/**
* @brief Data roles used by the view to request data
*/
enum DataRole {
UriRole = Qt::UserRole + 1,
UuidRole = Qt::UserRole + 1,
AuthorRole,
AuthorIdRole,
DescriptionRole,
@@ -69,60 +78,188 @@ public:
explicit NewestPacksModel(QObject *parent = nullptr);
/**
* @brief rowCount
* @param parent
* @return
*/
[[nodiscard]]
auto rowCount(const QModelIndex &parent = QModelIndex()) const -> int override;
auto data(const QModelIndex &index, int role = Qt::DisplayRole) const -> QVariant override;
/**
* @brief data
* Used by the view to pull data from the model.
* Required by QAbstractListModel
* @param index
* @param role
* @return
*/
[[nodiscard]]
auto data(
const QModelIndex &index,
int role = Qt::DisplayRole
) const -> QVariant override;
/**
* @brief index
* Used by the view to create an index for the data point.
* Required by QAbstractListModel
* @param row
* @param column
* @param parent
* @return
*/
[[nodiscard]]
auto index(
int row,
int column,
const QModelIndex &parent = QModelIndex()
) const -> QModelIndex override;
/**
* @brief columnCount
* Required by QAbstractListModel, but just returns 0
* since we dont use cols
* @param parent
* @return
*/
[[nodiscard]]
auto columnCount(
const QModelIndex &parent = QModelIndex()
) const -> int override;
/**
* @brief parent
* @param index
* @return
*/
[[nodiscard]]
auto parent(const QModelIndex &index) const -> QModelIndex override;
/**
* @brief setData
* Required by QAbstractListModel but not used
* @param index
* @param value
* @param role
* @return true always
*/
auto setData(
const QModelIndex &index,
const QVariant &value,
int role = Qt::EditRole
) -> bool override;
/**
* @brief state
* Current Model State
* @return
*/
auto state() const -> State;
auto setState(State state) -> void;
auto resetState() -> void;
/**
* @brief roleNames
* Used to tell the view what data roles are available
* and their QML friendly names
* @return
*/
[[nodiscard]]
auto roleNames() const -> QHash<int, QByteArray> override;
/**
* @brief errorString
* @return
*/
[[nodiscard]]
auto errorString() const -> QString;
/**
* @brief resultsPerPage
* @return
*/
auto resultsPerPage() const -> qsizetype;
/**
* @brief setResultsPerPage
* @param resultsPerPage
*/
auto setResultsPerPage(qsizetype resultsPerPage) -> void;
/**
* @brief totalResults
* @return
*/
auto totalResults() const -> qsizetype;
/**
* @brief page
* @return
*/
auto page() const -> qsizetype;
/**
* @brief totalPages
* @return
*/
auto totalPages() const -> qsizetype;
/**
* @brief nextPage
*/
Q_INVOKABLE auto nextPage() const -> void;
/**
* @brief previousPage
*/
Q_INVOKABLE auto previousPage() const -> void;
protected:
/**
* @brief setErrorString
* @param errorString
*/
auto setErrorString(const QString &errorString) -> void;
auto resultsPerPage() const -> qint64;
auto setResultsPerPage(qint64 resultsPerPage) -> void;
/**
* @brief setState
* @param state
*/
auto setState(State state) -> void;
qint64 page() const;
void setPage(qint64 page);
/**
* @brief resetState
*/
auto resetState() -> void;
/**
* @brief resetDataModel
*/
auto resetDataModel() -> void;
signals:
auto installedWallpapersChanged() -> void;
auto stateChanged() -> void;
auto errorStringChanged() -> void;
auto resultsPerPageChanged() -> void;
void pageChanged();
auto pageChanged() -> void;
auto totalResultsChanged() -> void;
auto totalPagesChanged() -> void;
private:
static inline const QHash<int, QByteArray> m_dataRoles =
{
{
static_cast<int>(UriRole),
QByteArray("uri")
static_cast<int>(UuidRole),
QByteArray("uuid")
},
{
static_cast<int>(AuthorRole),
QByteArray("author")
},
{
static_cast<int>(AuthorIdRole),
QByteArray("authorId")
},
{
static_cast<int>(DescriptionRole),
QByteArray("description")
@@ -156,23 +293,20 @@ private:
QByteArray("type")
}
};
static inline const QString m_endpointUri = QString("");
State m_state = Idle;
QString m_errorString = QString();
QString m_installDirectoryUri;
NewestPacksPaginator *m_paginator = nullptr;
qint64 m_page = 0;
qint64 m_resultsPerPage = 0;
NewestPacksPaginator m_wallpaperCache;
mutable QList<WallpaperCache> m_data;
Q_PROPERTY(State state READ state WRITE setState RESET resetState NOTIFY stateChanged FINAL)
Q_PROPERTY(QString errorString READ errorString WRITE setErrorString NOTIFY errorStringChanged FINAL)
Q_PROPERTY(qint64 resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
Q_PROPERTY(qint64 page READ page WRITE setPage NOTIFY pageChanged FINAL)
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(qsizetype page READ page NOTIFY pageChanged FINAL)
};
Q_DECLARE_METATYPE(NewestPacksModel)
@@ -0,0 +1,45 @@
/*
* 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 FEATUREDVIDEOSPAGINATOR_H
#define FEATUREDVIDEOSPAGINATOR_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 FeaturedVideosPaginator : public WallpaperPaginator
{
public:
explicit FeaturedVideosPaginator(QObject *parent = nullptr) : WallpaperPaginator(parent)
{
setUri(
QString::fromUtf8(KOMPLEX_ENDPOINT_VIDEOS_FEATURED)
);
}
};
#endif // FEATUREDVIDEOSPAGINATOR_H
@@ -182,14 +182,15 @@ protected:
fetchedResults.append(
{
resultObject.value(QString::fromUtf8("uri")).toString(),
resultObject.value(QString::fromUtf8("name")).toString(),
resultObject.value(QString::fromUtf8("uuid")).toString(),
resultObject.value(QString::fromUtf8("title")).toString(),
resultObject.value(QString::fromUtf8("author")).toString(),
resultObject.value(QString::fromUtf8("authorId")).toString(),
resultObject.value(QString::fromUtf8("author_id")).toString(),
resultObject.value(QString::fromUtf8("description")).toString(),
resultObject.value(QString::fromUtf8("thumbnail")).toString(),
QDateTime::fromString(
resultObject.value(QString::fromUtf8("createdDate")).toString()
resultObject.value(QString::fromUtf8("creation")).toString(),
QString::fromUtf8("yyyy-MM-dd HH:mm:ss")
),
resultObject.value(QString::fromUtf8("price")).toDouble(),
resultObject.value(QString::fromUtf8("currency")).toString(),
@@ -203,12 +204,14 @@ protected:
);
}
return
FetchResult<WallpaperCache> result
{
static_cast<qsizetype>(rootObject.value(QString::fromUtf8("total_results")).toInteger()),
fetchedResults.count(),
std::move(fetchedResults)
};
return std::move(result);
}
/**