1
0
Fork 0
mirror of https://github.com/HenkKalkwater/harbour-sailfin.git synced 2025-09-06 02:32:44 +00:00

Deserialized a list! Restructured project!

I finally got deserializing lists working. Exposing them to QML was not
a trivial task either. Note that I didn't do it the clean way. Nested
lists are not supported. But it works!

Because I got so frustarted at one point trying to implement things the
right way, I restructured the project to seperate the Sailfish code from
the Qt code and created a new, empty desktop project. The Qt code has
been transformed into a happy little library, to which the Sailfish OS
application links.

Note that QMake doesn't seem to strip the library for some reason.
This commit is contained in:
Chris Josten 2020-10-08 03:00:08 +02:00
parent 4e3395c4e5
commit 1e80ceb697
77 changed files with 507 additions and 213 deletions

View file

@ -0,0 +1,71 @@
/*
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
*/
/*
File taken and adapted from hutspot. Licensed under the MIT license.
Copyright (c) 2019 sailfish-spotify contributors
View ../licenses/MIT.txt for the full license.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import QtGraphicalEffects 1.0
/**
* A silica-like background for displaying backdrops.
*/
Rectangle {
property alias source: backgroundImage.source
property alias sourceSize: backgroundImage.sourceSize
property real dimmedOpacity: Theme.opacityFaint
readonly property alias status: backgroundImage.status
color: Theme.colorScheme == Theme.DarkOnLight ? "#fff" : "#000"
z: -1
opacity: status == Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
Image {
id: backgroundImage
cache: true
smooth: false
asynchronous: true
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
visible: false
}
FastBlur {
cached: true
anchors.fill: backgroundImage
source: backgroundImage
opacity: dimmedOpacity
radius: 100
}
Image {
anchors.fill: parent
fillMode: Image.Tile
source: "image://theme/graphic-shader-texture"
opacity: 0.1
visible: parent.visible
}
function clear() {
//source = ""
}
}

View file

@ -0,0 +1,45 @@
/*
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
BackgroundItem {
property alias text: label.text
property alias iconSource: icon.source
HighlightImage {
id: icon
anchors {
top: parent.top
topMargin: Theme.paddingMedium
left: parent.left
leftMargin: Theme.horizontalPageMargin
bottom: parent.bottom
bottomMargin: Theme.paddingMedium
}
}
Label {
id: label
anchors {
left: icon.right
leftMargin: Theme.paddingMedium
verticalCenter: parent.verticalCenter
}
}
}

View file

@ -0,0 +1,90 @@
/*
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.6
import Sailfish.Silica 1.0
import ".."
/**
* Delegate for displaying an item in the library.
*/
BackgroundItem {
id: root
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
RemoteImage {
id: posterImage
clip: true
anchors {
left: parent.left
top: parent.top
right: parent.right
bottom: parent.bottom
}
fillMode: Image.PreserveAspectCrop
fallbackColor: Utils.colorFromString(title)
}
/*Rectangle {
anchors.fill: posterImage
color: Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity)
visible: root.highlighted
}*/
Shim {
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: titleText.height * 1.5 + Theme.paddingSmall * 2
}
Label {
id: titleText
anchors {
left: parent.left
bottom: parent.bottom
right: parent.right
leftMargin: Theme.paddingMedium
rightMargin: Theme.paddingMedium
bottomMargin: Theme.paddingSmall
}
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
}
}

View file

@ -0,0 +1,114 @@
/*
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
*/
/*
File taken and adapted from Storeman. Licensed under the MIT license.
Copyright (c) 2017 Petr Tsymbarovich
View ../licenses/MIT.txt for the full license.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
Item {
id: root
property alias text: label.text
property alias textAlignment: label.horizontalAlignment
property bool busy: false
property bool clickable: true
property int depth: 0
readonly property color _color: {
if (!clickable) {
Theme.primaryColor
} else if (enabled) {
if (highlighted) {
Theme.highlightColor
} else {
Theme.primaryColor
}
} else {
Theme.secondaryColor
}
}
default property alias content: container.data
signal headerClicked()
implicitHeight: backgroundItem.height + container.height
width: parent.width
BackgroundItem {
id: backgroundItem
enabled: parent.enabled && parent.clickable
width: parent.width
height: Theme.itemSizeMedium
onClicked: root.headerClicked()
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: Theme.rgba(Theme.highlightBackgroundColor, 0.15) }
GradientStop { position: 1.0; color: "transparent" }
}
}
Label {
id: label
anchors {
left: parent.left
right: image.left
verticalCenter: parent.verticalCenter
leftMargin: Theme.horizontalPageMargin + depth * Theme.paddingLarge
rightMargin: Theme.paddingMedium
}
horizontalAlignment: Text.AlignRight
truncationMode: TruncationMode.Fade
color: _color
}
Image {
id: image
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
rightMargin: Theme.horizontalPageMargin
}
visible: root.enabled && root.clickable && !root.busy
source: "image://theme/icon-m-right?" + _color
}
BusyIndicator {
id: busyIndicator
running: root.busy
anchors.centerIn: image
size: BusyIndicatorSize.Small
}
}
Item {
id: container
anchors {
top: backgroundItem.bottom
left: parent.left
right: parent.right
}
width: parent.width
height: children.length > 0 ? children[0].height : 0
}
}

View file

@ -0,0 +1,37 @@
/*
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.6
import Sailfish.Silica 1.0
/**
* A label with the most commonly used settings set
*/
Label {
anchors {
left: parent.left
right: parent.right
leftMargin: Theme.horizontalPageMargin
rightMargin: Theme.horizontalPageMargin
}
color: Theme.highlightColor
linkColor: Theme.primaryColor
onLinkActivated: Qt.openUrlExternally(link)
wrapMode: Text.WordWrap
}

