diff --git a/js/app.js b/js/app.js index a61aff2..311d15c 100644 --- a/js/app.js +++ b/js/app.js @@ -299,6 +299,13 @@ function initializeKeyboardShortcuts(player, _audioPlayer) { }, lyrics: () => { trackKeyboardShortcut('L'); + const overlay = document.getElementById('fullscreen-cover-overlay'); + const isFullscreenOpen = overlay && getComputedStyle(overlay).display !== 'none'; + + if (isFullscreenOpen && UIRenderer.instance?.toggleFullscreenLyrics(overlay)) { + return; + } + document.getElementById('toggle-lyrics-btn')?.click(); }, search: () => { @@ -361,6 +368,19 @@ function initializeKeyboardShortcuts(player, _audioPlayer) { }); } +async function closeFullscreenOverlay() { + if (UIRenderer.instance?.dismissFullscreenCover) { + await UIRenderer.instance.dismissFullscreenCover({ animate: false }); + return; + } + + if (window.location.hash === '#fullscreen') { + window.history.back(); + } else { + UIRenderer.instance?.closeFullscreenCover(); + } +} + function showOfflineNotification() { const notification = document.createElement('div'); notification.className = 'offline-notification'; @@ -736,11 +756,7 @@ document.addEventListener('DOMContentLoaded', async () => { } else if (mode === 'cover') { const overlay = document.getElementById('fullscreen-cover-overlay'); if (overlay && overlay.style.display === 'flex') { - if (window.location.hash === '#fullscreen') { - window.history.back(); - } else { - UIRenderer.instance.closeFullscreenCover(); - } + await closeFullscreenOverlay(); } else { const nextTrack = Player.instance.getNextTrack(); UIRenderer.instance.showFullscreenCover( @@ -764,13 +780,9 @@ document.addEventListener('DOMContentLoaded', async () => { if (shareBtn) shareBtn.style.display = e.target.checked ? 'flex' : 'none'; }); - document.getElementById('close-fullscreen-cover-btn')?.addEventListener('click', () => { + document.getElementById('close-fullscreen-cover-btn')?.addEventListener('click', async () => { trackCloseFullscreenCover(); - if (window.location.hash === '#fullscreen') { - window.history.back(); - } else { - UIRenderer.instance.closeFullscreenCover(); - } + await closeFullscreenOverlay(); }); document.getElementById('fullscreen-cover-overlay')?.addEventListener('click', (e) => { @@ -785,11 +797,7 @@ document.addEventListener('DOMContentLoaded', async () => { switch (action) { case 'exit': - if (window.location.hash === '#fullscreen') { - window.history.back(); - } else { - UIRenderer.instance.closeFullscreenCover(); - } + closeFullscreenOverlay(); break; case 'hide-ui': if (overlay) { @@ -831,11 +839,7 @@ document.addEventListener('DOMContentLoaded', async () => { case 'nothing': break; default: - if (window.location.hash === '#fullscreen') { - window.history.back(); - } else { - UIRenderer.instance.closeFullscreenCover(); - } + closeFullscreenOverlay(); } }); diff --git a/js/settings.js b/js/settings.js index 2b8b187..ac17f46 100644 --- a/js/settings.js +++ b/js/settings.js @@ -1137,7 +1137,8 @@ export async function initializeSettings(scrobbler, player, api, ui) { if (replayGainPreamp) { replayGainPreamp.value = replayGainSettings.getPreamp(); replayGainPreamp.addEventListener('change', (e) => { - replayGainSettings.setPreamp(parseFloat(e.target.value) || 3); + const val = parseFloat(e.target.value); + replayGainSettings.setPreamp(isNaN(val) ? 3 : val); player.applyReplayGain(); }); } @@ -1174,7 +1175,8 @@ export async function initializeSettings(scrobbler, player, api, ui) { if (playbackSpeedSlider && playbackSpeedInput) { // Helper function to update both controls const updatePlaybackSpeedControls = (speed) => { - const validSpeed = Math.max(0.01, Math.min(100, parseFloat(speed) || 1.0)); + const parsedSpeed = parseFloat(speed); + const validSpeed = Math.max(0.01, Math.min(100, isNaN(parsedSpeed) ? 1.0 : parsedSpeed)); playbackSpeedInput.value = validSpeed; // Only update slider if value is within slider range if (validSpeed >= 0.25 && validSpeed <= 4.0) { diff --git a/js/storage.js b/js/storage.js index f702eac..dce47da 100644 --- a/js/storage.js +++ b/js/storage.js @@ -442,7 +442,8 @@ export const lastFMStorage = { }, setScrobblePercentage(percentage) { - const validPercentage = Math.max(1, Math.min(100, parseInt(percentage, 10) || 75)); + const parsed = parseInt(percentage, 10); + const validPercentage = Math.max(1, Math.min(100, isNaN(parsed) ? 75 : parsed)); localStorage.setItem(this.SCROBBLE_PERCENTAGE_KEY, validPercentage.toString()); }, @@ -1123,9 +1124,10 @@ export const equalizerSettings = { }, setBandCount(count) { + const parsedCount = parseInt(count, 10); const validCount = Math.max( this.MIN_BANDS, - Math.min(this.MAX_BANDS, parseInt(count, 10) || this.DEFAULT_BAND_COUNT) + Math.min(this.MAX_BANDS, isNaN(parsedCount) ? this.DEFAULT_BAND_COUNT : parsedCount) ); localStorage.setItem(this.BAND_COUNT_KEY, validCount.toString()); }, @@ -2451,7 +2453,8 @@ export const fontSettings = { }, setFontSize(size) { - const validSize = Math.max(50, Math.min(200, parseInt(size, 10) || 100)); + const parsed = parseInt(size, 10); + const validSize = Math.max(50, Math.min(200, isNaN(parsed) ? 100 : parsed)); localStorage.setItem(this.FONT_SIZE_KEY, validSize.toString()); this.applyFontSize(); return validSize; diff --git a/js/ui.js b/js/ui.js index 9238ea9..3e30b3b 100644 --- a/js/ui.js +++ b/js/ui.js @@ -1366,8 +1366,15 @@ export class UIRenderer { } const mainContent = document.querySelector('.main-content'); if (mainContent instanceof HTMLElement) { - this.fullscreenMainContentOverflow = mainContent.style.overflowY; - mainContent.style.overflowY = 'hidden'; + const computedStyles = window.getComputedStyle(mainContent); + this.fullscreenMainContentOverflow = { + overflow: mainContent.style.overflow, + overflowX: mainContent.style.overflowX, + overflowY: mainContent.style.overflowY, + computedOverflowX: computedStyles.overflowX, + computedOverflowY: computedStyles.overflowY, + }; + mainContent.style.overflow = 'hidden'; } this.setupFullscreenControls(); @@ -1418,6 +1425,14 @@ export class UIRenderer { }); } + toggleFullscreenLyrics(overlay = document.getElementById('fullscreen-cover-overlay')) { + if (!overlay || overlay.classList.contains('lyrics-unavailable')) return false; + + this.fullscreenLyricsVisible = !this.fullscreenLyricsVisible; + this.updateFullscreenLyricsVisibility(overlay); + return true; + } + updateFullscreenQualityBadgePlacement(track, overlay = document.getElementById('fullscreen-cover-overlay')) { if (!track || !overlay) return; @@ -1494,12 +1509,32 @@ export class UIRenderer { 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 - ) { - mainContent.style.overflowY = this.fullscreenMainContentOverflow; + const previousOverflow = this.fullscreenMainContentOverflow; + if (previousOverflow && typeof previousOverflow === 'object') { + if (previousOverflow.overflow) { + mainContent.style.overflow = previousOverflow.overflow; + } else { + mainContent.style.removeProperty('overflow'); + } + + if (previousOverflow.overflowX) { + mainContent.style.overflowX = previousOverflow.overflowX; + } else if (previousOverflow.computedOverflowX && previousOverflow.computedOverflowX !== 'visible') { + mainContent.style.overflowX = previousOverflow.computedOverflowX; + } else { + mainContent.style.removeProperty('overflow-x'); + } + + if (previousOverflow.overflowY) { + mainContent.style.overflowY = previousOverflow.overflowY; + } else if (previousOverflow.computedOverflowY && previousOverflow.computedOverflowY !== 'visible') { + mainContent.style.overflowY = previousOverflow.computedOverflowY; + } else { + mainContent.style.removeProperty('overflow-y'); + } } else { + mainContent.style.removeProperty('overflow'); + mainContent.style.removeProperty('overflow-x'); mainContent.style.removeProperty('overflow-y'); } this.fullscreenMainContentOverflow = null; @@ -1576,7 +1611,6 @@ export class UIRenderer { } if (this.visualizer) { - this.visualizer.applyPresetOverride('kawarp'); await this.visualizer.start(); overlay.classList.add('visualizer-active'); } @@ -1907,9 +1941,7 @@ export class UIRenderer { const handleToggle = (event) => { event.preventDefault(); event.stopPropagation(); - if (overlay.classList.contains('lyrics-unavailable')) return; - this.fullscreenLyricsVisible = !this.fullscreenLyricsVisible; - this.updateFullscreenLyricsVisibility(overlay); + this.toggleFullscreenLyrics(overlay); }; toggleButtons.forEach((toggleBtn) => toggleBtn.addEventListener('click', handleToggle)); diff --git a/styles.css b/styles.css index 5f78852..803f242 100644 --- a/styles.css +++ b/styles.css @@ -10336,7 +10336,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn { #fullscreen-cover-overlay #toggle-ui-btn { top: 1.25rem; - left: calc(9.9rem + env(safe-area-inset-left)); + left: calc(1.5rem + env(safe-area-inset-left) + (40px * 3) + (0.4rem * 3)); right: auto; width: 40px; height: 40px;