From 7c6d8486de174539dbbf7788d172b539f98f7aeb Mon Sep 17 00:00:00 2001 From: Chris Josten Date: Wed, 11 Jan 2023 23:11:02 +0100 Subject: [PATCH] ui: improve empty state, add remote playback indicator --- sailfish/qml/Utils.js | 6 ++- sailfish/qml/components/PlaybackBar.qml | 49 ++++++++++++++++--- sailfish/qml/components/VideoPlayer.qml | 12 ++++- .../qml/components/videoplayer/VideoHud.qml | 3 ++ sailfish/qml/harbour-sailfin.qml | 6 ++- .../qml/pages/ControllableDevicesPage.qml | 2 +- sailfish/qml/pages/VideoPage.qml | 11 ++++- 7 files changed, 76 insertions(+), 13 deletions(-) diff --git a/sailfish/qml/Utils.js b/sailfish/qml/Utils.js index 049c5f5..96e464e 100644 --- a/sailfish/qml/Utils.js +++ b/sailfish/qml/Utils.js @@ -69,7 +69,11 @@ function randomBackdrop(baseUrl, item) { function itemBackdropUrl(baseUrl, item, idx, options) { var extraQuery = propsToQuery(options) - return baseUrl + "/Items/" + item.jellyfinId + "/Images/Backdrop/" + idx + "?tag=" + item.backdropImageTags[idx] + extraQuery; + if (item.backdropImageTags[idx]) { + return baseUrl + "/Items/" + item.jellyfinId + "/Images/Backdrop/" + idx + "?tag=" + item.backdropImageTags[idx] + extraQuery; + } else { + return baseUrl + "/Items/" + item.parentBackdropItemId + "/Images/Backdrop/" + idx + "?tag=" + item.parentBackdropImageTags[idx] + extraQuery; + } } diff --git a/sailfish/qml/components/PlaybackBar.qml b/sailfish/qml/components/PlaybackBar.qml index 5614521..beb1b80 100644 --- a/sailfish/qml/components/PlaybackBar.qml +++ b/sailfish/qml/components/PlaybackBar.qml @@ -48,6 +48,8 @@ PanelBackground { property bool showQueue: false property bool _pageWasShowingNavigationIndicator + readonly property bool _isItemSet: manager.item !== null && manager.item !== undefined && manager.item.jellyfinId.length > 0 + readonly property bool controllingRemote: !manager.controllingSessionLocal readonly property bool mediaLoading: [J.MediaStatus.Loading, J.MediaStatus.Buffering].indexOf(manager.mediaStatus) >= 0 @@ -67,9 +69,12 @@ PanelBackground { top: parent.top } width: height - Binding on blurhash { - when: manager.item !== null && "Primary" in manager.item.imageBlurHashes && "Primary" in manager.item.imageTags - value: manager.item.imageBlurHashes["Primary"][manager.item.imageTags["Primary"]] + blurhash: { + if (_isItemSet && "Primary" in manager.item.imageBlurHashes && "Primary" in manager.item.imageTags) { + return manager.item.imageBlurHashes["Primary"][manager.item.imageTags["Primary"]] + } else { + return "" + } } source: largeAlbumArt.source fillMode: Image.PreserveAspectCrop @@ -125,7 +130,10 @@ PanelBackground { Label { id: name - text: manager.item === null ? qsTr("No media selected") : manager.item.name + text: manager.item.jellyfinId + ? manager.item.name + //: Shown in a bright font when no media is playing in the bottom bar and now playing screen + : qsTr("Nothing is playing") width: Math.min(contentWidth, parent.width) font.pixelSize: Theme.fontSizeMedium maximumLineCount: 1 @@ -133,8 +141,23 @@ PanelBackground { } Label { id: artists + leftPadding: controllingRemote ? remoteIcon.width + Theme.paddingSmall : 0 text: { - if (manager.item === null) return qsTr("Play some media!") + if (!_isItemSet) { + if (controllingRemote) { + //: Shown when no media is being played, but the app is controlling another Jellyfin client + //: %1 is the name of said client + return qsTr("Connected to %1").arg(manager.controllingSessionName) + } else { + return qsTr("Start playing some media!") + } + } + var remoteText = ""; + + if (controllingRemote) { + remoteText = manager.controllingSessionName + " - " + } + switch(manager.item.mediaType) { case "Audio": var links = []; @@ -147,7 +170,7 @@ PanelBackground { .arg(Theme.secondaryColor) ) } - return links.join(", ") + return remoteText + links.join(", ") } return qsTr("No audio") } @@ -162,6 +185,16 @@ PanelBackground { appWindow.navigateToItem(link, "Audio", "MusicArtist", true) } textFormat: Text.StyledText + Icon { + id: remoteIcon + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + height: parent + source: "image://theme/icon-s-device-upload" + visible: controllingRemote + } } } @@ -395,7 +428,9 @@ PanelBackground { }, State { name: "hidden" - when: ((manager.playbackState === J.PlayerState.Stopped && !mediaLoading) || "__hidePlaybackBar" in pageStack.currentPage) && !isFullPage + when: ((manager.playbackState === J.PlayerState.Stopped && !mediaLoading) + || ("__hidePlaybackBar" in pageStack.currentPage && pageStack.currentPage.__hidePlaybackBar)) + && !isFullPage PropertyChanges { target: playbackBarTranslate // + small padding since the ProgressBar otherwise would stick out diff --git a/sailfish/qml/components/VideoPlayer.qml b/sailfish/qml/components/VideoPlayer.qml index 602a2a0..2be0959 100644 --- a/sailfish/qml/components/VideoPlayer.qml +++ b/sailfish/qml/components/VideoPlayer.qml @@ -50,6 +50,16 @@ SilicaItem { color: Theme.overlayBackgroundColor } + RemoteImage { + id: backdrop + anchors.fill: parent + visible: !manager.controllingSessionLocal + || [J.MediaStatus.NoMedia, J.MediaStatus.Loading].indexOf(manager.mediaStatus) >= 0 + fillMode: Image.PreserveAspectFit + source: Utils.itemBackdropUrl(apiClient.baseUrl, item, 0, {"maxWidth": parent.width}) + blurhash: item.imageBlurHashes["Backdrop"][item.backdropImageTags[0]] + } + VideoOutput { id: videoOutput source: manager @@ -64,7 +74,7 @@ SilicaItem { anchors.fill: parent manager: playerRoot.manager title: videoPlayer.title - + alwaysVisible: !manager.controllingSessionLocal } VideoError { diff --git a/sailfish/qml/components/videoplayer/VideoHud.qml b/sailfish/qml/components/videoplayer/VideoHud.qml index 8f6c2d5..79c1c84 100644 --- a/sailfish/qml/components/videoplayer/VideoHud.qml +++ b/sailfish/qml/components/videoplayer/VideoHud.qml @@ -34,6 +34,8 @@ Item { property var manager property string title property bool _manuallyActivated: false + /// Don't allow the HUD to hide + property bool alwaysVisible: false readonly property bool hidden: opacity == 0.0 Behavior on opacity { FadeAnimator {} } @@ -174,6 +176,7 @@ Item { } function hide(manual) { + if (alwaysVisible) return // Don't hide if the user decided on their own to show the hud //if (!manual && _manuallyActivated) return; // Don't give in to the user if they want to hide the hud while it was forced upon them diff --git a/sailfish/qml/harbour-sailfin.qml b/sailfish/qml/harbour-sailfin.qml index f968b5b..d02a233 100644 --- a/sailfish/qml/harbour-sailfin.qml +++ b/sailfish/qml/harbour-sailfin.qml @@ -75,7 +75,7 @@ ApplicationWindow { //cover: CoverBackground {CoverPlaceholder { icon.source: "icon.png"; text: "Sailfin"}} cover: { // Disabled due to buggy Loader behaviour - if ([MediaPlayer.NoMedia, MediaPlayer.InvalidMedia, MediaPlayer.UnknownStatus].indexOf(_playbackManager.mediaStatus) >= 0 + if ([MediaStatus.NoMedia, MediaStatus.InvalidMedia].indexOf(_playbackManager.mediaStatus) >= 0 || _playbackManager.playbackState === MediaPlayer.StoppedState) { return Qt.resolvedUrl("cover/CollectionPage.qml") } else { @@ -134,7 +134,9 @@ ApplicationWindow { } DisplayBlanking { - preventBlanking: playbackManager.playbackState === MediaPlayer.PlayingState && playbackManager.hasVideo + preventBlanking: playbackManager.playbackState === MediaPlayer.PlayingState + && playbackManager.hasVideo + && playbackManager.controllingSessionLocal // Must be controlling a local session } PlaybackBar { diff --git a/sailfish/qml/pages/ControllableDevicesPage.qml b/sailfish/qml/pages/ControllableDevicesPage.qml index 2a40841..a6ec9cf 100644 --- a/sailfish/qml/pages/ControllableDevicesPage.qml +++ b/sailfish/qml/pages/ControllableDevicesPage.qml @@ -25,7 +25,7 @@ Page { property bool isConnected: model.jellyfinId === appWindow.playbackManager.controllingSessionId onClicked: deviceList.activateSession(appWindow.playbackManager, model.index) contentHeight: Theme.itemSizeMedium - HighlightImage { + Icon { id: deviceIcon anchors { left: parent.left diff --git a/sailfish/qml/pages/VideoPage.qml b/sailfish/qml/pages/VideoPage.qml index 9a3666c..d384c21 100644 --- a/sailfish/qml/pages/VideoPage.qml +++ b/sailfish/qml/pages/VideoPage.qml @@ -38,7 +38,16 @@ Page { property int subtitleTrack property bool resume: true - allowedOrientations: Orientation.All + allowedOrientations: { + if (itemData.width !== null && itemData.height !== null) { + return itemData.width / itemData.height > Screen.width / Screen.height + ? Orientation.LandscapeMask + : Orientation.PortraitMask + } else { + return Orientation.All + } + } + showNavigationIndicator: videoPlayer.hudVisible VideoPlayer {