refactor: move media cover art to separate component
This commit is contained in:
parent
61738554e5
commit
a54fe6f487
2 changed files with 163 additions and 148 deletions
161
components/widgets/CoverArt.qml
Normal file
161
components/widgets/CoverArt.qml
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import M3Shapes
|
||||
import Caelestia.Config
|
||||
import qs.components
|
||||
import qs.components.controls
|
||||
import qs.components.effects
|
||||
import qs.services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property alias shape: shape
|
||||
|
||||
property bool hadPrevious
|
||||
property color fallbackColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 2)
|
||||
|
||||
// Slight glow to separate from bg
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
shadowEnabled: true
|
||||
blurMax: 1
|
||||
shadowColor: Colours.palette.m3outline
|
||||
shadowOpacity: 0.3
|
||||
}
|
||||
|
||||
Behavior on fallbackColour {
|
||||
CAnim {}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: shapeWrapper
|
||||
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
opacity: root.fallbackColour.a
|
||||
|
||||
MaterialShape {
|
||||
id: shape
|
||||
|
||||
implicitSize: root.width
|
||||
shape: MaterialShape.Cookie12Sided
|
||||
color: Qt.alpha(root.fallbackColour, 1)
|
||||
|
||||
Anim on rotation {
|
||||
running: true
|
||||
paused: !Players.active?.isPlaying
|
||||
from: 360
|
||||
to: 0
|
||||
duration: 23500
|
||||
easing.type: Easing.Linear
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
anchors.centerIn: parent
|
||||
|
||||
grade: 200
|
||||
text: image.status === Image.Error ? "broken_image" : "art_track"
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
fontStyle: Tokens.font.icon.size((parent.width * 0.35) || 1).build()
|
||||
opacity: image.status === Image.Null || image.status === Image.Error ? 1 : 0
|
||||
animate: true
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
asynchronous: true
|
||||
active: opacity > 0
|
||||
opacity: image.status === Image.Loading ? 1 : 0
|
||||
|
||||
sourceComponent: LoadingIndicator {
|
||||
implicitSize: root.width * 0.3
|
||||
color: Colours.palette.m3primaryContainer
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
source: Players.getArtUrl(Players.active)
|
||||
asynchronous: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
sourceSize: {
|
||||
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||
return Qt.size(width * dpr, height * dpr);
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: Mask {
|
||||
maskSource: shapeWrapper
|
||||
}
|
||||
|
||||
retainWhileLoading: true
|
||||
opacity: 0
|
||||
|
||||
onStatusChanged: {
|
||||
if (!opacityInAnim.running && image.status === Image.Ready) {
|
||||
opacityInAnim.type = root.hadPrevious ? Anim.DefaultEffects : Anim.StandardLarge;
|
||||
opacityInAnim.start();
|
||||
}
|
||||
}
|
||||
|
||||
Anim on opacity {
|
||||
id: opacityInAnim
|
||||
|
||||
running: false
|
||||
to: 1
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
|
||||
Behavior on source {
|
||||
SequentialAnimation {
|
||||
Anim {
|
||||
target: image
|
||||
property: "opacity"
|
||||
to: 0
|
||||
type: Anim.FastEffects
|
||||
}
|
||||
PropertyAction {
|
||||
target: root
|
||||
property: "hadPrevious"
|
||||
value: image.source
|
||||
}
|
||||
PropertyAction {}
|
||||
ScriptAction {
|
||||
script: {
|
||||
if (!opacityInAnim.running && image.status === Image.Ready) {
|
||||
opacityInAnim.type = root.hadPrevious ? Anim.DefaultEffects : Anim.StandardLarge;
|
||||
opacityInAnim.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import M3Shapes
|
||||
import Caelestia.Config
|
||||
import Caelestia.Services
|
||||
import qs.components
|
||||
import qs.components.controls
|
||||
import qs.components.effects
|
||||
import qs.components.widgets
|
||||
import qs.services
|
||||
import qs.utils
|
||||
|
||||
|
|
@ -21,8 +18,6 @@ Item {
|
|||
}
|
||||
|
||||
readonly property real arcCoverGap: Tokens.spacing.extraSmall
|
||||
property bool coverHadPrevious
|
||||
property color coverFallbackColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 2)
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
|
@ -34,10 +29,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Behavior on coverFallbackColour {
|
||||
CAnim {}
|
||||
}
|
||||
|
||||
Timer {
|
||||
running: Players.active?.isPlaying ?? false
|
||||
interval: GlobalConfig.dashboard.mediaUpdateInterval
|
||||
|
|
@ -68,7 +59,7 @@ Item {
|
|||
wavePaused: !Players.active?.isPlaying
|
||||
}
|
||||
|
||||
Item {
|
||||
CoverArt {
|
||||
id: cover
|
||||
|
||||
anchors.top: parent.top
|
||||
|
|
@ -76,143 +67,6 @@ Item {
|
|||
anchors.right: parent.right
|
||||
anchors.margins: Tokens.padding.medium + root.arcCoverGap + prog.thickness
|
||||
implicitHeight: width
|
||||
|
||||
// Slight glow to separate from bg
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
shadowEnabled: true
|
||||
blurMax: 1
|
||||
shadowColor: Colours.palette.m3outline
|
||||
shadowOpacity: 0.3
|
||||
}
|
||||
|
||||
Item {
|
||||
id: coverShapeWrapper
|
||||
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
opacity: root.coverFallbackColour.a
|
||||
|
||||
MaterialShape {
|
||||
id: coverShape
|
||||
|
||||
implicitSize: cover.width
|
||||
shape: MaterialShape.Cookie12Sided
|
||||
color: Qt.alpha(root.coverFallbackColour, 1)
|
||||
|
||||
Anim on rotation {
|
||||
running: true
|
||||
paused: !Players.active?.isPlaying
|
||||
from: 360
|
||||
to: 0
|
||||
duration: 23500
|
||||
easing.type: Easing.Linear
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
anchors.centerIn: parent
|
||||
|
||||
grade: 200
|
||||
text: image.status === Image.Error ? "broken_image" : "art_track"
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
fontStyle: Tokens.font.icon.size((parent.width * 0.35) || 1).build()
|
||||
opacity: image.status === Image.Null || image.status === Image.Error ? 1 : 0
|
||||
animate: true
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
asynchronous: true
|
||||
active: opacity > 0
|
||||
opacity: image.status === Image.Loading ? 1 : 0
|
||||
|
||||
sourceComponent: LoadingIndicator {
|
||||
implicitSize: cover.width * 0.3
|
||||
color: Colours.palette.m3primaryContainer
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
source: Players.getArtUrl(Players.active)
|
||||
asynchronous: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
sourceSize: {
|
||||
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||
return Qt.size(width * dpr, height * dpr);
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: Mask {
|
||||
maskSource: coverShapeWrapper
|
||||
}
|
||||
|
||||
retainWhileLoading: true
|
||||
opacity: 0
|
||||
|
||||
onStatusChanged: {
|
||||
if (!opacityInAnim.running && image.status === Image.Ready) {
|
||||
opacityInAnim.type = root.coverHadPrevious ? Anim.DefaultEffects : Anim.StandardLarge;
|
||||
opacityInAnim.start();
|
||||
}
|
||||
}
|
||||
|
||||
Anim on opacity {
|
||||
id: opacityInAnim
|
||||
|
||||
running: false
|
||||
to: 1
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
|
||||
Behavior on source {
|
||||
SequentialAnimation {
|
||||
Anim {
|
||||
target: image
|
||||
property: "opacity"
|
||||
to: 0
|
||||
type: Anim.FastEffects
|
||||
}
|
||||
PropertyAction {
|
||||
target: root
|
||||
property: "coverHadPrevious"
|
||||
value: image.source
|
||||
}
|
||||
PropertyAction {}
|
||||
ScriptAction {
|
||||
script: {
|
||||
if (!opacityInAnim.running && image.status === Image.Ready) {
|
||||
opacityInAnim.type = root.coverHadPrevious ? Anim.DefaultEffects : Anim.StandardLarge;
|
||||
opacityInAnim.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue