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(PLATFORM_QTQUICK "Build QtQuick version of application")
if (NOT SAILFIN_VERSION)
set(SAILFIN_VERSION "1.0.0")
endif()
if(SAILFISHOS)
# Hardcode this less?
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["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]() {
int status = rep->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << "Got reply with status code " << status;
@ -202,6 +202,12 @@ void ApiClient::authenticate(QString username, QString password, bool storeCrede
if (storeCredentials) {
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();
});

View File

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

View File

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

View File

@ -1,6 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.12
import QtQuick.Window 2.12
import nl.netsoj.chris.Jellyfin 1.0
@ -31,11 +30,13 @@ ApplicationWindow {
}
_oldDepth = depth
}
initialItem: Qt.resolvedUrl("pages/MainPage.qml")
Keys.onEscapePressed: pop()
}
Connections {
target: ApiClient
onSetupRequired: pageStack.push(Qt.resolvedUrl("pages/setup/ServerSelectPage.qml"));
onSetupRequired: pageStack.replace(Qt.resolvedUrl("pages/setup/ServerSelectPage.qml"));
}
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.Controls 2.12
import nl.netsoj.chris.Jellyfin 1.0
import "../../components"
import "../../.."
Page {
property string loginMessage
property StackView stackView: StackView.view
header: ToolBar {
Label {
anchors.horizontalCenter: parent.horizontalCenter
@ -20,11 +24,27 @@ Page {
TextField {
id: usernameField
width: parent.width
placeholderText: qsTr("Username")
EnterKey.type: Qt.EnterKeyNext
}
TextField {
id: passwordField
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 {
width: parent.width
@ -32,4 +52,29 @@ Page {
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
}
}
}