mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2024-12-22 22:15:17 +00:00
Implemented collections + misc UI improvements
* There is a basic collection page, allowing the user to browse through collections. It has a sort function, that sort of works * Item cards now show a bar indicating play time * Item cards now have a black/white (depending on theme) shim, improving readability. * The resume watching section now actually loads items
This commit is contained in:
parent
5ea17070fe
commit
5d395ad7b6
|
@ -37,6 +37,7 @@ DISTFILES += \
|
|||
qml/components/MoreSection.qml \
|
||||
qml/components/PlainLabel.qml \
|
||||
qml/components/RemoteImage.qml \
|
||||
qml/components/Shim.qml \
|
||||
qml/components/UserGridDelegate.qml \
|
||||
qml/components/VideoPlayer.qml \
|
||||
qml/components/itemdetails/CollectionFolder.qml \
|
||||
|
@ -51,6 +52,7 @@ DISTFILES += \
|
|||
qml/cover/CoverPage.qml \
|
||||
qml/cover/PosterCover.qml \
|
||||
qml/cover/VideoCover.qml \
|
||||
qml/pages/CollectionPage.qml \
|
||||
qml/pages/DetailPage.qml \
|
||||
qml/pages/LegalPage.qml \
|
||||
qml/pages/MainPage.qml \
|
||||
|
|
|
@ -7,4 +7,5 @@ QtObject {
|
|||
readonly property real libraryDelegateHeight: Screen.width / 3
|
||||
|
||||
readonly property real libraryDelegatePosterHeight: Screen.width / 2
|
||||
readonly property real libraryProgressHeight: Theme.paddingMedium
|
||||
}
|
||||
|
|
|
@ -35,5 +35,5 @@ function itemModelImageUrl(baseUrl, itemId, tag, type, options) {
|
|||
}
|
||||
|
||||
function usePortraitCover(itemType) {
|
||||
return ["Series", "Movie"].indexOf(itemType) >= 0
|
||||
return ["Series", "Movie", "tvshows", "movies"].indexOf(itemType) >= 0
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ BackgroundItem {
|
|||
property alias poster: posterImage.source
|
||||
property alias title: titleText.text
|
||||
property bool landscape: false
|
||||
property real progress: 0.0
|
||||
|
||||
width: Constants.libraryDelegateWidth
|
||||
height: landscape ? Constants.libraryDelegateHeight : Constants.libraryDelegatePosterHeight
|
||||
|
||||
|
@ -32,17 +34,14 @@ BackgroundItem {
|
|||
visible: root.highlighted
|
||||
}*/
|
||||
|
||||
Rectangle {
|
||||
Shim {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
height: titleText.height * 1.5 + Theme.paddingSmall * 2
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: "transparent"; }
|
||||
GradientStop { position: 1.0; color: Theme.highlightDimmerColor }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Label {
|
||||
|
@ -58,4 +57,15 @@ BackgroundItem {
|
|||
truncationMode: TruncationMode.Fade
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: progress
|
||||
anchors {
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
}
|
||||
height: Theme.paddingSmall
|
||||
color: Theme.highlightColor
|
||||
width: root.progress * parent.width
|
||||
}
|
||||
}
|
||||
|
|
12
qml/components/Shim.qml
Normal file
12
qml/components/Shim.qml
Normal file
|
@ -0,0 +1,12 @@
|
|||
import QtQuick 2.6
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
Rectangle {
|
||||
property real shimOpacity: 1.0
|
||||
property color shimColor: Theme.overlayBackgroundColor
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: Theme.rgba(shimColor, 0.0); }
|
||||
GradientStop { position: 1.0; color: Theme.rgba(shimColor, shimOpacity); }
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick 2.6
|
||||
|
||||
Item {
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ Column {
|
|||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
bottom: parent.bottom
|
||||
}
|
||||
width: Constants.libraryDelegateWidth
|
||||
|
@ -35,6 +34,31 @@ Column {
|
|||
source: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": height})
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
clip: true
|
||||
|
||||
// Makes the progress bar stand out more
|
||||
Shim {
|
||||
anchors {
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
}
|
||||
height: parent.height / 3
|
||||
shimColor: Theme.overlayBackgroundColor
|
||||
shimOpacity: Theme.opacityOverlay
|
||||
//width: model.userData.PlayedPercentage * parent.width / 100
|
||||
visible: episodeProgress.width > 0 // It doesn't look nice when it's visible on every image
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: episodeProgress
|
||||
anchors {
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
}
|
||||
height: Theme.paddingMedium
|
||||
width: model.userData.PlayedPercentage * parent.width / 100
|
||||
color: Theme.highlightColor
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
|
|
|
@ -22,6 +22,7 @@ CoverBackground {
|
|||
imageTypes: ["Primary"]
|
||||
sortBy: ["IsFavoriteOrLiked", "Random"]
|
||||
recursive: true
|
||||
parentId: appWindow.collectionId
|
||||
Component.onCompleted: reload()
|
||||
}
|
||||
|
||||
|
@ -32,6 +33,7 @@ CoverBackground {
|
|||
imageTypes: ["Primary"]
|
||||
sortBy: ["IsFavoriteOrLiked", "Random"]
|
||||
recursive: true
|
||||
parentId: appWindow.collectionId
|
||||
Component.onCompleted: reload()
|
||||
}
|
||||
|
||||
|
@ -59,7 +61,8 @@ CoverBackground {
|
|||
clip: true
|
||||
height: row1.height
|
||||
width: height
|
||||
source: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": row1.height})
|
||||
source: model.id ? Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": row1.height})
|
||||
: ""
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +123,16 @@ CoverBackground {
|
|||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: appWindow
|
||||
onCollectionIdChanged: {
|
||||
randomItems1.parentId = collectionId
|
||||
randomItems2.parentId = collectionId
|
||||
randomItems1.reload()
|
||||
randomItems2.reload()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
property bool odd: false
|
||||
running: true
|
||||
|
|
|
@ -12,16 +12,11 @@ ApplicationWindow {
|
|||
property bool _hasInitialized: false
|
||||
// The global mediaPlayer instance
|
||||
readonly property MediaPlayer mediaPlayer: _mediaPlayer
|
||||
property url backgroundSource
|
||||
onBackgroundSourceChanged: {
|
||||
if (backgroundSource) {
|
||||
appWindow._overlayBackgroundSource.backgroundItem.source = backgroundSource
|
||||
} else {
|
||||
appWindow._overlayBackgroundSource.backgroundItem.source = Theme.backgroundImage
|
||||
}
|
||||
}
|
||||
|
||||
// Data of the currently selected item. For use on the cover.
|
||||
property var itemData
|
||||
// Id of the collection currently browsing. For use on the cover.
|
||||
property string collectionId
|
||||
|
||||
//FIXME: proper error handling
|
||||
Connections {
|
||||
|
|
179
qml/pages/CollectionPage.qml
Normal file
179
qml/pages/CollectionPage.qml
Normal file
|
@ -0,0 +1,179 @@
|
|||
import QtQuick 2.6
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
import nl.netsoj.chris.Jellyfin 1.0
|
||||
|
||||
import ".."
|
||||
import "../components"
|
||||
import "../Utils.js" as Utils
|
||||
|
||||
Page {
|
||||
id: pageRoot
|
||||
property var itemId
|
||||
property var itemData
|
||||
property bool _loading: true
|
||||
|
||||
UserItemModel {
|
||||
id: collectionModel
|
||||
apiClient: ApiClient
|
||||
parentId: itemData.Id || ""
|
||||
sortBy: ["SortName"]
|
||||
}
|
||||
|
||||
SilicaGridView {
|
||||
id: gridView
|
||||
anchors.fill: parent
|
||||
model: collectionModel
|
||||
cellWidth: Constants.libraryDelegateWidth
|
||||
cellHeight: Utils.usePortraitCover(itemData.CollectionType) ? Constants.libraryDelegatePosterHeight
|
||||
: Constants.libraryDelegateHeight
|
||||
header: PageHeader {
|
||||
title: itemData.Name || qsTr("Loading")
|
||||
}
|
||||
PullDownMenu {
|
||||
id: downMenu
|
||||
MenuItem {
|
||||
//: Menu item for selecting the sort order of a collection
|
||||
text: qsTr("Sort by")
|
||||
onClicked: pageStack.push(sortPageComponent)
|
||||
}
|
||||
busy: collectionModel.status == ApiModel.Loading
|
||||
}
|
||||
delegate: GridItem {
|
||||
RemoteImage {
|
||||
id: itemImage
|
||||
anchors.fill: parent
|
||||
source: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxWidth": width})
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
clip: true
|
||||
}
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
}
|
||||
height: itemName.height + Theme.paddingSmall * 2
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: "transparent" }
|
||||
GradientStop { position: 1.0; color: Theme.highlightDimmerColor }
|
||||
}
|
||||
visible: itemImage.status !== Image.Null
|
||||
}
|
||||
Label {
|
||||
id: itemName
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: Theme.paddingMedium
|
||||
right: parent.right
|
||||
rightMargin: Theme.paddingMedium
|
||||
bottom: parent.bottom
|
||||
bottomMargin: Theme.paddingSmall
|
||||
}
|
||||
text: model.name
|
||||
truncationMode: TruncationMode.Fade
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
onClicked: {
|
||||
switch(model.type) {
|
||||
case "Folder":
|
||||
pageStack.push(Qt.resolvedUrl("CollectionPage.qml"), {"itemId": model.id})
|
||||
break;
|
||||
default:
|
||||
pageStack.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ViewPlaceholder {
|
||||
enabled: gridView.count == 0 && !pageRoot._loading
|
||||
text: qsTr("Empty collection")
|
||||
hintText: qsTr("Add some items to this collection!")
|
||||
}
|
||||
|
||||
VerticalScrollDecorator {}
|
||||
}
|
||||
|
||||
PageBusyIndicator {
|
||||
running: pageRoot._loading
|
||||
}
|
||||
|
||||
onItemIdChanged: {
|
||||
itemData = {}
|
||||
if (itemId.length && PageStatus.Active) {
|
||||
pageRoot._loading = true
|
||||
ApiClient.fetchItem(itemId)
|
||||
}
|
||||
}
|
||||
|
||||
onStatusChanged: {
|
||||
if (status == PageStatus.Deactivating) {
|
||||
backdrop.clear()
|
||||
}
|
||||
if (status == PageStatus.Active) {
|
||||
if (itemId && !itemData) {
|
||||
ApiClient.fetchItem(itemId)
|
||||
appWindow.collectionId = itemId
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ApiClient
|
||||
onItemFetched: {
|
||||
if (itemId === pageRoot.itemId) {
|
||||
pageRoot.itemData = result
|
||||
pageRoot._loading = false
|
||||
console.log(JSON.stringify(result))
|
||||
collectionModel.parentId = result.Id
|
||||
collectionModel.reload()
|
||||
if (status == PageStatus.Active) {
|
||||
appWindow.itemData = null
|
||||
appWindow.collectionId = itemId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: sortPageComponent
|
||||
Page {
|
||||
id: sortPage
|
||||
|
||||
ListModel {
|
||||
id: sortOptions
|
||||
ListElement { name: qsTr("Name"); value: "SortName"; }
|
||||
ListElement { name: qsTr("Play count"); value: "PlayCount"; }
|
||||
ListElement { name: qsTr("Date added"); value: "DateCreated"; }
|
||||
}
|
||||
|
||||
SilicaListView {
|
||||
anchors.fill: parent
|
||||
model: sortOptions
|
||||
header: PageHeader {
|
||||
title: qsTr("Sort by")
|
||||
}
|
||||
delegate: ListItem {
|
||||
Label {
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
right: parent.right
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
text: model.name
|
||||
}
|
||||
onClicked: {
|
||||
collectionModel.sortBy = [model.value]
|
||||
collectionModel.reload()
|
||||
pageStack.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -30,13 +30,10 @@ Page {
|
|||
if (_backdropImages && _backdropImages.length > 0) {
|
||||
var rand = Math.floor(Math.random() * (_backdropImages.length - 0.001))
|
||||
console.log("Random: ", rand)
|
||||
//backdrop.source = ApiClient.baseUrl + "/Items/" + itemId + "/Images/Backdrop/" + rand + "?tag=" + _backdropImages[rand] + "&maxHeight" + height
|
||||
appWindow.backgroundSource = ApiClient.baseUrl + "/Items/" + itemId + "/Images/Backdrop/" + rand + "?tag=" + _backdropImages[rand] + "&maxHeight" + height
|
||||
backdrop.source = ApiClient.baseUrl + "/Items/" + itemId + "/Images/Backdrop/" + rand + "?tag=" + _backdropImages[rand] + "&maxHeight" + height
|
||||
} else if (_parentBackdropImages && _parentBackdropImages.length > 0) {
|
||||
console.log(parentId)
|
||||
//backdrop.source = ApiClient.baseUrl + "/Items/" + itemData.ParentBackdropItemId + "/Images/Backdrop/0?tag=" + _parentBackdropImages[0]
|
||||
appWindow.backgroundSource = ApiClient.baseUrl + "/Items/" + itemData.ParentBackdropItemId + "/Images/Backdrop/0?tag=" + _parentBackdropImages[0]
|
||||
Theme.backgroundGlowColor
|
||||
backdrop.source = ApiClient.baseUrl + "/Items/" + itemData.ParentBackdropItemId + "/Images/Backdrop/0?tag=" + _parentBackdropImages[0]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,6 @@ Page {
|
|||
id: page
|
||||
allowedOrientations: Orientation.All
|
||||
|
||||
ViewPlaceholder {
|
||||
|
||||
}
|
||||
|
||||
SilicaFlickable {
|
||||
anchors.fill: parent
|
||||
|
||||
|
@ -50,6 +46,20 @@ Page {
|
|||
MoreSection {
|
||||
text: qsTr("Resume watching")
|
||||
clickable: false
|
||||
busy: userResumeModel.status == ApiModel.Loading
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: carrouselView
|
||||
property alias itemModel: userResumeModel
|
||||
property string collectionType: "series"
|
||||
|
||||
UserItemResumeModel {
|
||||
id: userResumeModel
|
||||
apiClient: ApiClient
|
||||
limit: 12
|
||||
recursive: true
|
||||
}
|
||||
}
|
||||
}
|
||||
MoreSection {
|
||||
text: qsTr("Next up")
|
||||
|
@ -65,45 +75,14 @@ Page {
|
|||
MoreSection {
|
||||
text: model.name
|
||||
busy: userItemModel.status != ApiModel.Ready
|
||||
property string collectionType: model.collectionType || ""
|
||||
|
||||
onHeaderClicked: pageStack.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id})
|
||||
|
||||
SilicaListView {
|
||||
clip: true
|
||||
height: {
|
||||
if (count > 0) {
|
||||
if (["tvshows", "movies"].indexOf(collectionType) == -1) {
|
||||
Constants.libraryDelegateHeight
|
||||
} else {
|
||||
Constants.libraryDelegatePosterHeight
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation { duration: 300 }
|
||||
}
|
||||
onHeaderClicked: pageStack.push(Qt.resolvedUrl("CollectionPage.qml"), {"itemId": model.id})
|
||||
Loader {
|
||||
width: parent.width
|
||||
model: userItemModel
|
||||
orientation: ListView.Horizontal
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
spacing: Theme.paddingLarge
|
||||
delegate: LibraryItemDelegate {
|
||||
property string id: model.id
|
||||
title: model.name
|
||||
poster: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": height})
|
||||
/*model.imageTags["Primary"] ? ApiClient.baseUrl + "/Items/" + model.id
|
||||
+ "/Images/Primary?maxHeight=" + height + "&tag=" + model.imageTags["Primary"]
|
||||
: ""*/
|
||||
landscape: !Utils.usePortraitCover(model.type)
|
||||
sourceComponent: carrouselView
|
||||
property alias itemModel: userItemModel
|
||||
property string collectionType: model.collectionType || ""
|
||||
|
||||
onClicked: {
|
||||
pageStack.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id})
|
||||
}
|
||||
}
|
||||
UserItemLatestModel {
|
||||
id: userItemModel
|
||||
apiClient: ApiClient
|
||||
|
@ -165,6 +144,49 @@ Page {
|
|||
if (force || (ApiClient.authenticated && !_modelsLoaded)) {
|
||||
_modelsLoaded = true;
|
||||
mediaLibraryModel.reload()
|
||||
userResumeModel.reload()
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: carrouselView
|
||||
SilicaListView {
|
||||
id: list
|
||||
clip: true
|
||||
height: {
|
||||
if (count > 0) {
|
||||
if (["tvshows", "movies"].indexOf(collectionType) == -1) {
|
||||
Constants.libraryDelegateHeight
|
||||
} else {
|
||||
Constants.libraryDelegatePosterHeight
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation { 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.id
|
||||
title: model.name
|
||||
poster: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags["Primary"], "Primary", {"maxHeight": height})
|
||||
/*model.imageTags["Primary"] ? ApiClient.baseUrl + "/Items/" + model.id
|
||||
+ "/Images/Primary?maxHeight=" + height + "&tag=" + model.imageTags["Primary"]
|
||||
: ""*/
|
||||
landscape: !Utils.usePortraitCover(model.type)
|
||||
progress: model.userData.PlayedPercentage / 100
|
||||
|
||||
onClicked: {
|
||||
pageStack.push(Qt.resolvedUrl("DetailPage.qml"), {"itemId": model.id})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,19 +9,13 @@ ApiModel::ApiModel(QString path, bool hasRecordResponse, bool addUserId, QObject
|
|||
}
|
||||
|
||||
void ApiModel::reload() {
|
||||
this->setStatus(Loading);
|
||||
m_startIndex = 0;
|
||||
load(RELOAD);
|
||||
}
|
||||
|
||||
void ApiModel::load(LoadType type) {
|
||||
qDebug() << (type == RELOAD ? "RELOAD" : "LOAD_MORE");
|
||||
switch(type) {
|
||||
case RELOAD:
|
||||
this->setStatus(Loading);
|
||||
break;
|
||||
case LOAD_MORE:
|
||||
this->setStatus(LoadingMore);
|
||||
break;
|
||||
}
|
||||
if (m_apiClient == nullptr) {
|
||||
qWarning() << "Please set the apiClient property before (re)loading";
|
||||
return;
|
||||
|
@ -187,6 +181,7 @@ bool ApiModel::canFetchMore(const QModelIndex &parent) const {
|
|||
|
||||
void ApiModel::fetchMore(const QModelIndex &parent) {
|
||||
if (parent.isValid()) return;
|
||||
this->setStatus(LoadingMore);
|
||||
load(LOAD_MORE);
|
||||
}
|
||||
|
||||
|
@ -200,6 +195,7 @@ void registerModels(const char *URI) {
|
|||
qmlRegisterType<UserViewModel>(URI, 1, 0, "UserViewModel");
|
||||
qmlRegisterType<UserItemModel>(URI, 1, 0, "UserItemModel");
|
||||
qmlRegisterType<UserItemLatestModel>(URI, 1, 0, "UserItemLatestModel");
|
||||
qmlRegisterType<UserItemResumeModel>(URI, 1, 0, "UserItemResumeModel");
|
||||
qmlRegisterType<ShowSeasonsModel>(URI, 1, 0, "ShowSeasonsModel");
|
||||
qmlRegisterType<ShowEpisodesModel>(URI, 1, 0, "ShowEpisodesModel");
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ protected:
|
|||
QList<QString> m_fields;
|
||||
QList<QString> m_imageTypes;
|
||||
QList<QString> m_sortBy = {};
|
||||
bool m_recursive;
|
||||
bool m_recursive = false;
|
||||
|
||||
QHash<int, QByteArray> m_roles;
|
||||
|
||||
|
@ -218,13 +218,13 @@ private:
|
|||
class PublicUserModel : public ApiModel {
|
||||
public:
|
||||
explicit PublicUserModel (QObject *parent = nullptr)
|
||||
: ApiModel ("/users/public", "", false, parent) { }
|
||||
: ApiModel ("/users/public", false, false, parent) { }
|
||||
};
|
||||
|
||||
class UserViewModel : public ApiModel {
|
||||
public:
|
||||
explicit UserViewModel (QObject *parent = nullptr)
|
||||
: ApiModel ("/Users/{{user}}/Views", "Items", false, parent) {}
|
||||
: ApiModel ("/Users/{{user}}/Views", true, false, parent) {}
|
||||
};
|
||||
|
||||
class UserItemModel : public ApiModel {
|
||||
|
@ -232,6 +232,13 @@ public:
|
|||
explicit UserItemModel (QObject *parent = nullptr)
|
||||
: ApiModel ("/Users/{{user}}/Items", true, false, parent) {}
|
||||
};
|
||||
|
||||
class UserItemResumeModel : public ApiModel {
|
||||
public:
|
||||
explicit UserItemResumeModel (QObject *parent = nullptr)
|
||||
: ApiModel ("/Users/{{user}}/Items/Resume", true, false, parent) {}
|
||||
};
|
||||
|
||||
class UserItemLatestModel : public ApiModel {
|
||||
public:
|
||||
explicit UserItemLatestModel (QObject *parent = nullptr)
|
||||
|
|
|
@ -58,6 +58,38 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CollectionPage</name>
|
||||
<message>
|
||||
<source>Loading</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sort by</source>
|
||||
<extracomment>Menu item for selecting the sort order of a collection</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Empty collection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add some items to this collection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play count</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date added</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CoverPage</name>
|
||||
<message>
|
||||
|
|
Loading…
Reference in a new issue