feat: add Kirigami app skeleton with libmpv playback
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
1eb67b829c
8 files changed
+540
No files matched your search
@@ -0,0 +1,171 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.ki18n
|
||||
|
||||
Kirigami.Page {
|
||||
id: page
|
||||
|
||||
property url initialUrl
|
||||
readonly property alias mediaTitle: mpv.mediaTitle
|
||||
|
||||
signal aboutRequested()
|
||||
signal fullScreenToggled()
|
||||
|
||||
title: KI18n.i18nc("@title", "Player")
|
||||
padding: 0
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "document-open"
|
||||
text: KI18n.i18nc("@action", "Open File…")
|
||||
shortcut: StandardKey.Open
|
||||
onTriggered: fileDialog.open()
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "view-fullscreen"
|
||||
text: KI18n.i18nc("@action", "Full Screen")
|
||||
displayHint: Kirigami.DisplayHint.IconOnly
|
||||
shortcut: "F"
|
||||
onTriggered: page.fullScreenToggled()
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "help-about"
|
||||
text: KI18n.i18nc("@action", "About QtPotato")
|
||||
displayHint: Kirigami.DisplayHint.AlwaysHide
|
||||
onTriggered: page.aboutRequested()
|
||||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: {
|
||||
if (page.initialUrl.toString().length > 0) {
|
||||
mpv.loadFile(page.initialUrl)
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(totalSeconds: real): string {
|
||||
const s = Math.max(0, Math.floor(totalSeconds))
|
||||
const h = Math.floor(s / 3600)
|
||||
const m = Math.floor((s % 3600) / 60)
|
||||
const sec = String(s % 60).padStart(2, "0")
|
||||
return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${sec}` : `${m}:${sec}`
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Space"
|
||||
onActivated: mpv.togglePause()
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Left"
|
||||
onActivated: mpv.seek(mpv.position - 5)
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Right"
|
||||
onActivated: mpv.seek(mpv.position + 5)
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: fileDialog
|
||||
title: KI18n.i18nc("@title:window", "Open Video")
|
||||
nameFilters: [
|
||||
KI18n.i18nc("@item:inlistbox file filter", "Video files (*.mkv *.mp4 *.webm *.avi *.mov *.m4v *.ts *.flv *.wmv)"),
|
||||
KI18n.i18nc("@item:inlistbox file filter", "All files (*)")
|
||||
]
|
||||
onAccepted: mpv.loadFile(selectedFile)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
MpvItem {
|
||||
id: mpv
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "black"
|
||||
visible: !mpv.fileLoaded
|
||||
z: -1
|
||||
}
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - Kirigami.Units.gridUnit * 4
|
||||
visible: !mpv.fileLoaded
|
||||
icon.name: "video-symbolic"
|
||||
text: KI18n.i18nc("@info:placeholder", "No video open")
|
||||
explanation: KI18n.i18nc("@info:placeholder", "Open a file or drop one here")
|
||||
helpfulAction: page.actions[0]
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: mpv.togglePause()
|
||||
onDoubleClicked: page.fullScreenToggled()
|
||||
}
|
||||
|
||||
DropArea {
|
||||
anchors.fill: parent
|
||||
onDropped: drop => {
|
||||
if (drop.hasUrls) {
|
||||
mpv.loadFile(drop.urls[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.ToolBar {
|
||||
Layout.fillWidth: true
|
||||
position: QQC2.ToolBar.Footer
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
QQC2.ToolButton {
|
||||
enabled: mpv.fileLoaded
|
||||
focusPolicy: Qt.NoFocus
|
||||
icon.name: mpv.paused || !mpv.fileLoaded ? "media-playback-start" : "media-playback-pause"
|
||||
text: mpv.paused || !mpv.fileLoaded ? KI18n.i18nc("@action:button", "Play") : KI18n.i18nc("@action:button", "Pause")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
onClicked: mpv.togglePause()
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
|
||||
QQC2.Label {
|
||||
text: page.formatTime(seekBar.pressed ? seekBar.value : mpv.position)
|
||||
font.features: { "tnum": 1 }
|
||||
}
|
||||
|
||||
QQC2.Slider {
|
||||
id: seekBar
|
||||
Layout.fillWidth: true
|
||||
enabled: mpv.fileLoaded && mpv.duration > 0
|
||||
focusPolicy: Qt.NoFocus
|
||||
from: 0
|
||||
to: Math.max(mpv.duration, 1)
|
||||
onMoved: mpv.seek(value)
|
||||
|
||||
// Follow playback, but not while the user is dragging the handle.
|
||||
Binding on value {
|
||||
value: mpv.position
|
||||
when: !seekBar.pressed
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.Label {
|
||||
text: page.formatTime(mpv.duration)
|
||||
font.features: { "tnum": 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user