diff --git a/CMakeLists.txt b/CMakeLists.txt index d976813..371369a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,75 +1,55 @@ -# -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.14) project(cutefish-videoplayer LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) + set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -find_package(ECM 1.0.0 REQUIRED NO_MODULE) -set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) - -include(KDEInstallDirs) -include(ECMInstallIcons) -include(FeatureSummary) - -find_package(Qt5Core) -set_package_properties(Qt5Core PROPERTIES TYPE REQUIRED) - -find_package(Qt5DBus) -set_package_properties(Qt5DBus PROPERTIES TYPE REQUIRED) - -find_package(Qt5Qml) -set_package_properties(Qt5Qml PROPERTIES TYPE REQUIRED) - -find_package(Qt5Quick) -set_package_properties(Qt5Quick PROPERTIES TYPE REQUIRED) - -find_package(Qt5QuickControls2) -set_package_properties(Qt5QuickControls2 PROPERTIES TYPE REQUIRED) - +find_package(Qt5 COMPONENTS Core Quick DBus Widgets REQUIRED) find_package(Libmpv) -set_package_properties(Libmpv PROPERTIES TYPE REQUIRED - URL "https://mpv.io") - -find_package(KF5Config) -set_package_properties(KF5Config PROPERTIES TYPE REQUIRED - URL "https://api.kde.org/frameworks/kconfig/html/index.html") - -find_package(KF5CoreAddons) -set_package_properties(KF5CoreAddons PROPERTIES TYPE REQUIRED - URL "https://api.kde.org/frameworks/kcoreaddons/html/index.html") - -find_package(KF5DocTools) -set_package_properties(KF5DocTools PROPERTIES - DESCRIPTION "https://api.kde.org/frameworks/kdoctools/html/index.html") - -find_package(KF5FileMetaData) -set_package_properties(KF5FileMetaData PROPERTIES TYPE REQUIRED - URL "https://api.kde.org/frameworks/kfilemetadata/html/index.html") - -find_package(KF5KIO) -set_package_properties(KF5KIO PROPERTIES TYPE REQUIRED - URL "https://api.kde.org/frameworks/kio/html/index.html") - -#find_package(KF5Kirigami2) -#set_package_properties(KF5Kirigami2 PROPERTIES TYPE REQUIRED -# URL "https://api.kde.org/frameworks/kirigami/html/index.html") - -find_package(KF5XmlGui) -set_package_properties(KF5XmlGui PROPERTIES TYPE REQUIRED - URL "https://api.kde.org/frameworks/kxmlgui/html/index.html") - -#option(InstallColorSchemes "Installs breeze color schemes." OFF) - -feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) -add_subdirectory(src) +qt5_add_dbus_interface(screensaver_inhibit_SRCS ./org.freedesktop.ScreenSaver.xml screensaverdbusinterface) + +set(PROJECT_SOURCES + src/main.cpp + src/application.cpp + src/playlistmodel.cpp + src/playlistitem.cpp + src/track.cpp + src/tracksmodel.cpp + src/mpvobject.cpp + src/qthelper.h + src/lockmanager.cpp + src/mpris2/mediaplayer2.cpp + src/mpris2/mediaplayer2player.cpp + qml.qrc + ${screensaver_inhibit_SRCS} +) + +add_executable(cutefish-videoplayer + ${PROJECT_SOURCES} +) + +target_link_libraries(cutefish-videoplayer + PRIVATE + Qt5::Core + Qt5::Quick + Qt5::DBus + Qt5::Widgets + Libmpv::Libmpv +) + +install(TARGETS cutefish-videoplayer DESTINATION ${CMAKE_INSTALL_BINDIR}) + +install(FILES + cutefish-videoplayer.desktop + DESTINATION /usr/share/applications/ + COMPONENT Runtime +) diff --git a/README.md b/README.md index 491aa8f..5bd798b 100644 --- a/README.md +++ b/README.md @@ -2,46 +2,15 @@ An open source video player built with Qt/QML and libmpv. -Based on [haruna](https://github.com/g-fb/haruna) +### Third Party Code -# Features +[haruna](https://github.com/g-fb/haruna) -these are just some features that set Haruna apart from others players +## Dependencies -- play online videos, through youtube-dl - -- toggle playlist with mouse-over, playlist overlays the video - -- auto skip chapter containing certain words - -- configurable shortcuts and mouse buttons - -- quick jump to next chapter by middle click on progress bar - -# Dependencies - -### Build time -- Qt5Core -- Qt5DBus -- Qt5Qml -- Qt5Quick -- Qt5QuickControls2 -- Libmpv -- ExtraCmakeModules -- KF5Config -- KF5CoreAddons -- KF5FileMetaData -- KF5I18n -- KF5IconThemes -- KF5KIO -- KF5XmlGui - -### Runtime -- Kio-extras -- Breeze icons -- Breeze widgets style -- QQC2-Desktop-Style -- Youtube-dl +```sh +sudo apt install extra-cmake-modules qtbase5-dev qtdeclarative5-dev qtquickcontrols2-5-dev libmpv-dev +``` # Build and Install @@ -55,4 +24,4 @@ sudo make install # License -This project has been licensed by GPLv3. \ No newline at end of file +This project has been licensed by GPLv3. diff --git a/cutefish-videoplayer.desktop b/cutefish-videoplayer.desktop index 019e3cc..019b8c6 100644 --- a/cutefish-videoplayer.desktop +++ b/cutefish-videoplayer.desktop @@ -1,9 +1,8 @@ [Desktop Entry] Name=Cutefish Video Player Exec=cutefish-videoplayer %u -Icon=videoplayer +Icon=cutefish-videoplayer Type=Application -Categories=Qt;KDE;AudioVideo;Player;Video;TV; +Categories=Qt;AudioVideo;Player;Video;TV; MimeType=application/ogg;application/x-ogg;application/mxf;application/sdp;application/smil;application/x-smil;application/streamingmedia;application/x-streamingmedia;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;audio/aac;audio/x-aac;audio/vnd.dolby.heaac.1;audio/vnd.dolby.heaac.2;audio/aiff;audio/x-aiff;audio/m4a;audio/x-m4a;application/x-extension-m4a;audio/mp1;audio/x-mp1;audio/mp2;audio/x-mp2;audio/mp3;audio/x-mp3;audio/mpeg;audio/mpeg2;audio/mpeg3;audio/mpegurl;audio/x-mpegurl;audio/mpg;audio/x-mpg;audio/rn-mpeg;audio/musepack;audio/x-musepack;audio/ogg;audio/scpls;audio/x-scpls;audio/vnd.rn-realaudio;audio/wav;audio/x-pn-wav;audio/x-pn-windows-pcm;audio/x-realaudio;audio/x-pn-realaudio;audio/x-ms-wma;audio/x-pls;audio/x-wav;video/mpeg;video/x-mpeg2;video/x-mpeg3;video/mp4v-es;video/x-m4v;video/mp4;application/x-extension-mp4;video/divx;video/vnd.divx;video/msvideo;video/x-msvideo;video/ogg;video/quicktime;video/vnd.rn-realvideo;video/x-ms-afs;video/x-ms-asf;audio/x-ms-asf;application/vnd.ms-asf;video/x-ms-wmv;video/x-ms-wmx;video/x-ms-wvxvideo;video/x-avi;video/avi;video/x-flic;video/fli;video/x-flc;video/flv;video/x-flv;video/x-theora;video/x-theora+ogg;video/x-matroska;video/mkv;audio/x-matroska;application/x-matroska;video/webm;audio/webm;audio/vorbis;audio/x-vorbis;audio/x-vorbis+ogg;video/x-ogm;video/x-ogm+ogg;application/x-ogm;application/x-ogm-audio;application/x-ogm-video;application/x-shorten;audio/x-shorten;audio/x-ape;audio/x-wavpack;audio/x-tta;audio/AMR;audio/ac3;audio/eac3;audio/amr-wb;video/mp2t;audio/flac;audio/mp4;application/x-mpegurl;video/vnd.mpegurl;application/vnd.apple.mpegurl;audio/x-pn-au;video/3gp;video/3gpp;video/3gpp2;audio/3gpp;audio/3gpp2;video/dv;audio/dv;audio/opus;audio/vnd.dts;audio/vnd.dts.hd;audio/x-adpcm;application/x-cue;audio/m3u; -X-KDE-Protocols=ftp,http,https,mms,rtmp,rtsp,sftp,smb,srt -Terminal=false +Terminal=false \ No newline at end of file diff --git a/images/cutefish-videoplayer.svg b/images/cutefish-videoplayer.svg new file mode 100644 index 0000000..b3679df --- /dev/null +++ b/images/cutefish-videoplayer.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/images/dark/audio-volume-high-symbolic.svg b/images/dark/audio-volume-high-symbolic.svg new file mode 100755 index 0000000..d049922 --- /dev/null +++ b/images/dark/audio-volume-high-symbolic.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/images/dark/audio-volume-low-symbolic.svg b/images/dark/audio-volume-low-symbolic.svg new file mode 100755 index 0000000..4109e8c --- /dev/null +++ b/images/dark/audio-volume-low-symbolic.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/images/dark/audio-volume-medium-symbolic.svg b/images/dark/audio-volume-medium-symbolic.svg new file mode 100755 index 0000000..05433fb --- /dev/null +++ b/images/dark/audio-volume-medium-symbolic.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/images/dark/audio-volume-muted-symbolic.svg b/images/dark/audio-volume-muted-symbolic.svg new file mode 100755 index 0000000..8ae0231 --- /dev/null +++ b/images/dark/audio-volume-muted-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/images/dark/list.svg b/images/dark/list.svg new file mode 100644 index 0000000..5517525 --- /dev/null +++ b/images/dark/list.svg @@ -0,0 +1,105 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/images/dark/media-playback-pause-symbolic.svg b/images/dark/media-playback-pause-symbolic.svg new file mode 100644 index 0000000..63c10bf --- /dev/null +++ b/images/dark/media-playback-pause-symbolic.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/images/dark/media-playback-start-symbolic.svg b/images/dark/media-playback-start-symbolic.svg new file mode 100644 index 0000000..d9fd388 --- /dev/null +++ b/images/dark/media-playback-start-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/images/dark/media-skip-backward-symbolic.svg b/images/dark/media-skip-backward-symbolic.svg new file mode 100644 index 0000000..e35c9d5 --- /dev/null +++ b/images/dark/media-skip-backward-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/dark/media-skip-forward-symbolic.svg b/images/dark/media-skip-forward-symbolic.svg new file mode 100644 index 0000000..a2c94d7 --- /dev/null +++ b/images/dark/media-skip-forward-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/light/audio-volume-high-symbolic.svg b/images/light/audio-volume-high-symbolic.svg new file mode 100755 index 0000000..602c613 --- /dev/null +++ b/images/light/audio-volume-high-symbolic.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/images/light/audio-volume-low-symbolic.svg b/images/light/audio-volume-low-symbolic.svg new file mode 100755 index 0000000..51bc08b --- /dev/null +++ b/images/light/audio-volume-low-symbolic.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/images/light/audio-volume-medium-symbolic.svg b/images/light/audio-volume-medium-symbolic.svg new file mode 100755 index 0000000..e8d557d --- /dev/null +++ b/images/light/audio-volume-medium-symbolic.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/images/light/audio-volume-muted-symbolic.svg b/images/light/audio-volume-muted-symbolic.svg new file mode 100755 index 0000000..98183af --- /dev/null +++ b/images/light/audio-volume-muted-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/images/light/list.svg b/images/light/list.svg new file mode 100644 index 0000000..603a6d1 --- /dev/null +++ b/images/light/list.svg @@ -0,0 +1,105 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/images/light/media-playback-pause-symbolic.svg b/images/light/media-playback-pause-symbolic.svg new file mode 100644 index 0000000..7929a93 --- /dev/null +++ b/images/light/media-playback-pause-symbolic.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/images/light/media-playback-start-symbolic.svg b/images/light/media-playback-start-symbolic.svg new file mode 100644 index 0000000..551081f --- /dev/null +++ b/images/light/media-playback-start-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/images/light/media-skip-backward-symbolic.svg b/images/light/media-skip-backward-symbolic.svg new file mode 100644 index 0000000..1b85972 --- /dev/null +++ b/images/light/media-skip-backward-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/light/media-skip-forward-symbolic.svg b/images/light/media-skip-forward-symbolic.svg new file mode 100644 index 0000000..1193e44 --- /dev/null +++ b/images/light/media-skip-forward-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/org.freedesktop.ScreenSaver.xml.license b/org.freedesktop.ScreenSaver.xml.license deleted file mode 100644 index f0460a4..0000000 --- a/org.freedesktop.ScreenSaver.xml.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2020 George Florea Bănuș - -SPDX-License-Identifier: CC-BY-4.0 diff --git a/qml.qrc b/qml.qrc new file mode 100644 index 0000000..1873c09 --- /dev/null +++ b/qml.qrc @@ -0,0 +1,30 @@ + + + qml/main.qml + qml/MpvVideo.qml + qml/Footer.qml + qml/HProgressBar.qml + qml/PlayList.qml + qml/PlayListItem.qml + qml/Actions.qml + images/cutefish-videoplayer.svg + images/light/media-playback-pause-symbolic.svg + images/light/media-playback-start-symbolic.svg + images/light/media-skip-backward-symbolic.svg + images/light/media-skip-forward-symbolic.svg + images/dark/media-playback-pause-symbolic.svg + images/dark/media-playback-start-symbolic.svg + images/dark/media-skip-backward-symbolic.svg + images/dark/media-skip-forward-symbolic.svg + images/dark/audio-volume-high-symbolic.svg + images/dark/audio-volume-low-symbolic.svg + images/dark/audio-volume-medium-symbolic.svg + images/dark/audio-volume-muted-symbolic.svg + images/light/audio-volume-high-symbolic.svg + images/light/audio-volume-low-symbolic.svg + images/light/audio-volume-medium-symbolic.svg + images/light/audio-volume-muted-symbolic.svg + images/dark/list.svg + images/light/list.svg + + diff --git a/qml/Actions.qml b/qml/Actions.qml new file mode 100644 index 0000000..6c4a168 --- /dev/null +++ b/qml/Actions.qml @@ -0,0 +1,109 @@ +/* + * SPDX-FileCopyrightText: 2020 George Florea Bănuș + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +QtObject { + id: root + + property var list: ({}) + + property Action togglePlaylistAction: Action { + id: togglePlaylistAction + + Component.onCompleted: list["togglePlaylistAction"] = togglePlaylistAction + + onTriggered: { + if (playList.state === "visible") { + playList.state = "hidden" + } else { + playList.state = "visible" + } + } + } + + property Action playPreviousAction: Action { + id: playPreviousAction +// property var qaction: app.action("playPrevious") +// text: qaction.text +// shortcut: qaction.shortcutName +// icon.name: qaction.iconName() + + Component.onCompleted: list["playPreviousAction"] = playPreviousAction + + onTriggered: { + if (mpv.playlistModel.getPlayingVideo() !== 0) { + const previousFileRow = mpv.playlistModel.getPlayingVideo() - 1 + const previousFile = mpv.playlistModel.getPath(previousFileRow) + const updateLastPlayedFile = !playList.isYouTubePlaylist + mpv.playlistModel.setPlayingVideo(previousFileRow) + mpv.loadFile(previousFile, updateLastPlayedFile) + } + } + } + + + property Action muteAction: Action { + id: muteAction +// property var qaction: app.action("mute") +// text: qaction.text +// shortcut: qaction.shortcutName +// icon.name: qaction.iconName() + + Component.onCompleted: list["muteAction"] = muteAction + + onTriggered: { + mpv.setProperty("mute", !mpv.getProperty("mute")) + if (mpv.getProperty("mute")) { + text = qsTr("Unmute") + icon.name = "player-volume-muted" + } /*else { + text = qaction.text + icon.name = qaction.iconName() + }*/ + } + } + + property Action playNextAction: Action { + id: playNextAction +// property var qaction: app.action("playNext") +// text: qaction.text +// shortcut: qaction.shortcutName +// icon.name: qaction.iconName() + + Component.onCompleted: list["playNextAction"] = playNextAction + + onTriggered: { + const nextFileRow = mpv.playlistModel.getPlayingVideo() + 1 + const updateLastPlayedFile = !playList.isYouTubePlaylist + if (nextFileRow < playList.playlistView.count) { + const nextFile = mpv.playlistModel.getPath(nextFileRow) + mpv.playlistModel.setPlayingVideo(nextFileRow) + mpv.loadFile(nextFile, updateLastPlayedFile) + } else { + // Last file in playlist + // if (PlaylistSettings.repeat) { + mpv.playlistModel.setPlayingVideo(0) + mpv.loadFile(mpv.playlistModel.getPath(0), updateLastPlayedFile) + // } + } + } + } + + property Action playPauseAction: Action { + id: playPauseAction + text: qsTr("Play/Pause") + icon.name: "media-playback-pause" + shortcut: "Space" + + Component.onCompleted: list["playPauseAction"] = playPauseAction + + onTriggered: { + mpv.setProperty("pause", !mpv.getProperty("pause")) + } + } +} diff --git a/qml/Footer.qml b/qml/Footer.qml new file mode 100644 index 0000000..09038e5 --- /dev/null +++ b/qml/Footer.qml @@ -0,0 +1,215 @@ +/* + * SPDX-FileCopyrightText: 2020 George Florea Bănuș + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtGraphicalEffects 1.12 + +import FishUI 1.0 as FishUI + +Item { + id: control + + property alias progressBar: progressBar + property alias footerRow: footerRow + property alias timeInfo: timeInfo + property alias volume: volume + + height: mainLayout.childrenRect.height + FishUI.Units.smallSpacing + enabled: opacity !== 0 + visible: mpv.mouseY > rootWindow.height - footer.height && playList.state === "hidden" + + ShaderEffectSource { + id: shaderEffect + visible: true + anchors.fill: parent + sourceItem: mpv + sourceRect: Qt.rect(0, 0, control.width, control.height) + } + + FastBlur { + visible: true + anchors.fill: shaderEffect + source: shaderEffect + radius: 100 + } + + Rectangle { + id: _background + anchors.fill: parent + color: FishUI.Theme.backgroundColor + opacity: 0.7 + } + + ColumnLayout { + id: mainLayout + anchors.fill: parent + anchors.topMargin: 0 + anchors.bottomMargin: FishUI.Units.smallSpacing + spacing: FishUI.Units.smallSpacing + + HProgressBar { + id: progressBar + Layout.fillWidth: true + enabled: playList.playlistView.count >= 1 + } + + RowLayout { + id: footerRow + + Item { + width: FishUI.Units.smallSpacing + height: 30 + } + + Item { + id: leftItem + Layout.fillWidth: true + Layout.fillHeight: true + + RowLayout { + anchors.fill: parent + + Label { + id: timeInfo + text: app.formatTime(mpv.position) + " / " + app.formatTime(mpv.duration) + font.pointSize: 10 + visible: playList.playlistView.count >= 1 + Layout.alignment: Qt.AlignVCenter + } + } + } + + Item { + id: middleItem + Layout.preferredWidth: middleLayout.childrenRect.width + Layout.fillHeight: true + + RowLayout { + id: middleLayout + anchors.fill: parent + + FishUI.RoundImageButton { + width: 32 + height: 32 + iconMargins: FishUI.Units.smallSpacing + source: "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/media-skip-backward-symbolic.svg" + onClicked: actions.playPauseAction.triggered() + visible: playList.playlistView.count > 1 + } + + FishUI.RoundImageButton { + width: 32 + height: 32 + iconMargins: FishUI.Units.smallSpacing + source: mpv.pause ? "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/media-playback-start-symbolic.svg" + : "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/media-playback-pause-symbolic.svg" + onClicked: actions.playPauseAction.triggered() + } + + FishUI.RoundImageButton { + width: 32 + height: 32 + iconMargins: FishUI.Units.smallSpacing + source: "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/media-skip-forward-symbolic.svg" + onClicked: actions.playPauseAction.triggered() + visible: playList.playlistView.count > 1 + } + +// ToolButton { +// id: playPreviousFile +// action: actions.playPreviousAction +// text: "" +// focusPolicy: Qt.NoFocus +// enabled: playList.playlistView.count > 1 +// } + +// ToolButton { +// id: playPauseButton +// action: actions.playPauseAction +// text: "" +// icon.name: "media-playback-pause" +// focusPolicy: Qt.NoFocus +// } + +// ToolButton { +// id: playNextFile +// action: actions.playNextAction +// text: "" +// focusPolicy: Qt.NoFocus +// enabled: playList.playlistView.count > 1 +// } + } + } + + Item { + id: rightItem + Layout.fillWidth: true + Layout.fillHeight: true + + RowLayout { + anchors.fill: parent + spacing: FishUI.Units.smallSpacing + + Item { + Layout.fillWidth: true + } + + FishUI.RoundImageButton { + id: mute + width: 32 + height: 32 + iconMargins: FishUI.Units.smallSpacing + 3 + source: mpv.getProperty("mute") ? "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/audio-volume-muted-symbolic.svg" + : "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/audio-volume-high-symbolic.svg" + onClicked: { + mpv.setProperty("mute", !mpv.getProperty("mute")) + if (mpv.getProperty("mute")) { + mute.source = "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/audio-volume-muted-symbolic.svg" + } else { + mute.source = "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/audio-volume-high-symbolic.svg" + } + } + } + + Slider { + id: volume + from: 0 + to: 100 + value: mpv.volume + implicitWidth: 100 + implicitHeight: 25 + wheelEnabled: true + leftPadding: 0 + rightPadding: 0 + + onValueChanged: { + mpv.volume = value.toFixed(0) + // Settings.volume = value.toFixed(0) + } + } + + Item { + width: 1 + } + + FishUI.RoundImageButton { + width: 32 + height: 32 + iconMargins: FishUI.Units.smallSpacing + 2 + source: "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/list.svg" + onClicked: actions.togglePlaylistAction.triggered() + } + + Item { + width: FishUI.Units.smallSpacing + } + } + } + } + } +} diff --git a/src/qml/HProgressBar.qml b/qml/HProgressBar.qml similarity index 92% rename from src/qml/HProgressBar.qml rename to qml/HProgressBar.qml index c6633ce..527ec28 100644 --- a/src/qml/HProgressBar.qml +++ b/qml/HProgressBar.qml @@ -12,7 +12,6 @@ import QtQuick.Shapes 1.12 import QtGraphicalEffects 1.0 import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 Slider { id: root @@ -24,7 +23,7 @@ Slider { from: 0 to: mpv.duration implicitWidth: 200 - implicitHeight: 10 + implicitHeight: 7 leftPadding: 0 rightPadding: 0 @@ -34,19 +33,6 @@ Slider { id: progressBarBackground color: FishUI.Theme.alternateBackgroundColor -// layer.enabled: true -// layer.effect: OpacityMask { -// maskSource: Item { -// width: progressBarBackground.width -// height: progressBarBackground.height - -// Rectangle { -// anchors.fill: parent -// radius: FishUI.Theme.smallRadius -// } -// } -// } - Rectangle { id: loopIndicator property double startPosition: -1 @@ -122,7 +108,8 @@ Slider { // create markers for the chapters Repeater { id: chaptersInstantiator - model: GeneralSettings.showChapterMarkers ? chapters : 0 + // model: GeneralSettings.showChapterMarkers ? chapters : 0 + model: 0 delegate: Shape { id: chapterMarkerShape @@ -191,7 +178,7 @@ Slider { id: skipChaptersMenuItem text: qsTr("Skip Chapters") checkable: true - checked: PlaybackSettings.skipChapters + // checked: PlaybackSettings.skipChapters onCheckedChanged: { PlaybackSettings.skipChapters = checked PlaybackSettings.save() diff --git a/qml/MpvVideo.qml b/qml/MpvVideo.qml new file mode 100644 index 0000000..e46df14 --- /dev/null +++ b/qml/MpvVideo.qml @@ -0,0 +1,183 @@ +/* + * SPDX-FileCopyrightText: 2020 George Florea Bănuș + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Window 2.12 +import FishUI 1.0 as FishUI +import mpv 1.0 + +MpvObject { + id: control + + property int mouseX: mouseArea.mouseX + property int mouseY: mouseArea.mouseY + + onReady: { + if (app.argument(0) !== "") { + rootWindow.openFile(app.argument(0), true) + } + } + + onFileLoaded: { + // loadingIndicatorParent.visible = false + // header.audioTracks = getProperty("track-list").filter(track => track["type"] === "audio") + // header.subtitleTracks = getProperty("track-list").filter(track => track["type"] === "sub") + + if (playList.playlistView.count <= 1) { + setProperty("loop-file", "inf") + } + + setProperty("ab-loop-a", "no") + setProperty("ab-loop-b", "no") + + mpv.pause = loadTimePosition() !== 0 + position = loadTimePosition() + } + + onEndFile: { + if (reason === "error") { + if (playlistModel.rowCount() === 0) { + return + } + + // osd.message(i18n("Could not play: %1").arg(title)) + } + const nextFileRow = playlistModel.getPlayingVideo() + 1 + if (nextFileRow < playList.playlistView.count) { + const nextFile = playlistModel.getPath(nextFileRow) + playlistModel.setPlayingVideo(nextFileRow) + loadFile(nextFile) + } else { + // Last file in playlist + if (PlaylistSettings.repeat) { + playlistModel.setPlayingVideo(0) + loadFile(playlistModel.getPath(0)) + } + } + } + + onPauseChanged: { + if (pause) { + lockManager.setInhibitionOff() + } else { + lockManager.setInhibitionOn() + } + } + + Timer { + id: hideCursorTimer + + property double tx: mouseArea.mouseX + property double ty: mouseArea.mouseY + property int timeNotMoved: 0 + + running: rootWindow.isFullScreen() && mouseArea.containsMouse + repeat: true + interval: 50 + + onTriggered: { + if (mouseArea.mouseX === tx && mouseArea.mouseY === ty) { + if (timeNotMoved > 2000) { + app.hideCursor() + } + } else { + app.showCursor() + timeNotMoved = 0 + } + tx = mouseArea.mouseX + ty = mouseArea.mouseY + timeNotMoved += interval + } + } + + Connections { + target: mediaPlayer2Player + + function onPlaypause() { + actions.playPauseAction.trigger() + } + + function onPlay() { + control.pause = false + } + + function onPause() { + control.pause = true + } + + function onStop() { + control.position = 0 + control.pause = true + } + + function onNext() { + actions.playNextAction.trigger() + } + + function onPrevious() { + actions.playPreviousAction.trigger() + } + + function onSeek() { + control.command(["add", "time-pos", offset]) + } + + function onOpenUri() { + control.command(["add", "time-pos", offset]) + } + } + + Component.onCompleted: { + mediaPlayer2Player.mpv = control + } + + // Window move + DragHandler { + acceptedDevices: PointerDevice.GenericPointer + grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything + onActiveChanged: if (active) rootWindow.helper.startSystemMove(rootWindow) + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + + onDoubleClicked: { + if (mouse.button == Qt.LeftButton) + rootWindow.toggleFullScreen() + } + + onClicked: { + if (mouse.button == Qt.RightButton) + actions.playPauseAction.triggered() + } + + onPressed: { + playList.state = "hidden" + } + } + + DropArea { + id: dropArea + anchors.fill: parent + keys: ["text/uri-list"] + + property var acceptedSubtitleTypes: ["application/x-subrip", "text/x-ssa"] + + onDropped: { + if (acceptedSubtitleTypes.includes(app.mimeType(drop.urls[0]))) { + const subFile = drop.urls[0].replace("file://", "") + command(["sub-add", drop.urls[0], "select"]) + } + + if (app.mimeType(drop.urls[0]).startsWith("video/") || app.mimeType(drop.urls[0]).startsWith("audio/")) { + rootWindow.openFile(drop.urls[0], true) + } + } + } +} diff --git a/qml/PlayList.qml b/qml/PlayList.qml new file mode 100644 index 0000000..444d8d3 --- /dev/null +++ b/qml/PlayList.qml @@ -0,0 +1,155 @@ +/* + * SPDX-FileCopyrightText: 2020 George Florea Bănuș + * SPDX-FileCopyrightText: 2021 Reion Wong + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtGraphicalEffects 1.12 + +import FishUI 1.0 as FishUI +import mpv 1.0 + +Item { + id: control + height: mpv.height - FishUI.Units.largeSpacing * 6 + width: FishUI.Units.gridUnit * 16 + z: 9999 + x: parent.width + y: rootWindow.header.height + FishUI.Units.largeSpacing + state: "hidden" + + property string position: "right" + property alias scrollPositionTimer: scrollPositionTimer + property alias playlistView: playlistView + + Label { + anchors.centerIn: parent + z: 999 + text: qsTr("Playlist is empty") + visible: playlistView.count == 0 + } + + ScrollView { + id: playlistScrollView + + z: 20 + anchors.fill: parent + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + + ListView { + id: playlistView + model: mpv.playlistModel + spacing: 1 + delegate: PlayListItem { + onDoubleClicked: control.state = "hidden" + } + } + } + + Timer { + id: scrollPositionTimer + interval: 50 + running: true + repeat: true + + onTriggered: { + setPlayListScrollPosition() + scrollPositionTimer.stop() + } + } + + ShaderEffectSource { + id: shaderEffect + + anchors.fill: playlistScrollView + sourceItem: mpv + sourceRect: position === "right" + ? Qt.rect(mpv.width - control.width, mpv.y, control.width, control.height) + : Qt.rect(0, 0, control.width, control.height) + } + + FastBlur { + anchors.fill: shaderEffect + radius: 100 + source: shaderEffect + } + + Rectangle { + anchors.fill: parent + color: FishUI.Theme.backgroundColor + opacity: 0.7 + } + + states: [ + State { + name: "hidden" + PropertyChanges { target: control; x: position === "right" ? parent.width : -width } + PropertyChanges { target: control; visible: false } + }, + State { + name : "visible" + PropertyChanges { target: control; x: position === "right" ? parent.width - control.width - FishUI.Units.largeSpacing : 0 } + PropertyChanges { target: control; visible: true } + } + ] + + transitions: [ + Transition { + from: "visible" + to: "hidden" + + SequentialAnimation { + NumberAnimation { + target: control + property: "x" + duration: 150 + easing.type: Easing.InQuad + } + PropertyAction { + target: control + property: "visible" + value: false + } + } + }, + Transition { + from: "hidden" + to: "visible" + + SequentialAnimation { + PropertyAction { + target: control + property: "visible" + value: true + } + NumberAnimation { + target: control + property: "x" + duration: 150 + easing.type: Easing.OutQuad + } + } + } + ] + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Item { + width: control.width + height: control.height + + Rectangle { + anchors.fill: parent + radius: FishUI.Theme.bigRadius + } + } + } + + function setPlayListScrollPosition() { + playlistView.positionViewAtIndex(playlistView.model.playingVideo, ListView.Beginning) + } +} diff --git a/src/qml/PlayListItem.qml b/qml/PlayListItem.qml similarity index 63% rename from src/qml/PlayListItem.qml rename to qml/PlayListItem.qml index b42c2ed..a7a8c5c 100644 --- a/src/qml/PlayListItem.qml +++ b/qml/PlayListItem.qml @@ -10,17 +10,15 @@ import QtQuick.Layouts 1.12 import QtGraphicalEffects 1.12 import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 -import Haruna.Components 1.0 Item { id: root property bool isPlaying: model.isPlaying property string rowNumber: (index + 1).toString() - property var alpha: PlaylistSettings.overlayVideo ? 0.6 : 1 + property var alpha: 1 - height: label.font.pointSize * 3 + PlaylistSettings.rowHeight + height: label.font.pointSize * 3 + 10 width: ListView.view.width signal doubleClicked() @@ -31,15 +29,32 @@ Item { opacity: 0.5 } + Menu { + id: _itemMenu + + MenuItem { + text: qsTr("Play") + onTriggered: play() + } + + MenuItem { + text: qsTr("Remove from list") + onTriggered: mpv.playlistModel.remove(index) + } + } + MouseArea { anchors.fill: parent - acceptedButtons: Qt.LeftButton + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: { + if (mouse.button === Qt.RightButton) + _itemMenu.popup() + } + onDoubleClicked: { root.doubleClicked() - - mpv.playlistModel.setPlayingVideo(index) - mpv.loadFile(path, !isYouTubePlaylist) - mpv.pause = false + play() } } @@ -49,8 +64,8 @@ Item { Label { text: pad(root.rowNumber, playlistView.count.toString().length) - visible: PlaylistSettings.showRowNumber - font.pointSize: (window.isFullScreen() && playList.bigFont) + visible: true + font.pointSize: (rootWindow.isFullScreen() && playList.bigFont) ? FishUI.Units.gridUnit : FishUI.Units.gridUnit - 6 horizontalAlignment: Qt.AlignCenter @@ -63,41 +78,37 @@ Item { } } - FishUI.IconItem { - source: "media-playback-start" - width: FishUI.Units.iconSizes.small - height: FishUI.Units.iconSizes.small - visible: isPlaying - Layout.leftMargin: PlaylistSettings.showRowNumber ? 0 : FishUI.Units.largeSpacing - } - - LabelWithTooltip { + Label { id: label - toolTipFontSize: label.font.pointSize + 2 - horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignVCenter elide: Text.ElideRight - font.pointSize: (window.isFullScreen() && playList.bigFont) + font.pointSize: (rootWindow.isFullScreen() && playList.bigFont) ? FishUI.Units.gridUnit : FishUI.Units.gridUnit - 6 font.weight: Font.Normal color: isPlaying ? FishUI.Theme.highlightColor : FishUI.Theme.textColor - text: PlaylistSettings.showMediaTitle ? model.title : model.name + text: model.name layer.enabled: true Layout.fillWidth: true - Layout.leftMargin: PlaylistSettings.showRowNumber || isPlaying ? 0 : FishUI.Units.largeSpacing + // Layout.leftMargin: PlaylistSettings.showRowNumber || isPlaying ? 0 : FishUI.Units.largeSpacing } Label { text: model.duration visible: model.duration.length > 0 - font.pointSize: (window.isFullScreen() && playList.bigFont) + font.pointSize: (rootWindow.isFullScreen() && playList.bigFont) ? FishUI.Units.gridUnit : FishUI.Units.gridUnit - 6 horizontalAlignment: Qt.AlignCenter Layout.margins: FishUI.Units.largeSpacing } } + + function play() { + mpv.playlistModel.setPlayingVideo(index) + mpv.loadFile(path) + mpv.pause = false + } } diff --git a/qml/main.qml b/qml/main.qml new file mode 100644 index 0000000..63e1237 --- /dev/null +++ b/qml/main.qml @@ -0,0 +1,152 @@ +/* + * SPDX-FileCopyrightText: 2021 Reion Wong + * SPDX-FileCopyrightText: 2020 George Florea Bănuș + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtGraphicalEffects 1.12 +import Qt.labs.platform 1.0 as Platform + +import FishUI 1.0 as FishUI +import mpv 1.0 + +FishUI.Window { + id: rootWindow + width: 720 + height: 480 + minimumWidth: 700 + minimumHeight: 450 + color: FishUI.Theme.backgroundColor + + header.visible: mpv.mouseY >= 0 && mpv.mouseY <= header.height + headerBackground.color: FishUI.Theme.secondBackgroundColor + headerBackground.opacity: 0.95 + + contentTopMargin: 0 + + property int preFullScreenVisibility + + onVisibilityChanged: { + if (!rootWindow.isFullScreen()) { + preFullScreenVisibility = visibility + } + } + + headerItem: Item { + Label { + id: headerLabel + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: FishUI.Units.smallSpacing * 1.5 + anchors.leftMargin: FishUI.Units.largeSpacing + text: mpv.mediaTitle + color: "white" + z: 100 + } + + DropShadow { + anchors.fill: headerLabel + source: headerLabel + z: -1 + horizontalOffset: 1 + verticalOffset: 1 + radius: Math.round(6 * FishUI.Units.devicePixelRatio) + samples: radius * 2 + 1 + spread: 0.35 + color: Qt.rgba(0, 0, 0, 0.5) + opacity: 0.4 + visible: true + } + } + + Actions { + id: actions + } + + MpvVideo { + id: mpv + anchors.fill: parent + + Image { + id: _logo + anchors.centerIn: parent + width: 128 + height: 128 + source: "qrc:/images/cutefish-videoplayer.svg" + sourceSize: Qt.size(width, height) + visible: playList.playlistView.count === 0 + } + + Button { + visible: _logo.visible + anchors.top: _logo.bottom + anchors.topMargin: FishUI.Units.largeSpacing + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Open") + onClicked: fileDialog.open() + } + } + + Platform.FileDialog { + id: fileDialog + + property url location: "" + + folder: location + title: "Select file" + fileMode: Platform.FileDialog.OpenFile + + onAccepted: { + openFile(fileDialog.file.toString(), true) + // the timer scrolls the playlist to the playing file + // once the table view rows are loaded + playList.scrollPositionTimer.start() + mpv.focus = true + } + onRejected: mpv.focus = true + } + + PlayList { + id: playList + } + + Footer { + id: footer + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: mpv.bottom + } + + function openFile(path, startPlayback) { + mpv.playlistModel.addVideo(path) + // mpv.playlistModel.clear() + mpv.pause = !startPlayback + // mpv.playlistModel.getVideos(path) + mpv.loadFile(path) + } + + function isFullScreen() { + return rootWindow.visibility === Window.FullScreen + } + + function toggleFullScreen() { + if (!isFullScreen()) { + rootWindow.showFullScreen() + } else { + if (rootWindow.preFullScreenVisibility === Window.Windowed) { + rootWindow.showNormal() + } + if (rootWindow.preFullScreenVisibility === Window.Maximized) { + rootWindow.show() + rootWindow.showMaximized() + } + } + app.showCursor() + playList.scrollPositionTimer.start() + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 186b086..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -# -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -qt5_add_dbus_interface(screensaver_inhibit_SRCS ../org.freedesktop.ScreenSaver.xml screensaverdbusinterface) - -add_executable(cutefish-videoplayer) - -target_sources(cutefish-videoplayer - PRIVATE - application.cpp - global.cpp - haction.cpp - lockmanager.cpp - main.cpp - models/customcommandsmodel.cpp - models/subtitlesfoldersmodel.cpp - models/tracksmodel.cpp - models/playlistmodel.cpp - mpris2/mediaplayer2.cpp - mpris2/mediaplayer2player.cpp - mpvobject.cpp - qthelper.h - playlistitem.cpp - thumbnailimageprovider.cpp - track.cpp - worker.cpp - qml.qrc - ${screensaver_inhibit_SRCS} -) - -kconfig_add_kcfg_files(cutefish-videoplayer GENERATE_MOC settings/audiosettings.kcfgc) -kconfig_add_kcfg_files(cutefish-videoplayer GENERATE_MOC settings/generalsettings.kcfgc) -kconfig_add_kcfg_files(cutefish-videoplayer GENERATE_MOC settings/mousesettings.kcfgc) -kconfig_add_kcfg_files(cutefish-videoplayer GENERATE_MOC settings/playbacksettings.kcfgc) -kconfig_add_kcfg_files(cutefish-videoplayer GENERATE_MOC settings/playlistsettings.kcfgc) -kconfig_add_kcfg_files(cutefish-videoplayer GENERATE_MOC settings/subtitlessettings.kcfgc) -kconfig_add_kcfg_files(cutefish-videoplayer GENERATE_MOC settings/videosettings.kcfgc) - -target_include_directories(cutefish-videoplayer PRIVATE models mpris2) - -target_compile_definitions(cutefish-videoplayer PRIVATE $<$,$>:QT_QML_DEBUG>) - -target_link_libraries(cutefish-videoplayer PRIVATE - Qt5::Core - Qt5::DBus - Qt5::Qml - Qt5::Quick - Qt5::QuickControls2 - - KF5::ConfigCore - KF5::ConfigGui - KF5::CoreAddons - KF5::DocTools - KF5::FileMetaData - KF5::KIOCore - KF5::KIOFileWidgets - KF5::KIOWidgets - KF5::KIONTLM -# KF5::Kirigami2 - KF5::XmlGui - - Libmpv::Libmpv -) - -install(TARGETS cutefish-videoplayer DESTINATION ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/_debug.h b/src/_debug.h deleted file mode 100644 index bd520b2..0000000 --- a/src/_debug.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#ifndef __DEBUG_H -#define __DEBUG_H - -#include - -#define DEBUG qDebug() << Q_FUNC_INFO << ':' - -#endif - diff --git a/src/application.cpp b/src/application.cpp index f88a8b1..f1ef915 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,40 +1,26 @@ /* + * SPDX-FileCopyrightText: 2021 Reion Wong * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * SPDX-FileCopyrightText: 2021 Reion Wong * * SPDX-License-Identifier: GPL-3.0-or-later */ -#include "_debug.h" #include "application.h" -#include "audiosettings.h" -#include "customcommandsmodel.h" -#include "generalsettings.h" -#include "global.h" -#include "haction.h" -#include "lockmanager.h" -#include "mediaplayer2.h" -#include "mediaplayer2player.h" -#include "mousesettings.h" #include "mpvobject.h" -#include "playbacksettings.h" -#include "playlistitem.h" #include "playlistmodel.h" -#include "playlistsettings.h" -#include "subtitlesfoldersmodel.h" -#include "subtitlessettings.h" -#include "thumbnailimageprovider.h" +#include "playlistitem.h" #include "tracksmodel.h" -#include "videosettings.h" -#include "worker.h" - -#include +#include "track.h" +#include "lockmanager.h" +#include "mpris2/mediaplayer2.h" +#include "mpris2/mediaplayer2player.h" #include #include #include #include #include +#include #include #include #include @@ -44,69 +30,46 @@ #include #include #include -#include #include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include static QApplication *createApplication(int &argc, char **argv, const QString &applicationName) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QApplication::setOrganizationName("georgefb"); + QApplication::setOrganizationName("cutefishos"); QApplication::setApplicationName(applicationName); - QApplication::setOrganizationDomain("georgefb.com"); + QApplication::setOrganizationDomain("cutefishos.com"); QApplication::setApplicationDisplayName("Video Player"); - QApplication::setApplicationVersion(Application::version()); - QApplication::setWindowIcon(QIcon::fromTheme("org.kde.haruna")); + QApplication::setWindowIcon(QIcon::fromTheme("cutefish-videoplayer")); QApplication *app = new QApplication(argc, argv); return app; } Application::Application(int &argc, char **argv, const QString &applicationName) : m_app(createApplication(argc, argv, applicationName)) - , m_collection(this) { - m_config = KSharedConfig::openConfig(Global::instance()->appConfigFilePath()); - m_shortcuts = new KConfigGroup(m_config, "Shortcuts"); - m_schemes = new KColorSchemeManager(this); - m_systemDefaultStyle = m_app->style()->objectName(); - - setupUserActions(); - // register mpris dbus service - QString mspris2Name(QStringLiteral("org.mpris.MediaPlayer2.haruna")); + QString mspris2Name(QStringLiteral("org.mpris.MediaPlayer2.cutefish.videoplayer")); QDBusConnection::sessionBus().registerService(mspris2Name); QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/mpris/MediaPlayer2"), this, QDBusConnection::ExportAdaptors); // org.mpris.MediaPlayer2 mpris2 interface new MediaPlayer2(this); - if (GeneralSettings::guiStyle() != QStringLiteral("System")) { - QApplication::setStyle(GeneralSettings::guiStyle()); - } - // Qt sets the locale in the QGuiApplication constructor, but libmpv // requires the LC_NUMERIC category to be set to "C", so change it back. std::setlocale(LC_NUMERIC, "C"); - setupWorkerThread(); - setupAboutData(); - setupCommandLineParser(); + m_engine = new QQmlApplicationEngine(this); registerQmlTypes(); - setupQmlSettingsTypes(); + setupQmlContextProperties(); - m_engine = new QQmlApplicationEngine(this); const QUrl url(QStringLiteral("qrc:/qml/main.qml")); auto onObjectCreated = [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) { @@ -116,14 +79,8 @@ Application::Application(int &argc, char **argv, const QString &applicationName) QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated, m_app, onObjectCreated, Qt::QueuedConnection); m_engine->addImportPath("qrc:/qml"); - m_engine->addImageProvider("thumbnail", new ThumbnailImageProvider()); - setupQmlContextProperties(); - m_engine->load(url); -} -Application::~Application() -{ - delete m_engine; + m_engine->load(url); } int Application::run() @@ -131,171 +88,11 @@ int Application::run() return m_app->exec(); } -void Application::setupWorkerThread() -{ - auto worker = Worker::instance(); - auto thread = new QThread(); - worker->moveToThread(thread); - QObject::connect(thread, &QThread::finished, - worker, &Worker::deleteLater); - QObject::connect(thread, &QThread::finished, - thread, &QThread::deleteLater); - thread->start(); -} - -void Application::setupAboutData() -{ - m_aboutData = KAboutData(QStringLiteral("haruna"), - tr("Video Player"), - Application::version()); - m_aboutData.setShortDescription(tr("A configurable video player.")); - m_aboutData.setLicense(KAboutLicense::GPL_V3); - m_aboutData.setCopyrightStatement(tr("(c) 2019-2021")); - m_aboutData.setHomepage(QStringLiteral("https://invent.kde.org/multimedia/haruna")); - m_aboutData.setBugAddress(QStringLiteral("https://bugs.kde.org").toUtf8()); - m_aboutData.setDesktopFileName("org.kde.haruna"); - - m_aboutData.addAuthor(tr("George Florea Bănuș"), - tr("Developer"), - QStringLiteral("georgefb899@gmail.com"), - QStringLiteral("https://georgefb.com")); - - KAboutData::setApplicationData(m_aboutData); -} - -void Application::setupCommandLineParser() -{ - QCommandLineParser parser; - m_aboutData.setupCommandLine(&parser); - parser.addPositionalArgument(QStringLiteral("file"), tr("File to open")); - parser.process(*m_app); - m_aboutData.processCommandLine(&parser); - - for (auto i = 0; i < parser.positionalArguments().size(); ++i) { - addArgument(i, parser.positionalArguments().at(i)); - } -} - -void Application::registerQmlTypes() -{ - qmlRegisterType("mpv", 1, 0, "MpvObject"); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType("KFileMetaData::PropertyMap"); -} - -void Application::setupQmlSettingsTypes() -{ - auto audioProvider = [](QQmlEngine *, QJSEngine *) -> QObject * { return AudioSettings::self(); }; - qmlRegisterSingletonType("org.kde.haruna", 1, 0, "AudioSettings", audioProvider); - - auto generalProvider = [](QQmlEngine *, QJSEngine *) -> QObject * { return GeneralSettings::self(); }; - qmlRegisterSingletonType("org.kde.haruna", 1, 0, "GeneralSettings", generalProvider); - - auto mouseProvider = [](QQmlEngine *, QJSEngine *) -> QObject * { return MouseSettings::self(); }; - qmlRegisterSingletonType("org.kde.haruna", 1, 0, "MouseSettings", mouseProvider); - - auto playbackProvider = [](QQmlEngine *, QJSEngine *) -> QObject * { return PlaybackSettings::self(); }; - qmlRegisterSingletonType("org.kde.haruna", 1, 0, "PlaybackSettings", playbackProvider); - - auto playlistProvider = [](QQmlEngine *, QJSEngine *) -> QObject * { return PlaylistSettings::self(); }; - qmlRegisterSingletonType("org.kde.haruna", 1, 0, "PlaylistSettings", playlistProvider); - - auto subtitlesProvider = [](QQmlEngine *, QJSEngine *) -> QObject * { return SubtitlesSettings::self(); }; - qmlRegisterSingletonType("org.kde.haruna", 1, 0, "SubtitlesSettings", subtitlesProvider); - - auto videoProvider = [](QQmlEngine *, QJSEngine *) -> QObject * { return VideoSettings::self(); }; - qmlRegisterSingletonType("org.kde.haruna", 1, 0, "VideoSettings", videoProvider); -} - -void Application::setupQmlContextProperties() -{ - std::unique_ptr lockManager = std::make_unique(); - std::unique_ptr subsFoldersModel = std::make_unique(); - - m_engine->rootContext()->setContextProperty(QStringLiteral("app"), this); - qmlRegisterUncreatableType("Application", 1, 0, "Application", - QStringLiteral("Application should not be created in QML")); - - m_engine->rootContext()->setContextProperty(QStringLiteral("mediaPlayer2Player"), new MediaPlayer2Player(this)); - - m_engine->rootContext()->setContextProperty(QStringLiteral("lockManager"), lockManager.release()); - qmlRegisterUncreatableType("LockManager", 1, 0, "LockManager", - QStringLiteral("LockManager should not be created in QML")); - - m_engine->rootContext()->setContextProperty(QStringLiteral("subsFoldersModel"), subsFoldersModel.release()); - - auto customCommandsModel = new CustomCommandsModel(); - m_engine->rootContext()->setContextProperty(QStringLiteral("customCommandsModel"), customCommandsModel); - auto proxyCustomCommandsModel = new ProxyCustomCommandsModel(); - proxyCustomCommandsModel->setSourceModel(customCommandsModel); - m_engine->rootContext()->setContextProperty(QStringLiteral("proxyCustomCommandsModel"), proxyCustomCommandsModel); -} - -QUrl Application::configFilePath() -{ - auto configPath = QStandardPaths::writableLocation(m_config->locationType()); - auto configFilePath = configPath.append(QStringLiteral("/")).append(m_config->name()); - QUrl url(configFilePath); - url.setScheme("file"); - return url; -} - -QUrl Application::configFolderPath() -{ - auto configPath = QStandardPaths::writableLocation(m_config->locationType()); - auto configFilePath = configPath.append(QStringLiteral("/")).append(m_config->name()); - QFileInfo fileInfo(configFilePath); - QUrl url(fileInfo.absolutePath()); - url.setScheme("file"); - return url; -} - -QString Application::version() -{ - return QStringLiteral("0.6.3"); -} - -bool Application::hasYoutubeDl() -{ - return !QStandardPaths::findExecutable(QStringLiteral("youtube-dl")).isEmpty(); - -} - -QUrl Application::parentUrl(const QString &path) -{ - QUrl url(path); - if (!url.isValid()) { - return QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); - } - QFileInfo fileInfo; - if (url.isLocalFile()) { - fileInfo.setFile(url.toLocalFile()); - } else { - fileInfo.setFile(url.toString()); - } - QUrl parentFolderUrl(fileInfo.absolutePath()); - parentFolderUrl.setScheme("file"); - - return parentFolderUrl; -} - -QUrl Application::pathToUrl(const QString &path) -{ - QUrl url(path); - if (!url.isValid()) { - return QUrl(); - } - url.setScheme("file"); - - return url; -} - -bool Application::isYoutubePlaylist(const QString &path) +QString Application::mimeType(const QString &file) { - return path.contains("youtube.com/playlist?list"); + QMimeDatabase db; + QMimeType mime = db.mimeTypeForFile(file); + return mime.name(); } QString Application::formatTime(const double time) @@ -305,16 +102,6 @@ QString Application::formatTime(const double time) return formattedTime; } -void Application::hideCursor() -{ - QApplication::setOverrideCursor(Qt::BlankCursor); -} - -void Application::showCursor() -{ - QApplication::setOverrideCursor(Qt::ArrowCursor); -} - QString Application::argument(int key) { return m_args[key]; @@ -325,569 +112,48 @@ void Application::addArgument(int key, const QString &value) m_args.insert(key, value); } -QAction *Application::action(const QString &name) -{ - auto resultAction = m_collection.action(name); - - if (!resultAction) { - setupActions(name); - resultAction = m_collection.action(name); - } - - return resultAction; -} - -QString Application::getFileContent(const QString &file) -{ - QFile f(file); - f.open(QIODevice::ReadOnly); - QString content = f.readAll(); - f.close(); - return content; -} - -QString Application::mimeType(const QString &file) -{ - QMimeDatabase db; - QMimeType mime = db.mimeTypeForFile(file); - return mime.name(); -} - -QStringList Application::availableGuiStyles() -{ - return QStyleFactory::keys(); -} - -void Application::setGuiStyle(const QString &style) -{ - if (style == "Default") { - QApplication::setStyle(m_systemDefaultStyle); - return; - } - QApplication::setStyle(style); -} - -QAbstractItemModel *Application::colorSchemesModel() +void Application::hideCursor() { - return m_schemes->model(); + QApplication::setOverrideCursor(Qt::BlankCursor); } -void Application::activateColorScheme(const QString &name) +void Application::showCursor() { - m_schemes->activateScheme(m_schemes->indexForScheme(name)); + QApplication::setOverrideCursor(Qt::ArrowCursor); } -void Application::configureShortcuts(const QString &name) +void Application::setupCommandLineParser() { - KShortcutsDialog dlg(KShortcutsEditor::ApplicationAction, KShortcutsEditor::LetterShortcutsAllowed, nullptr); - connect(&dlg, &KShortcutsDialog::accepted, this, [ = ](){ - m_collection.writeSettings(m_shortcuts); - m_config->sync(); - }); - - if (!name.isEmpty()) { - auto searchLine = dlg.findChild(); - if (searchLine != nullptr) { - searchLine->setText(name); - } - } - - dlg.setModal(true); - dlg.addCollection(&m_collection); - dlg.configure(false); -} + QCommandLineParser parser; + parser.addPositionalArgument(QStringLiteral("file"), tr("File to open")); + parser.process(*m_app); -void Application::aboutApplication() -{ - static QPointer dialog; - if (!dialog) { - dialog = new KAboutApplicationDialog(KAboutData::applicationData(), nullptr); - dialog->setAttribute(Qt::WA_DeleteOnClose); + for (auto i = 0; i < parser.positionalArguments().size(); ++i) { + addArgument(i, parser.positionalArguments().at(i)); } - dialog->show(); } -void Application::setupActions(const QString &actionName) +void Application::setupQmlContextProperties() { - if (actionName == QStringLiteral("screenshot")) { - auto action = new HAction(); - action->setText(tr("Screenshot")); - action->setIcon(QIcon::fromTheme("image-x-generic")); - m_collection.setDefaultShortcut(action, Qt::Key_S); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("file_quit")) { - auto action = new HAction(); - action->setText(tr("Quit")); - action->setIcon(QIcon::fromTheme("application-exit")); - connect(action, &QAction::triggered, m_app, &QApplication::quit); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_Q); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("options_configure_keybinding")) { - auto action = new HAction(); - action->setText(tr("Configure Keyboard Shortcuts")); - action->setIcon(QIcon::fromTheme("configure-shortcuts")); - connect(action, &QAction::triggered, this, [=]() { configureShortcuts(); }); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_S); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("configure")) { - auto action = new HAction(); - action->setText(tr("Configure")); - action->setIcon(QIcon::fromTheme("configure")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_Comma); - m_collection.addAction(actionName, action); - } - - if (actionName == QStringLiteral("togglePlaylist")) { - auto action = new HAction(); - action->setText(tr("Playlist")); - action->setIcon(QIcon::fromTheme("view-media-playlist")); - m_collection.setDefaultShortcut(action, Qt::Key_P); - m_collection.addAction(actionName, action); - } - - if (actionName == QStringLiteral("openContextMenu")) { - auto action = new HAction(); - action->setText(tr("Open Context Menu")); - action->setIcon(QIcon::fromTheme("application-menu")); - m_collection.setDefaultShortcut(action, Qt::Key_Menu); - m_collection.addAction(actionName, action); - } - - if (actionName == QStringLiteral("toggleFullscreen")) { - auto action = new HAction(); - action->setText(tr("Toggle Fullscreen")); - action->setIcon(QIcon::fromTheme("view-fullscreen")); - m_collection.setDefaultShortcut(action, Qt::Key_F); - m_collection.addAction(actionName, action); - } - - if (actionName == QStringLiteral("openFile")) { - auto action = new HAction(); - action->setText(tr("Open File")); - action->setIcon(QIcon::fromTheme("folder-videos")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_O); - m_collection.addAction(actionName, action); - } - - if (actionName == QStringLiteral("openUrl")) { - auto action = new HAction(); - action->setText(tr("Open Url")); - action->setIcon(QIcon::fromTheme("internet-services")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_O); - m_collection.addAction(actionName, action); - } - - if (actionName == QStringLiteral("aboutHaruna")) { - auto action = new HAction(); - action->setText(tr("About Haruna")); - action->setIcon(QIcon::fromTheme("help-about")); - m_collection.setDefaultShortcut(action, Qt::Key_F1); - m_collection.addAction(actionName, action); - connect(action, &QAction::triggered, this, &Application::aboutApplication); - } - - // mpv actions - if (actionName == QStringLiteral("contrastUp")) { - auto action = new HAction(); - action->setText(tr("Contrast Up")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::Key_1); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("contrastDown")) { - auto action = new HAction(); - action->setText(tr("Contrast Down")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::Key_2); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("contrastReset")) { - auto action = new HAction(); - action->setText(tr("Contrast Reset")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_1); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("brightnessUp")) { - auto action = new HAction(); - action->setText(tr("Brightness Up")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::Key_3); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("brightnessDown")) { - auto action = new HAction(); - action->setText(tr("Brightness Down")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::Key_4); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("brightnessReset")) { - auto action = new HAction(); - action->setText(tr("Brightness Reset")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_3); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("gammaUp")) { - auto action = new HAction(); - action->setText(tr("Gamma Up")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::Key_5); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("gammaDown")) { - auto action = new HAction(); - action->setText(tr("Gamma Down")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::Key_6); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("gammaReset")) { - auto action = new HAction(); - action->setText(tr("Gamma Reset")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_5); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("saturationUp")) { - auto action = new HAction(); - action->setText(tr("Saturation Up")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::Key_7); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("saturationDown")) { - auto action = new HAction(); - action->setText(tr("Saturation Down")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::Key_8); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("saturationReset")) { - auto action = new HAction(); - action->setText(tr("Saturation Reset")); - action->setIcon(QIcon::fromTheme("contrast")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_7); - m_collection.addAction(actionName, action); - } - - if (actionName == QStringLiteral("playNext")) { - auto action = new HAction(); - action->setText(tr("Play Next")); - action->setIcon(QIcon::fromTheme("media-skip-forward")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_Period); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("playPrevious")) { - auto action = new HAction(); - action->setText(tr("Play Previous")); - action->setIcon(QIcon::fromTheme("media-skip-backward")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_Comma); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("volumeUp")) { - auto action = new HAction(); - action->setText(tr("Volume Up")); - action->setIcon(QIcon::fromTheme("audio-volume-high")); - m_collection.setDefaultShortcut(action, Qt::Key_9); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("volumeDown")) { - auto action = new HAction(); - action->setText(tr("Volume Down")); - action->setIcon(QIcon::fromTheme("audio-volume-low")); - m_collection.setDefaultShortcut(action, Qt::Key_0); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("mute")) { - auto action = new HAction(); - action->setText(tr("Mute")); - action->setIcon(QIcon::fromTheme("player-volume")); - m_collection.setDefaultShortcut(action, Qt::Key_M); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekForwardSmall")) { - auto action = new HAction(); - action->setText(tr("Seek Small Step Forward")); - action->setIcon(QIcon::fromTheme("media-seek-forward")); - m_collection.setDefaultShortcut(action, Qt::Key_Right); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekBackwardSmall")) { - auto action = new HAction(); - action->setText(tr("Seek Small Step Backward")); - action->setIcon(QIcon::fromTheme("media-seek-backward")); - m_collection.setDefaultShortcut(action, Qt::Key_Left); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekForwardMedium")) { - auto action = new HAction(); - action->setText(tr("Seek Medium Step Forward")); - action->setIcon(QIcon::fromTheme("media-seek-forward")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_Right); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekBackwardMedium")) { - auto action = new HAction(); - action->setText(tr("Seek Medium Step Backward")); - action->setIcon(QIcon::fromTheme("media-seek-backward")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_Left); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekForwardBig")) { - auto action = new HAction(); - action->setText(tr("Seek Big Step Forward")); - action->setIcon(QIcon::fromTheme("media-seek-forward")); - m_collection.setDefaultShortcut(action, Qt::Key_Up); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekBackwardBig")) { - auto action = new HAction(); - action->setText(tr("Seek Big Step Backward")); - action->setIcon(QIcon::fromTheme("media-seek-backward")); - m_collection.setDefaultShortcut(action, Qt::Key_Down); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekPreviousChapter")) { - auto action = new HAction(); - action->setText(tr("Seek Previous Chapter")); - action->setIcon(QIcon::fromTheme("media-seek-backward")); - m_collection.setDefaultShortcut(action, Qt::Key_PageDown); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekNextChapter")) { - auto action = new HAction(); - action->setText(tr("Seek Next Chapter")); - action->setIcon(QIcon::fromTheme("media-seek-forward")); - m_collection.setDefaultShortcut(action, Qt::Key_PageUp); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekNextSubtitle")) { - auto action = new HAction(); - action->setText(tr("Seek To Next Subtitle")); - action->setIcon(QIcon::fromTheme("media-seek-forward")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_Right); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("seekPreviousSubtitle")) { - auto action = new HAction(); - action->setText(tr("Seek To Previous Subtitle")); - action->setIcon(QIcon::fromTheme("media-seek-backward")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_Left); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("frameStep")) { - auto action = new HAction(); - action->setText(tr("Move one frame forward, then pause")); - m_collection.setDefaultShortcut(action, Qt::Key_Period); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("frameBackStep")) { - auto action = new HAction(); - action->setText(tr("Move one frame backward, then pause")); - m_collection.setDefaultShortcut(action, Qt::Key_Comma); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("increasePlayBackSpeed")) { - auto action = new HAction(); - action->setText(tr("Playback speed increase")); - m_collection.setDefaultShortcut(action, Qt::Key_BracketRight); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("decreasePlayBackSpeed")) { - auto action = new HAction(); - action->setText(tr("Playback speed decrease")); - m_collection.setDefaultShortcut(action, Qt::Key_BracketLeft); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("resetPlayBackSpeed")) { - auto action = new HAction(); - action->setText(tr("Playback speed reset")); - m_collection.setDefaultShortcut(action, Qt::Key_Backspace); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("subtitleQuicken")) { - auto action = new HAction(); - action->setText(tr("Subtitle Quicken")); - m_collection.setDefaultShortcut(action, Qt::Key_Z); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("subtitleDelay")) { - auto action = new HAction(); - action->setText(tr("Subtitle Delay")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_Z); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("subtitleToggle")) { - auto action = new HAction(); - action->setText(tr("Subtitle Toggle")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_S); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("audioCycleUp")) { - auto action = new HAction(); - action->setText(tr("Cycle Audio Up")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_3); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("audioCycleDown")) { - auto action = new HAction(); - action->setText(tr("Cycle Audio Down")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_2); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("subtitleCycleUp")) { - auto action = new HAction(); - action->setText(tr("Cycle Subtitle Up")); - m_collection.setDefaultShortcut(action, Qt::Key_J); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("subtitleCycleDown")) { - auto action = new HAction(); - action->setText(tr("Cycle Subtitle Down")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_J); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("zoomIn")) { - auto action = new HAction(); - action->setText(tr("Zoom In")); - action->setIcon(QIcon::fromTheme("zoom-in")); - m_collection.setDefaultShortcut(action, Qt::ALT + Qt::Key_Plus); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("zoomOut")) { - auto action = new HAction(); - action->setText(tr("Zoom Out")); - action->setIcon(QIcon::fromTheme("zoom-out")); - m_collection.setDefaultShortcut(action, Qt::ALT + Qt::Key_Minus); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("zoomReset")) { - auto action = new HAction(); - action->setText(tr("Zoom Reset")); - action->setIcon(QIcon::fromTheme("zoom-original")); - m_collection.setDefaultShortcut(action, Qt::ALT + Qt::Key_Backspace); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("videoPanXLeft")) { - auto action = new HAction(); - action->setText(tr("Video pan x left")); - m_collection.setDefaultShortcut(action, Qt::ALT + Qt::Key_Left); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("videoPanXRight")) { - auto action = new HAction(); - action->setText(tr("Video pan x right")); - m_collection.setDefaultShortcut(action, Qt::ALT + Qt::Key_Right); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("videoPanYUp")) { - auto action = new HAction(); - action->setText(tr("Video pan y up")); - m_collection.setDefaultShortcut(action, Qt::ALT + Qt::Key_Up); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("videoPanYDown")) { - auto action = new HAction(); - action->setText(tr("Video pan y down")); - m_collection.setDefaultShortcut(action, Qt::ALT + Qt::Key_Down); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("toggleMenuBar")) { - auto action = new HAction(); - action->setText(tr("Toggle Menu Bar")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_M); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("toggleHeader")) { - auto action = new HAction(); - action->setText(tr("Toggle Header")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_H); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("setLoop")) { - auto action = new HAction(); - action->setText(tr("Set Loop")); - m_collection.setDefaultShortcut(action, Qt::Key_L); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("increaseSubtitleFontSize")) { - auto action = new HAction(); - action->setText(tr("Increase Subtitle Font Size")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_Z); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("decreaseSubtitleFontSize")) { - auto action = new HAction(); - action->setText(tr("Decrease Subtitle Font Size")); - m_collection.setDefaultShortcut(action, Qt::CTRL + Qt::Key_X); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("subtitlePositionUp")) { - auto action = new HAction(); - action->setText(tr("Move Subtitle Up")); - m_collection.setDefaultShortcut(action, Qt::Key_R); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("subtitlePositionDown")) { - auto action = new HAction(); - action->setText(tr("Move Subtitle Down")); - m_collection.setDefaultShortcut(action, Qt::SHIFT + Qt::Key_R); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("toggleDeinterlacing")) { - auto action = new HAction(); - action->setText(tr("Toggle deinterlacing")); - m_collection.setDefaultShortcut(action, Qt::Key_D); - m_collection.addAction(actionName, action); - } - if (actionName == QStringLiteral("exitFullscreen")) { - auto action = new HAction(); - action->setText(tr("Exit Fullscreen")); - m_collection.setDefaultShortcut(action, Qt::Key_Escape); - m_collection.addAction(actionName, action); - } - m_collection.readSettings(m_shortcuts); -} + // C++ 14 + std::unique_ptr lockManager = std::make_unique(); -void Application::createUserAction(const QString &text) -{ - KSharedConfig::Ptr m_customCommandsConfig; - QString ccConfig = Global::instance()->appConfigFilePath(Global::ConfigFile::CustomCommands); - m_customCommandsConfig = KSharedConfig::openConfig(ccConfig, KConfig::SimpleConfig); - int counter = m_customCommandsConfig->group(QString()).readEntry("Counter", 0); - const QString &name = QString("Command_%1").arg(counter); + m_engine->rootContext()->setContextProperty(QStringLiteral("app"), this); + qmlRegisterUncreatableType("Application", 1, 0, "Application", + QStringLiteral("Application should not be created in QML")); - auto action = new HAction(); - action->setText(text); - m_collection.addAction(name, action); - m_collection.readSettings(m_shortcuts); -} + m_engine->rootContext()->setContextProperty(QStringLiteral("lockManager"), lockManager.release()); + qmlRegisterUncreatableType("LockManager", 1, 0, "LockManager", + QStringLiteral("LockManager should not be created in QML")); -void Application::openDocs(const QString &page) -{ - QDesktopServices::openUrl(QUrl(page)); + m_engine->rootContext()->setContextProperty(QStringLiteral("mediaPlayer2Player"), new MediaPlayer2Player(this)); } -void Application::setupUserActions() +void Application::registerQmlTypes() { - KSharedConfig::Ptr m_customCommandsConfig; - QString ccConfig = Global::instance()->appConfigFilePath(Global::ConfigFile::CustomCommands); - m_customCommandsConfig = KSharedConfig::openConfig(ccConfig, KConfig::SimpleConfig); - QStringList groups = m_customCommandsConfig->groupList(); - for (const QString &_group : qAsConst((groups))) { - auto configGroup = m_customCommandsConfig->group(_group); - QString command = configGroup.readEntry("Command", QString()); - - if (configGroup.readEntry("Type", QString()) == "shortcut") { - auto action = new HAction(); - action->setText(command); - m_collection.addAction(_group, action); - } - } - m_collection.readSettings(m_shortcuts); + qmlRegisterType("mpv", 1, 0, "MpvObject"); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); } diff --git a/src/application.h b/src/application.h index 215cde5..517e561 100644 --- a/src/application.h +++ b/src/application.h @@ -1,4 +1,5 @@ /* + * SPDX-FileCopyrightText: 2021 Reion Wong * SPDX-FileCopyrightText: 2020 George Florea Bănuș * * SPDX-License-Identifier: GPL-3.0-or-later @@ -8,75 +9,37 @@ #define APPLICATION_H #include -#include -#include #include +#include #include - -#include -#include -#include - -class KActionCollection; -class KConfigDialog; -class KColorSchemeManager; -class QAction; +#include class Application : public QObject { Q_OBJECT - Q_PROPERTY(QAbstractItemModel* colorSchemesModel READ colorSchemesModel CONSTANT) - Q_PROPERTY(QUrl configFilePath READ configFilePath CONSTANT) - Q_PROPERTY(QUrl configFolderPath READ configFolderPath CONSTANT) public: - explicit Application(int &argc, char **argv, const QString &applicationName); - ~Application(); + Application(int &argc, char **argv, const QString &applicationName); int run(); - QUrl configFilePath(); - QUrl configFolderPath(); - Q_INVOKABLE QUrl parentUrl(const QString &path); - Q_INVOKABLE QUrl pathToUrl(const QString &path); + + Q_INVOKABLE QString mimeType(const QString &file); + Q_INVOKABLE static QString formatTime(const double time); Q_INVOKABLE QString argument(int key); Q_INVOKABLE void addArgument(int key, const QString &value); - Q_INVOKABLE QAction *action(const QString &name); - Q_INVOKABLE QString getFileContent(const QString &file); - Q_INVOKABLE QString mimeType(const QString &file); - Q_INVOKABLE QStringList availableGuiStyles(); - Q_INVOKABLE void setGuiStyle(const QString &style); - Q_INVOKABLE void activateColorScheme(const QString &name); - Q_INVOKABLE void configureShortcuts(const QString &name = QString()); - Q_INVOKABLE void createUserAction(const QString &text); - Q_INVOKABLE void openDocs(const QString &page); - static QString version(); - Q_INVOKABLE static bool hasYoutubeDl(); - Q_INVOKABLE static bool isYoutubePlaylist(const QString &path); - Q_INVOKABLE static QString formatTime(const double time); Q_INVOKABLE static void hideCursor(); Q_INVOKABLE static void showCursor(); private: - void setupWorkerThread(); - void setupAboutData(); void setupCommandLineParser(); - void registerQmlTypes(); - void setupQmlSettingsTypes(); void setupQmlContextProperties(); - void aboutApplication(); - void setupActions(const QString &actionName); - void setupUserActions(); - QAbstractItemModel *colorSchemesModel(); + void registerQmlTypes(); + +private: QApplication *m_app; QQmlApplicationEngine *m_engine; - KAboutData m_aboutData; - KActionCollection m_collection; - KSharedConfig::Ptr m_config; - KConfigGroup *m_shortcuts; QMap m_args; - KColorSchemeManager *m_schemes; - QString m_systemDefaultStyle; }; #endif // APPLICATION_H diff --git a/src/global.cpp b/src/global.cpp deleted file mode 100644 index f5af7a9..0000000 --- a/src/global.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "global.h" - -#include "_debug.h" - -#include - -Global* Global::sm_instance = nullptr; - -Global *Global::instance() -{ - if (!sm_instance) { - sm_instance = new Global(); - } - return sm_instance; -} - -Global::Global() -{ - m_config = KSharedConfig::openConfig("haruna/haruna.conf"); - m_ccConfig = KSharedConfig::openConfig("haruna/haruna-custom-commands.conf"); -} - -const QString Global::systemConfigPath() -{ - return QStandardPaths::writableLocation(m_config->locationType()).append("/"); -} - -const QString Global::appConfigDirPath() -{ - QFileInfo configFile(QString(systemConfigPath()).append(m_config->name())); - return configFile.absolutePath(); -} - -const QString Global::appConfigFilePath(ConfigFile configFile) -{ - switch (configFile) { - case ConfigFile::Main: - return QString(systemConfigPath()).append(m_config->name()); - case ConfigFile::CustomCommands: - return QString(systemConfigPath()).append(m_ccConfig->name()); - } -} - diff --git a/src/global.h b/src/global.h deleted file mode 100644 index c1a1409..0000000 --- a/src/global.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef GLOBALS_H -#define GLOBALS_H - -#include -#include - -class Global -{ -public: - Global(); - - enum ConfigFile { - Main, - CustomCommands - }; - - const QString systemConfigPath(); - const QString appConfigDirPath(); - const QString appConfigFilePath(ConfigFile configFile = ConfigFile::Main); - - static Global *instance(); - -private: - KSharedConfig::Ptr m_config; - KSharedConfig::Ptr m_ccConfig; - static Global *sm_instance; -}; - -#endif // GLOBALS_H diff --git a/src/haction.cpp b/src/haction.cpp deleted file mode 100644 index 8c51574..0000000 --- a/src/haction.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include "haction.h" - -#include - -HAction::HAction(QObject *parent) : QAction(parent) -{ - -} - -QString HAction::shortcutName() -{ - return shortcut().toString(); -} - -QString HAction::iconName() -{ - return icon().name(); -} diff --git a/src/haction.h b/src/haction.h deleted file mode 100644 index 5ceed8d..0000000 --- a/src/haction.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#ifndef HACTION_H -#define HACTION_H - -#include - -/* - * Needed because QAction fails to trigger for non english languages - */ - -class HAction : public QAction -{ - Q_OBJECT - Q_PROPERTY(QString shortcutName READ shortcutName NOTIFY changed) -public: - explicit HAction(QObject *parent = nullptr); - -public slots: - QString shortcutName(); - QString iconName(); - -}; - -#endif // HACTION_H diff --git a/src/main.cpp b/src/main.cpp index d27840e..ebf3885 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,12 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - #include "application.h" int main(int argc, char *argv[]) { - Application app(argc, argv, "Haruna"); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif + + Application app(argc, argv, "cutefish-videoplayer"); return app.run(); } - diff --git a/src/models/customcommandsmodel.cpp b/src/models/customcommandsmodel.cpp deleted file mode 100644 index 906442c..0000000 --- a/src/models/customcommandsmodel.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "customcommandsmodel.h" - -#include "_debug.h" - -#include -#include - -CustomCommandsModel::CustomCommandsModel(QObject *parent) - : QAbstractListModel(parent) -{ - QString ccConfig = Global::instance()->appConfigFilePath(Global::ConfigFile::CustomCommands); - m_customCommandsConfig = KSharedConfig::openConfig(ccConfig, KConfig::SimpleConfig); - QStringList groups = m_customCommandsConfig->groupList(); - - beginInsertRows(QModelIndex(), 0, groups.size()); - for (const QString &groupName : qAsConst((groups))) { - auto configGroup = m_customCommandsConfig->group(groupName); - auto c = new Command(); - c->commandId = groupName; - c->command = configGroup.readEntry("Command", QString()); - c->osdMessage = configGroup.readEntry("OsdMessage", QString()); - c->type = configGroup.readEntry("Type", QString()); - c->order = configGroup.readEntry("Order", 0); - m_customCommands << c; - } - - std::sort(m_customCommands.begin(), m_customCommands.end(), [=](Command *c1, Command *c2) { - return c1->order < c2->order; - }); - - endInsertRows(); - - connect(this, &QAbstractListModel::rowsMoved, this, [=]() { - for (int i = 0; i < m_customCommands.size(); ++i) { - auto configGroup = m_customCommandsConfig->group(m_customCommands[i]->commandId); - configGroup.writeEntry("Order", i); - configGroup.sync(); - } - }); -} - -int CustomCommandsModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) - return 0; - - return m_customCommands.size(); -} - -QVariant CustomCommandsModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - Command *command = m_customCommands[index.row()]; - - switch (role) { - case CommandIdRole: - return QVariant(command->commandId); - case CommandRole: - return QVariant(command->command); - case OsdMessageRole: - return QVariant(command->osdMessage); - case TypeRole: - return QVariant(command->type); - } - - return QVariant(); -} - -QHash CustomCommandsModel::roleNames() const -{ - QHash roles; - roles[CommandIdRole] = "commandId"; - roles[OsdMessageRole] = "osdMessage"; - roles[CommandRole] = "command"; - roles[TypeRole] = "type"; - return roles; -} - -void CustomCommandsModel::moveRows(int oldIndex, int newIndex) -{ - if (oldIndex < newIndex) { - beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex + 1); - } else { - beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex); - } - Command *c = m_customCommands.takeAt(oldIndex); - m_customCommands.insert(newIndex, c); - endMoveRows(); -} - -void CustomCommandsModel::saveCustomCommand(const QString &command, const QString &osdMessage, const QString &type) -{ - int counter = m_customCommandsConfig->group(QString()).readEntry("Counter", 0); - const QString &groupName = QString("Command_%1").arg(counter); - - if (m_customCommandsConfig->group(groupName).exists()) { - return; - } - - m_customCommandsConfig->group(groupName).writeEntry(QStringLiteral("Command"), command); - m_customCommandsConfig->group(groupName).writeEntry(QStringLiteral("OsdMessage"), osdMessage); - m_customCommandsConfig->group(groupName).writeEntry(QStringLiteral("Type"), type); - m_customCommandsConfig->group(groupName).writeEntry(QStringLiteral("Order"), rowCount()); - m_customCommandsConfig->group(QString()).writeEntry(QStringLiteral("Counter"), counter + 1); - m_customCommandsConfig->sync(); - - beginInsertRows(QModelIndex(), rowCount(), rowCount()); - auto configGroup = m_customCommandsConfig->group(groupName); - auto p = new Command(); - p->commandId = groupName; - p->command = configGroup.readEntry("Command", QString()); - p->osdMessage = configGroup.readEntry("OsdMessage", QString()), - p->type = configGroup.readEntry("Type", QString()); - m_customCommands << p; - endInsertRows(); -} - -void CustomCommandsModel::editCustomCommand(int row, const QString &command, - const QString &osdMessage, const QString &type) -{ - auto customCommand = m_customCommands[row]; - customCommand->command = command; - customCommand->osdMessage = osdMessage; - customCommand->type = type; - - QString groupName = customCommand->commandId; - m_customCommandsConfig->group(groupName).writeEntry(QStringLiteral("Command"), command); - m_customCommandsConfig->group(groupName).writeEntry(QStringLiteral("OsdMessage"), osdMessage); - m_customCommandsConfig->group(groupName).writeEntry(QStringLiteral("Type"), type); - m_customCommandsConfig->sync(); - - emit dataChanged(index(row, 0), index(row, 0)); -} - -void CustomCommandsModel::deleteCustomCommand(const QString &groupName, int row) -{ - beginRemoveRows(QModelIndex(), row, row); - m_customCommandsConfig->deleteGroup(groupName); - m_customCommandsConfig->sync(); - m_customCommands.removeAt(row); - endRemoveRows(); - - KSharedConfig::Ptr config = KSharedConfig::openConfig(Global::instance()->appConfigFilePath()); - config->group("Shortcuts").deleteEntry(groupName); - config->sync(); -} - -ProxyCustomCommandsModel::ProxyCustomCommandsModel(QObject *parent) - : QSortFilterProxyModel(parent) -{ - setDynamicSortFilter(true); - setFilterRole(CustomCommandsModel::TypeRole); - setFilterCaseSensitivity(Qt::CaseInsensitive); - setFilterFixedString(QStringLiteral("shortcut")); -} diff --git a/src/models/customcommandsmodel.h b/src/models/customcommandsmodel.h deleted file mode 100644 index 4c6ce0e..0000000 --- a/src/models/customcommandsmodel.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef CUSTOMCOMMANDSMODEL_H -#define CUSTOMCOMMANDSMODEL_H - -#include -#include -#include - -class ProxyCustomCommandsModel : public QSortFilterProxyModel -{ - Q_OBJECT - -public: - explicit ProxyCustomCommandsModel(QObject *parent = nullptr); -}; - -class CustomCommandsModel : public QAbstractListModel -{ - Q_OBJECT - - struct Command { - QString commandId; - QString command; - QString osdMessage; - QString type; - int order; - }; - -public: - explicit CustomCommandsModel(QObject *parent = nullptr); - - enum Roles { - CommandIdRole = Qt::UserRole + 1, - CommandRole, - OsdMessageRole, - TypeRole, - }; - - // Basic functionality: - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - QHash roleNames() const; - - Q_INVOKABLE void moveRows(int oldIndex, int newIndex); - Q_INVOKABLE void saveCustomCommand(const QString &command, - const QString &osdMessage, - const QString &type); - Q_INVOKABLE void editCustomCommand(int row, - const QString &command, - const QString &osdMessage, - const QString &type); - Q_INVOKABLE void deleteCustomCommand(const QString &groupName, int row); - -private: - KSharedConfig::Ptr m_customCommandsConfig; - QList m_customCommands; -}; - -#endif // CUSTOMCOMMANDSMODEL_H diff --git a/src/models/subtitlesfoldersmodel.cpp b/src/models/subtitlesfoldersmodel.cpp deleted file mode 100644 index bef538e..0000000 --- a/src/models/subtitlesfoldersmodel.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include "_debug.h" -#include "subtitlesfoldersmodel.h" -#include "subtitlessettings.h" - -#include -#include -#include -#include - -SubtitlesFoldersModel::SubtitlesFoldersModel(QObject *parent) - : QAbstractListModel(parent) -{ - m_config = KSharedConfig::openConfig(Global::instance()->appConfigFilePath()); - m_list = m_config->group("Subtitles").readPathEntry("Folders", QStringList()); -} - -int SubtitlesFoldersModel::rowCount(const QModelIndex &parent) const -{ - // For list models only the root node (an invalid parent) should return the list's size. For all - // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. - if (parent.isValid()) - return 0; - - return m_list.size(); -} - -QVariant SubtitlesFoldersModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - - QString path = m_list[index.row()]; - - switch (role) { - case Qt::DisplayRole: - return QVariant(path); - } - - return QVariant(); -} - -void SubtitlesFoldersModel::updateFolder(const QString &folder, int row) -{ - m_list.replace(row, folder); - QStringList newList = m_list; - // remove empty strings - // removing directly from m_list messes with the ui logic - newList.removeAll(QString("")); - - SubtitlesSettings::self()->setSubtitlesFolders(newList); - SubtitlesSettings::self()->save(); -} - -void SubtitlesFoldersModel::deleteFolder(int row) -{ - beginRemoveRows(QModelIndex(), row, row); - m_list.removeAt(row); - endRemoveRows(); - m_config->group("Subtitles").writePathEntry("Folders", m_list); - m_config->sync(); -} - -void SubtitlesFoldersModel::addFolder() -{ - beginInsertRows(QModelIndex(), m_list.size(), m_list.size()); - m_list.append(QStringLiteral()); - endInsertRows(); -} diff --git a/src/models/subtitlesfoldersmodel.h b/src/models/subtitlesfoldersmodel.h deleted file mode 100644 index 43c9910..0000000 --- a/src/models/subtitlesfoldersmodel.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#ifndef SUBTITLESFOLDERSMODEL_H -#define SUBTITLESFOLDERSMODEL_H - -#include -#include - -class SubtitlesFoldersModel : public QAbstractListModel -{ - Q_OBJECT - -public: - explicit SubtitlesFoldersModel(QObject *parent = nullptr); - - // Basic functionality: - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - -public slots: - void updateFolder(const QString &folder, int row); - void deleteFolder(int row); - void addFolder(); - -private: - QStringList m_list; - KSharedConfig::Ptr m_config; -}; - -#endif // SUBTITLESFOLDERSMODEL_H diff --git a/src/mpris2/mediaplayer2.cpp b/src/mpris2/mediaplayer2.cpp index 86f98e1..41e34a7 100644 --- a/src/mpris2/mediaplayer2.cpp +++ b/src/mpris2/mediaplayer2.cpp @@ -5,9 +5,7 @@ */ #include "mediaplayer2.h" -#include "_debug.h" -#include #include MediaPlayer2::MediaPlayer2(QObject *obj) @@ -42,12 +40,12 @@ bool MediaPlayer2::HasTrackList() const QString MediaPlayer2::Identity() const { - return QStringLiteral("Haruna"); + return QStringLiteral("CutefishPlayer"); } QString MediaPlayer2::DesktopEntry() const { - return KAboutData::applicationData().desktopFileName(); + return ""; } QStringList MediaPlayer2::SupportedUriSchemes() const diff --git a/src/mpris2/mediaplayer2player.cpp b/src/mpris2/mediaplayer2player.cpp index cb8bbdb..1cb0b0a 100644 --- a/src/mpris2/mediaplayer2player.cpp +++ b/src/mpris2/mediaplayer2player.cpp @@ -5,8 +5,7 @@ */ #include "mediaplayer2player.h" -#include "_debug.h" -#include "mpvobject.h" +#include "../mpvobject.h" #include #include @@ -125,7 +124,7 @@ QVariantMap MediaPlayer2Player::Metadata() metadata.insert(QStringLiteral("mpris:length"), m_mpv->getProperty("duration").toDouble() * 1000 * 1000); metadata.insert(QStringLiteral("mpris:trackid"), - QVariant::fromValue(QDBusObjectPath("/org/kde/haruna"))); + QVariant::fromValue(QDBusObjectPath("/com/cutefish/videoplayer"))); metadata.insert(QStringLiteral("xesam:title"), m_mpv->getProperty("filename").toString()); QUrl url(m_mpv->getProperty("path").toString()); diff --git a/src/mpvobject.cpp b/src/mpvobject.cpp index ec71f6b..096b56f 100644 --- a/src/mpvobject.cpp +++ b/src/mpvobject.cpp @@ -4,17 +4,13 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -#include "_debug.h" #include "mpvobject.h" #include "application.h" -#include "generalsettings.h" -#include "playbacksettings.h" -#include "videosettings.h" #include "playlistitem.h" #include "track.h" #include "tracksmodel.h" -#include "global.h" +#include #include #include #include @@ -28,8 +24,6 @@ #include #include -#include - void on_mpv_redraw(void *ctx) { QMetaObject::invokeMethod(static_cast(ctx), "update", Qt::QueuedConnection); @@ -110,9 +104,9 @@ MpvObject::MpvObject(QQuickItem * parent) // setProperty("terminal", "yes"); // setProperty("msg-level", "all=v"); - QString hwdec = PlaybackSettings::useHWDecoding() ? PlaybackSettings::hWDecoding() : "no"; - setProperty("hwdec", hwdec); - setProperty("screenshot-template", VideoSettings::screenshotTemplate()); +// QString hwdec = PlaybackSettings::useHWDecoding() ? PlaybackSettings::hWDecoding() : "no"; + setProperty("hwdec", "auto"); +// setProperty("screenshot-template", VideoSettings::screenshotTemplate()); setProperty("sub-auto", "exact"); setProperty("volume-max", "100"); @@ -137,17 +131,17 @@ MpvObject::MpvObject(QQuickItem * parent) // run user commands - KSharedConfig::Ptr m_customPropsConfig; - QString ccConfig = Global::instance()->appConfigFilePath(Global::ConfigFile::CustomCommands); - m_customPropsConfig = KSharedConfig::openConfig(ccConfig, KConfig::SimpleConfig); - QStringList groups = m_customPropsConfig->groupList(); - for (const QString &_group : qAsConst((groups))) { - auto configGroup = m_customPropsConfig->group(_group); - QString type = configGroup.readEntry("Type", QString()); - if (type == "startup") { - userCommand(configGroup.readEntry("Command", QString())); - } - } +// KSharedConfig::Ptr m_customPropsConfig; +// QString ccConfig = Global::instance()->appConfigFilePath(Global::ConfigFile::CustomCommands); +// m_customPropsConfig = KSharedConfig::openConfig(ccConfig, KConfig::SimpleConfig); +// QStringList groups = m_customPropsConfig->groupList(); +// for (const QString &_group : qAsConst((groups))) { +// auto configGroup = m_customPropsConfig->group(_group); +// QString type = configGroup.readEntry("Type", QString()); +// if (type == "startup") { +// userCommand(configGroup.readEntry("Command", QString())); +// } +// } mpv_set_wakeup_callback(mpv, MpvObject::mpvEvents, this); @@ -391,18 +385,19 @@ QQuickFramebufferObject::Renderer *MpvObject::createRenderer() const return new MpvRenderer(const_cast(this)); } -void MpvObject::loadFile(const QString &file, bool updateLastPlayedFile) +void MpvObject::loadFile(const QString &file) { - setProperty("ytdl-format", PlaybackSettings::ytdlFormat()); +// setProperty("ytdl-format", PlaybackSettings::ytdlFormat()); + command(QStringList() << "loadfile" << file); - if (updateLastPlayedFile) { - GeneralSettings::setLastPlayedFile(file); - GeneralSettings::self()->save(); - } else { - GeneralSettings::setLastPlaylistIndex(m_playlistModel->getPlayingVideo()); - GeneralSettings::self()->save(); - } +// if (updateLastPlayedFile) { +// GeneralSettings::setLastPlayedFile(file); +// GeneralSettings::self()->save(); +// } else { +// GeneralSettings::setLastPlaylistIndex(m_playlistModel->getPlayingVideo()); +// GeneralSettings::self()->save(); +// } } void MpvObject::mpvEvents(void *ctx) @@ -605,7 +600,7 @@ void MpvObject::getYouTubePlaylist(const QString &path) video->setMediaTitle(!title.isEmpty() ? title : url); video->setFileName(!title.isEmpty() ? title : url); - video->setDuration(Application::formatTime(duration)); + // video->setDuration(Application::formatTime(duration)); m_playList.append(video); playlistFileContent += QString("%1,%2,%3\n").arg(url, title, QString::number(duration)); @@ -622,7 +617,7 @@ int MpvObject::setProperty(const QString &name, const QVariant &value, bool debu { auto result = mpv::qt::set_property(mpv, name, value); if (debug) { - DEBUG << mpv::qt::get_error(result); + qDebug() << mpv::qt::get_error(result); } return result; } @@ -631,7 +626,7 @@ QVariant MpvObject::getProperty(const QString &name, bool debug) { auto result = mpv::qt::get_property(mpv, name); if (debug) { - DEBUG << mpv::qt::get_error(result); + qDebug() << mpv::qt::get_error(result); } return result; } @@ -644,58 +639,59 @@ QVariant MpvObject::command(const QVariant ¶ms) void MpvObject::saveTimePosition() { // saving position is disabled - if (PlaybackSettings::minDurationToSavePosition() == -1) { - return; - } +// if (PlaybackSettings::minDurationToSavePosition() == -1) { +// return; +// } + // position is saved only for files longer than PlaybackSettings::minDurationToSavePosition() - if (getProperty("duration").toInt() < PlaybackSettings::minDurationToSavePosition() * 60) { + if (getProperty("duration").toInt() < 60) { return; } auto hash = md5(getProperty("path").toString()); auto timePosition = getProperty("time-pos"); - auto configPath = Global::instance()->appConfigDirPath(); - KConfig *config = new KConfig(configPath.append("/watch-later/").append(hash)); - config->group("").writeEntry("TimePosition", timePosition); - config->sync(); + +// auto configPath = Global::instance()->appConfigDirPath(); +// KConfig *config = new KConfig(configPath.append("/watch-later/").append(hash)); +// config->group("").writeEntry("TimePosition", timePosition); +// config->sync(); } double MpvObject::loadTimePosition() { - // saving position is disabled - if (PlaybackSettings::minDurationToSavePosition() == -1) { - return 0; - } // position is saved only for files longer than PlaybackSettings::minDurationToSavePosition() // but there can be cases when there is a saved position for files lower than minDurationToSavePosition() // when minDurationToSavePosition() was increased after position was already saved - if (getProperty("duration").toInt() < PlaybackSettings::minDurationToSavePosition() * 60) { + if (getProperty("duration").toInt() < 60) { return 0; } - auto hash = md5(getProperty("path").toString()); - auto configPath = Global::instance()->appConfigDirPath(); - KConfig *config = new KConfig(configPath.append("/watch-later/").append(hash)); - int position = config->group("").readEntry("TimePosition", QString::number(0)).toDouble(); +// auto hash = md5(getProperty("path").toString()); +// QSettings settings("cutefishos", "cutefish-videoplayer"); +// auto configPath = QFileInfo(settings.fileName()).absoluteDir(); +// qDebug() << configPath; +// KConfig *config = new KConfig(configPath.append("/watch-later/").append(hash)); +// QSettings set(configPath.append("/watch-later/")); +// int position = config->group("").readEntry("TimePosition", QString::number(0)).toDouble(); - return position; + return 0; } void MpvObject::resetTimePosition() { - auto hash = md5(getProperty("path").toString()); - auto configPath = Global::instance()->appConfigDirPath(); - QFile f(configPath.append("/watch-later/").append(hash)); +// auto hash = md5(getProperty("path").toString()); +// auto configPath = Global::instance()->appConfigDirPath(); +// QFile f(configPath.append("/watch-later/").append(hash)); - if (f.exists()) { - f.remove(); - } +// if (f.exists()) { +// f.remove(); +// } } void MpvObject::userCommand(const QString &commandString) { - QStringList args = KShell::splitArgs(commandString); - command(args); + // QStringList args = KShell::splitArgs(commandString); + // command(args); } QString MpvObject::md5(const QString &str) diff --git a/src/mpvobject.h b/src/mpvobject.h index 7fdfbf7..3d71b25 100644 --- a/src/mpvobject.h +++ b/src/mpvobject.h @@ -1,4 +1,4 @@ -/* +/* * SPDX-FileCopyrightText: 2020 George Florea Bănuș * * SPDX-License-Identifier: GPL-3.0-or-later @@ -11,6 +11,7 @@ #include #include + #include "qthelper.h" #include "playlistmodel.h" #include "tracksmodel.h" @@ -120,7 +121,7 @@ class MpvObject : public QQuickFramebufferObject bool pause(); void setPause(bool value); - + int volume(); void setVolume(int value); @@ -164,7 +165,7 @@ public: virtual ~MpvObject(); virtual Renderer *createRenderer() const; - Q_INVOKABLE void loadFile(const QString &file, bool updateLastPlayedFile = true); + Q_INVOKABLE void loadFile(const QString &file); Q_INVOKABLE void getYouTubePlaylist(const QString &path); Q_INVOKABLE QVariant command(const QVariant ¶ms); Q_INVOKABLE QVariant getProperty(const QString &name, bool debug = false); diff --git a/src/playlistitem.cpp b/src/playlistitem.cpp index 71a4f9d..5e8438a 100644 --- a/src/playlistitem.cpp +++ b/src/playlistitem.cpp @@ -4,7 +4,6 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -#include "_debug.h" #include "playlistitem.h" #include diff --git a/src/models/playlistmodel.cpp b/src/playlistmodel.cpp similarity index 64% rename from src/models/playlistmodel.cpp rename to src/playlistmodel.cpp index 8669913..18df205 100644 --- a/src/models/playlistmodel.cpp +++ b/src/playlistmodel.cpp @@ -1,39 +1,53 @@ /* + * SPDX-FileCopyrightText: 2021 Reion Wong * SPDX-FileCopyrightText: 2020 George Florea Bănuș * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "playlistmodel.h" -#include "playlistitem.h" -#include "_debug.h" -#include "application.h" -#include "worker.h" +#include #include #include #include #include #include -#include PlayListModel::PlayListModel(QObject *parent) : QAbstractListModel(parent) + , m_settings("cutefishos", "cutefish-videoplayer") { - m_config = KSharedConfig::openConfig(Global::instance()->appConfigFilePath()); - connect(this, &PlayListModel::videoAdded, - Worker::instance(), &Worker::getMetaData); + // Reion: init list. + QStringList list = m_settings.value("List").toString().split(','); + int idx = 0; - connect(Worker::instance(), &Worker::metaDataReady, this, [ = ](int i, KFileMetaData::PropertyMap metaData) { - auto duration = metaData[KFileMetaData::Property::Duration].toInt(); - auto title = metaData[KFileMetaData::Property::Title].toString(); + for (const QString &path : list) { + if (!QFile(path).exists()) + continue; - m_playList[i]->setDuration(Application::formatTime(duration)); - m_playList[i]->setMediaTitle(title); + auto video = new PlayListItem(path, idx , this); + m_playList.append(video); + ++idx; + } + + if (!m_playList.isEmpty()) + setPlayingVideo(0); + +// m_config = KSharedConfig::openConfig(Global::instance()->appConfigFilePath()); +// connect(this, &PlayListModel::videoAdded, +// Worker::instance(), &Worker::getMetaData); - emit dataChanged(index(i, 0), index(i, 0)); +// connect(Worker::instance(), &Worker::metaDataReady, this, [ = ](int i, KFileMetaData::PropertyMap metaData) { +// auto duration = metaData[KFileMetaData::Property::Duration].toInt(); +// auto title = metaData[KFileMetaData::Property::Title].toString(); - }); +// m_playList[i]->setDuration(Application::formatTime(duration)); +// m_playList[i]->setMediaTitle(title); + +// emit dataChanged(index(i, 0), index(i, 0)); + +// }); } int PlayListModel::rowCount(const QModelIndex &parent) const @@ -123,16 +137,6 @@ Playlist PlayListModel::items() const return m_playList; } -QString PlayListModel::configFolder() -{ - - auto configPath = QStandardPaths::writableLocation(m_config->locationType()); - auto configFilePath = configPath.append(QStringLiteral("/")).append(m_config->name()); - QFileInfo fileInfo(configFilePath); - - return fileInfo.absolutePath(); -} - Playlist PlayListModel::getPlayList() const { return m_playList; @@ -159,6 +163,56 @@ void PlayListModel::clear() endResetModel(); } +void PlayListModel::save() +{ + QString value; + for (int i = 0; i < m_playList.size(); ++i) { + const QString path = m_playList.at(i)->filePath(); + + if (value.isEmpty()) + value.append(path); + else + value.append(',' + path); + } + + m_settings.setValue("List", value); +} + +void PlayListModel::addVideo(const QString &path) +{ + QString newPath = QUrl(path).toLocalFile().isEmpty() ? path : QUrl(path).toLocalFile(); + + // Skip + for (int i = 0; i < m_playList.size(); ++i) { + if (m_playList.at(i)->filePath() == newPath) { + return; + } + } + + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + auto video = new PlayListItem(newPath, m_playList.size() - 1, this); + m_playList.append(video); + setPlayingVideo(m_playList.size() - 1); + endInsertRows(); + + save(); +} + +void PlayListModel::remove(int i) +{ + if (i < 0 || i > m_playList.size()) + return; + + setPlayingVideo(i); + + beginRemoveRows(QModelIndex(), i, i); + PlayListItem *item = m_playList.at(i); + m_playList.removeAt(i); + item->deleteLater(); + endRemoveRows(); + save(); +} + QString PlayListModel::getPath(int i) { // when restoring a youtube playlist diff --git a/src/models/playlistmodel.h b/src/playlistmodel.h similarity index 86% rename from src/models/playlistmodel.h rename to src/playlistmodel.h index 595e17c..2d2adcb 100644 --- a/src/models/playlistmodel.h +++ b/src/playlistmodel.h @@ -8,13 +8,13 @@ #define PLAYLISTMODEL_H #include -#include #include #include +#include -class PlayListItem; +#include "playlistitem.h" -using Playlist = QList; +using Playlist = QList; class PlayListModel : public QAbstractListModel { @@ -47,6 +47,10 @@ public: Q_INVOKABLE int getPlayingVideo() const; Q_INVOKABLE void getVideos(QString path); Q_INVOKABLE void clear(); + Q_INVOKABLE void save(); + + Q_INVOKABLE void addVideo(const QString &path); + Q_INVOKABLE void remove(int i); Playlist getPlayList() const; void setPlayList(const Playlist &playList); @@ -57,10 +61,9 @@ signals: private: Playlist items() const; - QString configFolder(); Playlist m_playList; int m_playingVideo = 0; - KSharedConfig::Ptr m_config; + QSettings m_settings; }; #endif // PLAYLISTMODEL_H diff --git a/src/qml.qrc b/src/qml.qrc deleted file mode 100644 index cd67322..0000000 --- a/src/qml.qrc +++ /dev/null @@ -1,40 +0,0 @@ - - - qml/main.qml - qml/PlayListItem.qml - qml/PlayList.qml - qml/MpvVideo.qml - qml/HProgressBar.qml - qml/Header.qml - qml/Footer.qml - qml/Osd.qml - qml/Actions.qml - qml/VolumeSlider.qml - qml/Settings/SettingsEditor.qml - qml/Haruna/Components/SubtitlesFolders.qml - qml/Settings/General.qml - qml/Settings/Mouse.qml - qml/Settings/Navigation.qml - qml/Settings/Playlist.qml - qml/Settings/Audio.qml - qml/Settings/Subtitles.qml - qml/Settings/Playback.qml - qml/Menus/FileMenu.qml - qml/Menus/PlaybackMenu.qml - qml/Menus/SubtitlesMenu.qml - qml/Menus/SettingsMenu.qml - qml/Menus/AudioMenu.qml - qml/Menus/ViewMenu.qml - qml/Menus/TrackMenuItems.qml - qml/Haruna/Components/SelectActionPopup.qml - qml/Settings/VideoSettings.qml - qml/Menus/HelpMenu.qml - qml/Haruna/Components/LabelWithTooltip.qml - qml/Haruna/Components/SettingsHeader.qml - qml/Haruna/Components/SettingsBasePage.qml - qml/Haruna/Components/qmldir - qml/Haruna/Components/ImageAdjustmentSlider.qml - qml/Settings/CustomCommands.qml - qml/Settings/EditCustomCommand.qml - - diff --git a/src/qml.qrc.license b/src/qml.qrc.license deleted file mode 100644 index 99c88cb..0000000 --- a/src/qml.qrc.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2020 George Florea Bănuș - -SPDX-License-Identifier: CC-BY-4.0 diff --git a/src/qml/Actions.qml b/src/qml/Actions.qml deleted file mode 100644 index 38a68e7..0000000 --- a/src/qml/Actions.qml +++ /dev/null @@ -1,1059 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -import org.kde.haruna 1.0 - -QtObject { - id: root - - property var list: ({}) - - property Action openContextMenuAction: Action { - id: openContextMenuAction - property var qaction: app.action("openContextMenu") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["openContextMenuAction"] = openContextMenuAction - - onTriggered: mpvContextMenu.popup() - } - - property Action togglePlaylistAction: Action { - id: togglePlaylistAction - property var qaction: app.action("togglePlaylist") - // text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["togglePlaylistAction"] = togglePlaylistAction - - onTriggered: { - if (playList.state === "visible") { - playList.state = "hidden" - } else { - playList.state = "visible" - } - } - } - - property Action volumeUpAction: Action { - id: volumeUpAction - property var qaction: app.action("volumeUp") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["volumeUpAction"] = volumeUpAction - - onTriggered: { - mpv.command(["add", "volume", GeneralSettings.volumeStep]) - osd.message(`Volume: ${parseInt(mpv.getProperty("volume"))}`) - } - } - - property Action volumeDownAction: Action { - id: volumeDownAction - property var qaction: app.action("volumeDown") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["volumeDownAction"] = volumeDownAction - - onTriggered: { - mpv.command(["add", "volume", -GeneralSettings.volumeStep]) - osd.message(`Volume: ${parseInt(mpv.getProperty("volume"))}`) - } - } - - property Action muteAction: Action { - id: muteAction - property var qaction: app.action("mute") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["muteAction"] = muteAction - - onTriggered: { - mpv.setProperty("mute", !mpv.getProperty("mute")) - if (mpv.getProperty("mute")) { - text = qsTr("Unmute") - icon.name = "player-volume-muted" - } else { - text = qaction.text - icon.name = qaction.iconName() - } - } - } - - property Action playNextAction: Action { - id: playNextAction - property var qaction: app.action("playNext") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["playNextAction"] = playNextAction - - onTriggered: { - const nextFileRow = mpv.playlistModel.getPlayingVideo() + 1 - const updateLastPlayedFile = !playList.isYouTubePlaylist - if (nextFileRow < playList.playlistView.count) { - const nextFile = mpv.playlistModel.getPath(nextFileRow) - mpv.playlistModel.setPlayingVideo(nextFileRow) - mpv.loadFile(nextFile, updateLastPlayedFile) - } else { - // Last file in playlist - if (PlaylistSettings.repeat) { - mpv.playlistModel.setPlayingVideo(0) - mpv.loadFile(mpv.playlistModel.getPath(0), updateLastPlayedFile) - } - } - } - } - - property Action playPreviousAction: Action { - id: playPreviousAction - property var qaction: app.action("playPrevious") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["playPreviousAction"] = playPreviousAction - - onTriggered: { - if (mpv.playlistModel.getPlayingVideo() !== 0) { - const previousFileRow = mpv.playlistModel.getPlayingVideo() - 1 - const previousFile = mpv.playlistModel.getPath(previousFileRow) - const updateLastPlayedFile = !playList.isYouTubePlaylist - mpv.playlistModel.setPlayingVideo(previousFileRow) - mpv.loadFile(previousFile, updateLastPlayedFile) - } - } - } - - property Action openAction: Action { - id: openAction - property var qaction: app.action("openFile") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["openAction"] = openAction - - onTriggered: fileDialog.open() - } - - property Action openUrlAction: Action { - id: openUrlAction - property var qaction: app.action("openUrl") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["openUrlAction"] = openUrlAction - - onTriggered: { - if (openUrlPopup.visible) { - openUrlPopup.close() - } else { - openUrlPopup.open() - } - } - } - - property Action aboutHarunaAction: Action { - id: aboutHarunaAction - property var qaction: app.action("aboutHaruna") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["aboutHarunaAction"] = aboutHarunaAction - - onTriggered: qaction.trigger() - } - - property Action seekForwardSmallAction: Action { - id: seekForwardSmallAction - property var qaction: app.action("seekForwardSmall") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekForwardSmallAction"] = seekForwardSmallAction - - onTriggered: mpv.command(["seek", GeneralSettings.seekSmallStep, "exact"]) - } - - property Action seekBackwardSmallAction: Action { - id: seekBackwardSmallAction - property var qaction: app.action("seekBackwardSmall") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekBackwardSmallAction"] = seekBackwardSmallAction - - onTriggered: mpv.command(["seek", -GeneralSettings.seekSmallStep, "exact"]) - } - - property Action seekForwardMediumAction: Action { - id: seekForwardMediumAction - property var qaction: app.action("seekForwardMedium") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekForwardMediumAction"] = seekForwardMediumAction - - onTriggered: mpv.command(["seek", GeneralSettings.seekMediumStep, "exact"]) - } - - property Action seekBackwardMediumAction: Action { - id: seekBackwardMediumAction - property var qaction: app.action("seekBackwardMedium") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekBackwardMediumAction"] = seekBackwardMediumAction - - onTriggered: mpv.command(["seek", -GeneralSettings.seekMediumStep, "exact"]) - } - - property Action seekForwardBigAction: Action { - id: seekForwardBigAction - property var qaction: app.action("seekForwardBig") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekForwardBigAction"] = seekForwardBigAction - - onTriggered: mpv.command(["seek", GeneralSettings.seekBigStep, "exact"]) - } - - property Action seekBackwardBigAction: Action { - id: seekBackwardBigAction - property var qaction: app.action("seekBackwardBig") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekBackwardBigAction"] = seekBackwardBigAction - - onTriggered: mpv.command(["seek", -GeneralSettings.seekBigStep, "exact"]) - } - - property Action seekPreviousChapterAction: Action { - id: seekPreviousChapterAction - property var qaction: app.action("seekPreviousChapter") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekPreviousChapterAction"] = seekPreviousChapterAction - - onTriggered: { - mpv.command(["add", "chapter", "-1"]) - } - } - - property Action seekNextChapterAction: Action { - id: seekNextChapterAction - property var qaction: app.action("seekNextChapter") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekNextChapterAction"] = seekNextChapterAction - - onTriggered: { - const chapters = mpv.getProperty("chapter-list") - const currentChapter = mpv.getProperty("chapter") - const nextChapter = currentChapter + 1 - if (nextChapter === chapters.length) { - playNextAction.trigger() - return - } - mpv.command(["add", "chapter", "1"]) - } - } - - property Action seekNextSubtitleAction: Action { - id: seekNextSubtitleAction - property var qaction: app.action("seekNextSubtitle") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekNextSubtitleAction"] = seekNextSubtitleAction - - onTriggered: { - if (mpv.getProperty("sid") !== false) { - mpv.command(["sub-seek", "1"]) - } else { - seekForwardSmallAction.trigger() - } - } - } - - property Action seekPrevSubtitleAction: Action { - id: seekPrevSubtitleAction - property var qaction: app.action("seekPreviousSubtitle") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["seekPrevSubtitleAction"] = seekPrevSubtitleAction - - onTriggered: { - if (mpv.getProperty("sid") !== false) { - mpv.command(["sub-seek", "-1"]) - } else { - seekBackwardSmallAction.trigger() - } - } - } - - property Action frameStepAction: Action { - id: frameStepAction - property var qaction: app.action("frameStep") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["frameStepAction"] = frameStepAction - - onTriggered: mpv.command(["frame-step"]) - } - - property Action frameBackStepAction: Action { - id: frameBackStepAction - property var qaction: app.action("frameBackStep") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["frameBackStepAction"] = frameBackStepAction - - onTriggered: mpv.command(["frame-back-step"]) - } - - property Action increasePlayBackSpeedAction: Action { - id: increasePlayBackSpeedAction - property var qaction: app.action("increasePlayBackSpeed") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["increasePlayBackSpeedAction"] = increasePlayBackSpeedAction - - onTriggered: { - mpv.command(["add", "speed", "0.1"]) - osd.message(`Speed: ${mpv.getProperty("speed").toFixed(2)}`) - } - } - - property Action decreasePlayBackSpeedAction: Action { - id: decreasePlayBackSpeedAction - property var qaction: app.action("decreasePlayBackSpeed") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["decreasePlayBackSpeedAction"] = decreasePlayBackSpeedAction - - onTriggered: { - mpv.command(["add", "speed", "-0.1"]) - osd.message(`Speed: ${mpv.getProperty("speed").toFixed(2)}`) - } - } - - property Action resetPlayBackSpeedAction: Action { - id: resetPlayBackSpeedAction - property var qaction: app.action("resetPlayBackSpeed") - text: qaction.text - shortcut: qaction.shortcutName - icon.name: qaction.iconName() - - Component.onCompleted: list["resetPlayBackSpeedAction"] = resetPlayBackSpeedAction - - onTriggered: { - mpv.setProperty("speed", 1.0) - osd.message(`Speed: ${mpv.getProperty("speed").toFixed(2)}`) - } - } - - property Action playPauseAction: Action { - id: playPauseAction - text: qsTr("Play/Pause") - icon.name: "media-playback-pause" - shortcut: "Space" - - Component.onCompleted: list["playPauseAction"] = playPauseAction - - onTriggered: mpv.setProperty("pause", !mpv.getProperty("pause")) - } - - property Action configureShortcutsAction: Action { - id: configureShortcutsAction - property var qaction: app.action("options_configure_keybinding") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["configureShortcutsAction"] = configureShortcutsAction - - onTriggered: qaction.trigger() - } - - property Action quitApplicationAction: Action { - id: quitApplicationAction - property var qaction: app.action("file_quit") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["quitApplicationAction"] = quitApplicationAction - - onTriggered: { - mpv.handleTimePosition() - qaction.trigger() - } - } - - property Action configureAction: Action { - id: configureAction - property var qaction: app.action("configure") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["configureAction"] = configureAction - - onTriggered: { - settingsEditor.visible = true - } - } - - property Action subtitleQuickenAction: Action { - id: subtitleQuickenAction - property var qaction: app.action("subtitleQuicken") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["subtitleQuickenAction"] = subtitleQuickenAction - - onTriggered: { - mpv.setProperty("sub-delay", mpv.getProperty("sub-delay") - 0.1) - osd.message(`Subtitle timing: ${mpv.getProperty("sub-delay").toFixed(2)}`) - } - } - - property Action subtitleDelayAction: Action { - id: subtitleDelayAction - property var qaction: app.action("subtitleDelay") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["subtitleDelayAction"] = subtitleDelayAction - - onTriggered: { - mpv.setProperty("sub-delay", mpv.getProperty("sub-delay") + 0.1) - osd.message(`Subtitle timing: ${mpv.getProperty("sub-delay").toFixed(2)}`) - } - } - - property Action subtitleToggleAction: Action { - id: subtitleToggleAction - property var qaction: app.action("subtitleToggle") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["subtitleToggleAction"] = subtitleToggleAction - - onTriggered: { - const visible = mpv.getProperty("sub-visibility") - const message = visible ? "Subtitles off" : "Subtitles on" - mpv.setProperty("sub-visibility", !visible) - osd.message(message) - } - } - - property Action audioCycleUpAction: Action { - id: audioCycleUpAction - property var qaction: app.action("audioCycleUp") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["audioCycleUpAction"] = audioCycleUpAction - - onTriggered: { - const tracks = mpv.getProperty("track-list") - let audioTracksCount = 0 - tracks.forEach(t => { if(t.type === "audio") ++audioTracksCount }) - - if (audioTracksCount > 1) { - mpv.command(["cycle", "aid", "up"]) - const currentTrackId = mpv.getProperty("aid") - - if (currentTrackId === false) { - audioCycleUpAction.trigger() - return - } - const track = tracks.find(t => t.type === "audio" && t.id === currentTrackId) - const message = `Audio: ${currentTrackId} (${track.lang})` - osd.message(message) - } - } - } - - property Action audioCycleDownAction: Action { - id: audioCycleDownAction - property var qaction: app.action("audioCycleDown") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["audioCycleDownAction"] = audioCycleDownAction - - onTriggered: { - const tracks = mpv.getProperty("track-list") - let audioTracksCount = 0 - tracks.forEach(t => { if(t.type === "audio") ++audioTracksCount }) - - if (audioTracksCount > 1) { - mpv.command(["cycle", "aid", "down"]) - const currentTrackId = mpv.getProperty("aid") - - if (currentTrackId === false) { - audioCycleDownAction.trigger() - return - } - const track = tracks.find(t => t.type === "audio" && t.id === currentTrackId) - const message = `Audio: ${currentTrackId} (${track.lang})` - osd.message(message) - } - } - } - - property Action subtitleCycleUpAction: Action { - id: subtitleCycleUpAction - property var qaction: app.action("subtitleCycleUp") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["subtitleCycleUpAction"] = subtitleCycleUpAction - - onTriggered: { - mpv.command(["cycle", "sid", "up"]) - const currentTrackId = mpv.getProperty("sid") - let message; - if (currentTrackId === false) { - message = `Subtitle: None` - } else { - const tracks = mpv.getProperty("track-list") - const track = tracks.find(t => t.type === "sub" && t.id === currentTrackId) - message = `Subtitle: ${currentTrackId} (${track.lang})` - } - osd.message(message) - } - } - - property Action subtitleCycleDownAction: Action { - id: subtitleCycleDownAction - property var qaction: app.action("subtitleCycleDown") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["subtitleCycleDownAction"] = subtitleCycleDownAction - - onTriggered: { - mpv.command(["cycle", "sid", "down"]) - const currentTrackId = mpv.getProperty("sid") - let message; - if (currentTrackId === false) { - message = `Subtitle: None` - } else { - const tracks = mpv.getProperty("track-list") - const track = tracks.find(t => t.type === "sub" && t.id === currentTrackId) - message = `Subtitle: ${currentTrackId} (${track.lang})` - } - osd.message(message) - } - } - - property Action contrastUpAction: Action { - id: contrastUpAction - property var qaction: app.action("contrastUp") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["contrastUpAction"] = contrastUpAction - - onTriggered: { - const contrast = parseInt(mpv.getProperty("contrast")) + 1 - mpv.setProperty("contrast", `${contrast}`) - osd.message(`Contrast: ${contrast}`) - } - } - property Action contrastDownAction: Action { - id: contrastDownAction - property var qaction: app.action("contrastDown") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["contrastDownAction"] = contrastDownAction - - onTriggered: { - const contrast = parseInt(mpv.getProperty("contrast")) - 1 - mpv.setProperty("contrast", `${contrast}`) - osd.message(`Contrast: ${contrast}`) - } - } - property Action contrastResetAction: Action { - id: contrastResetAction - property var qaction: app.action("contrastReset") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["contrastResetAction"] = contrastResetAction - - onTriggered: { - mpv.setProperty("contrast", `0`) - osd.message(`Contrast: 0`) - } - } - - property Action brightnessUpAction: Action { - id: brightnessUpAction - property var qaction: app.action("brightnessUp") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["brightnessUpAction"] = brightnessUpAction - - onTriggered: { - const brightness = parseInt(mpv.getProperty("brightness")) + 1 - mpv.setProperty("brightness", `${brightness}`) - osd.message(`Brightness: ${brightness}`) - } - } - property Action brightnessDownAction: Action { - id: brightnessDownAction - property var qaction: app.action("brightnessDown") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["brightnessDownAction"] = brightnessDownAction - - onTriggered: { - const brightness = parseInt(mpv.getProperty("brightness")) - 1 - mpv.setProperty("brightness", `${brightness}`) - osd.message(`Brightness: ${brightness}`) - } - } - property Action brightnessResetAction: Action { - id: brightnessResetAction - property var qaction: app.action("brightnessReset") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["brightnessResetAction"] = brightnessResetAction - - onTriggered: { - mpv.setProperty("brightness", `0`) - osd.message(`Brightness: 0`) - } - } - property Action gammaUpAction: Action { - id: gammaUpAction - property var qaction: app.action("gammaUp") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["gammaUpAction"] = gammaUpAction - - onTriggered: { - const gamma = parseInt(mpv.getProperty("gamma")) + 1 - mpv.setProperty("gamma", `${gamma}`) - osd.message(`Gamma: ${gamma}`) - } - } - property Action gammaDownAction: Action { - id: gammaDownAction - property var qaction: app.action("gammaDown") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["gammaDownAction"] = gammaDownAction - - onTriggered: { - const gamma = parseInt(mpv.getProperty("gamma")) - 1 - mpv.setProperty("gamma", `${gamma}`) - osd.message(`Gamma: ${gamma}`) - } - } - property Action gammaResetAction: Action { - id: gammaResetAction - property var qaction: app.action("gammaReset") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["gammaResetAction"] = gammaResetAction - - onTriggered: { - mpv.setProperty("gamma", `0`) - osd.message(`Gamma: 0`) - } - } - property Action saturationUpAction: Action { - id: saturationUpAction - property var qaction: app.action("saturationUp") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["saturationUpAction"] = saturationUpAction - - onTriggered: { - const saturation = parseInt(mpv.getProperty("saturation")) + 1 - mpv.setProperty("saturation", `${saturation}`) - osd.message(`Saturation: ${saturation}`) - } - } - property Action saturationDownAction: Action { - id: saturationDownAction - property var qaction: app.action("saturationDown") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["saturationDownAction"] = saturationDownAction - - onTriggered: { - const saturation = parseInt(mpv.getProperty("saturation")) - 1 - mpv.setProperty("saturation", `${saturation}`) - osd.message(`Saturation: ${saturation}`) - } - } - property Action saturationResetAction: Action { - id: saturationResetAction - property var qaction: app.action("saturationReset") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["saturationResetAction"] = saturationResetAction - - onTriggered: { - mpv.setProperty("saturation", `0`) - osd.message(`Saturation: 0`) - } - } - - property Action zoomInAction: Action { - id: zoomInAction - property var qaction: app.action("zoomIn") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["zoomInAction"] = zoomInAction - - onTriggered: { - const zoom = mpv.getProperty("video-zoom") + 0.1 - mpv.setProperty("video-zoom", zoom) - osd.message(`Zoom: ${zoom.toFixed(2)}`) - } - } - - property Action zoomOutAction: Action { - id: zoomOutAction - property var qaction: app.action("zoomOut") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["zoomOutAction"] = zoomOutAction - - onTriggered: { - const zoom = mpv.getProperty("video-zoom") - 0.1 - mpv.setProperty("video-zoom", zoom) - osd.message(`Zoom: ${zoom.toFixed(2)}`) - } - } - property Action zoomResetAction: Action { - id: zoomResetAction - property var qaction: app.action("zoomReset") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["zoomResetAction"] = zoomResetAction - - onTriggered: { - mpv.setProperty("video-zoom", 0) - osd.message(`Zoom: 0`) - } - } - - - property Action videoPanXLeftAction: Action { - id: videoPanXLeftAction - property var qaction: app.action("videoPanXLeft") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["videoPanXLeftAction"] = videoPanXLeftAction - - onTriggered: { - const pan = mpv.getProperty("video-pan-x") - 0.01 - mpv.setProperty("video-pan-x", pan) - osd.message(`Video pan x: ${pan.toFixed(2)}`) - } - } - property Action videoPanXRightAction: Action { - id: videoPanXRightAction - property var qaction: app.action("videoPanXRight") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["videoPanXRightAction"] = videoPanXRightAction - - onTriggered: { - const pan = mpv.getProperty("video-pan-x") + 0.01 - mpv.setProperty("video-pan-x", pan) - osd.message(`Video pan x: ${pan.toFixed(2)}`) - } - } - property Action videoPanYUpAction: Action { - id: videoPanYUpAction - property var qaction: app.action("videoPanYUp") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["videoPanYUpAction"] = videoPanYUpAction - - onTriggered: { - const pan = mpv.getProperty("video-pan-y") - 0.01 - mpv.setProperty("video-pan-y", pan) - osd.message(`Video pan x: ${pan.toFixed(2)}`) - } - } - property Action videoPanYDownAction: Action { - id: videoPanYDownAction - property var qaction: app.action("videoPanYDown") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["videoPanYDownAction"] = videoPanYDownAction - - onTriggered: { - const pan = mpv.getProperty("video-pan-y") + 0.01 - mpv.setProperty("video-pan-y", pan) - osd.message(`Video pan x: ${pan.toFixed(2)}`) - } - } - - property Action toggleFullscreenAction: Action { - id: toggleFullscreenAction - property var qaction: app.action("toggleFullscreen") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["toggleFullscreenAction"] = toggleFullscreenAction - - onTriggered: { - window.toggleFullScreen() - } - } - - property Action toggleMenuBarAction: Action { - id: toggleMenuBarAction - property var qaction: app.action("toggleMenuBar") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["toggleMenuBarAction"] = toggleMenuBarAction - - onTriggered: GeneralSettings.showMenuBar = !menuBar.visible - } - - property Action toggleHeaderAction: Action { - id: toggleHeaderAction - property var qaction: app.action("toggleHeader") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["toggleHeaderAction"] = toggleHeaderAction - - onTriggered: GeneralSettings.showHeader = !header.visible - } - - property Action screenshotAction: Action { - id: screenshotAction - property var qaction: app.action("screenshot") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["screenshotAction"] = screenshotAction - - onTriggered: mpv.command(["screenshot"]) - } - - property Action setLoopAction: Action { - id: setLoopAction - property var qaction: app.action("setLoop") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["setLoopAction"] = setLoopAction - - onTriggered: { - var a = mpv.getProperty("ab-loop-a") - var b = mpv.getProperty("ab-loop-b") - - var aIsSet = a !== "no" - var bIsSet = b !== "no" - - if (!aIsSet && !bIsSet) { - mpv.setProperty("ab-loop-a", mpv.position) - footer.progressBar.loopIndicator.startPosition = mpv.position - osd.message("Loop start: " + app.formatTime(mpv.position)) - } else if (aIsSet && !bIsSet) { - mpv.setProperty("ab-loop-b", mpv.position) - footer.progressBar.loopIndicator.endPosition = mpv.position - osd.message(`Loop: ${app.formatTime(a)} - ${app.formatTime(mpv.position)}`) - } else if (aIsSet && bIsSet) { - mpv.setProperty("ab-loop-a", "no") - mpv.setProperty("ab-loop-b", "no") - footer.progressBar.loopIndicator.startPosition = -1 - footer.progressBar.loopIndicator.endPosition = -1 - osd.message("Loop cleared") - } - } - } - - property Action increaseSubtitleFontSizeAction: Action { - id: increaseSubtitleFontSizeAction - property var qaction: app.action("increaseSubtitleFontSize") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["increaseSubtitleFontSizeAction"] = increaseSubtitleFontSizeAction - - onTriggered: { - mpv.command(["add", "sub-scale", "+0.1"]) - osd.message(qsTr("Subtitle scale: " + mpv.getProperty("sub-scale").toFixed(1))) - } - } - - property Action decreaseSubtitleFontSizeAction: Action { - id: decreaseSubtitleFontSizeAction - property var qaction: app.action("decreaseSubtitleFontSize") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["decreaseSubtitleFontSizeAction"] = decreaseSubtitleFontSizeAction - - onTriggered: { - mpv.command(["add", "sub-scale", "-0.1"]) - osd.message(qsTr("Subtitle scale: " + mpv.getProperty("sub-scale").toFixed(1))) - } - } - - property Action subtitlePositionUpAction: Action { - id: subtitlePositionUpAction - property var qaction: app.action("subtitlePositionUp") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["subtitlePositionUpAction"] = subtitlePositionUpAction - - onTriggered: { - mpv.command(["add", "sub-pos", "-1"]) - } - } - - property Action subtitlePositionDownAction: Action { - id: subtitlePositionDownAction - property var qaction: app.action("subtitlePositionDown") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["subtitlePositionDownAction"] = subtitlePositionDownAction - - onTriggered: { - mpv.command(["add", "sub-pos", "+1"]) - } - } - - property Action toggleDeinterlacingAction: Action { - id: toggleDeinterlacingAction - property var qaction: app.action("toggleDeinterlacing") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["toggleDeinterlacingAction"] = toggleDeinterlacingAction - - onTriggered: { - mpv.setProperty("deinterlace", !mpv.getProperty("deinterlace")) - osd.message(`Deinterlace: ${mpv.getProperty("deinterlace")}`) - } - } - - property Action exitFullscreenAction: Action { - id: exitFullscreenAction - property var qaction: app.action("exitFullscreen") - text: qaction.text - icon.name: qaction.iconName() - shortcut: qaction.shortcutName - - Component.onCompleted: list["exitFullscreenAction"] = exitFullscreenAction - - onTriggered: { - window.toggleFullScreen() - } - } -} diff --git a/src/qml/Footer.qml b/src/qml/Footer.qml deleted file mode 100644 index 5b3af59..0000000 --- a/src/qml/Footer.qml +++ /dev/null @@ -1,209 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * SPDX-FileCopyrightText: 2021 Reion Wong - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import QtGraphicalEffects 1.12 - -import FishUI 1.0 as FishUI - -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -Item { - id: root - - property alias progressBar: progressBar - property alias footerRow: footerRow - property alias timeInfo: timeInfo - property alias playPauseButton: playPauseButton - property alias volume: volume - - height: progressBar.height + 50 + FishUI.Units.smallSpacing -// height: mainLayout.childrenRect.height + FishUI.Units.smallSpacing - opacity: mpv.mouseY > window.height - footer.height - FishUI.Units.largeSpacing * 3 - && playList.state === "hidden" ? 1 : 0 - enabled: opacity !== 0 - visible: true - - Behavior on opacity { - NumberAnimation { - duration: 180 - } - } - - ShaderEffectSource { - id: shaderEffect - visible: true - anchors.fill: parent - sourceItem: mpv - sourceRect: Qt.rect(0, 0, root.width, root.height) - } - - FastBlur { - visible: true - anchors.fill: shaderEffect - source: shaderEffect - radius: 100 - } - - Rectangle { - id: _background - anchors.fill: parent - color: FishUI.Theme.backgroundColor - opacity: 0.8 - } - -// layer.enabled: true -// layer.effect: OpacityMask { -// maskSource: Item { -// width: root.width -// height: root.height - -// Rectangle { -// anchors.fill: parent -// radius: FishUI.Theme.bigRadius -// } -// } -// } - - Component { - id: togglePlaylistButton - - ToolButton { - action: actions.togglePlaylistAction - } - } - - ColumnLayout { - id: mainLayout - anchors.fill: parent - anchors.topMargin: 0 - anchors.bottomMargin: FishUI.Units.smallSpacing - spacing: FishUI.Units.smallSpacing - - HProgressBar { - id: progressBar - Layout.fillWidth: true - } - - RowLayout { - id: footerRow - - Item { - width: FishUI.Units.smallSpacing - } - - Item { - id: leftItem - Layout.fillWidth: true - Layout.fillHeight: true - - RowLayout { - anchors.fill: parent - - Label { - id: timeInfo - text: app.formatTime(mpv.position) + " / " + app.formatTime(mpv.duration) - font.pointSize: FishUI.Units.gridUnit - 6 - Layout.alignment: Qt.AlignVCenter - } - } - } - - Item { - id: middleItem - Layout.preferredWidth: middleLayout.childrenRect.width - Layout.fillHeight: true - - RowLayout { - id: middleLayout - anchors.fill: parent - - ToolButton { - id: playPreviousFile - action: actions.playPreviousAction - text: "" - focusPolicy: Qt.NoFocus - enabled: playList.playlistView.count > 1 - - ToolTip { - text: qsTr("Play previous file") - } - } - - ToolButton { - id: playPauseButton - action: actions.playPauseAction - text: "" - icon.name: "media-playback-start" - focusPolicy: Qt.NoFocus - - ToolTip { - id: playPauseButtonToolTip - text: mpv.pause ? qsTr("Start Playback") : qsTr("Pause Playback") - } - } - - ToolButton { - id: playNextFile - action: actions.playNextAction - text: "" - focusPolicy: Qt.NoFocus - enabled: playList.playlistView.count > 1 - - ToolTip { - text: qsTr("Play next file") - } - } - } - } - - Item { - id: rightItem - Layout.fillWidth: true - Layout.fillHeight: true - - RowLayout { - anchors.fill: parent - spacing: FishUI.Units.smallSpacing - - Item { - Layout.fillWidth: true - } - - ToolButton { - id: mute - action: actions.muteAction - text: "" - focusPolicy: Qt.NoFocus - - ToolTip { - text: actions.muteAction.text - } - } - - VolumeSlider { id: volume } - - Item { - width: 1 - } - - Loader { - sourceComponent: togglePlaylistButton - visible: true - } - - Item { - width: FishUI.Units.smallSpacing - } - } - } - } - } -} diff --git a/src/qml/Haruna/Components/ImageAdjustmentSlider.qml b/src/qml/Haruna/Components/ImageAdjustmentSlider.qml deleted file mode 100644 index 01f0a71..0000000 --- a/src/qml/Haruna/Components/ImageAdjustmentSlider.qml +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 - -RowLayout { - id: root - - property int value: 0 - signal sliderValueChanged(int value) - - Slider { - id: slider - - from: -100 - to: 100 - value: root.value - wheelEnabled: true - stepSize: 1 - onValueChanged: root.sliderValueChanged(value.toFixed(0)) - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.MiddleButton - onClicked: slider.value = 0 - } - - Component.onCompleted: background.activeControl = "" - } - - Label { - text: slider.value - horizontalAlignment: Qt.AlignHCenter - Layout.preferredWidth: 40 - } -} diff --git a/src/qml/Haruna/Components/LabelWithTooltip.qml b/src/qml/Haruna/Components/LabelWithTooltip.qml deleted file mode 100644 index 763bc3a..0000000 --- a/src/qml/Haruna/Components/LabelWithTooltip.qml +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 as QQC2 -import QtQuick.Layouts 1.12 - -QQC2.Label { - id: root - - property string toolTipText - property int toolTipFontSize - property bool alwaysShowToolTip - - QQC2.ToolTip { - id: toolTip - - visible: (root.alwaysShowToolTip && mouseArea.containsMouse) || (mouseArea.containsMouse && root.truncated) - text: root.toolTipText ? root.toolTipText : root.text - font.pointSize: root.toolTipFontSize ? root.toolTipFontSize : root.font.pointSize - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - acceptedButtons: Qt.NoButton - hoverEnabled: true - } -} diff --git a/src/qml/Haruna/Components/SelectActionPopup.qml b/src/qml/Haruna/Components/SelectActionPopup.qml deleted file mode 100644 index 814a707..0000000 --- a/src/qml/Haruna/Components/SelectActionPopup.qml +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import org.kde.kirigami 2.11 as Kirigami - -Popup { - id: root - - property string headerTitle - property int buttonIndex: -1 - - signal actionSelected(string actionName) - - implicitHeight: parent.height * 0.9 - implicitWidth: parent.width * 0.9 - modal: true - anchors.centerIn: parent - focus: true - - onOpened: { - filterActionsField.text = "" - filterActionsField.focus = true - } - - onActionSelected: close() - - Action { - shortcut: "ctrl+f" - onTriggered: filterActionsField.forceActiveFocus(Qt.ShortcutFocusReason) - } - - ColumnLayout { - anchors.fill: parent - - Kirigami.Heading { - text: root.headerTitle - } - - Label { - text: i18n("Double click to set action") - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop - } - - TextField { - id: filterActionsField - - placeholderText: i18n("Type to filter...") - focus: true - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop - KeyNavigation.up: actionsListView - KeyNavigation.down: clearActionButton - - onTextChanged: { - const menuModel = actionsListView.actionsList - actionsListView.model = menuModel.filter(action => action.toLowerCase().includes(text)) - } - } - Button { - id: clearActionButton - - Layout.fillWidth: true - text: i18n("Clear current action") - KeyNavigation.up: filterActionsField - KeyNavigation.down: actionsListView - onClicked: actionSelected("") - Keys.onEnterPressed: actionSelected("") - Keys.onReturnPressed: actionSelected("") - } - - ListView { - id: actionsListView - - property var actionsList: Object.keys(window.appActions).sort() - - implicitHeight: 30 * model.count - model: actionsList - spacing: 1 - clip: true - currentIndex: focus ? 0 : -1 - delegate: Kirigami.BasicListItem { - height: 30 - width: root.width - label: modelData - reserveSpaceForIcon: false - onDoubleClicked: actionSelected(modelData) - Keys.onEnterPressed: actionSelected(modelData) - Keys.onReturnPressed: actionSelected(modelData) - } - - Layout.fillWidth: true - Layout.fillHeight: true - Layout.alignment: Qt.AlignTop - KeyNavigation.up: clearActionButton - KeyNavigation.down: filterActionsField - Keys.onPressed: { - if (event.key === Qt.Key_End) { - actionsListView.currentIndex = actionsListView.count - 1 - actionsListView.positionViewAtIndex(actionsListView.currentIndex,ListView.Center) - } - if (event.key === Qt.Key_Home) { - actionsListView.currentIndex = 0 - actionsListView.positionViewAtIndex(actionsListView.currentIndex,ListView.Center) - } - } - } - } -} diff --git a/src/qml/Haruna/Components/SettingsBasePage.qml b/src/qml/Haruna/Components/SettingsBasePage.qml deleted file mode 100644 index 0d7553a..0000000 --- a/src/qml/Haruna/Components/SettingsBasePage.qml +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import QtQml 2.12 - -import org.kde.kirigami 2.11 as Kirigami -import org.kde.haruna 1.0 - -Kirigami.ScrollablePage { - id: root - - property bool hasHelp: false - property string helpFile: "" - property string docPage: "" - - actions { - contextualActions: [ - Kirigami.Action { - text: qsTr("Help!") - iconName: "system-help" - Kirigami.Action { - text: qsTr("Haruna help window (english only)") - enabled: root.hasHelp - onTriggered: root.hasHelp ? helpWindow.show() : undefined - } - Kirigami.Action { - text: qsTr("KHelpCenter") - enabled: root.docPage !== "" - onTriggered: enabled ? app.openDocs(root.docPage) : undefined - } - }, - Kirigami.Action { - text: qsTr("Open config ...") - iconName: "folder" - Kirigami.Action { - text: qsTr("File") - onTriggered: Qt.openUrlExternally(app.configFilePath) - } - Kirigami.Action { - text: qsTr("Folder") - onTriggered: Qt.openUrlExternally(app.configFolderPath) - } - } - ] - } - -} diff --git a/src/qml/Haruna/Components/SettingsHeader.qml b/src/qml/Haruna/Components/SettingsHeader.qml deleted file mode 100644 index f18263c..0000000 --- a/src/qml/Haruna/Components/SettingsHeader.qml +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import org.kde.kirigami 2.11 as Kirigami - -ColumnLayout { - id: root - - property string text: "" - property int topMargin: Kirigami.Units.gridUnit - - spacing: 0 - - Item { - width: 1 - height: root.topMargin - visible: root.topMargin > 0 - } - - RowLayout { - Rectangle { - width: Kirigami.Units.gridUnit - height: 1 - color: Kirigami.Theme.alternateBackgroundColor - } - - Kirigami.Heading { - text: root.text - } - - Rectangle { - height: 1 - color: Kirigami.Theme.alternateBackgroundColor - Layout.fillWidth: true - } - } -} diff --git a/src/qml/Haruna/Components/SubtitlesFolders.qml b/src/qml/Haruna/Components/SubtitlesFolders.qml deleted file mode 100644 index 8661908..0000000 --- a/src/qml/Haruna/Components/SubtitlesFolders.qml +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import org.kde.kirigami 2.11 as Kirigami - -// Subtitles Folders -Item { - id: root - - // prevent creating multiple empty items - // until the new one has been saved - property bool canAddFolder: true - - Layout.fillWidth: true - implicitHeight: sectionTitle.height + sfListView.implicitHeight + sfAddFolder.height + 25 - - Label { - id: sectionTitle - - text: i18n("Load subtitles from") - bottomPadding: 10 - } - - ListView { - id: sfListView - property int sfDelegateHeight: 40 - - anchors.top: sectionTitle.bottom - anchors.left: parent.left - anchors.right: parent.right - implicitHeight: count > 5 - ? 5 * sfListView.sfDelegateHeight + (sfListView.spacing * 4) - : count * sfListView.sfDelegateHeight + (sfListView.spacing * (count - 1)) - spacing: 5 - clip: true - model: subsFoldersModel - Layout.fillWidth: true - ScrollBar.vertical: ScrollBar { id: scrollBar } - delegate: Rectangle { - id: sfDelegate - width: root.width - height: sfListView.sfDelegateHeight - color: Kirigami.Theme.alternateBackgroundColor - - Loader { - id: sfLoader - anchors.fill: parent - sourceComponent: model.display === "" ? sfEditComponent : sfDisplayComponent - } - - Component { - id: sfDisplayComponent - - RowLayout { - - Label { - id: sfLabel - text: model.display - leftPadding: 10 - Layout.fillWidth: true - } - - Button { - icon.name: "edit-entry" - flat: true - onClicked: { - sfLoader.sourceComponent = sfEditComponent - } - } - - Item { width: scrollBar.width } - } - } // Component: display - - Component { - id: sfEditComponent - - RowLayout { - - TextField { - id: editField - leftPadding: 10 - text: model.display - Layout.leftMargin: 5 - Layout.fillWidth: true - Component.onCompleted: editField.forceActiveFocus(Qt.MouseFocusReason) - } - - Button { - property bool canDelete: editField.text === "" - icon.name: "delete" - flat: true - onClicked: { - if (!canDelete) { - text = i18n("Confirm deletion") - canDelete = true - return - } - - if (model.row === sfListView.count - 1) { - root.canAddFolder = true - } - subsFoldersModel.deleteFolder(model.row) - const rows = sfListView.count - sfListView.implicitHeight = rows > 5 - ? 5 * sfListView.sfDelegateHeight + (sfListView.spacing * 4) - : rows * sfListView.sfDelegateHeight + (sfListView.spacing * (rows - 1)) - - } - ToolTip { - text: i18n("Delete this folder from list") - } - } - - Button { - icon.name: "dialog-ok" - flat: true - enabled: editField.text !== "" ? true : false - onClicked: { - subsFoldersModel.updateFolder(editField.text, model.row) - sfLoader.sourceComponent = sfDisplayComponent - if (model.row === sfListView.count - 1) { - root.canAddFolder = true - } - } - ToolTip { - text: i18n("Save changes") - } - } - - Item { width: scrollBar.width } - } - } // Component: edit - } // delegate: Rectangle - } - - Item { - id: spacer - anchors.top: sfListView.bottom - height: 5 - } - - Button { - id: sfAddFolder - anchors.top: spacer.bottom - icon.name: "list-add" - text: i18n("Add new folder") - enabled: root.canAddFolder - onClicked: { - subsFoldersModel.addFolder() - const rows = sfListView.count - sfListView.implicitHeight = rows > 5 - ? 5 * sfListView.sfDelegateHeight + (sfListView.spacing * 4) - : rows * sfListView.sfDelegateHeight + (sfListView.spacing * (rows - 1)) - root.canAddFolder = false - } - } -} diff --git a/src/qml/Haruna/Components/qmldir b/src/qml/Haruna/Components/qmldir deleted file mode 100644 index 1802065..0000000 --- a/src/qml/Haruna/Components/qmldir +++ /dev/null @@ -1,13 +0,0 @@ -# -# SPDX-FileCopyrightText: 2021 George Florea Bănuș -# -# SPDX-License-Identifier: CC-BY-4.0 -# - -module Haruna.Components -LabelWithTooltip 1.0 LabelWithTooltip.qml -ImageAdjustmentSlider 1.0 ImageAdjustmentSlider.qml -SettingsBasePage 1.0 SettingsBasePage.qml -SettingsHeader 1.0 SettingsHeader.qml -SubtitlesFolders 1.0 SubtitlesFolders.qml -SelectActionPopup 1.0 SelectActionPopup.qml diff --git a/src/qml/Header.qml b/src/qml/Header.qml deleted file mode 100644 index e01aa34..0000000 --- a/src/qml/Header.qml +++ /dev/null @@ -1,179 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import QtQml 2.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 - -import "Menus" - -ToolBar { - id: root - - property var audioTracks - property var subtitleTracks - - position: ToolBar.Header - visible: !window.isFullScreen() && GeneralSettings.showHeader - - RowLayout { - id: headerRow - - width: parent.width - - ToolButton { - action: actions.openAction - focusPolicy: Qt.NoFocus - } - - ToolButton { - action: actions.openUrlAction - focusPolicy: Qt.NoFocus - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.MiddleButton - onClicked: { - openUrlTextField.clear() - openUrlTextField.paste() - window.openFile(openUrlTextField.text, true, false) - } - } - } - - ToolSeparator { - padding: vertical ? 10 : 2 - topPadding: vertical ? 2 : 10 - bottomPadding: vertical ? 2 : 10 - - contentItem: Rectangle { - implicitWidth: parent.vertical ? 1 : 24 - implicitHeight: parent.vertical ? 24 : 1 - color: FishUI.Theme.textColor - } - } - - ToolButton { - id: subtitleMenuButton - - property var model: 0 - - text: qsTr("Subtitles") - icon.name: "add-subtitle" - focusPolicy: Qt.NoFocus - - onClicked: { - if (subtitleMenuButton.model === 0) { - subtitleMenuButton.model = mpv.subtitleTracksModel - } - - subtitleMenu.visible = !subtitleMenu.visible - } - - Menu { - id: subtitleMenu - - y: parent.height - - Menu { - id: secondarySubtitleMenu - - title: qsTr("Secondary Subtitle") - - Instantiator { - id: secondarySubtitleMenuInstantiator - model: subtitleMenuButton.model - onObjectAdded: secondarySubtitleMenu.insertItem( index, object ) - onObjectRemoved: secondarySubtitleMenu.removeItem( object ) - delegate: MenuItem { - enabled: model.id !== mpv.subtitleId || model.id === 0 - checkable: true - checked: model.id === mpv.secondarySubtitleId - text: model.text - onTriggered: mpv.secondarySubtitleId = model.id - } - } - } - - MenuSeparator {} - - MenuItem { - text: qsTr("Primary Subtitle") - hoverEnabled: false - } - - Instantiator { - id: primarySubtitleMenuInstantiator - model: subtitleMenuButton.model - onObjectAdded: subtitleMenu.addItem( object ) - onObjectRemoved: subtitleMenu.removeItem( object ) - delegate: MenuItem { - enabled: model.id !== mpv.secondarySubtitleId || model.id === 0 - checkable: true - checked: model.id === mpv.subtitleId - text: model.text - onTriggered: mpv.subtitleId = model.id - } - } - } - } - - ToolButton { - text: qsTr("Audio") - icon.name: "audio-volume-high" - focusPolicy: Qt.NoFocus - - onClicked: { - if (audioMenuInstantiator.model === 0) { - audioMenuInstantiator.model = mpv.audioTracksModel - } - audioMenu.visible = !audioMenu.visible - } - - Menu { - id: audioMenu - - y: parent.height - - Instantiator { - id: audioMenuInstantiator - - model: 0 - onObjectAdded: audioMenu.insertItem( index, object ) - onObjectRemoved: audioMenu.removeItem( object ) - delegate: MenuItem { - id: audioMenuItem - checkable: true - checked: model.id === mpv.audioId - text: model.text - onTriggered: mpv.audioId = model.id - } - } - } - } - - Item { - Layout.fillWidth: true - } - - ToolButton { - action: actions.configureAction - focusPolicy: Qt.NoFocus - } - - ToolButton { - // using `action: actions.quitApplicationAction` breaks the action - // doens't work on the first try in certain circumstances - text: actions.quitApplicationAction.text - icon: actions.quitApplicationAction.icon - focusPolicy: Qt.NoFocus - onClicked: actions.quitApplicationAction.trigger() - } - } -} diff --git a/src/qml/Menus/AudioMenu.qml b/src/qml/Menus/AudioMenu.qml deleted file mode 100644 index 4110bbb..0000000 --- a/src/qml/Menus/AudioMenu.qml +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQml 2.12 -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -Menu { - id: root - - title: i18n("&Audio") - - Menu { - id: audioMenu - - title: i18n("&Primary Track") - - Instantiator { - id: audioMenuInstantiator - model: 0 - onObjectAdded: audioMenu.insertItem( index, object ) - onObjectRemoved: audioMenu.removeItem( object ) - delegate: MenuItem { - id: audioMenuItem - checkable: true - checked: model.id === mpv.audioId - text: model.text - onTriggered: mpv.audioId = model.id - } - } - Connections { - target: mpv - onFileLoaded: { - audioMenuInstantiator.model = mpv.audioTracksModel - } - } - } - - MenuSeparator {} - - MenuItem { action: actions["muteAction"] } - MenuItem { action: actions["volumeUpAction"] } - MenuItem { action: actions["volumeDownAction"] } -} diff --git a/src/qml/Menus/FileMenu.qml b/src/qml/Menus/FileMenu.qml deleted file mode 100644 index a1d472b..0000000 --- a/src/qml/Menus/FileMenu.qml +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -Menu { - id: root - - title: i18n("&File") - - MenuItem { action: actions["openAction"] } - MenuItem { action: actions["openUrlAction"] } - - MenuSeparator {} - - MenuItem { action: actions["quitApplicationAction"] } -} diff --git a/src/qml/Menus/HelpMenu.qml b/src/qml/Menus/HelpMenu.qml deleted file mode 100644 index a840040..0000000 --- a/src/qml/Menus/HelpMenu.qml +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -Menu { - id: root - - title: i18n("&Help") - - MenuItem { action: actions["aboutHarunaAction"] } -} diff --git a/src/qml/Menus/PlaybackMenu.qml b/src/qml/Menus/PlaybackMenu.qml deleted file mode 100644 index 939b922..0000000 --- a/src/qml/Menus/PlaybackMenu.qml +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -Menu { - id: root - - title: i18n("&Playback") - - MenuItem { action: actions["playPauseAction"] } - MenuItem { action: actions["playNextAction"] } - MenuItem { action: actions["playPreviousAction"] } - - MenuSeparator {} - - MenuItem { action: actions["increasePlayBackSpeedAction"] } - MenuItem { action: actions["decreasePlayBackSpeedAction"] } - MenuItem { action: actions["resetPlayBackSpeedAction"] } - - MenuSeparator {} - - Menu { - title: "Seek" - MenuItem { action: actions["seekForwardSmallAction"] } - MenuItem { action: actions["seekBackwardSmallAction"] } - - MenuSeparator {} - - MenuItem { action: actions["seekForwardMediumAction"] } - MenuItem { action: actions["seekBackwardMediumAction"] } - - MenuSeparator {} - - MenuItem { action: actions["seekForwardBigAction"] } - MenuItem { action: actions["seekBackwardBigAction"] } - - MenuSeparator {} - - MenuItem { action: actions["seekNextSubtitleAction"] } - MenuItem { action: actions["seekPrevSubtitleAction"] } - - MenuSeparator {} - - MenuItem { action: actions["seekPreviousChapterAction"] } - MenuItem { action: actions["seekNextChapterAction"] } - - MenuSeparator {} - - MenuItem { action: actions["frameStepAction"] } - MenuItem { action: actions["frameBackStepAction"] } - } -} diff --git a/src/qml/Menus/SettingsMenu.qml b/src/qml/Menus/SettingsMenu.qml deleted file mode 100644 index bfcd39b..0000000 --- a/src/qml/Menus/SettingsMenu.qml +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -Menu { - id: root - - title: i18n("&Settings") - - MenuItem { action: actions["configureAction"] } - MenuItem { action: actions["configureShortcutsAction"] } -} diff --git a/src/qml/Menus/SubtitlesMenu.qml b/src/qml/Menus/SubtitlesMenu.qml deleted file mode 100644 index a179c04..0000000 --- a/src/qml/Menus/SubtitlesMenu.qml +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQml 2.12 -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -Menu { - id: root - - title: i18n("&Subtitles") - - Menu { - id: primarySubtitleMenu - - title: i18n("Primary Subtitle") - onOpened: primarySubtitleMenuInstantiator.model = mpv.subtitleTracksModel - - Instantiator { - id: primarySubtitleMenuInstantiator - model: 0 - onObjectAdded: primarySubtitleMenu.insertItem( index, object ) - onObjectRemoved: primarySubtitleMenu.removeItem( object ) - delegate: MenuItem { - enabled: model.id !== mpv.secondarySubtitleId || model.id === 0 - checkable: true - checked: model.id === mpv.subtitleId - text: model.text - onTriggered: mpv.subtitleId = model.id - } - } - } - - Menu { - id: secondarySubtitleMenu - - title: i18n("Secondary Subtitle") - onOpened: secondarySubtitleMenuInstantiator.model = mpv.subtitleTracksModel - - Instantiator { - id: secondarySubtitleMenuInstantiator - model: 0 - onObjectAdded: secondarySubtitleMenu.insertItem( index, object ) - onObjectRemoved: secondarySubtitleMenu.removeItem( object ) - delegate: MenuItem { - enabled: model.id !== mpv.subtitleId || model.id === 0 - checkable: true - checked: model.id === mpv.secondarySubtitleId - text: model.text - onTriggered: mpv.secondarySubtitleId = model.id - } - } - } - - MenuSeparator {} - - MenuItem { action: actions["subtitleQuickenAction"] } - MenuItem { action: actions["subtitleDelayAction"] } - MenuItem { action: actions["subtitleToggleAction"] } -} diff --git a/src/qml/Menus/TrackMenuItems.qml b/src/qml/Menus/TrackMenuItems.qml deleted file mode 100644 index c51e3ad..0000000 --- a/src/qml/Menus/TrackMenuItems.qml +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQml 2.12 - -Instantiator { - id: root - - property bool isFirst: true - property var menu - - signal subtitleChanged(int id, int index) - - model: 0 - onObjectAdded: menu.addItem( object ) - onObjectRemoved: menu.removeItem( object ) - delegate: MenuItem { - checkable: true - checked: isFirst ? model.isFirstTrack : model.isSecondTrack - text: model.text - onTriggered: subtitleChanged(model.id, model.index) - } -} diff --git a/src/qml/Menus/ViewMenu.qml b/src/qml/Menus/ViewMenu.qml deleted file mode 100644 index 25a0c39..0000000 --- a/src/qml/Menus/ViewMenu.qml +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -Menu { - id: root - - title: i18n("&View") - - MenuItem { - action: actions["toggleMenuBarAction"] - text: menuBar.visible ? i18n("Hide Menu Bar") : i18n("Show Menu Bar") - } - MenuItem { - action: actions["toggleHeaderAction"] - text: header.visible ? i18n("Hide Header") : i18n("Show Header") - } -} diff --git a/src/qml/MpvVideo.qml b/src/qml/MpvVideo.qml deleted file mode 100644 index 0b16f95..0000000 --- a/src/qml/MpvVideo.qml +++ /dev/null @@ -1,392 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Window 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import mpv 1.0 - -import FishUI 1.0 as FishUI - -import org.kde.haruna 1.0 - -MpvObject { - id: root - - property int mouseX: mouseArea.mouseX - property int mouseY: mouseArea.mouseY - - signal setSubtitle(int id) - signal setSecondarySubtitle(int id) - signal setAudio(int id) - - width: parent.width - height: window.isFullScreen() ? parent.height : parent.height - footer.height - anchors.left: PlaylistSettings.overlayVideo - ? parent.left - : (PlaylistSettings.position === "left" ? playList.right : parent.left) - anchors.right: PlaylistSettings.overlayVideo - ? parent.right - : (PlaylistSettings.position === "right" ? playList.left : parent.right) - anchors.top: parent.top - anchors.bottom: parent.bottom - volume: GeneralSettings.volume - - onSetSubtitle: { - setProperty("sid", id) - } - - onSetSecondarySubtitle: { - setProperty("secondary-sid", id) - } - - onSetAudio: { - setProperty("aid", id) - } - - onReady: { - setProperty("screenshot-template", VideoSettings.screenshotTemplate) - setProperty("screenshot-format", VideoSettings.screenshotFormat) - const preferredAudioTrack = AudioSettings.preferredTrack - setProperty("aid", preferredAudioTrack === 0 ? "auto" : preferredAudioTrack) - setProperty("alang", AudioSettings.preferredLanguage) - - const preferredSubTrack = SubtitlesSettings.preferredTrack - setProperty("sid", preferredSubTrack === 0 ? "auto" : preferredSubTrack) - setProperty("slang", SubtitlesSettings.preferredLanguage) - setProperty("sub-file-paths", SubtitlesSettings.subtitlesFolders.join(":")) - - if (app.argument(0) !== "") { - window.openFile(app.argument(0), true, PlaylistSettings.loadSiblings) - } else { - // open last played file - if (app.isYoutubePlaylist(GeneralSettings.lastPlayedFile)) { - getYouTubePlaylist(GeneralSettings.lastPlayedFile) - playList.isYouTubePlaylist = true - } else { - // file is local, open normally - window.openFile(GeneralSettings.lastPlayedFile, false, PlaylistSettings.loadSiblings) - } - } - } - - onYoutubePlaylistLoaded: { - mpv.command(["loadfile", playlistModel.getPath(GeneralSettings.lastPlaylistIndex)]) - playlistModel.setPlayingVideo(GeneralSettings.lastPlaylistIndex) - - playList.setPlayListScrollPosition() - } - - onFileStarted: { - if (typeof getProperty("path") === "string" && getProperty("path").startsWith("http")) { - loadingIndicatorParent.visible = true - } - } - - onFileLoaded: { - loadingIndicatorParent.visible = false - header.audioTracks = getProperty("track-list").filter(track => track["type"] === "audio") - header.subtitleTracks = getProperty("track-list").filter(track => track["type"] === "sub") - - if (playList.playlistView.count <= 1) { - setProperty("loop-file", "inf") - } - - setProperty("ab-loop-a", "no") - setProperty("ab-loop-b", "no") - - mpv.pause = loadTimePosition() !== 0 - position = loadTimePosition() - } - - onChapterChanged: { - if (!PlaybackSettings.skipChapters) { - return - } - - const chapters = mpv.getProperty("chapter-list") - const chaptersToSkip = PlaybackSettings.chaptersToSkip - if (chapters.length === 0 || chaptersToSkip === "") { - return - } - - const words = chaptersToSkip.split(",") - for (let i = 0; i < words.length; ++i) { - if (chapters[mpv.chapter] && chapters[mpv.chapter].title.toLowerCase().includes(words[i].trim())) { - actions.seekNextChapterAction.trigger() - if (PlaybackSettings.showOsdOnSkipChapters) { - osd.message(i18n("Skipped chapter: %1").arg(chapters[mpv.chapter-1].title)) - } - // a chapter title can match multiple words - // return to prevent skipping multiple chapters - return - } - } - } - - onEndFile: { - if (reason === "error") { - if (playlistModel.rowCount() === 0) { - return - } - - const title = playlistModel.getItem(playlistModel.getPlayingVideo()).mediaTitle() - osd.message(i18n("Could not play: %1").arg(title)) - // only skip to next video if it's a youtube playList - // to do: figure out why playback fails and act accordingly - if (!playList.isYouTubePlaylist) { - return - } - } - const nextFileRow = playlistModel.getPlayingVideo() + 1 - if (nextFileRow < playList.playlistView.count) { - const nextFile = playlistModel.getPath(nextFileRow) - playlistModel.setPlayingVideo(nextFileRow) - loadFile(nextFile, !playList.isYouTubePlaylist) - } else { - // Last file in playlist - if (PlaylistSettings.repeat) { - playlistModel.setPlayingVideo(0) - loadFile(playlistModel.getPath(0), !playList.isYouTubePlaylist) - } - } - } - - onPauseChanged: { - if (pause) { - footer.playPauseButton.icon.name = "media-playback-start" - lockManager.setInhibitionOff() - } else { - footer.playPauseButton.icon.name = "media-playback-pause" - lockManager.setInhibitionOn() - } - } - - Timer { - id: saveWatchLaterFileTimer - - interval: 1000 - running: !mpv.pause - repeat: true - - onTriggered: handleTimePosition() - } - - Timer { - id: hideCursorTimer - - property double tx: mouseArea.mouseX - property double ty: mouseArea.mouseY - property int timeNotMoved: 0 - - running: window.isFullScreen() && mouseArea.containsMouse - repeat: true - interval: 50 - - onTriggered: { - if (mouseArea.mouseX === tx && mouseArea.mouseY === ty) { - if (timeNotMoved > 2000) { - app.hideCursor() - } - } else { - app.showCursor() - timeNotMoved = 0 - } - tx = mouseArea.mouseX - ty = mouseArea.mouseY - timeNotMoved += interval - } - } - - // Window move - DragHandler { - acceptedDevices: PointerDevice.GenericPointer - grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything - onActiveChanged: if (active) window.helper.startSystemMove(window) - } - - MouseArea { - id: mouseArea - - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - anchors.fill: parent - hoverEnabled: true - - onPositionChanged: { - if (!playList.canToggleWithMouse || playList.playlistView.count <= 1) { - return - } -// if (playList.position === "right") { -// if (mouseX > width - 50) { -// playList.state = "visible" -// } -// if (mouseX < width - playList.width - 20) { -// playList.state = "hidden" -// } -// } else { -// if (mouseX < 50) { -// playList.state = "visible" -// } -// if (mouseX > playList.width + 20) { -// playList.state = "hidden" -// } -// } - } - - onWheel: { - if (wheel.angleDelta.y > 0) { - if (MouseSettings.scrollUp) { - actions[MouseSettings.scrollUp].trigger() - } - } else if (wheel.angleDelta.y) { - if (MouseSettings.scrollDown) { - actions[MouseSettings.scrollDown].trigger() - } - } - } - - onPressed: { - focus = true - - // Hide play list - playList.state = "hidden" - - if (mouse.button === Qt.LeftButton) { - if (MouseSettings.left) { - actions[MouseSettings.left].trigger() - } - } else if (mouse.button === Qt.MiddleButton) { - if (MouseSettings.middle) { - actions[MouseSettings.middle].trigger() - } - } else if (mouse.button === Qt.RightButton) { - if (MouseSettings.right) { - actions[MouseSettings.right].trigger() - } - } - } - - onDoubleClicked: { - if (mouse.button === Qt.LeftButton) { - if (MouseSettings.leftx2) { - actions[MouseSettings.leftx2].trigger() - } - } else if (mouse.button === Qt.MiddleButton) { - if (MouseSettings.middlex2) { - actions[MouseSettings.middlex2].trigger() - } - } else if (mouse.button === Qt.RightButton) { - if (MouseSettings.rightx2) { - actions[MouseSettings.rightx2].trigger() - } - } - } - } - - DropArea { - id: dropArea - - property var acceptedSubtitleTypes: ["application/x-subrip", "text/x-ssa"] - - anchors.fill: parent - keys: ["text/uri-list"] - - onDropped: { - if (acceptedSubtitleTypes.includes(app.mimeType(drop.urls[0]))) { - const subFile = drop.urls[0].replace("file://", "") - command(["sub-add", drop.urls[0], "select"]) - } - - if (app.mimeType(drop.urls[0]).startsWith("video/") || app.mimeType(drop.urls[0]).startsWith("audio/")) { - window.openFile(drop.urls[0], true, PlaylistSettings.loadSiblings) - } - } - } - - Connections { - target: mediaPlayer2Player - - function onPlaypause() { - actions.playPauseAction.trigger() - } - - function onPlay() { - root.pause = false - } - - function onPause() { - root.pause = true - } - - function onStop() { - root.position = 0 - root.pause = true - } - - function onNext() { - actions.playNextAction.trigger() - } - - function onPrevious() { - actions.playPreviousAction.trigger() - } - - function onSeek() { - root.command(["add", "time-pos", offset]) - } - - function onOpenUri() { - root.command(["add", "time-pos", offset]) - } - } - - Rectangle { - id: loadingIndicatorParent - - visible: false - anchors.centerIn: parent - color: { - let color = FishUI.Theme.backgroundColor - Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, 0.2) - } - - FishUI.IconItem { - id: loadingIndicator - - source: "view-refresh" - anchors.centerIn: parent - width: FishUI.Units.iconSizes.large - height: FishUI.Units.iconSizes.large - - RotationAnimator { - target: loadingIndicator; - from: 0; - to: 360; - duration: 1500 - loops: Animation.Infinite - running: true - } - - Component.onCompleted: { - parent.width = width + 10 - parent.height = height + 10 - } - } - } - - Component.onCompleted: { - mediaPlayer2Player.mpv = root - } - - function handleTimePosition() { - if (mpv.position < mpv.duration - 10) { - saveTimePosition() - } else { - resetTimePosition() - } - } -} diff --git a/src/qml/Osd.qml b/src/qml/Osd.qml deleted file mode 100644 index 1c0e185..0000000 --- a/src/qml/Osd.qml +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 - -Item { - id: root - - property alias label: label - - Label { - id: label - x: 10 - y: 10 - visible: false - color: FishUI.Theme.textColor - background: Rectangle { - color: FishUI.Theme.backgroundColor - } - padding: 5 - font.pointSize: parseInt(GeneralSettings.osdFontSize) - } - - Timer { - id: timer - running: false - repeat: false - interval: 3000 - - onTriggered: { - label.visible = false - } - } - - function message(text) { - const osdFontSize = parseInt(GeneralSettings.osdFontSize) - label.text = text - if (osdFontSize === 0) { - return; - } - - if(label.visible) { - timer.restart() - } else { - timer.start() - } - label.visible = true - } - -} diff --git a/src/qml/PlayList.qml b/src/qml/PlayList.qml deleted file mode 100644 index 64378aa..0000000 --- a/src/qml/PlayList.qml +++ /dev/null @@ -1,164 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * SPDX-FileCopyrightText: 2021 Reion Wong - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import QtGraphicalEffects 1.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 - -Item { - id: root - - property alias scrollPositionTimer: scrollPositionTimer - property alias playlistView: playlistView - // property bool canToggleWithMouse: PlaylistSettings.canToggleWithMouse - property bool canToggleWithMouse: true - property string position: PlaylistSettings.position - property int rowHeight: PlaylistSettings.rowHeight - property int bigFont: PlaylistSettings.bigFontFullscreen - property bool isYouTubePlaylist: false - - z: 9999 - - height: mpv.height - FishUI.Units.largeSpacing * 6 - width: { - if (PlaylistSettings.style === "compact") { - return FishUI.Units.gridUnit * 20 - } else { - const w = FishUI.Units.gridUnit * 30 - return (parent.width * 0.33) < w ? w : parent.width * 0.33 - } - } - x: position === "right" ? parent.width : -width - y: FishUI.Units.largeSpacing * 3 - state: "hidden" - - ScrollView { - id: playlistScrollView - - z: 20 - anchors.fill: parent - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - - ListView { - id: playlistView - model: mpv.playlistModel - spacing: 1 - delegate: PlayListItem { - onDoubleClicked: root.state = "hidden" - } - } - } - - Timer { - id: scrollPositionTimer - interval: 50 - running: true - repeat: true - - onTriggered: { - setPlayListScrollPosition() - scrollPositionTimer.stop() - } - } - - ShaderEffectSource { - id: shaderEffect - - visible: PlaylistSettings.overlayVideo - anchors.fill: playlistScrollView - sourceItem: mpv - sourceRect: position === "right" - ? Qt.rect(mpv.width - root.width, mpv.y, root.width, root.height) - : Qt.rect(0, 0, root.width, root.height) - } - - FastBlur { - visible: PlaylistSettings.overlayVideo - anchors.fill: shaderEffect - radius: 100 - source: shaderEffect - } - - Rectangle { - anchors.fill: parent - color: FishUI.Theme.backgroundColor - opacity: 0.7 - } - - states: [ - State { - name: "hidden" - PropertyChanges { target: root; x: position === "right" ? parent.width : -width } - PropertyChanges { target: root; visible: false } - }, - State { - name : "visible" - PropertyChanges { target: root; x: position === "right" ? parent.width - root.width - FishUI.Units.largeSpacing : 0 } - PropertyChanges { target: root; visible: true } - } - ] - - transitions: [ - Transition { - from: "visible" - to: "hidden" - - SequentialAnimation { - NumberAnimation { - target: root - property: "x" - duration: 150 - easing.type: Easing.InQuad - } - PropertyAction { - target: root - property: "visible" - value: false - } - } - }, - Transition { - from: "hidden" - to: "visible" - - SequentialAnimation { - PropertyAction { - target: root - property: "visible" - value: true - } - NumberAnimation { - target: root - property: "x" - duration: 150 - easing.type: Easing.OutQuad - } - } - } - ] - - layer.enabled: true - layer.effect: OpacityMask { - maskSource: Item { - width: root.width - height: root.height - - Rectangle { - anchors.fill: parent - radius: FishUI.Theme.bigRadius - } - } - } - - function setPlayListScrollPosition() { - playlistView.positionViewAtIndex(playlistView.model.playingVideo, ListView.Beginning) - } -} diff --git a/src/qml/Settings/Audio.qml b/src/qml/Settings/Audio.qml deleted file mode 100644 index 8f57cbd..0000000 --- a/src/qml/Settings/Audio.qml +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - hasHelp: false - helpFile: "" - - GridLayout { - id: content - - columns: 2 - - Label { - text: i18n("Preferred language") - Layout.alignment: Qt.AlignRight - } - TextField { - text: AudioSettings.preferredLanguage - placeholderText: "eng,ger etc." - Layout.fillWidth: true - onTextEdited: { - AudioSettings.preferredLanguage = text - AudioSettings.save() - mpv.setProperty("alang", text) - } - - ToolTip { - text: i18n("Do not use spaces.") - } - } - - - Label { - text: i18n("Preferred track") - Layout.alignment: Qt.AlignRight - } - SpinBox { - from: 0 - to: 100 - value: AudioSettings.preferredTrack - editable: true - onValueChanged: { - AudioSettings.preferredTrack = value - AudioSettings.save() - if (value === 0) { - mpv.setProperty("aid", "auto") - } else { - mpv.setProperty("aid", value) - } - } - } - - Item { - width: FishUI.Units.gridUnit - height: FishUI.Units.gridUnit - } - } -} diff --git a/src/qml/Settings/CustomCommands.qml b/src/qml/Settings/CustomCommands.qml deleted file mode 100644 index 1077bdb..0000000 --- a/src/qml/Settings/CustomCommands.qml +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import org.kde.kirigami 2.11 as Kirigami -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - hasHelp: true - helpFile: ":/CustomCommandsSettings.html" - docPage: "help:/haruna/CustomCommandsSettings.html" - - Component { - id: customCommandDelegate - - Kirigami.AbstractListItem { - id: customCommandItem - - height: Kirigami.Units.gridUnit * 3 - padding: 0 - - contentItem: RowLayout { - anchors.fill: parent - spacing: 0 - - Kirigami.ListItemDragHandle { - listItem: customCommandItem - listView: customCommandsView - onMoveRequested: customCommandsModel.moveRows(oldIndex, newIndex) - } - - Kirigami.Icon { - source: model.type === "shortcut" ? "configure-shortcuts" : "code-context" - width: Kirigami.Units.iconSizes.small - height: Kirigami.Units.iconSizes.small - } - - LabelWithTooltip { - text: model.command - elide: Text.ElideRight - - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - Layout.fillWidth: true - Layout.margins: Kirigami.Units.largeSpacing - } - - ToolButton { - text: i18n("Shortcut") - icon.name: "configure-shortcuts" - visible: model.type === "shortcut" - onClicked: app.configureShortcuts(model.command) - - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - } - - ToolButton { - icon.name: "edit-entry" - Layout.rightMargin: Kirigami.Units.largeSpacing - onClicked: applicationWindow().pageStack.replace("qrc:/EditCustomCommand.qml", - { - command: model.command, - osdMessage: model.osdMessage, - type: model.type, - commandId: model.commandId, - index: model.index, - mode: EditCustomCommand.Mode.Edit - }) - } - } - } - } - - ListView { - id: customCommandsView - - model: customCommandsModel - delegate: Kirigami.DelegateRecycler { - width: customCommandsView.width - sourceComponent: customCommandDelegate - } - } - - footer: ToolBar { - RowLayout { - anchors.fill: parent - - ToolButton { - id: addButton - - text: i18n("&Add") - icon.name: "list-add" - onClicked: applicationWindow().pageStack.replace("qrc:/EditCustomCommand.qml") - Layout.alignment: Qt.AlignRight - } - } - } - -} diff --git a/src/qml/Settings/EditCustomCommand.qml b/src/qml/Settings/EditCustomCommand.qml deleted file mode 100644 index 750913b..0000000 --- a/src/qml/Settings/EditCustomCommand.qml +++ /dev/null @@ -1,168 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - property string command: "" - property string osdMessage: "" - property string type: "shortcut" - property string commandId: "" - property int index: -1 - property int mode: EditCustomCommand.Mode.Create - - enum Mode { - Create = 0, - Edit - } - - hasHelp: true - helpFile: ":/CustomCommandsSettings.html" - - Action { - shortcut: "esc" - onTriggered: applicationWindow().pageStack.replace("qrc:/CustomCommands.qml") - } - - GridLayout { - columns: 2 - - Label { - text: i18n("Command") - Layout.alignment: Qt.AlignRight - } - - TextField { - id: commandTextField - - text: root.command - placeholderText: "add volume +10" - Layout.fillWidth: true - Component.onCompleted: forceActiveFocus() - } - - Label { - text: i18n("OSD Message") - Layout.alignment: Qt.AlignRight - } - - TextField { - id: osdMessageTextField - - text: root.osdMessage - enabled: typeGroup.checkedButton.optionName === "shortcut" - placeholderText: "Filename: ${filename}" - Layout.fillWidth: true - } - - Label { - text: i18n("Type") - Layout.alignment: Qt.AlignRight | Qt.AlignTop - } - - ButtonGroup { - id: typeGroup - - buttons: typeGroupItems.children - } - - Column { - id: typeGroupItems - - spacing: FishUI.Units.largeSpacing - - RadioButton { - property string optionName: "shortcut" - - checked: optionName === root.type - text: i18n("Keyboard shortcut") - } - - RadioButton { - property string optionName: "startup" - - checked: optionName === root.type - text: i18n("Run at startup") - } - } - } - - footer: ToolBar { - RowLayout { - anchors.fill: parent - - ToolButton { - text: i18n("Delete") - icon.name: "delete" - visible: root.mode === EditCustomCommand.Mode.Edit - onClicked: { - customCommandsModel.deleteCustomCommand(root.commandId, root.index) - applicationWindow().pageStack.replace("qrc:/CustomCommands.qml") - } - } - - Item { - - Layout.fillWidth: true - } - - ToolButton { - text: i18n("Cancel") - icon.name: "dialog-cancel" - onClicked: applicationWindow().pageStack.replace("qrc:/CustomCommands.qml") - Layout.alignment: Qt.AlignRight - } - - ToolButton { - text: i18n("&Save") - icon.name: "document-save" - enabled: commandTextField.text !== "" - onClicked: saveCustomCommand() - - Layout.alignment: Qt.AlignRight - - function saveCustomCommand() { - if (commandTextField.text === "") { - return - } - if (typeGroup.checkedButton.optionName === "shortcut") { - // creates action and adds it to the action collection - // so that its shortcut can be set by the user - app.createUserAction(commandTextField.text) - } else { - // execute the user command - mpv.userCommand(commandTextField.text) - } - switch (root.mode) { - case EditCustomCommand.Mode.Create: - // save new command to config file - customCommandsModel.saveCustomCommand(commandTextField.text, - osdMessageTextField.text, - typeGroup.checkedButton.optionName) - break - case EditCustomCommand.Mode.Edit: - // update existing command - customCommandsModel.editCustomCommand(root.index, - commandTextField.text, - osdMessageTextField.text, - typeGroup.checkedButton.optionName) - break - } - applicationWindow().pageStack.replace("qrc:/CustomCommands.qml") - } - - } - } - } -} diff --git a/src/qml/Settings/General.qml b/src/qml/Settings/General.qml deleted file mode 100644 index bc6d9cc..0000000 --- a/src/qml/Settings/General.qml +++ /dev/null @@ -1,336 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import org.kde.kirigami 2.11 as Kirigami -import org.kde.haruna 1.0 - -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - hasHelp: true - helpFile: ":/GeneralSettings.html" - docPage: "help:/haruna/GeneralSettings.html" - - GridLayout { - id: content - - columns: 2 - - // OSD Font Size - Label { - text: qsTr("Osd font size") - Layout.alignment: Qt.AlignRight - } - - Item { - height: osdFontSize.height - SpinBox { - id: osdFontSize - - // used to prevent osd showing when opening the page - property bool completed: false - - editable: true - from: 0 - to: 100 - value: GeneralSettings.osdFontSize - onValueChanged: { - if (completed) { - osd.label.font.pointSize = osdFontSize.value - osd.message("Test osd font size") - GeneralSettings.osdFontSize = osdFontSize.value - GeneralSettings.save() - } - } - Component.onCompleted: completed = true - } - Layout.fillWidth: true - } - - // Volume Step - Label { - text: qsTr("Volume step") - Layout.alignment: Qt.AlignRight - } - - Item { - height: volumeStep.height - SpinBox { - id: volumeStep - editable: true - from: 0 - to: 100 - value: GeneralSettings.volumeStep - onValueChanged: { - if (root.visible) { - GeneralSettings.volumeStep = volumeStep.value - GeneralSettings.save() - } - } - } - Layout.fillWidth: true - } - - // Seek Small Step - Label { - text: qsTr("Seek small step") - Layout.alignment: Qt.AlignRight - } - - Item { - height: seekSmallStep.height - SpinBox { - id: seekSmallStep - editable: true - from: 0 - to: 100 - value: GeneralSettings.seekSmallStep - onValueChanged: { - GeneralSettings.seekSmallStep = seekSmallStep.value - GeneralSettings.save() - } - } - Layout.fillWidth: true - } - - // Seek Medium Step - Label { - text: qsTr("Seek medium step") - Layout.alignment: Qt.AlignRight - } - - Item { - height: seekMediumStep.height - RowLayout { - - SpinBox { - id: seekMediumStep - editable: true - from: 0 - to: 100 - value: GeneralSettings.seekMediumStep - onValueChanged: { - GeneralSettings.seekMediumStep = seekMediumStep.value - GeneralSettings.save() - } - } - - ToolButton { - icon.name: "documentinfo" - checkable: true - checked: false - - ToolTip { - text: qsTr("This is also used for mouse wheel seeking, when mouse is over the progress bar") - visible: parent.checked - delay: 0 - timeout: -1 - closePolicy: Popup.NoAutoClose - } - } - } - - Layout.fillWidth: true - } - - // Seek Big Step - Label { - text: qsTr("Seek big step") - Layout.alignment: Qt.AlignRight - } - - Item { - height: seekBigStep.height - SpinBox { - id: seekBigStep - editable: true - from: 0 - to: 100 - value: GeneralSettings.seekBigStep - onValueChanged: { - GeneralSettings.seekBigStep = seekBigStep.value - GeneralSettings.save() - } - } - Layout.fillWidth: true - } - - Label { - text: qsTr("File dialog location") - Layout.alignment: Qt.AlignRight - } - - Item { - height: fileDialogLocation.height - Layout.fillWidth: true - - TextField { - id: fileDialogLocation - - text: GeneralSettings.fileDialogLocation - onEditingFinished: { - GeneralSettings.fileDialogLocation = fileDialogLocation.text - GeneralSettings.save() - } - - ToolTip { - text: qsTr("If empty the file dialog will remember the last opened location.") - } - } - } - - SettingsHeader { - text: qsTr("Interface") - Layout.columnSpan: 2 - Layout.fillWidth: true - } - - CheckBox { - text: qsTr("Show MenuBar") - checked: GeneralSettings.showMenuBar - onCheckedChanged: { - GeneralSettings.showMenuBar = checked - GeneralSettings.save() - } - Layout.row: 8 - Layout.column: 1 - } - - CheckBox { - text: qsTr("Show Header") - checked: GeneralSettings.showHeader - onCheckedChanged: { - GeneralSettings.showHeader = checked - GeneralSettings.save() - } - Layout.row: 9 - Layout.column: 1 - } - - CheckBox { - text: qsTr("Show chapter markers") - checked: GeneralSettings.showChapterMarkers - onCheckedChanged: { - GeneralSettings.showChapterMarkers = checked - GeneralSettings.save() - } - Layout.row: 10 - Layout.column: 1 - } - - Label { - text: qsTr("Color scheme") - Layout.alignment: Qt.AlignRight - } - - ComboBox { - id: colorThemeSwitcher - - textRole: "display" - model: app.colorSchemesModel - delegate: ItemDelegate { - Kirigami.Theme.colorSet: Kirigami.Theme.View - width: colorThemeSwitcher.width - highlighted: model.display === GeneralSettings.colorScheme - contentItem: RowLayout { - Kirigami.Icon { - source: model.decoration - Layout.preferredHeight: Kirigami.Units.iconSizes.small - Layout.preferredWidth: Kirigami.Units.iconSizes.small - } - Label { - text: model.display - color: highlighted ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor - Layout.fillWidth: true - } - } - } - - onActivated: { - GeneralSettings.colorScheme = colorThemeSwitcher.textAt(index) - GeneralSettings.save() - app.activateColorScheme(GeneralSettings.colorScheme) - } - - Component.onCompleted: currentIndex = find(GeneralSettings.colorScheme) - } - - Label { - text: qsTr("GUI Style") - Layout.alignment: Qt.AlignRight - } - - ComboBox { - id: guiStyleComboBox - - textRole: "key" - model: ListModel { - id: stylesModel - - ListElement { key: "Default"; } - } - - onActivated: { - GeneralSettings.guiStyle = model.get(index).key - app.setGuiStyle(GeneralSettings.guiStyle) - // some themes can cause a crash - // the timer prevents saving the crashing theme, - // which would cause the app to crash on startup - saveGuiStyleTimer.start() - } - - Timer { - id: saveGuiStyleTimer - - interval: 1000 - running: false - repeat: false - onTriggered: GeneralSettings.save() - } - - Component.onCompleted: { - // populate the model with the available styles - for (let i = 0; i < app.availableGuiStyles().length; ++i) { - stylesModel.append({key: app.availableGuiStyles()[i]}) - } - - // set the saved style as the current item in the combo box - for (let j = 0; j < stylesModel.count; ++j) { - if (stylesModel.get(j).key === GeneralSettings.guiStyle) { - currentIndex = j - break - } - } - } - } - - CheckBox { - text: qsTr("Use Breeze icon theme") - checked: GeneralSettings.useBreezeIconTheme - onCheckedChanged: { - GeneralSettings.useBreezeIconTheme = checked - GeneralSettings.save() - } - Layout.row: 14 - Layout.column: 1 - - ToolTip { - text: qsTr("Sets the icon theme to breeze.\nRequires restart.") - } - } - - Item { - width: Kirigami.Units.gridUnit - height: Kirigami.Units.gridUnit - } - } -} diff --git a/src/qml/Settings/Mouse.qml b/src/qml/Settings/Mouse.qml deleted file mode 100644 index dc85072..0000000 --- a/src/qml/Settings/Mouse.qml +++ /dev/null @@ -1,111 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQml 2.12 -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import org.kde.kirigami 2.11 as Kirigami -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - hasHelp: false - helpFile: "" - - ColumnLayout { - id: content - - spacing: Kirigami.Units.largeSpacing - - ListModel { - id: mouseActionsModel - - ListElement { - label: "Left" - key: "left" - } - ListElement { - label: "Left double click" - key: "leftx2" - } - ListElement { - label: "Right" - key: "right" - } - ListElement { - label: "Right double click" - key: "rightx2" - } - ListElement { - label: "Middle" - key: "middle" - } - ListElement { - label: "Middle double click" - key: "middlex2" - } - ListElement { - label: "ScrollUp" - key: "scrollUp" - } - ListElement { - label: "ScrollDown" - key: "scrollDown" - } - } - - ListView { - id: mouseButtonsListView - - property int delegateHeight - - implicitHeight: delegateHeight * (mouseButtonsListView.count + 1) - model: mouseActionsModel - - delegate: Kirigami.BasicListItem { - id: delegate - - label: model.label - subtitle: MouseSettings[model.key] ? MouseSettings[model.key] : "No action set" - icon: MouseSettings[model.key] ? "checkmark" : "" - reserveSpaceForIcon: true - width: content.width - highlighted: false - - onClicked: openSelectActionPopup() - Component.onCompleted: mouseButtonsListView.delegateHeight = height - - Connections { - target: selectActionPopup - onActionSelected: { - if (selectActionPopup.buttonIndex === model.index) { - MouseSettings[model.key] = actionName - MouseSettings.save() - } - } - } - - function openSelectActionPopup() { - selectActionPopup.buttonIndex = model.index - selectActionPopup.headerTitle = model.label - selectActionPopup.open() - } - } - - } - - Item { - width: Kirigami.Units.gridUnit - height: Kirigami.Units.gridUnit - } - - SelectActionPopup { id: selectActionPopup } - } -} diff --git a/src/qml/Settings/Navigation.qml b/src/qml/Settings/Navigation.qml deleted file mode 100644 index 1fcb611..0000000 --- a/src/qml/Settings/Navigation.qml +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 -import org.kde.kirigami 2.11 as Kirigami - -Kirigami.Page -{ - padding: 0 - leftPadding: 0 - topPadding: 0 - rightPadding: 0 - bottomPadding: 0 - - Component.onCompleted: applicationWindow().pageStack.columnView.columnWidth = 250 - - - footer: ToolBar { - RowLayout { - anchors.fill: parent - - ToolButton { - text: qsTr("Configure shortcuts") - icon.name: "configure-shortcuts" - onClicked: appActions.configureShortcutsAction.trigger() - Layout.fillWidth: true - } - } - } - - ListModel { - id: settingsPagesModel - ListElement { - name: "General" - iconName: "configure" - page: "qrc:/General.qml" - } - ListElement { - name: "Playback" - iconName: "media-playback-start" - page: "qrc:/Playback.qml" - } - ListElement { - name: "Video" - iconName: "video-x-generic" - page: "qrc:/VideoSettings.qml" - } - ListElement { - name: "Audio" - iconName: "player-volume" - page: "qrc:/Audio.qml" - } - ListElement { - name: "Subtitles" - iconName: "add-subtitle" - page: "qrc:/Subtitles.qml" - } - ListElement { - name: "Playlist" - iconName: "view-media-playlist" - page: "qrc:/Playlist.qml" - } - ListElement { - name: "Mouse" - iconName: "input-mouse" - page: "qrc:/Mouse.qml" - } - ListElement { - name: "Custom commands" - iconName: "configure" - page: "qrc:/CustomCommands.qml" - } - } - - ListView { - id: settingsPagesList - - anchors.fill: parent - model: settingsPagesModel - delegate: Kirigami.BasicListItem { - text: qsTr(name) - icon: iconName - onClicked: applicationWindow().pageStack.push(model.page) - } - } -} diff --git a/src/qml/Settings/Playback.qml b/src/qml/Settings/Playback.qml deleted file mode 100644 index 1f2ad4f..0000000 --- a/src/qml/Settings/Playback.qml +++ /dev/null @@ -1,281 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - hasHelp: true - helpFile: ":/PlaybackSettings.html" - docPage: "help:/haruna/PlaybackSettings.html" - - GridLayout { - id: content - - columns: 2 - - CheckBox { - id: hwDecodingCheckBox - text: i18n("Use hardware decoding") - checked: PlaybackSettings.useHWDecoding - onCheckedChanged: { - mpv.hwDecoding = checked - PlaybackSettings.useHWDecoding = checked - PlaybackSettings.save() - } - } - - ComboBox { - id: hwDecodingComboBox - - enabled: hwDecodingCheckBox.checked - textRole: "key" - model: ListModel { - id: hwDecModel - ListElement { key: "auto"; } - ListElement { key: "auto-safe"; } - ListElement { key: "auto-copy"; } - ListElement { key: "vdpau"; } - ListElement { key: "vdpau-copy"; } - ListElement { key: "vaapi"; } - ListElement { key: "vaapi-copy"; } - ListElement { key: "videotoolbox"; } - ListElement { key: "videotoolbox-copy"; } - ListElement { key: "dxva2"; } - ListElement { key: "dxva2-copy"; } - ListElement { key: "d3d11va"; } - ListElement { key: "d3d11va-copy"; } - ListElement { key: "mediacodec"; } - ListElement { key: "mediacodec-copy"; } - ListElement { key: "mmal"; } - ListElement { key: "mmal-copy"; } - ListElement { key: "nvdec"; } - ListElement { key: "nvdec-copy"; } - ListElement { key: "cuda"; } - ListElement { key: "cuda-copy"; } - ListElement { key: "crystalhd"; } - ListElement { key: "rkmpp"; } - } - - onActivated: { - PlaybackSettings.hWDecoding = model.get(index).key - PlaybackSettings.save() - mpv.setProperty("hwdec", PlaybackSettings.hWDecoding) - } - - Component.onCompleted: { - for (let i = 0; i < hwDecModel.count; ++i) { - if (hwDecModel.get(i).key === PlaybackSettings.hWDecoding) { - currentIndex = i - break - } - } - } - } - - Label { - text: i18n("Remember time position") - } - - RowLayout { - SpinBox { - id: timePositionSaving - from: -1 - to: 9999 - value: PlaybackSettings.minDurationToSavePosition - - onValueChanged: { - PlaybackSettings.minDurationToSavePosition = value - PlaybackSettings.save() - } - } - - LabelWithTooltip { - text: { - if (timePositionSaving.value === -1) { - return i18n("Disabled") - } else if (timePositionSaving.value === 0) { - return i18n("For all files") - } else if (timePositionSaving.value === 1) { - return i18n("For files longer than %1 minute").arg(timePositionSaving.value) - } else { - return i18n("For files longer than %1 minutes").arg(timePositionSaving.value) - } - } - elide: Text.ElideRight - Layout.fillWidth: true - } - } - - CheckBox { - id: skipChaptersCheckBox - text: i18n("Skip chapters") - checked: PlaybackSettings.skipChapters - onCheckedChanged: { - PlaybackSettings.skipChapters = checked - PlaybackSettings.save() - } - Layout.columnSpan: 2 - } - - Label { - text: i18n("Skip chapters containing the following words") - enabled: skipChaptersCheckBox.checked - Layout.columnSpan: 2 - } - - TextField { - text: PlaybackSettings.chaptersToSkip - placeholderText: "op, ed, chapter 1" - enabled: skipChaptersCheckBox.checked - Layout.fillWidth: true - onEditingFinished: { - PlaybackSettings.chaptersToSkip = text - PlaybackSettings.save() - } - Layout.columnSpan: 2 - - ToolTip { - text: i18n("Separate words with a comma") - } - } - - CheckBox { - text: i18n("Show an osd message when skipping chapters") - enabled: skipChaptersCheckBox.checked - checked: PlaybackSettings.showOsdOnSkipChapters - onCheckedChanged: { - PlaybackSettings.showOsdOnSkipChapters = checked - PlaybackSettings.save() - } - Layout.columnSpan: 2 - } - - // ------------------------------------ - // Youtube-dl format settings - // ------------------------------------ - - SettingsHeader { - text: i18n("Youtube-dl") - Layout.columnSpan: 2 - Layout.fillWidth: true - } - - Label { - text: i18n("Format selection") - Layout.alignment: Qt.AlignRight - } - - Item { - height: ytdlFormatComboBox.height - ComboBox { - id: ytdlFormatComboBox - property string hCurrentvalue: "" - textRole: "key" - model: ListModel { - id: leftButtonModel - ListElement { key: "Custom"; value: "" } - ListElement { key: "2160"; value: "bestvideo[height<=2160]+bestaudio/best" } - ListElement { key: "1440"; value: "bestvideo[height<=1440]+bestaudio/best" } - ListElement { key: "1080"; value: "bestvideo[height<=1080]+bestaudio/best" } - ListElement { key: "720"; value: "bestvideo[height<=720]+bestaudio/best" } - ListElement { key: "480"; value: "bestvideo[height<=480]+bestaudio/best" } - } - ToolTip { - text: i18n("Selects the best video with a height lower than or equal to the selected value.") - } - - onActivated: { - hCurrentvalue = model.get(index).value - if (index === 0) { - ytdlFormatField.text = PlaybackSettings.ytdlFormat - } - if(index > 0) { - ytdlFormatField.focus = true - ytdlFormatField.text = model.get(index).value - } - PlaybackSettings.ytdlFormat = ytdlFormatField.text - PlaybackSettings.save() - mpv.setProperty("ytdl-format", PlaybackSettings.ytdlFormat) - } - - Component.onCompleted: { - let i = hIndexOfValue(PlaybackSettings.ytdlFormat) - currentIndex = (i === -1) ? 0 : i - } - - function hIndexOfValue(value) { - if (value === "bestvideo[height<=2160]+bestaudio/best") { - return 1 - } - if (value === "bestvideo[height<=1440]+bestaudio/best") { - return 2 - } - if (value === "bestvideo[height<=1080]+bestaudio/best") { - return 3 - } - if (value === "bestvideo[height<=720]+bestaudio/best") { - return 4 - } - if (value === "bestvideo[height<=480]+bestaudio/best") { - return 5 - } - return 0 - } - } - Layout.fillWidth: true - } - - TextField { - id: ytdlFormatField - text: PlaybackSettings.ytdlFormat - onEditingFinished: { - PlaybackSettings.ytdlFormat = text - PlaybackSettings.save() - } - placeholderText: i18n("bestvideo+bestaudio/best") - - onTextChanged: { - if (ytdlFormatComboBox.hCurrentvalue !== ytdlFormatField.text) { - ytdlFormatComboBox.currentIndex = 0 - return; - } - if (ytdlFormatComboBox.hIndexOfValue(ytdlFormatField.text) !== -1) { - ytdlFormatComboBox.currentIndex = ytdlFormatComboBox.hIndexOfValue(ytdlFormatField.text) - return; - } - } - - Layout.fillWidth: true - Layout.columnSpan: 2 - } - TextEdit { - text: i18n("Leave empty for default value: bestvideo+bestaudio/best") - color: FishUI.Theme.textColor - readOnly: true - wrapMode: Text.WordWrap - textFormat: TextEdit.RichText - selectByMouse: true - Layout.fillWidth: true - Layout.columnSpan: 2 - } - // ------------------------------------ - // END - Youtube-dl format settings - // ------------------------------------ - - Item { - width: FishUI.Units.gridUnit - height: FishUI.Units.gridUnit - } - } -} diff --git a/src/qml/Settings/Playlist.qml b/src/qml/Settings/Playlist.qml deleted file mode 100644 index 29eaa54..0000000 --- a/src/qml/Settings/Playlist.qml +++ /dev/null @@ -1,179 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - hasHelp: false - helpFile: "" - - GridLayout { - id: content - - columns: 2 - - Label { - text: i18n("Position") - Layout.alignment: Qt.AlignRight - } - - ComboBox { - textRole: "key" - model: ListModel { - ListElement { key: "Left"; value: "left" } - ListElement { key: "Right"; value: "right" } - } - Component.onCompleted: { - for (let i = 0; i < model.count; ++i) { - if (model.get(i).value === PlaylistSettings.position) { - currentIndex = i - break - } - } - } - onActivated: { - PlaylistSettings.position = model.get(index).value - PlaylistSettings.save() - playList.position = model.get(index).value - } - } - - Label { - text: i18n("Row height") - Layout.alignment: Qt.AlignRight - } - - SpinBox { - from: 0 - to: 100 - value: PlaylistSettings.rowHeight - enabled: PlaylistSettings.style === "compact" ? false : true - onValueChanged: { - PlaylistSettings.rowHeight = value - PlaylistSettings.save() - playList.rowHeight = value - playList.playlistView.forceLayout() - } - } - - Label { - text: i18n("Playlist style") - Layout.alignment: Qt.AlignRight - } - - ComboBox { - textRole: "display" - model: ListModel { - ListElement { display: "Default"; value: "default" } - ListElement { display: "WithThumbnails"; value: "withThumbnails" } - ListElement { display: "Compact"; value: "compact" } - } - Component.onCompleted: { - for (let i = 0; i < model.count; ++i) { - if (model.get(i).value === PlaylistSettings.style) { - currentIndex = i - break - } - } - } - onActivated: { - PlaylistSettings.style = model.get(index).value - PlaylistSettings.save() - } - } - - Item { width: 1; height: 1 } - CheckBox { - checked: PlaylistSettings.overlayVideo - text: i18n("Overlay video") - onCheckStateChanged: { - PlaylistSettings.overlayVideo = checked - PlaylistSettings.save() - } - - ToolTip { - text: i18n("When checked the playlist goes on top of the video\nWhen unchecked the video is resized") - } - } - - Item { width: 1; height: 1 } - CheckBox { - checked: PlaylistSettings.showMediaTitle - text: i18n("Show media title instead of file name") - onCheckStateChanged: { - PlaylistSettings.showMediaTitle = checked - PlaylistSettings.save() - } - } - - Item { width: 1; height: 1 } - CheckBox { - checked: PlaylistSettings.loadSiblings - text: i18n("Auto load videos from same folder") - onCheckStateChanged: { - PlaylistSettings.loadSiblings = checked - PlaylistSettings.save() - } - } - - Item { width: 1; height: 1 } - CheckBox { - checked: PlaylistSettings.repeat - text: i18n("Repeat") - onCheckStateChanged: { - PlaylistSettings.repeat = checked - PlaylistSettings.save() - } - } - - Item { width: 1; height: 1 } - CheckBox { - checked: PlaylistSettings.showRowNumber - text: i18n("Show row number") - onCheckStateChanged: { - PlaylistSettings.showRowNumber = checked - PlaylistSettings.save() - } - } - - Item { width: 1; height: 1 } - CheckBox { - checked: PlaylistSettings.canToggleWithMouse - text: i18n("Toggle with mouse") - onCheckStateChanged: { - PlaylistSettings.canToggleWithMouse = checked - PlaylistSettings.save() - playList.canToggleWithMouse = checked - } - } - - Item { width: 1; height: 1 } - CheckBox { - text: i18n("Increase font size when fullscreen") - checked: PlaylistSettings.bigFontFullscreen - enabled: PlaylistSettings.style === "compact" ? false : true - onCheckStateChanged: { - PlaylistSettings.bigFontFullscreen = checked - PlaylistSettings.save() - playList.bigFont = checked - playList.playlistView.forceLayout() - } - } - - Item { - width: FishUI.Units.gridUnit - height: FishUI.Units.gridUnit - } - } -} diff --git a/src/qml/Settings/SettingsEditor.qml b/src/qml/Settings/SettingsEditor.qml deleted file mode 100644 index dd27368..0000000 --- a/src/qml/Settings/SettingsEditor.qml +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.10 -import QtQuick.Window 2.1 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 -import QtGraphicalEffects 1.12 - -import org.kde.kirigami 2.11 as Kirigami -import org.kde.haruna 1.0 as Haruna - -Kirigami.ApplicationWindow { - id: root - - width: 800 - height: 600 - title: qsTr("Haruna Settings") - visible: false - pageStack.initialPage: "qrc:/Navigation.qml" - - Component.onCompleted: pageStack.push("qrc:/General.qml") - - Window { - id: helpWindow - - width: 700 - height: 600 - title: qsTr("Help") - color: Kirigami.Theme.backgroundColor - onVisibleChanged: info.text = app.getFileContent(applicationWindow().pageStack.currentItem.helpFile) - - Flickable { - id: scrollView - - property int scrollStepSize: 100 - - anchors.fill: parent - contentHeight: info.height - - ScrollBar.vertical: ScrollBar { - id: scrollbar - policy: ScrollBar.AlwaysOn - stepSize: scrollView.scrollStepSize/scrollView.contentHeight - } - - MouseArea { - anchors.fill: parent - onWheel: { - if (wheel.angleDelta.y > 0) { - scrollbar.decrease() - } else { - scrollbar.increase() - } - } - } - - TextArea { - id: info - - background: Rectangle { - color: "transparent" - border.color: "transparent" - } - width: parent.width - color: Kirigami.Theme.textColor - readOnly: true - textFormat: Text.RichText - wrapMode: Text.WordWrap - selectByMouse: true - rightPadding: scrollbar.width - onLinkActivated: Qt.openUrlExternally(link) - onHoveredLinkChanged: hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } - } -} diff --git a/src/qml/Settings/Subtitles.qml b/src/qml/Settings/Subtitles.qml deleted file mode 100644 index d9b76de..0000000 --- a/src/qml/Settings/Subtitles.qml +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - hasHelp: false - helpFile: "" - - GridLayout { - id: content - - columns: 2 - - SubtitlesFolders { - id: subtitleFolders - implicitWidth: root.width - Layout.fillWidth: true - Layout.columnSpan: 2 - } - - Label { - text: i18n("Preferred language") - Layout.alignment: Qt.AlignRight - } - TextField { - text: SubtitlesSettings.preferredLanguage - placeholderText: "eng,ger etc." - Layout.fillWidth: true - onTextEdited: { - SubtitlesSettings.preferredLanguage = text - SubtitlesSettings.save() - mpv.setProperty("slang", text) - } - - ToolTip { - text: i18n("Do not use spaces.") - } - } - - Label { - text: i18n("Preferred track") - Layout.alignment: Qt.AlignRight - } - SpinBox { - from: 0 - to: 100 - value: SubtitlesSettings.preferredTrack - editable: true - onValueChanged: { - SubtitlesSettings.preferredTrack = value - SubtitlesSettings.save() - if (value === 0) { - mpv.setProperty("sid", "auto") - } else { - mpv.setProperty("sid", value) - } - } - } - - Item { - width: FishUI.Units.gridUnit - height: FishUI.Units.gridUnit - } - } -} diff --git a/src/qml/Settings/VideoSettings.qml b/src/qml/Settings/VideoSettings.qml deleted file mode 100644 index e352d72..0000000 --- a/src/qml/Settings/VideoSettings.qml +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 -import Haruna.Components 1.0 - -SettingsBasePage { - id: root - - hasHelp: true - helpFile: ":/VideoSettings.html" - docPage: "help:/haruna/VideoSettings.html" - - GridLayout { - id: content - - columns: 2 - - SettingsHeader { - text: i18n("Screenshots") - topMargin: 0 - Layout.columnSpan: 2 - Layout.fillWidth: true - } - - // ------------------------------------ - // Screenshot Format - // ------------------------------------ - Label { - text: i18n("Format") - Layout.alignment: Qt.AlignRight - } - - Item { - height: screenshotFormat.height - ComboBox { - id: screenshotFormat - textRole: "key" - model: ListModel { - ListElement { key: "PNG"; } - ListElement { key: "JPG"; } - ListElement { key: "WebP"; } - } - - onActivated: { - VideoSettings.screenshotFormat = model.get(index).key - VideoSettings.save() - mpv.setProperty("screenshot-format", VideoSettings.screenshotFormat) - } - - Component.onCompleted: { - if (VideoSettings.screenshotFormat === "PNG") { - currentIndex = 0 - } - if (VideoSettings.screenshotFormat === "JPG") { - currentIndex = 1 - } - if (VideoSettings.screenshotFormat === "WebP") { - currentIndex = 2 - } - } - } - Layout.fillWidth: true - } - - // ------------------------------------ - // Screenshot template - // ------------------------------------ - Label { - text: i18n("Template") - Layout.alignment: Qt.AlignRight - } - - Item { - height: screenshotTemplate.height - TextField { - id: screenshotTemplate - text: VideoSettings.screenshotTemplate - onEditingFinished: { - VideoSettings.screenshotTemplate = text - VideoSettings.save() - mpv.setProperty("screenshot-template", VideoSettings.screenshotTemplate) - } - Layout.fillWidth: true - } - } - - SettingsHeader { - text: i18n("Image adjustments") - Layout.columnSpan: 2 - Layout.fillWidth: true - } - - - // ------------------------------------ - // CONTRAST - // ------------------------------------ - Label { - text: i18n("Contrast") - Layout.alignment: Qt.AlignRight - } - - ImageAdjustmentSlider { - id: contrastSlider - - value: mpv.contrast - onSliderValueChanged: mpv.contrast = value.toFixed(0) - - Layout.topMargin: FishUI.Units.largeSpacing - } - - // ------------------------------------ - // BRIGHTNESS - // ------------------------------------ - Label { - text: i18n("Brightness") - Layout.alignment: Qt.AlignRight - } - - ImageAdjustmentSlider { - id: brightnessSlider - - value: mpv.brightness - onSliderValueChanged: mpv.brightness = value.toFixed(0) - - Layout.topMargin: FishUI.Units.largeSpacing - } - - // ------------------------------------ - // GAMMA - // ------------------------------------ - Label { - text: i18n("Gamma") - Layout.alignment: Qt.AlignRight - } - - ImageAdjustmentSlider { - id: gammaSlider - - value: mpv.gamma - onSliderValueChanged: mpv.gamma = value.toFixed(0) - - Layout.topMargin: FishUI.Units.largeSpacing - } - - // ------------------------------------ - // SATURATION - // ------------------------------------ - Label { - text: i18n("Saturation") - Layout.alignment: Qt.AlignRight - } - - ImageAdjustmentSlider { - id: saturationSlider - - value: mpv.saturation - onSliderValueChanged: mpv.saturation = value.toFixed(0) - - Layout.topMargin: FishUI.Units.largeSpacing - } - - Label { - text: i18n("Middle click on the sliders to reset them") - Layout.columnSpan: 2 - Layout.topMargin: FishUI.Units.largeSpacing - } - - } -} diff --git a/src/qml/VolumeSlider.qml b/src/qml/VolumeSlider.qml deleted file mode 100644 index 20ae018..0000000 --- a/src/qml/VolumeSlider.qml +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQml 2.12 -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import QtQuick.Shapes 1.12 -import QtGraphicalEffects 1.12 - -import FishUI 1.0 as FishUI -import org.kde.haruna 1.0 - -Slider { - id: root - - from: 0 - to: 100 - value: mpv.volume - implicitWidth: 100 - implicitHeight: 25 - wheelEnabled: true - leftPadding: 0 - rightPadding: 0 - - onValueChanged: { - mpv.volume = value.toFixed(0) - GeneralSettings.volume = value.toFixed(0) - GeneralSettings.save() - } -} diff --git a/src/qml/main.qml b/src/qml/main.qml deleted file mode 100644 index 0e53e86..0000000 --- a/src/qml/main.qml +++ /dev/null @@ -1,236 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Window 2.12 -import QtQuick.Layouts 1.12 -import QtGraphicalEffects 1.12 -import Qt.labs.platform 1.0 as Platform -import QtQml 2.12 - -import FishUI 1.0 as FishUI - -import org.kde.haruna 1.0 - -import mpv 1.0 -import "Menus" -import "Settings" - -FishUI.Window { - id: window - - property var configure: app.action("configure") - property int preFullScreenVisibility - property var appActions: actions.list - - visible: true - title: mpv.mediaTitle - width: 1200 - minimumWidth: 700 - height: 720 - minimumHeight: 450 - color: FishUI.Theme.backgroundColor - - header.visible: false - - onVisibilityChanged: { - if (!window.isFullScreen()) { - preFullScreenVisibility = visibility - } - } - - contentTopMargin: 0 - - Header { id: header } - - // menuBar: MenuBar { - // hoverEnabled: true - // visible: !window.isFullScreen() && GeneralSettings.showMenuBar - // background: Rectangle { - // color: Kirigami.Theme.backgroundColor - // } - // Kirigami.Theme.colorSet: Kirigami.Theme.Header - - // FileMenu {} - // ViewMenu {} - // PlaybackMenu {} - // SubtitlesMenu {} - // AudioMenu {} - // SettingsMenu {} - // HelpMenu {} - // } - -// Menu { -// id: mpvContextMenu - -// modal: true - -// FileMenu {} -// ViewMenu {} -// PlaybackMenu {} -// SubtitlesMenu {} -// AudioMenu {} -// SettingsMenu {} -// HelpMenu {} -// } - -// SystemPalette { id: systemPalette; colorGroup: SystemPalette.Active } - - SettingsEditor { id: settingsEditor } - - Actions { id: actions } - - MpvVideo { - id: mpv - - Osd { id: osd } - } - - PlayList { id: playList } - - Footer { - id: footer - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: mpv.bottom - -// anchors.leftMargin: FishUI.Units.largeSpacing * 2 -// anchors.rightMargin: FishUI.Units.largeSpacing * 2 -// anchors.bottomMargin: FishUI.Units.largeSpacing * 2 - } - - Instantiator { - model: proxyCustomCommandsModel - delegate: Action { - property var qaction: app.action(model.commandId) - text: qaction.text - shortcut: qaction.shortcutName - onTriggered: { - mpv.userCommand(model.command) - osd.message(mpv.command(["expand-text", model.osdMessage])) - } - } - } - - Platform.FileDialog { - id: fileDialog - - property url location: GeneralSettings.fileDialogLocation - ? app.pathToUrl(GeneralSettings.fileDialogLocation) - : app.pathToUrl(GeneralSettings.fileDialogLastLocation) - - folder: location - title: "Select file" - fileMode: Platform.FileDialog.OpenFile - - onAccepted: { - openFile(fileDialog.file.toString(), true, PlaylistSettings.loadSiblings) - // the timer scrolls the playlist to the playing file - // once the table view rows are loaded - playList.scrollPositionTimer.start() - mpv.focus = true - - GeneralSettings.fileDialogLastLocation = app.parentUrl(fileDialog.file) - GeneralSettings.save() - } - onRejected: mpv.focus = true - } - - Popup { - id: openUrlPopup - x: 10 - y: 10 - - onOpened: { - openUrlTextField.forceActiveFocus(Qt.MouseFocusReason) - openUrlTextField.selectAll() - } - - RowLayout { - anchors.fill: parent - - Label { - text: qsTr("Youtube-dl was not found.") - visible: !app.hasYoutubeDl() - onLinkActivated: Qt.openUrlExternally(link) - } - - TextField { - id: openUrlTextField - - visible: app.hasYoutubeDl() - Layout.preferredWidth: 400 - Layout.fillWidth: true - Component.onCompleted: text = GeneralSettings.lastUrl - - Keys.onPressed: { - if (event.key === Qt.Key_Enter - || event.key === Qt.Key_Return) { - openUrlButton.clicked() - } - if (event.key === Qt.Key_Escape) { - openUrlPopup.close() - } - } - } - Button { - id: openUrlButton - - visible: app.hasYoutubeDl() - text: qsTr("Open") - - onClicked: { - openFile(openUrlTextField.text, true, false) - GeneralSettings.lastUrl = openUrlTextField.text - // in case the url is a playList, it opens the first video - GeneralSettings.lastPlaylistIndex = 0 - openUrlPopup.close() - openUrlTextField.clear() - } - } - } - } - - Component.onCompleted: app.activateColorScheme(GeneralSettings.colorScheme) - - function openFile(path, startPlayback, loadSiblings) { - if (app.isYoutubePlaylist(path)) { - mpv.getYouTubePlaylist(path); - playList.isYouTubePlaylist = true - } else { - playList.isYouTubePlaylist = false - } - - mpv.playlistModel.clear() - mpv.pause = !startPlayback - if (loadSiblings) { - // get video files from same folder as the opened file - mpv.playlistModel.getVideos(path) - } - mpv.loadFile(path) - } - - function isFullScreen() { - return window.visibility === Window.FullScreen - } - - function toggleFullScreen() { - if (!isFullScreen()) { - window.showFullScreen() - } else { - if (window.preFullScreenVisibility === Window.Windowed) { - window.showNormal() - } - if (window.preFullScreenVisibility === Window.Maximized) { - window.show() - window.showMaximized() - } - } - app.showCursor() - playList.scrollPositionTimer.start() - } -} diff --git a/src/settings/audiosettings.kcfg b/src/settings/audiosettings.kcfg deleted file mode 100644 index 9149ff7..0000000 --- a/src/settings/audiosettings.kcfg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/settings/audiosettings.kcfgc b/src/settings/audiosettings.kcfgc deleted file mode 100644 index 1c5d9c2..0000000 --- a/src/settings/audiosettings.kcfgc +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# SPDX-License-Identifier: GPL-3.0-or-later - -File=audiosettings.kcfg -ClassName=AudioSettings -Mutators=true -DefaultValueGetters=true -GenerateProperties=true -ParentInConstructor=true -Singleton=true diff --git a/src/settings/generalsettings.kcfg b/src/settings/generalsettings.kcfg deleted file mode 100644 index 889eaae..0000000 --- a/src/settings/generalsettings.kcfg +++ /dev/null @@ -1,79 +0,0 @@ - - - - - QStandardPaths - - - - 25 - - - - 5 - - - - 5 - - - - 15 - - - - 30 - - - - true - - - - true - - - - true - - - - - - false - - - Default - - - - 80 - - - - - - 0 - - - - - - - - QString videoFolder = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); - - videoFolder - - - - - - diff --git a/src/settings/generalsettings.kcfgc b/src/settings/generalsettings.kcfgc deleted file mode 100644 index bc91b53..0000000 --- a/src/settings/generalsettings.kcfgc +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# SPDX-License-Identifier: GPL-3.0-or-later - -File=generalsettings.kcfg -ClassName=GeneralSettings -Mutators=true -DefaultValueGetters=true -GenerateProperties=true -ParentInConstructor=true -Singleton=true diff --git a/src/settings/mousesettings.kcfg b/src/settings/mousesettings.kcfg deleted file mode 100644 index f197af8..0000000 --- a/src/settings/mousesettings.kcfg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - toggleFullscreenAction - - - - muteAction - - - - configureAction - - - - playPauseAction - - - - - - - volumeUpAction - - - - volumeDownAction - - - diff --git a/src/settings/mousesettings.kcfgc b/src/settings/mousesettings.kcfgc deleted file mode 100644 index 7b5fcfa..0000000 --- a/src/settings/mousesettings.kcfgc +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# SPDX-License-Identifier: GPL-3.0-or-later - -File=mousesettings.kcfg -ClassName=MouseSettings -Mutators=true -DefaultValueGetters=true -GenerateProperties=true -ParentInConstructor=true -Singleton=true diff --git a/src/settings/playbacksettings.kcfg b/src/settings/playbacksettings.kcfg deleted file mode 100644 index d6aaa2b..0000000 --- a/src/settings/playbacksettings.kcfg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - 1 - - - - false - - - - - - - true - - - - - - false - - - auto - - - diff --git a/src/settings/playbacksettings.kcfgc b/src/settings/playbacksettings.kcfgc deleted file mode 100644 index 0abec46..0000000 --- a/src/settings/playbacksettings.kcfgc +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# SPDX-License-Identifier: GPL-3.0-or-later - -File=playbacksettings.kcfg -ClassName=PlaybackSettings -Mutators=true -DefaultValueGetters=true -GenerateProperties=true -ParentInConstructor=true -Singleton=true diff --git a/src/settings/playlistsettings.kcfg b/src/settings/playlistsettings.kcfg deleted file mode 100644 index d6263b3..0000000 --- a/src/settings/playlistsettings.kcfg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - right - - - - 10 - - - default - - - true - - - - false - - - - true - - - - true - - - - true - - - - true - - - - true - - - - true - - - diff --git a/src/settings/playlistsettings.kcfgc b/src/settings/playlistsettings.kcfgc deleted file mode 100644 index b4af628..0000000 --- a/src/settings/playlistsettings.kcfgc +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# SPDX-License-Identifier: GPL-3.0-or-later - -File=playlistsettings.kcfg -ClassName=PlaylistSettings -Mutators=true -DefaultValueGetters=true -GenerateProperties=true -ParentInConstructor=true -Singleton=true diff --git a/src/settings/subtitlessettings.kcfg b/src/settings/subtitlessettings.kcfg deleted file mode 100644 index 0031dca..0000000 --- a/src/settings/subtitlessettings.kcfg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - subs - - - - - - - - - diff --git a/src/settings/subtitlessettings.kcfgc b/src/settings/subtitlessettings.kcfgc deleted file mode 100644 index 4405878..0000000 --- a/src/settings/subtitlessettings.kcfgc +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# SPDX-License-Identifier: GPL-3.0-or-later - -File=subtitlessettings.kcfg -ClassName=SubtitlesSettings -Mutators=true -DefaultValueGetters=true -GenerateProperties=true -ParentInConstructor=true -Singleton=true diff --git a/src/settings/videosettings.kcfg b/src/settings/videosettings.kcfg deleted file mode 100644 index 0f3b4eb..0000000 --- a/src/settings/videosettings.kcfg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - QStandardPaths - - - - jpg - - - - - QString screenshotsFolder = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); - screenshotsFolder.append("/Haruna screenshots/%F-%n"); - - screenshotsFolder - - - diff --git a/src/settings/videosettings.kcfgc b/src/settings/videosettings.kcfgc deleted file mode 100644 index 64adee2..0000000 --- a/src/settings/videosettings.kcfgc +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2020 George Florea Bănuș -# SPDX-License-Identifier: GPL-3.0-or-later - -File=videosettings.kcfg -ClassName=VideoSettings -Mutators=true -DefaultValueGetters=true -GenerateProperties=true -ParentInConstructor=true -Singleton=true diff --git a/src/thumbnailimageprovider.cpp b/src/thumbnailimageprovider.cpp deleted file mode 100644 index c763118..0000000 --- a/src/thumbnailimageprovider.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include "_debug.h" -#include "thumbnailimageprovider.h" - -#include -#include -#include - -ThumbnailImageProvider::ThumbnailImageProvider() -{ - qRegisterMetaType("KFileItem"); -} - -QQuickImageResponse *ThumbnailImageProvider::requestImageResponse(const QString& id, const QSize& requestedSize) -{ - auto response = new ThumbnailResponse(id, requestedSize); - return response; -} - - -ThumbnailResponse::ThumbnailResponse(const QString &id, const QSize &requestedSize) -{ - getPreview(id, requestedSize); -} - -void ThumbnailResponse::getPreview(const QString &id, const QSize &requestedSize) -{ - auto file = QUrl::fromPercentEncoding(id.toUtf8()).toUtf8(); - if(QFile(file).exists()) { - QMimeDatabase db; - QString mimetype = db.mimeTypeForFile(file).name(); - - QStringList allPlugins{KIO::PreviewJob::availablePlugins()}; - auto list = KFileItemList() << KFileItem(QUrl::fromLocalFile(file), mimetype); - auto job = new KIO::PreviewJob(list, requestedSize, &allPlugins); - - connect(job, &KIO::PreviewJob::gotPreview, this, - [this] (const KFileItem &item, const QPixmap &pixmap) { - Q_UNUSED(item); - m_texture = QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()); - emit finished(); - }, Qt::QueuedConnection); - - connect(job, &KIO::PreviewJob::failed, this, [=] (const KFileItem &item) { - DEBUG << "Failed to create thumbnail" << item.name(); - - QString iconName; - if (mimetype.startsWith("video/")) { - iconName = QStringLiteral("video-x-generic"); - } else if (mimetype.startsWith("audio/")) { - iconName = QStringLiteral("audio-x-generic"); - } else { - return; - } - auto icon = QIcon::fromTheme(iconName).pixmap(requestedSize); - m_texture = QQuickTextureFactory::textureFactoryForImage(icon.toImage()); - - emit finished(); - }); - } - if (QUrl(id).scheme() == "http" || QUrl(id).scheme() == "https") { - QStringList allPlugins{KIO::PreviewJob::availablePlugins()}; - auto list = KFileItemList() << KFileItem(QUrl(file)); - auto job = new KIO::PreviewJob(list, requestedSize, &allPlugins); - - connect(job, &KIO::PreviewJob::gotPreview, this, - [this] (const KFileItem &item, const QPixmap &pixmap) { - Q_UNUSED(item); - m_texture = QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()); - emit finished(); - }, Qt::QueuedConnection); - - connect(job, &KIO::PreviewJob::failed, this, [=] (const KFileItem &item) { - Q_UNUSED(item); - auto icon = QIcon::fromTheme("im-youtube", QIcon::fromTheme("video-x-generic")); - m_texture = QQuickTextureFactory::textureFactoryForImage(icon.pixmap(requestedSize).toImage()); - emit finished(); - }); - } -} - -QQuickTextureFactory *ThumbnailResponse::textureFactory() const -{ - return m_texture; -} diff --git a/src/thumbnailimageprovider.h b/src/thumbnailimageprovider.h deleted file mode 100644 index 579824d..0000000 --- a/src/thumbnailimageprovider.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#ifndef THUMBNAILIMAGEPROVIDER_H -#define THUMBNAILIMAGEPROVIDER_H - -#include -#include - -class KFileItem; -class KJob; - -class ThumbnailImageProvider : public QQuickAsyncImageProvider -{ -public: - explicit ThumbnailImageProvider(); - QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override; -}; - - -class ThumbnailResponse : public QQuickImageResponse -{ - public: - ThumbnailResponse(const QString &id, const QSize &requestedSize); - - QQuickTextureFactory *textureFactory() const override; - - QImage m_image; - QQuickTextureFactory *m_texture {nullptr}; - void getPreview(const QString &id, const QSize &requestedSize); -}; - -#endif // THUMBNAILIMAGEPROVIDER_H diff --git a/src/models/tracksmodel.cpp b/src/tracksmodel.cpp similarity index 98% rename from src/models/tracksmodel.cpp rename to src/tracksmodel.cpp index ddddb17..8120214 100644 --- a/src/models/tracksmodel.cpp +++ b/src/tracksmodel.cpp @@ -4,9 +4,9 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -#include "_debug.h" #include "track.h" #include "tracksmodel.h" + #include TracksModel::TracksModel(QObject *parent) diff --git a/src/models/tracksmodel.h b/src/tracksmodel.h similarity index 99% rename from src/models/tracksmodel.h rename to src/tracksmodel.h index 5ef039a..54f5b5e 100644 --- a/src/models/tracksmodel.h +++ b/src/tracksmodel.h @@ -15,8 +15,10 @@ class Track; class TracksModel : public QAbstractListModel { Q_OBJECT + public: explicit TracksModel(QObject *parent = nullptr); + enum { TextRole = Qt::UserRole, LanguageRole, @@ -24,12 +26,14 @@ public: IDRole, CodecRole }; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual QHash roleNames() const override; public slots: void setTracks(QMap tracks); + private: QMap m_tracks; }; diff --git a/src/worker.cpp b/src/worker.cpp deleted file mode 100644 index 391d036..0000000 --- a/src/worker.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include "_debug.h" -#include "worker.h" - -#include -#include -#include -#include - -Worker* Worker::sm_worker = nullptr; - -Worker* Worker::instance() -{ - if (!sm_worker) { - sm_worker = new Worker(); - } - return sm_worker; -} - -void Worker::getMetaData(int index, const QString &path) -{ - QMimeDatabase db; - QMimeType type = db.mimeTypeForFile(path); - KFileMetaData::ExtractorCollection exCol; - QList extractors = exCol.fetchExtractors(type.name()); - KFileMetaData::SimpleExtractionResult result(path, type.name(), - KFileMetaData::ExtractionResult::ExtractMetaData); - if (extractors.size() == 0) { - return; - } - KFileMetaData::Extractor* ex = extractors.first(); - ex->extract(&result); - auto properties = result.properties(); - - emit metaDataReady(index, properties); -} diff --git a/src/worker.h b/src/worker.h deleted file mode 100644 index 6a83610..0000000 --- a/src/worker.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 George Florea Bănuș - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#ifndef WORKER_H -#define WORKER_H - -#include -#include - -class Worker : public QObject -{ - Q_OBJECT -public: - Worker() = default; - ~Worker() = default; - - static Worker* instance(); - -signals: - void metaDataReady(int index, KFileMetaData::PropertyMap metadata); - -public slots: - void getMetaData(int index, const QString &path); - -private: - static Worker *sm_worker; -}; - -#endif // WORKER_H