fedora
This commit is contained in:
+311
@@ -0,0 +1,311 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Modules.DesktopWidgets
|
||||
import qs.Services.Media
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
import qs.Widgets.AudioSpectrum
|
||||
|
||||
DraggableDesktopWidget {
|
||||
id: root
|
||||
|
||||
defaultY: 200
|
||||
|
||||
// Widget settings - check widgetData exists before accessing properties
|
||||
readonly property string hideMode: (widgetData && widgetData.hideMode !== undefined) ? widgetData.hideMode : "visible"
|
||||
readonly property bool showButtons: (widgetData && widgetData.showButtons !== undefined) ? widgetData.showButtons : true
|
||||
readonly property bool showAlbumArt: (widgetData && widgetData.showAlbumArt !== undefined) ? widgetData.showAlbumArt : true
|
||||
readonly property bool showVisualizer: (widgetData && widgetData.showVisualizer !== undefined) ? widgetData.showVisualizer : true
|
||||
readonly property string visualizerType: (widgetData && widgetData.visualizerType && widgetData.visualizerType !== "") ? widgetData.visualizerType : "linear"
|
||||
readonly property bool roundedCorners: (widgetData && widgetData.roundedCorners !== undefined) ? widgetData.roundedCorners : true
|
||||
readonly property bool hasPlayer: MediaService.currentPlayer !== null
|
||||
readonly property bool isPlaying: MediaService.isPlaying
|
||||
readonly property bool hasActiveTrack: hasPlayer && (MediaService.trackTitle || MediaService.trackArtist)
|
||||
|
||||
// State
|
||||
// Hide when idle when playback is not active
|
||||
readonly property bool shouldHideIdle: (hideMode === "idle") && !isPlaying
|
||||
readonly property bool shouldHideEmpty: !hasPlayer && hideMode === "hidden"
|
||||
readonly property bool isHidden: (shouldHideIdle || shouldHideEmpty) && !DesktopWidgetRegistry.editMode
|
||||
visible: !isHidden
|
||||
|
||||
// SpectrumService registration for visualizer
|
||||
readonly property string spectrumComponentId: "desktopmediaplayer:" + (root.screen ? root.screen.name : "unknown")
|
||||
readonly property bool needsSpectrum: root.shouldShowVisualizer && !root.isHidden
|
||||
|
||||
onNeedsSpectrumChanged: {
|
||||
if (root.needsSpectrum) {
|
||||
SpectrumService.registerComponent(root.spectrumComponentId);
|
||||
} else {
|
||||
SpectrumService.unregisterComponent(root.spectrumComponentId);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.needsSpectrum) {
|
||||
SpectrumService.registerComponent(root.spectrumComponentId);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
SpectrumService.unregisterComponent(root.spectrumComponentId);
|
||||
}
|
||||
|
||||
readonly property bool showPrev: hasPlayer && MediaService.canGoPrevious
|
||||
readonly property bool showNext: hasPlayer && MediaService.canGoNext
|
||||
readonly property int visibleButtonCount: root.showButtons ? (1 + (showPrev ? 1 : 0) + (showNext ? 1 : 0)) : 0
|
||||
|
||||
implicitWidth: Math.round(400 * widgetScale)
|
||||
implicitHeight: Math.round(64 * widgetScale + Style.margin2M * widgetScale)
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
// Visualizer visibility mode
|
||||
readonly property bool shouldShowVisualizer: {
|
||||
if (!root.showVisualizer)
|
||||
return false;
|
||||
if (root.visualizerType === "" || root.visualizerType === "none")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Visualizer overlay (visibility controlled by visualizerVisibility setting)
|
||||
// Completely disabled during scaling to avoid expensive canvas redraws
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Math.round(Style.marginXS * widgetScale)
|
||||
anchors.rightMargin: Math.round(Style.marginXS * widgetScale)
|
||||
anchors.topMargin: Math.round(Style.marginXS * widgetScale)
|
||||
anchors.bottomMargin: 0
|
||||
z: 0
|
||||
clip: true
|
||||
active: needsSpectrum
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
layer.effect: MultiEffect {
|
||||
maskEnabled: root.roundedCorners
|
||||
maskSource: ShaderEffectSource {
|
||||
sourceItem: Rectangle {
|
||||
width: root.width - Math.round(Style.marginXS * widgetScale) * 2
|
||||
height: root.height - Math.round(Style.marginXS * widgetScale)
|
||||
radius: root.roundedCorners ? Math.round(Math.max(0, (Style.radiusL - Style.marginXS) * widgetScale)) : 0
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: {
|
||||
switch (root.visualizerType) {
|
||||
case "linear":
|
||||
return linearComponent;
|
||||
case "mirrored":
|
||||
return mirroredComponent;
|
||||
case "wave":
|
||||
return waveComponent;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: linearComponent
|
||||
NLinearSpectrum {
|
||||
anchors.fill: parent
|
||||
values: SpectrumService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: 0.5
|
||||
mirrored: Settings.data.audio.spectrumMirrored
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: mirroredComponent
|
||||
NMirroredSpectrum {
|
||||
anchors.fill: parent
|
||||
values: SpectrumService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: 0.5
|
||||
mirrored: Settings.data.audio.spectrumMirrored
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: waveComponent
|
||||
NWaveSpectrum {
|
||||
anchors.fill: parent
|
||||
values: SpectrumService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: 0.5
|
||||
mirrored: Settings.data.audio.spectrumMirrored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drop shadow for text and controls readability over visualizer
|
||||
// Disabled during scaling to avoid expensive recomputations
|
||||
NDropShadow {
|
||||
visible: !root.isScaling
|
||||
anchors.fill: contentLayout
|
||||
source: contentLayout
|
||||
z: 1
|
||||
autoPaddingEnabled: true
|
||||
shadowBlur: 1.0
|
||||
shadowOpacity: 0.9
|
||||
shadowHorizontalOffset: 0
|
||||
shadowVerticalOffset: 0
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: contentLayout
|
||||
states: [
|
||||
State {
|
||||
when: root.showButtons
|
||||
AnchorChanges {
|
||||
target: contentLayout
|
||||
anchors.horizontalCenter: undefined
|
||||
anchors.verticalCenter: undefined
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
},
|
||||
State {
|
||||
when: !root.showButtons
|
||||
AnchorChanges {
|
||||
target: contentLayout
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.top: undefined
|
||||
anchors.bottom: undefined
|
||||
anchors.left: undefined
|
||||
anchors.right: undefined
|
||||
}
|
||||
}
|
||||
]
|
||||
anchors.margins: Math.round(Style.marginM * widgetScale)
|
||||
spacing: Math.round(Style.marginS * widgetScale)
|
||||
z: 2
|
||||
|
||||
Item {
|
||||
visible: root.showAlbumArt
|
||||
Layout.preferredWidth: Math.round(48 * widgetScale)
|
||||
Layout.preferredHeight: Math.round(48 * widgetScale)
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
NImageRounded {
|
||||
visible: hasPlayer
|
||||
anchors.fill: parent
|
||||
radius: Math.round(Style.radiusM * widgetScale)
|
||||
imagePath: MediaService.trackArtUrl
|
||||
imageFillMode: Image.PreserveAspectCrop
|
||||
fallbackIcon: isPlaying ? "media-pause" : "media-play"
|
||||
fallbackIconSize: Math.round(20 * widgetScale)
|
||||
borderWidth: 0
|
||||
}
|
||||
|
||||
NIcon {
|
||||
visible: !hasPlayer
|
||||
anchors.centerIn: parent
|
||||
icon: "disc"
|
||||
pointSize: Math.round(24 * widgetScale)
|
||||
color: Color.mOnSurfaceVariant
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: root.showAlbumArt
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: root.showButtons ? Qt.AlignVCenter : Qt.AlignCenter
|
||||
spacing: 0
|
||||
|
||||
NText {
|
||||
Layout.fillWidth: true
|
||||
text: hasPlayer ? (MediaService.trackTitle || "Unknown Track") : "No media playing"
|
||||
pointSize: Math.round(Style.fontSizeS * widgetScale)
|
||||
font.weight: Style.fontWeightSemiBold
|
||||
color: Color.mOnSurface
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
}
|
||||
|
||||
NText {
|
||||
visible: hasPlayer && MediaService.trackArtist
|
||||
Layout.fillWidth: true
|
||||
text: MediaService.trackArtist || ""
|
||||
pointSize: Math.round(Style.fontSizeXS * widgetScale)
|
||||
font.weight: Style.fontWeightRegular
|
||||
color: Color.mSecondary
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: controlsRow
|
||||
spacing: Math.round(Style.marginXS * widgetScale)
|
||||
z: 10
|
||||
visible: root.showButtons
|
||||
Layout.alignment: root.showAlbumArt ? Qt.AlignVCenter : Qt.AlignCenter
|
||||
|
||||
NIconButton {
|
||||
opacity: showPrev ? 1 : 0
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationSlow
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
baseSize: Math.round(32 * widgetScale)
|
||||
icon: "media-prev"
|
||||
enabled: hasPlayer && MediaService.canGoPrevious
|
||||
colorBg: Color.mSurfaceVariant
|
||||
colorFg: enabled ? Color.mPrimary : Color.mOnSurfaceVariant
|
||||
customRadius: Math.round(Style.radiusS * widgetScale)
|
||||
onClicked: {
|
||||
if (enabled)
|
||||
MediaService.previous();
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
baseSize: Math.round(36 * widgetScale)
|
||||
icon: isPlaying ? "media-pause" : "media-play"
|
||||
enabled: hasPlayer && (MediaService.canPlay || MediaService.canPause)
|
||||
colorBg: Color.mPrimary
|
||||
colorFg: Color.mOnPrimary
|
||||
colorBgHover: Qt.lighter(Color.mPrimary, 1.1)
|
||||
colorFgHover: Color.mOnPrimary
|
||||
customRadius: Math.round(Style.radiusS * widgetScale)
|
||||
onClicked: {
|
||||
if (enabled) {
|
||||
MediaService.playPause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
opacity: showNext ? 1 : 0
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationSlow
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
baseSize: Math.round(32 * widgetScale)
|
||||
icon: "media-next"
|
||||
enabled: hasPlayer && MediaService.canGoNext
|
||||
colorBg: Color.mSurfaceVariant
|
||||
colorFg: enabled ? Color.mPrimary : Color.mOnSurfaceVariant
|
||||
customRadius: Math.round(Style.radiusS * widgetScale)
|
||||
onClicked: {
|
||||
if (enabled)
|
||||
MediaService.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user