mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-02 11:38:30 -04:00
59d367f4a4
* fix(media): use system colours in player instead of album cover accent Closes #2831 Removes ColorQuantizer-based album art accent extraction from MediaAccentService. All accent properties now return Theme.primary and Theme.onPrimary directly, so the Dank Dash player always matches the system colour scheme. Blame:ee6f7b47(introduced MediaAccentService & ColorQuantizer)d799175c(tweaked seekbar accent colours)a62ae336(further integrated accent into player/album art)c44ffae7(monochrome art edge case fixes) * feat(media): add toggle for album art accent colours (#2831) Adds mediaUseAlbumArtAccent setting (default: off) to Settings. When enabled, MediaAccentService extracts accent from album art via ColorQuantizer. When disabled, uses Theme.primary. Toggle is in Settings > Media Player. * fix: use american english spelling (colour -> color) Port 1.5 (cherry picked from commite2b3a2e3ca)
111 lines
3.7 KiB
QML
111 lines
3.7 KiB
QML
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
import Quickshell
|
|
import QtQuick
|
|
import qs.Common
|
|
import qs.Services
|
|
|
|
// Accent color extracted from the current track's album art via ColorQuantizer,
|
|
// falling back to Theme.primary when no usable accent is available.
|
|
Singleton {
|
|
id: root
|
|
|
|
readonly property bool hasAccent: SettingsData.mediaUseAlbumArtAccent ? _accent !== null : true
|
|
readonly property color accent: SettingsData.mediaUseAlbumArtAccent && _accent !== null ? _accent : Theme.primary
|
|
|
|
readonly property color onAccent: SettingsData.mediaUseAlbumArtAccent && _accent !== null ? (() => {
|
|
const lum = 0.2126 * _accent.r + 0.7152 * _accent.g + 0.0722 * _accent.b;
|
|
return lum > 0.6 ? Qt.rgba(0, 0, 0, 1) : Qt.rgba(1, 1, 1, 1);
|
|
})() : Theme.onPrimary
|
|
|
|
readonly property color accentHover: Theme.withAlpha(accent, 0.12)
|
|
readonly property color accentPressed: Theme.withAlpha(accent, Theme.transparentBlurLayers ? 0.24 : 0.16)
|
|
|
|
readonly property color accentTrack: Theme.withAlpha(accent, 0.28)
|
|
readonly property color accentSubtle: Theme.withAlpha(accent, 0.55)
|
|
|
|
// Prefer the validated url, but fall back to the live mpris art so quantization
|
|
// starts as soon as the cover exists instead of waiting on the commit pipeline.
|
|
readonly property string artUrl: {
|
|
const resolved = TrackArtService.resolvedArtUrl;
|
|
if (resolved !== "")
|
|
return resolved;
|
|
const p = MprisController.activePlayer;
|
|
if (!p)
|
|
return "";
|
|
if (p.trackArtUrl)
|
|
return p.trackArtUrl;
|
|
const m = p.metadata;
|
|
return m && m["mpris:artUrl"] ? m["mpris:artUrl"].toString() : "";
|
|
}
|
|
|
|
// Hold the last accent across the brief artUrl blank between tracks; never reset to primary.
|
|
property var _accent: null
|
|
|
|
ColorQuantizer {
|
|
id: quantizer
|
|
source: root.artUrl
|
|
depth: 4
|
|
rescaleSize: 64
|
|
onColorsChanged: {
|
|
// Hold last accent only across the blank-art gap; else always recompute.
|
|
if (!colors || colors.length === 0)
|
|
return;
|
|
root._accent = root._pickAccent(colors);
|
|
}
|
|
}
|
|
|
|
function _pickAccent(colors) {
|
|
if (!colors || colors.length === 0)
|
|
return null;
|
|
|
|
let best = null;
|
|
let bestScore = -1;
|
|
for (let i = 0; i < colors.length; i++) {
|
|
const c = colors[i];
|
|
const s = c.hsvSaturation;
|
|
const v = c.hsvValue;
|
|
if (v < 0.22 || v > 0.96 || s < 0.22)
|
|
continue;
|
|
const score = s * (1 - Math.abs(v - 0.68));
|
|
if (score > bestScore) {
|
|
bestScore = score;
|
|
best = c;
|
|
}
|
|
}
|
|
|
|
if (best)
|
|
return _normalize(best);
|
|
|
|
// Monochrome art: pick a neutral tone instead of keeping the last accent.
|
|
return _pickNeutral(colors);
|
|
}
|
|
|
|
function _pickNeutral(colors) {
|
|
let best = null;
|
|
let bestScore = -1;
|
|
for (let i = 0; i < colors.length; i++) {
|
|
const c = colors[i];
|
|
const v = c.hsvValue;
|
|
const score = (1 - Math.abs(v - 0.6)) + c.hsvSaturation * 0.5;
|
|
if (score > bestScore) {
|
|
bestScore = score;
|
|
best = c;
|
|
}
|
|
}
|
|
|
|
const hue = best.hsvHue < 0 ? 0 : best.hsvHue;
|
|
const s = Math.min(best.hsvSaturation, 0.18);
|
|
const v = Math.min(Math.max(best.hsvValue, 0.6), 0.82);
|
|
return Qt.hsva(hue, s, v, 1);
|
|
}
|
|
|
|
function _normalize(c) {
|
|
const hue = c.hsvHue < 0 ? 0 : c.hsvHue;
|
|
const s = Math.min(1, c.hsvSaturation * 1.05);
|
|
const v = Math.max(c.hsvValue, 0.62);
|
|
return Qt.hsva(hue, s, v, 1);
|
|
}
|
|
}
|