feat: auto-hide controls in full screen, add subtitle size and outline settings

This commit is contained in:
tri committed 2026-10-27 23:00:17 +07:00
1 parent 4665bf632a
commit fe2f159660
4 files changed
+176 -8

No files matched your search

+1
View File
@@ -18,6 +18,7 @@ Kirigami.ApplicationWindow {
pageStack.initialPage: PlayerPage {
id: player
initialUrl: root.initialUrl
fullScreen: root.visibility === Window.FullScreen
onAboutRequested: root.pageStack.layers.push(aboutPage)
onSettingsRequested: root.pageStack.layers.push(settingsPage)
onFullScreenToggled: root.visibility = root.visibility === Window.FullScreen ? Window.Windowed : Window.FullScreen
+135 -8
View File
@@ -9,6 +9,9 @@ Kirigami.Page {
id: page
property url initialUrl
// Set by the window. In full screen the bars float over the video and hide when the
// pointer rests.
property bool fullScreen: false
readonly property alias mediaTitle: mpv.mediaTitle
readonly property alias translator: translator
@@ -18,6 +21,27 @@ Kirigami.Page {
title: KI18n.i18nc("@title", "Player")
padding: 0
globalToolBarStyle: fullScreen ? Kirigami.ApplicationHeaderStyle.None : Kirigami.ApplicationHeaderStyle.ToolBar
// Kept true for a moment after the pointer moves.
property bool pointerActive: false
readonly property bool controlsVisible: !fullScreen || pointerActive || topBarHover.hovered || footerHover.hovered
|| subtitlePopup.visible || seekBar.pressed || !mpv.fileLoaded || menuOpen
// Set while the full screen "More" menu is open, so the bars stay.
property bool menuOpen: false
onFullScreenChanged: page.revealControls()
function revealControls() {
pointerActive = true
idleTimer.restart()
}
Timer {
id: idleTimer
interval: 2500
onTriggered: page.pointerActive = false
}
actions: [
Kirigami.Action {
@@ -27,10 +51,10 @@ Kirigami.Page {
onTriggered: fileDialog.open()
},
Kirigami.Action {
icon.name: "view-fullscreen"
text: KI18n.i18nc("@action", "Full Screen")
// F and Esc are handled by the Shortcuts below, which work while the bars are hidden.
icon.name: page.fullScreen ? "view-restore" : "view-fullscreen"
text: page.fullScreen ? KI18n.i18nc("@action", "Exit Full Screen") : KI18n.i18nc("@action", "Full Screen")
displayHint: Kirigami.DisplayHint.IconOnly
shortcut: "F"
onTriggered: page.fullScreenToggled()
},
Kirigami.Action {
@@ -49,11 +73,23 @@ Kirigami.Page {
]
Component.onCompleted: {
page.applySubtitleStyle()
if (page.initialUrl.toString().length > 0) {
mpv.loadFile(page.initialUrl)
}
}
// Plain-text and translated subtitles; styled ASS subtitles keep their own fonts.
function applySubtitleStyle() {
mpv.setPropertyAsync("sub-font-size", QtPotatoSettings.subtitleFontSize)
mpv.setPropertyAsync("sub-outline-size", QtPotatoSettings.subtitleOutlineSize)
}
readonly property int subtitleFontSize: QtPotatoSettings.subtitleFontSize
onSubtitleFontSizeChanged: applySubtitleStyle()
readonly property int subtitleOutlineSize: QtPotatoSettings.subtitleOutlineSize
onSubtitleOutlineSizeChanged: applySubtitleStyle()
function formatTime(totalSeconds: real): string {
const s = Math.max(0, Math.floor(totalSeconds))
const h = Math.floor(s / 3600)
@@ -66,6 +102,15 @@ Kirigami.Page {
sequence: "Space"
onActivated: mpv.togglePause()
}
Shortcut {
sequence: "F"
onActivated: page.fullScreenToggled()
}
Shortcut {
sequence: "Escape"
enabled: page.fullScreen
onActivated: page.fullScreenToggled()
}
Shortcut {
sequence: "Left"
onActivated: mpv.seek(mpv.position - 5)
@@ -125,14 +170,17 @@ Kirigami.Page {
onAccepted: mpv.loadFile(selectedFile)
}
ColumnLayout {
Item {
anchors.fill: parent
spacing: 0
MpvItem {
id: mpv
Layout.fillWidth: true
Layout.fillHeight: true
anchors {
left: parent.left
right: parent.right
top: parent.top
bottom: page.fullScreen ? parent.bottom : footer.top
}
Rectangle {
anchors.fill: parent
@@ -153,6 +201,9 @@ Kirigami.Page {
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: page.controlsVisible ? Qt.ArrowCursor : Qt.BlankCursor
onPositionChanged: page.revealControls()
onClicked: mpv.togglePause()
onDoubleClicked: page.fullScreenToggled()
}
@@ -173,9 +224,85 @@ Kirigami.Page {
}
}
// Stands in for the page header in full screen.
QQC2.ToolBar {
Layout.fillWidth: true
id: topBar
anchors {
left: parent.left
right: parent.right
top: parent.top
}
position: QQC2.ToolBar.Header
// No fade: over a paused video Qt Quick renders frames too rarely for a smooth one.
visible: page.fullScreen && page.controlsVisible
HoverHandler {
id: topBarHover
}
contentItem: RowLayout {
spacing: Kirigami.Units.smallSpacing
Kirigami.Heading {
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing
level: 1
elide: Text.ElideRight
text: mpv.mediaTitle
}
// Plain buttons: Kirigami.ActionToolBar dropped the full screen action here.
QQC2.ToolButton {
action: page.actions[0]
focusPolicy: Qt.NoFocus
}
QQC2.ToolButton {
action: page.actions[1]
focusPolicy: Qt.NoFocus
display: QQC2.AbstractButton.IconOnly
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
QQC2.ToolButton {
id: moreButton
focusPolicy: Qt.NoFocus
icon.name: "overflow-menu"
text: KI18n.i18nc("@action:button", "More")
display: QQC2.AbstractButton.IconOnly
down: moreMenu.visible
onPressed: moreMenu.popup(moreButton, 0, moreButton.height)
QQC2.Menu {
id: moreMenu
onVisibleChanged: page.menuOpen = visible
QQC2.MenuItem {
action: page.actions[2]
}
QQC2.MenuItem {
action: page.actions[3]
}
}
}
}
}
QQC2.ToolBar {
id: footer
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
position: QQC2.ToolBar.Footer
visible: page.controlsVisible
HoverHandler {
id: footerHover
}
RowLayout {
anchors.fill: parent
+26
View File
@@ -27,6 +27,32 @@ FormCard.FormCardPage {
onVisibleChanged: if (!visible) page.translator.clearError()
}
FormCard.FormHeader {
title: KI18n.i18nc("@title:group", "Subtitles")
}
FormCard.FormCard {
FormCard.FormSpinBoxDelegate {
label: KI18n.i18nc("@label:spinbox", "Text size")
description: KI18n.i18nc("@info", "Text size and outline apply to translated and plain-text subtitles. Styled subtitles (ASS) keep the look they were made with.")
from: 20
to: 150
stepSize: 2
value: QtPotatoSettings.subtitleFontSize
onValueModified: QtPotatoSettings.subtitleFontSize = value
}
FormCard.FormDelegateSeparator {}
FormCard.FormSpinBoxDelegate {
label: KI18n.i18nc("@label:spinbox", "Outline size")
from: 0
to: 10
value: QtPotatoSettings.subtitleOutlineSize
onValueModified: QtPotatoSettings.subtitleOutlineSize = value
}
}
FormCard.FormHeader {
title: KI18n.i18nc("@title:group", "Subtitle Translation")
}
+14
View File
@@ -3,6 +3,20 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfgfile name="qtpotatorc"/>
<group name="Subtitles">
<entry name="SubtitleFontSize" type="Int">
<label>Font size of plain-text and translated subtitles, in mpv's scaled pixels (mpv's own default is 38)</label>
<default>52</default>
<min>20</min>
<max>150</max>
</entry>
<entry name="SubtitleOutlineSize" type="Int">
<label>Outline width of plain-text and translated subtitles (mpv's own default is 1.65)</label>
<default>3</default>
<min>0</min>
<max>10</max>
</entry>
</group>
<group name="Translation">
<entry name="ApiBaseUrl" type="String">
<label>Base URL of the OpenAI-compatible API, including the version path (for example …/v1)</label>