mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2025-09-04 01:42:44 +00:00
Added user details and somewhat imporved error handling
* [UI] Improved: error handling should be slightly better * [UI] Improved: settings now show the user name and picture instead of the user id if network is available.
This commit is contained in:
parent
8a683df2a2
commit
d3a7c17586
11 changed files with 240 additions and 80 deletions
|
@ -126,9 +126,39 @@ signals:
|
|||
void apiClientChanged(ApiClient *newApiClient);
|
||||
void errorChanged(QNetworkReply::NetworkError newError);
|
||||
void errorStringChanged(QString newErrorString);
|
||||
/**
|
||||
* @brief Convenience signal for status == RemoteData.Ready.
|
||||
*/
|
||||
void ready();
|
||||
public slots:
|
||||
virtual void reload() = 0;
|
||||
|
||||
/**
|
||||
* @brief Overload this method to reimplement the fetching mechanism to
|
||||
* populate the RemoteData with data from the server.
|
||||
*
|
||||
* The default implementation makes a GET request to getDataUrl() and parses the resulting JSON,
|
||||
* which should be enough for most cases. Consider overriding getDataUrl() and
|
||||
* canRelaod() if possible. Manual overrides need to make sure that
|
||||
* they're calling setStatus(Status), setError(QNetworkReply::NetworkError) and
|
||||
* setErrorString() to let the QML side know what this thing is up to.
|
||||
*/
|
||||
virtual void reload();
|
||||
protected:
|
||||
/**
|
||||
* @brief Subclasses should implement this to determine if they can
|
||||
* load data from the server.
|
||||
*
|
||||
* Usage cases include checking if the
|
||||
* required properties, such as the item id are set.
|
||||
*/
|
||||
virtual bool canReload() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Construct the URL to fetch the data from.
|
||||
* @return The URL to load data from.
|
||||
*/
|
||||
virtual QString getDataUrl() const = 0;
|
||||
|
||||
void setStatus(Status newStatus);
|
||||
void setError(QNetworkReply::NetworkError error);
|
||||
void setErrorString(const QString &newErrorString);
|
||||
|
@ -139,6 +169,33 @@ private:
|
|||
QString m_errorString;
|
||||
};
|
||||
|
||||
class User : public RemoteData {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE User(QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(QString userId MEMBER m_userId WRITE setUserId NOTIFY userIdChanged)
|
||||
Q_PROPERTY(QString name MEMBER m_name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString primaryImageTag MEMBER m_primaryImageTag NOTIFY primaryImageTagChanged)
|
||||
|
||||
void setUserId(const QString &newUserId) {
|
||||
this->m_userId = newUserId;
|
||||
emit userIdChanged(newUserId);
|
||||
reload();
|
||||
}
|
||||
signals:
|
||||
void userIdChanged(const QString &newUserId);
|
||||
void nameChanged(const QString &newName);
|
||||
void primaryImageTagChanged(const QString &newPrimaryImageTag);
|
||||
protected:
|
||||
QString getDataUrl() const override;
|
||||
bool canReload() const override;
|
||||
private:
|
||||
QString m_userId;
|
||||
QString m_name;
|
||||
QString m_primaryImageTag;
|
||||
};
|
||||
|
||||
class MediaStream : public JsonSerializable {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -365,12 +422,12 @@ signals:
|
|||
void imageBlurHashesChanged();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief (Re)loads the item from the Jellyfin server.
|
||||
*/
|
||||
void reload() override;
|
||||
void onUserDataChanged(const QString &itemId, QSharedPointer<UserData> userData);
|
||||
protected:
|
||||
// Overrides
|
||||
QString getDataUrl() const override;
|
||||
bool canReload() const override;
|
||||
|
||||
QString m_id;
|
||||
QString m_name;
|
||||
QString m_originalTitle;
|
||||
|
|
|
@ -198,6 +198,7 @@ RemoteData::RemoteData(QObject *parent) : JsonSerializable (parent) {}
|
|||
void RemoteData::setStatus(Status newStatus) {
|
||||
m_status = newStatus;
|
||||
emit statusChanged(newStatus);
|
||||
if (newStatus == Ready) emit ready();
|
||||
}
|
||||
|
||||
void RemoteData::setError(QNetworkReply::NetworkError error) {
|
||||
|
@ -216,6 +217,54 @@ void RemoteData::setApiClient(ApiClient *newApiClient) {
|
|||
reload();
|
||||
}
|
||||
|
||||
void RemoteData::reload() {
|
||||
if (!canReload() || m_apiClient == nullptr) {
|
||||
setStatus(Uninitialised);
|
||||
return;
|
||||
} else {
|
||||
setStatus(Loading);
|
||||
}
|
||||
QNetworkReply *rep = m_apiClient->get(getDataUrl());
|
||||
connect(rep, &QNetworkReply::finished, this, [this, rep]() {
|
||||
rep->deleteLater();
|
||||
|
||||
QJsonParseError error;
|
||||
QString data(rep->readAll());
|
||||
data = data.normalized(QString::NormalizationForm_D);
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &error);
|
||||
if (doc.isNull()) {
|
||||
this->setError(QNetworkReply::ProtocolFailure);
|
||||
this->setErrorString(error.errorString());
|
||||
return;
|
||||
}
|
||||
if (!doc.isObject()) {
|
||||
this->setError(QNetworkReply::ProtocolFailure);
|
||||
this->setErrorString(tr("Invalid response from the server: root element is not an object."));
|
||||
return;
|
||||
}
|
||||
this->deserialize(doc.object());
|
||||
this->setStatus(Ready);
|
||||
});
|
||||
connect(rep, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
|
||||
this, [this, rep](QNetworkReply::NetworkError error) {
|
||||
this->setError(error);
|
||||
this->setErrorString(rep->errorString());
|
||||
this->setStatus(Error);
|
||||
rep->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
// User
|
||||
User::User(QObject *parent) : RemoteData (parent) {}
|
||||
|
||||
QString User::getDataUrl() const {
|
||||
return QString("/Users/") + m_apiClient->userId();
|
||||
}
|
||||
|
||||
bool User::canReload() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// MediaStream
|
||||
MediaStream::MediaStream(QObject *parent) : JsonSerializable (parent) {}
|
||||
MediaStream::MediaStream(const MediaStream &other)
|
||||
|
@ -277,6 +326,13 @@ Item::Item(QObject *parent) : RemoteData(parent) {
|
|||
});
|
||||
}
|
||||
|
||||
QString Item::getDataUrl() const {
|
||||
return QString("/Users/") + m_apiClient->userId() + "/Items/" + m_id;
|
||||
}
|
||||
|
||||
bool Item::canReload() const {
|
||||
return !m_id.isNull();
|
||||
}
|
||||
|
||||
void Item::setJellyfinId(QString newId) {
|
||||
m_id = newId.trimmed();
|
||||
|
@ -286,42 +342,7 @@ void Item::setJellyfinId(QString newId) {
|
|||
}
|
||||
}
|
||||
|
||||
void Item::reload() {
|
||||
if (m_id.isEmpty() || m_apiClient == nullptr) {
|
||||
setStatus(Uninitialised);
|
||||
return;
|
||||
} else {
|
||||
setStatus(Loading);
|
||||
}
|
||||
QNetworkReply *rep = m_apiClient->get("/Users/" + m_apiClient->userId() + "/Items/" + m_id);
|
||||
connect(rep, &QNetworkReply::finished, this, [this, rep]() {
|
||||
rep->deleteLater();
|
||||
|
||||
QJsonParseError error;
|
||||
QString data(rep->readAll());
|
||||
data = data.normalized(QString::NormalizationForm_D);
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &error);
|
||||
if (doc.isNull()) {
|
||||
this->setError(QNetworkReply::ProtocolFailure);
|
||||
this->setErrorString(error.errorString());
|
||||
return;
|
||||
}
|
||||
if (!doc.isObject()) {
|
||||
this->setError(QNetworkReply::ProtocolFailure);
|
||||
this->setErrorString(tr("Invalid response from the server: root element is not an object."));
|
||||
return;
|
||||
}
|
||||
this->deserialize(doc.object());
|
||||
this->setStatus(Ready);
|
||||
});
|
||||
connect(rep, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
|
||||
this, [this, rep](QNetworkReply::NetworkError error) {
|
||||
rep->deleteLater();
|
||||
this->setError(error);
|
||||
this->setErrorString(rep->errorString());
|
||||
this->setStatus(Error);
|
||||
});
|
||||
}
|
||||
|
||||
void Item::onUserDataChanged(const QString &itemId, QSharedPointer<UserData> userData) {
|
||||
if (itemId != m_id || m_userData == nullptr) return;
|
||||
|
@ -330,6 +351,7 @@ void Item::onUserDataChanged(const QString &itemId, QSharedPointer<UserData> use
|
|||
|
||||
void registerSerializableJsonTypes(const char* URI) {
|
||||
qmlRegisterType<MediaStream>(URI, 1, 0, "MediaStream");
|
||||
qmlRegisterType<User>(URI, 1, 0, "User");
|
||||
qmlRegisterType<UserData>(URI, 1, 0, "UserData");
|
||||
qmlRegisterType<Item>(URI, 1, 0, "JellyfinItem");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue