refactor: migration to be based on https://github.com/ruinivist/kde-6-widget-starter
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
import QtQuick
|
||||
import org.kde.plasma.configuration
|
||||
|
||||
ConfigModel {
|
||||
ConfigCategory {
|
||||
name: i18n("General")
|
||||
icon: "preferences-desktop"
|
||||
source: "configGeneral.qml"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name=""/>
|
||||
<group name="General">
|
||||
<entry name="opacity" type="Int">
|
||||
<label>Opacity</label>
|
||||
<default>100</default>
|
||||
</entry>
|
||||
<entry name="fontFamily" type="String">
|
||||
<label>Font family</label>
|
||||
<default>Noto Sans</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
Credits: https://github.com/ccatterina/plasmusic-toolbar
|
||||
|
||||
looked handy, ty
|
||||
*/
|
||||
|
||||
import QtQml.Models
|
||||
import QtQuick
|
||||
import org.kde.plasma.private.mpris as Mpris
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
property string sourceName: "any"
|
||||
property var mpris2Model
|
||||
readonly property bool ready: {
|
||||
if (!mpris2Model.currentPlayer)
|
||||
return false;
|
||||
|
||||
return mpris2Model.currentPlayer.desktopEntry === sourceName || sourceName === "any";
|
||||
}
|
||||
readonly property string artists: ready ? mpris2Model.currentPlayer.artist : ""
|
||||
readonly property string title: ready ? mpris2Model.currentPlayer.track : ""
|
||||
readonly property int playbackStatus: ready ? mpris2Model.currentPlayer.playbackStatus : Mpris.PlaybackStatus.Unknown
|
||||
readonly property int shuffle: ready ? mpris2Model.currentPlayer.shuffle : Mpris.ShuffleStatus.Unknown
|
||||
readonly property string artUrl: ready ? mpris2Model.currentPlayer.artUrl : ""
|
||||
readonly property int loopStatus: ready ? mpris2Model.currentPlayer.loopStatus : Mpris.LoopStatus.Unknown
|
||||
readonly property double songPosition: ready ? mpris2Model.currentPlayer.position : 0
|
||||
readonly property double songLength: ready ? mpris2Model.currentPlayer.length : 0
|
||||
readonly property real volume: ready ? mpris2Model.currentPlayer.volume : 0
|
||||
readonly property string identity: ready ? mpris2Model.currentPlayer.identity : ""
|
||||
readonly property bool canGoNext: ready ? mpris2Model.currentPlayer.canGoNext : false
|
||||
readonly property bool canGoPrevious: ready ? mpris2Model.currentPlayer.canGoPrevious : false
|
||||
readonly property bool canPlay: ready ? mpris2Model.currentPlayer.canPlay : false
|
||||
readonly property bool canPause: ready ? mpris2Model.currentPlayer.canPause : false
|
||||
readonly property bool canSeek: ready ? mpris2Model.currentPlayer.canSeek : false
|
||||
readonly property bool canRaise: ready ? mpris2Model.currentPlayer.canRaise : false
|
||||
// To know whether Shuffle and Loop can be changed we have to check if the property is defined,
|
||||
// unlike the other commands, LoopStatus and Shuffle do not have specific properties such as
|
||||
// CanPause, CanSeek, etc.
|
||||
readonly property bool canChangeShuffle: ready ? mpris2Model.currentPlayer.shuffle !== undefined : false
|
||||
readonly property bool canChangeLoopStatus: ready ? mpris2Model.currentPlayer.loopStatus !== undefined : false
|
||||
|
||||
function togglePlayPause() {
|
||||
if (mpris2Model.currentPlayer)
|
||||
mpris2Model.currentPlayer.PlayPause();
|
||||
|
||||
}
|
||||
|
||||
function setPosition(position) {
|
||||
mpris2Model.currentPlayer.position = position;
|
||||
}
|
||||
|
||||
function next() {
|
||||
if (mpris2Model.currentPlayer)
|
||||
mpris2Model.currentPlayer.Next();
|
||||
|
||||
}
|
||||
|
||||
function previous() {
|
||||
if (mpris2Model.currentPlayer)
|
||||
mpris2Model.currentPlayer.Previous();
|
||||
|
||||
}
|
||||
|
||||
function updatePosition() {
|
||||
if (mpris2Model.currentPlayer)
|
||||
mpris2Model.currentPlayer.updatePosition();
|
||||
|
||||
}
|
||||
|
||||
function setVolume(volume) {
|
||||
mpris2Model.currentPlayer.volume = volume;
|
||||
}
|
||||
|
||||
function changeVolume(delta, showOSD) {
|
||||
mpris2Model.currentPlayer.changeVolume(delta, showOSD);
|
||||
}
|
||||
|
||||
function setShuffle(shuffle) {
|
||||
mpris2Model.currentPlayer.shuffle = shuffle;
|
||||
}
|
||||
|
||||
function setLoopStatus(loopStatus) {
|
||||
mpris2Model.currentPlayer.loopStatus = loopStatus;
|
||||
}
|
||||
|
||||
function raise() {
|
||||
mpris2Model.currentPlayer.Raise();
|
||||
}
|
||||
|
||||
function formatTrackTime(s) {
|
||||
const hours = Math.floor(s / 3600);
|
||||
let minutes = Math.floor((s - hours * 3600) / 60);
|
||||
let seconds = Math.ceil(s - hours * 3600 - minutes * 60);
|
||||
minutes = minutes < 10 ? "0" + minutes : minutes;
|
||||
seconds = seconds < 10 ? "0" + seconds : seconds;
|
||||
return minutes + ":" + seconds;
|
||||
}
|
||||
|
||||
mpris2Model: Mpris.Mpris2Model {
|
||||
onRowsInserted: (_, rowIndex) => {
|
||||
const CONTAINER_ROLE = Qt.UserRole + 1;
|
||||
const player = this.data(this.index(rowIndex, 0), CONTAINER_ROLE);
|
||||
if (player.desktopEntry === root.sourceName)
|
||||
this.currentIndex = rowIndex;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.plasma.components as PlasmaComponents
|
||||
|
||||
MouseArea {
|
||||
id: mediaControlsMouseArea
|
||||
|
||||
readonly property double buttonSize: 16
|
||||
|
||||
focus: true
|
||||
hoverEnabled: true
|
||||
Keys.onPressed: (event) => {
|
||||
if (!event.modifiers) {
|
||||
event.accepted = true;
|
||||
if (event.key === Qt.Key_Space || event.key === Qt.Key_K)
|
||||
player.togglePlayPause();
|
||||
else if (event.key === Qt.Key_P)
|
||||
player.previous();
|
||||
else if (event.key === Qt.Key_N)
|
||||
player.next();
|
||||
else
|
||||
event.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
id: leftColumn
|
||||
|
||||
Layout.fillHeight: true
|
||||
states: [
|
||||
State {
|
||||
name: "buttonsVisible"
|
||||
when: mediaControlsMouseArea.containsMouse
|
||||
|
||||
PropertyChanges {
|
||||
target: nowPlayingLabels
|
||||
Layout.bottomMargin: 10
|
||||
}
|
||||
|
||||
},
|
||||
State {
|
||||
name: "buttonsHidden"
|
||||
when: !mediaControlsMouseArea.containsMouse
|
||||
|
||||
PropertyChanges {
|
||||
target: nowPlayingLabels
|
||||
Layout.bottomMargin: 0
|
||||
}
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: nowPlayingLabels
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
spacing: 0
|
||||
|
||||
PlasmaComponents.Label {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "NOW"
|
||||
lineHeight: 0.8
|
||||
font.pixelSize: 16
|
||||
font.bold: true
|
||||
// qmllint disable missing-property
|
||||
font.family: plasmoid.configuration.fontFamily
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
id: nowPlayingLabel2
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "PLAYING"
|
||||
lineHeight: 0.8
|
||||
font.bold: true
|
||||
font.pixelSize: 16
|
||||
// qmllint disable missing-property
|
||||
font.family: plasmoid.configuration.fontFamily
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: mediaControls
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
opacity: mediaControlsMouseArea.containsMouse ? 1 : 0
|
||||
visible: opacity > 0
|
||||
|
||||
QQC2.Button {
|
||||
Layout.preferredWidth: buttonSize
|
||||
Layout.preferredHeight: buttonSize
|
||||
padding: 0
|
||||
background: null
|
||||
onClicked: {
|
||||
player.previous();
|
||||
console.log("prev clicked");
|
||||
}
|
||||
|
||||
contentItem: Kirigami.Icon {
|
||||
source: "media-skip-backward"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
id: playButton
|
||||
|
||||
Layout.preferredWidth: buttonSize
|
||||
Layout.preferredHeight: buttonSize
|
||||
padding: 0
|
||||
background: null
|
||||
onClicked: {
|
||||
player.togglePlayPause();
|
||||
console.log("pause clicked");
|
||||
}
|
||||
|
||||
contentItem: Kirigami.Icon {
|
||||
source: player.playbackStatus === 2 ? "media-playback-pause" : "media-playback-start"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
Layout.preferredWidth: buttonSize
|
||||
Layout.preferredHeight: buttonSize
|
||||
padding: 0
|
||||
background: null
|
||||
onClicked: player.next()
|
||||
|
||||
contentItem: Kirigami.Icon {
|
||||
source: "media-skip-forward"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
PropertyAnimation {
|
||||
duration: 250
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
NumberAnimation {
|
||||
duration: 250
|
||||
easing.type: Easing.InOutQuad
|
||||
properties: "Layout.bottomMargin"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: separator
|
||||
|
||||
Layout.fillHeight: true
|
||||
width: 1
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: infoColumn
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
PlasmaComponents.Label {
|
||||
Layout.fillWidth: true
|
||||
text: player.title
|
||||
font.pixelSize: 28
|
||||
font.bold: true
|
||||
// qmllint disable missing-property
|
||||
font.family: plasmoid.configuration.fontFamily
|
||||
lineHeight: 0.8
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
Layout.maximumWidth: 300
|
||||
Layout.fillWidth: true
|
||||
text: player.artists
|
||||
font.pixelSize: 26
|
||||
// qmllint disable missing-property
|
||||
font.family: plasmoid.configuration.fontFamily
|
||||
lineHeight: 0.8
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kcmutils as KCM
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
KCM.SimpleKCM {
|
||||
id: configRoot
|
||||
|
||||
property alias cfg_opacity: opacitySpinBox.value
|
||||
property string cfg_fontFamily
|
||||
readonly property var availableFonts: Qt.fontFamilies()
|
||||
|
||||
onCfg_fontFamilyChanged: {
|
||||
const index = availableFonts.indexOf(cfg_fontFamily);
|
||||
if (index >= 0 && fontFamilyComboBox.currentIndex !== index)
|
||||
fontFamilyComboBox.currentIndex = index;
|
||||
|
||||
}
|
||||
|
||||
Kirigami.FormLayout {
|
||||
QQC2.SpinBox {
|
||||
id: opacitySpinBox
|
||||
|
||||
Kirigami.FormData.label: i18n("Opacity percent:")
|
||||
from: 0
|
||||
to: 100
|
||||
}
|
||||
|
||||
QQC2.ComboBox {
|
||||
id: fontFamilyComboBox
|
||||
|
||||
Kirigami.FormData.label: i18n("Font:")
|
||||
model: configRoot.availableFonts
|
||||
onActivated: configRoot.cfg_fontFamily = currentText
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.plasma.plasmoid
|
||||
|
||||
PlasmoidItem {
|
||||
id: root
|
||||
|
||||
// Properties accessed from configuration.
|
||||
// "qmllint" sees `plasmoid` as QObject here, but Plasma injects `configuration` at runtime.
|
||||
// qmllint disable missing-property
|
||||
property int configuredOpacity: plasmoid.configuration.opacity
|
||||
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
height: Kirigami.Units.gridUnit * 5
|
||||
Layout.minimumWidth: Kirigami.Units.gridUnit * 25
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
|
||||
Plasmoid.backgroundHints: "NoBackground"
|
||||
opacity: configuredOpacity / 100
|
||||
|
||||
Player {
|
||||
id: player
|
||||
}
|
||||
|
||||
fullRepresentation: Representation {
|
||||
Layout.minimumWidth: Kirigami.Units.gridUnit * 25
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
|
||||
Layout.preferredWidth: root.width
|
||||
Layout.preferredHeight: root.height
|
||||
}
|
||||
|
||||
compactRepresentation: Representation {
|
||||
Layout.minimumWidth: Kirigami.Units.gridUnit * 25
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Name": "ruinivist"
|
||||
}
|
||||
],
|
||||
"Category": "Multimedia",
|
||||
"Description": "An aesthetic song name widget with media controls. Meant to be placed on Desktop not in panel.",
|
||||
"Icon": "applications-multimedia",
|
||||
"Id": "org.ruiny.NowPlaying",
|
||||
"License": "GPLv3",
|
||||
"Name": "NowPlaying",
|
||||
"Version": "1.0",
|
||||
"Website": "https://github.com/ruinivist/NowPlaying"
|
||||
},
|
||||
"KPackageStructure": "Plasma/Applet",
|
||||
"X-Plasma-API-Minimum-Version": "6.0",
|
||||
"X-Plasma-Provides": ["org.kde.plasma.multimediacontrols"],
|
||||
"X-Plasma-DBusActivationService": "org.mpris.MediaPlayer2.*"
|
||||
}
|
||||
Reference in New Issue
Block a user