initial commit for media widget update + anim tokens restructure
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 20s
JS/TS / lint (pull_request) Successful in 22s
Python / static (pull_request) Successful in 57s
Rust / fmt (pull_request) Successful in 1m2s
C++ / build (pull_request) Successful in 2m10s
Rust / build (pull_request) Successful in 1m50s
Rust / clippy (pull_request) Successful in 1m25s
Python / verify (pull_request) Successful in 2m58s
C++ / clang-tidy (pull_request) Successful in 7m8s

This commit is contained in:
2026-08-18 16:14:41 +02:00
parent 8ec454306f
commit 7d6f3cc275
162 changed files with 1385 additions and 1080 deletions
+2 -2
View File
@@ -32,11 +32,11 @@ Item {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: Tokens.padding.smaller
anchors.margins: Tokens.padding.small
anchors.right: parent.right
anchors.top: parent.top
color: "transparent"
radius: Tokens.rounding.normal - anchors.margins
radius: Tokens.rounding.extraLarge - anchors.margins
Item {
id: view
+5 -4
View File
@@ -13,11 +13,11 @@ GridLayout {
required property PersistentProperties dashState
readonly property bool dashboardVisible: visibilities.dashboard
property int radius: Tokens.rounding.smallest
property int radius: Tokens.rounding.medium
required property PersistentProperties visibilities
columnSpacing: Tokens.spacing.smaller
rowSpacing: Tokens.spacing.smaller
columnSpacing: Tokens.spacing.small
rowSpacing: Tokens.spacing.small
ParallelAnimation {
id: openAnim
@@ -104,12 +104,13 @@ GridLayout {
}
}
Rect {
CustomClippingRect {
Layout.column: 0
Layout.columnSpan: 5
Layout.fillWidth: true
Layout.preferredHeight: media.implicitHeight
Layout.row: 2
color: Colors.tPalette.m3surfaceContainer
radius: root.radius
Media {
+4 -4
View File
@@ -132,7 +132,7 @@ CustomMouseArea {
IconButton {
icon: "chevron_left"
padding: Tokens.padding.small
padding: Tokens.padding.extraSmall
type: IconButton.Text
onClicked: root.dashState.currentDate = new Date(root.realCurrYear, root.realCurrMonth - 1, 1)
@@ -150,7 +150,7 @@ CustomMouseArea {
const now = new Date();
return root.realCurrMonth !== now.getMonth() || root.realCurrYear !== now.getFullYear();
}
radius: pressed ? Tokens.rounding.small : Tokens.rounding.large
radius: pressed ? Tokens.rounding.small : Tokens.rounding.largeIncreased
Behavior on radius {
Anim {
@@ -203,7 +203,7 @@ CustomMouseArea {
IconButton {
icon: "chevron_right"
padding: Tokens.padding.small
padding: Tokens.padding.extraSmall
type: IconButton.Text
onClicked: root.dashState.currentDate = new Date(root.realCurrYear, root.realCurrMonth + 1, 1)
@@ -259,7 +259,7 @@ CustomMouseArea {
required property var model
implicitHeight: text.implicitHeight + Tokens.padding.normal * 2
implicitHeight: text.implicitHeight + Tokens.padding.small * 2
implicitWidth: implicitHeight
CustomText {
+25 -46
View File
@@ -9,6 +9,7 @@ import QtQuick.Effects
import ZShell.Components
import ZShell.Services
import ZShell.Config
import qs.Modules.Dashboard.Dash.Media
import qs.Daemons
import qs.Components
import qs.Helpers
@@ -25,7 +26,7 @@ Item {
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: layout.implicitHeight
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
function lengthStr(length: int): string {
if (length < 0)
return "-1:-1";
@@ -57,14 +58,18 @@ Item {
service: Audio.cava
}
BackgroundShapes {
anchors.fill: parent
}
Shape {
id: visualizer
readonly property int bars: Config.services.visualizerBars
property color color: Colors.palette.m3tertiary
property color fillColor: Qt.alpha(color, 0.25)
property color color: Qt.alpha(Colors.palette.m3primary, 0.5)
property color fillColor: Qt.alpha(color, 0.1)
anchors.fill: layout
anchors.fill: parent
anchors.leftMargin: -(shape.strokeWidth / 2)
layer.enabled: true
asynchronous: true
@@ -87,15 +92,15 @@ Item {
if (n < 2)
return "";
const h = layout.height + shape.strokeWidth / 2;
const w = layout.width + shape.strokeWidth;
const h = root.height + shape.strokeWidth / 2;
const w = root.width + shape.strokeWidth;
function x(i) {
return i * w / (n - 1);
}
function y(i) {
return h - values[i] * Config.dashboard.sizes.mediaVisualizerSize;
return h - (values[i] * Config.dashboard.sizes.mediaVisualizerSize) / 2;
}
let d = `M 0 ${h} `;
@@ -142,48 +147,21 @@ Item {
RowLayout {
id: layout
anchors.left: parent.left
anchors.right: parent.right
anchors.fill: parent
anchors.margins: Tokens.padding.large
anchors.leftMargin: Tokens.padding.extraLarge
CustomClippingRect {
id: cover
Layout.alignment: Qt.AlignLeft
Layout.bottomMargin: Tokens.padding.large + Config.dashboard.sizes.mediaProgressThickness + Tokens.spacing.small
Layout.leftMargin: Tokens.padding.large + Config.dashboard.sizes.mediaProgressThickness + Tokens.spacing.small
Layout.preferredHeight: Config.dashboard.sizes.mediaCoverArtSize
Layout.preferredWidth: Config.dashboard.sizes.mediaCoverArtSize
Layout.topMargin: Tokens.padding.large + Config.dashboard.sizes.mediaProgressThickness + Tokens.spacing.small
color: Colors.tPalette.m3surfaceContainerHigh
radius: Infinity
MaterialIcon {
anchors.centerIn: parent
color: Colors.palette.m3onSurfaceVariant
font.pointSize: (parent.width * 0.4) || 1
grade: 200
text: "art_track"
}
Image {
id: image
anchors.fill: parent
asynchronous: true
fillMode: Image.PreserveAspectCrop
source: Players.active?.trackArtUrl ?? ""
sourceSize.height: Math.floor(height)
sourceSize.width: Math.floor(width)
}
CoverVisualizer {
Layout.fillHeight: true
implicitWidth: Config.dashboard.sizes.mediaCoverArtSize
}
ColumnLayout {
Layout.fillWidth: true
Layout.leftMargin: Tokens.spacing.large
Layout.rightMargin: Tokens.spacing.large
Layout.preferredHeight: childrenRect.height
Layout.leftMargin: Tokens.spacing.largeIncreased
Layout.rightMargin: Tokens.spacing.largeIncreased
spacing: Tokens.spacing.normal
spacing: Tokens.spacing.small
MarqueeText {
id: title
@@ -222,7 +200,7 @@ Item {
RowLayout {
id: positionSliderLayout
Layout.topMargin: Tokens.spacing.extraLargeIncreased
Layout.topMargin: Tokens.spacing.large
Layout.fillWidth: true
spacing: Tokens.spacing.small
@@ -289,7 +267,6 @@ Item {
checked: Players.active?.shuffle ?? false
enabled: Players.active?.shuffleSupported
onClicked: Players.active.shuffle = !Players.active?.shuffle
implicitWidth: Math.round(implicitHeight * 0.9)
}
IconButton {
@@ -301,6 +278,7 @@ Item {
shapeMorph: true
enabled: Players.active?.canGoPrevious
onClicked: Players.active?.previous()
font.pointSize: Tokens.font.size.large
}
IconButton {
@@ -313,6 +291,7 @@ Item {
checked: Players.active?.isPlaying ?? false
enabled: Players.active?.canTogglePlaying
onClicked: Players.active?.togglePlaying()
font.pointSize: Tokens.font.size.large
}
IconButton {
@@ -324,6 +303,7 @@ Item {
shapeMorph: true
enabled: Players.active?.canGoNext
onClicked: Players.active?.next()
font.pointSize: Tokens.font.size.large
}
IconButton {
@@ -342,7 +322,6 @@ Item {
else
Players.active.loopState = MprisLoopState.None;
}
implicitWidth: Math.round(implicitHeight * 0.9)
}
}
}
@@ -0,0 +1,97 @@
pragma ComponentBehavior: Bound
import QtQuick
import M3Shapes
import qs.Components
import qs.Services
import qs.Helpers
Item {
id: root
property int count: 14
property list<real> darkOpacities: [0.10, 0.20, 0.10, 0.20]
property list<real> lightOpacities: [0.34, 0.34, 0.08, 0.2]
property real maxRotSpeed: 12
property real maxSize: 124
property real maxSpeed: 18
property real minRotSpeed: -12
property real minSize: 36
property real minSpeed: 4
readonly property list<int> shapePool: [MaterialShape.Circle, MaterialShape.Cookie4Sided, MaterialShape.Cookie6Sided, MaterialShape.Cookie7Sided, MaterialShape.Cookie9Sided, MaterialShape.Cookie12Sided, MaterialShape.Sunny, MaterialShape.VerySunny, MaterialShape.SoftBurst, MaterialShape.Pentagon, MaterialShape.Gem, MaterialShape.Arch, MaterialShape.Arrow, MaterialShape.Pill, MaterialShape.Triangle, MaterialShape.Fan, MaterialShape.Oval]
function rand(min: real, max: real): real {
return min + Math.random() * (max - min);
}
function signedRand(min: real, max: real): real {
return rand(min, max) * (Math.random() < 0.5 ? -1 : 1);
}
Component.onCompleted: shapes.model = count
Repeater {
id: shapes
DriftingShape {
}
}
FrameAnimation {
running: root.visible && root.width > 0 && root.height > 0 && (Players.active?.isPlaying ?? false)
onTriggered: {
const dt = frameTime;
for (let i = 0; i < shapes.count; i++) {
const s = shapes.itemAt(i) as DriftingShape;
if (!s)
continue;
s.x += s.vx * dt;
s.y += s.vy * dt;
s.rotation += s.vr * dt;
if (s.x + s.width < 0)
s.x = root.width;
else if (s.x > root.width)
s.x = -s.width;
if (s.y + s.height < 0)
s.y = root.height;
else if (s.y > root.height)
s.y = -s.height;
}
}
}
component DriftingShape: MaterialShape {
id: shapeItem
readonly property int colorIdx: Math.floor(Math.random() * 4)
required property int index
property real vr: root.rand(root.minRotSpeed, root.maxRotSpeed)
property real vx: root.signedRand(root.minSpeed, root.maxSpeed)
property real vy: root.signedRand(root.minSpeed, root.maxSpeed)
color: [Colors.palette.m3primaryContainer, Colors.palette.m3secondaryContainer, Colors.palette.m3tertiaryContainer, Colors.palette.m3outlineVariant][colorIdx]
implicitSize: root.minSize + (index / root.count) * (root.maxSize - root.minSize)
opacity: Colors.light ? root.lightOpacities[colorIdx] : root.darkOpacities[colorIdx]
rotation: root.rand(0, 360)
shape: root.shapePool[Math.floor(Math.random() * root.shapePool.length)]
Behavior on color {
CAnim {
}
}
Behavior on opacity {
Anim {
type: Anim.SlowEffects
}
}
Component.onCompleted: {
x = root.rand(0, root.width - implicitSize);
y = root.rand(0, root.height - implicitSize);
}
}
}
+100
View File
@@ -0,0 +1,100 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Effects
import M3Shapes
import qs.Helpers
import qs.Effects
import qs.Components
import qs.Services
Item {
id: root
property color fallbackColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 2)
property bool hadPrevious
readonly property alias shape: shape
layer.enabled: true
Behavior on fallbackColor {
CAnim {
}
}
layer.effect: MultiEffect {
blurMax: 1
shadowColor: Colors.palette.m3outline
shadowEnabled: true
shadowOpacity: 0.3
}
Item {
id: shapeWrapper
anchors.fill: parent
layer.enabled: true
opacity: root.fallbackColor.a
MaterialShape {
id: shape
color: Qt.alpha(root.fallbackColor, 1)
implicitSize: root.width
shape: MaterialShape.Cookie12Sided
Anim on rotation {
duration: 23500
easing.type: Easing.Linear
from: 360
loops: Animation.Infinite
paused: !Players.active?.isPlaying
running: true
to: 0
}
}
}
MaterialIcon {
anchors.centerIn: parent
animate: true
color: Colors.palette.m3onSurfaceVariant
grade: 200
opacity: image.status === Image.Null || image.status === Image.Error ? 1 : 0
text: image.status === Image.Error ? "broken_image" : "art_track"
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
}
Loader {
active: opacity > 0
anchors.centerIn: parent
asynchronous: true
opacity: image.status === Image.Loading ? 1 : 0
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
sourceComponent: LoadingIndicator {
color: Colors.palette.m3primaryContainer
implicitSize: root.width * 0.3
}
}
FadeImage {
id: image
anchors.fill: parent
layer.enabled: true
source: Players.getArtUrl(Players.active)
layer.effect: Mask {
maskSource: shapeWrapper
}
}
}
@@ -0,0 +1,18 @@
pragma ComponentBehavior: Bound
import QtQuick
import M3Shapes
import ZShell.Config
Item {
id: root
CoverArt {
id: cover
anchors.centerIn: parent
implicitHeight: Config.dashboard.sizes.mediaCoverArtSize
implicitWidth: Config.dashboard.sizes.mediaCoverArtSize
shape.shape: MaterialShape.Cookie9Sided
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
anchors.margins: Tokens.padding.large
anchors.top: parent.top
spacing: Tokens.spacing.normal
spacing: Tokens.spacing.medium
Resource {
fgColor: Colors.palette.m3primary
+1 -1
View File
@@ -18,7 +18,7 @@ Row {
color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
implicitHeight: info.implicitHeight
implicitWidth: info.implicitHeight
radius: Tokens.rounding.smallest
radius: Tokens.rounding.small
MaterialIcon {
anchors.centerIn: parent
+1 -1
View File
@@ -27,7 +27,7 @@ Item {
id: info
anchors.left: icon.right
anchors.leftMargin: Tokens.spacing.large
anchors.leftMargin: Tokens.spacing.largeIncreased
anchors.verticalCenter: parent.verticalCenter
spacing: 8
+1 -1
View File
@@ -181,7 +181,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
color: "transparent"
implicitHeight: parent.height + 8 * 2
radius: Tokens.rounding.smallest
radius: Tokens.rounding.small
CustomRect {
id: stateLayer