diff --git a/plugins/oled-theme-luna/src/Settings.tsx b/plugins/oled-theme-luna/src/Settings.tsx index 1163f70..845f999 100644 --- a/plugins/oled-theme-luna/src/Settings.tsx +++ b/plugins/oled-theme-luna/src/Settings.tsx @@ -17,7 +17,7 @@ export const Settings = () => { { console.log("Quality Color Matched Seek Bar:", checked ? "enabled" : "disabled"); diff --git a/plugins/oled-theme-luna/src/index.ts b/plugins/oled-theme-luna/src/index.ts index 0752d93..dd27ca2 100644 --- a/plugins/oled-theme-luna/src/index.ts +++ b/plugins/oled-theme-luna/src/index.ts @@ -1,5 +1,5 @@ import { LunaUnload, Tracer } from "@luna/core"; -import { StyleTag } from "@luna/lib"; +import { StyleTag, observePromise, PlayState, Quality, type MediaItem } from "@luna/lib"; import { settings, Settings } from "./Settings"; // Import CSS files directly using Luna's file:// syntax @@ -17,30 +17,112 @@ export const unloads = new Set(); // StyleTag instance for theme management const themeStyleTag = new StyleTag("OLED-Theme", unloads); +// Quality color mapping +const QUALITY_COLORS = { + MAX: "#FED330", // Max/HiFi + HIGH: "#31FFEE", // High + LOW: "#FFFFFE" // Low +}; + +// Function to get quality color based on audio quality +const getQualityColor = (audioQuality: string): string => { + const quality = audioQuality?.toUpperCase(); + if (quality?.includes("HI_RES_LOSSLESS")) { + return QUALITY_COLORS.MAX; + } else if (quality?.includes("LOSSLESS")) { + return QUALITY_COLORS.HIGH; + } else { + return QUALITY_COLORS.LOW; + } +}; + +// Function to Reset Seek Bar Color (if setting gets disabled while playing) +const resetSeekBarColor = async (): Promise => { + try { + const progressBarWrapper = await observePromise(unloads, `[class^="_progressBarWrapper"]`); + if (!progressBarWrapper) return; + progressBarWrapper.style.removeProperty('color'); + progressBarWrapper.querySelectorAll('[class*="progress"], [class*="bar"]').forEach(el => { + if (el instanceof HTMLElement) el.style.removeProperty('color'); + }); + } catch (error) { + trace.msg.err(`Failed to reset seek bar color: ${error}`); + } +}; + +// Function to apply quality-based seek bar coloring (if enabled) +const applyQualityColors = async (): Promise => { + if (!settings.qualityColorMatchedSeekBar) return; + try { + const progressBarWrapper = await observePromise(unloads, `[class^="_progressBarWrapper"]`); + if (!progressBarWrapper) return; + const audioQuality = PlayState.playbackContext?.actualAudioQuality; + if (!audioQuality) return; + const qualityColor = getQualityColor(audioQuality); + progressBarWrapper.style.setProperty('color', qualityColor, 'important'); + progressBarWrapper.querySelectorAll('[class*="progress"], [class*="bar"]').forEach(el => { + if (el instanceof HTMLElement) el.style.setProperty('color', qualityColor, 'important'); + }); + //trace.msg.log(`Applied quality color ${qualityColor}`); + } catch (error) { + trace.msg.err(`Failed to apply quality colors: ${error}`); + } +}; + +// Function to monitor track changes using track ID +const setupQualityMonitoring = (): void => { + let lastTrackId: string | null = null; + const interval = setInterval(() => { + if (!settings.qualityColorMatchedSeekBar) return; + const currentTrackId = PlayState.playbackContext?.actualProductId; + if (currentTrackId && currentTrackId !== lastTrackId) { + //trace.msg.log(`[OLED Theme] Track ID changed: ${lastTrackId} -> ${currentTrackId}`); + lastTrackId = currentTrackId; + applyQualityColors(); + } + }, 250); + unloads.add(() => clearInterval(interval)); + + // Initial color application (if a track is already loaded) + const currentTrackId = PlayState.playbackContext?.actualProductId; + if (settings.qualityColorMatchedSeekBar && currentTrackId) { + lastTrackId = currentTrackId; + applyQualityColors(); + } +}; + // Function to apply theme styles based on current settings const applyThemeStyles = function(): void { // Choose the appropriate CSS file based on settings let selectedStyle: string; if (settings.lightMode) { - // Light mode always uses the full light theme (OLED friendly doesn't apply to light theme) + // Light mode - (OLED friendly doesn't apply to light theme) selectedStyle = lightTheme; } else { - // Dark mode - choose between full dark theme or OLED friendly version + // Dark mode selectedStyle = settings.oledFriendlyButtons ? oledFriendlyTheme : darkTheme; } // Remove SeekBar coloring if Quality Color Matched Seek Bar is enabled + // This allows our manual coloring to take precedence if (settings.qualityColorMatchedSeekBar) { selectedStyle = selectedStyle.replace(/\[class\^="_progressBarWrapper"\]\s*\{[^}]*\}/g, ''); + setupQualityMonitoring(); + } else { + // If disabling, reset the seek bar color + resetSeekBarColor(); } // Apply the selected theme using StyleTag themeStyleTag.css = selectedStyle; + + }; // Make this function available globally so Settings can call it (window as any).updateOLEDThemeStyles = applyThemeStyles; // Apply the OLED theme initially -applyThemeStyles(); \ No newline at end of file +applyThemeStyles(); + diff --git a/plugins/oled-theme-luna/src/light-theme.css b/plugins/oled-theme-luna/src/light-theme.css index a49dbb8..2fec709 100644 --- a/plugins/oled-theme-luna/src/light-theme.css +++ b/plugins/oled-theme-luna/src/light-theme.css @@ -129,13 +129,7 @@ color: #333333; } -/* Override button span color specifically for play/shuffle buttons */ -button[data-test="play-all"] [class^="button"]>span, -button[data-test="shuffle-all"] [class^="button"]>span, -button[data-test="play-all"] span, -button[data-test="shuffle-all"] span { - color: white !important; -} + [class^="_explicitBadge"] { color: var(--wave-color-solid-accent-fill); @@ -292,42 +286,72 @@ button[data-test="close-now-playing"]:hover { margin-top: 7.5px; } -/* Play and Shuffle buttons - ultra aggressive targeting */ -button[data-test="play-all"], -button[data-test="shuffle-all"], -div[data-test="play-all"], -div[data-test="shuffle-all"] { - background-color: #666666 !important; - color: white !important; - border-radius: 12px !important; +/* Button styling using proper light theme approach */ +:root { + --button-light: #d9d9d9 !important; + --button-medium: #cbcbcb !important; } -/* Target all possible text and icon elements */ -button[data-test="play-all"] *, -button[data-test="shuffle-all"] *, -div[data-test="play-all"] *, -div[data-test="shuffle-all"] *, -[data-test="play-all"] span, -[data-test="shuffle-all"] span, -[data-test="play-all"] svg, -[data-test="shuffle-all"] svg, -[data-test="play-all"] path, -[data-test="shuffle-all"] path, -[data-test="play-all"] div, -[data-test="shuffle-all"] div, -[data-test="play-all"] button, -[data-test="shuffle-all"] button { - color: white !important; - fill: white !important; - background-color: transparent !important; +/*buttons*/ +._activeTab_f47dafa { + background: #0000001c; } -/* Override any CSS variable usage */ -[data-test="play-all"], -[data-test="shuffle-all"] { - --wave-color-solid-accent-fill: white !important; - --wave-color-solid-contrast-fill: white !important; - --wave-text-body-medium: white !important; +/*canvas nav buttons*/ +.viewAllButton--Nb87U, +.css-7l8ggf { + background: #e0e0e0; +} + +.viewAllButton--Nb87U:hover, +.css-7l8ggf:hover { + background: #cbcbcb; +} + +/*tracks page*/ +.variantPrimary--pjymy, +._button_3357ce6 { + background-color: var(--button-light); +} + +._button_f1c7fcb { + background: var(--wave-color-solid-base-brighter); +} + +._button_84b8ffe { + background-color: var(--wave-color-solid-base-brighter); +} + +._button_84b8ffe:hover { + background-color: var(--wave-color-solid-base-brightest); +} + +.button--_0I_t { + background-color: var(--button-light); +} + +.button--_0I_t:hover { + background-color: var(--wave-color-opacity-contrast-fill-regular); +} + +._button_94c5125 { + background: var(--wave-color-solid-base-brighter); +} + +.primary--NLSX4 { + background-color: #d5d5d5; +} + +.primary--NLSX4:hover { + background-color: var(--wave-color-opacity-contrast-fill-regular) !important; +} + +.primary--NLSX4:disabled { + background-color: #e7e7e8; +} + +.primary--NLSX4:disabled:hover { + background-color: #e7e7e8; } [class^="__NEPTUNE_PAGE"],