mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2025-09-04 01:42:44 +00:00
WIP: Reimplementation of ListModels.
This commit is contained in:
parent
76a49868b9
commit
e421adf733
356 changed files with 1830 additions and 1833 deletions
|
@ -20,12 +20,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#ifndef JELLYFIN_API_MODEL
|
||||
#define JELLYFIN_API_MODEL
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QFlags>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QMetaEnum>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonValue>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <QtQml>
|
||||
#include <QQmlParserStatus>
|
||||
#include <QVariant>
|
||||
|
@ -36,41 +41,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "dto/baseitemdto.h"
|
||||
#include "dto/userdto.h"
|
||||
#include "dto/useritemdatadto.h"
|
||||
#include "dto/baseitemdtoqueryresult.h"
|
||||
#include "loader/requesttypes.h"
|
||||
#include "support/loader.h"
|
||||
|
||||
namespace Jellyfin {
|
||||
|
||||
class SortOptions : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SortOptions (QObject *parent = nullptr) : QObject(parent) {}
|
||||
enum SortBy {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
Budget,
|
||||
CommunityRating,
|
||||
CriticRating,
|
||||
DateCreated,
|
||||
DatePlayed,
|
||||
PlayCount,
|
||||
PremiereDate,
|
||||
ProductionYear,
|
||||
SortName,
|
||||
Random,
|
||||
Revenue,
|
||||
Runtime
|
||||
};
|
||||
Q_ENUM(SortBy)
|
||||
};
|
||||
|
||||
/**
|
||||
* Q_OBJECT does not support template classes. This base class declares the
|
||||
* Q_OBJECT related properties and signals.
|
||||
* Pageable response, which support offset and record parameters. The result
|
||||
* should contain a field with the total item count, returned item count and an array
|
||||
* containing the results.
|
||||
*/
|
||||
class BaseApiModel : public QAbstractListModel, public QQmlParserStatus {
|
||||
Q_OBJECT
|
||||
struct PageableResponse;
|
||||
|
||||
class ModelStatusClass {
|
||||
Q_GADGET
|
||||
public:
|
||||
explicit BaseApiModel(QString path, bool hasRecordResponse, bool addUserId, QObject *parent = nullptr);
|
||||
enum ModelStatus {
|
||||
Uninitialised,
|
||||
Loading,
|
||||
|
@ -79,61 +65,51 @@ public:
|
|||
LoadingMore
|
||||
};
|
||||
Q_ENUM(ModelStatus)
|
||||
private:
|
||||
ModelStatusClass() {}
|
||||
};
|
||||
|
||||
enum SortOrder {
|
||||
Unspecified,
|
||||
Ascending,
|
||||
Descending
|
||||
};
|
||||
Q_ENUM(SortOrder)
|
||||
Q_PROPERTY(ApiClient *apiClient MEMBER m_apiClient NOTIFY apiClientChanged)
|
||||
using ModelStatus = ModelStatusClass::ModelStatus;
|
||||
|
||||
class BaseModelLoader : public QObject, public QQmlParserStatus {
|
||||
Q_INTERFACES(QQmlParserStatus)
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BaseModelLoader(QObject *parent = nullptr);
|
||||
Q_PROPERTY(ApiClient *apiClient READ apiClient WRITE setApiClient NOTIFY apiClientChanged)
|
||||
Q_PROPERTY(ModelStatus status READ status NOTIFY statusChanged)
|
||||
Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged)
|
||||
Q_PROPERTY(bool autoReload READ autoReload WRITE setAutoReload NOTIFY autoReloadChanged)
|
||||
|
||||
// Query properties
|
||||
Q_PROPERTY(int limit MEMBER m_limit NOTIFY limitChanged)
|
||||
Q_PROPERTY(QList<QString> sortBy MEMBER m_sortBy NOTIFY sortByChanged)
|
||||
Q_PROPERTY(QList<QString> fields MEMBER m_fields NOTIFY fieldsChanged)
|
||||
Q_PROPERTY(SortOrder sortOrder MEMBER m_sortOrder NOTIFY sortOrderChanged)
|
||||
ApiClient *apiClient() const { return m_apiClient; }
|
||||
void setApiClient(ApiClient *newApiClient);
|
||||
|
||||
int limit() const { return m_limit; }
|
||||
void setLimit(int newLimit);
|
||||
bool autoReload() const { return m_autoReload; }
|
||||
void setAutoReload(bool newAutoReload);
|
||||
|
||||
ModelStatus status() const { return m_status; }
|
||||
void setApiClient(ApiClient *newApiClient);
|
||||
void setLimit(int newLimit);
|
||||
|
||||
// From AbstractListModel, gets implemented in ApiModel<T>
|
||||
virtual int rowCount(const QModelIndex &index) const override = 0;
|
||||
virtual QHash<int, QByteArray> roleNames() const override = 0;
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override = 0;
|
||||
virtual bool canFetchMore(const QModelIndex &parent) const override = 0;
|
||||
virtual void fetchMore(const QModelIndex &parent) override = 0;
|
||||
|
||||
// QQmlParserStatus interface
|
||||
virtual void classBegin() override;
|
||||
virtual void componentComplete() override;
|
||||
|
||||
void autoReloadIfNeeded();
|
||||
signals:
|
||||
void ready();
|
||||
void apiClientChanged(ApiClient *newApiClient);
|
||||
void statusChanged(ModelStatus newStatus);
|
||||
void statusChanged();
|
||||
void limitChanged(int newLimit);
|
||||
void sortByChanged(QList<QString> newSortOrder);
|
||||
void sortOrderChanged(SortOrder newSortOrder);
|
||||
void fieldsChanged(QList<QString> newFields);
|
||||
void autoReloadChanged(bool newAutoReload);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief (Re)loads the data into this model. This might make a network request.
|
||||
*/
|
||||
void reload();
|
||||
void reloadWanted();
|
||||
|
||||
protected:
|
||||
enum LoadType {
|
||||
RELOAD,
|
||||
LOAD_MORE
|
||||
};
|
||||
|
||||
ApiClient *m_apiClient = nullptr;
|
||||
// Is this object being parsed by the QML engine
|
||||
bool m_isBeingParsed = false;
|
||||
// Per-model specific settings.
|
||||
QString m_path;
|
||||
bool m_hasRecordResponse;
|
||||
bool m_addUserId;
|
||||
ApiClient *m_apiClient = nullptr;
|
||||
bool m_autoReload = true;
|
||||
|
||||
// Query/record controlling properties
|
||||
int m_limit = -1;
|
||||
|
@ -141,55 +117,168 @@ protected:
|
|||
int m_totalRecordCount = 0;
|
||||
const int DEFAULT_LIMIT = 100;
|
||||
|
||||
// Query properties
|
||||
QList<QString> m_fields = {};
|
||||
QList<QString> m_sortBy = {};
|
||||
SortOrder m_sortOrder = Unspecified;
|
||||
|
||||
// State properties.
|
||||
ModelStatus m_status = Uninitialised;
|
||||
|
||||
ModelStatus m_status = ModelStatus::Uninitialised;
|
||||
void setStatus(ModelStatus newStatus) {
|
||||
if (this->m_status != newStatus) {
|
||||
this->m_status = newStatus;
|
||||
emit this->statusChanged(newStatus);
|
||||
if (m_status == Ready) {
|
||||
emit this->statusChanged();
|
||||
if (this->m_status == ModelStatus::Ready) {
|
||||
emit ready();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load(LoadType loadType);
|
||||
virtual void setModelData(QJsonArray &data) = 0;
|
||||
virtual void appendModelData(QJsonArray &data) = 0;
|
||||
/**
|
||||
* @brief Adds parameters to the query
|
||||
* @param query The query to add parameters to
|
||||
*
|
||||
* This method is intended to be overrided by subclasses. It gets called
|
||||
* before a request is made to the server and can be used to enable
|
||||
* query types specific for a certain model to be available.
|
||||
*
|
||||
* Make sure to call the method in the superclass as well!
|
||||
*/
|
||||
virtual void addQueryParameters(QUrlQuery &query);
|
||||
|
||||
/**
|
||||
* @brief Replaces placeholders in an URL.
|
||||
* @param path The path in which placeholders should be replaced.
|
||||
*
|
||||
* This method is intended to be overrided by subclasses. It gets called
|
||||
* before a request is made to the server and can be used to enable
|
||||
* query types specific for a certain model to be available.
|
||||
*
|
||||
* Make sure to call the method in the superclass as well!
|
||||
*/
|
||||
virtual void replacePathPlaceholders(QString &path);
|
||||
|
||||
virtual void classBegin() override;
|
||||
virtual void componentComplete() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base model loader that only has one template parameter,
|
||||
* so it can be used within the ApiModel.
|
||||
*/
|
||||
template <class T>
|
||||
class ModelLoader : public BaseModelLoader {
|
||||
public:
|
||||
ModelLoader(QObject *parent = nullptr)
|
||||
: BaseModelLoader(parent) {}
|
||||
|
||||
QList<T> reload() {
|
||||
m_startIndex = 0;
|
||||
m_totalRecordCount = -1;
|
||||
return loadMore();
|
||||
}
|
||||
|
||||
QList<T> loadMore() {
|
||||
if (m_startIndex == 0) {
|
||||
this->setStatus(ModelStatus::Loading);
|
||||
} else {
|
||||
this->setStatus(ModelStatus::LoadingMore);
|
||||
}
|
||||
std::pair<QList<T>, int> result;
|
||||
try {
|
||||
result = loadMore(m_startIndex, m_limit);
|
||||
} catch(Support::LoadException &e) {
|
||||
qWarning() << "Exception while loading in ModelLoader: " << e.what();
|
||||
return QList<T>();
|
||||
}
|
||||
m_startIndex += result.first.size();
|
||||
m_totalRecordCount = result.second;
|
||||
return result.first;
|
||||
}
|
||||
|
||||
virtual bool canLoadMore() const {
|
||||
return m_totalRecordCount == -1 || m_startIndex < m_totalRecordCount;
|
||||
}
|
||||
protected:
|
||||
virtual std::pair<QList<T>, int> loadMore(int offset, int limit) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Template to extract records from the given result.
|
||||
*/
|
||||
template <class T, class R>
|
||||
QList<T> extractRecords(const R &result) {
|
||||
Q_UNUSED(result)
|
||||
Q_UNIMPLEMENTED();
|
||||
return QList<T>();
|
||||
}
|
||||
|
||||
template <class R>
|
||||
int extractTotalRecordCount(const R &result) {
|
||||
Q_UNUSED(result)
|
||||
Q_UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
template <class R>
|
||||
void setRequestLimit(R ¶meters, int limit) {
|
||||
Q_UNUSED(parameters)
|
||||
Q_UNUSED(limit)
|
||||
Q_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void setRequestStartIndex(P ¶meters, int startIndex) {
|
||||
Q_UNUSED(parameters)
|
||||
Q_UNUSED(startIndex)
|
||||
Q_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
/**
|
||||
* Template for implementing a loader for the given type, response and parameters
|
||||
* @tparam T type of which this loader should load a list of
|
||||
* @tparam D type of the DTO which can be converted into T using T(const D&, ApiClient*);
|
||||
* @tparam R type of the deserialized loader response
|
||||
* @tparam P type of the deserialized loader request parameters
|
||||
*/
|
||||
template <class T, class D, class R, class P>
|
||||
class LoaderModelLoader : public ModelLoader<T> {
|
||||
public:
|
||||
explicit LoaderModelLoader(Support::Loader<R, P> loader, QObject *parent = nullptr)
|
||||
: ModelLoader<T>(parent), m_loader(loader) { }
|
||||
protected:
|
||||
std::pair<QList<T>, int> loadMore(int offset, int limit) override {
|
||||
QMutexLocker(&this->m_mutex);
|
||||
// We never want to set this while the loader is running, hence the Mutex and setting it here
|
||||
// instead when Loader::setApiClient is called.
|
||||
this->m_loader.setApiClient(this->m_apiClient);
|
||||
try {
|
||||
setRequestStartIndex<P>(this->m_parameters, offset);
|
||||
setRequestLimit(this->m_parameters, limit);
|
||||
R result;
|
||||
try {
|
||||
std::optional<R> optResult = m_loader.load(this->m_parameters);
|
||||
if (!optResult.has_value()) {
|
||||
this->setStatus(ModelStatus::Error);
|
||||
return {QList<T>(), -1};
|
||||
}
|
||||
result = optResult.value();
|
||||
} catch (Support::LoadException e) {
|
||||
this->setStatus(ModelStatus::Error);
|
||||
return {QList<T>(), -1};
|
||||
}
|
||||
|
||||
QList<D> records = extractRecords<D, R>(result);
|
||||
int totalRecordCount = extractTotalRecordCount<R>(result);
|
||||
// If totalRecordCount < 0, it is not supported for this endpoint
|
||||
if (totalRecordCount < 0) {
|
||||
totalRecordCount = records.size();
|
||||
}
|
||||
QList<T> models;
|
||||
models.reserve(records.size());
|
||||
|
||||
// Convert the DTOs into models
|
||||
for (int i = 0; i < records.size(); i++) {
|
||||
models[i] = T(records[i], m_loader.apiClient());
|
||||
}
|
||||
this->setStatus(ModelStatus::Ready);
|
||||
return { models, totalRecordCount};
|
||||
} catch (Support::LoadException e) {
|
||||
//this->setErrorString(QString(e.what()));
|
||||
this->setStatus(ModelStatus::Error);
|
||||
return {QList<T>(), -1};
|
||||
}
|
||||
}
|
||||
Support::Loader<R, P> m_loader;
|
||||
QMutex m_mutex;
|
||||
P m_parameters;
|
||||
};
|
||||
|
||||
class BaseApiModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
BaseApiModel(QObject *parent = nullptr)
|
||||
: QAbstractListModel (parent) {}
|
||||
|
||||
Q_PROPERTY(BaseModelLoader *loader READ loader WRITE setLoader NOTIFY loaderChanged)
|
||||
|
||||
virtual BaseModelLoader *loader() const = 0;
|
||||
virtual void setLoader(BaseModelLoader *newLoader) {
|
||||
Q_UNUSED(newLoader);
|
||||
connect(newLoader, &BaseModelLoader::reloadWanted, this, &BaseApiModel::reload);
|
||||
emit loaderChanged();
|
||||
};
|
||||
public slots:
|
||||
virtual void reload();
|
||||
signals:
|
||||
void loaderChanged();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Abstract model for displaying a REST JSON collection. Role names will be based on the fields encountered in the
|
||||
|
@ -214,6 +303,10 @@ protected:
|
|||
* @endcode
|
||||
* The model will have roleNames for "name" and "id".
|
||||
*
|
||||
* @tparam T The class of the result.
|
||||
* @tparam R The class returned by the loader.
|
||||
* @tparam P The class with the request parameters for the loader.
|
||||
*
|
||||
*/
|
||||
template <class T>
|
||||
class ApiModel : public BaseApiModel {
|
||||
|
@ -246,156 +339,126 @@ public:
|
|||
* @endcode
|
||||
* responseHasRecords should be true
|
||||
*/
|
||||
explicit ApiModel(QString path, bool responseHasRecords, bool passUserId = false, QObject *parent = nullptr);
|
||||
explicit ApiModel(QObject *parent = nullptr)
|
||||
: BaseApiModel(parent) {
|
||||
m_futureWatcherConnection = connect(&m_futureWatcher, &QFutureWatcher<QList<T>>::finished,
|
||||
[&](){ futureFinished(); });
|
||||
}
|
||||
|
||||
// Standard QAbstractItemModel overrides
|
||||
int rowCount(const QModelIndex &index) const override {
|
||||
if (!index.isValid()) return m_array.size();
|
||||
return 0;
|
||||
}
|
||||
QHash<int, QByteArray> roleNames() const override { return m_roles; }
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
bool canFetchMore(const QModelIndex &parent) const override;
|
||||
void fetchMore(const QModelIndex &parent) override;
|
||||
|
||||
// Helper methods
|
||||
template<typename QEnum>
|
||||
QString enumToString (const QEnum anEnum) { return QVariant::fromValue(anEnum).toString(); }
|
||||
|
||||
// QList-like API
|
||||
T* at(int index) { return m_array.at(index); }
|
||||
int size() { return rowCount(QModelIndex()); }
|
||||
void insert(int index, T* object);
|
||||
void append(T* object) { insert(size(), object); }
|
||||
void removeAt(int index);
|
||||
void removeOne(T* object);
|
||||
T& at(int index) { return m_array.at(index); }
|
||||
/**
|
||||
* @return the amount of objects in this model.
|
||||
*/
|
||||
int size() {
|
||||
return m_array.size();
|
||||
}
|
||||
|
||||
template<typename QEnum>
|
||||
QString enumListToString (const QList<QEnum> enumList) {
|
||||
QString result;
|
||||
for (QEnum e : enumList) {
|
||||
result += QVariant::fromValue(e).toString() + ",";
|
||||
void insert(int index, T &object) {
|
||||
Q_ASSERT(index >= 0 && index <= size());
|
||||
this->beginInsertRows(QModelIndex(), index, index);
|
||||
m_array.insert(index, object);
|
||||
this->endInsertRows();
|
||||
}
|
||||
|
||||
void append(T &object) { insert(size(), object); }
|
||||
void append(QList<T> &objects) {
|
||||
int index = size();
|
||||
this->beginInsertRows(QModelIndex(), index, index + objects.size());
|
||||
m_array.append(objects);
|
||||
this->endInsertRows();
|
||||
};
|
||||
|
||||
void removeAt(int index) {
|
||||
this->beginRemoveRows(QModelIndex(), index, index);
|
||||
m_array.removeAt(index);
|
||||
this->endRemoveRows();
|
||||
}
|
||||
|
||||
void removeOne(T &object) {
|
||||
int idx = m_array.indexOf(object);
|
||||
if (idx >= 0) {
|
||||
removeAt(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// From AbstractListModel, gets implemented in ApiModel<T>
|
||||
//virtual QHash<int, QByteArray> roleNames() const override = 0;
|
||||
/*virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override = 0;*/
|
||||
virtual bool canFetchMore(const QModelIndex &parent) const override {
|
||||
if (parent.isValid()) return false;
|
||||
if (m_loader == nullptr) return false;
|
||||
return m_loader->canLoadMore();
|
||||
}
|
||||
virtual void fetchMore(const QModelIndex &parent) override {
|
||||
if (parent.isValid()) return;
|
||||
if (m_loader != nullptr) {
|
||||
QFuture<QList<T>> result = QtConcurrent::run(m_loader, &ModelLoader<T>::loadMore);
|
||||
m_futureWatcher.setFuture(result);
|
||||
}
|
||||
}
|
||||
|
||||
BaseModelLoader *loader() const override {
|
||||
return m_loader;
|
||||
}
|
||||
|
||||
void setLoader(BaseModelLoader *newLoader) {
|
||||
ModelLoader<T> *castedLoader = dynamic_cast<ModelLoader<T> *>(newLoader);
|
||||
if (castedLoader != nullptr) {
|
||||
m_loader = castedLoader;
|
||||
// Hacky way to emit a signal
|
||||
BaseApiModel::setLoader(newLoader);
|
||||
} else {
|
||||
qWarning() << "Somehow set a BaseModelLoader on ApiModel instead of a ModelLoader<T>";
|
||||
}
|
||||
}
|
||||
|
||||
void reload() override {
|
||||
if (m_loader != nullptr) {
|
||||
QFuture<QList<T>> result = QtConcurrent::run(m_loader, &ModelLoader<T>::reload);
|
||||
m_futureWatcher.setFuture(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
// AbstractItemModel bookkeeping
|
||||
QHash<int, QByteArray> m_roles;
|
||||
|
||||
// Helper methods.
|
||||
T *deserializeResult(QJsonValueRef source);
|
||||
virtual void addQueryParameters(QUrlQuery &query) override;
|
||||
virtual void replacePathPlaceholders(QString &path) override;
|
||||
|
||||
virtual void setModelData(QJsonArray &data) override;
|
||||
virtual void appendModelData(QJsonArray &data) override;
|
||||
|
||||
// Model-specific properties.
|
||||
QList<T*> m_array;
|
||||
QList<T> m_array;
|
||||
ModelLoader<T> *m_loader;
|
||||
QFutureWatcher<QList<T>> m_futureWatcher;
|
||||
|
||||
void futureFinished() {
|
||||
try {
|
||||
QList<T> result = m_futureWatcher.result();
|
||||
append(result);
|
||||
} catch (QUnhandledException &e) {
|
||||
qWarning() << "Unhandled exception while waiting for a future: " << e.what();
|
||||
}
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* @brief Generates roleNames based on the first record in m_array.
|
||||
*/
|
||||
void generateFields();
|
||||
QString sortByToString(SortOptions::SortBy sortBy);
|
||||
QMetaObject::Connection m_futureWatcherConnection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief List of the public users on the server.
|
||||
*/
|
||||
class PublicUserModel : public ApiModel<QJsonValue> {
|
||||
/*class PublicUserModel : public ApiModel<QJsonValue> {
|
||||
public:
|
||||
explicit PublicUserModel (QObject *parent = nullptr);
|
||||
};
|
||||
};*/
|
||||
|
||||
/**
|
||||
* @brief Base class for each model that works with items.
|
||||
*
|
||||
* Listens for updates in the library and updates the model accordingly.
|
||||
*/
|
||||
class ItemModel : public ApiModel<QJsonValue> {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ItemModel (QString path, bool responseHasRecords, bool replaceUser, QObject *parent = nullptr);
|
||||
// Query parameters
|
||||
Q_PROPERTY(QString parentId MEMBER m_parentId WRITE setParentId NOTIFY parentIdChanged)
|
||||
Q_PROPERTY(QString seasonId MEMBER m_seasonId NOTIFY seasonIdChanged)
|
||||
Q_PROPERTY(QList<QString> imageTypes MEMBER m_imageTypes NOTIFY imageTypesChanged)
|
||||
Q_PROPERTY(QList<QString> includeItemTypes MEMBER m_includeItemTypes NOTIFY includeItemTypesChanged)
|
||||
Q_PROPERTY(bool recursive MEMBER m_recursive)
|
||||
QList<QString> m_includeItemTypes = {};
|
||||
|
||||
// Path properties
|
||||
Q_PROPERTY(QString show MEMBER m_show NOTIFY showChanged)
|
||||
|
||||
void setParentId(const QString &parentId) {
|
||||
m_parentId = parentId;
|
||||
emit parentIdChanged(m_parentId);
|
||||
}
|
||||
signals:
|
||||
// Query property signals
|
||||
void parentIdChanged(QString newParentId);
|
||||
void seasonIdChanged(QString newSeasonId);
|
||||
void imageTypesChanged(QList<QString> newImageTypes);
|
||||
void includeItemTypesChanged(const QList<QString> &newIncludeItemTypes);
|
||||
|
||||
// Path property signals
|
||||
void showChanged(QString newShow);
|
||||
public slots:
|
||||
void onUserDataChanged(const QString &itemId, DTO::UserData *userData);
|
||||
protected:
|
||||
virtual void addQueryParameters(QUrlQuery &query) override;
|
||||
virtual void replacePathPlaceholders(QString &path) override;
|
||||
private:
|
||||
// Path properties
|
||||
QString m_show;
|
||||
|
||||
// Query parameters
|
||||
QString m_parentId;
|
||||
QString m_seasonId;
|
||||
QList<QString> m_imageTypes = {};
|
||||
bool m_recursive = false;
|
||||
};
|
||||
|
||||
//template<>
|
||||
//void ApiModel<Item>::apiClientChanged();
|
||||
|
||||
class UserViewModel : public ItemModel {
|
||||
public:
|
||||
explicit UserViewModel (QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
class UserItemModel : public ItemModel {
|
||||
public:
|
||||
explicit UserItemModel (QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
class UserItemResumeModel : public ItemModel {
|
||||
public:
|
||||
explicit UserItemResumeModel (QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
class UserItemLatestModel : public ItemModel {
|
||||
public:
|
||||
explicit UserItemLatestModel (QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
class ShowNextUpModel : public ItemModel {
|
||||
public:
|
||||
explicit ShowNextUpModel (QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
class ShowSeasonsModel : public ItemModel {
|
||||
public:
|
||||
explicit ShowSeasonsModel (QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
class ShowEpisodesModel : public ItemModel {
|
||||
public:
|
||||
explicit ShowEpisodesModel (QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
|
||||
void registerModels(const char *URI);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue