mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2024-11-22 01:05:17 +00:00
Add music library page
This commit is contained in:
parent
0c0b91dc4b
commit
dc9c3ea1b8
|
@ -253,6 +253,8 @@ extern template void setRequestLimit(Loader::GetPublicUsersParams ¶ms, int l
|
||||||
extern template bool setRequestStartIndex(Loader::GetPublicUsersParams ¶ms, int offset);
|
extern template bool setRequestStartIndex(Loader::GetPublicUsersParams ¶ms, int offset);
|
||||||
extern template void setRequestLimit(Loader::GetNextUpParams ¶ms, int limit);
|
extern template void setRequestLimit(Loader::GetNextUpParams ¶ms, int limit);
|
||||||
extern template bool setRequestStartIndex(Loader::GetNextUpParams ¶ms, int offset);
|
extern template bool setRequestStartIndex(Loader::GetNextUpParams ¶ms, int offset);
|
||||||
|
extern template void setRequestLimit(Loader::GetAlbumArtistsParams ¶ms, int limit);
|
||||||
|
extern template bool setRequestStartIndex(Loader::GetAlbumArtistsParams ¶ms, int offset);
|
||||||
|
|
||||||
extern template QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result);
|
extern template QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result);
|
||||||
extern template int extractTotalRecordCount(const QList<DTO::UserDto> &result);
|
extern template int extractTotalRecordCount(const QList<DTO::UserDto> &result);
|
||||||
|
|
|
@ -290,6 +290,42 @@ public:
|
||||||
FWDPROP(QString, seriesId, SeriesId)
|
FWDPROP(QString, seriesId, SeriesId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using AlbumArtistLoaderBase = AbstractUserParameterLoader<Model::Item, DTO::BaseItemDto, DTO::BaseItemDtoQueryResult, Jellyfin::Loader::GetAlbumArtistsParams>;
|
||||||
|
class AlbumArtistLoader : public AlbumArtistLoaderBase {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit AlbumArtistLoader(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
FWDLISTPROP(Jellyfin::DTO::ImageTypeClass::Value, enableImageTypes, EnableImageTypes);
|
||||||
|
FWDPROP(bool, enableImages, EnableImages)
|
||||||
|
FWDPROP(bool, enableTotalRecordCount, EnableTotalRecordCount)
|
||||||
|
FWDPROP(bool, enableUserData, EnableUserData)
|
||||||
|
FWDPROP(QStringList, excludeItemTypes, ExcludeItemTypes)
|
||||||
|
FWDLISTPROP(Jellyfin::DTO::ItemFieldsClass::Value, fields, Fields)
|
||||||
|
FWDLISTPROP(Jellyfin::DTO::ItemFilterClass::Value, filters, Filters)
|
||||||
|
FWDPROP(QStringList, genreIds, GenreIds)
|
||||||
|
FWDPROP(QStringList, genres, Genres)
|
||||||
|
FWDPROP(qint32, imageTypeLimit, ImageTypeLimit)
|
||||||
|
FWDPROP(QStringList, includeItemTypes, IncludeItemTypes)
|
||||||
|
FWDPROP(bool, isFavorite, IsFavorite)
|
||||||
|
FWDPROP(int, limit, Limit)
|
||||||
|
FWDPROP(QStringList, mediaTypes, MediaTypes)
|
||||||
|
FWDPROP(double, minCommunityRating, MinCommunityRating)
|
||||||
|
FWDPROP(QString, nameLessThan, NameLessThan)
|
||||||
|
FWDPROP(QString, nameStartsWith, NameStartsWith)
|
||||||
|
FWDPROP(QString, nameStartsWithOrGreater, NameStartsWithOrGreater)
|
||||||
|
FWDPROP(QStringList, officialRatings, OfficialRatings)
|
||||||
|
FWDPROP(QString, parentId, ParentId)
|
||||||
|
FWDPROP(QStringList, personIds, PersonIds)
|
||||||
|
FWDPROP(QStringList, personTypes, PersonTypes)
|
||||||
|
FWDPROP(QString, searchTerm, SearchTerm)
|
||||||
|
FWDPROP(int, startIndex, StartIndex)
|
||||||
|
FWDPROP(QStringList, studioIds, StudioIds)
|
||||||
|
FWDPROP(QStringList, studios, Studios)
|
||||||
|
FWDPROP(QStringList, tags, Tags)
|
||||||
|
FWDPROP(QString, userId, UserId)
|
||||||
|
FWDLISTPROP(int, years, Years);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base class for each model that works with items.
|
* @brief Base class for each model that works with items.
|
||||||
|
|
|
@ -184,6 +184,16 @@ bool setRequestStartIndex(Loader::GetNextUpParams ¶ms, int offset) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void setRequestLimit(Loader::GetAlbumArtistsParams ¶ms, int limit) {
|
||||||
|
params.setLimit(limit);
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
bool setRequestStartIndex(Loader::GetAlbumArtistsParams ¶ms, int offset) {
|
||||||
|
params.setStartIndex(offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result) {
|
QList<DTO::UserDto> extractRecords(const QList<DTO::UserDto> &result) {
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -77,6 +77,7 @@ void JellyfinPlugin::registerTypes(const char *uri) {
|
||||||
qmlRegisterType<ViewModel::ShowEpisodesLoader>(uri, 1, 0, "ShowEpisodesLoader");
|
qmlRegisterType<ViewModel::ShowEpisodesLoader>(uri, 1, 0, "ShowEpisodesLoader");
|
||||||
qmlRegisterType<ViewModel::NextUpLoader>(uri, 1, 0, "NextUpLoader");
|
qmlRegisterType<ViewModel::NextUpLoader>(uri, 1, 0, "NextUpLoader");
|
||||||
qmlRegisterType<ViewModel::PublicUsersLoader>(uri, 1, 0, "PublicUsersLoader");
|
qmlRegisterType<ViewModel::PublicUsersLoader>(uri, 1, 0, "PublicUsersLoader");
|
||||||
|
qmlRegisterType<ViewModel::AlbumArtistLoader>(uri, 1, 0, "AlbumArtistLoader");
|
||||||
|
|
||||||
// Enumerations
|
// Enumerations
|
||||||
qmlRegisterUncreatableType<Jellyfin::DTO::GeneralCommandTypeClass>(uri, 1, 0, "GeneralCommandType", "Is an enum");
|
qmlRegisterUncreatableType<Jellyfin::DTO::GeneralCommandTypeClass>(uri, 1, 0, "GeneralCommandType", "Is an enum");
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
#include "JellyfinQt/viewmodel/itemmodel.h"
|
#include "JellyfinQt/viewmodel/itemmodel.h"
|
||||||
|
|
||||||
|
#include "JellyfinQt/loader/http/artists.h"
|
||||||
#include "JellyfinQt/loader/http/items.h"
|
#include "JellyfinQt/loader/http/items.h"
|
||||||
#include "JellyfinQt/loader/http/userlibrary.h"
|
#include "JellyfinQt/loader/http/userlibrary.h"
|
||||||
#include "JellyfinQt/loader/http/userviews.h"
|
#include "JellyfinQt/loader/http/userviews.h"
|
||||||
|
@ -57,6 +58,9 @@ ShowEpisodesLoader::ShowEpisodesLoader(QObject *parent)
|
||||||
NextUpLoader::NextUpLoader(QObject *parent)
|
NextUpLoader::NextUpLoader(QObject *parent)
|
||||||
: NextUpLoaderBase(new Jellyfin::Loader::HTTP::GetNextUpLoader(), parent) {}
|
: NextUpLoaderBase(new Jellyfin::Loader::HTTP::GetNextUpLoader(), parent) {}
|
||||||
|
|
||||||
|
AlbumArtistLoader::AlbumArtistLoader(QObject *parent)
|
||||||
|
: AlbumArtistLoaderBase(new Jellyfin::Loader::HTTP::GetAlbumArtistsLoader(), parent) {}
|
||||||
|
|
||||||
ItemModel::ItemModel(QObject *parent)
|
ItemModel::ItemModel(QObject *parent)
|
||||||
: ApiModel<Model::Item>(parent) {
|
: ApiModel<Model::Item>(parent) {
|
||||||
connect(this, &QAbstractItemModel::rowsInserted, this, &ItemModel::onInsertItems);
|
connect(this, &QAbstractItemModel::rowsInserted, this, &ItemModel::onInsertItems);
|
||||||
|
@ -128,7 +132,7 @@ QSharedPointer<Model::Item> ItemModel::itemAt(int index) {
|
||||||
|
|
||||||
void ItemModel::onInsertItems(const QModelIndex &parent, int start, int end) {
|
void ItemModel::onInsertItems(const QModelIndex &parent, int start, int end) {
|
||||||
if (parent.isValid()) return;
|
if (parent.isValid()) return;
|
||||||
qDebug() << "Connecting " << (end - start + 1) << "items!";
|
//qDebug() << "Connecting " << (end - start + 1) << "items!";
|
||||||
for (int i = start; i <= end; i++) {
|
for (int i = start; i <= end; i++) {
|
||||||
connect(itemAt(i).data(), &Model::Item::userDataChanged, this, &ItemModel::onUserDataUpdated);
|
connect(itemAt(i).data(), &Model::Item::userDataChanged, this, &ItemModel::onUserDataUpdated);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ set(sailfin_QML_SOURCES
|
||||||
qml/components/videoplayer/VideoError.qml
|
qml/components/videoplayer/VideoError.qml
|
||||||
qml/components/videoplayer/VideoHud.qml
|
qml/components/videoplayer/VideoHud.qml
|
||||||
qml/components/IconListItem.qml
|
qml/components/IconListItem.qml
|
||||||
|
qml/components/ItemChildrenShowcase.qml
|
||||||
qml/components/JItem.qml
|
qml/components/JItem.qml
|
||||||
qml/components/LibraryItemDelegate.qml
|
qml/components/LibraryItemDelegate.qml
|
||||||
qml/components/MoreSection.qml
|
qml/components/MoreSection.qml
|
||||||
|
@ -54,6 +55,7 @@ set(sailfin_QML_SOURCES
|
||||||
qml/pages/itemdetails/FilmPage.qml
|
qml/pages/itemdetails/FilmPage.qml
|
||||||
qml/pages/itemdetails/MusicAlbumPage.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/PhotoPage.qml
|
||||||
qml/pages/itemdetails/SeasonPage.qml
|
qml/pages/itemdetails/SeasonPage.qml
|
||||||
qml/pages/itemdetails/SeriesPage.qml
|
qml/pages/itemdetails/SeriesPage.qml
|
||||||
|
|
|
@ -112,6 +112,13 @@ function getPageUrl(mediaType, itemType, isFolder) {
|
||||||
return Qt.resolvedUrl("pages/itemdetails/MusicAlbumPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/MusicAlbumPage.qml")
|
||||||
case "photo":
|
case "photo":
|
||||||
return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
|
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:
|
default:
|
||||||
switch (mediaType ? mediaType.toLowerCase() : isFolder ? "folder" : "") {
|
switch (mediaType ? mediaType.toLowerCase() : isFolder ? "folder" : "") {
|
||||||
case "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,19 +78,10 @@ Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MoreSection {
|
ItemChildrenShowcase {
|
||||||
//- Section header for films and TV shows that an user hasn't completed yet.
|
//- Section header for films and TV shows that an user hasn't completed yet.
|
||||||
text: qsTr("Resume watching")
|
text: qsTr("Resume watching")
|
||||||
clickable: false
|
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 {
|
loader: J.ResumeItemsLoader {
|
||||||
id: userResumeLoader
|
id: userResumeLoader
|
||||||
apiClient: appWindow.apiClient
|
apiClient: appWindow.apiClient
|
||||||
|
@ -98,53 +89,29 @@ Page {
|
||||||
//recursive: true
|
//recursive: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
ItemChildrenShowcase {
|
||||||
}
|
|
||||||
MoreSection {
|
|
||||||
//- Section header for next episodes in a TV show that an user was watching.
|
//- Section header for next episodes in a TV show that an user was watching.
|
||||||
text: qsTr("Next up")
|
text: qsTr("Next up")
|
||||||
clickable: false
|
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 {
|
loader: J.NextUpLoader {
|
||||||
id: showNextUpLoader
|
id: showNextUpLoader
|
||||||
apiClient: appWindow.apiClient
|
apiClient: appWindow.apiClient
|
||||||
enableUserData: true
|
enableUserData: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: mediaLibraryModel
|
model: mediaLibraryModel
|
||||||
MoreSection {
|
ItemChildrenShowcase {
|
||||||
text: model.name
|
text: model.name
|
||||||
busy: userItemModel.status !== J.UsersViewsLoader.Ready
|
onHeaderClicked: appWindow.navigateToItem(model.jellyfinId, model.collectionType, model.type, model.isFolder);
|
||||||
onHeaderClicked: appWindow.navigateToItem(model.jellyfinId, model.mediaType, model.type, model.isFolder);
|
collectionType: model.collectionType || ""
|
||||||
Loader {
|
|
||||||
width: parent.width
|
|
||||||
sourceComponent: carrouselView
|
|
||||||
property alias itemModel: userItemModel
|
|
||||||
property string collectionType: model.collectionType || ""
|
|
||||||
|
|
||||||
J.ItemModel {
|
|
||||||
id: userItemModel
|
|
||||||
loader: J.LatestMediaLoader {
|
loader: J.LatestMediaLoader {
|
||||||
apiClient: appWindow.apiClient
|
apiClient: appWindow.apiClient
|
||||||
parentId: jellyfinId
|
parentId: jellyfinId
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Connections {
|
Connections {
|
||||||
target: mediaLibraryLoader
|
target: mediaLibraryLoader
|
||||||
onReady: userItemModel.reload()
|
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"
|
state: "default"
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
|
|
|
@ -73,10 +73,9 @@ BaseDetailPage {
|
||||||
}
|
}
|
||||||
PullDownMenu {
|
PullDownMenu {
|
||||||
id: downMenu
|
id: downMenu
|
||||||
visible: visibleChildren.length > 0
|
visible: pageRoot.allowSort
|
||||||
MenuItem {
|
MenuItem {
|
||||||
id: sortMenuItem
|
id: sortMenuItem
|
||||||
visible: pageRoot.allowSort
|
|
||||||
//: Menu item for selecting the sort order of a collection
|
//: Menu item for selecting the sort order of a collection
|
||||||
text: qsTr("Sort by")
|
text: qsTr("Sort by")
|
||||||
onClicked: pageStack.push(sortPageComponent)
|
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…
Reference in a new issue