Updated
This commit is contained in:
+54
-25
@@ -89,6 +89,9 @@ const stationLibraryPagePrevBtn = document.getElementById('station-library-page-
|
||||
const stationLibraryPageNextBtn = document.getElementById('station-library-page-next');
|
||||
const stationLibraryPageInfo = document.getElementById('station-library-page-info');
|
||||
const stationTabBtns = document.querySelectorAll('[data-station-tab]');
|
||||
const installPromptBannerEl = document.getElementById('install-prompt-banner');
|
||||
const installPromptActionBtn = document.getElementById('install-prompt-action');
|
||||
const installPromptDismissBtn = document.getElementById('install-prompt-dismiss');
|
||||
|
||||
const radioCountryCodeByName = new Map(radioCountries.map((country) => [country.name, country.code]));
|
||||
const radioCountryNameByCode = new Map(radioCountries.map((country) => [country.code, country.name]));
|
||||
@@ -124,6 +127,47 @@ function prefersReducedMotion() {
|
||||
}
|
||||
}
|
||||
|
||||
function isMobileViewport() {
|
||||
return window.matchMedia('(max-width: 760px)').matches;
|
||||
}
|
||||
|
||||
function isStandalonePwa() {
|
||||
return window.matchMedia('(display-mode: standalone)').matches
|
||||
|| window.matchMedia('(display-mode: fullscreen)').matches
|
||||
|| window.navigator.standalone === true;
|
||||
}
|
||||
|
||||
async function lockPortraitOrientation() {
|
||||
if (!isMobileViewport()) return;
|
||||
if (!isStandalonePwa()) return;
|
||||
if (!screen?.orientation?.lock) return;
|
||||
|
||||
try {
|
||||
await screen.orientation.lock('portrait');
|
||||
} catch (e) {
|
||||
// Some browsers require a user gesture or simply do not allow locking.
|
||||
console.debug('Portrait orientation lock not available:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function isMobileInstallViewport() {
|
||||
return window.matchMedia('(max-width: 760px)').matches;
|
||||
}
|
||||
|
||||
function hideInstallPromptUI() {
|
||||
installAppBtn?.classList.add('hidden');
|
||||
installPromptBannerEl?.classList.add('hidden');
|
||||
}
|
||||
|
||||
function showInstallPromptUI() {
|
||||
if (!deferredInstallPrompt) return;
|
||||
if (isMobileInstallViewport()) {
|
||||
installPromptBannerEl?.classList.remove('hidden');
|
||||
} else {
|
||||
installAppBtn?.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function clearArtworkShineTimers() {
|
||||
if (artworkShineTimeoutId) {
|
||||
clearTimeout(artworkShineTimeoutId);
|
||||
@@ -2252,6 +2296,8 @@ function setupEventListeners() {
|
||||
|
||||
artworkPlaceholder?.addEventListener('click', openStationLibrary);
|
||||
castOutputBtn?.addEventListener('click', toggleCastBothMode);
|
||||
installPromptActionBtn?.addEventListener('click', promptInstallApp);
|
||||
installPromptDismissBtn?.addEventListener('click', hideInstallPromptUI);
|
||||
window.addEventListener('resize', () => {
|
||||
updateCoverflowTransforms();
|
||||
updateStationTitleLayout(getStationTitle(stations[currentIndex]));
|
||||
@@ -2283,7 +2329,7 @@ async function promptInstallApp() {
|
||||
deferredInstallPrompt.prompt();
|
||||
try { await deferredInstallPrompt.userChoice; } catch (e) { /* ignore */ }
|
||||
deferredInstallPrompt = null;
|
||||
installAppBtn?.classList.add('hidden');
|
||||
hideInstallPromptUI();
|
||||
}
|
||||
|
||||
// ── Media Session API (for OS media controls / lock screen) ──────────────────
|
||||
@@ -2325,6 +2371,7 @@ async function init() {
|
||||
restoreLastStationCountry();
|
||||
await loadStations();
|
||||
setupEventListeners();
|
||||
lockPortraitOrientation();
|
||||
ensureArtworkPointerFallback();
|
||||
scheduleArtworkShine();
|
||||
updateUI();
|
||||
@@ -2337,37 +2384,19 @@ async function init() {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Service Worker registration (PWA) ────────────────────────────────────────
|
||||
|
||||
if ('serviceWorker' in navigator && import.meta.env.DEV) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.getRegistrations()
|
||||
.then((registrations) => Promise.all(registrations.map((reg) => reg.unregister())))
|
||||
.catch((err) => console.debug('ServiceWorker dev cleanup failed:', err));
|
||||
|
||||
if ('caches' in window) {
|
||||
caches.keys()
|
||||
.then((keys) => Promise.all(keys.map((key) => caches.delete(key))))
|
||||
.catch((err) => console.debug('Cache dev cleanup failed:', err));
|
||||
}
|
||||
});
|
||||
} else if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register(`${import.meta.env.BASE_URL}sw.js`)
|
||||
.then((reg) => console.log('ServiceWorker registered:', reg.scope))
|
||||
.catch((err) => console.debug('ServiceWorker registration failed:', err));
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('beforeinstallprompt', (event) => {
|
||||
event.preventDefault();
|
||||
deferredInstallPrompt = event;
|
||||
installAppBtn?.classList.remove('hidden');
|
||||
showInstallPromptUI();
|
||||
});
|
||||
|
||||
window.addEventListener('appinstalled', () => {
|
||||
deferredInstallPrompt = null;
|
||||
installAppBtn?.classList.add('hidden');
|
||||
hideInstallPromptUI();
|
||||
});
|
||||
|
||||
window.addEventListener('orientationchange', () => {
|
||||
lockPortraitOrientation();
|
||||
});
|
||||
|
||||
export function initPlayer() {
|
||||
|
||||
Reference in New Issue
Block a user