1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2024-11-25 18:35:17 +00:00
harbour-sailfin/sailfish/qml/pages/MainPage.qml

293 lines
9.5 KiB
QML
Raw Permalink Normal View History

/*
Sailfin: a Jellyfin client written using Qt
Copyright (C) 2020 Chris Josten
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
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 "../components"
2021-01-17 16:08:07 +00:00
import "../components/search"
import "../"
import "../Utils.js" as Utils
/**
* Main page, which simply shows some content of every library, as well as next items.
*/
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
allowedOrientations: Orientation.All
SilicaFlickable {
2021-01-17 16:08:07 +00:00
id: mainView
anchors.fill: parent
// PullDownMenu and PushUpMenu must be declared in SilicaFlickable, SilicaListView or SilicaGridView
PullDownMenu {
MenuItem {
text: qsTr("Settings")
onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml"))
}
MenuItem {
text: qsTr("Refresh")
onClicked: loadModels(true)
}
busy: mediaLibraryModel.status == ApiModel.Loading
}
// Tell SilicaFlickable the height of its content.
contentHeight: column.visible ? column.height : errorColumn.height
// Place our content in a Column. The PageHeader is always placed at the top
// of the page, followed by our content.
Column {
id: column
visible: mediaLibraryModel.status != ApiModel.Error
width: page.width
//spacing: Theme.paddingLarge
UserViewModel {
id: mediaLibraryModel2
apiClient: ApiClient
}
2021-01-17 16:08:07 +00:00
Item {
id: searchBoxPlaceholder
width: parent.width
height: searchBox.height
2021-01-17 16:08:07 +00:00
SearchField {
id: searchBox
width: parent.width
2021-01-17 16:08:07 +00:00
placeholderText: qsTr("Search")
}
2020-09-27 01:14:05 +00:00
}
2021-01-17 16:08:07 +00:00
Label {
text: "%1 results".arg(searchView.count)
2020-09-27 01:14:05 +00:00
}
2021-01-17 16:08:07 +00:00
Column {
id: homeView
width: parent.width
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 {
2021-01-17 16:08:07 +00:00
text: qsTr("Next up")
clickable: false
busy: showNextUpModel.status == ApiModel.Loading
Loader {
width: parent.width
sourceComponent: carrouselView
2021-01-17 16:08:07 +00:00
property alias itemModel: showNextUpModel
property string collectionType: "series"
2021-01-17 16:08:07 +00:00
ShowNextUpModel {
id: showNextUpModel
apiClient: ApiClient
limit: 12
}
2021-01-17 16:08:07 +00:00
}
}
UserViewModel {
id: mediaLibraryModel
apiClient: ApiClient
}
Repeater {
model: mediaLibraryModel
MoreSection {
text: model.name
busy: userItemModel.status != ApiModel.Ready
onHeaderClicked: pageStack.push(Qt.resolvedUrl("itemdetails/CollectionPage.qml"), {"itemId": model.id})
Loader {
width: parent.width
sourceComponent: carrouselView
property alias itemModel: userItemModel
property string collectionType: model.collectionType || ""
UserItemLatestModel {
id: userItemModel
apiClient: ApiClient
parentId: model.id
limit: 12
}
Connections {
target: mediaLibraryModel
onStatusChanged: {
console.log("MediaLibraryModel status " + status)
if (status == ApiModel.Ready) {
userItemModel.reload()
}
}
}
}
}
}
}
}
Column {
id: errorColumn
width: parent.width
visible: mediaLibraryModel.status == ApiModel.Error
PageHeader {
title: qsTr("Network error")
}
Item {
width: 1
height: page.height / 3
}
PlainLabel {
text: qsTr("An error has occurred. Please try again.")
}
Item { width: 1; height: Theme.paddingLarge }
Button {
text: qsTr("Retry")
anchors.horizontalCenter: parent.horizontalCenter
onClicked: loadModels(true)
}
Item { width: 1; height: Theme.paddingLarge }
}
}
2021-01-17 16:08:07 +00:00
SearchResults {
id: searchView
anchors.fill: parent
header: Item {
width: parent.width
height: searchBox.height
}
query: searchBox.text
visible: false
opacity: 0
}
states: [
State {
name: "search"
when: searchBox.text.length
PropertyChanges {
target: searchView
visible: true
opacity: 1
}
PropertyChanges {
target: mainView
opacity: 0
visible: false
}
ParentChange {
target: searchBox
parent: searchView.headerItem
}
StateChangeScript {
script: searchBox.forceActiveFocus()
}
}
]
onStatusChanged: {
if (status == PageStatus.Active) {
appWindow.itemData = null
loadModels(false)
}
}
Connections {
target: ApiClient
onAuthenticatedChanged: loadModels(false)
}
/**
2021-01-17 16:08:07 +00:00
* Loads models if not loaded. Set force to true to reload models
* even if loaded.
*/
function loadModels(force) {
if (force || (ApiClient.authenticated && !_modelsLoaded)) {
_modelsLoaded = true;
mediaLibraryModel.reload()
userResumeModel.reload()
showNextUpModel.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})
blurhash: model.imageBlurHashes["primary"][model.imageTags["primary"]]
landscape: !Utils.usePortraitCover(collectionType)
progress: (typeof model.userData !== "undefined") ? model.userData.playedPercentage / 100 : 0.0
onClicked: {
pageStack.push(Utils.getPageUrl(model.mediaType, model.type), {"itemId": model.id})
}
}
}
2020-09-27 01:14:05 +00:00
}
}