2023-09-27 05:41:52 +00:00
|
|
|
// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
|
|
|
|
|
// SPDX-FileCopyrightText: 2016 Kai Uwe Broulik <kde@privat.broulik.de>
|
|
|
|
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2023-05-13 15:15:52 +00:00
|
|
|
import QtQuick
|
|
|
|
|
import QtQuick.Layouts
|
|
|
|
|
import QtQuick.Controls as QQC2
|
2024-08-01 01:18:33 +00:00
|
|
|
import QtQuick.Effects
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2023-05-13 15:15:52 +00:00
|
|
|
import org.kde.kirigami as Kirigami
|
2024-07-26 01:22:04 +00:00
|
|
|
import org.kde.plasma.components 3.0 as PC3
|
2023-11-02 11:08:17 +00:00
|
|
|
import org.kde.plasma.private.mobileshell as MobileShell
|
|
|
|
|
import org.kde.plasma.private.mobileshell.state as MobileShellState
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2023-09-27 05:41:52 +00:00
|
|
|
import org.kde.plasma.private.mpris as Mpris
|
|
|
|
|
|
2022-04-09 01:48:42 +00:00
|
|
|
/**
|
|
|
|
|
* Embeddable component that provides MPRIS control.
|
|
|
|
|
*/
|
|
|
|
|
Item {
|
2021-12-22 23:29:00 +00:00
|
|
|
id: root
|
2023-09-27 05:41:52 +00:00
|
|
|
visible: sourceRepeater.count > 0
|
2024-07-26 01:22:04 +00:00
|
|
|
|
2025-06-23 00:16:16 +00:00
|
|
|
property int panelType: MobileShell.PanelBackground.PanelType.Drawer
|
2024-07-26 01:22:04 +00:00
|
|
|
property bool detailledView: false
|
|
|
|
|
|
2023-09-27 05:41:52 +00:00
|
|
|
readonly property real padding: Kirigami.Units.gridUnit
|
2024-07-31 14:16:13 +00:00
|
|
|
readonly property real contentHeight: {
|
|
|
|
|
let heightMultiplier = detailledView ? 2 : 1
|
|
|
|
|
Kirigami.Units.gridUnit * 2 * heightMultiplier
|
|
|
|
|
}
|
2022-04-09 01:48:42 +00:00
|
|
|
implicitHeight: visible ? padding * 2 + contentHeight : 0
|
2024-07-26 01:22:04 +00:00
|
|
|
|
|
|
|
|
Behavior on implicitHeight {
|
2024-07-31 14:16:13 +00:00
|
|
|
NumberAnimation {
|
2025-06-23 00:16:16 +00:00
|
|
|
duration: implicitHeight == 0 ? 0 : Kirigami.Units.longDuration
|
|
|
|
|
easing.type: Easing.OutQuart
|
2024-07-31 14:16:13 +00:00
|
|
|
}
|
2024-07-26 01:22:04 +00:00
|
|
|
}
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2022-04-09 01:48:42 +00:00
|
|
|
MediaControlsSource {
|
|
|
|
|
id: mpris2Source
|
2021-12-22 23:29:00 +00:00
|
|
|
}
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2022-04-09 01:48:42 +00:00
|
|
|
// page indicator
|
|
|
|
|
RowLayout {
|
|
|
|
|
z: 1
|
|
|
|
|
visible: view.count > 1
|
|
|
|
|
spacing: Kirigami.Units.smallSpacing
|
2023-09-27 05:41:52 +00:00
|
|
|
anchors.bottomMargin: Kirigami.Units.smallSpacing
|
2022-04-09 01:48:42 +00:00
|
|
|
anchors.bottom: view.bottom
|
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2022-04-09 01:48:42 +00:00
|
|
|
Repeater {
|
|
|
|
|
model: view.count
|
|
|
|
|
delegate: Rectangle {
|
|
|
|
|
width: Kirigami.Units.smallSpacing
|
|
|
|
|
height: Kirigami.Units.smallSpacing
|
|
|
|
|
radius: width / 2
|
|
|
|
|
color: Qt.rgba(255, 255, 255, view.currentIndex == model.index ? 1 : 0.5)
|
|
|
|
|
}
|
2021-12-22 23:29:00 +00:00
|
|
|
}
|
2022-04-09 01:48:42 +00:00
|
|
|
}
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2025-06-23 00:16:16 +00:00
|
|
|
MobileShell.PanelBackground {
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
panelType: root.panelType
|
2024-08-01 01:18:33 +00:00
|
|
|
}
|
|
|
|
|
|
2022-04-09 01:48:42 +00:00
|
|
|
// list of app media widgets
|
|
|
|
|
QQC2.SwipeView {
|
|
|
|
|
id: view
|
|
|
|
|
clip: true
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2022-04-09 01:48:42 +00:00
|
|
|
anchors.fill: parent
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2022-04-09 01:48:42 +00:00
|
|
|
Repeater {
|
2023-09-27 05:41:52 +00:00
|
|
|
id: sourceRepeater
|
|
|
|
|
model: mpris2Source.mpris2Model
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2022-05-16 18:17:03 +00:00
|
|
|
delegate: Loader {
|
2023-09-27 05:41:52 +00:00
|
|
|
id: delegate
|
|
|
|
|
// NOTE: model is PlayerContainer from KMpris in plasma-workspace
|
|
|
|
|
|
2022-05-16 18:17:03 +00:00
|
|
|
asynchronous: true
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2023-09-27 05:41:52 +00:00
|
|
|
function getTrackName() {
|
|
|
|
|
console.log('track name: ' + model.title);
|
|
|
|
|
if (model.title) {
|
|
|
|
|
return model.title;
|
|
|
|
|
}
|
|
|
|
|
// if no track title is given, print out the file name
|
|
|
|
|
if (!model.url) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
const lastSlashPos = model.url.lastIndexOf('/')
|
|
|
|
|
if (lastSlashPos < 0) {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
const lastUrlPart = model.url.substring(lastSlashPos + 1);
|
|
|
|
|
return decodeURIComponent(lastUrlPart);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-26 01:22:04 +00:00
|
|
|
function msecToString(duration: int): string {
|
|
|
|
|
let seconds = Math.floor(duration / 1000000)
|
|
|
|
|
let minutes = Math.floor(seconds / 60)
|
|
|
|
|
seconds -= minutes * 60
|
|
|
|
|
return `${minutes}:${seconds.toString().padStart(2, '0')}`
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-12 22:10:08 +00:00
|
|
|
sourceComponent: MouseArea {
|
|
|
|
|
id: mouseArea
|
2024-08-01 01:35:20 +00:00
|
|
|
implicitHeight: root.contentHeight + root.padding * 2
|
|
|
|
|
implicitWidth: root.width
|
2024-07-26 01:22:04 +00:00
|
|
|
|
|
|
|
|
onPressAndHold: {
|
2023-11-02 11:08:17 +00:00
|
|
|
MobileShell.AppLaunch.launchOrActivateApp(model.desktopEntry + ".desktop");
|
2023-03-20 01:32:19 +00:00
|
|
|
MobileShellState.ShellDBusClient.closeActionDrawer();
|
2022-05-16 18:17:03 +00:00
|
|
|
}
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2024-07-26 01:22:04 +00:00
|
|
|
onClicked: {
|
|
|
|
|
root.detailledView = !root.detailledView
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-01 01:35:20 +00:00
|
|
|
BlurredBackground {
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
darken: mouseArea.pressed
|
|
|
|
|
inActionDrawer: root.inActionDrawer
|
|
|
|
|
imageSource: model.artUrl
|
|
|
|
|
}
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2023-11-02 11:08:17 +00:00
|
|
|
MobileShell.BaseItem {
|
2022-10-12 22:10:08 +00:00
|
|
|
id: playerItem
|
2024-08-01 01:35:20 +00:00
|
|
|
anchors.top: parent.top
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
anchors.right: parent.right
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2022-10-12 22:10:08 +00:00
|
|
|
padding: root.padding
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2024-07-26 01:22:04 +00:00
|
|
|
contentItem: ColumnLayout {
|
2022-10-12 22:10:08 +00:00
|
|
|
width: playerItem.width - playerItem.leftPadding - playerItem.rightPadding
|
2024-07-26 01:22:04 +00:00
|
|
|
spacing: Kirigami.Units.largeSpacing
|
2024-07-27 03:47:44 +00:00
|
|
|
|
2022-10-12 22:10:08 +00:00
|
|
|
RowLayout {
|
|
|
|
|
id: controlsRow
|
|
|
|
|
spacing: 0
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2023-09-27 05:41:52 +00:00
|
|
|
enabled: model.canControl
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2022-10-12 22:10:08 +00:00
|
|
|
Image {
|
|
|
|
|
id: albumArt
|
|
|
|
|
Layout.preferredWidth: height
|
2024-07-26 01:22:04 +00:00
|
|
|
Layout.preferredHeight: controlsRow.height
|
2022-10-12 22:10:08 +00:00
|
|
|
asynchronous: true
|
|
|
|
|
fillMode: Image.PreserveAspectFit
|
2023-09-27 05:41:52 +00:00
|
|
|
source: model.artUrl
|
2022-10-12 22:10:08 +00:00
|
|
|
sourceSize.height: height
|
|
|
|
|
visible: status === Image.Loading || status === Image.Ready
|
|
|
|
|
}
|
2022-05-16 18:15:48 +00:00
|
|
|
|
2022-10-12 22:10:08 +00:00
|
|
|
ColumnLayout {
|
2023-07-25 01:13:52 +00:00
|
|
|
Layout.leftMargin: albumArt.visible ? Kirigami.Units.gridUnit : 0
|
2024-07-26 01:22:04 +00:00
|
|
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
2022-05-16 18:17:03 +00:00
|
|
|
Layout.fillWidth: true
|
2022-10-12 22:10:08 +00:00
|
|
|
spacing: Kirigami.Units.smallSpacing
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2023-09-27 05:41:52 +00:00
|
|
|
// media track name text
|
2023-11-02 11:08:17 +00:00
|
|
|
MobileShell.MarqueeLabel {
|
2023-09-27 05:41:52 +00:00
|
|
|
id: trackLabel
|
2022-10-12 22:10:08 +00:00
|
|
|
Layout.fillWidth: true
|
2022-05-16 18:17:03 +00:00
|
|
|
|
2023-09-27 05:41:52 +00:00
|
|
|
inputText: model.track || i18n("No media playing");
|
2022-10-12 22:10:08 +00:00
|
|
|
textFormat: Text.PlainText
|
2023-07-25 01:13:52 +00:00
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize
|
2022-10-12 22:10:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-27 05:41:52 +00:00
|
|
|
// media artist name text
|
2023-11-02 11:08:17 +00:00
|
|
|
MobileShell.MarqueeLabel {
|
2023-09-27 05:41:52 +00:00
|
|
|
id: artistLabel
|
2022-10-12 22:10:08 +00:00
|
|
|
Layout.fillWidth: true
|
2022-05-16 18:15:48 +00:00
|
|
|
|
2022-10-12 22:10:08 +00:00
|
|
|
// if no artist is given, show player name instead
|
2023-09-27 05:41:52 +00:00
|
|
|
inputText: model.artist || model.identity || ""
|
2022-10-12 22:10:08 +00:00
|
|
|
textFormat: Text.PlainText
|
2023-07-25 01:13:52 +00:00
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.9
|
2022-10-12 22:10:08 +00:00
|
|
|
opacity: 0.9
|
|
|
|
|
}
|
2022-05-16 18:17:03 +00:00
|
|
|
}
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2024-03-09 05:48:49 +00:00
|
|
|
QQC2.ToolButton {
|
2023-09-27 05:41:52 +00:00
|
|
|
enabled: model.canGoPrevious
|
2022-10-12 22:10:08 +00:00
|
|
|
icon.name: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward"
|
2024-07-26 01:22:04 +00:00
|
|
|
icon.width: Kirigami.Units.iconSizes.smallMedium
|
|
|
|
|
icon.height: Kirigami.Units.iconSizes.smallMedium
|
2023-09-27 05:41:52 +00:00
|
|
|
onClicked: {
|
|
|
|
|
mpris2Source.setIndex(model.index);
|
|
|
|
|
mpris2Source.goPrevious();
|
|
|
|
|
}
|
|
|
|
|
visible: model.canGoPrevious || model.canGoNext
|
2022-10-12 22:10:08 +00:00
|
|
|
Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Previous track")
|
|
|
|
|
}
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2024-03-09 05:48:49 +00:00
|
|
|
QQC2.ToolButton {
|
2023-09-27 05:41:52 +00:00
|
|
|
icon.name: (model.playbackStatus === Mpris.PlaybackStatus.Playing) ? "media-playback-pause" : "media-playback-start"
|
2024-07-26 01:22:04 +00:00
|
|
|
icon.width: Kirigami.Units.iconSizes.smallMedium
|
|
|
|
|
icon.height: Kirigami.Units.iconSizes.smallMedium
|
2023-09-27 05:41:52 +00:00
|
|
|
onClicked: {
|
|
|
|
|
mpris2Source.setIndex(model.index);
|
|
|
|
|
mpris2Source.playPause();
|
|
|
|
|
}
|
2022-10-12 22:10:08 +00:00
|
|
|
Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Play or Pause media")
|
|
|
|
|
}
|
2021-12-22 23:29:00 +00:00
|
|
|
|
2024-03-09 05:48:49 +00:00
|
|
|
QQC2.ToolButton {
|
2023-09-27 05:41:52 +00:00
|
|
|
enabled: model.canGoNext
|
2022-10-12 22:10:08 +00:00
|
|
|
icon.name: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward"
|
2024-07-26 01:22:04 +00:00
|
|
|
icon.width: Kirigami.Units.iconSizes.smallMedium
|
|
|
|
|
icon.height: Kirigami.Units.iconSizes.smallMedium
|
2023-09-27 05:41:52 +00:00
|
|
|
onClicked: {
|
|
|
|
|
mpris2Source.setIndex(model.index);
|
|
|
|
|
mpris2Source.goNext();
|
|
|
|
|
}
|
|
|
|
|
visible: model.canGoPrevious || model.canGoNext
|
2022-10-12 22:10:08 +00:00
|
|
|
Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Next track")
|
|
|
|
|
}
|
2022-05-16 18:17:03 +00:00
|
|
|
}
|
2024-07-26 01:22:04 +00:00
|
|
|
|
|
|
|
|
RowLayout {
|
|
|
|
|
id: timerControlsRow
|
|
|
|
|
|
|
|
|
|
spacing: Kirigami.Units.largeSpacing
|
|
|
|
|
|
|
|
|
|
visible: root.detailledView
|
|
|
|
|
|
|
|
|
|
Text {
|
|
|
|
|
text: msecToString(model.position)
|
|
|
|
|
|
|
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.9
|
2024-08-01 01:18:33 +00:00
|
|
|
color: Kirigami.Theme.textColor
|
2024-07-26 01:22:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PC3.Slider {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
|
|
|
|
|
from: 0
|
|
|
|
|
value: model.position
|
|
|
|
|
to: model.length
|
|
|
|
|
|
|
|
|
|
onMoved: model.position = value
|
|
|
|
|
|
|
|
|
|
Timer {
|
|
|
|
|
interval: 1000; running: true; repeat: true
|
|
|
|
|
onTriggered: {
|
|
|
|
|
mpris2Source.setIndex(model.index);
|
|
|
|
|
mpris2Source.updatePosition()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Text {
|
|
|
|
|
text: msecToString(model.length)
|
|
|
|
|
|
|
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.9
|
2024-08-01 01:18:33 +00:00
|
|
|
color: Kirigami.Theme.textColor
|
2024-07-26 01:22:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-04-09 01:48:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-22 23:29:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|