1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2025-09-05 10:12:46 +00:00

Added track selection and minor UI improvements

This commit is contained in:
Chris Josten 2020-09-25 17:14:44 +02:00
parent 1eb6a8fb5d
commit 020c968f9c
18 changed files with 271 additions and 68 deletions

19
qml/Utils.js Normal file
View file

@ -0,0 +1,19 @@
.pragma library
/**
* Converts miliseconds to a h:mm:ss format
*/
function timeToText(time) {
if (time < 0) return "??:??:??"
var hours = Math.floor(time / (60 * 60 * 1000))
var left = time % (60 * 60 * 1000)
var minutes = Math.floor(left / (60 * 1000))
left = time % (60 * 1000)
var seconds = Math.floor(left / 1000)
return hours + ":" + (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "")+ seconds
}
function ticksToText(ticks) {
return timeToText(ticks / 10000);
}

View file

@ -26,10 +26,11 @@ Rectangle {
}
FastBlur {
cached: true
anchors.fill: backgroundImage
source: backgroundImage
opacity: dimmedOpacity
radius: 100
radius: 50
}
Image {

View file

@ -18,6 +18,8 @@ SilicaItem {
readonly property bool landscape: videoOutput.contentRect.width > videoOutput.contentRect.height
property MediaPlayer player
readonly property bool hudVisible: !hud.hidden
property alias audioTrack: mediaSource.audioIndex
property alias subtitleTrack: mediaSource.subtitleIndex
// Force a Light on Dark theme since I doubt that there are persons who are willing to watch a Video
// on a white background.

View file

@ -1,5 +1,41 @@
import QtQuick 2.0
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../"
import "../../Utils.js" as Utils
Column {
property var itemData
spacing: Theme.paddingMedium
PlayToolbar {
onPlayPressed: pageStack.push(Qt.resolvedUrl("../../pages/VideoPage.qml"),
{"itemId": itemId, "itemData": itemData, "audioTrack": trackSelector.audioTrack,
"subtitleTrack": trackSelector.subtitleTrack })
}
VideoTrackSelector {
id: trackSelector
width: parent.width
tracks: itemData.MediaStreams
}
PlainLabel {
text: "sub: %1 dub: %2".arg(trackSelector.subtitleTrack).arg(trackSelector.audioTrack)
}
PlainLabel {
id: tinyDetails
text: qsTr("Released: %1 — Run time: %2").arg(itemData.ProductionYear).arg(Utils.ticksToText(itemData.RunTimeTicks))
}
PlainLabel {
id: overviewText
text: itemData.Overview
font.pixelSize: Theme.fontSizeSmall
color: Theme.secondaryHighlightColor
}
Item {
}

View file

@ -0,0 +1,23 @@
import QtQuick 2.6
import Sailfish.Silica 1.0
Row {
signal playPressed()
anchors {
//left: parent.left
right: parent.right
leftMargin: Theme.horizontalPageMargin
rightMargin: Theme.horizontalPageMargin
}
spacing: Theme.paddingMedium
IconButton {
id: favouriteButton
icon.source: "image://theme/icon-m-favorite"
}
IconButton {
id: playButton
icon.source: "image://theme/icon-l-play"
onPressed: playPressed()
}
}

View file

@ -0,0 +1,8 @@
import QtQuick 2.6
import Sailfish.Silica 1.0
ViewPlaceholder {
enabled: true
text: qsTr("Item type unsupported")
hintText: qsTr("This is still an alpha version :)")
}

View file

@ -0,0 +1,67 @@
import QtQuick 2.6
import Sailfish.Silica 1.0
Column {
property var tracks
readonly property int audioTrack: audioSelector.currentItem ? audioSelector.currentItem._index : 0
readonly property int subtitleTrack: subitleSelector.currentItem._index
ListModel {
id: audioModel
}
ListModel {
id: subtitleModel
}
ComboBox {
id: audioSelector
label: qsTr("Audio track")
menu: ContextMenu {
Repeater {
model: audioModel
MenuItem {
readonly property int _index: model.Index
text: model.DisplayTitle
}
}
}
}
ComboBox {
id: subitleSelector
label: qsTr("Subtitle track")
menu: ContextMenu {
MenuItem {
readonly property int _index: -1
//: Value in ComboBox to disable subtitles
text: qsTr("Off")
}
Repeater {
model: subtitleModel
MenuItem {
readonly property int _index: model.Index
text: model.DisplayTitle
}
}
}
}
onTracksChanged: {
audioModel.clear()
subtitleModel.clear()
for(var i = 0; i < tracks.length; i++) {
var track = tracks[i];
switch(track.Type) {
case "Audio":
audioModel.append(track)
break;
case "Subtitle":
subtitleModel.append(track)
break;
default:
break;
}
}
}
}

View file

@ -2,6 +2,8 @@ import QtQuick 2.6
import QtMultimedia 5.6
import Sailfish.Silica 1.0
import "../../Utils.js" as Utils
/**
* The video "hud" or controls. This is the overlay displayed over a video player, which contains controls
* and playback information.
@ -92,7 +94,7 @@ Item {
anchors.left: parent.left
anchors.leftMargin: Theme.horizontalPageMargin
anchors.verticalCenter: progressSlider.verticalCenter
text: timeToText(player.position)
text: Utils.timeToText(player.position)
}
Slider {
@ -112,21 +114,12 @@ Item {
anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin
anchors.verticalCenter: progress.verticalCenter
text: timeToText(player.duration)
text: Utils.timeToText(player.duration)
}
}
}
function timeToText(time) {
if (time < 0) return "??:??:??"
var hours = Math.floor(time / (60 * 60 * 1000))
var left = time % (60 * 60 * 1000)
var minutes = Math.floor(left / (60 * 1000))
left = time % (60 * 1000)
var seconds = Math.floor(left / 1000)
return hours + ":" + (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "")+ seconds
}
Connections {
target: player

View file

@ -2,8 +2,13 @@ import QtQuick 2.6
import QtMultimedia 5.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import "../components"
CoverBackground {
readonly property MediaPlayer player: appWindow.mediaPlayer
property var mData: appWindow.itemData
Rectangle {
anchors.fill: parent
@ -17,12 +22,27 @@ CoverBackground {
}*/
}
// As a temporary fallback, use the poster image
RemoteImage {
anchors.fill: parent
source: mData.ImageTags["Primary"] ? ApiClient.baseUrl + "/Items/" + mData.Id
+ "/Images/Primary?maxHeight=" + height + "&tag=" + mData.ImageTags["Primary"]
: ""
fillMode: Image.PreserveAspectCrop
}
CoverActionList {
CoverAction {
id: playPause
iconSource: player.playbackState === MediaPlayer.PlayingState ? "image://theme/icon-cover-pause"
: "image://theme/icon-cover-play"
onTriggered: {
if (player.playbackState === MediaPlayer.PlayingState) {
player.pause()
} else {
player.play()
}
}
}
}

View file

@ -81,37 +81,24 @@ Page {
height: Theme.paddingLarge
}
PlainLabel {
id: overviewText
text: itemData.Overview
visible: text.length > 0
font.pixelSize: Theme.fontSizeSmall
Loader {
active: itemData != undefined
asynchronous: true
width: parent.width
source: {
switch (itemData.Type){
case "Movie":
return Qt.resolvedUrl("../components/itemdetails/FilmDetails.qml")
default:
return Qt.resolvedUrl("../components/itemdetails/UnsupportedDetails.qml")
}
}
onLoaded: {
item.itemData = Qt.binding(function() { return pageRoot.itemData; })
}
}
Item {
visible: overviewText.visible
width: 1
height: Theme.paddingLarge
}
Row {
anchors {
//left: parent.left
right: parent.right
leftMargin: Theme.horizontalPageMargin
rightMargin: Theme.horizontalPageMargin
}
spacing: Theme.paddingMedium
IconButton {
id: favouriteButton
icon.source: "image://theme/icon-m-favorite"
}
IconButton {
id: playButton
icon.source: "image://theme/icon-l-play"
onPressed: pageStack.push(Qt.resolvedUrl("VideoPage.qml"), {"itemId": itemId, "itemData": itemData})
}
}
}
}

View file

@ -84,7 +84,7 @@ Page {
}
}
HorizontalScrollDecorator {}
UserItemModel {
UserItemLatestModel {
id: userItemModel
apiClient: ApiClient
parentId: model.id

View file

@ -13,6 +13,9 @@ Page {
id: videoPage
property string itemId
property var itemData
property int audioTrack
property int subtitleTrack
allowedOrientations: Orientation.All
showNavigationIndicator: videoPlayer.hudVisible
@ -22,6 +25,8 @@ Page {
itemId: videoPage.itemId
player: appWindow.mediaPlayer
title: itemData.Name
audioTrack: videoPage.audioTrack
subtitleTrack: videoPage.subtitleTrack
onLandscapeChanged: {
console.log("Is landscape: " + landscape)
@ -31,8 +36,13 @@ Page {
}
onStatusChanged: {
if (status == PageStatus.Inactive) {
switch(status) {
case PageStatus.Inactive:
videoPlayer.stop()
break;
case PageStatus.Active:
appWindow.itemData = videoPage.itemData
break;
}
}
}