1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2025-09-05 10:12:46 +00:00

WIP: Add playlists/queues and add support for Sailfish back

This commit is contained in:
Chris Josten 2021-07-31 15:06:17 +02:00
parent fbc154fb56
commit 86672be051
89 changed files with 1637 additions and 849 deletions

View file

@ -19,9 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../components"
import ".."
Page {
id: page

View file

@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import QtQuick 2.0
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../components"
import "../"
@ -32,7 +32,7 @@ Page {
/// True if the models on this page already have been loaded and don't necessarily need a refresh
property bool _modelsLoaded: false
id: page
id: mainPage
allowedOrientations: Orientation.All
// This component is reused both in the normal state and error state
@ -49,7 +49,7 @@ Page {
text: qsTr("Reload")
onClicked: loadModels(true)
}
busy: mediaLibraryModel.status == ApiModel.Loading
busy: userViewsLoader.status === J.UsersViewsLoader.Loading
}
}
@ -67,29 +67,33 @@ Page {
// of the page, followed by our content.
Column {
id: column
width: page.width
width: mainPage.width
UserViewModel {
id: mediaLibraryModel2
apiClient: ApiClient
J.ItemModel {
id: mediaLibraryModel
loader: J.UsersViewsLoader {
id: mediaLibraryLoader
apiClient: ApiClient
}
}
MoreSection {
//- Section header for films and TV shows that an user hasn't completed yet.
text: qsTr("Resume watching")
clickable: false
busy: userResumeModel.status === ApiModel.Loading
//busy: userResumeModel.status === J.ApiModel.Loading
Loader {
width: parent.width
sourceComponent: carrouselView
property alias itemModel: userResumeModel
property string collectionType: "series"
UserItemResumeModel {
J.ItemModel {
id: userResumeModel
apiClient: ApiClient
// Resume model
/*apiClient: ApiClient
limit: 12
recursive: true
recursive: true*/
}
}
}
@ -97,7 +101,7 @@ Page {
//- Section header for next episodes in a TV show that an user was watching.
text: qsTr("Next up")
clickable: false
busy: showNextUpModel.status === ApiModel.Loading
//busy: showNextUpModel.status === .Loading
Loader {
width: parent.width
@ -105,23 +109,18 @@ Page {
property alias itemModel: showNextUpModel
property string collectionType: "series"
ShowNextUpModel {
J.ItemModel {
id: showNextUpModel
apiClient: ApiClient
limit: 12
/*apiClient: ApiClient
limit: 12*/
}
}
}
UserViewModel {
id: mediaLibraryModel
apiClient: ApiClient
}
Repeater {
model: mediaLibraryModel
MoreSection {
text: model.name
busy: userItemModel.status !== ApiModel.Ready
busy: userItemModel.status !== J.UsersViewsLoader.Ready
onHeaderClicked: pageStack.push(Qt.resolvedUrl("itemdetails/CollectionPage.qml"), {"itemId": model.jellyfinId})
Loader {
@ -130,11 +129,12 @@ Page {
property alias itemModel: userItemModel
property string collectionType: model.collectionType || ""
UserItemLatestModel {
J.ItemModel {
id: userItemModel
apiClient: ApiClient
parentId: jellyfinId
limit: 16
loader: J.LatestMediaLoader {
apiClient: ApiClient
parentId: jellyfinId
}
}
Connections {
target: mediaLibraryModel
@ -184,8 +184,8 @@ Page {
if (force || (ApiClient.authenticated && !_modelsLoaded)) {
_modelsLoaded = true;
mediaLibraryModel.reload()
userResumeModel.reload()
showNextUpModel.reload()
//userResumeModel.reload()
//showNextUpModel.reload()
}
}
@ -236,11 +236,11 @@ Page {
states: [
State {
name: "default"
when: mediaLibraryModel2.status !== ApiModel.Error
when: mediaLibraryLoader.status !== J.UsersViewsLoader.Error
},
State {
name: "error"
when: mediaLibraryModel2.status === ApiModel.Error
when: mediaLibraryLoader.status === J.UsersViewsLoader.Error
PropertyChanges {
target: errorFlickable

View file

@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../components"
@ -57,9 +57,9 @@ Page {
rightMargin: Theme.horizontalPageMargin
}
height: user.implicitHeight + server.implicitHeight + Theme.paddingMedium
User {
QtObject {
id: loggedInUser
apiClient: ApiClient
//apiClient: ApiClient
}
RemoteImage {
id: userIcon

View file

@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../../components"
import "../.."
@ -32,14 +32,14 @@ import "../.."
*/
Page {
id: pageRoot
property alias itemId: jItem.jellyfinId
property alias itemData: jItem
property string itemId: ""
property alias itemData: jItemLoader.data
//property string itemId: ""
//property var itemData: ({})
property bool _loading: jItem.status === "Loading"
readonly property bool hasLogo: (typeof itemData.ImageTags !== "undefined") && (typeof itemData.ImageTags["Logo"] !== "undefined")
property bool _loading: jItemLoader.status === J.ItemLoader.Loading
readonly property bool hasLogo: (typeof itemData.imageTags !== "undefined") && (typeof itemData.imageTags["Logo"] !== "undefined")
property string _chosenBackdropImage: ""
readonly property string parentId: itemData.ParentId || ""
readonly property string parentId: itemData.parentId || ""
function updateBackdrop() {
var rand = 0;
@ -62,13 +62,13 @@ Page {
SilicaFlickable {
anchors.fill: parent
contentHeight: errorContent.height
visible: jItem.status == JellyfinItem.Error
visible: jItemLoader.status === J.ItemLoader.Error
PullDownMenu {
busy: jItem.status == JellyfinItem.Loading
busy: jItemLoader.status === J.ItemLoader.Loading
MenuItem {
text: qsTr("Retry")
onClicked: jItem.reload()
onClicked: jItemLoader.reload()
}
}
@ -79,28 +79,33 @@ Page {
ViewPlaceholder {
enabled: true
text: qsTr("An error has occured")
hintText: jItem.errorString
hintText: jItemLoader.errorString
}
}
}
JellyfinItem {
id: jItem
J.ItemLoader {
id: jItemLoader
apiClient: ApiClient
itemId: pageRoot.itemId
onStatusChanged: {
//console.log("Status changed: " + newStatus, JSON.stringify(jItem))
if (status == JellyfinItem.Ready) {
console.log("Status changed: " + newStatus, JSON.stringify(jItemLoader.data))
if (status === J.ItemLoader.Ready) {
updateBackdrop()
}
}
}
Label {
text: "ItemLoader status=%1, \nitemId=%2\nitemData=%3".arg(jItemLoader.status).arg(jItemLoader.itemId).arg(jItemLoader.data)
}
onStatusChanged: {
if (status == PageStatus.Deactivating) {
//appWindow.itemData = ({})
}
if (status == PageStatus.Active) {
appWindow.itemData = jItem
//appWindow.itemData = jItemLoader.data
}
}
}

View file

@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../.."
import "../../components"
@ -27,12 +27,13 @@ import "../../components"
BaseDetailPage {
id: pageRoot
UserItemModel {
J.ItemModel {
id: collectionModel
apiClient: ApiClient
parentId: itemData.jellyfinId
sortBy: ["SortName"]
onParentIdChanged: reload()
//sortBy: ["SortName"]
loader: J.UserItemsLoader {
apiClient: ApiClient
parentId: itemData.jellyfinId
}
}
SilicaGridView {
@ -42,7 +43,7 @@ BaseDetailPage {
cellWidth: Constants.libraryDelegateWidth
cellHeight: Utils.usePortraitCover(itemData.collectionType) ? Constants.libraryDelegatePosterHeight
: Constants.libraryDelegateHeight
visible: itemData.status !== JellyfinItem.Error
visible: itemData.status !== J.ItemLoader.Error
header: PageHeader {
title: itemData.name || qsTr("Loading")
@ -54,7 +55,7 @@ BaseDetailPage {
text: qsTr("Sort by")
onClicked: pageStack.push(sortPageComponent)
}
busy: collectionModel.status === ApiModel.Loading
busy: collectionModel.status === J.UserItemsLoader.Loading
}
delegate: GridItem {
RemoteImage {

View file

@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../../components"
import "../.."

View file

@ -20,7 +20,7 @@ import QtQuick 2.6
import Sailfish.Silica 1.0
import QtQuick.Layouts 1.1
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../../components"
import "../../components/music"
@ -33,13 +33,15 @@ BaseDetailPage {
readonly property bool _twoColumns: albumPageRoot.width / Theme.pixelRatio >= 800
UserItemModel {
J.ItemModel {
id: collectionModel
apiClient: ApiClient
sortBy: ["SortName"]
fields: ["ItemCounts","PrimaryImageAspectRatio","BasicSyncInfo","CanDelete","MediaSourceCount"]
parentId: itemData.jellyfinId
onParentIdChanged: reload()
loader: J.UserItemsLoader {
apiClient: ApiClient
//sortBy: ["SortName"]
//fields: ["ItemCounts","PrimaryImageAspectRatio","BasicSyncInfo","CanDelete","MediaSourceCount"]
parentId: itemData.jellyfinId
onParentIdChanged: reload()
}
}
RowLayout {
anchors.fill: parent
@ -50,9 +52,9 @@ BaseDetailPage {
visible: _twoColumns
Layout.minimumWidth: 1000 / Theme.pixelRatio
Layout.fillHeight: true
source: visible
/*source: visible
? "../../components/music/WideAlbumCover.qml" : ""
onLoaded: bindAlbum(item)
onLoaded: bindAlbum(item)*/
}
Item {height: 1; width: Theme.horizontalPageMargin; visible: wideAlbumCover.visible; }
SilicaListView {
@ -62,8 +64,8 @@ BaseDetailPage {
model: collectionModel
header: Loader {
width: parent.width
source: "../../components/music/NarrowAlbumCover.qml"
onLoaded: bindAlbum(item)
/*source: "../../components/music/NarrowAlbumCover.qml"
onLoaded: bindAlbum(item)*/
}
section {
property: "parentIndexNumber"
@ -84,14 +86,8 @@ BaseDetailPage {
}
}
Connections {
target: itemData
onAlbumArtistsChanged: {
}
}
function bindAlbum(item) {
item.albumArt = Qt.binding(function(){ return Utils.itemImageUrl(ApiClient.baseUrl, itemData, "Primary", {"maxWidth": parent.width})})
//item.albumArt = Qt.binding(function(){ return Utils.itemImageUrl(ApiClient.baseUrl, itemData, "Primary", {"maxWidth": parent.width})})
item.name = Qt.binding(function(){ return itemData.name})
item.releaseYear = Qt.binding(function() { return itemData.productionYear})
item.albumArtist = Qt.binding(function() { return itemData.albumArtist})

View file

@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../../components"
import "../.."
@ -33,11 +33,11 @@ BaseDetailPage {
property alias subtitle: pageHeader.description
default property alias _data: content.data
property real _playbackProsition: itemData.userData.playbackPositionTicks
readonly property bool _userdataReady: itemData.status == JellyfinItem.Ready && itemData.userData != null
readonly property bool _userdataReady: itemData.status === J.ItemLoader.Ready && itemData.userData !== null
SilicaFlickable {
anchors.fill: parent
contentHeight: content.height + Theme.paddingLarge
visible: itemData.status !== JellyfinItem.Error
visible: itemData.status !== J.ItemLoader.Error
VerticalScrollDecorator {}
@ -84,7 +84,7 @@ BaseDetailPage {
Connections {
target: itemData
onStatusChanged: {
if (status == JellyfinItem.Ready) {
if (status === J.ItemLoader.Ready) {
console.log(itemData.mediaStreams)
}
}

View file

@ -19,9 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../../components"
import "../.."
Page {
id: page
@ -53,7 +54,7 @@ Page {
label: qsTr("Connection state")
value: {
var stateText
switch( ApiClient.websocket.state) {
switch(ApiClient.websocket.state) {
case 0:
//- Socket state
stateText = qsTr("Unconnected");

View file

@ -18,7 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../.."
/**
* Page to indicate that the application is connecting to a server.

View file

@ -18,7 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../../"
/**
* Dialog showed when the user has to connect to a Jellyfin server.
@ -49,7 +51,7 @@ Dialog {
title: qsTr("Connect to Jellyfin")
}
ServerDiscoveryModel {
J.ServerDiscoveryModel {
id: serverModel
}

View file

@ -18,9 +18,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import nl.netsoj.chris.Jellyfin 1.0 as J
import "../../components"
import "../../"
/**
* Page where the user can login on their server. Is displayed after the AddServerPage successfully connected
@ -31,7 +32,7 @@ Dialog {
id: loginDialog
property string loginMessage
property Page firstPage
property User selectedUser: null
property QtObject /*User*/ selectedUser: null
property string error
@ -65,11 +66,13 @@ Dialog {
}
}
PublicUserModel {
QtObject { id: userModel; }
/*PublicUserModel {
id: userModel
apiClient: ApiClient
Component.onCompleted: reload();
}
}*/
DialogHeader {
id: dialogHeader
@ -97,7 +100,7 @@ Dialog {
width: parent.width
Repeater {
id: userRepeater
model: userModel
model: 0 //userModel
delegate: UserGridDelegate {
name: model.name
image: model.primaryImageTag ? "%1/Users/%2/Images/Primary?tag=%3".arg(ApiClient.baseUrl).arg(model.jellyfinId).arg(model.primaryImageTag) : ""