2023-03-25 13:35:21 +08:00
|
|
|
|
import QtQuick 2.15
|
|
|
|
|
import QtQuick.Controls 2.15
|
|
|
|
|
import QtMultimedia 5.15
|
|
|
|
|
import FluentUI 1.0
|
2023-03-24 15:21:47 +08:00
|
|
|
|
|
2023-03-25 20:45:33 +08:00
|
|
|
|
Rectangle {
|
|
|
|
|
|
|
|
|
|
property url source
|
2023-03-27 18:24:35 +08:00
|
|
|
|
property bool showControl: false
|
|
|
|
|
property real volume: 30
|
|
|
|
|
|
2023-03-24 18:25:13 +08:00
|
|
|
|
id:control
|
|
|
|
|
width: 480
|
|
|
|
|
height: 270
|
2023-03-25 20:45:33 +08:00
|
|
|
|
color: FluColors.Black
|
|
|
|
|
clip: true
|
2023-03-24 18:25:13 +08:00
|
|
|
|
|
2023-03-25 20:45:33 +08:00
|
|
|
|
MouseArea{
|
2023-03-24 18:25:13 +08:00
|
|
|
|
anchors.fill: parent
|
2023-03-29 22:42:08 +08:00
|
|
|
|
preventStealing: true
|
2023-03-25 20:45:33 +08:00
|
|
|
|
onClicked: {
|
|
|
|
|
showControl = !showControl
|
|
|
|
|
}
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
2023-03-24 15:21:47 +08:00
|
|
|
|
|
|
|
|
|
MediaPlayer {
|
|
|
|
|
id: mediaplayer
|
2023-03-24 18:25:13 +08:00
|
|
|
|
property bool autoSeek:true
|
2023-03-25 13:35:21 +08:00
|
|
|
|
autoPlay: true
|
2023-03-24 18:25:13 +08:00
|
|
|
|
source: control.source
|
2023-03-25 13:35:21 +08:00
|
|
|
|
onError: {
|
|
|
|
|
console.debug(error)
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
|
|
|
|
onPositionChanged: {
|
|
|
|
|
if(autoSeek){
|
|
|
|
|
slider.seek(mediaplayer.position*slider.maxValue/mediaplayer.duration)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-25 13:35:21 +08:00
|
|
|
|
onStatusChanged: {
|
|
|
|
|
if(status===6){
|
2023-03-24 18:25:13 +08:00
|
|
|
|
slider.maxValue = mediaplayer.duration
|
2023-03-27 18:24:35 +08:00
|
|
|
|
showControl = true
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-24 15:21:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-24 18:25:13 +08:00
|
|
|
|
onSourceChanged: {
|
2023-03-25 20:45:33 +08:00
|
|
|
|
slider.seek(0)
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
2023-03-24 15:21:47 +08:00
|
|
|
|
|
|
|
|
|
VideoOutput {
|
|
|
|
|
anchors.fill: parent
|
2023-03-25 13:35:21 +08:00
|
|
|
|
source: mediaplayer
|
2023-03-24 15:21:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-24 18:25:13 +08:00
|
|
|
|
Item{
|
|
|
|
|
height: 100
|
2023-03-25 20:45:33 +08:00
|
|
|
|
y:showControl ? control.height - 110 : control.height
|
2023-03-24 18:25:13 +08:00
|
|
|
|
anchors{
|
|
|
|
|
left: parent.left
|
|
|
|
|
right: parent.right
|
|
|
|
|
leftMargin: 10
|
|
|
|
|
rightMargin: 10
|
2023-03-25 20:45:33 +08:00
|
|
|
|
}
|
|
|
|
|
MouseArea{
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Behavior on y{
|
|
|
|
|
NumberAnimation{
|
|
|
|
|
duration: 150
|
|
|
|
|
}
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rectangle{
|
|
|
|
|
anchors.fill: parent
|
2023-03-28 21:37:10 +08:00
|
|
|
|
color:FluTheme.dark ? Qt.rgba(45/255,45/255,45/255,0.97) : Qt.rgba(237/255,237/255,237/255,0.97)
|
2023-03-24 18:25:13 +08:00
|
|
|
|
radius: 5
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FluSlider{
|
|
|
|
|
id:slider
|
|
|
|
|
size:parent.width-20
|
|
|
|
|
y:20
|
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
2023-03-30 11:43:35 +08:00
|
|
|
|
tipEnabled:false
|
2023-03-24 18:25:13 +08:00
|
|
|
|
onPressed: {
|
|
|
|
|
mediaplayer.autoSeek = false
|
2023-03-25 23:28:48 +08:00
|
|
|
|
mediaplayer.pause()
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
2023-03-27 18:24:35 +08:00
|
|
|
|
value:0
|
2023-03-24 18:25:13 +08:00
|
|
|
|
onReleased: {
|
|
|
|
|
mediaplayer.autoSeek = true
|
2023-03-25 23:28:48 +08:00
|
|
|
|
mediaplayer.play()
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
2023-03-25 23:28:48 +08:00
|
|
|
|
|
|
|
|
|
onValueChanged: {
|
|
|
|
|
if(mediaplayer.autoSeek == false){
|
|
|
|
|
mediaplayer.seek(value*mediaplayer.duration/slider.maxValue)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-25 20:45:33 +08:00
|
|
|
|
onLineClickFunc:function(val){
|
|
|
|
|
mediaplayer.seek(val*mediaplayer.duration/slider.maxValue)
|
|
|
|
|
}
|
2023-03-24 15:21:47 +08:00
|
|
|
|
}
|
2023-03-24 18:25:13 +08:00
|
|
|
|
|
|
|
|
|
FluText{
|
|
|
|
|
id:start_time
|
|
|
|
|
anchors{
|
|
|
|
|
top: slider.bottom
|
|
|
|
|
topMargin: 10
|
|
|
|
|
left: slider.left
|
|
|
|
|
}
|
|
|
|
|
text: formatDuration(slider.value*mediaplayer.duration/slider.maxValue)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FluText{
|
|
|
|
|
id:end_time
|
|
|
|
|
anchors{
|
|
|
|
|
top: slider.bottom
|
|
|
|
|
right: slider.right
|
|
|
|
|
topMargin: 10
|
|
|
|
|
}
|
|
|
|
|
text: formatDuration(mediaplayer.duration)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-27 18:24:35 +08:00
|
|
|
|
|
|
|
|
|
Row{
|
|
|
|
|
spacing: 10
|
2023-03-24 18:25:13 +08:00
|
|
|
|
anchors{
|
|
|
|
|
horizontalCenter: parent.horizontalCenter
|
|
|
|
|
bottom: parent.bottom
|
|
|
|
|
bottomMargin: 10
|
|
|
|
|
}
|
2023-03-27 18:24:35 +08:00
|
|
|
|
FluIconButton{
|
|
|
|
|
iconSize: 17
|
|
|
|
|
iconSource: FluentIcons.SkipBack10
|
|
|
|
|
onClicked: {
|
|
|
|
|
mediaplayer.seek(Math.max(mediaplayer.position-10*1000,0))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FluIconButton{
|
|
|
|
|
iconSize: 15
|
|
|
|
|
iconSource: mediaplayer.playbackState === Audio.PlayingState ? FluentIcons.Pause : FluentIcons.Play
|
|
|
|
|
onClicked: {
|
|
|
|
|
if(mediaplayer.playbackState === Audio.PlayingState){
|
|
|
|
|
mediaplayer.pause()
|
|
|
|
|
}else{
|
|
|
|
|
mediaplayer.play()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FluIconButton{
|
|
|
|
|
iconSize: 17
|
|
|
|
|
iconSource: FluentIcons.SkipForward30
|
|
|
|
|
onClicked: {
|
|
|
|
|
mediaplayer.seek(Math.min(mediaplayer.position+30*1000,mediaplayer.duration))
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-27 18:24:35 +08:00
|
|
|
|
|
2023-03-25 23:28:48 +08:00
|
|
|
|
FluIconButton{
|
2023-03-27 18:24:35 +08:00
|
|
|
|
id:btn_volume
|
2023-03-25 23:28:48 +08:00
|
|
|
|
iconSize: 17
|
|
|
|
|
iconSource: mediaplayer.volume ? FluentIcons.Volume : FluentIcons.Mute
|
|
|
|
|
anchors{
|
|
|
|
|
left: parent.left
|
|
|
|
|
leftMargin: 5
|
|
|
|
|
bottom: parent.bottom
|
|
|
|
|
bottomMargin: 10
|
|
|
|
|
}
|
|
|
|
|
onClicked: {
|
|
|
|
|
mediaplayer.volume = !mediaplayer.volume
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-27 18:24:35 +08:00
|
|
|
|
FluSlider{
|
|
|
|
|
id:slider_volume
|
|
|
|
|
size: 80
|
|
|
|
|
dotSize: 20
|
|
|
|
|
value:30
|
|
|
|
|
anchors{
|
|
|
|
|
left:btn_volume.right
|
|
|
|
|
verticalCenter: btn_volume.verticalCenter
|
|
|
|
|
leftMargin: 10
|
|
|
|
|
}
|
|
|
|
|
onValueChanged:{
|
|
|
|
|
mediaplayer.volume = value/100
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-25 23:28:48 +08:00
|
|
|
|
|
2023-03-24 18:25:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatDuration(duration) {
|
|
|
|
|
const seconds = Math.floor(duration / 1000);
|
|
|
|
|
const hours = Math.floor(seconds / 3600);
|
|
|
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
|
|
|
const remainingSeconds = seconds % 60;
|
|
|
|
|
return `${pad(hours)}:${pad(minutes)}:${pad(remainingSeconds)}`;
|
2023-03-24 15:21:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-24 18:25:13 +08:00
|
|
|
|
function pad(value) {
|
|
|
|
|
return value.toString().padStart(2, '0');
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-25 20:45:33 +08:00
|
|
|
|
function pause(){
|
|
|
|
|
mediaplayer.pause()
|
|
|
|
|
}
|
2023-03-24 18:25:13 +08:00
|
|
|
|
|
2023-03-25 20:45:33 +08:00
|
|
|
|
function play(){
|
|
|
|
|
mediaplayer.play()
|
|
|
|
|
}
|
2023-03-24 18:25:13 +08:00
|
|
|
|
|
2023-03-24 15:21:47 +08:00
|
|
|
|
}
|
|
|
|
|
|