203 lines
6.9 KiB
QML
203 lines
6.9 KiB
QML
// SPDX-FileCopyrightText: 2020 George Florea Bănuș <georgefb899@gmail.com>
|
|
// SPDX-FileCopyrightText: 2026 Tri Vo Khac
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import org.kde.ki18n
|
|
import org.kde.kirigami as Kirigami
|
|
|
|
// The video, with Haruna's default mouse bindings and drag and drop.
|
|
MpvItem {
|
|
id: root
|
|
|
|
required property Actions actions
|
|
property bool fullscreen: false
|
|
|
|
signal pointerMoved(x: real, y: real)
|
|
signal pointerLeft()
|
|
// Files dropped on the top part are queued; on the bottom part they play now.
|
|
signal filesDropped(urls: list<url>, append: bool)
|
|
signal subtitleDropped(url: url)
|
|
|
|
function isSubtitleFile(url: url): bool {
|
|
return /\.(srt|ass|ssa|vtt|sub|sup)$/i.test(url.toString())
|
|
}
|
|
|
|
// Plain-text and translated subtitles; styled ASS subtitles keep their own fonts.
|
|
function applySubtitleStyle() {
|
|
setPropertyAsync("sub-font-size", QtPotatoSettings.subtitleFontSize)
|
|
setPropertyAsync("sub-outline-size", QtPotatoSettings.subtitleOutlineSize)
|
|
}
|
|
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
|
Kirigami.Theme.inherit: false
|
|
|
|
loadUserConfig: QtPotatoSettings.loadMpvConfig
|
|
preferredAudioLanguages: QtPotatoSettings.preferredAudioLanguages
|
|
preferredSubtitleLanguages: QtPotatoSettings.preferredSubtitleLanguages
|
|
autoSelectSubtitle: QtPotatoSettings.autoSelectSubtitle
|
|
|
|
// Set once the saved volume is applied; mpv reports its default volume before that.
|
|
property bool volumeRestored: false
|
|
|
|
// QtPotato's own settings win over mpv.conf.
|
|
onUserConfigApplied: {
|
|
applySubtitleStyle()
|
|
volume = QtPotatoSettings.volume
|
|
volumeRestored = true
|
|
}
|
|
|
|
onVolumeChanged: {
|
|
if (volumeRestored) {
|
|
QtPotatoSettings.volume = volume
|
|
}
|
|
}
|
|
|
|
readonly property int subtitleFontSize: QtPotatoSettings.subtitleFontSize
|
|
onSubtitleFontSizeChanged: applySubtitleStyle()
|
|
readonly property int subtitleOutlineSize: QtPotatoSettings.subtitleOutlineSize
|
|
onSubtitleOutlineSizeChanged: applySubtitleStyle()
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: Kirigami.Theme.backgroundColor
|
|
visible: !root.fileLoaded
|
|
z: -1
|
|
}
|
|
|
|
Kirigami.PlaceholderMessage {
|
|
anchors.centerIn: parent
|
|
width: parent.width - Kirigami.Units.gridUnit * 4
|
|
visible: !root.fileLoaded && !dropArea.containsDrag
|
|
icon.name: "video-symbolic"
|
|
text: KI18n.i18nc("@info:placeholder", "No video open")
|
|
explanation: KI18n.i18nc("@info:placeholder", "Open a file or drop one here")
|
|
}
|
|
|
|
Timer {
|
|
id: hideCursorTimer
|
|
running: root.fullscreen && mouseArea.containsMouse
|
|
repeat: true
|
|
interval: 2000
|
|
onTriggered: mouseArea.hideCursor = true
|
|
}
|
|
|
|
MouseArea {
|
|
id: mouseArea
|
|
|
|
property bool hideCursor: false
|
|
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton | Qt.ForwardButton | Qt.BackButton
|
|
hoverEnabled: true
|
|
cursorShape: hideCursor && root.fullscreen ? Qt.BlankCursor : Qt.ArrowCursor
|
|
|
|
onPositionChanged: mouse => {
|
|
hideCursor = false
|
|
hideCursorTimer.restart()
|
|
root.pointerMoved(mouse.x, mouse.y)
|
|
}
|
|
onExited: root.pointerLeft()
|
|
|
|
onPressed: mouse => {
|
|
root.forceActiveFocus(Qt.MouseFocusReason)
|
|
switch (mouse.button) {
|
|
case Qt.LeftButton:
|
|
root.actions.playPause.trigger()
|
|
break
|
|
case Qt.MiddleButton:
|
|
root.actions.mute.trigger()
|
|
break
|
|
case Qt.RightButton:
|
|
root.actions.openContextMenu.trigger()
|
|
break
|
|
case Qt.ForwardButton:
|
|
root.actions.seekForwardSmall.trigger()
|
|
break
|
|
case Qt.BackButton:
|
|
root.actions.seekBackwardSmall.trigger()
|
|
break
|
|
}
|
|
}
|
|
|
|
onDoubleClicked: mouse => {
|
|
if (mouse.button === Qt.LeftButton) {
|
|
// Both presses of the double click toggled playback, so it is unchanged.
|
|
root.actions.toggleFullscreen.trigger()
|
|
} else if (mouse.button === Qt.MiddleButton) {
|
|
root.actions.configure.trigger()
|
|
}
|
|
}
|
|
|
|
onWheel: wheel => {
|
|
if (wheel.angleDelta.y > 0) {
|
|
root.actions.volumeUp.trigger()
|
|
} else if (wheel.angleDelta.y < 0) {
|
|
root.actions.volumeDown.trigger()
|
|
}
|
|
}
|
|
}
|
|
|
|
DropArea {
|
|
id: dropArea
|
|
|
|
readonly property bool onTopPart: containsDrag && drag.y <= height * 0.25
|
|
property bool onlySubtitles: false
|
|
|
|
anchors.fill: parent
|
|
keys: ["text/uri-list"]
|
|
|
|
onEntered: drag => {
|
|
onlySubtitles = drag.urls.length > 0 && drag.urls.every(url => root.isSubtitleFile(url))
|
|
}
|
|
|
|
onDropped: drop => {
|
|
if (!drop.hasUrls) {
|
|
return
|
|
}
|
|
if (onlySubtitles) {
|
|
root.subtitleDropped(drop.urls[0])
|
|
} else {
|
|
root.filesDropped(drop.urls, onTopPart)
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
model: dropArea.containsDrag && !dropArea.onlySubtitles ? 2 : 0
|
|
delegate: Rectangle {
|
|
id: dropZone
|
|
|
|
required property int index
|
|
readonly property bool isTop: index === 0
|
|
readonly property bool active: isTop === dropArea.onTopPart
|
|
|
|
x: Kirigami.Units.smallSpacing
|
|
y: isTop ? Kirigami.Units.smallSpacing : dropArea.height * 0.25 + Kirigami.Units.smallSpacing
|
|
width: dropArea.width - Kirigami.Units.smallSpacing * 2
|
|
height: (isTop ? dropArea.height * 0.25 : dropArea.height * 0.75) - Kirigami.Units.smallSpacing * 2
|
|
color: "transparent"
|
|
radius: Kirigami.Units.cornerRadius
|
|
border.color: active ? Kirigami.Theme.activeTextColor : "transparent"
|
|
border.width: active ? 3 : 0
|
|
|
|
Label {
|
|
anchors.fill: parent
|
|
text: dropZone.isTop
|
|
? KI18n.i18nc("@info:drag&drop append items", "Add to Playlist")
|
|
: KI18n.i18nc("@info:drag&drop play now", "Play Now")
|
|
elide: Text.ElideRight
|
|
color: "white"
|
|
style: Text.Outline
|
|
styleColor: "black"
|
|
opacity: dropZone.active ? 1 : 0.7
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * (dropZone.isTop ? 1.6 : 2.2)
|
|
font.bold: true
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
verticalAlignment: Qt.AlignVCenter
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|