diff --git a/example/T_MediaPlayer.qml b/example/T_MediaPlayer.qml index d9ef52c..3abe00c 100644 --- a/example/T_MediaPlayer.qml +++ b/example/T_MediaPlayer.qml @@ -7,11 +7,11 @@ import FluentUI 1.0 FluScrollablePage{ - title:"ColorPicker" + title:"MediaPlayer" FluArea{ width: parent.width - height: 280 + height: 320 Layout.topMargin: 20 paddings: 10 ColumnLayout{ @@ -21,7 +21,10 @@ FluScrollablePage{ } FluMediaPlayer{ - + source:{ + console.debug("-------------->") + return "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" + } } } diff --git a/example/page/MainPage.qml b/example/page/MainPage.qml index bd83d73..ef249fc 100644 --- a/example/page/MainPage.qml +++ b/example/page/MainPage.qml @@ -11,7 +11,7 @@ FluWindow { width: 860 height: 600 title: "FluentUI" - minimumWidth: 500 + minimumWidth: 520 minimumHeight: 400 FluAppBar{ diff --git a/src/controls/FluMediaPlayer.qml b/src/controls/FluMediaPlayer.qml index 79fe465..3dc8e49 100644 --- a/src/controls/FluMediaPlayer.qml +++ b/src/controls/FluMediaPlayer.qml @@ -1,28 +1,141 @@ import QtQuick 2.15 -import QtMultimedia 5.9 +import QtQuick.Controls 2.15 +import QtMultimedia 5.15 +import QtGraphicalEffects 1.15 +import FluentUI 1.0 Item { - width: 320 - height: 240 + id:control + width: 480 + height: 270 + + property url source + + + Rectangle{ + anchors.fill: parent + color: FluColors.Black + } MediaPlayer { id: mediaplayer - source: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" + property bool autoSeek:true + autoPlay: true + source: control.source + onError: { + console.debug(error) + } + onPositionChanged: { + if(autoSeek){ + slider.seek(mediaplayer.position*slider.maxValue/mediaplayer.duration) + } + } + onStatusChanged: { + if(status===6){ + slider.maxValue = mediaplayer.duration + } + } } + onSourceChanged: { + slider.seek(0) + } VideoOutput { anchors.fill: parent source: mediaplayer } - MouseArea { - anchors.fill: parent - onPressed: { - console.debug("------>") - mediaplayer.play() + Item{ + height: 100 + anchors{ + bottom: parent.bottom + left: parent.left + right: parent.right + leftMargin: 10 + rightMargin: 10 + bottomMargin: 10 } + + Rectangle{ + anchors.fill: parent + color:FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,0.97) : Qt.rgba(237/255,237/255,237/255,0.97) + radius: 5 + layer.enabled: true + layer.effect: GaussianBlur { + radius: 5 + samples: 16 + } + } + + FluSlider{ + id:slider + size:parent.width-20 + y:20 + anchors.horizontalCenter: parent.horizontalCenter + enableTip:false + onPressed: { + mediaplayer.autoSeek = false + } + onReleased: { + mediaplayer.seek(value*mediaplayer.duration/slider.maxValue) + mediaplayer.autoSeek = true + } + } + + 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) + } + + FluIconButton{ + iconSize: 15 + iconSource: mediaplayer.playbackState === Audio.PlayingState ? FluentIcons.Pause : FluentIcons.Play + anchors{ + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: 10 + } + onClicked: { + if(mediaplayer.playbackState === Audio.PlayingState){ + mediaplayer.pause() + }else{ + mediaplayer.play() + } + } + } + } + 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)}`; + } + + function pad(value) { + return value.toString().padStart(2, '0'); + } + + + } diff --git a/src/controls/FluMenu.qml b/src/controls/FluMenu.qml index 9a8f730..f8c78e1 100644 --- a/src/controls/FluMenu.qml +++ b/src/controls/FluMenu.qml @@ -18,7 +18,7 @@ Menu { radius: 5 layer.enabled: true layer.effect: GaussianBlur { - radius: 8 + radius: 5 samples: 16 } } diff --git a/src/controls/FluSlider.qml b/src/controls/FluSlider.qml index 3768203..5bdfc5f 100644 --- a/src/controls/FluSlider.qml +++ b/src/controls/FluSlider.qml @@ -6,12 +6,15 @@ Item{ id:root - property int lineSize: 5 + property int lineSize: 4 property int size: 180 - property int dotSize: 28 + property int dotSize: 24 property int value: 50 + property int maxValue: 100 + + enum Orientation { Horizontal, Vertical @@ -24,20 +27,15 @@ Item{ property bool isHorizontal: orientation === FluSlider.Horizontal + property bool enableTip : true + + signal pressed + signal released + rotation: isHorizontal ? 0 : 180 Component.onCompleted: { - if(isHorizontal){ - dot.x =value/100*control.width - dotSize/2 - root.value = Qt.binding(function(){ - return (dot.x+dotSize/2)/control.width*100 - }) - }else{ - dot.y =value/100*control.height - dotSize/2 - root.value = Qt.binding(function(){ - return (dot.y+dotSize/2)/control.height*100 - }) - } + seek(0) } FluRectangle { @@ -51,8 +49,8 @@ Item{ Rectangle{ id:rect radius: 3 - width: isHorizontal ? control.width*(value/100) : control.width - height: isHorizontal ? control.height : control.height*(value/100) + width: isHorizontal ? control.width*(value/maxValue) : control.width + height: isHorizontal ? control.height : control.height*(value/maxValue) color:FluTheme.isDark ? FluTheme.primaryColor.lighter :FluTheme.primaryColor.dark } } @@ -94,11 +92,15 @@ Item{ maximumY: isHorizontal ? 0 : (control.height - dotSize/2) } onPressed: { - tool_tip.visible = true + if(enableTip){ + tool_tip.visible = true + } + root.pressed() } onReleased: { tool_tip.visible = false + root.released() } } @@ -109,5 +111,20 @@ Item{ } } + function seek(position){ + console.debug(position) + if(isHorizontal){ + dot.x =position/maxValue*control.width - dotSize/2 + root.value = Qt.binding(function(){ + return (dot.x+dotSize/2)/control.width*maxValue + }) + }else{ + dot.y =position/maxValue*control.height - dotSize/2 + root.value = Qt.binding(function(){ + return (dot.y+dotSize/2)/control.height*maxValue + }) + } + } + }