mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2025-09-04 01:42:44 +00:00
Fix a few bugs and unimplemented features
* Show the now playing cover when playing an item, otherwise show the collection cover. * ItemModelLoaders now correctly expose list properties of non-built-in Qt objects * toString is now implemented for lists, fixing some query construction code. * PlaybackManager now clears the playlist when playing a single item to prevent weird behaviour. * The covers are slightly updated.
This commit is contained in:
parent
60bc90c5fa
commit
caf72af999
19 changed files with 179 additions and 81 deletions
|
@ -47,6 +47,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "support/loader.h"
|
||||
#include "viewmodel/modelstatus.h"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(jellyfinApiModel)
|
||||
|
||||
namespace Jellyfin {
|
||||
|
||||
/*
|
||||
|
@ -121,6 +123,7 @@ protected:
|
|||
int m_limit = -1;
|
||||
int m_startIndex = 0;
|
||||
int m_totalRecordCount = 0;
|
||||
bool m_explicitLimitSet = false;
|
||||
const int DEFAULT_LIMIT = 100;
|
||||
void emitModelShouldClear() { emit modelShouldClear(); }
|
||||
void emitItemsLoaded() { emit itemsLoaded(); }
|
||||
|
@ -165,14 +168,14 @@ public:
|
|||
m_startIndex = 0;
|
||||
m_totalRecordCount = -1;
|
||||
emitModelShouldClear();
|
||||
loadMore(0, m_limit, ViewModel::ModelStatus::Loading);
|
||||
loadMore(ViewModel::ModelStatus::Loading);
|
||||
}
|
||||
|
||||
void loadMore() {
|
||||
if (!canReload()) {
|
||||
return;
|
||||
}
|
||||
loadMore(m_startIndex, m_limit, ViewModel::ModelStatus::LoadingMore);
|
||||
loadMore(ViewModel::ModelStatus::LoadingMore);
|
||||
}
|
||||
|
||||
virtual bool canLoadMore() const {
|
||||
|
@ -192,12 +195,10 @@ protected:
|
|||
* The itemsLoaded() signal is emitted when new data is ready. Call
|
||||
* getLoadedItems to retrieve the loaded items.
|
||||
*
|
||||
* @param offset The offset to start loading items from
|
||||
* @param limit The maximum amount of items to load.
|
||||
* @param suggestedStatus The suggested status this model should take on if it is able to load (more).
|
||||
* Either LOADING or LOAD_MORE.
|
||||
*/
|
||||
virtual void loadMore(int offset, int limit, ViewModel::ModelStatus suggestedStatus) = 0;
|
||||
virtual void loadMore(ViewModel::ModelStatus suggestedStatus) = 0;
|
||||
std::pair<QList<T*>, int> m_result;
|
||||
};
|
||||
|
||||
|
@ -270,7 +271,7 @@ public:
|
|||
this->connect(m_loader.data(), &Support::Loader<R, P>::error, this, &LoaderModelLoader<T, D, R, P>::loaderError);
|
||||
}
|
||||
protected:
|
||||
void loadMore(int offset, int limit, ViewModel::ModelStatus suggestedModelStatus) override {
|
||||
void loadMore(ViewModel::ModelStatus suggestedModelStatus) override {
|
||||
// This method should only be callable on one thread.
|
||||
// If futureWatcher's future is running, this method should not be called again.
|
||||
if (m_loader->isRunning()) {
|
||||
|
@ -279,20 +280,22 @@ protected:
|
|||
// Set an invalid result.
|
||||
this->m_result = { QList<T*>(), -1 };
|
||||
|
||||
if (!setRequestStartIndex<P>(this->m_parameters, offset)
|
||||
if (!setRequestStartIndex<P>(this->m_parameters, this->m_startIndex)
|
||||
&& suggestedModelStatus == ViewModel::ModelStatus::LoadingMore) {
|
||||
// This loader's parameters does not setting a starting index,
|
||||
// meaning loadMore is not supported.
|
||||
return;
|
||||
}
|
||||
setRequestStartIndex<P>(this->m_parameters, this->m_startIndex);
|
||||
|
||||
if (limit > 0) {
|
||||
if (suggestedModelStatus == ViewModel::ModelStatus::Loading) {
|
||||
setRequestLimit<P>(this->m_parameters, limit);
|
||||
} else {
|
||||
// If an explicit limit is set, we should load no more
|
||||
return;
|
||||
}
|
||||
if (suggestedModelStatus == ViewModel::ModelStatus::LoadingMore && this->m_explicitLimitSet) {
|
||||
// If an explicit limit is set, we should load no more
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(jellyfinApiModel) << "Explicit limit set: " << this->m_explicitLimitSet << ", " << this->m_limit;
|
||||
if (this->m_explicitLimitSet) {
|
||||
setRequestLimit<P>(this->m_parameters, this->m_limit);
|
||||
} else {
|
||||
setRequestLimit<P>(this->m_parameters, this->DEFAULT_LIMIT);
|
||||
}
|
||||
|
|
|
@ -100,6 +100,12 @@ public:
|
|||
*/
|
||||
void appendToList(ViewModel::ItemModel &model);
|
||||
|
||||
/**
|
||||
* @brief appendToList Appends a single item to the current list
|
||||
* @param item The item to append
|
||||
*/
|
||||
void appendToList(QSharedPointer<Model::Item> item);
|
||||
|
||||
/**
|
||||
* @brief Start playing this playlist
|
||||
* @param index The index to start from.
|
||||
|
|
|
@ -139,6 +139,12 @@ QJsonValue toJsonValue(const QSharedPointer<T> &source, convertType<QSharedPoint
|
|||
* Templates for string conversion.
|
||||
*/
|
||||
|
||||
|
||||
template <typename T>
|
||||
QString toString(const T &source) {
|
||||
return toString(source, convertType<T>{});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QString toString(const T &source, convertType<T>) {
|
||||
return toJsonValue(source).toString();
|
||||
|
@ -154,11 +160,15 @@ QString toString(const std::optional<T> &source, convertType<std::optional<T>>)
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
QString toString(const T &source) {
|
||||
return toString(source, convertType<T>{});
|
||||
QString toString(const QList<T> &source, convertType<QList<T>>) {
|
||||
QStringList tmp;
|
||||
tmp.reserve(source.size());
|
||||
for (auto it = source.cbegin(); it != source.cend(); it++) {
|
||||
tmp.append(toString<T>(*it, convertType<T>{}));
|
||||
}
|
||||
return tmp.join(',');
|
||||
}
|
||||
|
||||
|
||||
} // NS Support
|
||||
} // NS Jellyfin
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QAbstractListModel>
|
||||
#include <QObject>
|
||||
#include <QScopedPointer>
|
||||
#include <QVariantList>
|
||||
|
||||
#include "../dto/baseitemdto.h"
|
||||
#include "../dto/baseitemdtoqueryresult.h"
|
||||
|
@ -45,6 +46,31 @@
|
|||
Q_SIGNALS: \
|
||||
void propName##Changed();
|
||||
|
||||
#define FWDLISTPROP(type, propName, propSetName) \
|
||||
public: \
|
||||
Q_PROPERTY(QVariantList propName READ propName WRITE set##propSetName NOTIFY propName##Changed) \
|
||||
QVariantList propName() const { \
|
||||
QVariantList result; \
|
||||
QList<type> list; \
|
||||
result.reserve(list.size()); \
|
||||
for (auto it = list.cbegin(); it != list.cend(); it++) { \
|
||||
result.append(QVariant::fromValue<type>(*it)); \
|
||||
} \
|
||||
return result; \
|
||||
} \
|
||||
void set##propSetName(const QVariantList &newValue) { \
|
||||
QList<type> list;\
|
||||
list.reserve(newValue.size()); \
|
||||
for(auto it = newValue.cbegin(); it != newValue.cend(); it++) { \
|
||||
list.append(it->value<type>()); \
|
||||
} \
|
||||
this->m_parameters.set##propSetName(list); \
|
||||
emit propName##Changed(); \
|
||||
autoReloadIfNeeded(); \
|
||||
} \
|
||||
Q_SIGNALS: \
|
||||
void propName##Changed();
|
||||
|
||||
namespace Jellyfin {
|
||||
|
||||
namespace ViewModel {
|
||||
|
@ -112,7 +138,7 @@ public:
|
|||
FWDPROP(QList<Jellyfin::DTO::ImageTypeClass::Value>, enableImageTypes, EnableImageTypes)
|
||||
FWDPROP(bool, enableImages, EnableImages)
|
||||
FWDPROP(bool, enableUserData, EnableUserData)
|
||||
FWDPROP(QList<Jellyfin::DTO::ItemFieldsClass::Value>, fields, Fields)
|
||||
FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
|
||||
FWDPROP(bool, groupItems, GroupItems)
|
||||
FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
|
||||
FWDPROP(QStringList, includeItemTypes, IncludeItemTypes)
|
||||
|
@ -134,7 +160,7 @@ public:
|
|||
FWDPROP(QStringList, artists, Artists)
|
||||
FWDPROP(bool, collapseBoxSetItems, CollapseBoxSetItems)
|
||||
FWDPROP(QStringList, contributingArtistIds, ContributingArtistIds)
|
||||
FWDPROP(QList<Jellyfin::DTO::ImageTypeClass::Value>, enableImageTypes, EnableImageTypes);
|
||||
FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, enableImageTypes, EnableImageTypes);
|
||||
FWDPROP(bool, enableImages, EnableImages)
|
||||
FWDPROP(bool, enableTotalRecordCount, EnableTotalRecordCount)
|
||||
FWDPROP(bool, enableUserData, EnableUserData)
|
||||
|
@ -142,8 +168,8 @@ public:
|
|||
FWDPROP(QStringList, excludeItemIds, ExcludeItemIds)
|
||||
FWDPROP(QStringList, excludeItemTypes, ExcludeItemTypes)
|
||||
FWDPROP(QList<Jellyfin::DTO::LocationTypeClass::Value>, excludeLocationTypes, ExcludeLocationTypes)
|
||||
FWDPROP(QList<Jellyfin::DTO::ItemFieldsClass::Value>, fields, Fields)
|
||||
FWDPROP(QList<Jellyfin::DTO::ItemFilterClass::Value>, filters, Filters)
|
||||
FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
|
||||
FWDLISTPROP(Jellyfin::DTO::ItemFilterClass::Value, filters, Filters)
|
||||
FWDPROP(QStringList, genreIds, GenreIds)
|
||||
FWDPROP(QStringList, genres, Genres)
|
||||
FWDPROP(bool, hasImdbId, HasImdbId)
|
||||
|
@ -159,7 +185,7 @@ public:
|
|||
FWDPROP(bool, hasTvdbId, HasTvdbId)
|
||||
FWDPROP(QStringList, ids, Ids)
|
||||
FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
|
||||
FWDPROP(QList<Jellyfin::DTO::ImageTypeClass::Value>, imageTypes, ImageTypes)
|
||||
FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, imageTypes, ImageTypes)
|
||||
FWDPROP(QStringList, includeItemTypes, IncludeItemTypes)
|
||||
FWDPROP(bool, is3D, Is3D)
|
||||
FWDPROP(bool, is4K, Is4K)
|
||||
|
@ -170,8 +196,7 @@ public:
|
|||
FWDPROP(bool, isPlaceHolder, IsPlaceHolder)
|
||||
FWDPROP(bool, isPlayed, IsPlayed)
|
||||
FWDPROP(bool, isUnaired, IsUnaired)
|
||||
FWDPROP(int, limit, Limit)
|
||||
FWDPROP(QList<Jellyfin::DTO::LocationTypeClass::Value>, locationTypes, LocationTypes)
|
||||
FWDLISTPROP(Jellyfin::DTO::LocationTypeClass::Value, locationTypes, LocationTypes)
|
||||
FWDPROP(qint32, maxHeight, MaxHeight)
|
||||
FWDPROP(QString, maxOfficialRating, MaxOfficialRating)
|
||||
FWDPROP(QDateTime, maxPremiereDate, MaxPremiereDate)
|
||||
|
@ -198,12 +223,12 @@ class ResumeItemsLoader : public ResumeItemsLoaderBase {
|
|||
public:
|
||||
explicit ResumeItemsLoader(QObject *parent = nullptr);
|
||||
|
||||
FWDPROP(QList<Jellyfin::DTO::ImageTypeClass::Value>, enableImageTypes, EnableImageTypes);
|
||||
FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, enableImageTypes, EnableImageTypes);
|
||||
FWDPROP(bool, enableImages, EnableImages)
|
||||
FWDPROP(bool, enableTotalRecordCount, EnableTotalRecordCount)
|
||||
FWDPROP(bool, enableUserData, EnableUserData)
|
||||
FWDPROP(QStringList, excludeItemTypes, ExcludeItemTypes)
|
||||
FWDPROP(QList<Jellyfin::DTO::ItemFieldsClass::Value>, fields, Fields)
|
||||
FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
|
||||
FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
|
||||
FWDPROP(QStringList, includeItemTypes, IncludeItemTypes)
|
||||
FWDPROP(QStringList, mediaTypes, MediaTypes)
|
||||
|
@ -219,10 +244,10 @@ public:
|
|||
|
||||
FWDPROP(QString, seriesId, SeriesId)
|
||||
FWDPROP(QString, adjacentTo, AdjacentTo)
|
||||
FWDPROP(QList<Jellyfin::DTO::ImageTypeClass::Value>, enableImageTypes, EnableImageTypes)
|
||||
FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, enableImageTypes, EnableImageTypes)
|
||||
FWDPROP(bool, enableImages, EnableImages)
|
||||
FWDPROP(bool, enableUserData, EnableUserData)
|
||||
FWDPROP(QList<Jellyfin::DTO::ItemFieldsClass::Value>, fields, Fields)
|
||||
FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
|
||||
FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
|
||||
FWDPROP(bool, isMissing, IsMissing)
|
||||
FWDPROP(bool, isSpecialSeason, IsSpecialSeason)
|
||||
|
@ -239,7 +264,7 @@ public:
|
|||
FWDPROP(QString, adjacentTo, AdjacentTo)
|
||||
FWDPROP(bool, enableImages, EnableImages)
|
||||
FWDPROP(bool, enableUserData, EnableUserData)
|
||||
FWDPROP(QList<Jellyfin::DTO::ItemFieldsClass::Value>, fields, Fields)
|
||||
FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
|
||||
FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
|
||||
FWDPROP(bool, isMissing, IsMissing)
|
||||
FWDPROP(qint32, season, Season)
|
||||
|
@ -248,6 +273,23 @@ public:
|
|||
FWDPROP(QString, startItemId, StartItemId)
|
||||
};
|
||||
|
||||
using NextUpLoaderBase = AbstractUserParameterLoader<Model::Item, DTO::BaseItemDto, DTO::BaseItemDtoQueryResult, Jellyfin::Loader::GetNextUpParams>;
|
||||
class NextUpLoader : public NextUpLoaderBase {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NextUpLoader(QObject *parent = nullptr);
|
||||
|
||||
FWDPROP(bool, disableFirstEpisode, DisableFirstEpisode)
|
||||
FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, enableImageTypes, EnableImageTypes);
|
||||
FWDPROP(bool, enableImges, EnableImges)
|
||||
FWDPROP(bool, enableTotalRecordCount, EnableTotalRecordCount)
|
||||
FWDPROP(bool, enableUserData, EnableUserData)
|
||||
FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
|
||||
FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
|
||||
FWDPROP(QString, parentId, ParentId)
|
||||
FWDPROP(QString, seriesId, SeriesId)
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Base class for each model that works with items.
|
||||
|
@ -278,6 +320,7 @@ public:
|
|||
runTimeTicks,
|
||||
artists,
|
||||
isFolder,
|
||||
overview,
|
||||
parentIndexNumber,
|
||||
userDataRating,
|
||||
userDataPlayedPercentage,
|
||||
|
@ -317,6 +360,7 @@ public:
|
|||
JFRN(runTimeTicks),
|
||||
JFRN(artists),
|
||||
JFRN(isFolder),
|
||||
JFRN(overview),
|
||||
JFRN(parentIndexNumber),
|
||||
JFRN(userDataRating),
|
||||
JFRN(userDataPlayedPercentage),
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
: QObject(parent), m_apiClient(apiClient) {}
|
||||
|
||||
Q_PROPERTY(ApiClient *apiClient MEMBER m_apiClient WRITE setApiClient NOTIFY apiClientChanged STORED false)
|
||||
Q_PROPERTY(Status status READ status NOTIFY statusChanged STORED false)
|
||||
Q_PROPERTY(Jellyfin::ViewModel::LoaderBase::Status status READ status NOTIFY statusChanged STORED false)
|
||||
Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged STORED false)
|
||||
Q_PROPERTY(bool autoReload MEMBER m_autoReload NOTIFY autoReloadChanged)
|
||||
Q_PROPERTY(QObject *data READ data NOTIFY dataChanged STORED false)
|
||||
|
@ -73,7 +73,7 @@ public:
|
|||
void setApiClient(ApiClient *newApiClient);
|
||||
void setExtraFields(const QStringList &extraFields);
|
||||
signals:
|
||||
void statusChanged(Status newStatus);
|
||||
void statusChanged(Jellyfin::ViewModel::LoaderBase::Status newStatus);
|
||||
void apiClientChanged(ApiClient *newApiClient);
|
||||
void errorStringChanged(QString newErrorString);
|
||||
void autoReloadChanged(bool newAutoReload);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue