@@ -6,106 +6,17 @@ import QtQuick
66import qs.Common
77import qs.Services
88
9- // Accent color extracted from the current track's album art via ColorQuantizer,
10- // falling back to Theme.primary when no usable accent is available.
119Singleton {
1210 id: root
1311
14- readonly property bool hasAccent: _accent !== null
15- readonly property color accent: _accent !== null ? _accent : Theme .primary
12+ readonly property bool hasAccent: true
13+ readonly property color accent: Theme .primary
1614
17- readonly property color onAccent: {
18- const c = accent;
19- const lum = 0.2126 * c .r + 0.7152 * c .g + 0.0722 * c .b ;
20- return lum > 0.6 ? Qt .rgba (0 , 0 , 0 , 1 ) : Qt .rgba (1 , 1 , 1 , 1 );
21- }
15+ readonly property color onAccent: Theme .onPrimary
2216
2317 readonly property color accentHover: Theme .withAlpha (accent, 0.12 )
2418 readonly property color accentPressed: Theme .withAlpha (accent, Theme .transparentBlurLayers ? 0.24 : 0.16 )
2519
2620 readonly property color accentTrack: Theme .withAlpha (accent, 0.28 )
2721 readonly property color accentSubtle: Theme .withAlpha (accent, 0.55 )
28-
29- // Prefer the validated url, but fall back to the live mpris art so quantization
30- // starts as soon as the cover exists instead of waiting on the commit pipeline.
31- readonly property string artUrl: {
32- const resolved = TrackArtService .resolvedArtUrl ;
33- if (resolved !== " " )
34- return resolved;
35- const p = MprisController .activePlayer ;
36- if (! p)
37- return " " ;
38- if (p .trackArtUrl )
39- return p .trackArtUrl ;
40- const m = p .metadata ;
41- return m && m[" mpris:artUrl" ] ? m[" mpris:artUrl" ].toString () : " " ;
42- }
43-
44- // Hold the last accent across the brief artUrl blank between tracks; never reset to primary.
45- property var _accent: null
46-
47- ColorQuantizer {
48- id: quantizer
49- source: root .artUrl
50- depth: 4
51- rescaleSize: 64
52- onColorsChanged: {
53- // Hold last accent only across the blank-art gap; else always recompute.
54- if (! colors || colors .length === 0 )
55- return ;
56- root ._accent = root ._pickAccent (colors);
57- }
58- }
59-
60- function _pickAccent (colors ) {
61- if (! colors || colors .length === 0 )
62- return null ;
63-
64- let best = null ;
65- let bestScore = - 1 ;
66- for (let i = 0 ; i < colors .length ; i++ ) {
67- const c = colors[i];
68- const s = c .hsvSaturation ;
69- const v = c .hsvValue ;
70- if (v < 0.22 || v > 0.96 || s < 0.22 )
71- continue ;
72- const score = s * (1 - Math .abs (v - 0.68 ));
73- if (score > bestScore) {
74- bestScore = score;
75- best = c;
76- }
77- }
78-
79- if (best)
80- return _normalize (best);
81-
82- // Monochrome art: pick a neutral tone instead of keeping the last accent.
83- return _pickNeutral (colors);
84- }
85-
86- function _pickNeutral (colors ) {
87- let best = null ;
88- let bestScore = - 1 ;
89- for (let i = 0 ; i < colors .length ; i++ ) {
90- const c = colors[i];
91- const v = c .hsvValue ;
92- const score = (1 - Math .abs (v - 0.6 )) + c .hsvSaturation * 0.5 ;
93- if (score > bestScore) {
94- bestScore = score;
95- best = c;
96- }
97- }
98-
99- const hue = best .hsvHue < 0 ? 0 : best .hsvHue ;
100- const s = Math .min (best .hsvSaturation , 0.18 );
101- const v = Math .min (Math .max (best .hsvValue , 0.6 ), 0.82 );
102- return Qt .hsva (hue, s, v, 1 );
103- }
104-
105- function _normalize (c ) {
106- const hue = c .hsvHue < 0 ? 0 : c .hsvHue ;
107- const s = Math .min (1 , c .hsvSaturation * 1.05 );
108- const v = Math .max (c .hsvValue , 0.62 );
109- return Qt .hsva (hue, s, v, 1 );
110- }
11122}
0 commit comments