diff --git a/CMakeLists.txt b/CMakeLists.txt index fcd9fbd..cf70fb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,11 @@ find_package(Qt5Gui REQUIRED) find_package(Qt5 CONFIG REQUIRED COMPONENTS Qml Quick Gui Widgets Core X11Extras) find_package(Qt5QuickCompiler) +if(DEVELOP) +qt5_add_resources(QT_RESOURCES qml.qrc) +else() qtquick_compiler_add_resources(qml_QRC src/qml/qml.qrc) +endif() find_package(PkgConfig) pkg_check_modules(MPV REQUIRED mpv) diff --git a/src/MpvPlayerBackend.cpp b/src/MpvPlayerBackend.cpp index 6f31b6c..62c77a0 100644 --- a/src/MpvPlayerBackend.cpp +++ b/src/MpvPlayerBackend.cpp @@ -581,4 +581,3 @@ MpvPlayerBackend::createRenderer() const window()->setPersistentSceneGraph(true); return new MpvRenderer(const_cast(this)); } - diff --git a/src/main.cpp b/src/main.cpp index 5de26f6..400b6be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -106,23 +106,22 @@ main(int argc, char* argv[]) QSettings settings; QString backendSetting = settings.value("Backend/backend", "").toString(); if (backendSetting.length() == 0) { - #ifndef DISABLE_MpvPlayerBackend - settings.setValue("Backend/backend", "mpv"); - #else - settings.setValue("Backend/backend", "direct-mpv"); - #endif +#ifndef DISABLE_MpvPlayerBackend + settings.setValue("Backend/backend", "mpv"); +#else + settings.setValue("Backend/backend", "direct-mpv"); +#endif } - qDebug() << backendSetting; + qDebug() << backendSetting; for (int i = 1; i < argc; ++i) { if (!qstrcmp(argv[i], "--update")) { Utils::updateAppImage(); - } - else if (!qstrcmp(argv[i], "--backend=mpv") || backendSetting == "mpv") { + } else if (!qstrcmp(argv[i], "--backend=mpv") || backendSetting == "mpv") { backend = Enums::Backends::MpvBackend; - } - else if (!qstrcmp(argv[i], "--backend=direct-mpv") || backendSetting == "direct-mpv") { + } else if (!qstrcmp(argv[i], "--backend=direct-mpv") || + backendSetting == "direct-mpv") { backend = Enums::Backends::DirectMpvBackend; } } @@ -141,19 +140,20 @@ main(int argc, char* argv[]) qRegisterMetaType("Enums.Backends"); qRegisterMetaType("Enums.Commands"); - + qmlRegisterType("player", 1, 0, "Utils"); switch (backend) { case Enums::Backends::MpvBackend: { - #ifndef DISABLE_MpvPlayerBackend - qmlRegisterType("player", 1, 0, "PlayerBackend"); - #else - qDebug() << "Normal MPV backend not available, resetting backend option to blank."; - settings.setValue("Backend/backend", "direct-mpv"); - app.exit(); - #endif - break; +#ifndef DISABLE_MpvPlayerBackend + qmlRegisterType("player", 1, 0, "PlayerBackend"); +#else + qDebug() << "Normal MPV backend not available, resetting backend option " + "to blank."; + settings.setValue("Backend/backend", "direct-mpv"); + app.exit(); +#endif + break; } case Enums::Backends::DirectMpvBackend: { qmlRegisterType("player", 1, 0, "PlayerBackend"); @@ -171,7 +171,7 @@ main(int argc, char* argv[]) rt->setMainQmlFilename("main.qml"); rt->reload(); #else - engine.load(QUrl(QStringLiteral("qrc:///player/main.qml"))); + engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); #endif return app.exec(); diff --git a/src/qml/ControlsBar.qml b/src/qml/ControlsBar.qml index 8234caf..658e9d8 100644 --- a/src/qml/ControlsBar.qml +++ b/src/qml/ControlsBar.qml @@ -8,6 +8,7 @@ import Qt.labs.platform 1.0 as LabsPlatform import player 1.0 Item { + id: controlsBarItem anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right @@ -17,6 +18,23 @@ Item { property var controls: controlsBar property var duration: progressBar.to + Component.onCompleted: { + setControlsTheme(appearance.themeName) + } + + function setControlsTheme(themeName) { + for (var i = 0; i < controlsBar.children.length; ++i) { + if (controlsBar.children[i].objectName == "buttonLayout") { + controlsBar.children[i].destroy() + } + } + + var component = Qt.createComponent(themeName + "ButtonLayout.qml") + component.createObject(controlsBar, { + anchors.fill: controlsBar + }) + } + Item { id: subtitlesBar visible: !appearance.useMpvSubs @@ -67,10 +85,12 @@ Item { width: subsContainer.childrenRect.width height: subsContainer.childrenRect.height } - Component.onCompleted: { - player.subtitlesChanged.connect(function (subtitles) { - text = subtitles - }) + Connections { + target: player + enabled: true + onSubtitlesChanged: function (subtitles) { + nativeSubs.text = subtitles + } } } } @@ -79,9 +99,8 @@ Item { Rectangle { id: controlsBackground - height: controlsBar.visible ? controlsBar.height - + (fun.nyanCat ? progressBackground.height - * 0.3 : progressBackground.height * 2) : 0 + height: controlsBar.visible ? controlsBar.height + progressBar.topPadding + + (fun.nyanCat ? 0 : 1) : 0 anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right @@ -100,353 +119,13 @@ Item { anchors.bottom: parent.bottom anchors.bottomMargin: 2 visible: true - - Slider { + VideoProgress { id: progressBar - objectName: "progressBar" - to: 1 - value: 0.0 anchors.bottom: parent.top anchors.left: parent.left anchors.right: parent.right anchors.bottomMargin: 0 - anchors.topMargin: progressBackground.height bottomPadding: 0 - Component.onCompleted: { - player.positionChanged.connect(function (position) { - if (!pressed) { - progressBar.value = position - } - }) - player.durationChanged.connect(function (duration) { - progressBar.to = duration - }) - player.cachedDurationChanged.connect(function (duration) { - cachedLength.duration = duration - }) - } - onMoved: { - player.playerCommand(Enums.Commands.SeekAbsolute, value) - } - - function getProgressBarHeight(nyan, isMouse) { - var x = Math.max(Screen.height / 256, fun.nyanCat ? 12 : 2) - return isMouse & !fun.nyanCat ? x * 2 : x - } - MouseArea { - id: mouseAreaProgressBar - width: parent.width - height: parent.height - anchors.fill: parent - y: parent.y - x: parent.x - hoverEnabled: true - propagateComposedEvents: false - acceptedButtons: Qt.NoButton - z: 1 - onPositionChanged: { - var a = (progressBar.to / progressBar.width ) * mouseAreaProgressBar.mouseX - hoverProgressLabel.text = utils.createTimestamp(a) - } - } - - background: Rectangle { - id: progressBackground - x: progressBar.leftPadding - y: progressBar.topPadding + progressBar.availableHeight / 2 - height / 2 - width: progressBar.availableWidth - height: progressBar.getProgressBarHeight( - fun.nyanCat, mouseAreaProgressBar.containsMouse) - color: appearance.progressBackgroundColor - - - Rectangle { - x: (mouseAreaProgressBar.mouseX - width / 2) + progressBar.leftPadding - y: progressBackground.y - 20 - height - visible: mouseAreaProgressBar.containsMouse - color: appearance.mainBackground - height: 20 - width: 50 - z: 80 - Text { - id: hoverProgressLabel - text: "0:00" - color: "white" - padding: 2 - font.family: appearance.fontName - font.pixelSize: 14 - verticalAlignment: Text.AlignVCenter - renderType: Text.NativeRendering - } - } - - ProgressBar { - id: cachedLength - background: Item { - } - contentItem: Item { - Rectangle { - width: cachedLength.visualPosition * parent.width - height: parent.height - color: appearance.progressCachedColor - } - } - z: 40 - to: progressBar.to - property int duration - value: progressBar.value + duration - anchors.fill: parent - } - - Item { - anchors.fill: parent - id: chapterMarkers - Component.onCompleted: { - player.chaptersChanged.connect(chaptersChanged) - } - function chaptersChanged(chapters) { - for (var i = 0, len = chapters.length; i < len; i++) { - var chapter = chapters[i] - var component = Qt.createComponent( - "ChapterMarker.qml") - - var marker = component.createObject(chapterMarkers, - { - time: chapter["time"] - }) - } - } - } - - Rectangle { - id: progressLength - z: 50 - anchors.left: progressBackground.left - width: progressBar.visualPosition * parent.width - height: parent.height - color: appearance.progressSliderColor - Image { - visible: fun.nyanCat - id: rainbow - anchors.fill: parent - height: parent.height - width: parent.width - source: "qrc:/player/icons/rainbow.png" - fillMode: Image.TileHorizontally - } - } - } - - handle: Rectangle { - z: 70 - id: handleRect - x: progressBar.leftPadding + progressBar.visualPosition - * (progressBar.availableWidth - width) - y: progressBar.topPadding + progressBar.availableHeight / 2 - height / 2 - implicitHeight: radius - implicitWidth: radius - radius: 12 + (progressBackground.height / 2) - color: fun.nyanCat ? "transparent" : appearance.progressSliderColor - AnimatedImage { - z: 80 - visible: fun.nyanCat - paused: progressBar.pressed - height: 30 - id: nyanimation - anchors.centerIn: parent - source: "qrc:/player/icons/nyancat.gif" - fillMode: Image.PreserveAspectFit - } - } - } - - RowLayout { - id: layout - anchors.fill: parent - spacing: 2 - - Button { - id: playlistPrevButton - objectName: "playlistPrevButton" - icon.source: "icons/prev.svg" - icon.color: appearance.buttonColor - display: AbstractButton.IconOnly - visible: false - width: visible ? playPauseButton.width : 0 - onClicked: { - player.playerCommand(Enums.Commands.PreviousPlaylistItem) - } - background: Item { - } - Component.onCompleted: { - player.playlistPositionChanged.connect(function (position) { - if (position != 0) { - visible = true - } else { - visible = false - } - }) - } - } - - Button { - id: playPauseButton - icon.source: "icons/pause.svg" - icon.color: appearance.buttonColor - display: AbstractButton.IconOnly - onClicked: { - player.playerCommand(Enums.Commands.TogglePlayPause) - } - background: Item { - } - Component.onCompleted: { - player.playStatusChanged.connect(function (status) { - if (status == Enums.PlayStatus.Playing) { - icon.source = "qrc:/player/icons/pause.svg" - } else if (status == Enums.PlayStatus.Paused) { - icon.source = "qrc:/player/icons/play.svg" - } - }) - } - } - - Button { - id: playlistNextButton - //icon.name: "next" - icon.source: "icons/next.svg" - icon.color: appearance.buttonColor - display: AbstractButton.IconOnly - onClicked: { - player.playerCommand(Enums.Commands.NextPlaylistItem) - } - background: Item { - } - } - - Button { - id: volumeButton - objectName: "volumeButton" - icon.source: "icons/volume-up.svg" - icon.color: appearance.buttonColor - display: AbstractButton.IconOnly - onClicked: { - player.playerCommand(Enums.Commands.ToggleMute) - } - background: Item { - } - Component.onCompleted: { - player.volumeStatusChanged.connect(function (status) { - if (status == Enums.VolumeStatus.Muted) { - volumeButton.icon.source = "qrc:/player/icons/volume-mute.svg" - } else if (status == Enums.VolumeStatus.Low) { - volumeButton.icon.source = "qrc:/player/icons/volume-down.svg" - } else if (status == Enums.VolumeStatus.Normal) { - volumeButton.icon.source = "qrc:/player/icons/volume-up.svg" - } - }) - } - } - Slider { - id: volumeBar - to: 100 - value: 100 - palette.dark: "#f00" - - implicitWidth: Math.max( - background ? background.implicitWidth : 0, - (handle ? handle.implicitWidth : 0) - + leftPadding + rightPadding) - implicitHeight: Math.max( - background ? background.implicitHeight : 0, - (handle ? handle.implicitHeight : 0) - + topPadding + bottomPadding) - onMoved: { - player.playerCommand(Enums.Commands.SetVolume, - Math.round(volumeBar.value).toString()) - } - Component.onCompleted: { - player.volumeChanged.connect(function (volume) { - volumeBar.value = volume - }) - } - handle: Rectangle { - x: volumeBar.leftPadding + volumeBar.visualPosition - * (volumeBar.availableWidth - width) - y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2 - implicitWidth: 12 - implicitHeight: 12 - radius: 12 - color: "#f6f6f6" - border.color: "#f6f6f6" - } - - background: Rectangle { - x: volumeBar.leftPadding - y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2 - implicitWidth: 60 - implicitHeight: 3 - width: volumeBar.availableWidth - height: implicitHeight - color: "#33333311" - Rectangle { - width: volumeBar.visualPosition * parent.width - height: parent.height - color: "white" - } - } - } - - Text { - id: timeLabel - objectName: "timeLabel" - text: "0:00 / 0:00" - color: "white" - padding: 2 - font.family: appearance.fontName - font.pixelSize: 14 - verticalAlignment: Text.AlignVCenter - renderType: Text.NativeRendering - Component.onCompleted: { - player.durationStringChanged.connect( - function (durationString) { - text = durationString - }) - } - } - - Item { - Layout.fillWidth: true - } - - Button { - id: settingsButton - //icon.name: "settings" - icon.source: "icons/settings.svg" - icon.color: appearance.buttonColor - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - display: AbstractButton.IconOnly - onClicked: { - console.log("Settings Menu Not Yet Implemented.") - } - background: Item { - } - } - - Button { - id: fullscreenButton - //icon.name: "fullscreen" - icon.source: "icons/fullscreen.svg" - icon.color: appearance.buttonColor - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - - display: AbstractButton.IconOnly - onClicked: { - toggleFullscreen() - } - - background: Item { - } - } } } } diff --git a/src/qml/CustomComboBox.qml b/src/qml/CustomComboBox.qml deleted file mode 100644 index 29561c0..0000000 --- a/src/qml/CustomComboBox.qml +++ /dev/null @@ -1,75 +0,0 @@ -import QtQuick 2.11 -import QtQuick.Controls 2.4 -import Qt.labs.settings 1.0 - -ComboBox { - id: control - width: parent.width - height: 10 - - indicator: Canvas { - id: canvas - x: control.width - width - control.rightPadding - y: control.topPadding + (control.availableHeight - height) / 2 - width: 12 - height: 8 - contextType: "2d" - - Connections { - target: control - onPressedChanged: canvas.requestPaint() - } - - onPaint: { - context.reset() - context.moveTo(0, 0) - context.lineTo(width, 0) - context.lineTo(width / 2, height) - context.closePath() - context.fillStyle = control.pressed ? "#17a81a" : "#21be2b" - context.fill() - } - } - - contentItem: Text { - leftPadding: 2 - rightPadding: control.indicator.width + control.spacing - text: control.displayText - font.family: appearance.fontName - color: control.pressed ? "#5a50da" : "white" - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } - - background: Rectangle { - implicitWidth: 120 - implicitHeight: 40 - color: "transparent" - } - - popup: Popup { - y: control.height - 1 - width: control.width - implicitHeight: contentItem.implicitHeight - padding: 1 - - contentItem: ListView { - clip: true - implicitHeight: contentHeight - model: control.popup.visible ? control.delegateModel : null - currentIndex: control.highlightedIndex - highlight: Rectangle { - color: "white" - opacity: 1 - } - - ScrollIndicator.vertical: ScrollIndicator { - } - } - - background: Rectangle { - opacity: 0.6 - color: "orange" - } - } -} diff --git a/src/qml/PlaylistDialog.qml b/src/qml/Dialogs/PlaylistDialog.qml similarity index 78% rename from src/qml/PlaylistDialog.qml rename to src/qml/Dialogs/PlaylistDialog.qml index ac244f4..b74aa4c 100644 --- a/src/qml/PlaylistDialog.qml +++ b/src/qml/Dialogs/PlaylistDialog.qml @@ -12,19 +12,20 @@ Dialog { height: Math.max(480, childrenRect.height * playlistListView.count) width: 720 modality: Qt.NonModal - Component.onCompleted: { - player.playlistChanged.connect(updatePlaylistMenu) - } - function updatePlaylistMenu(playlist) { - playlistModel.clear() - for (var thing in playlist) { - var item = playlist[thing] - playlistModel.append({ - playlistItemTitle: item["title"], - playlistItemFilename: item["filename"], - current: item["current"], - playlistPos: thing - }) + Connections { + target: player + enabled: true + onPlaylistChanged: function(playlist) { + playlistModel.clear() + for (var thing in playlist) { + var item = playlist[thing] + playlistModel.append({ + playlistItemTitle: item["title"], + playlistItemFilename: item["filename"], + current: item["current"], + playlistPos: thing + }) + } } } diff --git a/src/qml/AudioDeviceItem.qml b/src/qml/Items/AudioDeviceItem.qml similarity index 100% rename from src/qml/AudioDeviceItem.qml rename to src/qml/Items/AudioDeviceItem.qml diff --git a/src/qml/ChapterMarker.qml b/src/qml/Items/ChapterMarkerItem.qml similarity index 76% rename from src/qml/ChapterMarker.qml rename to src/qml/Items/ChapterMarkerItem.qml index 7963bd3..d0c148e 100644 --- a/src/qml/ChapterMarker.qml +++ b/src/qml/Items/ChapterMarkerItem.qml @@ -7,8 +7,10 @@ Rectangle { id: chapterMarker property int time: 0 color: appearance.chapterMarkerColor - Component.onCompleted: { - player.chaptersChanged.connect(chapterMarker.destroy) + Connections { + target: player + enabled: true + onChaptersChanged: {chapterMarker.destroy()} } width: 4 diff --git a/src/qml/CustomMenuItem.qml b/src/qml/Items/CustomMenuItem.qml similarity index 100% rename from src/qml/CustomMenuItem.qml rename to src/qml/Items/CustomMenuItem.qml diff --git a/src/qml/TrackItem.qml b/src/qml/Items/TrackItem.qml similarity index 100% rename from src/qml/TrackItem.qml rename to src/qml/Items/TrackItem.qml diff --git a/src/qml/MainMenu.qml b/src/qml/MainMenu.qml index 5000964..66a6fad 100644 --- a/src/qml/MainMenu.qml +++ b/src/qml/MainMenu.qml @@ -20,8 +20,12 @@ MenuBar { } } - Component.onCompleted: { - player.tracksChanged.connect(updateTracks) + Connections { + target: player + enabled: true + onTracksChanged: function (tracks) { + menuBar.updateTracks(tracks) + } } function updateTracks(tracks) { @@ -340,8 +344,12 @@ MenuBar { id: audioDeviceMenu objectName: "audioDeviceMenu" - Component.onCompleted: { - player.audioDevicesChanged.connect(updateAudioDevices) + Connections { + target: player + enabled: true + onAudioDevicesChanged: function (ad) { + audioDeviceMenu.updateAudioDevices(ad) + } } function updateAudioDevices(audioDevices) { for (var i = 0, len = audioDeviceMenu.count; i < len; i++) { diff --git a/src/qml/NiconicoButtonLayout.qml b/src/qml/NiconicoButtonLayout.qml new file mode 100644 index 0000000..317149a --- /dev/null +++ b/src/qml/NiconicoButtonLayout.qml @@ -0,0 +1,76 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + +Item { + objectName: "buttonLayout" + id: layout + + PlayPauseButton { + id: playPauseButton + anchors.top: parent.top + anchors.bottom: parent.bottom + height: 16 + width: 26 + icon.height: 16 + icon.width: 26 + } + VolumeButton { + id: volumeButton + anchors.left: playPauseButton.right + anchors.top: parent.top + anchors.bottom: parent.bottom + icon.height: 16 + icon.width: 16 + } + VolumeSlider { + anchors.left: volumeButton.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + PlaylistPrevButton { + id: playlistPrevButton + anchors.right: timeLabel.left + anchors.top: parent.top + anchors.bottom: parent.bottom + icon.height: 16 + icon.width: 16 + } + TimeLabel { + id: timeLabel + anchors.centerIn: parent + anchors.top: parent.top + anchors.bottom: parent.bottom + } + PlaylistNextButton { + id: playlistNextButton + anchors.left: timeLabel.right + anchors.top: parent.top + anchors.bottom: parent.bottom + icon.height: 16 + icon.width: 16 + } + + FullscreenButton { + id: fullscreenButton + anchors.right: settingsButton.left + anchors.top: parent.top + anchors.bottom: parent.bottom + icon.height: 16 + icon.width: 16 + } + SettingsButton { + id: settingsButton + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + icon.height: 16 + icon.width: 16 + } +} diff --git a/src/qml/UIComponents/FullscreenButton.qml b/src/qml/UIComponents/FullscreenButton.qml new file mode 100644 index 0000000..56e5548 --- /dev/null +++ b/src/qml/UIComponents/FullscreenButton.qml @@ -0,0 +1,24 @@ + import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + Button { + id: fullscreenButton + //icon.name: "fullscreen" + icon.source: "icons/" + appearance.themeName + "/fullscreen.svg" + icon.color: appearance.buttonColor + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + + display: AbstractButton.IconOnly + onClicked: { + toggleFullscreen() + } + + background: Item { + } + } diff --git a/src/qml/UIComponents/PlayPauseButton.qml b/src/qml/UIComponents/PlayPauseButton.qml new file mode 100644 index 0000000..f7f1092 --- /dev/null +++ b/src/qml/UIComponents/PlayPauseButton.qml @@ -0,0 +1,32 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + Button { + id: playPauseButton + icon.source: "icons/" + appearance.themeName + "/pause.svg" + icon.color: appearance.buttonColor + display: AbstractButton.IconOnly + onClicked: { + player.playerCommand(Enums.Commands.TogglePlayPause) + } + background: Item { + } + Connections { + target: player + enabled: true + onPlayStatusChanged: function (status) { + console.log(icon.height) + if (status == Enums.PlayStatus.Playing) { + icon.source = "qrc:/icons/" + appearance.themeName + "/pause.svg" + } else if (status == Enums.PlayStatus.Paused) { + icon.source = "qrc:/icons/" + appearance.themeName + "/play.svg" + } + } + } + } diff --git a/src/qml/UIComponents/PlaylistNextButton.qml b/src/qml/UIComponents/PlaylistNextButton.qml new file mode 100644 index 0000000..0bde443 --- /dev/null +++ b/src/qml/UIComponents/PlaylistNextButton.qml @@ -0,0 +1,23 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + + Button { + id: playlistNextButton + //icon.name: "next" + icon.source: "icons/" + appearance.themeName + "/next.svg" + icon.color: appearance.buttonColor + display: AbstractButton.IconOnly + onClicked: { + player.playerCommand(Enums.Commands.NextPlaylistItem) + } + background: Item { + } + } + diff --git a/src/qml/UIComponents/PlaylistPrevButton.qml b/src/qml/UIComponents/PlaylistPrevButton.qml new file mode 100644 index 0000000..9a30ee7 --- /dev/null +++ b/src/qml/UIComponents/PlaylistPrevButton.qml @@ -0,0 +1,37 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + +Button { + id: playlistPrevButton + objectName: "playlistPrevButton" + icon.source: "icons/" + appearance.themeName + "/prev.svg" + icon.color: appearance.buttonColor + display: AbstractButton.IconOnly + visible: appearance.themeName == "Youtube" ? false : true + onClicked: { + player.playerCommand(Enums.Commands.PreviousPlaylistItem) + } + background: Item { + } + Connections { + target: player + enabled: true + onPlaylistPositionChanged: function (position) { + if (appearance.themeName == "YouTube") { + if (position != 0) { + visible = true + + } else { + visible = false + } + } + } + } + } diff --git a/src/qml/UIComponents/SettingsButton.qml b/src/qml/UIComponents/SettingsButton.qml new file mode 100644 index 0000000..07faf65 --- /dev/null +++ b/src/qml/UIComponents/SettingsButton.qml @@ -0,0 +1,24 @@ + import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + Button { + id: settingsButton + //icon.name: "settings" + icon.source: "icons/" + appearance.themeName + "/settings.svg" + icon.color: appearance.buttonColor + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + display: AbstractButton.IconOnly + onClicked: { + appearance.themeName = appearance.themeName == "YouTube" ? "Niconico" : "YouTube" + controlsBarItem.setControlsTheme(appearance.themeName) + console.log("Settings Menu Not Yet Implemented.") + } + background: Item { + } + } diff --git a/src/qml/UIComponents/TimeLabel.qml b/src/qml/UIComponents/TimeLabel.qml new file mode 100644 index 0000000..73d07df --- /dev/null +++ b/src/qml/UIComponents/TimeLabel.qml @@ -0,0 +1,27 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + Text { + id: timeLabel + objectName: "timeLabel" + text: "0:00 / 0:00" + color: "white" + padding: 2 + font.family: appearance.fontName + font.pixelSize: 14 + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + Connections { + target: player + enabled: true + onDurationStringChanged: function (durationString) { + timeLabel.text = durationString + } + } + } diff --git a/src/qml/UIComponents/VideoProgress.qml b/src/qml/UIComponents/VideoProgress.qml new file mode 100644 index 0000000..8e84039 --- /dev/null +++ b/src/qml/UIComponents/VideoProgress.qml @@ -0,0 +1,181 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + Slider { + id: progressBar + objectName: "progressBar" + to: 1 + value: 0.0 + Connections { + target: player + enabled: true + onPositionChanged: function (position) { + if (!pressed) { + progressBar.value = position + } + } + onDurationChanged: function (duration) { + progressBar.to = duration + } + onCachedDurationChanged: function (duration) { + cachedLength.duration = duration + } + } + onMoved: { + player.playerCommand(Enums.Commands.SeekAbsolute, value) + } + + function getProgressBarHeight(nyan, isMouse) { + var x = Math.max(Screen.height / 256, fun.nyanCat ? 12 : 2) + if (appearance.themeName == "Niconico" && !fun.nyanCat) { + return x * 2 + } else if (isMouse & !fun.nyanCat) { + return x * 2 + } else { + return x + } + } + function getHandleVisibility(themeName, isMouse) { + if (appearance.themeName == "Niconico" && isMouse) { + return true + } else if (appearance.themeName == "Niconico") { + return false + } else { + return true + } + } + MouseArea { + id: mouseAreaProgressBar + width: parent.width + height: parent.height + anchors.fill: parent + y: parent.y + x: parent.x + hoverEnabled: true + propagateComposedEvents: false + acceptedButtons: Qt.NoButton + z: 1 + + onPositionChanged: { + var a = (progressBar.to / progressBar.width ) * mouseAreaProgressBar.mouseX + hoverProgressLabel.text = utils.createTimestamp(a) + } + } + + background: Rectangle { + id: progressBackground + x: progressBar.leftPadding + y: progressBar.topPadding + progressBar.availableHeight / 2 - height / 2 + width: progressBar.availableWidth + height: progressBar.getProgressBarHeight( + fun.nyanCat, mouseAreaProgressBar.containsMouse) + color: appearance.progressBackgroundColor + + + Rectangle { + x: (mouseAreaProgressBar.mouseX - width / 2) + progressBar.leftPadding + y: progressBackground.y - 20 - height + visible: mouseAreaProgressBar.containsMouse + color: appearance.mainBackground + height: 20 + width: 50 + z: 80 + Text { + id: hoverProgressLabel + text: "0:00" + color: "white" + padding: 2 + font.family: appearance.fontName + font.pixelSize: 14 + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + } + } + + ProgressBar { + id: cachedLength + background: Item { + } + contentItem: Item { + Rectangle { + width: cachedLength.visualPosition * parent.width + height: parent.height + color: appearance.progressCachedColor + } + } + z: 40 + to: progressBar.to + property int duration + value: progressBar.value + duration + anchors.fill: parent + } + + Item { + anchors.fill: parent + id: chapterMarkers + Connections { + target: player + enabled: true + onChaptersChanged: function(chapters) { + for (var i = 0, len = chapters.length; i < len; i++) { + var component = Qt.createComponent( + "ChapterMarker.qml") + + var marker = component.createObject(chapterMarkers, + { + time: chapters[i]["time"] + }) + } + } + } + + } + + Rectangle { + id: progressLength + z: 50 + anchors.left: progressBackground.left + width: progressBar.visualPosition * parent.width + height: parent.height + color: appearance.progressSliderColor + Image { + visible: fun.nyanCat + id: rainbow + anchors.fill: parent + height: parent.height + width: parent.width + source: "qrc:/icons/rainbow.png" + fillMode: Image.TileHorizontally + } + } + } + + handle: Rectangle { + z: 70 + id: handleRect + x: progressBar.leftPadding + progressBar.visualPosition + * (progressBar.availableWidth - width) + y: progressBar.topPadding + progressBar.availableHeight / 2 - height / 2 + implicitHeight: radius + implicitWidth: radius + radius: 12 + (progressBackground.height / 2) + color: fun.nyanCat ? "transparent" : appearance.progressSliderColor + visible: getHandleVisibility(appearance.themeName, mouseAreaProgressBar.containsMouse) + AnimatedImage { + z: 80 + visible: fun.nyanCat + paused: progressBar.pressed + height: 30 + id: nyanimation + anchors.centerIn: parent + source: "qrc:/icons/nyancat.gif" + fillMode: Image.PreserveAspectFit + } + } + } diff --git a/src/qml/UIComponents/VolumeButton.qml b/src/qml/UIComponents/VolumeButton.qml new file mode 100644 index 0000000..aa2660f --- /dev/null +++ b/src/qml/UIComponents/VolumeButton.qml @@ -0,0 +1,38 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + + Button { + id: volumeButton + objectName: "volumeButton" + icon.source: "icons/" + appearance.themeName + "/volume-up.svg" + icon.color: appearance.buttonColor + display: AbstractButton.IconOnly + onClicked: { + player.playerCommand(Enums.Commands.ToggleMute) + } + background: Item { + } + Connections { + target: player + enabled: true + onVolumeStatusChanged: function (status){ + if (volumeButton == null) + console.log("OwO"); + + if (status == Enums.VolumeStatus.Muted) { + volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-mute.svg" + } else if (status == Enums.VolumeStatus.Low) { + volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-down.svg" + } else if (status == Enums.VolumeStatus.Normal) { + volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-up.svg" + } + } + } + } diff --git a/src/qml/UIComponents/VolumeSlider.qml b/src/qml/UIComponents/VolumeSlider.qml new file mode 100644 index 0000000..32cacc8 --- /dev/null +++ b/src/qml/UIComponents/VolumeSlider.qml @@ -0,0 +1,63 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + + + Slider { + id: volumeBar + to: 100 + value: 100 + palette.dark: "#f00" + + implicitWidth: Math.max( + background ? background.implicitWidth : 0, + (handle ? handle.implicitWidth : 0) + + leftPadding + rightPadding) + implicitHeight: Math.max( + background ? background.implicitHeight : 0, + (handle ? handle.implicitHeight : 0) + + topPadding + bottomPadding) + onMoved: { + player.playerCommand(Enums.Commands.SetVolume, + Math.round(volumeBar.value).toString()) + } + Connections { + target: player + enabled: true + onVolumeChanged: function (volume){ + volumeBar.value = volume + } + } + handle: Rectangle { + x: volumeBar.leftPadding + volumeBar.visualPosition + * (volumeBar.availableWidth - width) + y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2 + implicitWidth: 12 + implicitHeight: 12 + radius: 12 + visible: appearance.themeName == "Niconico" ? false : true + color: "#f6f6f6" + border.color: "#f6f6f6" + } + + background: Rectangle { + x: volumeBar.leftPadding + y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2 + implicitWidth: appearance.themeName == "Niconico" ? 80 : 60 + implicitHeight: appearance.themeName == "Niconico" ? 4 : 3 + width: volumeBar.availableWidth + height: implicitHeight + color: appearance.progressBackgroundColor + Rectangle { + width: volumeBar.visualPosition * parent.width + height: parent.height + color: appearance.volumeSliderBackground + } + } + } + diff --git a/src/qml/Translator.qml b/src/qml/Utils/Translator.qml similarity index 100% rename from src/qml/Translator.qml rename to src/qml/Utils/Translator.qml diff --git a/src/qml/codes.js b/src/qml/Utils/codes.js similarity index 100% rename from src/qml/codes.js rename to src/qml/Utils/codes.js diff --git a/src/qml/translations.js b/src/qml/Utils/translations.js similarity index 100% rename from src/qml/translations.js rename to src/qml/Utils/translations.js diff --git a/src/qml/YouTubeButtonLayout.qml b/src/qml/YouTubeButtonLayout.qml new file mode 100644 index 0000000..ba5e67b --- /dev/null +++ b/src/qml/YouTubeButtonLayout.qml @@ -0,0 +1,64 @@ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.settings 1.0 +import Qt.labs.platform 1.0 as LabsPlatform +import player 1.0 + +Item { + objectName: "buttonLayout" + id: layout + + PlaylistPrevButton { + id: playlistPrevButton + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: visible ? playlistNextButton.width : 0 + } + PlayPauseButton { + id: playPauseButton + anchors.left: playlistPrevButton.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + PlaylistNextButton { + id: playlistNextButton + anchors.left: playPauseButton.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + VolumeButton { + id: volumeButton + anchors.left: playlistNextButton.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + VolumeSlider { + id: volumeSlider + anchors.left: volumeButton.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + TimeLabel { + anchors.left: volumeSlider.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + SettingsButton { + id: settingsButton + anchors.right: fullscreenButton.left + anchors.top: parent.top + anchors.bottom: parent.bottom + } + FullscreenButton { + id: fullscreenButton + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } +} diff --git a/src/qml/icons/Niconico/fullscreen.svg b/src/qml/icons/Niconico/fullscreen.svg new file mode 100644 index 0000000..ca141bd --- /dev/null +++ b/src/qml/icons/Niconico/fullscreen.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/Niconico/next.svg b/src/qml/icons/Niconico/next.svg new file mode 100644 index 0000000..7ff4a9a --- /dev/null +++ b/src/qml/icons/Niconico/next.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/Niconico/pause.svg b/src/qml/icons/Niconico/pause.svg new file mode 100644 index 0000000..48620df --- /dev/null +++ b/src/qml/icons/Niconico/pause.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/Niconico/play.svg b/src/qml/icons/Niconico/play.svg new file mode 100644 index 0000000..c9676e3 --- /dev/null +++ b/src/qml/icons/Niconico/play.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/Niconico/prev.svg b/src/qml/icons/Niconico/prev.svg new file mode 100644 index 0000000..01b2d8a --- /dev/null +++ b/src/qml/icons/Niconico/prev.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/Niconico/settings.svg b/src/qml/icons/Niconico/settings.svg new file mode 100644 index 0000000..273b638 --- /dev/null +++ b/src/qml/icons/Niconico/settings.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/Niconico/volume-down.svg b/src/qml/icons/Niconico/volume-down.svg new file mode 100644 index 0000000..1b8ff4a --- /dev/null +++ b/src/qml/icons/Niconico/volume-down.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/Niconico/volume-mute.svg b/src/qml/icons/Niconico/volume-mute.svg new file mode 100644 index 0000000..4a94e03 --- /dev/null +++ b/src/qml/icons/Niconico/volume-mute.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/Niconico/volume-up.svg b/src/qml/icons/Niconico/volume-up.svg new file mode 100644 index 0000000..1b8ff4a --- /dev/null +++ b/src/qml/icons/Niconico/volume-up.svg @@ -0,0 +1 @@ + diff --git a/src/qml/icons/README.md b/src/qml/icons/README.md deleted file mode 100644 index e195a8b..0000000 --- a/src/qml/icons/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Icons -- Icons where all from https://material.io/tools/icons/?style=baseline -- Exceptions: nyancat.gif diff --git a/src/qml/icons/backward.svg b/src/qml/icons/YouTube/backward.svg similarity index 100% rename from src/qml/icons/backward.svg rename to src/qml/icons/YouTube/backward.svg diff --git a/src/qml/icons/forward.svg b/src/qml/icons/YouTube/forward.svg similarity index 100% rename from src/qml/icons/forward.svg rename to src/qml/icons/YouTube/forward.svg diff --git a/src/qml/icons/fullscreen.svg b/src/qml/icons/YouTube/fullscreen.svg similarity index 100% rename from src/qml/icons/fullscreen.svg rename to src/qml/icons/YouTube/fullscreen.svg diff --git a/src/qml/icons/next.svg b/src/qml/icons/YouTube/next.svg similarity index 100% rename from src/qml/icons/next.svg rename to src/qml/icons/YouTube/next.svg diff --git a/src/qml/icons/pause.svg b/src/qml/icons/YouTube/pause.svg similarity index 100% rename from src/qml/icons/pause.svg rename to src/qml/icons/YouTube/pause.svg diff --git a/src/qml/icons/play.svg b/src/qml/icons/YouTube/play.svg similarity index 100% rename from src/qml/icons/play.svg rename to src/qml/icons/YouTube/play.svg diff --git a/src/qml/icons/playlist.svg b/src/qml/icons/YouTube/playlist.svg similarity index 100% rename from src/qml/icons/playlist.svg rename to src/qml/icons/YouTube/playlist.svg diff --git a/src/qml/icons/prev.svg b/src/qml/icons/YouTube/prev.svg similarity index 100% rename from src/qml/icons/prev.svg rename to src/qml/icons/YouTube/prev.svg diff --git a/src/qml/icons/settings.svg b/src/qml/icons/YouTube/settings.svg similarity index 100% rename from src/qml/icons/settings.svg rename to src/qml/icons/YouTube/settings.svg diff --git a/src/qml/icons/subtitles.svg b/src/qml/icons/YouTube/subtitles.svg similarity index 100% rename from src/qml/icons/subtitles.svg rename to src/qml/icons/YouTube/subtitles.svg diff --git a/src/qml/icons/volume-down.svg b/src/qml/icons/YouTube/volume-down.svg similarity index 100% rename from src/qml/icons/volume-down.svg rename to src/qml/icons/YouTube/volume-down.svg diff --git a/src/qml/icons/volume-mute.svg b/src/qml/icons/YouTube/volume-mute.svg similarity index 100% rename from src/qml/icons/volume-mute.svg rename to src/qml/icons/YouTube/volume-mute.svg diff --git a/src/qml/icons/volume-up.svg b/src/qml/icons/YouTube/volume-up.svg similarity index 100% rename from src/qml/icons/volume-up.svg rename to src/qml/icons/YouTube/volume-up.svg diff --git a/src/qml/main.qml b/src/qml/main.qml index 39d4806..aaae98f 100644 --- a/src/qml/main.qml +++ b/src/qml/main.qml @@ -17,7 +17,7 @@ Window { height: 480 property bool onTop: false - + Translator { id: translate } @@ -34,6 +34,7 @@ Window { property bool titleOnlyOnFullscreen: true property bool clickToPause: true property bool useMpvSubs: false + property string themeName: "YouTube" property string fontName: "Roboto" property string mainBackground: "#9C000000" property string progressBackgroundColor: "#3CFFFFFF" @@ -41,7 +42,9 @@ Window { property string buttonColor: "white" property string progressSliderColor: "red" property string chapterMarkerColor: "#fc0" + property string volumeSliderBackground: "white" } + Settings { id: i18n category: "I18N" @@ -118,11 +121,11 @@ Window { mainWindow.visibility = lastScreenVisibility } } - + Utils { id: utils } - + PlayerBackend { id: player anchors.fill: parent @@ -196,7 +199,7 @@ Window { } } } - + Item { id: controlsOverlay anchors.centerIn: player @@ -218,7 +221,7 @@ Window { mouseAreaPlayer.cursorShape = Qt.ArrowCursor } } - + MouseArea { id: mouseAreaBar @@ -322,10 +325,12 @@ Window { visible: controlsOverlay.controlsShowing && ((!appearance.titleOnlyOnFullscreen) || (mainWindow.visibility == Window.FullScreen)) - Component.onCompleted: { - player.titleChanged.connect(function (title) { - text = title - }) + Connections { + target: player + enabled: true + onTitleChanged: function (title) { + titleLabel.text = title + } } } } diff --git a/src/qml/qml.qrc b/src/qml/qml.qrc index 46212fa..60aba24 100644 --- a/src/qml/qml.qrc +++ b/src/qml/qml.qrc @@ -1,32 +1,51 @@ - + main.qml - ChapterMarker.qml - PlaylistDialog.qml - CustomComboBox.qml - CustomMenuItem.qml CustomMenu.qml ControlsBar.qml MainMenu.qml - TrackItem.qml - AudioDeviceItem.qml - Translator.qml - translations.js - icons/play.svg - icons/pause.svg - icons/forward.svg - icons/backward.svg - icons/settings.svg - icons/fullscreen.svg - icons/volume-up.svg - icons/volume-mute.svg - icons/volume-down.svg - icons/next.svg - icons/prev.svg - icons/subtitles.svg + YouTubeButtonLayout.qml + NiconicoButtonLayout.qml + UIComponents/PlaylistPrevButton.qml + UIComponents/PlayPauseButton.qml + UIComponents/VideoProgress.qml + UIComponents/VolumeButton.qml + UIComponents/VolumeSlider.qml + UIComponents/TimeLabel.qml + UIComponents/SettingsButton.qml + UIComponents/FullscreenButton.qml + UIComponents/PlaylistNextButton.qml + Utils/codes.js + Utils/Translator.qml + Utils/translations.js + Items/ChapterMarkerItem.qml + Items/TrackItem.qml + Items/AudioDeviceItem.qml + Items/CustomMenuItem.qml + Dialogs/PlaylistDialog.qml + icons/YouTube/play.svg + icons/YouTube/pause.svg + icons/YouTube/forward.svg + icons/YouTube/backward.svg + icons/YouTube/settings.svg + icons/YouTube/fullscreen.svg + icons/YouTube/volume-up.svg + icons/YouTube/volume-mute.svg + icons/YouTube/volume-down.svg + icons/YouTube/next.svg + icons/YouTube/prev.svg + icons/YouTube/subtitles.svg + icons/YouTube/playlist.svg + icons/Niconico/play.svg + icons/Niconico/pause.svg + icons/Niconico/settings.svg + icons/Niconico/volume-up.svg + icons/Niconico/volume-down.svg + icons/Niconico/volume-mute.svg + icons/Niconico/prev.svg + icons/Niconico/next.svg + icons/Niconico/fullscreen.svg icons/nyancat.gif icons/rainbow.png - icons/playlist.svg - codes.js