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]) } } }