// Icon-only quality badge with a hover tooltip. // // The square badge is intentionally compact (it buys layout space); the // exact quality — "Hi-Res: 24-bit / 96 kHz" — is revealed on hover, the // same string the Tauri QualityBadge surfaces. import { Theme } from "../foundation/semantic-colors.slint"; import { Typography } from "../foundation/typography.slint"; import { Radius } from "../foundation/radius.slint"; import { QbzIcon } from "QbzIcon.slint"; export component QualityBadge inherits Rectangle { // "hires" | "cd" | "mp3" | "lossless" | "" — empty hides the badge entirely. in property tier; // Exact quality string for the hover tooltip. in property label; // For the "lossless" tier (un-hydrated filetype, e.g. an un-hydrated Plex // FLAC): the bare filetype to print, e.g. "FLAC". in property detail; visible: root.tier != ""; width: root.tier == "hires" ? 42px : (root.tier == "lossless" ? 36px : 30px); height: 30px; if root.tier == "hires": Image { source: @image-url("../assets/hi-res.svg"); width: 42px; height: 28px; x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: Math.round((parent.height - self.height) / 2 / 1px) * 1px; image-fit: contain; } if root.tier == "cd": Rectangle { width: 30px; height: 30px; border-radius: 3px; background: Theme.surface-elevated; border-width: 1px; border-color: Theme.border-subtle; QbzIcon { x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: Math.round((parent.height - self.height) / 2 / 1px) * 1px; width: 16px; height: 16px; source: @image-url("../assets/cd.svg"); image-fit: contain; // Tinted light, matching the Tauri CD badge. tint: #b0b0b0; } } if root.tier == "mp3": Rectangle { width: 30px; height: 30px; border-radius: 3px; background: Theme.surface-elevated; border-width: 1px; border-color: Theme.border-subtle; QbzIcon { x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: Math.round((parent.height - self.height) / 2 / 1px) * 1px; width: 16px; height: 16px; source: @image-url("../assets/mp3.svg"); image-fit: contain; tint: #b0b0b0; } } // Un-hydrated lossless: the bit-depth/rate isn't known yet, but the // filetype is — show it as a neutral text chip (e.g. "FLAC") rather than // disappearing. Upgrades to the cd/hires badge once hydrated. if root.tier == "lossless": Rectangle { width: 36px; height: 30px; border-radius: 3px; background: Theme.surface-elevated; border-width: 1px; border-color: Theme.border-subtle; Text { x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: Math.round((parent.height - self.height) / 2 / 1px) * 1px; text: root.detail; color: #b0b0b0; font-size: 9px; font-weight: Typography.medium; } } // Hover tooltip — floats just above the badge, right-anchored so it // extends leftward into the card and is never clipped by the next card. tip := Rectangle { x: root.width - self.width; y: -self.height - 6px; width: tip-row.preferred-width; height: 24px; background: Theme.surface-elevated; border-radius: Radius.sm; border-width: 1px; border-color: Theme.border-subtle; drop-shadow-blur: 14px; drop-shadow-color: Theme.card-shadow; drop-shadow-offset-y: 3px; opacity: ta.has-hover && root.label != "" ? 1.0 : 0.0; animate opacity { duration: 120ms; } tip-row := HorizontalLayout { padding-left: 9px; padding-right: 9px; Text { text: root.label; color: Theme.text-secondary; font-size: 11px; font-weight: Typography.medium; vertical-alignment: center; } } } ta := TouchArea { mouse-cursor: default; } }