mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2024-11-25 02:15:17 +00:00
Minor UI tweaks
This commit is contained in:
parent
382af84846
commit
eda4994aac
|
@ -74,13 +74,14 @@ function usePortraitCover(itemType) {
|
||||||
/**
|
/**
|
||||||
* Returns the page url for a certain item type.
|
* Returns the page url for a certain item type.
|
||||||
*/
|
*/
|
||||||
function getPageUrl(mediaType, itemType) {
|
function getPageUrl(mediaType, itemType, isFolder) {
|
||||||
switch (itemType.toLowerCase()) {
|
switch (itemType.toLowerCase()) {
|
||||||
case "series":
|
case "series":
|
||||||
return Qt.resolvedUrl("pages/itemdetails/SeriesPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/SeriesPage.qml")
|
||||||
case "movie":
|
case "movie":
|
||||||
return Qt.resolvedUrl("pages/itemdetails/FilmPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/FilmPage.qml")
|
||||||
case "collection":
|
case "collection":
|
||||||
|
case "photoalbum":
|
||||||
return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
|
||||||
case "season":
|
case "season":
|
||||||
return Qt.resolvedUrl("pages/itemdetails/SeasonPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/SeasonPage.qml")
|
||||||
|
@ -88,8 +89,10 @@ function getPageUrl(mediaType, itemType) {
|
||||||
return Qt.resolvedUrl("pages/itemdetails/EpisodePage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/EpisodePage.qml")
|
||||||
case "musicalbum":
|
case "musicalbum":
|
||||||
return Qt.resolvedUrl("pages/itemdetails/MusicAlbumPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/MusicAlbumPage.qml")
|
||||||
|
case "photo":
|
||||||
|
return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
|
||||||
default:
|
default:
|
||||||
switch (mediaType ? mediaType.toLowerCase() : "folder") {
|
switch (mediaType ? mediaType.toLowerCase() : isFolder ? "folder" : "") {
|
||||||
case "folder":
|
case "folder":
|
||||||
return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
|
||||||
case "video":
|
case "video":
|
||||||
|
@ -97,6 +100,7 @@ function getPageUrl(mediaType, itemType) {
|
||||||
case "photo":
|
case "photo":
|
||||||
return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/PhotoPage.qml")
|
||||||
default:
|
default:
|
||||||
|
if (isFolder) return Qt.resolvedUrl("pages/itemdetails/CollectionPage.qml")
|
||||||
return Qt.resolvedUrl("pages/itemdetails/UnsupportedPage.qml")
|
return Qt.resolvedUrl("pages/itemdetails/UnsupportedPage.qml")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,14 @@ Column {
|
||||||
property real imageAspectRatio: 1.0
|
property real imageAspectRatio: 1.0
|
||||||
property real playProgress: 0.0
|
property real playProgress: 0.0
|
||||||
property bool favourited: false
|
property bool favourited: false
|
||||||
|
property alias imageBlurhash: playImage.blurhash
|
||||||
signal playPressed(bool startFromBeginning)
|
signal playPressed(bool startFromBeginning)
|
||||||
spacing: Theme.paddingLarge
|
spacing: Theme.paddingLarge
|
||||||
|
|
||||||
BackgroundItem {
|
BackgroundItem {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: width / imageAspectRatio
|
height: width / imageAspectRatio
|
||||||
HighlightImage {
|
RemoteImage {
|
||||||
id: playImage
|
id: playImage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
|
|
@ -23,7 +23,10 @@ import Sailfish.Silica 1.0
|
||||||
import nl.netsoj.chris.blurhash 1.0
|
import nl.netsoj.chris.blurhash 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An image for "remote" images (loaded over e.g. http), with a spinner and a fallback image
|
* An image for "remote" images (loaded over e.g. http), with a spinner and a fallback image.
|
||||||
|
*
|
||||||
|
* If placed in a page, it will delay the loading of the image until the transition is over,
|
||||||
|
* displaying a simpler blurhash instead, to reduce the stutter during the transition
|
||||||
*/
|
*/
|
||||||
SilicaItem {
|
SilicaItem {
|
||||||
id: root
|
id: root
|
||||||
|
|
113
sailfish/qml/harbour-sailfin.qml.autosave
Normal file
113
sailfish/qml/harbour-sailfin.qml.autosave
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
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 QtMultimedia 5.6
|
||||||
|
import nl.netsoj.chris.Jellyfin 1.0
|
||||||
|
|
||||||
|
import Nemo.Notifications 1.0
|
||||||
|
import Nemo.KeepAlive 1.2
|
||||||
|
|
||||||
|
import "components"
|
||||||
|
import "pages"
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
id: appWindow
|
||||||
|
property bool _hasInitialized: false
|
||||||
|
// The global mediaPlayer instance
|
||||||
|
readonly property MediaPlayer mediaPlayer: _mediaPlayer
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
target: ApiClient
|
||||||
|
onNetworkError: errorNotification.show("Network error: " + error)
|
||||||
|
onConnectionFailed: errorNotification.show("Connect error: " + error)
|
||||||
|
//onConnectionSuccess: errorNotification.show("Success: " + loginMessage)
|
||||||
|
onSetupRequired: {
|
||||||
|
var isInSetup = pageStack.find(function (page) { return typeof page._isSetupPage !== "undefined" }) !== null
|
||||||
|
console.log("Is in setup: " + isInSetup)
|
||||||
|
if (!isInSetup) {
|
||||||
|
pageStack.replace(Qt.resolvedUrl("pages/setup/AddServerPage.qml"), {"backNavigation": false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initialPage: Component {
|
||||||
|
MainPage {
|
||||||
|
Connections {
|
||||||
|
target: ApiClient
|
||||||
|
// Replace the MainPage if no server was set up.
|
||||||
|
|
||||||
|
}
|
||||||
|
onStatusChanged: {
|
||||||
|
if (status == PageStatus.Active && !_hasInitialized) {
|
||||||
|
_hasInitialized = true;
|
||||||
|
ApiClient.restoreSavedSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cover: {
|
||||||
|
if ([MediaPlayer.NoMedia, MediaPlayer.InvalidMedia, MediaPlayer.UnknownStatus].indexOf(mediaPlayer.status) >= 0) {
|
||||||
|
if (itemData) {
|
||||||
|
return Qt.resolvedUrl("cover/PosterCover.qml")
|
||||||
|
} else {
|
||||||
|
return Qt.resolvedUrl("cover/CoverPage.qml")
|
||||||
|
}
|
||||||
|
} else if (mediaPlayer.hasVideo){
|
||||||
|
return Qt.resolvedUrl("cover/VideoCover.qml")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allowedOrientations: Orientation.All
|
||||||
|
|
||||||
|
Notification {
|
||||||
|
id: errorNotification
|
||||||
|
previewSummary: "foo"
|
||||||
|
isTransient: true
|
||||||
|
|
||||||
|
function show(data) {
|
||||||
|
previewSummary = data;
|
||||||
|
publish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPlayer {
|
||||||
|
id: _mediaPlayer
|
||||||
|
autoPlay: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the sytem alive while playing media
|
||||||
|
KeepAlive {
|
||||||
|
enabled: _mediaPlayer.playbackState == MediaPlayer.PlayingState
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayBlanking {
|
||||||
|
preventBlanking: _mediaPlayer.playbackState == MediaPlayer.PlayingState && _mediaPlayer.hasVideo
|
||||||
|
}
|
||||||
|
|
||||||
|
DockedPanel {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -226,7 +226,7 @@ Page {
|
||||||
progress: (typeof model.userData !== "undefined") ? model.userData.playedPercentage / 100 : 0.0
|
progress: (typeof model.userData !== "undefined") ? model.userData.playedPercentage / 100 : 0.0
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
pageStack.push(Utils.getPageUrl(model.mediaType, model.type), {"itemId": model.id})
|
pageStack.push(Utils.getPageUrl(model.mediaType, model.type, model.isFolder), {"itemId": model.id})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,22 +39,18 @@ Page {
|
||||||
//property var itemData: ({})
|
//property var itemData: ({})
|
||||||
property bool _loading: jItem.status === "Loading"
|
property bool _loading: jItem.status === "Loading"
|
||||||
readonly property bool hasLogo: (typeof itemData.ImageTags !== "undefined") && (typeof itemData.ImageTags["Logo"] !== "undefined")
|
readonly property bool hasLogo: (typeof itemData.ImageTags !== "undefined") && (typeof itemData.ImageTags["Logo"] !== "undefined")
|
||||||
readonly property var _backdropImages: itemData.backdropImageTags
|
|
||||||
readonly property var _parentBackdropImages: itemData.parentBackdropImageTags
|
|
||||||
property string _chosenBackdropImage: ""
|
property string _chosenBackdropImage: ""
|
||||||
readonly property string parentId: itemData.ParentId || ""
|
readonly property string parentId: itemData.ParentId || ""
|
||||||
|
|
||||||
on_BackdropImagesChanged: updateBackdrop()
|
|
||||||
on_ParentBackdropImagesChanged: updateBackdrop()
|
|
||||||
|
|
||||||
function updateBackdrop() {
|
function updateBackdrop() {
|
||||||
|
var rand = 0;
|
||||||
if (itemData.backdropImageTags.length > 0) {
|
if (itemData.backdropImageTags.length > 0) {
|
||||||
var rand = Math.floor(Math.random() * (_backdropImages.length - 0.001))
|
rand = Math.floor(Math.random() * (itemData.backdropImageTags.length - 0.001))
|
||||||
console.log("Random: ", rand)
|
console.log("Random: ", rand)
|
||||||
_chosenBackdropImage = ApiClient.baseUrl + "/Items/" + itemId + "/Images/Backdrop/" + rand + "?tag=" + _backdropImages[rand] + "&maxHeight" + height
|
_chosenBackdropImage = ApiClient.baseUrl + "/Items/" + itemId + "/Images/Backdrop/" + rand + "?tag=" +itemData.backdropImageTags[rand] + "&maxHeight" + height
|
||||||
//_chosenBackdropImage = Utils.itemImageUrl(ApiClient.baseUrl, itemData, "Backdrop/" + rand)
|
|
||||||
} else if (itemData.parentBackdropImageTags.length > 0) {
|
} else if (itemData.parentBackdropImageTags.length > 0) {
|
||||||
_chosenBackdropImage = ApiClient.baseUrl + "/Items/" + itemData.parentBackdropItemId + "/Images/Backdrop/0?tag=" + _parentBackdropImages[0]
|
rand = Math.floor(Math.random() * (itemData.parentBackdropImageTags.length - 0.001))
|
||||||
|
_chosenBackdropImage = ApiClient.baseUrl + "/Items/" + itemData.parentBackdropItemId + "/Images/Backdrop/" + rand + "?tag=" + itemData.parentBackdropImageTags[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,11 +72,6 @@ Page {
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
|
||||||
color: "red"
|
|
||||||
text: _chosenBackdropImage || "No backdrop"
|
|
||||||
}
|
|
||||||
|
|
||||||
PageBusyIndicator {
|
PageBusyIndicator {
|
||||||
running: pageRoot._loading
|
running: pageRoot._loading
|
||||||
}
|
}
|
||||||
|
@ -116,6 +107,9 @@ Page {
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
console.log("Status changed: " + newStatus, JSON.stringify(jItem))
|
console.log("Status changed: " + newStatus, JSON.stringify(jItem))
|
||||||
console.log(jItem.mediaStreams)
|
console.log(jItem.mediaStreams)
|
||||||
|
if (status == JellyfinItem.Ready) {
|
||||||
|
updateBackdrop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ BaseDetailPage {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
model: collectionModel
|
model: collectionModel
|
||||||
cellWidth: Constants.libraryDelegateWidth
|
cellWidth: Constants.libraryDelegateWidth
|
||||||
cellHeight: Utils.usePortraitCover(itemData.collectionType) ? Constants.libraryDelegatePosterHeight
|
cellHeight: Utils.usePortraitCover(itemData.type) ? Constants.libraryDelegatePosterHeight
|
||||||
: Constants.libraryDelegateHeight
|
: Constants.libraryDelegateHeight
|
||||||
visible: itemData.status !== JellyfinItem.Error
|
visible: itemData.status !== JellyfinItem.Error
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ BaseDetailPage {
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
}
|
}
|
||||||
onClicked: pageStack.push(Utils.getPageUrl(model.mediaType, model.type), {"itemId": model.id})
|
onClicked: pageStack.push(Utils.getPageUrl(model.mediaType, model.type, model.isFolder), {"itemId": model.id})
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewPlaceholder {
|
ViewPlaceholder {
|
||||||
|
|
|
@ -78,13 +78,14 @@ BaseDetailPage {
|
||||||
model: showSeasonsModel
|
model: showSeasonsModel
|
||||||
clip: true
|
clip: true
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: Screen.width / 2
|
height: Constants.libraryDelegatePosterHeight
|
||||||
orientation: ListView.Horizontal
|
orientation: ListView.Horizontal
|
||||||
spacing: Theme.paddingLarge
|
spacing: Theme.paddingLarge
|
||||||
leftMargin: Theme.horizontalPageMargin
|
leftMargin: Theme.horizontalPageMargin
|
||||||
rightMargin: Theme.horizontalPageMargin
|
rightMargin: Theme.horizontalPageMargin
|
||||||
delegate: LibraryItemDelegate {
|
delegate: LibraryItemDelegate {
|
||||||
poster: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags.primary, "Primary", {"maxHeight": height})
|
poster: Utils.itemModelImageUrl(ApiClient.baseUrl, model.id, model.imageTags.primary, "Primary", {"maxHeight": height})
|
||||||
|
blurhash: model.imageBlurHashes["primary"][model.imageTags.primary]
|
||||||
title: model.name
|
title: model.name
|
||||||
onClicked: pageStack.push(Utils.getPageUrl(model.mediaType, model.type), {"itemId": model.id})
|
onClicked: pageStack.push(Utils.getPageUrl(model.mediaType, model.type), {"itemId": model.id})
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ BaseDetailPage {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
imageSource: Utils.itemImageUrl(ApiClient.baseUrl, itemData, "Primary", {"maxWidth": parent.width})
|
imageSource: Utils.itemImageUrl(ApiClient.baseUrl, itemData, "Primary", {"maxWidth": parent.width})
|
||||||
imageAspectRatio: Constants.horizontalVideoAspectRatio
|
imageAspectRatio: Constants.horizontalVideoAspectRatio
|
||||||
|
imageBlurhash: itemData.imageBlurHashes["Primary"][itemData.imageTags["Primary"]]
|
||||||
favourited: itemData.userData.isFavorite
|
favourited: itemData.userData.isFavorite
|
||||||
playProgress: itemData.userData.playedPercentage / 100
|
playProgress: itemData.userData.playedPercentage / 100
|
||||||
onPlayPressed: pageStack.push(Qt.resolvedUrl("../VideoPage.qml"),
|
onPlayPressed: pageStack.push(Qt.resolvedUrl("../VideoPage.qml"),
|
||||||
|
|
Loading…
Reference in a new issue