mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2024-11-22 01:05:17 +00:00
Added settings, logout and improved error states
This commit is contained in:
parent
edb514bf2d
commit
67c8621d6f
|
@ -32,6 +32,7 @@ DISTFILES += \
|
||||||
qml/Constants.qml \
|
qml/Constants.qml \
|
||||||
qml/Utils.js \
|
qml/Utils.js \
|
||||||
qml/components/GlassyBackground.qml \
|
qml/components/GlassyBackground.qml \
|
||||||
|
qml/components/IconListItem.qml \
|
||||||
qml/components/LibraryItemDelegate.qml \
|
qml/components/LibraryItemDelegate.qml \
|
||||||
qml/components/MoreSection.qml \
|
qml/components/MoreSection.qml \
|
||||||
qml/components/PlainLabel.qml \
|
qml/components/PlainLabel.qml \
|
||||||
|
@ -54,6 +55,7 @@ DISTFILES += \
|
||||||
qml/pages/MainPage.qml \
|
qml/pages/MainPage.qml \
|
||||||
qml/pages/AboutPage.qml \
|
qml/pages/AboutPage.qml \
|
||||||
qml/harbour-sailfin.qml \
|
qml/harbour-sailfin.qml \
|
||||||
|
qml/pages/SettingsPage.qml \
|
||||||
qml/pages/VideoPage.qml \
|
qml/pages/VideoPage.qml \
|
||||||
qml/pages/setup/AddServerConnectingPage.qml \
|
qml/pages/setup/AddServerConnectingPage.qml \
|
||||||
qml/pages/setup/LoginDialog.qml \
|
qml/pages/setup/LoginDialog.qml \
|
||||||
|
|
27
qml/components/IconListItem.qml
Normal file
27
qml/components/IconListItem.qml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
import Sailfish.Silica 1.0
|
||||||
|
|
||||||
|
BackgroundItem {
|
||||||
|
property alias text: label.text
|
||||||
|
property alias iconSource: icon.source
|
||||||
|
HighlightImage {
|
||||||
|
id: icon
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: Theme.paddingMedium
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: Theme.horizontalPageMargin
|
||||||
|
bottom: parent.bottom
|
||||||
|
bottomMargin: Theme.paddingMedium
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: label
|
||||||
|
anchors {
|
||||||
|
left: icon.right
|
||||||
|
leftMargin: Theme.paddingMedium
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import Sailfish.Silica 1.0
|
||||||
HighlightImage {
|
HighlightImage {
|
||||||
property string fallbackImage
|
property string fallbackImage
|
||||||
property bool usingFallbackImage
|
property bool usingFallbackImage
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
BusyIndicator {
|
BusyIndicator {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
|
@ -13,6 +13,14 @@ ApplicationWindow {
|
||||||
property bool _hasInitialized: false
|
property bool _hasInitialized: false
|
||||||
// The global mediaPlayer instance
|
// The global mediaPlayer instance
|
||||||
readonly property MediaPlayer mediaPlayer: _mediaPlayer
|
readonly property MediaPlayer mediaPlayer: _mediaPlayer
|
||||||
|
property url backgroundSource
|
||||||
|
onBackgroundSourceChanged: {
|
||||||
|
if (backgroundSource) {
|
||||||
|
appWindow._overlayBackgroundSource.backgroundItem.source = backgroundSource
|
||||||
|
} else {
|
||||||
|
appWindow._overlayBackgroundSource.backgroundItem.source = Theme.backgroundImage
|
||||||
|
}
|
||||||
|
}
|
||||||
// Data of the currently selected item. For use on the cover.
|
// Data of the currently selected item. For use on the cover.
|
||||||
property var itemData
|
property var itemData
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ Page {
|
||||||
readonly property string _logo: itemData.ImageTags.Logo
|
readonly property string _logo: itemData.ImageTags.Logo
|
||||||
readonly property var _backdropImages: itemData.BackdropImageTags
|
readonly property var _backdropImages: itemData.BackdropImageTags
|
||||||
readonly property var _parentBackdropImages: itemData.ParentBackdropImageTags
|
readonly property var _parentBackdropImages: itemData.ParentBackdropImageTags
|
||||||
readonly property string parentId: itemData.ParentId
|
readonly property string parentId: itemData.ParentId || ""
|
||||||
|
|
||||||
on_BackdropImagesChanged: updateBackdrop()
|
on_BackdropImagesChanged: updateBackdrop()
|
||||||
on_ParentBackdropImagesChanged: updateBackdrop()
|
on_ParentBackdropImagesChanged: updateBackdrop()
|
||||||
|
@ -30,10 +30,13 @@ Page {
|
||||||
if (_backdropImages && _backdropImages.length > 0) {
|
if (_backdropImages && _backdropImages.length > 0) {
|
||||||
var rand = Math.floor(Math.random() * (_backdropImages.length - 0.001))
|
var rand = Math.floor(Math.random() * (_backdropImages.length - 0.001))
|
||||||
console.log("Random: ", rand)
|
console.log("Random: ", rand)
|
||||||
backdrop.source = ApiClient.baseUrl + "/Items/" + itemId + "/Images/Backdrop/" + rand + "?tag=" + _backdropImages[rand] + "&maxHeight" + height
|
//backdrop.source = ApiClient.baseUrl + "/Items/" + itemId + "/Images/Backdrop/" + rand + "?tag=" + _backdropImages[rand] + "&maxHeight" + height
|
||||||
|
appWindow.backgroundSource = ApiClient.baseUrl + "/Items/" + itemId + "/Images/Backdrop/" + rand + "?tag=" + _backdropImages[rand] + "&maxHeight" + height
|
||||||
} else if (_parentBackdropImages && _parentBackdropImages.length > 0) {
|
} else if (_parentBackdropImages && _parentBackdropImages.length > 0) {
|
||||||
console.log(parentId)
|
console.log(parentId)
|
||||||
backdrop.source = ApiClient.baseUrl + "/Items/" + itemData.ParentBackdropItemId + "/Images/Backdrop/0?tag=" + _parentBackdropImages[0]
|
//backdrop.source = ApiClient.baseUrl + "/Items/" + itemData.ParentBackdropItemId + "/Images/Backdrop/0?tag=" + _parentBackdropImages[0]
|
||||||
|
appWindow.backgroundSource = ApiClient.baseUrl + "/Items/" + itemData.ParentBackdropItemId + "/Images/Backdrop/0?tag=" + _parentBackdropImages[0]
|
||||||
|
Theme.backgroundGlowColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +56,7 @@ Page {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
PageHeader {
|
PageHeader {
|
||||||
title: itemData.Name
|
title: itemData.Name || qsTr("Loading")
|
||||||
visible: !_hasLogo
|
visible: !_hasLogo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +70,7 @@ Page {
|
||||||
anchors {
|
anchors {
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
source: _hasLogo ? ApiClient.baseUrl + "/Items/" + itemId + "/Images/Logo?tag=" + _logo : undefined
|
source: _hasLogo ? ApiClient.baseUrl + "/Items/" + itemId + "/Images/Logo?tag=" + _logo : ""
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
width: 1
|
width: 1
|
||||||
|
@ -95,6 +98,8 @@ Page {
|
||||||
return Qt.resolvedUrl("../components/itemdetails/SeasonDetails.qml")
|
return Qt.resolvedUrl("../components/itemdetails/SeasonDetails.qml")
|
||||||
case "Episode":
|
case "Episode":
|
||||||
return Qt.resolvedUrl("../components/itemdetails/EpisodeDetails.qml")
|
return Qt.resolvedUrl("../components/itemdetails/EpisodeDetails.qml")
|
||||||
|
case undefined:
|
||||||
|
return ""
|
||||||
default:
|
default:
|
||||||
return Qt.resolvedUrl("../components/itemdetails/UnsupportedDetails.qml")
|
return Qt.resolvedUrl("../components/itemdetails/UnsupportedDetails.qml")
|
||||||
}
|
}
|
||||||
|
@ -114,7 +119,7 @@ Page {
|
||||||
|
|
||||||
onItemIdChanged: {
|
onItemIdChanged: {
|
||||||
itemData = {}
|
itemData = {}
|
||||||
if (itemId.length > 0) {
|
if (itemId.length && PageStatus.Active) {
|
||||||
pageRoot._loading = true
|
pageRoot._loading = true
|
||||||
ApiClient.fetchItem(itemId)
|
ApiClient.fetchItem(itemId)
|
||||||
}
|
}
|
||||||
|
@ -125,8 +130,11 @@ Page {
|
||||||
backdrop.clear()
|
backdrop.clear()
|
||||||
//appWindow.itemData = ({})
|
//appWindow.itemData = ({})
|
||||||
}
|
}
|
||||||
if (status == PageStatus.Active && itemData) {
|
if (status == PageStatus.Active) {
|
||||||
appWindow.itemData = itemData
|
if (itemId) {
|
||||||
|
ApiClient.fetchItem(itemId)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,15 +16,20 @@ Page {
|
||||||
id: page
|
id: page
|
||||||
allowedOrientations: Orientation.All
|
allowedOrientations: Orientation.All
|
||||||
|
|
||||||
|
ViewPlaceholder {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
SilicaFlickable {
|
SilicaFlickable {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
// PullDownMenu and PushUpMenu must be declared in SilicaFlickable, SilicaListView or SilicaGridView
|
// PullDownMenu and PushUpMenu must be declared in SilicaFlickable, SilicaListView or SilicaGridView
|
||||||
PullDownMenu {
|
PullDownMenu {
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: qsTr("About")
|
text: qsTr("Settings")
|
||||||
onClicked: pageStack.push(Qt.resolvedUrl("AboutPage.qml"))
|
onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml"))
|
||||||
}
|
}
|
||||||
|
busy: mediaLibraryModel.status == ApiModel.Loading
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell SilicaFlickable the height of its content.
|
// Tell SilicaFlickable the height of its content.
|
||||||
|
@ -60,7 +65,7 @@ Page {
|
||||||
MoreSection {
|
MoreSection {
|
||||||
text: model.name
|
text: model.name
|
||||||
busy: userItemModel.status != ApiModel.Ready
|
busy: userItemModel.status != ApiModel.Ready
|
||||||
property string collectionType: model.collectionType
|
property string collectionType: model.collectionType || ""
|
||||||
|
|
||||||
onHeaderClicked: pageStack.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id})
|
onHeaderClicked: pageStack.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id})
|
||||||
|
|
||||||
|
@ -117,30 +122,49 @@ Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
visible: mediaLibraryModel.status == ApiModel.Error
|
||||||
|
PageHeader {
|
||||||
|
title: qsTr("Network error")
|
||||||
|
//clickable: false
|
||||||
|
}
|
||||||
|
|
||||||
|
PlainLabel {
|
||||||
|
text: qsTr("An error has occurred. Please try again.")
|
||||||
|
}
|
||||||
|
Item { width: 1; height: Theme.paddingLarge }
|
||||||
|
Button {
|
||||||
|
text: qsTr("Retry")
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
onClicked: loadModels(true)
|
||||||
|
}
|
||||||
|
Item { width: 1; height: Theme.paddingLarge }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
if (status == PageStatus.Active) {
|
if (status == PageStatus.Active) {
|
||||||
appWindow.itemData = null
|
appWindow.itemData = null
|
||||||
if (!_modelsLoaded && ApiClient.authenticated) loadModels()
|
loadModels(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ApiClient
|
target: ApiClient
|
||||||
onAuthenticatedChanged: {
|
onAuthenticatedChanged: loadModels(false)
|
||||||
if (authenticated /*&& !_modelsLoaded*/) loadModels();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
if (ApiClient.authenticated && _modelsLoaded) {
|
/**
|
||||||
loadModels();
|
* Loads models if not laoded. Set force to true to reload models
|
||||||
|
* even if loaded.
|
||||||
|
*/
|
||||||
|
function loadModels(force) {
|
||||||
|
if (force || (ApiClient.authenticated && !_modelsLoaded)) {
|
||||||
|
_modelsLoaded = true;
|
||||||
|
mediaLibraryModel.reload()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
function loadModels() {
|
|
||||||
_modelsLoaded = true;
|
|
||||||
mediaLibraryModel.reload()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
75
qml/pages/SettingsPage.qml
Normal file
75
qml/pages/SettingsPage.qml
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import QtQuick 2.6
|
||||||
|
import Sailfish.Silica 1.0
|
||||||
|
|
||||||
|
import nl.netsoj.chris.Jellyfin 1.0
|
||||||
|
|
||||||
|
import "../components"
|
||||||
|
|
||||||
|
Page {
|
||||||
|
id: settingsPage
|
||||||
|
|
||||||
|
SilicaFlickable {
|
||||||
|
anchors.fill: parent
|
||||||
|
contentHeight: content.height
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: content
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
RemorsePopup {
|
||||||
|
id: remorse
|
||||||
|
}
|
||||||
|
|
||||||
|
PageHeader {
|
||||||
|
//: Header of Settings page
|
||||||
|
title: qsTr("Settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Session")
|
||||||
|
}
|
||||||
|
|
||||||
|
PlainLabel {
|
||||||
|
text: qsTr("Server")
|
||||||
|
}
|
||||||
|
|
||||||
|
PlainLabel {
|
||||||
|
text: ApiClient.baseUrl
|
||||||
|
color: Theme.secondaryHighlightColor
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { width: 1; height: Theme.paddingMedium; }
|
||||||
|
|
||||||
|
PlainLabel {
|
||||||
|
text: qsTr("User id")
|
||||||
|
}
|
||||||
|
|
||||||
|
PlainLabel {
|
||||||
|
text: ApiClient.userId
|
||||||
|
color: Theme.secondaryHighlightColor
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { width: 1; height: Theme.paddingLarge; }
|
||||||
|
|
||||||
|
ButtonLayout {
|
||||||
|
Button {
|
||||||
|
text: qsTr("Log out")
|
||||||
|
onClicked: remorse.execute(qsTr("Logging out"), ApiClient.deleteSession)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionHeader {
|
||||||
|
//: Other settings
|
||||||
|
text: qsTr("Other")
|
||||||
|
}
|
||||||
|
|
||||||
|
IconListItem {
|
||||||
|
text: qsTr("About Sailfin")
|
||||||
|
iconSource: "image://theme/icon-m-about"
|
||||||
|
onClicked: pageStack.push(Qt.resolvedUrl("AboutPage.qml"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ void FallbackCredentialsManager::get(const QString &server, const QString &user)
|
||||||
}
|
}
|
||||||
|
|
||||||
void FallbackCredentialsManager::remove(const QString &server, const QString &user) {
|
void FallbackCredentialsManager::remove(const QString &server, const QString &user) {
|
||||||
m_settings.remove(urlToGroupName(server) + "/" + user);
|
m_settings.remove(urlToGroupName(server) + "/users/" + user);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FallbackCredentialsManager::listServers() const {
|
void FallbackCredentialsManager::listServers() const {
|
||||||
|
|
|
@ -132,12 +132,7 @@ void ApiClient::setupConnection() {
|
||||||
}
|
}
|
||||||
rep->deleteLater();
|
rep->deleteLater();
|
||||||
});
|
});
|
||||||
connect(rep, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
|
setDefaultErrorHandler(rep);
|
||||||
this, [rep, this](QNetworkReply::NetworkError error) {
|
|
||||||
qDebug() << "Error from URL: " << rep->url();
|
|
||||||
emit this->networkError(error);
|
|
||||||
rep->deleteLater();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiClient::getBrandingConfiguration() {
|
void ApiClient::getBrandingConfiguration() {
|
||||||
|
@ -162,11 +157,7 @@ void ApiClient::getBrandingConfiguration() {
|
||||||
}
|
}
|
||||||
rep->deleteLater();
|
rep->deleteLater();
|
||||||
});
|
});
|
||||||
connect(rep, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
|
setDefaultErrorHandler(rep);
|
||||||
this, [rep, this](QNetworkReply::NetworkError error) {
|
|
||||||
emit this->networkError(error);
|
|
||||||
rep->deleteLater();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiClient::authenticate(QString username, QString password, bool storeCredentials) {
|
void ApiClient::authenticate(QString username, QString password, bool storeCredentials) {
|
||||||
|
@ -195,8 +186,17 @@ void ApiClient::authenticate(QString username, QString password, bool storeCrede
|
||||||
}
|
}
|
||||||
rep->deleteLater();
|
rep->deleteLater();
|
||||||
});
|
});
|
||||||
connect(rep, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
|
setDefaultErrorHandler(rep);
|
||||||
this, &ApiClient::defaultNetworkErrorHandler);
|
}
|
||||||
|
|
||||||
|
void ApiClient::deleteSession() {
|
||||||
|
QNetworkReply *rep = post("/Sessions/Logout");
|
||||||
|
connect(rep, &QNetworkReply::finished, this, [rep, this] {
|
||||||
|
m_credManager->remove(m_baseUrl, m_userId);
|
||||||
|
this->setAuthenticated(false);
|
||||||
|
emit this->setupRequired();
|
||||||
|
rep->deleteLater();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiClient::fetchItem(const QString &id) {
|
void ApiClient::fetchItem(const QString &id) {
|
||||||
|
@ -209,6 +209,11 @@ void ApiClient::fetchItem(const QString &id) {
|
||||||
}
|
}
|
||||||
rep->deleteLater();
|
rep->deleteLater();
|
||||||
});
|
});
|
||||||
|
connect(rep, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
|
||||||
|
this, [id, rep, this](QNetworkReply::NetworkError error) {
|
||||||
|
emit this->itemFetchFailed(id, error);
|
||||||
|
rep->deleteLater();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiClient::postCapabilities() {
|
void ApiClient::postCapabilities() {
|
||||||
|
@ -221,8 +226,7 @@ void ApiClient::postCapabilities() {
|
||||||
capabilities["IconUrl"] = "https://chris.netsoj.nl/static/img/logo.png";
|
capabilities["IconUrl"] = "https://chris.netsoj.nl/static/img/logo.png";
|
||||||
capabilities["DeviceProfile"] = m_deviceProfile;
|
capabilities["DeviceProfile"] = m_deviceProfile;
|
||||||
QNetworkReply *rep = post("/Sessions/Capabilities/Full", QJsonDocument(capabilities));
|
QNetworkReply *rep = post("/Sessions/Capabilities/Full", QJsonDocument(capabilities));
|
||||||
connect(rep, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
|
setDefaultErrorHandler(rep);
|
||||||
this, &ApiClient::defaultNetworkErrorHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiClient::generateDeviceProfile() {
|
void ApiClient::generateDeviceProfile() {
|
||||||
|
@ -244,6 +248,7 @@ void ApiClient::defaultNetworkErrorHandler(QNetworkReply::NetworkError error) {
|
||||||
QObject *signalSender = sender();
|
QObject *signalSender = sender();
|
||||||
QNetworkReply *rep = dynamic_cast<QNetworkReply *>(signalSender);
|
QNetworkReply *rep = dynamic_cast<QNetworkReply *>(signalSender);
|
||||||
if (rep != nullptr && statusCode(rep) == 401) {
|
if (rep != nullptr && statusCode(rep) == 401) {
|
||||||
|
this->setAuthenticated(false);
|
||||||
emit this->authenticationError(ApiError::INVALID_PASSWORD);
|
emit this->authenticationError(ApiError::INVALID_PASSWORD);
|
||||||
} else {
|
} else {
|
||||||
emit this->networkError(error);
|
emit this->networkError(error);
|
||||||
|
|
|
@ -106,6 +106,7 @@ signals:
|
||||||
void userIdChanged(QString userId);
|
void userIdChanged(QString userId);
|
||||||
|
|
||||||
void itemFetched(const QString &itemId, const QJsonObject &result);
|
void itemFetched(const QString &itemId, const QJsonObject &result);
|
||||||
|
void itemFetchFailed(const QString &itemId, const QNetworkReply::NetworkError error);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/**
|
/**
|
||||||
|
@ -120,6 +121,12 @@ public slots:
|
||||||
*/
|
*/
|
||||||
void setupConnection();
|
void setupConnection();
|
||||||
void authenticate(QString username, QString password, bool storeCredentials = false);
|
void authenticate(QString username, QString password, bool storeCredentials = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logs the user out and clears the session.
|
||||||
|
*/
|
||||||
|
void deleteSession();
|
||||||
|
|
||||||
void fetchItem(const QString &id);
|
void fetchItem(const QString &id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,6 +164,7 @@ protected:
|
||||||
* is a big mess and should be safely contained in it's own file.
|
* is a big mess and should be safely contained in it's own file.
|
||||||
*/
|
*/
|
||||||
void generateDeviceProfile();
|
void generateDeviceProfile();
|
||||||
|
|
||||||
QString &token() { return m_token; }
|
QString &token() { return m_token; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -206,6 +214,18 @@ private:
|
||||||
static inline int statusCode(QNetworkReply *rep) {
|
static inline int statusCode(QNetworkReply *rep) {
|
||||||
return rep->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
return rep->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the error handler of a reply to this classes default error handler
|
||||||
|
* @param rep The reply to set the error handler on.
|
||||||
|
*
|
||||||
|
* Motivation for this helper is because I forget the correct signature each time, with all the
|
||||||
|
* funky casts.
|
||||||
|
*/
|
||||||
|
void setDefaultErrorHandler(QNetworkReply *rep) {
|
||||||
|
connect(rep, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
|
||||||
|
this, &ApiClient::defaultNetworkErrorHandler);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // NS Jellyfin
|
} // NS Jellyfin
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>DetailPage</name>
|
||||||
|
<message>
|
||||||
|
<source>Loading</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>EpisodeDetails</name>
|
<name>EpisodeDetails</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -127,10 +134,6 @@
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MainPage</name>
|
<name>MainPage</name>
|
||||||
<message>
|
|
||||||
<source>About</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Resume watching</source>
|
<source>Resume watching</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
|
@ -139,6 +142,22 @@
|
||||||
<source>Next up</source>
|
<source>Next up</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Network error</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An error has occurred. Please try again.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Retry</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SeasonDetails</name>
|
<name>SeasonDetails</name>
|
||||||
|
@ -156,6 +175,39 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SettingsPage</name>
|
||||||
|
<message>
|
||||||
|
<source>Settings</source>
|
||||||
|
<extracomment>Header of Settings page</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Other</source>
|
||||||
|
<extracomment>Other settings</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>About Sailfin</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Session</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Server</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>User id</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Log out</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>UnsupportedDetails</name>
|
<name>UnsupportedDetails</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
Loading…
Reference in a new issue