1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2025-09-04 01:42:44 +00:00

Moved playback logic to C++-side (and refractoring)

This commit is contained in:
Chris Josten 2021-02-20 23:20:39 +01:00
parent 895731ae38
commit f7bca333c8
35 changed files with 1063 additions and 449 deletions

View file

@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include <QJsonDocument>
#include <QJsonObject>
#include <QtQml>
#include <QQmlParserStatus>
#include <QVariant>
#include "apiclient.h"
@ -35,9 +36,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
namespace Jellyfin {
namespace DTO {
class Item;
class JsonSerializable;
class User;
}
class SortOptions : public QObject{
class SortOptions : public QObject {
Q_OBJECT
public:
explicit SortOptions (QObject *parent = nullptr) : QObject(parent) {}
@ -61,6 +64,134 @@ public:
Q_ENUM(SortBy)
};
/**
* Q_OBJECT does not support template classes. This base class declares the
* Q_OBJECT related properties and signals.
*/
class BaseApiModel : public QAbstractListModel, public QQmlParserStatus {
Q_OBJECT
public:
explicit BaseApiModel(QString path, bool hasRecordResponse, bool addUserId, QObject *parent = nullptr);
enum ModelStatus {
Uninitialised,
Loading,
Ready,
Error,
LoadingMore
};
Q_ENUM(ModelStatus)
enum SortOrder {
Unspecified,
Ascending,
Descending
};
Q_ENUM(SortOrder)
Q_PROPERTY(ApiClient *apiClient MEMBER m_apiClient NOTIFY apiClientChanged)
Q_PROPERTY(ModelStatus status READ status NOTIFY statusChanged)
// 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)
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;
signals:
void ready();
void apiClientChanged(ApiClient *newApiClient);
void statusChanged(ModelStatus newStatus);
void limitChanged(int newLimit);
void sortByChanged(QList<QString> newSortOrder);
void sortOrderChanged(SortOrder newSortOrder);
void fieldsChanged(QList<QString> newFields);
public slots:
/**
* @brief (Re)loads the data into this model. This might make a network request.
*/
void reload();
protected:
enum LoadType {
RELOAD,
LOAD_MORE
};
ApiClient *m_apiClient = nullptr;
bool m_isBeingParsed = false;
// Per-model specific settings.
QString m_path;
bool m_hasRecordResponse;
bool m_addUserId;
bool padding; bool padding2;
// Query/record controlling properties
int m_limit = -1;
int m_startIndex = 0;
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;
void setStatus(ModelStatus newStatus) {
if (this->m_status != newStatus) {
this->m_status = newStatus;
emit this->statusChanged(newStatus);
if (m_status == 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;
};
/**
* @brief Abstract model for displaying a REST JSON collection. Role names will be based on the fields encountered in the
@ -86,25 +217,9 @@ public:
* The model will have roleNames for "name" and "id".
*
*/
class ApiModel : public QAbstractListModel {
Q_OBJECT
template <typename T>
class ApiModel : public BaseApiModel {
public:
enum ModelStatus {
Uninitialised,
Loading,
Ready,
Error,
LoadingMore
};
Q_ENUM(ModelStatus)
enum SortOrder {
Unspecified,
Ascending,
Descending
};
Q_ENUM(SortOrder)
/**
* @brief Creates a new basemodel
* @param path The path (relative to the baseUrl of JellyfinApiClient) to make the call to.
@ -134,22 +249,6 @@ public:
* responseHasRecords should be true
*/
explicit ApiModel(QString path, bool responseHasRecords, bool passUserId = false, QObject *parent = nullptr);
Q_PROPERTY(ApiClient *apiClient MEMBER m_apiClient NOTIFY apiClientChanged)
Q_PROPERTY(ModelStatus status READ status NOTIFY statusChanged)
// Query properties
Q_PROPERTY(int limit MEMBER m_limit NOTIFY limitChanged)
Q_PROPERTY(QString parentId MEMBER m_parentId NOTIFY parentIdChanged)
Q_PROPERTY(QList<QString> sortBy MEMBER m_sortBy NOTIFY sortByChanged)
Q_PROPERTY(QList<QString> fields MEMBER m_fields NOTIFY fieldsChanged)
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)
Q_PROPERTY(SortOrder sortOrder MEMBER m_sortOrder NOTIFY sortOrderChanged)
// Path properties
Q_PROPERTY(QString show MEMBER m_show NOTIFY showChanged)
// Standard QAbstractItemModel overrides
int rowCount(const QModelIndex &index) const override {
@ -161,12 +260,18 @@ public:
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
ModelStatus status() const { return m_status; }
// 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);
template<typename QEnum>
QString enumListToString (const QList<QEnum> enumList) {
QString result;
@ -176,74 +281,20 @@ public:
return result;
}
signals:
void apiClientChanged(ApiClient *newApiClient);
void statusChanged(ModelStatus newStatus);
void limitChanged(int newLimit);
void parentIdChanged(QString newParentId);
void sortByChanged(QList<QString> newSortOrder);
void sortOrderChanged(SortOrder newSortOrder);
void showChanged(QString newShow);
void seasonIdChanged(QString newSeasonId);
void fieldsChanged(QList<QString> newFields);
void imageTypesChanged(QList<QString> newImageTypes);
void includeItemTypesChanged(const QList<QString> &newIncludeItemTypes);
public slots:
/**
* @brief (Re)loads the data into this model. This might make a network request.
*/
void reload();
protected:
enum LoadType {
RELOAD,
LOAD_MORE
};
void load(LoadType loadType);
/**
* @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.
*/
virtual void addQueryParameters(QUrlQuery &query);
ApiClient *m_apiClient = nullptr;
ModelStatus m_status = Uninitialised;
QString m_path;
QJsonArray m_array;
bool m_hasRecordResponse;
// Path properties
QString m_show;
// Query/record controlling properties
int m_limit = -1;
int m_startIndex = 0;
int m_totalRecordCount = 0;
const int DEFAULT_LIMIT = 100;
// Query properties
bool m_addUserId = false;
QString m_parentId;
QString m_seasonId;
QList<QString> m_fields = {};
QList<QString> m_imageTypes = {};
QList<QString> m_sortBy = {};
QList<QString> m_includeItemTypes = {};
SortOrder m_sortOrder = Unspecified;
bool m_recursive = false;
// AbstractItemModel bookkeeping
QHash<int, QByteArray> m_roles;
void setStatus(ModelStatus newStatus) {
this->m_status = newStatus;
emit this->statusChanged(newStatus);
}
// 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;
private:
/**
@ -256,7 +307,7 @@ private:
/**
* @brief List of the public users on the server.
*/
class PublicUserModel : public ApiModel {
class PublicUserModel : public ApiModel<User> {
public:
explicit PublicUserModel (QObject *parent = nullptr);
};
@ -266,15 +317,54 @@ public:
*
* Listens for updates in the library and updates the model accordingly.
*/
class ItemModel : public ApiModel {
class ItemModel : public ApiModel<Item> {
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, QSharedPointer<DTO::UserData> userData);
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;
};
class UserViewModel : public ApiModel {
//template<>
//void ApiModel<Item>::apiClientChanged();
class UserViewModel : public ItemModel {
public:
explicit UserViewModel (QObject *parent = nullptr);
};