mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2025-09-04 01:42:44 +00:00
Add music library page
This commit is contained in:
parent
0c0b91dc4b
commit
dc9c3ea1b8
11 changed files with 284 additions and 102 deletions
|
@ -26,6 +26,7 @@ set(sailfin_QML_SOURCES
|
|||
qml/components/videoplayer/VideoError.qml
|
||||
qml/components/videoplayer/VideoHud.qml
|
||||
qml/components/IconListItem.qml
|
||||
qml/components/ItemChildrenShowcase.qml
|
||||
qml/components/JItem.qml
|
||||
qml/components/LibraryItemDelegate.qml
|
||||
qml/components/MoreSection.qml
|
||||
|
@ -53,7 +54,8 @@ set(sailfin_QML_SOURCES
|
|||
qml/pages/itemdetails/EpisodePage.qml
|
||||
qml/pages/itemdetails/FilmPage.qml
|
||||
qml/pages/itemdetails/MusicAlbumPage.qml
|
||||
qml/pages/itemdetails/MusicArtistPage.qml
|
||||
qml/pages/itemdetails/MusicArtistPage.qml
|
||||
qml/pages/itemdetails/MusicLibraryPage.qml
|
||||
qml/pages/itemdetails/PhotoPage.qml
|
||||
qml/pages/itemdetails/SeasonPage.qml
|
||||
qml/pages/itemdetails/SeriesPage.qml
|
||||
|
|
|
@ -112,6 +112,13 @@ function getPageUrl(mediaType, itemType, isFolder) {
|
|||
return Qt.resolvedUrl("pages/itemdetails/MusicAlbumPage.qml")
|
||||
case "photo":
|
||||
return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
|
||||
case "collectionfolder":
|
||||
// TODO: support for other collection folders
|
||||
switch(mediaType.toLowerCase()) {
|
||||
case "music":
|
||||
return Qt.resolvedUrl("pages/itemdetails/MusicLibraryPage.qml")
|
||||
}
|
||||
// FALLTRHOUGH
|
||||
default:
|
||||
switch (mediaType ? mediaType.toLowerCase() : isFolder ? "folder" : "") {
|
||||
case "folder":
|
||||
|
|
60
sailfish/qml/components/ItemChildrenShowcase.qml
Normal file
60
sailfish/qml/components/ItemChildrenShowcase.qml
Normal file
|
@ -0,0 +1,60 @@
|
|||
import QtQuick 2.6
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
import nl.netsoj.chris.Jellyfin 1.0 as J
|
||||
|
||||
import "../"
|
||||
|
||||
MoreSection {
|
||||
id: header
|
||||
busy: itemModel.loader.status === J.ModelStatus.Loading || extraBusy
|
||||
property bool extraBusy: false
|
||||
property alias loader: itemModel.loader
|
||||
property string collectionType
|
||||
property bool collapseWhenEmpty: true
|
||||
|
||||
J.ItemModel {
|
||||
id: itemModel
|
||||
}
|
||||
|
||||
SilicaListView {
|
||||
readonly property bool isPortrait: Utils.usePortraitCover(collectionType)
|
||||
id: list
|
||||
clip: true
|
||||
height: {
|
||||
if (count > 0 || !collapseWhenEmpty) {
|
||||
if (isPortrait) {
|
||||
Constants.libraryDelegatePosterHeight
|
||||
} else {
|
||||
Constants.libraryDelegateHeight
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation { easing.type: Easing.OutQuad; duration: 300 }
|
||||
}
|
||||
model: itemModel
|
||||
width: parent.width
|
||||
orientation: ListView.Horizontal
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
spacing: Theme.paddingLarge
|
||||
delegate: LibraryItemDelegate {
|
||||
property string id: model.jellyfinId
|
||||
title: model.name
|
||||
poster: Utils.itemModelImageUrl(appWindow.apiClient.baseUrl, model.jellyfinId, model.imageTags["Primary"], "Primary", {"height": height})
|
||||
Binding on blurhash {
|
||||
when: poster != ""
|
||||
value: model.imageBlurHashes["Primary"][model.imageTags["Primary"]]
|
||||
}
|
||||
landscape: !list.isPortrait
|
||||
progress: (typeof model.userDataPlayedProgress !== 0.0) ? model.userDataPlayedPercentage / 100 : 0.0
|
||||
|
||||
onClicked: {
|
||||
appWindow.navigateToItem(model.jellyfinId, model.mediaType, model.type, model.isFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -78,73 +78,40 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
MoreSection {
|
||||
ItemChildrenShowcase {
|
||||
//- Section header for films and TV shows that an user hasn't completed yet.
|
||||
text: qsTr("Resume watching")
|
||||
clickable: false
|
||||
busy: userResumeLoader.status === J.ModelStatus.Loading
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: carrouselView
|
||||
property alias itemModel: userResumeModel
|
||||
property string collectionType: "series"
|
||||
|
||||
J.ItemModel {
|
||||
id: userResumeModel
|
||||
loader: J.ResumeItemsLoader {
|
||||
id: userResumeLoader
|
||||
apiClient: appWindow.apiClient
|
||||
limit: 12
|
||||
//recursive: true
|
||||
}
|
||||
}
|
||||
loader: J.ResumeItemsLoader {
|
||||
id: userResumeLoader
|
||||
apiClient: appWindow.apiClient
|
||||
limit: 12
|
||||
//recursive: true
|
||||
}
|
||||
}
|
||||
MoreSection {
|
||||
ItemChildrenShowcase {
|
||||
//- Section header for next episodes in a TV show that an user was watching.
|
||||
text: qsTr("Next up")
|
||||
clickable: false
|
||||
busy: showNextUpLoader.status === J.ModelStatus.Loading
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: carrouselView
|
||||
property alias itemModel: showNextUpModel
|
||||
property string collectionType: "series"
|
||||
|
||||
J.ItemModel {
|
||||
id: showNextUpModel
|
||||
loader: J.NextUpLoader {
|
||||
id: showNextUpLoader
|
||||
apiClient: appWindow.apiClient
|
||||
enableUserData: true
|
||||
}
|
||||
}
|
||||
loader: J.NextUpLoader {
|
||||
id: showNextUpLoader
|
||||
apiClient: appWindow.apiClient
|
||||
enableUserData: true
|
||||
}
|
||||
}
|
||||
Repeater {
|
||||
model: mediaLibraryModel
|
||||
MoreSection {
|
||||
ItemChildrenShowcase {
|
||||
text: model.name
|
||||
busy: userItemModel.status !== J.UsersViewsLoader.Ready
|
||||
onHeaderClicked: appWindow.navigateToItem(model.jellyfinId, model.mediaType, model.type, model.isFolder);
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: carrouselView
|
||||
property alias itemModel: userItemModel
|
||||
property string collectionType: model.collectionType || ""
|
||||
|
||||
J.ItemModel {
|
||||
id: userItemModel
|
||||
loader: J.LatestMediaLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: jellyfinId
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: mediaLibraryLoader
|
||||
onReady: userItemModel.reload()
|
||||
}
|
||||
onHeaderClicked: appWindow.navigateToItem(model.jellyfinId, model.collectionType, model.type, model.isFolder);
|
||||
collectionType: model.collectionType || ""
|
||||
loader: J.LatestMediaLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: jellyfinId
|
||||
}
|
||||
Connections {
|
||||
target: mediaLibraryLoader
|
||||
onReady: loader.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,50 +161,6 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: carrouselView
|
||||
SilicaListView {
|
||||
property bool isPortrait: Utils.usePortraitCover(collectionType)
|
||||
id: list
|
||||
clip: true
|
||||
height: {
|
||||
if (count > 0) {
|
||||
if (isPortrait) {
|
||||
Constants.libraryDelegatePosterHeight
|
||||
} else {
|
||||
Constants.libraryDelegateHeight
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation { easing.type: Easing.OutQuad; duration: 300 }
|
||||
}
|
||||
model: itemModel
|
||||
width: parent.width
|
||||
orientation: ListView.Horizontal
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
spacing: Theme.paddingLarge
|
||||
delegate: LibraryItemDelegate {
|
||||
property string id: model.jellyfinId
|
||||
title: model.name
|
||||
poster: Utils.itemModelImageUrl(appWindow.apiClient.baseUrl, model.jellyfinId, model.imageTags["Primary"], "Primary", {"height": height})
|
||||
Binding on blurhash {
|
||||
when: poster !== ""
|
||||
value: model.imageBlurHashes["Primary"][model.imageTags["Primary"]]
|
||||
}
|
||||
landscape: !isPortrait
|
||||
progress: (typeof model.userDataPlayedProgress !== 0.0) ? model.userDataPlayedPercentage / 100 : 0.0
|
||||
|
||||
onClicked: {
|
||||
appWindow.navigateToItem(model.jellyfinId, model.mediaType, model.type, model.isFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state: "default"
|
||||
states: [
|
||||
State {
|
||||
|
|
|
@ -73,10 +73,9 @@ BaseDetailPage {
|
|||
}
|
||||
PullDownMenu {
|
||||
id: downMenu
|
||||
visible: visibleChildren.length > 0
|
||||
visible: pageRoot.allowSort
|
||||
MenuItem {
|
||||
id: sortMenuItem
|
||||
visible: pageRoot.allowSort
|
||||
//: Menu item for selecting the sort order of a collection
|
||||
text: qsTr("Sort by")
|
||||
onClicked: pageStack.push(sortPageComponent)
|
||||
|
|
138
sailfish/qml/pages/itemdetails/MusicLibraryPage.qml
Normal file
138
sailfish/qml/pages/itemdetails/MusicLibraryPage.qml
Normal file
|
@ -0,0 +1,138 @@
|
|||
import QtQuick 2.6
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
import nl.netsoj.chris.Jellyfin 1.0 as J
|
||||
|
||||
import "../../components"
|
||||
import "../.."
|
||||
|
||||
BaseDetailPage {
|
||||
id: musicLibraryPage
|
||||
property bool _firstTimeLoaded: false
|
||||
|
||||
onStatusChanged: {
|
||||
if (status == PageStatus.Active) {
|
||||
_firstTimeLoaded = true
|
||||
}
|
||||
}
|
||||
|
||||
SilicaFlickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: content.height
|
||||
|
||||
Component {
|
||||
id: albumArtistLoaderComponent
|
||||
J.AlbumArtistLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: itemData.jellyfinId
|
||||
autoReload: false
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: albumLoaderComponent
|
||||
J.UserItemsLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: itemData.jellyfinId
|
||||
includeItemTypes: "MusicAlbum"
|
||||
recursive: true
|
||||
sortBy: "SortName"
|
||||
autoReload: false
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: playlistLoaderComponent
|
||||
J.UserItemsLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: itemData.jellyfinId
|
||||
includeItemTypes: "Playlist"
|
||||
recursive: true
|
||||
sortBy: "SortName"
|
||||
autoReload: false
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width
|
||||
|
||||
PageHeader {
|
||||
title: itemData.name
|
||||
}
|
||||
|
||||
ItemChildrenShowcase {
|
||||
//: Header on music library: Recently added music albums
|
||||
text: qsTr("Recently added")
|
||||
//collapseWhenEmpty: false
|
||||
extraBusy: !_firstTimeLoaded
|
||||
clickable: false
|
||||
loader: J.LatestMediaLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: itemData.jellyfinId
|
||||
autoReload: _firstTimeLoaded && itemData.jellyfinId.length > 0
|
||||
includeItemTypes: "Audio"
|
||||
limit: 12
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ItemChildrenShowcase {
|
||||
text: qsTr("Albums")
|
||||
//collapseWhenEmpty: false
|
||||
extraBusy: !_firstTimeLoaded
|
||||
loader: J.UserItemsLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: itemData.jellyfinId
|
||||
includeItemTypes: "MusicAlbum"
|
||||
autoReload: _firstTimeLoaded && itemData.jellyfinId.length > 0
|
||||
sortBy: "Random"
|
||||
recursive: true
|
||||
limit: 12
|
||||
}
|
||||
onHeaderClicked: pageStack.push(Qt.resolvedUrl("CollectionPage.qml"), {
|
||||
"loader": albumLoaderComponent.createObject(musicLibraryPage),
|
||||
//: Page title for the list of all albums within the music library
|
||||
"pageTitle": qsTr("Albums")
|
||||
})
|
||||
}
|
||||
|
||||
ItemChildrenShowcase {
|
||||
text: qsTr("Playlists")
|
||||
//collapseWhenEmpty: false
|
||||
extraBusy: !_firstTimeLoaded
|
||||
loader: J.UserItemsLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: itemData.jellyfinId
|
||||
includeItemTypes: "Playlist"
|
||||
autoReload: _firstTimeLoaded && itemData.jellyfinId.length > 0
|
||||
sortBy: "Random"
|
||||
recursive: true
|
||||
limit: 12
|
||||
}
|
||||
onHeaderClicked: pageStack.push(Qt.resolvedUrl("CollectionPage.qml"), {
|
||||
"loader": playlistLoaderComponent.createObject(musicLibraryPage),
|
||||
//: Page title for the list of all playlists within the music library
|
||||
"pageTitle": qsTr("Playlists")
|
||||
})
|
||||
}
|
||||
|
||||
ItemChildrenShowcase {
|
||||
//: Header for music artists
|
||||
text: qsTr("Artists")
|
||||
//collapseWhenEmpty: false
|
||||
extraBusy: !_firstTimeLoaded
|
||||
loader: J.AlbumArtistLoader {
|
||||
apiClient: appWindow.apiClient
|
||||
parentId: itemData.jellyfinId
|
||||
autoReload: _firstTimeLoaded && itemData.jellyfinId.length > 0
|
||||
limit: 12
|
||||
}
|
||||
onHeaderClicked: pageStack.push(Qt.resolvedUrl("CollectionPage.qml"), {
|
||||
"loader": albumArtistLoaderComponent.createObject(musicLibraryPage),
|
||||
"allowSort": false,
|
||||
//: Page title for the list of all artists within the music library
|
||||
"pageTitle": qsTr("Artists")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue