1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2024-11-22 09:15:18 +00:00

Update UI to bare minimum to allow for core lib testing

This commit is contained in:
Chris Josten 2021-03-19 20:57:04 +01:00
parent 56d7c1486e
commit 3cd1fd3e23
8 changed files with 206 additions and 12 deletions

View file

@ -9,6 +9,10 @@ cmake_policy(SET CMP0048 NEW)
option(SAILFISHOS "Build SailfishOS version of application") option(SAILFISHOS "Build SailfishOS version of application")
option(PLATFORM_QTQUICK "Build QtQuick version of application") option(PLATFORM_QTQUICK "Build QtQuick version of application")
if (NOT SAILFIN_VERSION)
set(SAILFIN_VERSION "1.0.0")
endif()
if(SAILFISHOS) if(SAILFISHOS)
# Hardcode this less? # Hardcode this less?
set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/share/harbour-sailfin/lib") set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/share/harbour-sailfin/lib")

View file

@ -184,7 +184,7 @@ void ApiClient::authenticate(QString username, QString password, bool storeCrede
requestData["Username"] = username; requestData["Username"] = username;
requestData["Pw"] = password; requestData["Pw"] = password;
QNetworkReply *rep = post("/Users/Authenticatebyname", QJsonDocument(requestData)); QNetworkReply *rep = post("/Users/authenticatebyname", QJsonDocument(requestData));
connect(rep, &QNetworkReply::finished, this, [rep, username, storeCredentials, this]() { connect(rep, &QNetworkReply::finished, this, [rep, username, storeCredentials, this]() {
int status = rep->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); int status = rep->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << "Got reply with status code " << status; qDebug() << "Got reply with status code " << status;
@ -202,6 +202,12 @@ void ApiClient::authenticate(QString username, QString password, bool storeCrede
if (storeCredentials) { if (storeCredentials) {
m_credManager->store(this->m_baseUrl, this->m_userId, this->m_token); m_credManager->store(this->m_baseUrl, this->m_userId, this->m_token);
} }
} else if(status >= 400 && status < 500) {
if (status == 401) {
emit authenticationError(ApiError::INVALID_PASSWORD);
} else {
emit authenticationError(ApiError::UNEXPECTED_STATUS);
}
} }
rep->deleteLater(); rep->deleteLater();
}); });

View file

