From c27ce2ebcfc3bf73896f2f42e2d16ec3bc7e0af3 Mon Sep 17 00:00:00 2001 From: reionwong Date: Tue, 12 Oct 2021 08:12:50 +0800 Subject: [PATCH] Add media control --- .../dark/media-playback-pause-symbolic.svg | 6 + .../dark/media-playback-start-symbolic.svg | 3 + .../dark/media-skip-backward-symbolic.svg | 4 + .../dark/media-skip-forward-symbolic.svg | 4 + .../light/media-playback-pause-symbolic.svg | 6 + .../light/media-playback-start-symbolic.svg | 3 + .../light/media-skip-backward-symbolic.svg | 4 + .../light/media-skip-forward-symbolic.svg | 4 + screenlocker/images/media-cover.svg | 4 + screenlocker/qml.qrc | 11 + screenlocker/qml/IconButton.qml | 79 +++++++ screenlocker/qml/LockScreen.qml | 17 +- screenlocker/qml/LoginButton.qml | 1 - screenlocker/qml/MprisItem.qml | 192 ++++++++++++++++++ 14 files changed, 336 insertions(+), 2 deletions(-) create mode 100644 screenlocker/images/dark/media-playback-pause-symbolic.svg create mode 100644 screenlocker/images/dark/media-playback-start-symbolic.svg create mode 100644 screenlocker/images/dark/media-skip-backward-symbolic.svg create mode 100644 screenlocker/images/dark/media-skip-forward-symbolic.svg create mode 100644 screenlocker/images/light/media-playback-pause-symbolic.svg create mode 100644 screenlocker/images/light/media-playback-start-symbolic.svg create mode 100644 screenlocker/images/light/media-skip-backward-symbolic.svg create mode 100644 screenlocker/images/light/media-skip-forward-symbolic.svg create mode 100644 screenlocker/images/media-cover.svg create mode 100644 screenlocker/qml/IconButton.qml create mode 100644 screenlocker/qml/MprisItem.qml diff --git a/screenlocker/images/dark/media-playback-pause-symbolic.svg b/screenlocker/images/dark/media-playback-pause-symbolic.svg new file mode 100644 index 0000000..63c10bf --- /dev/null +++ b/screenlocker/images/dark/media-playback-pause-symbolic.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/screenlocker/images/dark/media-playback-start-symbolic.svg b/screenlocker/images/dark/media-playback-start-symbolic.svg new file mode 100644 index 0000000..d9fd388 --- /dev/null +++ b/screenlocker/images/dark/media-playback-start-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/screenlocker/images/dark/media-skip-backward-symbolic.svg b/screenlocker/images/dark/media-skip-backward-symbolic.svg new file mode 100644 index 0000000..e35c9d5 --- /dev/null +++ b/screenlocker/images/dark/media-skip-backward-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/screenlocker/images/dark/media-skip-forward-symbolic.svg b/screenlocker/images/dark/media-skip-forward-symbolic.svg new file mode 100644 index 0000000..a2c94d7 --- /dev/null +++ b/screenlocker/images/dark/media-skip-forward-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/screenlocker/images/light/media-playback-pause-symbolic.svg b/screenlocker/images/light/media-playback-pause-symbolic.svg new file mode 100644 index 0000000..7929a93 --- /dev/null +++ b/screenlocker/images/light/media-playback-pause-symbolic.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/screenlocker/images/light/media-playback-start-symbolic.svg b/screenlocker/images/light/media-playback-start-symbolic.svg new file mode 100644 index 0000000..551081f --- /dev/null +++ b/screenlocker/images/light/media-playback-start-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/screenlocker/images/light/media-skip-backward-symbolic.svg b/screenlocker/images/light/media-skip-backward-symbolic.svg new file mode 100644 index 0000000..1b85972 --- /dev/null +++ b/screenlocker/images/light/media-skip-backward-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/screenlocker/images/light/media-skip-forward-symbolic.svg b/screenlocker/images/light/media-skip-forward-symbolic.svg new file mode 100644 index 0000000..1193e44 --- /dev/null +++ b/screenlocker/images/light/media-skip-forward-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/screenlocker/images/media-cover.svg b/screenlocker/images/media-cover.svg new file mode 100644 index 0000000..c4542b5 --- /dev/null +++ b/screenlocker/images/media-cover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/screenlocker/qml.qrc b/screenlocker/qml.qrc index 81370ca..e2cfe9c 100644 --- a/screenlocker/qml.qrc +++ b/screenlocker/qml.qrc @@ -5,5 +5,16 @@ qml/LoginButton.qml images/screensaver-unlock-symbolic.svg images/system-lock-screen-symbolic.svg + qml/MprisItem.qml + images/media-cover.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 + qml/IconButton.qml diff --git a/screenlocker/qml/IconButton.qml b/screenlocker/qml/IconButton.qml new file mode 100644 index 0000000..010e066 --- /dev/null +++ b/screenlocker/qml/IconButton.qml @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import FishUI 1.0 as FishUI + +Item { + id: control + + property url source + property real size: 24 + property string popupText + + signal leftButtonClicked + signal rightButtonClicked + + MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + hoverEnabled: control.visible ? true : false + + onClicked: { + if (mouse.button === Qt.LeftButton) + control.leftButtonClicked() + else if (mouse.button === Qt.RightButton) + control.rightButtonClicked() + } + } + + Rectangle { + anchors.fill: parent + anchors.margins: 1 + // radius: parent.height * 0.2 + radius: parent.height / 2 + + color: { + if (mouseArea.containsMouse) { + if (mouseArea.containsPress) + return (FishUI.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.3) : Qt.rgba(0, 0, 0, 0.2) + else + return (FishUI.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.2) : Qt.rgba(0, 0, 0, 0.1) + } + + return "transparent" + } + } + + Image { + id: iconImage + anchors.centerIn: parent + width: parent.height * 0.8 + height: width + sourceSize.width: width + sourceSize.height: height + source: control.source + asynchronous: true + antialiasing: true + smooth: false + } +} diff --git a/screenlocker/qml/LockScreen.qml b/screenlocker/qml/LockScreen.qml index 2571893..c9c360f 100644 --- a/screenlocker/qml/LockScreen.qml +++ b/screenlocker/qml/LockScreen.qml @@ -171,7 +171,7 @@ Item { Item { id: _mainItem anchors.centerIn: parent - width: 260 + FishUI.Units.largeSpacing * 3 + width: 280 + FishUI.Units.largeSpacing * 3 height: _mainLayout.implicitHeight + FishUI.Units.largeSpacing * 4 Layout.alignment: Qt.AlignHCenter @@ -312,6 +312,21 @@ Item { visible: true } + Item { + // anchors.top: message.bottom + // anchors.topMargin: FishUI.Units.largeSpacing + anchors.bottom: parent.bottom + anchors.bottomMargin: root.height * 0.05 //FishUI.Units.largeSpacing + anchors.horizontalCenter: parent.horizontalCenter + + width: 280 + FishUI.Units.largeSpacing * 3 + height: 70 + + MprisItem { + anchors.fill: parent + } + } + function tryUnlock() { if (!password.text) { notificationResetTimer.start() diff --git a/screenlocker/qml/LoginButton.qml b/screenlocker/qml/LoginButton.qml index 446bde4..70dfcb2 100644 --- a/screenlocker/qml/LoginButton.qml +++ b/screenlocker/qml/LoginButton.qml @@ -54,7 +54,6 @@ Item { id: mouseArea anchors.fill: parent hoverEnabled: true - onClicked: control.clicked() } diff --git a/screenlocker/qml/MprisItem.qml b/screenlocker/qml/MprisItem.qml new file mode 100644 index 0000000..9c0c8d8 --- /dev/null +++ b/screenlocker/qml/MprisItem.qml @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import QtGraphicalEffects 1.0 +import FishUI 1.0 as FishUI +import Cutefish.Mpris 1.0 + +Item { + id: control + + property bool available: mprisManager.availableServices.length > 0 + property bool isPlaying: currentService && mprisManager.playbackStatus === Mpris.Playing + property alias currentService: mprisManager.currentService + property var artUrlTag: Mpris.metadataToString(Mpris.ArtUrl) + property var titleTag: Mpris.metadataToString(Mpris.Title) + property var artistTag: Mpris.metadataToString(Mpris.Artist) + + MprisManager { + id: mprisManager + + onCurrentServiceChanged: { + control.updateInfo() + } + + onMetadataChanged: { + control.updateInfo() + } + } + + Component.onCompleted: { control.updateInfo() } + + function updateInfo() { + var titleAvailable = (titleTag in mprisManager.metadata) ? mprisManager.metadata[titleTag].toString() !== "" : false + var artistAvailable = (artistTag in mprisManager.metadata) ? mprisManager.metadata[artistTag].toString() !== "" : false + + control.visible = titleAvailable || artistAvailable + _songLabel.text = titleAvailable ? mprisManager.metadata[titleTag].toString() : "" + _artistLabel.text = artistAvailable ? mprisManager.metadata[artistTag].toString() : "" + artImage.source = (artUrlTag in mprisManager.metadata) ? mprisManager.metadata[artUrlTag].toString() : "" + } + + Rectangle { + anchors.fill: parent + radius: FishUI.Theme.bigRadius + 2 + color: FishUI.Theme.darkMode ? "#424242" : "white" + opacity: 0.5 + } + + RowLayout { + id: _mainLayout + anchors.fill: parent + anchors.margins: FishUI.Units.largeSpacing + spacing: FishUI.Units.largeSpacing + + Image { + id: defaultImage + width: _mainLayout.height + height: width + source: "qrc:/images/media-cover.svg" + sourceSize: Qt.size(width, height) + visible: !artImage.visible + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Item { + width: defaultImage.width + height: defaultImage.height + + Rectangle { + anchors.fill: parent + radius: FishUI.Theme.smallRadius + } + } + } + } + + Image { + id: artImage + Layout.preferredHeight: _mainLayout.height + Layout.preferredWidth: _mainLayout.height + visible: status === Image.Ready + // sourceSize: Qt.size(width, height) + fillMode: Image.PreserveAspectFit + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Item { + width: artImage.width + height: artImage.height + + Rectangle { + anchors.fill: parent + radius: FishUI.Theme.smallRadius + } + } + } + } + + Item { + Layout.fillHeight: true + Layout.fillWidth: true + + ColumnLayout { + anchors.fill: parent + + Item { + Layout.fillHeight: true + } + + Label { + id: _songLabel + Layout.fillWidth: true + visible: _songLabel.text !== "" + elide: Text.ElideRight + } + + Label { + id: _artistLabel + Layout.fillWidth: true + visible: _artistLabel.text !== "" + elide: Text.ElideRight + } + + Item { + Layout.fillHeight: true + } + } + } + + Item { + id: _buttons + Layout.fillHeight: true + Layout.preferredWidth: _buttonsLayout.implicitWidth + + RowLayout { + id: _buttonsLayout + anchors.fill: parent + spacing: FishUI.Units.smallSpacing + + IconButton { + width: 30 + height: 30 + source: "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/media-skip-backward-symbolic.svg" + onLeftButtonClicked: if (mprisManager.canGoPrevious) mprisManager.previous() + visible: mprisManager.canGoPrevious + Layout.alignment: Qt.AlignRight + } + + IconButton { + width: 30 + height: 30 + source: control.isPlaying ? "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/media-playback-pause-symbolic.svg" + : "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/media-playback-start-symbolic.svg" + Layout.alignment: Qt.AlignRight + visible: mprisManager.canPause || mprisManager.canPlay + onLeftButtonClicked: + if ((control.isPlaying && mprisManager.canPause) || (!control.isPlaying && mprisManager.canPlay)) { + mprisManager.playPause() + } + } + + IconButton { + width: 30 + height: 30 + source: "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/media-skip-forward-symbolic.svg" + Layout.alignment: Qt.AlignRight + visible: mprisManager.canGoNext + onLeftButtonClicked: if (mprisManager.canGoNext) mprisManager.next() + } + } + } + } +}