View file

@ -0,0 +1,80 @@
/*
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.6
import Sailfish.Silica 1.0
Column {
property alias imageSource : playImage.source
property real imageAspectRatio: 1.0
property real playProgress: 0.0
signal playPressed(bool startFromBeginning)
spacing: Theme.paddingLarge
BackgroundItem {
width: parent.width
height: width / imageAspectRatio
HighlightImage {
id: playImage
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
clip: true
}
Rectangle {
anchors.fill: parent
color: Theme.rgba(Theme.overlayBackgroundColor, Theme.opacityLow)
}
Icon {
id: playButton
source: "image://theme/icon-l-play"
anchors.centerIn: parent
highlighted: parent.highlighted
}
Rectangle {
anchors {
left: parent.left
bottom: parent.bottom
}
height: Theme.paddingMedium
color: Theme.highlightColor
width: parent.width * playProgress
}
onClicked: playPressed(false)
}
Row {
anchors {
//left: parent.left
right: parent.right
leftMargin: Theme.horizontalPageMargin
rightMargin: Theme.horizontalPageMargin
}
spacing: Theme.paddingMedium
IconButton {
id: playFromBeginning
icon.source: "image://theme/icon-m-backup"
visible: playProgress > 0
onClicked: playPressed(true)
}
IconButton {
id: favouriteButton
icon.source: "image://theme/icon-m-favorite"
}
}
}

View file

@ -0,0 +1,53 @@
/*
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.6
import Sailfish.Silica 1.0
/**
* An image for "remote" images (loaded over e.g. http), with a spinner and a fallback image
*/
HighlightImage {
property string fallbackImage
property bool usingFallbackImage
property color fallbackColor: Theme.highlightColor
asynchronous: true
Rectangle {
id: fallbackBackground
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: fallbackColor; }
GradientStop { position: 1.0; color: Theme.highlightDimmerFromColor(fallbackColor, Theme.colorScheme); }
}
visible: parent.status == Image.Error || parent.status == Image.Null || parent.status == Image.Loading
}
BusyIndicator {
anchors.centerIn: parent
running: parent.status == Image.Loading
}
HighlightImage {
id: fallbackImageItem
anchors.centerIn: parent
visible: parent.status == Image.Error || parent.status == Image.Null
source: fallbackImage ? fallbackImage : "image://theme/icon-m-question"
}
}

View file

