harbour-tooter/qml/pages/components/MediaItem.qml
2022-12-02 11:32:30 +01:00

323 lines
8.6 KiB
QML

import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
ListItem {
id: item
property string url
property string mediaUrl
property string mimeType: 'audio/mp3'
property int length
property bool _isAudio: mimeType.substring(0, 6) === "audio/"
property bool _isImage: mimeType.substring(0, 6) === "image/"
function _toTime(s)
{
if (s < 0)
{
return "-";
}
s /= 1000;
var seconds = Math.floor(s) % 60;
s /= 60;
var minutes = Math.floor(s) % 60;
s /= 60;
var hours = Math.floor(s);
if (seconds < 10)
{
seconds = "0" + seconds;
}
if (minutes < 10)
{
minutes = "0" + minutes;
}
if (hours > 0)
{
return hours + ":" + minutes + ":" + seconds;
}
else
{
return minutes + ":" + seconds;
}
}
/* Returns the filename of the given URL.
*/
function _urlFilename(url) {
var idx = url.lastIndexOf("=");
if (idx !== -1) {
return url.substring(idx + 1);
}
idx = url.lastIndexOf("/");
if (idx === url.length - 1) {
idx = url.substring(0, idx).lastIndexOf("/");
}
if (idx !== -1) {
return url.substring(idx + 1);
}
return url;
}
/* Returns the icon source for the given media.
*/
function _mediaIcon(url, type) {
if (type.substring(0, 6) === "image/") {
return url;
} else if (type.substring(0, 6) === "video/") {
return "image://theme/icon-l-play";
} else {
return "image://theme/icon-m-other";
}
}
/* Returns a user-friendly media type name for the given MIME type.
*/
function _mediaTypeName(type) {
if (type.substring(0, 6) === "image/") {
return qsTr("Image");
} else if (type.substring(0, 6) === "video/") {
return qsTr("Video");
} else if (type === "application/pdf") {
return qsTr("PDF document");
} else {
return type;
}
}
onClicked: {
console.log('MediaItem')
console.log(url)
console.log(mediaUrl)
if (_isAudio)
{
if (audioProxy.playing)
{
audioProxy.pause();
}
else
{
audioProxy.play();
}
}
else if (_isImage)
{
var props = {
"url": item.url,
"name": _urlFilename(item.url)
}
pageStack.push(Qt.resolvedUrl("ImagePage.qml"), props);
}
else
{
Qt.openUrlExternally(item.url);
}
}
QtObject {
id: audioProxy
property bool _active: audioPlayer.source == source
property bool playing: _active ? audioPlayer.playing
: false
property bool paused: _active ? audioPlayer.paused
: false
property real duration: _active ? audioPlayer.duration
: -1
property real position: _active ? audioPlayer.position
: 0
property string source: _isAudio ? item.url : ""
property Timer _seeker: Timer {
interval: 50
onTriggered: {
if (audioProxy._active)
{
if (! audioPlayer.playing)
{
console.log("Stream is not ready. Deferring seek operation.")
_seeker.start();
}
else
{
audioPlayer.seek(Math.max(0, database.audioBookmark(audioProxy.source) - 3000));
}
}
}
}
function play()
{
if (_active)
{
audioPlayer.play();
}
else
{
// save bookmark before switching to another podcast
if (audioPlayer.playing)
{
database.setAudioBookmark(audioPlayer.source,
audioPlayer.position);
}
audioPlayer.stop();
audioPlayer.source = source;
audioPlayer.play();
_seeker.start();
}
}
function pause()
{
if (_active)
{
//database.setAudioBookmark(source, audioPlayer.position);
audioPlayer.pause();
}
}
function seek(value)
{
if (_active) audioPlayer.seek(value);
}
onPositionChanged: {
if (_active)
{
if (! slider.down)
{
slider.value = position;
}
}
}
onDurationChanged: {
if (_active)
{
slider.maximumValue = duration;
}
}
}
Audio {
id: audioPlayer
property bool playing: playbackState === Audio.PlayingState
property bool paused: playbackState === Audio.PausedState
autoLoad: false
autoPlay: false
}
Image {
id: mediaIcon
anchors.left: parent.left
anchors.leftMargin: Theme.paddingLarge
anchors.rightMargin: Theme.paddingMedium
width: height
height: parent.height
asynchronous: true
smooth: true
fillMode: Image.PreserveAspectCrop
sourceSize.width: width * 2
sourceSize.height: height * 2
source: ! _isAudio ? _mediaIcon(item.url, item.mimeType)
: audioProxy.playing ? "image://theme/icon-l-pause"
: "image://theme/icon-l-play"
clip: true
BusyIndicator {
running: parent.status === Image.Loading
anchors.centerIn: parent
size: BusyIndicatorSize.Medium
}
}
Label {
id: mediaNameLabel
anchors.left: mediaIcon.right
anchors.right: parent.right
anchors.leftMargin: Theme.paddingLarge
anchors.rightMargin: Theme.paddingLarge
truncationMode: TruncationMode.Fade
font.pixelSize: Theme.fontSizeSmall
color: Theme.primaryColor
text: _urlFilename(item.url)
}
Label {
id: label1
anchors.top: mediaNameLabel.bottom
anchors.left: mediaNameLabel.left
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
text: ! slider.visible ? _mediaTypeName(item.mimeType)
: audioProxy.playing ? _toTime(slider.sliderValue)
: _toTime(database.audioBookmark(audioProxy.source))
}
Label {
id: label2
anchors.top: mediaNameLabel.bottom
anchors.right: parent.right
anchors.rightMargin: Theme.paddingLarge
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
text: slider.visible ? _toTime(audioProxy.duration)
: item.length >= 0 ? Format.formatFileSize(item.length)
: ""
}
Slider {
id: slider
visible: _isAudio
enabled: audioProxy.playing || audioProxy.paused
anchors.left: label1.right
anchors.right: label2.left
anchors.verticalCenter: label1.verticalCenter
leftMargin: Theme.paddingSmall
rightMargin: Theme.paddingSmall
height: Theme.itemSizeSmall / 3
handleVisible: false
minimumValue: 0
onDownChanged: {
if (! down)
{
audioProxy.seek(sliderValue);
if (! audioProxy.playing)
{
audioProxy.play();
}
}
}
}//Slider
IconButton {
id: mediaDlBtn
icon.source: "image://theme/icon-m-cloud-download"
anchors {
right: parent.right
rightMargin: Theme.horizontalPageMargin
bottom: parent.bottom
bottomMargin: Theme.horizontalPageMargin
}
onClicked: {
var filename = url.split("/")
FileDownloader.downloadFile(url, filename[filename.length-1])
}
}
}