1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2024-05-07 14:52:42 +00:00

Fix a few bugs regarding loaders and models

* Properly keep track of the current offset and total recourd count in
  models.
* Catch exceptions and store them in errorString properties wherever
  applicable in loaders.
This commit is contained in:
Chris Josten 2021-08-23 01:48:35 +02:00
parent 1aae311b9b
commit 5ee2869db9
5 changed files with 77 additions and 36 deletions

View file

@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#define JELLYFIN_API_MODEL #define JELLYFIN_API_MODEL
#include <optional> #include <optional>
#include <typeinfo>
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QFlags> #include <QFlags>
@ -114,6 +115,7 @@ protected:
ApiClient *m_apiClient = nullptr; ApiClient *m_apiClient = nullptr;
bool m_autoReload = true; bool m_autoReload = true;
bool m_needsAuthentication = true; bool m_needsAuthentication = true;
bool m_manualLimitSet = false;
// Query/record controlling properties // Query/record controlling properties
int m_limit = -1; int m_limit = -1;
@ -158,7 +160,6 @@ public:
void reload() override { void reload() override {
if (!canReload()) { if (!canReload()) {
qDebug() << "Cannot yet reload ApiModel: canReload() returned false.";
return; return;
} }
m_startIndex = 0; m_startIndex = 0;
@ -169,7 +170,6 @@ public:
void loadMore() { void loadMore() {
if (!canReload()) { if (!canReload()) {
qDebug() << "Cannot yet reload ApiModel: canReload() returned false.";
return; return;
} }
loadMore(m_startIndex, m_limit, ViewModel::ModelStatus::LoadingMore); loadMore(m_startIndex, m_limit, ViewModel::ModelStatus::LoadingMore);
@ -198,10 +198,6 @@ protected:
* Either LOADING or LOAD_MORE. * Either LOADING or LOAD_MORE.
*/ */
virtual void loadMore(int offset, int limit, ViewModel::ModelStatus suggestedStatus) = 0; virtual void loadMore(int offset, int limit, ViewModel::ModelStatus suggestedStatus) = 0;
void updatePosition(int startIndex, int totalRecordCount) {
m_startIndex = startIndex;
m_totalRecordCount = totalRecordCount;
}
std::pair<QList<T*>, int> m_result; std::pair<QList<T*>, int> m_result;
}; };
@ -211,21 +207,21 @@ protected:
template <class T, class R> template <class T, class R>
QList<T> extractRecords(const R &result) { QList<T> extractRecords(const R &result) {
Q_UNUSED(result) Q_UNUSED(result)
Q_UNIMPLEMENTED(); qDebug() << "extractRecords not implemented for type " << typeid(R).name();
return QList<T>(); return QList<T>();
} }
template <class R> template <class R>
int extractTotalRecordCount(const R &result) { int extractTotalRecordCount(const R &result) {
Q_UNUSED(result) Q_UNUSED(result)
Q_UNIMPLEMENTED(); qDebug() << "extractTotalRecourdCount not implemented for type " << typeid(R).name();
return -1; return -1;
} }
template <class R> template <class P>
void setRequestLimit(R &parameters, int limit) { void setRequestLimit(P &parameters, int limit) {
Q_UNUSED(parameters) Q_UNUSED(parameters)
Q_UNUSED(limit) Q_UNUSED(limit)
Q_UNIMPLEMENTED(); qDebug() << "setRequestLimit not implemented for type " << typeid(P).name();
} }
/** /**
@ -235,7 +231,7 @@ template <class P>
bool setRequestStartIndex(P &parameters, int startIndex) { bool setRequestStartIndex(P &parameters, int startIndex) {
Q_UNUSED(parameters) Q_UNUSED(parameters)
Q_UNUSED(startIndex) Q_UNUSED(startIndex)
Q_UNIMPLEMENTED(); qDebug() << "setRequestStartIndex not implemented for type " << typeid(P).name();
return false; return false;
} }
@ -248,6 +244,10 @@ extern template QList<DTO::BaseItemDto> extractRecords(const QList<DTO::BaseItem
extern template int extractTotalRecordCount(const QList<DTO::BaseItemDto> &result); extern template int extractTotalRecordCount(const QList<DTO::BaseItemDto> &result);
extern template void setRequestLimit(Loader::GetLatestMediaParams &params, int limit); extern template void setRequestLimit(Loader::GetLatestMediaParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetLatestMediaParams &params, int offset); extern template bool setRequestStartIndex(Loader::GetLatestMediaParams &params, int offset);
extern template void setRequestLimit(Loader::GetItemsByUserIdParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetItemsByUserIdParams &params, int offset);
extern template void setRequestLimit(Loader::GetResumeItemsParams &params, int limit);
extern template bool setRequestStartIndex(Loader::GetResumeItemsParams &params, int offset);
extern template QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result); extern template QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result);
extern template int extractTotalRecordCount(const QList<DTO::UserDto> &result); extern template int extractTotalRecordCount(const QList<DTO::UserDto> &result);
@ -285,8 +285,16 @@ protected:
// meaning loadMore is not supported. // meaning loadMore is not supported.
return; return;
} }
if (limit > 0) { if (limit > 0) {
setRequestLimit<P>(this->m_parameters, limit); if (suggestedModelStatus == ViewModel::ModelStatus::Loading) {
setRequestLimit<P>(this->m_parameters, limit);
} else {
// If an explicit limit is set, we should load no more
return;
}
} else {
setRequestLimit<P>(this->m_parameters, this->DEFAULT_LIMIT);
} }
this->setStatus(suggestedModelStatus); this->setStatus(suggestedModelStatus);
@ -301,25 +309,32 @@ protected:
P m_parameters; P m_parameters;
void loaderReady() { void loaderReady() {
R result = m_loader->result(); try {
QList<D> records = extractRecords<D, R>(result); R result = m_loader->result();
int totalRecordCount = extractTotalRecordCount<R>(result); QList<D> records = extractRecords<D, R>(result);
qDebug() << "Total record count: " << totalRecordCount << ", records in request: " << records.size(); int totalRecordCount = extractTotalRecordCount<R>(result);
// If totalRecordCount < 0, it is not supported for this endpoint qDebug() << "Total record count: " << totalRecordCount << ", records in request: " << records.size();
if (totalRecordCount < 0) { // If totalRecordCount < 0, it is not supported for this endpoint
totalRecordCount = records.size(); if (totalRecordCount < 0) {
} totalRecordCount = records.size();
QList<T*> models; }
models.reserve(records.size()); QList<T*> models;
models.reserve(records.size());
// Convert the DTOs into models // Convert the DTOs into models
for (int i = 0; i < records.size(); i++) { for (int i = 0; i < records.size(); i++) {
models.append(new T(records[i], m_loader->apiClient())); models.append(new T(records[i], m_loader->apiClient()));
}
this->setStatus(ViewModel::ModelStatus::Ready);
this->m_result = { models, this->m_startIndex};
this->m_startIndex += records.size();
this->m_totalRecordCount = totalRecordCount;
this->emitItemsLoaded();
} catch(QException &e) {
qWarning() << "Error while loading data: " << e.what();
this->setStatus(ViewModel::ModelStatus::Error);
} }
this->setStatus(ViewModel::ModelStatus::Ready);
this->m_result = { models, this->m_startIndex};
this->m_startIndex += totalRecordCount;
this->emitItemsLoaded();
} }
void loaderError(QString error) { void loaderError(QString error) {

View file

@ -34,6 +34,7 @@
#include "viewmodel/item.h" #include "viewmodel/item.h"
#include "viewmodel/itemmodel.h" #include "viewmodel/itemmodel.h"
#include "viewmodel/loader.h" #include "viewmodel/loader.h"
#include "viewmodel/mediastream.h"
#include "viewmodel/modelstatus.h" #include "viewmodel/modelstatus.h"
#include "viewmodel/playbackmanager.h" #include "viewmodel/playbackmanager.h"
#include "viewmodel/playlist.h" #include "viewmodel/playlist.h"

View file

@ -225,16 +225,16 @@ private:
void onResponseParsed() { void onResponseParsed() {
Q_ASSERT(m_parsedWatcher.isFinished()); Q_ASSERT(m_parsedWatcher.isFinished());
if (m_parsedWatcher.result().has_value()) { try {
try { if (m_parsedWatcher.result().has_value()) {
this->m_result = m_parsedWatcher.result().value(); this->m_result = m_parsedWatcher.result().value();
this->m_isRunning = false; this->m_isRunning = false;
emit this->ready(); emit this->ready();
} catch (QException &e) { } else {
this->stopWithError(e.what()); this->m_isRunning = false;
} }
} else { } catch (QException &e) {
this->m_isRunning = false; this->stopWithError(e.what());
} }
} }
}; };

View file

@ -141,6 +141,29 @@ bool setRequestStartIndex(Loader::GetLatestMediaParams &params, int offset) {
return false; return false;
} }
template<>
void setRequestLimit(Loader::GetItemsByUserIdParams &params, int limit) {
params.setLimit(limit);
}
template<>
bool setRequestStartIndex(Loader::GetItemsByUserIdParams &params, int index) {
params.setLimit(index);
return true;
}
template<>
void setRequestLimit(Loader::GetResumeItemsParams &params, int limit) {
params.setLimit(limit);
}
template<>
bool setRequestStartIndex(Loader::GetResumeItemsParams &params, int index) {
params.setLimit(index);
return true;
}
template<> template<>
QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result) { QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result) {
return result; return result;

View file

@ -27,6 +27,7 @@ void registerTypes(const char *uri) {
qmlRegisterUncreatableType<ViewModel::User>(uri, 1, 0, "User", "Acquire one via UserLoader or exposed properties"); qmlRegisterUncreatableType<ViewModel::User>(uri, 1, 0, "User", "Acquire one via UserLoader or exposed properties");
qmlRegisterUncreatableType<EventBus>(uri, 1, 0, "EventBus", "Obtain one via your ApiClient"); qmlRegisterUncreatableType<EventBus>(uri, 1, 0, "EventBus", "Obtain one via your ApiClient");
qmlRegisterUncreatableType<WebSocket>(uri, 1, 0, "WebSocket", "Obtain one via your ApiClient"); qmlRegisterUncreatableType<WebSocket>(uri, 1, 0, "WebSocket", "Obtain one via your ApiClient");
qmlRegisterUncreatableType<ViewModel::MediaStream>(uri, 1, 0, "MediaStream", "Obtain one via an Item");
qmlRegisterUncreatableType<ViewModel::UserData>(uri, 1, 0, "UserData", "Obtain one via an Item"); qmlRegisterUncreatableType<ViewModel::UserData>(uri, 1, 0, "UserData", "Obtain one via an Item");
// AbstractItemModels // AbstractItemModels
@ -53,6 +54,7 @@ void registerTypes(const char *uri) {
qmlRegisterUncreatableType<Jellyfin::ViewModel::ModelStatusClass>(uri, 1, 0, "ModelStatus", "Is an enum"); qmlRegisterUncreatableType<Jellyfin::ViewModel::ModelStatusClass>(uri, 1, 0, "ModelStatus", "Is an enum");
qmlRegisterUncreatableType<Jellyfin::DTO::PlayMethodClass>(uri, 1, 0, "PlayMethod", "Is an enum"); qmlRegisterUncreatableType<Jellyfin::DTO::PlayMethodClass>(uri, 1, 0, "PlayMethod", "Is an enum");
qmlRegisterUncreatableType<Jellyfin::DTO::ItemFieldsClass>(uri, 1, 0, "ItemFields", "Is an enum"); qmlRegisterUncreatableType<Jellyfin::DTO::ItemFieldsClass>(uri, 1, 0, "ItemFields", "Is an enum");
qmlRegisterUncreatableType<Jellyfin::DTO::ImageTypeClass>(uri, 1, 0, "ImageType", "Is an enum");
qmlRegisterUncreatableType<Jellyfin::ViewModel::NowPlayingSection>(uri, 1, 0, "NowPlayingSection", "Is an enum"); qmlRegisterUncreatableType<Jellyfin::ViewModel::NowPlayingSection>(uri, 1, 0, "NowPlayingSection", "Is an enum");
qRegisterMetaType<Jellyfin::DTO::PlayMethodClass::Value>(); qRegisterMetaType<Jellyfin::DTO::PlayMethodClass::Value>();