@ -85,7 +85,7 @@ QJsonObject DeviceProfile::generateProfile() {
QJsonObject { QJsonObject {
JsonPair("Property", "IsSecondaryAudio"), JsonPair("Property", "IsSecondaryAudio"),
JsonPair("Condition", "Equals"), JsonPair("Condition", "Equals"),
JsonPair("Value", false), JsonPair("Value", "false"),
JsonPair("IsRequired", false) JsonPair("IsRequired", false)
} }
}), }),
@ -97,7 +97,7 @@ QJsonObject DeviceProfile::generateProfile() {
QJsonObject { QJsonObject {
JsonPair("Property", "IsAnamorphic"), JsonPair("Property", "IsAnamorphic"),
JsonPair("Condition", "NotEquals"), JsonPair("Condition", "NotEquals"),
JsonPair("Value", true), JsonPair("Value", "true"),
JsonPair("IsRequired", false) JsonPair("IsRequired", false)
}, },
QJsonObject { QJsonObject {
@ -109,13 +109,13 @@ QJsonObject DeviceProfile::generateProfile() {
QJsonObject { QJsonObject {
JsonPair("Property", "VideoLevel"), JsonPair("Property", "VideoLevel"),
JsonPair("Condition", "LessThanEqual"), JsonPair("Condition", "LessThanEqual"),
JsonPair("Value", 51), JsonPair("Value", "51"),
JsonPair("IsRequired", false) JsonPair("IsRequired", false)
}, },
QJsonObject { QJsonObject {
JsonPair("Property", "IsInterlaced"), JsonPair("Property", "IsInterlaced"),
JsonPair("Condition", "NotEquals"), JsonPair("Condition", "NotEquals"),
JsonPair("Value", true), JsonPair("Value", "true"),
JsonPair("IsRequired", false) JsonPair("IsRequired", false)
} }
}), }),
@ -130,8 +130,8 @@ QJsonObject DeviceProfile::generateProfile() {
transcoding1["BreakOnNonKeyFrames"] =true; transcoding1["BreakOnNonKeyFrames"] =true;
transcoding1["Container"] = "ts"; transcoding1["Container"] = "ts";
transcoding1["Context"] = "Streaming"; transcoding1["Context"] = "Streaming";
transcoding1["MaxAudioChannels"] = 2; transcoding1["MaxAudioChannels"] = "2";
transcoding1["MinSegments"] = 1; transcoding1["MinSegments"] = "1";
transcoding1["Protocol"] = "hls"; transcoding1["Protocol"] = "hls";
transcoding1["Type"] = "Audio"; transcoding1["Type"] = "Audio";
transcodingProfiles.append(transcoding1); transcodingProfiles.append(transcoding1);
@ -142,7 +142,7 @@ QJsonObject DeviceProfile::generateProfile() {
JsonPair("BreakOnNonKeyFrames", true), JsonPair("BreakOnNonKeyFrames", true),
JsonPair("Container", "ts"), JsonPair("Container", "ts"),
JsonPair("Context", "Streaming"), JsonPair("Context", "Streaming"),
JsonPair("MaxAudioChannels", 2), JsonPair("MaxAudioChannels", "2"),
JsonPair("MinSegments", 1), JsonPair("MinSegments", 1),
JsonPair("Protocol", "hls"), JsonPair("Protocol", "hls"),
JsonPair("Type", "Video"), JsonPair("Type", "Video"),
@ -168,8 +168,8 @@ QJsonObject DeviceProfile::generateProfile() {
JsonPair("VideoCodec", hlsVideoCodecs.join(",")), JsonPair("VideoCodec", hlsVideoCodecs.join(",")),
JsonPair("Context", "Streaming"), JsonPair("Context", "Streaming"),
JsonPair("Protocol", "hls"), JsonPair("Protocol", "hls"),
JsonPair("MaxAudioChannels", 2), JsonPair("MaxAudioChannels", "2"),
JsonPair("MinSegments", 1), JsonPair("MinSegments", "1"),
JsonPair("BreakOnNonKeyFrames", true) JsonPair("BreakOnNonKeyFrames", true)
}); });
} }

View file