@ -0,0 +1,32 @@
/*
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.6
import Sailfish.Silica 1.0
Rectangle {
property real shimOpacity: 1.0
property color shimColor: Theme.overlayBackgroundColor
property bool upsideDown: false
gradient: Gradient {
GradientStop { position: upsideDown ? 1.0 : 0.0; color: Theme.rgba(shimColor, 0.0); }
GradientStop { position: upsideDown ? 0.0 : 1.0; color: Theme.rgba(shimColor, shimOpacity); }
}
}

View file

@ -0,0 +1,54 @@
/*
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.6
import Sailfish.Silica 1.0
GridItem {
id: root
property string image
property alias name: nameLabel.text
RemoteImage {
id: userImage
anchors.fill: parent
source: root.image ? root.image : "image://theme/icon-m-contact?" + ((root.highlighted || root.down) ? Theme.highlightColor : Theme.primaryColor)
fillMode: Image.PreserveAspectCrop
clip: true
}
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "transparent" }
GradientStop { position: 1.0; color: Theme.overlayBackgroundColor }
}
}
Label {
id: nameLabel
anchors {
leftMargin: Theme.horizontalPageMargin
rightMargin: Theme.horizontalPageMargin
right: parent.right
left: parent.left
bottom: parent.bottom
bottomMargin: Theme.paddingSmall
}
text: qsTr("Other account")
color: (root.highlighted || root.down) ? Theme.highlightColor : Theme.secondaryColor
}
}

View file

@ -0,0 +1,122 @@
/*
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.6
import QtMultimedia 5.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 1.0
import "videoplayer"
import "../"
/**
* A videoPlayer for Jellyfin videos
*/
SilicaItem {
id: playerRoot
property string itemId
property string title
property int progress
readonly property bool landscape: videoOutput.contentRect.width > videoOutput.contentRect.height
property MediaPlayer player
readonly property bool hudVisible: !hud.hidden || player.error !== MediaPlayer.NoError
property alias audioTrack: mediaSource.audioIndex
property alias subtitleTrack: mediaSource.subtitleIndex
property int startTicks: 0
// Force a Light on Dark theme since I doubt that there are persons who are willing to watch a Video
// on a white background.
palette.colorScheme: Theme.LightOnDark
// Blackground to prevent the ambience from leaking through
Rectangle {
anchors.fill: parent
color: "black"
}
PlaybackManager {
id: mediaSource
apiClient: ApiClient
itemId: playerRoot.itemId
autoOpen: true
onStreamUrlChanged: {
if (mediaSource.streamUrl != "") {
player.source = streamUrl
}
}
}
Connections {
target: player
onPlaybackStateChanged: mediaSource.state = player.playbackState
onPositionChanged: mediaSource.position = Utils.msToTicks(player.position)
}
VideoOutput {
id: videoOutput
source: player
anchors.fill: parent
}
VideoHud {
id: hud
anchors.fill: parent
player: playerRoot.player
title: videoPlayer.title
Label {
anchors.fill: parent
anchors.margins: Theme.horizontalPageMargin
text: itemId + "\n" + mediaSource.streamUrl + "\n"
+ player.status + "\n"
+ player.bufferProgress + "\n"
+ player.metaData.videoCodec + "@" + player.metaData.videoFrameRate + "(" + player.metaData.videoBitRate + ")" + "\n"
+ player.metaData.audioCodec + "(" + player.metaData.audioBitRate + ")" + "\n"
+ player.errorString + "\n"
font.pixelSize: Theme.fontSizeExtraSmall
wrapMode: "WordWrap"
visible: false
}
}
VideoError {
anchors.fill: videoOutput
player: playerRoot.player
}
function stop() {
player.stop()
}
Connections {
property bool enabled: true
id: playerReadyToSeek
target: player
onPlaybackStateChanged: {
if (!enabled) return;
if (startTicks > 0 && player.playbackState == MediaPlayer.PlayingState) {
console.log("Seeking to " + Utils.ticksToMs(startTicks))
player.seek(Utils.ticksToMs(startTicks))
playerReadyToSeek.enabled = false // Only seek the first time this property changes
}
}
}
}

View file

@ -0,0 +1,95 @@
/*
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.6
import Sailfish.Silica 1.0
import nl.netsoj.chris.Jellyfin 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")
enabled: audioModel.count > 1
menu: ContextMenu {
Repeater {
model: audioModel
MenuItem {
readonly property int _index: model.index
text: model.displayTitle
}
}
}
}
ComboBox {
id: subitleSelector
label: qsTr("Subtitle track")
enabled: subtitleModel.count > 0
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()
if (typeof tracks === "undefined") {
console.log("tracks undefined")
return
}
console.log(tracks)
for(var i = 0; i < tracks.length; i++) {
var track = tracks[i];
switch(track.type) {
case MediaStream.Audio:
audioModel.append(track)
break;
case MediaStream.Subtitle:
subtitleModel.append(track)
break;
default:
console.log("Ignored " + track.displayTitle + "(" + track.type + ")")
break;
}
}
}
}

View file

@ -0,0 +1,91 @@
/*
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.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
Rectangle {
id: videoError
property MediaPlayer player
color: pal.palette.overlayBackgroundColor
opacity: player.error === MediaPlayer.NoError ? 0.0 : 1.0
Behavior on opacity { FadeAnimator {} }
SilicaItem {
id: pal
}
Column {
anchors.centerIn: parent
anchors.margins: Theme.horizontalPageMargin
Label {
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Theme.fontSizeExtraLarge
color: Theme.errorColor
text: {
switch(player.error) {
case MediaPlayer.NoError:
//: Just to be complete if the application shows a video playback error when there's no error.
qsTr("No error");
break;
case MediaPlayer.ResourceError:
//: Video playback error: out of resources
qsTr("Resource allocation error")
break;
case MediaPlayer.FormatError:
//: Video playback error: unsupported format/codec
qsTr("Video format unsupported")
break;
case MediaPlayer.NetworkError:
//: Video playback error: network error
qsTr("Network error")
break;
case MediaPlayer.AccessDenied:
//: Video playback error: access denied
qsTr("Access denied")
break;
case MediaPlayer.ServiceMissing:
//: Video playback error: the media cannot be played because the media service could not be instantiated.
qsTr("Media service missing")
break;
}
}
}
Label {
wrapMode: Text.WordWrap
text: player.errorString
color: Theme.errorColor
width: videoError.width - Theme.horizontalPageMargin * 2
horizontalAlignment: Text.AlignHCenter
}
Item { width: 1; height: Theme.paddingLarge; }
ButtonLayout {
Button {
//: Button to retry loading a video after a failure
text: qsTr("Retry")
onClicked: player.play()
}
}
}
}

View file

@ -0,0 +1,188 @@
/*
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.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.
*/
Item {
id: videoHud
property MediaPlayer player
property string title
property bool _manuallyActivated: false
readonly property bool hidden: opacity == 0.0
Behavior on opacity { FadeAnimator {} }
Rectangle {
id: topBar
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: pageTitle.height
gradient: Gradient {
GradientStop { position: 1.0; color: Theme.rgba(palette.overlayBackgroundColor, 0.15); }
GradientStop { position: 0.0; color: Theme.rgba(palette.overlayBackgroundColor, 0.30); }
}
PageHeader {
id: pageTitle
title: videoHud.title
anchors.fill: parent
titleColor: palette.primaryColor
}
}
Rectangle {
anchors.top: topBar.bottom
anchors.bottom: bottomBar.top
anchors.left: parent.left
anchors.right: parent.right
color: Theme.rgba(palette.overlayBackgroundColor, 0.15)
}
MouseArea {
id: wakeupArea
enabled: true
anchors.fill: parent
onClicked: {
hidden ? videoHud.show(true) : videoHud.hide(true)
console.log("Trying")
}
}
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
size: BusyIndicatorSize.Medium
running: [MediaPlayer.Loading, MediaPlayer.Stalled].indexOf(player.status) >= 0
}
IconButton {
id: playPause
enabled: !hidden
anchors.centerIn: parent
icon.source: player.playbackState == MediaPlayer.PausedState ? "image://theme/icon-l-play" : "image://theme/icon-l-pause"
onClicked: {
if (player.playbackState == MediaPlayer.PlayingState) {
player.pause()
} else {
player.play()
}
}
visible: !busyIndicator.running
}
Rectangle {
id: bottomBar
anchors.bottom: parent.bottom
width: parent.width
height: progress.height
visible: [MediaPlayer.Unavailable, MediaPlayer.Loading, MediaPlayer.NoMedia].indexOf(player.status) == -1
gradient: Gradient {
GradientStop { position: 0.0; color: Theme.rgba(palette.overlayBackgroundColor, 0.15); }
GradientStop { position: 1.0; color: Theme.rgba(palette.overlayBackgroundColor, 0.30); }
}
Item {
id: progress
height: progressSlider.height + 2 * Theme.paddingMedium
width: parent.width
Label {
id: playedTime
anchors.left: parent.left
anchors.leftMargin: Theme.horizontalPageMargin
anchors.verticalCenter: progressSlider.verticalCenter
text: Utils.timeToText(player.position)
}
Slider {
id: progressSlider
enabled: player.seekable
value: player.position
maximumValue: player.duration
stepSize: 1000
anchors.left: playedTime.right
anchors.right: totalTime.left
anchors.verticalCenter: parent.verticalCenter
onDownChanged: if (!down) { player.seek(value) }
}
Label {
id: totalTime
anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin
anchors.verticalCenter: progress.verticalCenter
text: Utils.timeToText(player.duration)
}
}
}
Connections {
target: player
onStatusChanged: {
console.log("New mediaPlayer status: " + player.status)
switch(player.status) {
case MediaPlayer.Loaded:
case MediaPlayer.Buffering:
show(false)
break;
case MediaPlayer.Buffered:
hide(false)
break;
}
}
}
function show(manual) {
_manuallyActivated = manual
if (manual) {
inactivityTimer.restart()
} else {
inactivityTimer.stop()
}
opacity = 1
}
function hide(manual) {
// 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
/*if (!_manuallyActivated && manual) return;
_manuallyActivated = false;*/
opacity = 0
}
Timer {
id: inactivityTimer
interval: 5000
onTriggered: {
hide(true)
}
}
}