Warning, /multimedia/haruna/src/qml/HProgressBar.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * SPDX-FileCopyrightText: 2020 George Florea Bănuș <georgefb899@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 import QtQml
0008 import QtQuick
0009 import QtQuick.Controls
0010 import QtQuick.Layouts
0011 import QtQuick.Shapes
0012 
0013 import org.kde.kirigami as Kirigami
0014 import org.kde.haruna
0015 import org.kde.haruna.mpvproperties
0016 import org.kde.haruna.settings
0017 
0018 Slider {
0019     id: root
0020 
0021     property alias loopIndicator: loopIndicator
0022     property bool seekStarted: false
0023 
0024     from: 0
0025     to: mpv.duration
0026     implicitWidth: 200
0027     implicitHeight: 25
0028     leftPadding: 0
0029     rightPadding: 0
0030 
0031     handle: Item { visible: false }
0032 
0033     background: Rectangle {
0034         id: progressBarBG
0035         color: Kirigami.Theme.alternateBackgroundColor
0036         scale: root.mirrored ? -1 : 1
0037 
0038         Rectangle {
0039             id: loopIndicator
0040             property double startPosition: -1
0041             property double endPosition: -1
0042             width: endPosition === -1 ? 1 : (endPosition / mpv.duration * progressBarBG.width) - x
0043             height: parent.height
0044             color: Qt.hsla(0, 0, 0, 0.4)
0045             visible: startPosition !== -1
0046             x: startPosition / mpv.duration * progressBarBG.width
0047             z: 110
0048         }
0049 
0050         Rectangle {
0051             width: root.position * parent.width
0052             height: parent.height
0053             color: Kirigami.Theme.highlightColor
0054         }
0055 
0056         ToolTip {
0057             id: progressBarToolTip
0058 
0059             z: 10
0060             visible: progressBarMouseArea.containsMouse && mpv.duration > 0
0061             timeout: -1
0062             delay: 0
0063             contentItem: ColumnLayout {
0064 
0065                 Loader {
0066                     id: previewMpvLoader
0067 
0068                     property string file: ""
0069                     property double position: 0
0070                     property double aspectRatio: 1
0071 
0072                     active: GeneralSettings.showPreviewThumbnail && previewMpvLoader.file !== ""
0073                     visible: false
0074                     sourceComponent: MpvPreview {
0075                         anchors.fill: parent
0076                         accuratePreview: GeneralSettings.accuratePreviewThumbnail
0077                         position: previewMpvLoader.position
0078                         file: previewMpvLoader.file
0079 
0080                         onIsLocalFileChanged: {
0081                             previewMpvLoader.visible = isLocalFile
0082                         }
0083                         onAspectRatioChanged: previewMpvLoader.aspectRatio = aspectRatio || 1
0084                     }
0085 
0086                     Layout.preferredWidth: GeneralSettings.previewThumbnailWidth
0087                     Layout.preferredHeight: Math.ceil(Layout.preferredWidth / previewMpvLoader.aspectRatio)
0088                     Layout.alignment: Qt.AlignCenter
0089 
0090                 }
0091 
0092                 Label {
0093                     text: progressBarToolTip.text
0094                     Kirigami.Theme.colorSet: Kirigami.Theme.Tooltip
0095                     Layout.alignment: Qt.AlignCenter
0096                 }
0097             }
0098 
0099         }
0100 
0101         MouseArea {
0102             id: progressBarMouseArea
0103 
0104             anchors.fill: parent
0105             hoverEnabled: true
0106             acceptedButtons: Qt.MiddleButton | Qt.RightButton
0107 
0108             onClicked: function(mouse) {
0109                 if (mouse.button === Qt.MiddleButton) {
0110                     if (!GeneralSettings.showChapterMarkers) {
0111                         return
0112                     }
0113 
0114                     const time = mouseX / progressBarBG.width * root.to
0115                     const chapters = mpv.getProperty(MpvProperties.ChapterList)
0116                     const nextChapter = chapters.findIndex(chapter => chapter.time > time)
0117                     mpv.chapter = nextChapter
0118                 }
0119                 if (mouse.button === Qt.RightButton && mpv.chaptersModel.rowCount() > 0) {
0120                     chaptersPopup.x = mouseX - chaptersPopup.width * 0.5
0121                     chaptersPopup.open()
0122                 }
0123             }
0124 
0125             onMouseXChanged: {
0126                 progressBarToolTip.x = mouseX - (progressBarToolTip.width * 0.5)
0127 
0128                 const time = mouseX / progressBarBG.width * root.to
0129                 previewMpvLoader.position = time
0130                 progressBarToolTip.text = app.formatTime(time)
0131             }
0132 
0133             onEntered: {
0134                 progressBarToolTip.x = mouseX - (progressBarToolTip.width * 0.5)
0135                 progressBarToolTip.y = root.height + Kirigami.Units.largeSpacing
0136             }
0137 
0138             onWheel: function(wheel) {
0139                 if (wheel.angleDelta.y > 0) {
0140                     appActions.seekForwardMediumAction.trigger()
0141                 } else if (wheel.angleDelta.y) {
0142                     appActions.seekBackwardMediumAction.trigger()
0143                 }
0144             }
0145         }
0146     }
0147 
0148     onToChanged: value = mpv.position
0149     onPressedChanged: {
0150         if (pressed) {
0151             seekStarted = true
0152         } else {
0153             mpv.command(["seek", value, "absolute"])
0154             seekStarted = false
0155         }
0156     }
0157 
0158     // create markers for the chapters
0159     Repeater {
0160         id: chaptersInstantiator
0161         model: GeneralSettings.showChapterMarkers ? mpv.chaptersModel : 0
0162         delegate: Shape {
0163             id: chapterMarkerShape
0164 
0165             // where the chapter marker shoud be positioned on the progress bar
0166             property int position: root.mirrored
0167                                    ? progressBarBG.width - (model.startTime / mpv.duration * progressBarBG.width)
0168                                    : model.startTime / mpv.duration * progressBarBG.width
0169 
0170             antialiasing: true
0171             ShapePath {
0172                 id: shape
0173                 strokeWidth: 1
0174                 strokeColor: Kirigami.Theme.textColor
0175                 startX: chapterMarkerShape.position
0176                 startY: root.height
0177                 fillColor: Kirigami.Theme.textColor
0178                 PathLine { x: shape.startX; y: -1 }
0179                 PathLine { x: shape.startX + 6; y: -7 }
0180                 PathLine { x: shape.startX - 7; y: -7 }
0181                 PathLine { x: shape.startX - 1; y: -1 }
0182             }
0183             Rectangle {
0184                 x: chapterMarkerShape.position - 8
0185                 y: -11
0186                 width: 15
0187                 height: 11
0188                 color: "transparent"
0189                 ToolTip {
0190                     id: chapterTitleToolTip
0191                     text: model.title
0192                     visible: false
0193                     delay: 0
0194                     timeout: 10000
0195                 }
0196                 MouseArea {
0197                     anchors.fill: parent
0198                     hoverEnabled: true
0199                     onEntered: chapterTitleToolTip.visible = true
0200                     onExited: chapterTitleToolTip.visible = false
0201                     onClicked: mpv.chapter = index
0202                 }
0203             }
0204         }
0205     }
0206 
0207     Popup {
0208         id: chaptersPopup
0209 
0210         property int itemHeight
0211         property int itemBiggestWidth: 1
0212         property var checkedItem
0213         property int maxWidth: window.width * 0.7 > Kirigami.Units.gridUnit * 40
0214                                ? Kirigami.Units.gridUnit * 40
0215                                : window.width * 0.7
0216 
0217         y: -height - root.height
0218         z: 20
0219         width: itemBiggestWidth > maxWidth ? maxWidth : itemBiggestWidth
0220         height: itemHeight * mpv.chaptersModel.rowCount() + listViewPage.footer.height > mpv.height - Kirigami.Units.gridUnit
0221                 ? mpv.height - Kirigami.Units.gridUnit
0222                 : itemHeight * mpv.chaptersModel.rowCount() + listViewPage.footer.height
0223         padding: 0
0224         onOpened: {
0225             listView.positionViewAtIndex(checkedItem, ListView.Beginning)
0226         }
0227 
0228         Kirigami.ScrollablePage {
0229             id: listViewPage
0230 
0231             padding: 0
0232 
0233             anchors.fill: parent
0234             footer: ToolBar {
0235                 z: 100
0236                 width: parent.width
0237                 CheckBox {
0238                     text: i18nc("@action:inmenu", "Skip Chapters")
0239                     checked: PlaybackSettings.skipChapters
0240                     onCheckedChanged: {
0241                         PlaybackSettings.skipChapters = checked
0242                         PlaybackSettings.save()
0243                     }
0244 
0245                     ToolTip {
0246                         text: i18nc("@info:tooltip", "Automatically skips chapters containing certain words/characters.\nCheck 'Playback' settings for more details")
0247                     }
0248                 }
0249             }
0250 
0251             ListView {
0252                 id: listView
0253 
0254                 model: mpv.chaptersModel
0255                 delegate: CheckDelegate {
0256                     id: menuitem
0257 
0258                     text: `${app.formatTime(model.startTime)} - ${model.title}`
0259                     checked: index === chaptersPopup.checkedItem
0260                     width: listViewPage.width
0261                     onClicked: {
0262                         chaptersPopup.close()
0263                         mpv.chapter = index
0264                     }
0265                     Component.onCompleted: {
0266                         const scrollBarWidth = listViewPage.contentItem.ScrollBar.vertical.width
0267                         chaptersPopup.itemBiggestWidth = menuitem.implicitWidth + scrollBarWidth > chaptersPopup.width
0268                                 ? menuitem.implicitWidth + scrollBarWidth
0269                                 : chaptersPopup.width
0270 
0271                         chaptersPopup.itemHeight = height
0272                     }
0273                 }
0274             }
0275         }
0276     }
0277 
0278     Connections {
0279         target: mpv
0280         function onFileLoaded() {
0281             loopIndicator.startPosition = -1
0282             loopIndicator.endPosition = -1
0283             previewMpvLoader.file = mpv.currentUrl
0284         }
0285         function onChapterChanged() {
0286             chaptersPopup.checkedItem = mpv.chapter
0287         }
0288         function onPositionChanged() {
0289             if (!root.seekStarted) {
0290                 root.value = mpv.position
0291             }
0292         }
0293     }
0294 }