fix: visualizer bugs and better mobile support (#509)
* Refine fullscreen player to look more like apple music
* fix: buttons when in visualizer only mode
* fix: mobile sizing
* Update styles.css
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update js/ui.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat: refine fullscreen apple player
* fix: add lyrics toggle for mobile
* add lyrics toggle for mobile
* wrong branch oops 😭
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
7df10b0f5e
commit
f2135cc455
6 changed files with 752 additions and 361 deletions
|
|
@ -19,4 +19,3 @@ new_func = """def download_and_process_cover(cover_uuid):
|
|||
content = re.sub(r"def download_and_process_cover\(cover_uuid\):[\s\S]*?(?=def process_cover)", new_func + "\n\n", content)
|
||||
|
||||
with open("gen-editors-picks.py", "w") as f: f.write(content)
|
||||
|
||||
|
|
|
|||
18
index.html
18
index.html
|
|
@ -205,13 +205,17 @@
|
|||
z-index: 0;
|
||||
"
|
||||
></div>
|
||||
<button id="fullscreen-dismiss-handle" type="button" aria-label="Dismiss fullscreen"></button>
|
||||
<button id="toggle-fullscreen-lyrics-mobile-btn" class="fullscreen-mobile-lyrics-toggle" title="Hide Lyrics">
|
||||
<use svg="!lucide/mic-vocal.svg" size="18" />
|
||||
</button>
|
||||
<button id="toggle-ui-btn" class="fullscreen-ui-toggle" title="Toggle UI">
|
||||
<use svg="!lucide/eye-off.svg" size="24" />
|
||||
</button>
|
||||
<button id="toggle-fullscreen-lyrics-btn" class="fullscreen-lyrics-toggle" title="Toggle Lyrics">
|
||||
<use svg="!lucide/mic-vocal.svg" size="24" />
|
||||
</button>
|
||||
<div class="fullscreen-top-actions">
|
||||
<button id="toggle-fullscreen-lyrics-btn" class="fullscreen-lyrics-toggle" title="Hide Lyrics">
|
||||
<use svg="!lucide/mic-vocal.svg" size="20" />
|
||||
</button>
|
||||
<button id="fs-visualizer-btn" class="fs-visualizer-btn" title="Disable Visualizer">
|
||||
<use svg="!lucide/audio-lines.svg" size="20" />
|
||||
</button>
|
||||
|
|
@ -257,6 +261,7 @@
|
|||
</div>
|
||||
|
||||
<div class="fullscreen-controls">
|
||||
<div id="fullscreen-mobile-quality" class="fullscreen-mobile-quality" aria-hidden="true"></div>
|
||||
<div class="fullscreen-progress-container">
|
||||
<span id="fs-current-time">0:00</span>
|
||||
<div id="fs-progress-bar" class="progress-bar">
|
||||
|
|
@ -280,12 +285,7 @@
|
|||
<button id="fs-repeat-btn" title="Repeat">
|
||||
<use svg="!lucide/repeat.svg" size="24" />
|
||||
</button>
|
||||
<button
|
||||
id="fs-quality-btn"
|
||||
class="fs-quality-btn"
|
||||
title="Quality"
|
||||
style="display: none"
|
||||
>
|
||||
<button id="fs-quality-btn" class="fs-quality-btn" title="Quality" style="display: none">
|
||||
<use svg="!lucide/pencil-line.svg" size="20" />
|
||||
<span class="fs-quality-label">Auto</span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1013,12 +1013,16 @@ function applyFullscreenLyricsShadowTweaks(amLyrics, container) {
|
|||
}
|
||||
|
||||
.lyrics-line {
|
||||
transform-origin: left center;
|
||||
transition:
|
||||
opacity 0.42s ease,
|
||||
transform 0.55s cubic-bezier(0.22, 1, 0.36, 1) var(--lyrics-line-delay, 0ms),
|
||||
filter 0.48s cubic-bezier(0.22, 1, 0.36, 1) !important;
|
||||
}
|
||||
|
||||
.lyrics-line:not(.active):not(.pre-active) {
|
||||
opacity: 0.44;
|
||||
}
|
||||
.lyrics-line-container {
|
||||
transition:
|
||||
transform 0.72s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
|
|
@ -1033,6 +1037,10 @@ function applyFullscreenLyricsShadowTweaks(amLyrics, container) {
|
|||
background-color 0.22s ease,
|
||||
color 0.22s ease !important;
|
||||
}
|
||||
|
||||
.lyrics-line.active .lyrics-line-container {
|
||||
transform: scale(1.015);
|
||||
}
|
||||
`;
|
||||
|
||||
return true;
|
||||
|
|
|
|||
298
js/ui.js
298
js/ui.js
|
|
@ -93,6 +93,7 @@ const setFullscreenUIToggleIcon = (button, visualizerOnlyMode) => {
|
|||
button.innerHTML = visualizerOnlyMode ? SVG_EYE(24) : SVG_EYE_OFF(24);
|
||||
};
|
||||
|
||||
const isMobileFullscreenViewport = () => window.matchMedia('(max-width: 768px)').matches;
|
||||
function sortTracks(tracks, sortType) {
|
||||
if (sortType === 'custom') return [...tracks];
|
||||
const sorted = [...tracks];
|
||||
|
|
@ -155,6 +156,10 @@ export class UIRenderer {
|
|||
this.renderLock = false;
|
||||
this.lastRecommendedTracks = [];
|
||||
this.currentArtistId = null;
|
||||
this.fullscreenLyricsVisible = true;
|
||||
this.fullscreenPlaybackStateCleanup = null;
|
||||
this.fullscreenDismissHandleCleanup = null;
|
||||
this.fullscreenLyricsToggleCleanup = null;
|
||||
|
||||
// Listen for dynamic color reset events
|
||||
window.addEventListener('reset-dynamic-color', () => {
|
||||
|
|
@ -1095,9 +1100,13 @@ export class UIRenderer {
|
|||
let r = parseInt(hex.substr(0, 2), 16);
|
||||
let g = parseInt(hex.substr(2, 2), 16);
|
||||
let b = parseInt(hex.substr(4, 2), 16);
|
||||
let fullscreenR = r;
|
||||
let fullscreenG = g;
|
||||
let fullscreenB = b;
|
||||
|
||||
// Calculate perceived brightness
|
||||
let brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
||||
let fullscreenBrightness = brightness;
|
||||
|
||||
if (isLightMode) {
|
||||
// In light mode, the background is white.
|
||||
|
|
@ -1124,6 +1133,23 @@ export class UIRenderer {
|
|||
}
|
||||
|
||||
const adjustedColor = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
||||
while (fullscreenBrightness < 105) {
|
||||
fullscreenR = Math.min(255, Math.max(fullscreenR + 1, Math.floor(fullscreenR * 1.08)));
|
||||
fullscreenG = Math.min(255, Math.max(fullscreenG + 1, Math.floor(fullscreenG * 1.08)));
|
||||
fullscreenB = Math.min(255, Math.max(fullscreenB + 1, Math.floor(fullscreenB * 1.08)));
|
||||
fullscreenBrightness = (fullscreenR * 299 + fullscreenG * 587 + fullscreenB * 114) / 1000;
|
||||
if (fullscreenR >= 255 && fullscreenG >= 255 && fullscreenB >= 255) break;
|
||||
}
|
||||
while (fullscreenBrightness > 185) {
|
||||
fullscreenR = Math.floor(fullscreenR * 0.92);
|
||||
fullscreenG = Math.floor(fullscreenG * 0.92);
|
||||
fullscreenB = Math.floor(fullscreenB * 0.92);
|
||||
fullscreenBrightness = (fullscreenR * 299 + fullscreenG * 587 + fullscreenB * 114) / 1000;
|
||||
}
|
||||
|
||||
const fullscreenAdjustedColor = `#${fullscreenR.toString(16).padStart(2, '0')}${fullscreenG
|
||||
.toString(16)
|
||||
.padStart(2, '0')}${fullscreenB.toString(16).padStart(2, '0')}`;
|
||||
|
||||
// Calculate contrast text color for buttons (text on top of the vibrant color)
|
||||
const foreground = brightness > 128 ? '#000000' : '#ffffff';
|
||||
|
|
@ -1135,6 +1161,8 @@ export class UIRenderer {
|
|||
root.style.setProperty('--highlight-rgb', `${r}, ${g}, ${b}`);
|
||||
root.style.setProperty('--active-highlight', adjustedColor);
|
||||
root.style.setProperty('--ring', adjustedColor);
|
||||
root.style.setProperty('--fs-accent', fullscreenAdjustedColor);
|
||||
root.style.setProperty('--fs-accent-rgb', `${fullscreenR}, ${fullscreenG}, ${fullscreenB}`);
|
||||
|
||||
// Calculate a safe hover color
|
||||
let hoverColor;
|
||||
|
|
@ -1157,6 +1185,8 @@ export class UIRenderer {
|
|||
root.style.removeProperty('--highlight-rgb');
|
||||
root.style.removeProperty('--active-highlight');
|
||||
root.style.removeProperty('--ring');
|
||||
root.style.removeProperty('--fs-accent');
|
||||
root.style.removeProperty('--fs-accent-rgb');
|
||||
root.style.removeProperty('--track-hover-bg');
|
||||
}
|
||||
|
||||
|
|
@ -1270,12 +1300,10 @@ export class UIRenderer {
|
|||
currentImage.src = coverUrl;
|
||||
}
|
||||
}
|
||||
overlay.style.setProperty('--bg-image', `url('${this.api.getCoverUrl(track.album?.cover, '1280')}')`);
|
||||
await this.extractAndApplyColor(this.api.getCoverUrl(track.album?.cover, '80'));
|
||||
}
|
||||
|
||||
const qualityBadge = this.getFullscreenQualityBadgeHTML(track);
|
||||
title.innerHTML = `${escapeHtml(track.title)} ${qualityBadge}`;
|
||||
this.updateFullscreenQualityBadgePlacement(track, overlay);
|
||||
artist.textContent = getTrackArtists(track);
|
||||
|
||||
if (nextTrack) {
|
||||
|
|
@ -1288,7 +1316,7 @@ export class UIRenderer {
|
|||
|
||||
async showFullscreenCover(track, nextTrack, lyricsManager, activeElement) {
|
||||
if (!track) return;
|
||||
this.fullscreenVisualizerSuppressed = true;
|
||||
this.fullscreenVisualizerSuppressed = isMobileFullscreenViewport();
|
||||
if (window.location.hash !== '#fullscreen') {
|
||||
window.history.pushState({ fullscreen: true }, '', '#fullscreen');
|
||||
}
|
||||
|
|
@ -1308,23 +1336,23 @@ export class UIRenderer {
|
|||
nextTrackEl.classList.remove('animate-in');
|
||||
}
|
||||
|
||||
const canRenderLyrics = Boolean(
|
||||
lyricsManager && activeElement && lyricsPane && lyricsContent && track.type !== 'video'
|
||||
);
|
||||
const canRenderLyrics = Boolean(lyricsManager && activeElement && lyricsPane && lyricsContent && track.type !== 'video');
|
||||
if (canRenderLyrics) {
|
||||
lyricsToggleBtn.style.display = 'none';
|
||||
this.fullscreenLyricsVisible = true;
|
||||
if (lyricsToggleBtn) lyricsToggleBtn.style.removeProperty('display');
|
||||
overlay.classList.remove('lyrics-unavailable');
|
||||
clearFullscreenLyricsSync(lyricsContent);
|
||||
await renderLyricsInFullscreen(track, activeElement, lyricsManager, lyricsContent);
|
||||
} else {
|
||||
lyricsToggleBtn.style.display = 'none';
|
||||
this.fullscreenLyricsVisible = false;
|
||||
if (lyricsToggleBtn) lyricsToggleBtn.style.display = 'none';
|
||||
overlay.classList.add('lyrics-unavailable');
|
||||
if (lyricsContent) {
|
||||
clearFullscreenLyricsSync(lyricsContent);
|
||||
lyricsContent.innerHTML =
|
||||
'<div class="fullscreen-lyrics-empty">Lyrics are not available for this track.</div>';
|
||||
lyricsContent.innerHTML = '<div class="fullscreen-lyrics-empty">Lyrics are not available for this track.</div>';
|
||||
}
|
||||
}
|
||||
this.updateFullscreenLyricsVisibility(overlay);
|
||||
|
||||
const playerBar = document.querySelector('.now-playing-bar');
|
||||
if (playerBar) playerBar.style.display = 'none';
|
||||
|
|
@ -1355,9 +1383,84 @@ export class UIRenderer {
|
|||
this.setupUIToggleButton(overlay);
|
||||
this.setupControlsAutoHide(overlay);
|
||||
this.setupFullscreenSidePanelSync(overlay);
|
||||
this.setupFullscreenDismissHandle(overlay);
|
||||
this.setupFullscreenLyricsToggle(overlay);
|
||||
await this.refreshFullscreenVisualizerState(activeElement);
|
||||
}
|
||||
|
||||
updateFullscreenLyricsVisibility(overlay = document.getElementById('fullscreen-cover-overlay')) {
|
||||
if (!overlay) return;
|
||||
|
||||
const lyricsToggleButtons = [
|
||||
document.getElementById('toggle-fullscreen-lyrics-btn'),
|
||||
document.getElementById('toggle-fullscreen-lyrics-mobile-btn'),
|
||||
].filter(Boolean);
|
||||
const lyricsUnavailable = overlay.classList.contains('lyrics-unavailable');
|
||||
const shouldShowLyrics = this.fullscreenLyricsVisible && !lyricsUnavailable;
|
||||
|
||||
overlay.classList.toggle('lyrics-hidden', !shouldShowLyrics);
|
||||
this.updateFullscreenQualityBadgePlacement(this.player?.currentTrack, overlay);
|
||||
|
||||
lyricsToggleButtons.forEach((lyricsToggleBtn) => {
|
||||
lyricsToggleBtn.classList.toggle('active', shouldShowLyrics);
|
||||
lyricsToggleBtn.title = shouldShowLyrics ? 'Hide Lyrics' : 'Show Lyrics';
|
||||
lyricsToggleBtn.setAttribute('aria-pressed', shouldShowLyrics ? 'true' : 'false');
|
||||
if (lyricsUnavailable) {
|
||||
lyricsToggleBtn.style.display = 'none';
|
||||
} else {
|
||||
lyricsToggleBtn.style.removeProperty('display');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateFullscreenQualityBadgePlacement(track, overlay = document.getElementById('fullscreen-cover-overlay')) {
|
||||
if (!track || !overlay) return;
|
||||
|
||||
const title = document.getElementById('fullscreen-track-title');
|
||||
const mobileQuality = document.getElementById('fullscreen-mobile-quality');
|
||||
if (!title) return;
|
||||
|
||||
const qualityBadge = this.getFullscreenQualityBadgeHTML(track);
|
||||
const useMobileBadgeOnly = window.matchMedia('(max-width: 768px)').matches && overlay.classList.contains('lyrics-hidden');
|
||||
|
||||
title.innerHTML = useMobileBadgeOnly ? escapeHtml(track.title) : `${escapeHtml(track.title)} ${qualityBadge}`;
|
||||
if (mobileQuality) {
|
||||
mobileQuality.innerHTML = useMobileBadgeOnly ? qualityBadge : '';
|
||||
}
|
||||
}
|
||||
|
||||
async dismissFullscreenCover({ animate = true } = {}) {
|
||||
const overlay = document.getElementById('fullscreen-cover-overlay');
|
||||
if (!overlay || overlay.style.display === 'none') return;
|
||||
|
||||
if (animate) {
|
||||
await new Promise((resolve) => {
|
||||
const finish = () => {
|
||||
overlay.removeEventListener('transitionend', handleTransitionEnd);
|
||||
overlay.classList.remove('fullscreen-dragging', 'fullscreen-dismissing');
|
||||
overlay.style.removeProperty('--fullscreen-drag-offset');
|
||||
overlay.style.removeProperty('--fullscreen-drag-progress');
|
||||
resolve();
|
||||
};
|
||||
|
||||
const handleTransitionEnd = (event) => {
|
||||
if (event.target !== overlay.querySelector('.fullscreen-cover-content')) return;
|
||||
finish();
|
||||
};
|
||||
|
||||
overlay.addEventListener('transitionend', handleTransitionEnd);
|
||||
overlay.classList.add('fullscreen-dismissing');
|
||||
window.setTimeout(finish, 280);
|
||||
});
|
||||
}
|
||||
|
||||
this.closeFullscreenCover();
|
||||
|
||||
if (window.location.hash === '#fullscreen') {
|
||||
window.history.back();
|
||||
}
|
||||
}
|
||||
|
||||
closeFullscreenCover() {
|
||||
const overlay = document.getElementById('fullscreen-cover-overlay');
|
||||
const coverImage = document.getElementById('fullscreen-cover-image');
|
||||
|
|
@ -1370,16 +1473,22 @@ export class UIRenderer {
|
|||
lyricsContent.innerHTML = '<div class="fullscreen-lyrics-empty">Lyrics appear here.</div>';
|
||||
}
|
||||
overlay.style.display = 'none';
|
||||
overlay.classList.remove('visualizer-active', 'ui-hidden', 'fullscreen-cover-no-round', 'fullscreen-paused');
|
||||
overlay.classList.remove(
|
||||
'visualizer-active',
|
||||
'ui-hidden',
|
||||
'fullscreen-cover-no-round',
|
||||
'fullscreen-paused',
|
||||
'fullscreen-dragging',
|
||||
'fullscreen-dismissing'
|
||||
);
|
||||
overlay.style.removeProperty('--fullscreen-drag-offset');
|
||||
overlay.style.removeProperty('--fullscreen-drag-progress');
|
||||
|
||||
const playerBar = document.querySelector('.now-playing-bar');
|
||||
if (playerBar) playerBar.style.removeProperty('display');
|
||||
const mainContent = document.querySelector('.main-content');
|
||||
if (mainContent instanceof HTMLElement) {
|
||||
if (
|
||||
typeof this.fullscreenMainContentOverflow === 'string' &&
|
||||
this.fullscreenMainContentOverflow.length > 0
|
||||
) {
|
||||
if (typeof this.fullscreenMainContentOverflow === 'string' && this.fullscreenMainContentOverflow.length > 0) {
|
||||
mainContent.style.overflowY = this.fullscreenMainContentOverflow;
|
||||
} else {
|
||||
mainContent.style.removeProperty('overflow-y');
|
||||
|
|
@ -1434,6 +1543,16 @@ export class UIRenderer {
|
|||
this.fullscreenSidePanelSyncCleanup();
|
||||
this.fullscreenSidePanelSyncCleanup = null;
|
||||
}
|
||||
|
||||
if (this.fullscreenDismissHandleCleanup) {
|
||||
this.fullscreenDismissHandleCleanup();
|
||||
this.fullscreenDismissHandleCleanup = null;
|
||||
}
|
||||
|
||||
if (this.fullscreenLyricsToggleCleanup) {
|
||||
this.fullscreenLyricsToggleCleanup();
|
||||
this.fullscreenLyricsToggleCleanup = null;
|
||||
}
|
||||
}
|
||||
|
||||
async startFullscreenVisualizer(activeElement, overlay) {
|
||||
|
|
@ -1448,6 +1567,7 @@ export class UIRenderer {
|
|||
}
|
||||
|
||||
if (this.visualizer) {
|
||||
this.visualizer.applyPresetOverride('kawarp');
|
||||
await this.visualizer.start();
|
||||
overlay.classList.add('visualizer-active');
|
||||
}
|
||||
|
|
@ -1493,7 +1613,7 @@ export class UIRenderer {
|
|||
const visualizerBtn = document.getElementById('fs-visualizer-btn');
|
||||
const toggleBtn = document.getElementById('toggle-ui-btn');
|
||||
const isVideoTrack = this.player?.currentTrack?.type === 'video';
|
||||
const enabled = visualizerSettings.isEnabled() && !isVideoTrack && !this.fullscreenVisualizerSuppressed;
|
||||
const enabled = !isVideoTrack && !this.fullscreenVisualizerSuppressed && !isMobileFullscreenViewport();
|
||||
|
||||
if (!overlay) return;
|
||||
|
||||
|
|
@ -1578,7 +1698,6 @@ export class UIRenderer {
|
|||
}
|
||||
|
||||
this.fullscreenVisualizerSuppressed = false;
|
||||
visualizerSettings.setEnabled(true);
|
||||
await this.refreshFullscreenVisualizerState(this.player?.activeElement);
|
||||
|
||||
if (!overlay.classList.contains('visualizer-active')) {
|
||||
|
|
@ -1659,6 +1778,138 @@ export class UIRenderer {
|
|||
};
|
||||
}
|
||||
|
||||
setupFullscreenDismissHandle(overlay) {
|
||||
if (this.fullscreenDismissHandleCleanup) {
|
||||
this.fullscreenDismissHandleCleanup();
|
||||
this.fullscreenDismissHandleCleanup = null;
|
||||
}
|
||||
|
||||
const handle = document.getElementById('fullscreen-dismiss-handle');
|
||||
if (!handle) return;
|
||||
|
||||
let activePointerId = null;
|
||||
let startY = 0;
|
||||
let startX = 0;
|
||||
let lastY = 0;
|
||||
let lastTimestamp = 0;
|
||||
let velocityY = 0;
|
||||
let hasDragged = false;
|
||||
|
||||
const resetDragState = () => {
|
||||
activePointerId = null;
|
||||
hasDragged = false;
|
||||
overlay.classList.remove('fullscreen-dragging');
|
||||
overlay.style.removeProperty('--fullscreen-drag-offset');
|
||||
overlay.style.removeProperty('--fullscreen-drag-progress');
|
||||
};
|
||||
|
||||
const onPointerDown = (event) => {
|
||||
if (!isMobileFullscreenViewport()) return;
|
||||
|
||||
activePointerId = event.pointerId;
|
||||
startY = event.clientY;
|
||||
startX = event.clientX;
|
||||
lastY = event.clientY;
|
||||
lastTimestamp = event.timeStamp;
|
||||
velocityY = 0;
|
||||
hasDragged = false;
|
||||
overlay.classList.add('fullscreen-dragging');
|
||||
handle.setPointerCapture(event.pointerId);
|
||||
};
|
||||
|
||||
const onPointerMove = (event) => {
|
||||
if (event.pointerId !== activePointerId) return;
|
||||
|
||||
const deltaY = Math.max(0, event.clientY - startY);
|
||||
const deltaX = Math.abs(event.clientX - startX);
|
||||
|
||||
if (!hasDragged && deltaX > deltaY) {
|
||||
resetDragState();
|
||||
return;
|
||||
}
|
||||
|
||||
hasDragged = true;
|
||||
event.preventDefault();
|
||||
|
||||
const elapsed = Math.max(1, event.timeStamp - lastTimestamp);
|
||||
velocityY = (event.clientY - lastY) / elapsed;
|
||||
lastY = event.clientY;
|
||||
lastTimestamp = event.timeStamp;
|
||||
|
||||
const progress = Math.min(deltaY / Math.max(window.innerHeight * 0.32, 1), 1);
|
||||
overlay.style.setProperty('--fullscreen-drag-offset', `${deltaY}px`);
|
||||
overlay.style.setProperty('--fullscreen-drag-progress', progress.toFixed(3));
|
||||
};
|
||||
|
||||
const onPointerEnd = async (event) => {
|
||||
if (event.pointerId !== activePointerId) return;
|
||||
|
||||
const deltaY = Math.max(0, event.clientY - startY);
|
||||
const shouldDismiss = hasDragged && (deltaY > 96 || velocityY > 0.55);
|
||||
|
||||
if (handle.hasPointerCapture(event.pointerId)) {
|
||||
handle.releasePointerCapture(event.pointerId);
|
||||
}
|
||||
|
||||
if (shouldDismiss) {
|
||||
await this.dismissFullscreenCover();
|
||||
return;
|
||||
}
|
||||
|
||||
resetDragState();
|
||||
};
|
||||
|
||||
const onClick = async (event) => {
|
||||
if (!isMobileFullscreenViewport() || hasDragged) return;
|
||||
event.preventDefault();
|
||||
await this.dismissFullscreenCover();
|
||||
};
|
||||
|
||||
handle.addEventListener('pointerdown', onPointerDown);
|
||||
handle.addEventListener('pointermove', onPointerMove);
|
||||
handle.addEventListener('pointerup', onPointerEnd);
|
||||
handle.addEventListener('pointercancel', onPointerEnd);
|
||||
handle.addEventListener('click', onClick);
|
||||
|
||||
this.fullscreenDismissHandleCleanup = () => {
|
||||
handle.removeEventListener('pointerdown', onPointerDown);
|
||||
handle.removeEventListener('pointermove', onPointerMove);
|
||||
handle.removeEventListener('pointerup', onPointerEnd);
|
||||
handle.removeEventListener('pointercancel', onPointerEnd);
|
||||
handle.removeEventListener('click', onClick);
|
||||
overlay.classList.remove('fullscreen-dragging');
|
||||
overlay.style.removeProperty('--fullscreen-drag-offset');
|
||||
overlay.style.removeProperty('--fullscreen-drag-progress');
|
||||
};
|
||||
}
|
||||
|
||||
setupFullscreenLyricsToggle(overlay) {
|
||||
if (this.fullscreenLyricsToggleCleanup) {
|
||||
this.fullscreenLyricsToggleCleanup();
|
||||
this.fullscreenLyricsToggleCleanup = null;
|
||||
}
|
||||
|
||||
const toggleButtons = [
|
||||
document.getElementById('toggle-fullscreen-lyrics-btn'),
|
||||
document.getElementById('toggle-fullscreen-lyrics-mobile-btn'),
|
||||
].filter(Boolean);
|
||||
if (toggleButtons.length === 0) return;
|
||||
|
||||
const handleToggle = (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (overlay.classList.contains('lyrics-unavailable')) return;
|
||||
this.fullscreenLyricsVisible = !this.fullscreenLyricsVisible;
|
||||
this.updateFullscreenLyricsVisibility(overlay);
|
||||
};
|
||||
|
||||
toggleButtons.forEach((toggleBtn) => toggleBtn.addEventListener('click', handleToggle));
|
||||
this.updateFullscreenLyricsVisibility(overlay);
|
||||
|
||||
this.fullscreenLyricsToggleCleanup = () => {
|
||||
toggleButtons.forEach((toggleBtn) => toggleBtn.removeEventListener('click', handleToggle));
|
||||
};
|
||||
}
|
||||
setupFullscreenControls() {
|
||||
const playBtn = document.getElementById('fs-play-pause-btn');
|
||||
const prevBtn = document.getElementById('fs-prev-btn');
|
||||
|
|
@ -1728,16 +1979,7 @@ export class UIRenderer {
|
|||
|
||||
if (visualizerBtn) {
|
||||
visualizerBtn.onclick = async () => {
|
||||
if (this.fullscreenVisualizerSuppressed) {
|
||||
this.fullscreenVisualizerSuppressed = false;
|
||||
visualizerSettings.setEnabled(true);
|
||||
} else if (visualizerSettings.isEnabled()) {
|
||||
visualizerSettings.setEnabled(false);
|
||||
this.fullscreenVisualizerSuppressed = false;
|
||||
} else {
|
||||
this.fullscreenVisualizerSuppressed = false;
|
||||
visualizerSettings.setEnabled(true);
|
||||
}
|
||||
this.fullscreenVisualizerSuppressed = !this.fullscreenVisualizerSuppressed;
|
||||
await this.refreshFullscreenVisualizerState(this.player.activeElement);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,4 +337,16 @@ export class Visualizer {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
applyPresetOverride(key) {
|
||||
if (!this.presets?.[key] || this.activePresetKey === key) return;
|
||||
|
||||
if (this.activePreset?.destroy) {
|
||||
this.activePreset.destroy();
|
||||
}
|
||||
|
||||
this._currentContextType = undefined;
|
||||
this.ctx = null;
|
||||
this.activePresetKey = key;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
776
styles.css
776
styles.css
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue