Warning, /multimedia/haruna/src/qml/main.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 QtQuick
0008 import QtQuick.Window
0009 import QtQuick.Layouts
0010 import Qt.labs.platform as Platform
0011 import QtQml
0012
0013 import org.kde.kirigami as Kirigami
0014 import org.kde.haruna
0015 import org.kde.haruna.settings
0016
0017 Kirigami.ApplicationWindow {
0018 id: window
0019
0020 property bool containsMouse: false
0021
0022 property int previousVisibility: Window.Windowed
0023 property var acceptedSubtitleTypes: ["application/x-subrip", "text/x-ssa"]
0024
0025 visible: true
0026 title: mpv.mediaTitle || i18nc("@title:window", "Haruna")
0027 width: Kirigami.Units.gridUnit * 66
0028 minimumWidth: Kirigami.Units.gridUnit * 36
0029 height: Kirigami.Units.gridUnit * 40
0030 minimumHeight: Kirigami.Units.gridUnit * 22
0031 color: Kirigami.Theme.backgroundColor
0032
0033 onClosing: app.saveWindowGeometry(window)
0034 onWidthChanged: saveWindowGeometryTimer.restart()
0035 onHeightChanged: saveWindowGeometryTimer.restart()
0036 onXChanged: saveWindowGeometryTimer.restart()
0037 onYChanged: saveWindowGeometryTimer.restart()
0038
0039 onVisibilityChanged: function(visibility) {
0040 if (PlaybackSettings.pauseWhileMinimized) {
0041 if (visibility === Window.Minimized) {
0042 if (mpv.pause) {
0043 mpv.preMinimizePlaybackState = MpvVideo.PlaybackState.Paused
0044 } else {
0045 mpv.preMinimizePlaybackState = MpvVideo.PlaybackState.Playing
0046 }
0047 mpv.pause = true
0048 }
0049 if (previousVisibility === Window.Minimized
0050 && visibility === Window.Windowed | Window.Maximized | Window.FullScreen) {
0051 if (mpv.preMinimizePlaybackState === MpvVideo.PlaybackState.Playing) {
0052 mpv.pause = false
0053 }
0054 }
0055 }
0056
0057 // used to restore window state, when exiting fullscreen,
0058 // to the one it had before going fullscreen
0059 if (visibility !== Window.FullScreen) {
0060 previousVisibility = visibility
0061 }
0062 }
0063
0064 header: Header { id: header }
0065
0066 menuBar: MenuBarLoader {
0067 id: menuBarLoader
0068 }
0069
0070 MpvVideo {
0071 id: mpv
0072
0073 width: window.contentItem.width
0074 height: window.isFullScreen() ? window.contentItem.height : window.contentItem.height - footer.height
0075 anchors.left: PlaylistSettings.overlayVideo
0076 ? window.contentItem.left
0077 : (PlaylistSettings.position === "left" ? playlist.right : window.contentItem.left)
0078 anchors.right: PlaylistSettings.overlayVideo
0079 ? window.contentItem.right
0080 : (PlaylistSettings.position === "right" ? playlist.left : window.contentItem.right)
0081 anchors.top: parent.top
0082
0083 onVideoReconfig: {
0084 resizeWindow()
0085 }
0086
0087 onAddToRecentFiles: function(url) {
0088 recentFilesModel.addUrl(url)
0089 }
0090
0091 Osd {
0092 id: osd
0093
0094 maxWidth: mpv.width
0095 }
0096
0097 SelectActionPopup {
0098 id: triggerActionPopup
0099
0100 property int minHeight: mpv.height * 0.5
0101 property int maxHeight: mpv.height * 0.9
0102
0103 x: mpv.width * 0.5 - width * 0.5
0104 y: Kirigami.Units.largeSpacing
0105 width: Kirigami.Units.gridUnit * 20
0106 height: minHeight < Kirigami.Units.gridUnit * 16 ? maxHeight : minHeight
0107 title: ""
0108 subtitle: ""
0109
0110 onActionSelected: function (actionName) {
0111 appActions[actionName].trigger()
0112 }
0113 }
0114 }
0115
0116 PlayList {
0117 id: playlist
0118
0119 anchors.top: mpv.top
0120 anchors.bottom: footer.top
0121 }
0122
0123 Footer {
0124 id: footer
0125
0126 m_mpv: mpv
0127
0128 anchors.left: window.contentItem.left
0129 anchors.right: window.contentItem.right
0130 anchors.bottom: window.isFullScreen() ? mpv.bottom : window.contentItem.bottom
0131 state: !window.isFullScreen() || (mpv.mouseY > window.height - footer.implicitHeight && window.containsMouse)
0132 ? "visible" : "hidden"
0133 }
0134
0135 Actions {}
0136
0137 ActionsModel {
0138 id: actionsModel
0139 }
0140
0141 ProxyActionsModel {
0142 id: proxyActionsModel
0143
0144 sourceModel: actionsModel
0145 }
0146
0147 CustomCommandsModel {
0148 id: customCommandsModel
0149
0150 appActionsModel: actionsModel
0151 Component.onCompleted: init()
0152 }
0153
0154 RecentFilesModel {
0155 id: recentFilesModel
0156 }
0157
0158 SubtitlesFoldersModel {
0159 id: subtitlesFoldersModel
0160 }
0161
0162 RowLayout {
0163 width: window.width * 0.8 > Kirigami.Units.gridUnit * 50
0164 ? Kirigami.Units.gridUnit * 50
0165 : window.width * 0.8
0166 anchors.centerIn: parent
0167
0168 Kirigami.InlineMessage {
0169 id: messageBox
0170
0171 Layout.fillWidth: true
0172 Layout.fillHeight: true
0173 type: Kirigami.MessageType.Error
0174 showCloseButton: true
0175 }
0176 }
0177
0178 Loader {
0179 id: mpvContextMenuLoader
0180
0181 active: false
0182 sourceComponent: ContextMenu {
0183 onClosed: mpvContextMenuLoader.active = false
0184 }
0185 }
0186
0187 Loader {
0188 id: settingsLoader
0189
0190 active: false
0191 sourceComponent: SettingsWindow {}
0192 }
0193
0194 Connections {
0195 target: app
0196 function onQmlApplicationMouseLeave() {
0197 if (PlaylistSettings.canToggleWithMouse && window.isFullScreen()) {
0198 playlist.state = "hidden"
0199 }
0200 window.containsMouse = false
0201 }
0202 function onQmlApplicationMouseEnter() {
0203 window.containsMouse = true
0204 }
0205 function onError(message) {
0206 messageBox.visible = true
0207 messageBox.text = message
0208 }
0209 function onOpenUrl(url) {
0210 if (GeneralSettings.appendVideoToSingleInstance) {
0211 mpv.playlistModel.appendItem(url.toString())
0212 } else {
0213 openFile(url)
0214 }
0215 }
0216 }
0217
0218 Platform.FileDialog {
0219 id: fileDialog
0220
0221 property url location: GeneralSettings.fileDialogLocation
0222 ? app.pathToUrl(GeneralSettings.fileDialogLocation)
0223 : app.pathToUrl(GeneralSettings.fileDialogLastLocation)
0224
0225 folder: location
0226 title: i18nc("@title:window", "Select file")
0227 fileMode: Platform.FileDialog.OpenFile
0228
0229 onAccepted: {
0230 openFile(fileDialog.file.toString(), true)
0231 mpv.focus = true
0232
0233 GeneralSettings.fileDialogLastLocation = app.parentUrl(fileDialog.file)
0234 GeneralSettings.save()
0235 }
0236 onRejected: mpv.focus = true
0237 }
0238
0239 Platform.FileDialog {
0240 id: subtitlesFileDialog
0241
0242 property url location: {
0243 if (mpv.currentUrl) {
0244 return app.parentUrl(mpv.currentUrl)
0245 } else {
0246 return (GeneralSettings.fileDialogLocation
0247 ? app.pathToUrl(GeneralSettings.fileDialogLocation)
0248 : app.pathToUrl(GeneralSettings.fileDialogLastLocation))
0249 }
0250 }
0251
0252 folder: location
0253 title: i18nc("@title:window", "Select subtitles file")
0254 fileMode: Platform.FileDialog.OpenFile
0255 nameFilters: ["Subtitles (*.srt *.ssa *.ass)"]
0256
0257 onAccepted: {
0258 if (acceptedSubtitleTypes.includes(app.mimeType(subtitlesFileDialog.file))) {
0259 mpv.command(["sub-add", subtitlesFileDialog.file.toString(), "select"])
0260 }
0261 }
0262 onRejected: mpv.focus = true
0263 }
0264
0265 InputPopup {
0266 id: openUrlPopup
0267
0268 x: 10
0269 y: 10
0270 lastUrl: GeneralSettings.lastUrl
0271 buttonText: i18nc("@action:button", "Open")
0272
0273 onUrlOpened: function(url) {
0274 window.openFile(url, true)
0275 GeneralSettings.lastUrl = url
0276 GeneralSettings.save()
0277 }
0278 }
0279
0280 // This timer allows to batch update the window size change to reduce
0281 // the io load and also work around the fact that x/y/width/height are
0282 // changed when loading the page and overwrite the saved geometry from
0283 // the previous session.
0284 Timer {
0285 id: saveWindowGeometryTimer
0286
0287 interval: 1000
0288 onTriggered: app.saveWindowGeometry(window)
0289 }
0290
0291 Component.onCompleted: {
0292 app.restoreWindowGeometry(window)
0293 app.activateColorScheme(GeneralSettings.colorScheme)
0294 }
0295
0296 function openFile(path, addToRecentFiles = false) {
0297 if (addToRecentFiles) {
0298 recentFilesModel.addUrl(path)
0299 }
0300
0301 mpv.playlistModel.addItem(path, PlaylistModel.Clear)
0302 }
0303
0304 function isFullScreen() {
0305 return window.visibility === Window.FullScreen
0306 }
0307
0308 function toggleFullScreen() {
0309 if (!isFullScreen()) {
0310 window.showFullScreen()
0311 } else {
0312 exitFullscreen()
0313 }
0314 }
0315
0316 function exitFullscreen() {
0317 if (window.previousVisibility === Window.Maximized) {
0318 window.show()
0319 window.showMaximized()
0320 } else {
0321 window.showNormal()
0322 }
0323 }
0324
0325 function resizeWindow() {
0326 if (!GeneralSettings.resizeWindowToVideo || isFullScreen()) {
0327 return
0328 }
0329
0330 window.width = mpv.videoWidth
0331 window.height = mpv.videoHeight
0332 + (footer.visible ? footer.height : 0)
0333 + (header.visible ? header.height : 0)
0334 + (menuBar.visible ? menuBar.height : 0)
0335 }
0336 }