Warning, /graphics/koko/src/qml/imagedelegate/VideoPlayer.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 * SPDX-FileCopyrightText: (C) 2021 Mikel Johnson <mikel5764@gmail.com> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.15 0008 import QtQuick.Layouts 1.15 0009 import QtQuick.Controls 2.15 as Controls 0010 import org.kde.kirigami 2.15 as Kirigami 0011 import QtMultimedia 5.15 0012 import org.kde.kcoreaddons 1.0 as KCA 0013 0014 Item { 0015 id: videoPlayerRoot 0016 0017 // `required` here breaks stuff 0018 property string source 0019 readonly property alias player: videoPlayer 0020 readonly property bool playing: videoPlayer.playbackState === MediaPlayer.PlayingState 0021 readonly property alias status: videoPlayer.status 0022 0023 // signals when playback starts and finishes 0024 signal playbackStarted() 0025 signal playbackFinished() 0026 0027 // convenience function 0028 function play() { 0029 if (videoPlayer.status != MediaPlayer.Loaded) { 0030 videoPlayer.autoPlay = true 0031 } else { 0032 videoPlayer.play(); 0033 } 0034 } 0035 0036 function stop() { 0037 videoPlayer.stop(); 0038 } 0039 0040 implicitWidth: videoPlayer.implicitWidth 0041 implicitHeight: videoPlayer.implicitHeight 0042 0043 Timer { 0044 id: doubleClickTimer 0045 interval: 150 0046 onTriggered: { 0047 applicationWindow().controlsVisible = !applicationWindow().controlsVisible; 0048 } 0049 } 0050 0051 MouseArea { 0052 anchors.fill: parent 0053 onClicked: { 0054 if (applicationWindow().contextDrawer) { 0055 applicationWindow().contextDrawer.drawerOpen = false; 0056 } 0057 doubleClickTimer.restart(); 0058 } 0059 onDoubleClicked: { 0060 doubleClickTimer.running = false; 0061 if (videoPlayer.playbackState === MediaPlayer.PlayingState) { 0062 videoPlayer.pause(); 0063 } else{ 0064 videoPlayer.play(); 0065 } 0066 } 0067 } 0068 0069 Video { 0070 id: videoPlayer 0071 implicitWidth: videoPlayer.metaData.resolution ? videoPlayer.metaData.resolution.width : 0 0072 implicitHeight: videoPlayer.metaData.resolution ? videoPlayer.metaData.resolution.height : 0 0073 anchors.fill: parent 0074 loops: videoPlayer.duration >= 5000 ? 0 : MediaPlayer.Infinite // loop short videos 0075 // See https://doc.qt.io/qt-5/qml-qtmultimedia-qtmultimedia.html#convertVolume-method 0076 volume: QtMultimedia.convertVolume(volumeSlider.value, 0077 QtMultimedia.LogarithmicVolumeScale, 0078 QtMultimedia.LinearVolumeScale) 0079 source: videoPlayerRoot.source 0080 onPlaying: videoPlayerRoot.playbackStarted() 0081 onStopped: videoPlayerRoot.playbackFinished() 0082 0083 function seekForward() { 0084 if (videoPlayer.position + 5000 < videoPlayer.duration) { 0085 videoPlayer.seek(videoPlayer.position + 5000); 0086 } else { 0087 videoPlayer.seek(0); 0088 videoPlayer.stop(); 0089 } 0090 } 0091 0092 function seekBackward() { 0093 videoPlayer.seek(videoPlayer.position - 5000); 0094 } 0095 } 0096 0097 Controls.ToolButton { 0098 anchors.centerIn: parent 0099 0100 icon.name: "media-playback-start" 0101 icon.color: "white" 0102 0103 icon.width: Kirigami.Units.gridUnit * 3 0104 icon.height: Kirigami.Units.gridUnit * 3 0105 0106 visible: videoPlayer.playbackState === MediaPlayer.StoppedState 0107 0108 onClicked: { 0109 videoPlayer.play(); 0110 } 0111 } 0112 0113 Item { 0114 id: playerToolbar 0115 0116 anchors.left: parent.left 0117 anchors.right: parent.right 0118 anchors.bottom: parent.bottom 0119 anchors.bottomMargin: Kirigami.Units.smallSpacing 0120 0121 height: Kirigami.Units.gridUnit * 2 0122 opacity: applicationWindow().controlsVisible ? 1 : 0 0123 visible: opacity !== 0 0124 0125 Kirigami.Theme.inherit: false 0126 Kirigami.Theme.textColor: "white" 0127 0128 Behavior on opacity { 0129 OpacityAnimator { 0130 duration: Kirigami.Units.longDuration 0131 easing.type: Easing.InOutQuad 0132 } 0133 } 0134 0135 // Pretty gradient ftw 0136 Rectangle { 0137 anchors.left: parent.left 0138 anchors.right: parent.right 0139 anchors.bottom: parent.bottom 0140 height: Kirigami.Units.gridUnit * 4 0141 opacity: 0.6 0142 gradient: Gradient { 0143 GradientStop { position: 0.0; color: "transparent" } 0144 GradientStop { position: 1.0; color: "black" } 0145 } 0146 } 0147 0148 Rectangle { 0149 anchors.left:parent.left 0150 anchors.right:parent.right 0151 anchors.top: parent.bottom 0152 height: parent.anchors.bottomMargin 0153 opacity: 0.6 0154 color: "black" 0155 } 0156 0157 Controls.Slider { 0158 id: timeSlider 0159 0160 // NOTE: Screen reader reports raw numbers, not sure if there's any way around it 0161 Accessible.name: i18n("Seek slider") 0162 0163 anchors.left: parent.left 0164 anchors.right: parent.right 0165 anchors.bottom: parent.top 0166 anchors.leftMargin: Kirigami.Units.smallSpacing 0167 anchors.rightMargin: Kirigami.Units.smallSpacing 0168 0169 value: pressed ? 0 : videoPlayer.position // don't change value while we drag 0170 to: videoPlayer.duration 0171 0172 Controls.ToolTip { 0173 parent: timeSlider.handle 0174 visible: timeSlider.pressed 0175 text: KCA.Format.formatDuration(timeSlider.value, KCA.FormatTypes.FoldHours) 0176 } 0177 0178 Keys.onLeftPressed: { 0179 videoPlayer.seekBackward(); 0180 event.accepted = true; 0181 } 0182 Keys.onRightPressed: { 0183 videoPlayer.seekForward(); 0184 event.accepted = true; 0185 } 0186 // update on release 0187 onPressedChanged: { 0188 if (!pressed) { 0189 videoPlayer.seek(value); 0190 } 0191 } 0192 } 0193 0194 RowLayout { 0195 anchors.left: parent.left 0196 anchors.right: parent.right 0197 anchors.leftMargin: Kirigami.Units.smallSpacing 0198 anchors.rightMargin: Kirigami.Units.smallSpacing 0199 anchors.verticalCenter: parent.verticalCenter 0200 spacing: Kirigami.Units.smallSpacing 0201 0202 Controls.ToolButton { 0203 Accessible.name: i18np("Skip backward 1 second", "Skip backward %1 seconds", 5) 0204 visible: videoPlayer.duration >= 5000 && !Kirigami.Settings.isMobile 0205 icon.name: "media-skip-backward" 0206 enabled: videoPlayer.playbackState != MediaPlayer.StoppedState 0207 onClicked: { 0208 videoPlayer.seekBackward(); 0209 } 0210 } 0211 0212 Controls.ToolButton { 0213 Accessible.name: videoPlayer.playbackState == MediaPlayer.PlayingState ? i18n("Pause playback") : i18n("Continue playback") 0214 icon.name: videoPlayer.playbackState == MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" 0215 onClicked: { 0216 if (videoPlayer.playbackState === MediaPlayer.PlayingState) { 0217 videoPlayer.pause(); 0218 } else { 0219 videoPlayer.play(); 0220 } 0221 } 0222 } 0223 0224 Controls.ToolButton { 0225 Accessible.name: i18np("Skip backward 1 second", "Skip forward %1 seconds", 5) 0226 visible: videoPlayer.duration >= 5000 && !Kirigami.Settings.isMobile 0227 icon.name: "media-skip-forward" 0228 enabled: videoPlayer.playbackState != MediaPlayer.StoppedState 0229 onClicked: { 0230 videoPlayer.seekForward(); 0231 } 0232 } 0233 0234 Controls.ToolButton { 0235 Accessible.name: videoPlayer.muted ? i18n("Unmute audio") : i18n("Mute audio") 0236 visible: videoPlayer.hasAudio 0237 icon.name: videoPlayer.muted ? "audio-volume-muted" : 0238 volumeSlider.value == 0 ? "audio-volume-low" : 0239 volumeSlider.value >= 0.5 ? "audio-volume-high" : "audio-volume-medium" 0240 onClicked: { 0241 videoPlayer.muted = !videoPlayer.muted; 0242 } 0243 } 0244 0245 Controls.Slider { 0246 id: volumeSlider 0247 Accessible.name: i18n("Volume slider") 0248 value: 1 0249 visible: videoPlayer.hasAudio 0250 Layout.preferredWidth: Kirigami.Units.gridUnit * 5 0251 onPressedChanged: videoPlayer.muted = false 0252 } 0253 0254 Item { 0255 Layout.fillWidth: true 0256 height: 1 0257 } 0258 0259 Controls.Label { 0260 text: KCA.Format.formatDuration(videoPlayer.position, KCA.FormatTypes.FoldHours) + " / " + 0261 KCA.Format.formatDuration(videoPlayer.duration, KCA.FormatTypes.FoldHours) 0262 } 0263 0264 // this local and independed from slideshow to avoid confusion 0265 Controls.ToolButton { 0266 // Follows Elisa's convention 0267 Accessible.name: videoPlayer.loops == MediaPlayer.Infinite ? i18n("Repeat current video") : i18n("Don't repeat current video") 0268 Controls.ToolTip.text: Accessible.name 0269 Controls.ToolTip.visible: hovered 0270 Controls.ToolTip.delay: Kirigami.Units.toolTipDelay 0271 icon.name: videoPlayer.loops == MediaPlayer.Infinite ? "media-repeat-single" : "media-repeat-none" 0272 onClicked: { 0273 if (videoPlayer.loops == MediaPlayer.Infinite) { 0274 videoPlayer.loops = 0; 0275 } else { 0276 videoPlayer.loops = MediaPlayer.Infinite; 0277 } 0278 } 0279 } 0280 } 0281 } 0282 }