feat: auto-hide controls in full screen, add subtitle size and outline settings
This commit is contained in:
1 parent
4665bf632a
commit
fe2f159660
4 files changed
+175
-7
No files matched your search
@@ -18,6 +18,7 @@ Kirigami.ApplicationWindow {
|
|||||||
pageStack.initialPage: PlayerPage {
|
pageStack.initialPage: PlayerPage {
|
||||||
id: player
|
id: player
|
||||||
initialUrl: root.initialUrl
|
initialUrl: root.initialUrl
|
||||||
|
fullScreen: root.visibility === Window.FullScreen
|
||||||
onAboutRequested: root.pageStack.layers.push(aboutPage)
|
onAboutRequested: root.pageStack.layers.push(aboutPage)
|
||||||
onSettingsRequested: root.pageStack.layers.push(settingsPage)
|
onSettingsRequested: root.pageStack.layers.push(settingsPage)
|
||||||
onFullScreenToggled: root.visibility = root.visibility === Window.FullScreen ? Window.Windowed : Window.FullScreen
|
onFullScreenToggled: root.visibility = root.visibility === Window.FullScreen ? Window.Windowed : Window.FullScreen
|
||||||
|
|||||||
+134
-7
@@ -9,6 +9,9 @@ Kirigami.Page {
|
|||||||
id: page
|
id: page
|
||||||
|
|
||||||
property url initialUrl
|
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 mediaTitle: mpv.mediaTitle
|
||||||
readonly property alias translator: translator
|
readonly property alias translator: translator
|
||||||
|
|
||||||
@@ -18,6 +21,27 @@ Kirigami.Page {
|
|||||||
|
|
||||||
title: KI18n.i18nc("@title", "Player")
|
title: KI18n.i18nc("@title", "Player")
|
||||||
padding: 0
|
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: [
|
actions: [
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
@@ -27,10 +51,10 @@ Kirigami.Page {
|
|||||||
onTriggered: fileDialog.open()
|
onTriggered: fileDialog.open()
|
||||||
},
|
},
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
icon.name: "view-fullscreen"
|
// F and Esc are handled by the Shortcuts below, which work while the bars are hidden.
|
||||||
text: KI18n.i18nc("@action", "Full Screen")
|
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
|
displayHint: Kirigami.DisplayHint.IconOnly
|
||||||
shortcut: "F"
|
|
||||||
onTriggered: page.fullScreenToggled()
|
onTriggered: page.fullScreenToggled()
|
||||||
},
|
},
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
@@ -49,11 +73,23 @@ Kirigami.Page {
|
|||||||
]
|
]
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
page.applySubtitleStyle()
|
||||||
if (page.initialUrl.toString().length > 0) {
|
if (page.initialUrl.toString().length > 0) {
|
||||||
mpv.loadFile(page.initialUrl)
|
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 {
|
function formatTime(totalSeconds: real): string {
|
||||||
const s = Math.max(0, Math.floor(totalSeconds))
|
const s = Math.max(0, Math.floor(totalSeconds))
|
||||||
const h = Math.floor(s / 3600)
|
const h = Math.floor(s / 3600)
|
||||||
@@ -66,6 +102,15 @@ Kirigami.Page {
|
|||||||
sequence: "Space"
|
sequence: "Space"
|
||||||
onActivated: mpv.togglePause()
|
onActivated: mpv.togglePause()
|
||||||
}
|
}
|
||||||
|
Shortcut {
|
||||||
|
sequence: "F"
|
||||||
|
onActivated: page.fullScreenToggled()
|
||||||
|
}
|
||||||
|
Shortcut {
|
||||||
|
sequence: "Escape"
|
||||||
|
enabled: page.fullScreen
|
||||||
|
onActivated: page.fullScreenToggled()
|
||||||
|
}
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Left"
|
sequence: "Left"
|
||||||
onActivated: mpv.seek(mpv.position - 5)
|
onActivated: mpv.seek(mpv.position - 5)
|
||||||
@@ -125,14 +170,17 @@ Kirigami.Page {
|
|||||||
onAccepted: mpv.loadFile(selectedFile)
|
onAccepted: mpv.loadFile(selectedFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
MpvItem {
|
MpvItem {
|
||||||
id: mpv
|
id: mpv
|
||||||
Layout.fillWidth: true
|
anchors {
|
||||||
Layout.fillHeight: true
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
top: parent.top
|
||||||
|
bottom: page.fullScreen ? parent.bottom : footer.top
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -153,6 +201,9 @@ Kirigami.Page {
|
|||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: page.controlsVisible ? Qt.ArrowCursor : Qt.BlankCursor
|
||||||
|
onPositionChanged: page.revealControls()
|
||||||
onClicked: mpv.togglePause()
|
onClicked: mpv.togglePause()
|
||||||
onDoubleClicked: page.fullScreenToggled()
|
onDoubleClicked: page.fullScreenToggled()
|
||||||
}
|
}
|
||||||
@@ -173,9 +224,85 @@ Kirigami.Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stands in for the page header in full screen.
|
||||||
QQC2.ToolBar {
|
QQC2.ToolBar {
|
||||||
|
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.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
|
position: QQC2.ToolBar.Footer
|
||||||
|
visible: page.controlsVisible
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: footerHover
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -27,6 +27,32 @@ FormCard.FormCardPage {
|
|||||||
onVisibleChanged: if (!visible) page.translator.clearError()
|
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 {
|
FormCard.FormHeader {
|
||||||
title: KI18n.i18nc("@title:group", "Subtitle Translation")
|
title: KI18n.i18nc("@title:group", "Subtitle Translation")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,20 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
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">
|
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||||
<kcfgfile name="qtpotatorc"/>
|
<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">
|
<group name="Translation">
|
||||||
<entry name="ApiBaseUrl" type="String">
|
<entry name="ApiBaseUrl" type="String">
|
||||||
<label>Base URL of the OpenAI-compatible API, including the version path (for example …/v1)</label>
|
<label>Base URL of the OpenAI-compatible API, including the version path (for example …/v1)</label>
|
||||||
|
|||||||
Reference in new issue
Block a user