@ -14,5 +14,7 @@
<file>qml/components/+sailfinstyle/Background.qml</file> <file>qml/components/+sailfinstyle/Background.qml</file>
<file>qml/components/BusyDialog.qml</file> <file>qml/components/BusyDialog.qml</file>
<file>qml/pages/setup/LoginPage.qml</file> <file>qml/pages/setup/LoginPage.qml</file>
<file>qml/pages/MainPage.qml</file>
<file>qml/pages/DetailPage.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -1,6 +1,5 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtGraphicalEffects 1.12
import QtQuick.Window 2.12 import QtQuick.Window 2.12
import nl.netsoj.chris.Jellyfin 1.0 import nl.netsoj.chris.Jellyfin 1.0
@ -31,11 +30,13 @@ ApplicationWindow {
} }
_oldDepth = depth _oldDepth = depth
} }
initialItem: Qt.resolvedUrl("pages/MainPage.qml")
Keys.onEscapePressed: pop()
} }
Connections { Connections {
target: ApiClient target: ApiClient
onSetupRequired: pageStack.push(Qt.resolvedUrl("pages/setup/ServerSelectPage.qml")); onSetupRequired: pageStack.replace(Qt.resolvedUrl("pages/setup/ServerSelectPage.qml"));
} }
Component.onCompleted: { Component.onCompleted: {

View file

@ -0,0 +1,37 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12
import nl.netsoj.chris.Jellyfin 1.0
import "../components"
import "../.."
Page {
property bool _modelsLoaded: false
property StackView stackView: StackView.view
property string itemId
property alias jellyfinItem: jellyfinItem
header: ToolBar {
Label {
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: SailfinStyle.fontSizeLarge
text: jellyfinItem.name
}
}
MouseArea {
anchors.fill: parent
onClicked: stackView.pop()
}
JellyfinItem {
id: jellyfinItem
jellyfinId: itemId
apiClient: ApiClient
}
Image {
anchors.centerIn: parent
source: ApiClient.baseUrl + "/Items/" + itemId + "/Images/Primary?tag=" + jellyfinItem.tag
}
}

View file

@ -0,0 +1,99 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12
import nl.netsoj.chris.Jellyfin 1.0
import "../components"
import "../.."
Page {
property bool _modelsLoaded: false
property StackView stackView: StackView.view
header: ToolBar {
Label {
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: SailfinStyle.fontSizeLarge
text: qsTr("Main page")
}
}
UserViewModel {
id: mediaLibraryModel
apiClient: ApiClient
}
ScrollView {
anchors.fill: parent
contentHeight: content.height
Column {
id: content
width: parent.width
Repeater {
model: mediaLibraryModel
Column {
width: parent.width
UserItemLatestModel {
id: userItemModel
apiClient: ApiClient
parentId: model.id
limit: 16
}
Label {
text: model.name
}
ListView {
width: parent.width
height: SailfinStyle.unit * 20
orientation: ListView.Horizontal
model: userItemModel
delegate: ItemDelegate {
width: 12 * SailfinStyle.unit
height: 20 * SailfinStyle.unit
Image {
anchors.fill: parent
source: ApiClient.baseUrl + "/Items/" + model.id + "/Images/Primary?tag=" + model.tag
}
Label {
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right
text: model.name
}
onClicked: stackView.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id})
}
}
Connections {
target: mediaLibraryModel
onStatusChanged: {
if (mediaLibraryModel.status == UserItemModel.Ready) {
userItemModel.reload()
}
}
}
}
}
}
}
/**
* 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()
}
}
Connections {
target: ApiClient
onAuthenticatedChanged: {
if (authenticated) {
loadModels(false)
}
}
}
}

View file

@ -1,10 +1,14 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import nl.netsoj.chris.Jellyfin 1.0
import "../../components"
import "../../.." import "../../.."
Page { Page {
property string loginMessage property string loginMessage
property StackView stackView: StackView.view
header: ToolBar { header: ToolBar {
Label { Label {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@ -20,11 +24,27 @@ Page {
TextField { TextField {
id: usernameField id: usernameField
width: parent.width width: parent.width
placeholderText: qsTr("Username")
EnterKey.type: Qt.EnterKeyNext EnterKey.type: Qt.EnterKeyNext
} }
TextField { TextField {
id: passwordField id: passwordField
width: parent.width width: parent.width
placeholderText: qsTr("Password")
echoMode: TextInput.Password
}
Label {
id: loginError
width: parent.width
wrapMode: Text.WordWrap
text: qsTr("Invalid username/password")
visible: false
}
Button {
text: qsTr("Login")
onClicked: login()
} }
Label { Label {
width: parent.width width: parent.width
@ -32,4 +52,29 @@ Page {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }
} }
BusyDialog {
id: busyDialog
anchors.centerIn: Overlay.overlay
title: qsTr("Logging in as %1").arg(usernameField.text)
}
function login() {
busyDialog.open()
ApiClient.authenticate(usernameField.text, passwordField.text, true)
}
Connections {
target: ApiClient
onAuthenticatedChanged: {
busyDialog.close()
if (authenticated) {
stackView.replace(null, Qt.resolvedUrl("../MainPage.qml"), {})
}
}
onAuthenticationError: {
busyDialog.close()
loginError.visible = true
}
}
} }