mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-21 18:54:01 -04:00
166 lines
4.5 KiB
QML
166 lines
4.5 KiB
QML
import QtQuick
|
|
import QtQuick.Effects
|
|
import Quickshell.Services.Mpris
|
|
import Quickshell.Widgets
|
|
import qs.Common
|
|
import qs.Services
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property MprisPlayer activePlayer
|
|
property real radius: Theme.cornerRadius
|
|
property real artOpacity: 0.7
|
|
property real surfaceTint: 0.3
|
|
property real stableHeight: 0
|
|
property string artUrl: TrackArtService.resolvedArtUrl
|
|
|
|
readonly property bool pinned: root.stableHeight > 0
|
|
readonly property real anchorHeight: root.pinned ? root.stableHeight : root.height
|
|
readonly property real blurExtent: Math.max(root.width, root.anchorHeight) * 1.1
|
|
readonly property int blurDecodeSize: Math.min(384, Math.max(128, Math.ceil(root.blurExtent / 128) * 128))
|
|
|
|
signal artReady
|
|
|
|
readonly property string curArt: artUrl
|
|
property bool _showA: true
|
|
readonly property bool transitioning: layerA.revealing || layerB.revealing
|
|
readonly property bool onScreen: visible && (Window.window?.visible ?? false)
|
|
|
|
visible: layerA.ready || layerB.ready
|
|
|
|
onCurArtChanged: syncArt()
|
|
onOnScreenChanged: {
|
|
if (onScreen)
|
|
return;
|
|
layerA.finishReveal();
|
|
layerB.finishReveal();
|
|
}
|
|
Component.onCompleted: syncArt()
|
|
|
|
function syncArt() {
|
|
if (curArt === "") {
|
|
layerA.art = "";
|
|
layerB.art = "";
|
|
return;
|
|
}
|
|
const front = _showA ? layerA : layerB;
|
|
const back = _showA ? layerB : layerA;
|
|
if (front.art == curArt)
|
|
return;
|
|
front.finishReveal();
|
|
if (back.art == curArt) {
|
|
if (back.ready)
|
|
promote(back);
|
|
return;
|
|
}
|
|
back.art = curArt;
|
|
}
|
|
|
|
function promote(layer) {
|
|
const front = _showA ? layerA : layerB;
|
|
const back = _showA ? layerB : layerA;
|
|
if (layer !== back || layer.art != curArt)
|
|
return;
|
|
const animate = onScreen && !SettingsData.reduceMotion && Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None;
|
|
_showA = (layer === layerA);
|
|
if (animate)
|
|
layer.reveal();
|
|
else
|
|
layer.finishReveal();
|
|
root.artReady();
|
|
}
|
|
|
|
Item {
|
|
anchors.fill: parent
|
|
opacity: root.artOpacity
|
|
layer.enabled: root.onScreen
|
|
|
|
BgBlurLayer {
|
|
id: layerA
|
|
front: root._showA
|
|
}
|
|
|
|
BgBlurLayer {
|
|
id: layerB
|
|
front: !root._showA
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
radius: root.radius
|
|
color: Theme.cardSurface
|
|
opacity: root.surfaceTint
|
|
}
|
|
|
|
component BgBlurLayer: ClippingRectangle {
|
|
id: layer
|
|
property alias art: layerImg.source
|
|
readonly property bool ready: layerImg.status === Image.Ready && layerImg.source != ""
|
|
readonly property bool revealing: fadeIn.running
|
|
property bool front: false
|
|
|
|
anchors.fill: parent
|
|
radius: root.radius
|
|
color: "transparent"
|
|
antialiasing: true
|
|
z: front ? 1 : 0
|
|
visible: front || root.transitioning
|
|
|
|
function reveal() {
|
|
fadeIn.restart();
|
|
}
|
|
|
|
function finishReveal() {
|
|
fadeIn.stop();
|
|
opacity = 1;
|
|
}
|
|
|
|
Timer {
|
|
id: promoteDeferred
|
|
interval: 0
|
|
onTriggered: root.promote(layer)
|
|
}
|
|
|
|
NumberAnimation {
|
|
id: fadeIn
|
|
target: layer
|
|
property: "opacity"
|
|
from: 0
|
|
to: 1
|
|
duration: Theme.expressiveDurations.expressiveEffects
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: Theme.expressiveCurves.expressiveEffects
|
|
}
|
|
|
|
Image {
|
|
id: layerImg
|
|
width: root.blurExtent
|
|
height: width
|
|
fillMode: Image.PreserveAspectCrop
|
|
sourceSize: Qt.size(root.blurDecodeSize, root.blurDecodeSize)
|
|
asynchronous: true
|
|
cache: true
|
|
visible: false
|
|
onStatusChanged: {
|
|
if (status === Image.Ready && source != "")
|
|
promoteDeferred.restart();
|
|
}
|
|
}
|
|
|
|
MultiEffect {
|
|
x: (parent.width - width) / 2
|
|
y: root.pinned ? 0 : (parent.height - height) / 2
|
|
width: layerImg.width
|
|
height: layerImg.height
|
|
source: layerImg
|
|
blurEnabled: root.onScreen
|
|
blurMax: 64
|
|
blur: 0.8
|
|
saturation: -0.2
|
|
brightness: -0.25
|
|
}
|
|
}
|
|
}
|