refactor(UIRenderer): convert to singleton
This commit is contained in:
parent
2fdd169ba0
commit
e32fbc3813
4 changed files with 85 additions and 68 deletions
109
js/app.js
109
js/app.js
|
|
@ -264,23 +264,20 @@ function initializeKeyboardShortcuts(player, _audioPlayer) {
|
||||||
},
|
},
|
||||||
visualizerNext: () => {
|
visualizerNext: () => {
|
||||||
trackKeyboardShortcut('VisualizerNext');
|
trackKeyboardShortcut('VisualizerNext');
|
||||||
const ui = window.monochromeUi;
|
if (UIRenderer.instance.visualizer?.presets?.['butterchurn']) {
|
||||||
if (ui?.visualizer?.presets?.['butterchurn']) {
|
UIRenderer.instance.visualizer.presets['butterchurn'].nextPreset();
|
||||||
ui.visualizer.presets['butterchurn'].nextPreset();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
visualizerPrev: () => {
|
visualizerPrev: () => {
|
||||||
trackKeyboardShortcut('VisualizerPrev');
|
trackKeyboardShortcut('VisualizerPrev');
|
||||||
const ui = window.monochromeUi;
|
if (UIRenderer.instance.visualizer?.presets?.['butterchurn']) {
|
||||||
if (ui?.visualizer?.presets?.['butterchurn']) {
|
UIRenderer.instance.visualizer.presets['butterchurn'].prevPreset();
|
||||||
ui.visualizer.presets['butterchurn'].prevPreset();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
visualizerCycle: () => {
|
visualizerCycle: () => {
|
||||||
trackKeyboardShortcut('VisualizerCycle');
|
trackKeyboardShortcut('VisualizerCycle');
|
||||||
const ui = window.monochromeUi;
|
if (UIRenderer.instance.visualizer?.presets?.['butterchurn']) {
|
||||||
if (ui?.visualizer?.presets?.['butterchurn']) {
|
UIRenderer.instance.visualizer.presets['butterchurn'].toggleCycle();
|
||||||
ui.visualizer.presets['butterchurn'].toggleCycle();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -386,10 +383,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
if (import.meta.env.DEV) {
|
||||||
window.monochrome = {
|
window.monochrome = {
|
||||||
MusicAPI,
|
|
||||||
LyricsManager,
|
|
||||||
Player,
|
|
||||||
HiFiClient,
|
HiFiClient,
|
||||||
|
LyricsManager,
|
||||||
|
MusicAPI,
|
||||||
|
Player,
|
||||||
|
UIRenderer,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -506,8 +504,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const castBtn = document.getElementById('cast-btn');
|
const castBtn = document.getElementById('cast-btn');
|
||||||
initializeCasting(audioPlayer, castBtn);
|
initializeCasting(audioPlayer, castBtn);
|
||||||
|
|
||||||
const ui = new UIRenderer(MusicAPI.instance, Player.instance);
|
await UIRenderer.initialize(MusicAPI.instance, Player.instance);
|
||||||
window.monochromeUi = ui;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans the configured local media folder and refreshes `window.localFilesCache`.
|
* Scans the configured local media folder and refreshes `window.localFilesCache`.
|
||||||
|
|
@ -559,7 +556,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const metadata = await readTrackMetadata(file);
|
const metadata = await readTrackMetadata(file);
|
||||||
metadata.id = `local-${idCounter++}-${entry.entry}`;
|
metadata.id = `local-${idCounter++}-${entry.entry}`;
|
||||||
tracks.push(metadata);
|
tracks.push(metadata);
|
||||||
window.monochromeUi?.renderLocalFiles(
|
UIRenderer.instance.renderLocalFiles(
|
||||||
document.getElementById('library-local-container')
|
document.getElementById('library-local-container')
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -596,7 +593,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const metadata = await readTrackMetadata(file);
|
const metadata = await readTrackMetadata(file);
|
||||||
metadata.id = `local-${idCounter++}-${file.name}`;
|
metadata.id = `local-${idCounter++}-${file.name}`;
|
||||||
tracks.push(metadata);
|
tracks.push(metadata);
|
||||||
window.monochromeUi?.renderLocalFiles(
|
UIRenderer.instance.renderLocalFiles(
|
||||||
document.getElementById('library-local-container')
|
document.getElementById('library-local-container')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -610,7 +607,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
tracks.sort((a, b) => (a.artist.name || '').localeCompare(b.artist.name || ''));
|
tracks.sort((a, b) => (a.artist.name || '').localeCompare(b.artist.name || ''));
|
||||||
// Update only the local-files section without navigating to the library page.
|
// Update only the local-files section without navigating to the library page.
|
||||||
window.monochromeUi?.renderLocalFiles(document.getElementById('library-local-container'));
|
UIRenderer.instance.renderLocalFiles(document.getElementById('library-local-container'));
|
||||||
} finally {
|
} finally {
|
||||||
window.localFilesScanInProgress = false;
|
window.localFilesScanInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
@ -643,7 +640,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
window.localFilesCache = [...existing, metadata].sort((a, b) =>
|
window.localFilesCache = [...existing, metadata].sort((a, b) =>
|
||||||
(a.artist.name || '').localeCompare(b.artist.name || '')
|
(a.artist.name || '').localeCompare(b.artist.name || '')
|
||||||
);
|
);
|
||||||
window.monochromeUi?.renderLocalFiles(document.getElementById('library-local-container'));
|
UIRenderer.instance.renderLocalFiles(document.getElementById('library-local-container'));
|
||||||
} catch {
|
} catch {
|
||||||
// Fall back to a full rescan if metadata extraction fails.
|
// Fall back to a full rescan if metadata extraction fails.
|
||||||
await scanLocalMediaFolder(true);
|
await scanLocalMediaFolder(true);
|
||||||
|
|
@ -665,7 +662,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
window.monochromeScrobbler = scrobbler;
|
window.monochromeScrobbler = scrobbler;
|
||||||
|
|
||||||
const lyricsManager = await LyricsManager.initialize(MusicAPI.instance);
|
const lyricsManager = await LyricsManager.initialize(MusicAPI.instance);
|
||||||
ui.lyricsManager = lyricsManager;
|
UIRenderer.instance.lyricsManager = lyricsManager;
|
||||||
|
|
||||||
// Check browser support for local files
|
// Check browser support for local files
|
||||||
const selectLocalBtn = document.getElementById('select-local-folder-btn');
|
const selectLocalBtn = document.getElementById('select-local-folder-btn');
|
||||||
|
|
@ -698,11 +695,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
sidebarSettings.restoreState();
|
sidebarSettings.restoreState();
|
||||||
|
|
||||||
// Render pinned items
|
// Render pinned items
|
||||||
await ui.renderPinnedItems();
|
await UIRenderer.instance.renderPinnedItems();
|
||||||
|
|
||||||
// Load settings module and initialize
|
// Load settings module and initialize
|
||||||
const { initializeSettings } = await loadSettingsModule();
|
const { initializeSettings } = await loadSettingsModule();
|
||||||
await initializeSettings(scrobbler, Player.instance, MusicAPI.instance, ui);
|
await initializeSettings(scrobbler, Player.instance, MusicAPI.instance, UIRenderer.instance);
|
||||||
|
|
||||||
// Track sidebar navigation clicks
|
// Track sidebar navigation clicks
|
||||||
document.querySelectorAll('.sidebar-nav a').forEach((link) => {
|
document.querySelectorAll('.sidebar-nav a').forEach((link) => {
|
||||||
|
|
@ -715,22 +712,22 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
initializePlayerEvents(Player.instance, audioPlayer, scrobbler, ui);
|
initializePlayerEvents(Player.instance, audioPlayer, scrobbler, UIRenderer.instance);
|
||||||
initializeTrackInteractions(
|
initializeTrackInteractions(
|
||||||
Player.instance,
|
Player.instance,
|
||||||
MusicAPI.instance,
|
MusicAPI.instance,
|
||||||
document.querySelector('.main-content'),
|
document.querySelector('.main-content'),
|
||||||
document.getElementById('context-menu'),
|
document.getElementById('context-menu'),
|
||||||
lyricsManager,
|
lyricsManager,
|
||||||
ui,
|
UIRenderer.instance,
|
||||||
scrobbler
|
scrobbler
|
||||||
);
|
);
|
||||||
initializeUIInteractions(Player.instance, MusicAPI.instance, ui);
|
initializeUIInteractions(Player.instance, MusicAPI.instance, UIRenderer.instance);
|
||||||
initializeKeyboardShortcuts(Player.instance, audioPlayer);
|
initializeKeyboardShortcuts(Player.instance, audioPlayer);
|
||||||
|
|
||||||
// Restore UI state for the current track (like button, theme)
|
// Restore UI state for the current track (like button, theme)
|
||||||
if (Player.instance.currentTrack) {
|
if (Player.instance.currentTrack) {
|
||||||
ui.setCurrentTrack(Player.instance.currentTrack);
|
UIRenderer.instance.setCurrentTrack(Player.instance.currentTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector('.now-playing-bar').addEventListener('click', async (e) => {
|
document.querySelector('.now-playing-bar').addEventListener('click', async (e) => {
|
||||||
|
|
@ -775,11 +772,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (window.location.hash === '#fullscreen') {
|
if (window.location.hash === '#fullscreen') {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
} else {
|
} else {
|
||||||
ui.closeFullscreenCover();
|
UIRenderer.instance.closeFullscreenCover();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const nextTrack = Player.instance.getNextTrack();
|
const nextTrack = Player.instance.getNextTrack();
|
||||||
ui.showFullscreenCover(
|
UIRenderer.instance.showFullscreenCover(
|
||||||
Player.instance.currentTrack,
|
Player.instance.currentTrack,
|
||||||
nextTrack,
|
nextTrack,
|
||||||
lyricsManager,
|
lyricsManager,
|
||||||
|
|
@ -805,7 +802,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (window.location.hash === '#fullscreen') {
|
if (window.location.hash === '#fullscreen') {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
} else {
|
} else {
|
||||||
ui.closeFullscreenCover();
|
UIRenderer.instance.closeFullscreenCover();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -824,7 +821,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (window.location.hash === '#fullscreen') {
|
if (window.location.hash === '#fullscreen') {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
} else {
|
} else {
|
||||||
ui.closeFullscreenCover();
|
UIRenderer.instance.closeFullscreenCover();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'hide-ui':
|
case 'hide-ui':
|
||||||
|
|
@ -847,11 +844,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
toggleBtn.title = 'Show UI';
|
toggleBtn.title = 'Show UI';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ui && typeof ui.setupUIToggleButton === 'function') {
|
if (UIRenderer.instance && typeof UIRenderer.instance.setupUIToggleButton === 'function') {
|
||||||
if (ui.uiToggleCleanup) {
|
if (UIRenderer.instance.uiToggleCleanup) {
|
||||||
ui.uiToggleCleanup();
|
UIRenderer.instance.uiToggleCleanup();
|
||||||
}
|
}
|
||||||
ui.setupUIToggleButton(overlay);
|
UIRenderer.instance.setupUIToggleButton(overlay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -870,7 +867,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (window.location.hash === '#fullscreen') {
|
if (window.location.hash === '#fullscreen') {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
} else {
|
} else {
|
||||||
ui.closeFullscreenCover();
|
UIRenderer.instance.closeFullscreenCover();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1085,7 +1082,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
MusicAPI.instance,
|
MusicAPI.instance,
|
||||||
lyricsManager,
|
lyricsManager,
|
||||||
'track',
|
'track',
|
||||||
ui
|
UIRenderer.instance
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1096,7 +1093,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (!Player.instance.currentTrack) return;
|
if (!Player.instance.currentTrack) return;
|
||||||
|
|
||||||
// Update UI with current track info for theme
|
// Update UI with current track info for theme
|
||||||
ui.setCurrentTrack(Player.instance.currentTrack);
|
UIRenderer.instance.setCurrentTrack(Player.instance.currentTrack);
|
||||||
|
|
||||||
// Update Media Session with new track
|
// Update Media Session with new track
|
||||||
Player.instance.updateMediaSession(Player.instance.currentTrack);
|
Player.instance.updateMediaSession(Player.instance.currentTrack);
|
||||||
|
|
@ -1115,7 +1112,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const fullscreenOverlay = document.getElementById('fullscreen-cover-overlay');
|
const fullscreenOverlay = document.getElementById('fullscreen-cover-overlay');
|
||||||
if (fullscreenOverlay && getComputedStyle(fullscreenOverlay).display !== 'none') {
|
if (fullscreenOverlay && getComputedStyle(fullscreenOverlay).display !== 'none') {
|
||||||
const nextTrack = Player.instance.getNextTrack();
|
const nextTrack = Player.instance.getNextTrack();
|
||||||
ui.showFullscreenCover(
|
UIRenderer.instance.showFullscreenCover(
|
||||||
Player.instance.currentTrack,
|
Player.instance.currentTrack,
|
||||||
nextTrack,
|
nextTrack,
|
||||||
lyricsManager,
|
lyricsManager,
|
||||||
|
|
@ -1131,7 +1128,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
getComputedStyle(fullscreenOverlay).display === 'none'
|
getComputedStyle(fullscreenOverlay).display === 'none'
|
||||||
) {
|
) {
|
||||||
const nextTrack = Player.instance.getNextTrack();
|
const nextTrack = Player.instance.getNextTrack();
|
||||||
ui.showFullscreenCover(
|
UIRenderer.instance.showFullscreenCover(
|
||||||
Player.instance.currentTrack,
|
Player.instance.currentTrack,
|
||||||
nextTrack,
|
nextTrack,
|
||||||
lyricsManager,
|
lyricsManager,
|
||||||
|
|
@ -1434,7 +1431,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const folder = await db.createFolder(name, cover);
|
const folder = await db.createFolder(name, cover);
|
||||||
trackCreateFolder(folder);
|
trackCreateFolder(folder);
|
||||||
await syncManager.syncUserFolder(folder, 'create');
|
await syncManager.syncUserFolder(folder, 'create');
|
||||||
ui.renderLibraryPage();
|
UIRenderer.instance.renderLibraryPage();
|
||||||
document.getElementById('folder-modal').classList.remove('active');
|
document.getElementById('folder-modal').classList.remove('active');
|
||||||
trackCloseModal('Create Folder');
|
trackCloseModal('Create Folder');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1496,10 +1493,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
await handlePublicStatus(playlist);
|
await handlePublicStatus(playlist);
|
||||||
await db.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
await db.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||||
syncManager.syncUserPlaylist(playlist, 'update');
|
syncManager.syncUserPlaylist(playlist, 'update');
|
||||||
ui.renderLibraryPage();
|
UIRenderer.instance.renderLibraryPage();
|
||||||
// Also update current page if we are on it
|
// Also update current page if we are on it
|
||||||
if (window.location.pathname === `/userplaylist/${editingId}`) {
|
if (window.location.pathname === `/userplaylist/${editingId}`) {
|
||||||
ui.renderPlaylistPage(editingId, 'user');
|
UIRenderer.instance.renderPlaylistPage(editingId, 'user');
|
||||||
}
|
}
|
||||||
modal.classList.remove('active');
|
modal.classList.remove('active');
|
||||||
delete modal.dataset.editingId;
|
delete modal.dataset.editingId;
|
||||||
|
|
@ -2022,7 +2019,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
await db.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
await db.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||||
await syncManager.syncUserPlaylist(playlist, 'create');
|
await syncManager.syncUserPlaylist(playlist, 'create');
|
||||||
trackCreatePlaylist(playlist, importSource);
|
trackCreatePlaylist(playlist, importSource);
|
||||||
ui.renderLibraryPage();
|
UIRenderer.instance.renderLibraryPage();
|
||||||
modal.classList.remove('active');
|
modal.classList.remove('active');
|
||||||
trackCloseModal('Create Playlist');
|
trackCloseModal('Create Playlist');
|
||||||
});
|
});
|
||||||
|
|
@ -2100,7 +2097,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (confirm('Are you sure you want to delete this playlist?')) {
|
if (confirm('Are you sure you want to delete this playlist?')) {
|
||||||
db.deletePlaylist(playlistId).then(() => {
|
db.deletePlaylist(playlistId).then(() => {
|
||||||
syncManager.syncUserPlaylist({ id: playlistId }, 'delete');
|
syncManager.syncUserPlaylist({ id: playlistId }, 'delete');
|
||||||
ui.renderLibraryPage();
|
UIRenderer.instance.renderLibraryPage();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2194,7 +2191,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const updatedPlaylist = await db.removeTrackFromPlaylist(playlistId, trackId, trackType);
|
const updatedPlaylist = await db.removeTrackFromPlaylist(playlistId, trackId, trackType);
|
||||||
syncManager.syncUserPlaylist(updatedPlaylist, 'update');
|
syncManager.syncUserPlaylist(updatedPlaylist, 'update');
|
||||||
const scrollTop = document.querySelector('.main-content').scrollTop;
|
const scrollTop = document.querySelector('.main-content').scrollTop;
|
||||||
await ui.renderPlaylistPage(playlistId, 'user');
|
await UIRenderer.instance.renderPlaylistPage(playlistId, 'user');
|
||||||
document.querySelector('.main-content').scrollTop = scrollTop;
|
document.querySelector('.main-content').scrollTop = scrollTop;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -2545,7 +2542,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
const tracks = scanLocalMediaFolder(true);
|
const tracks = scanLocalMediaFolder(true);
|
||||||
trackSelectLocalFolder(tracks?.length ?? 0);
|
trackSelectLocalFolder(tracks?.length ?? 0);
|
||||||
ui.renderLibraryPage();
|
UIRenderer.instance.renderLibraryPage();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.name !== 'AbortError') {
|
if (err.name !== 'AbortError') {
|
||||||
console.error('Error selecting folder:', err);
|
console.error('Error selecting folder:', err);
|
||||||
|
|
@ -2565,7 +2562,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const searchForm = document.getElementById('search-form');
|
const searchForm = document.getElementById('search-form');
|
||||||
const searchInput = document.getElementById('search-input');
|
const searchInput = document.getElementById('search-input');
|
||||||
|
|
||||||
ui.setupSearchClearButton(searchInput);
|
UIRenderer.instance.setupSearchClearButton(searchInput);
|
||||||
|
|
||||||
const performSearch = (query) => {
|
const performSearch = (query) => {
|
||||||
if (query) {
|
if (query) {
|
||||||
|
|
@ -2618,16 +2615,16 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
searchInput.addEventListener('change', (e) => {
|
searchInput.addEventListener('change', (e) => {
|
||||||
const query = e.target.value.trim();
|
const query = e.target.value.trim();
|
||||||
if (query) {
|
if (query) {
|
||||||
ui.addToSearchHistory(query);
|
UIRenderer.instance.addToSearchHistory(query);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
searchInput.addEventListener('focus', () => {
|
searchInput.addEventListener('focus', () => {
|
||||||
ui.renderSearchHistory();
|
UIRenderer.instance.renderSearchHistory();
|
||||||
});
|
});
|
||||||
|
|
||||||
searchInput.addEventListener('click', () => {
|
searchInput.addEventListener('click', () => {
|
||||||
ui.renderSearchHistory();
|
UIRenderer.instance.renderSearchHistory();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
|
|
@ -2643,7 +2640,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (!query) return;
|
if (!query) return;
|
||||||
|
|
||||||
if (!handleExternalLink(query)) {
|
if (!handleExternalLink(query)) {
|
||||||
ui.addToSearchHistory(query);
|
UIRenderer.instance.addToSearchHistory(query);
|
||||||
performSearch(query);
|
performSearch(query);
|
||||||
const historyEl = document.getElementById('search-history');
|
const historyEl = document.getElementById('search-history');
|
||||||
if (historyEl) historyEl.style.display = 'none';
|
if (historyEl) historyEl.style.display = 'none';
|
||||||
|
|
@ -2662,14 +2659,14 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
document.querySelector('.now-playing-bar .play-pause-btn').innerHTML = SVG_PLAY(20);
|
document.querySelector('.now-playing-bar .play-pause-btn').innerHTML = SVG_PLAY(20);
|
||||||
|
|
||||||
const router = createRouter(ui);
|
const router = createRouter(UIRenderer.instance);
|
||||||
|
|
||||||
const handleRouteChange = async (event) => {
|
const handleRouteChange = async (event) => {
|
||||||
const overlay = document.getElementById('fullscreen-cover-overlay');
|
const overlay = document.getElementById('fullscreen-cover-overlay');
|
||||||
const isFullscreenOpen = overlay && getComputedStyle(overlay).display === 'flex';
|
const isFullscreenOpen = overlay && getComputedStyle(overlay).display === 'flex';
|
||||||
|
|
||||||
if (isFullscreenOpen && window.location.hash !== '#fullscreen') {
|
if (isFullscreenOpen && window.location.hash !== '#fullscreen') {
|
||||||
ui.closeFullscreenCover();
|
UIRenderer.instance.closeFullscreenCover();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event && event.state && event.state.exitTrap) {
|
if (event && event.state && event.state.exitTrap) {
|
||||||
|
|
@ -2773,14 +2770,14 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
window.addEventListener('library-changed', () => {
|
window.addEventListener('library-changed', () => {
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
if (path === '/library') {
|
if (path === '/library') {
|
||||||
ui.renderLibraryPage();
|
UIRenderer.instance.renderLibraryPage();
|
||||||
} else if (path === '/' || path === '/home') {
|
} else if (path === '/' || path === '/home') {
|
||||||
ui.renderHomePage();
|
UIRenderer.instance.renderHomePage();
|
||||||
} else if (path.startsWith('/userplaylist/')) {
|
} else if (path.startsWith('/userplaylist/')) {
|
||||||
const playlistId = path.split('/')[2];
|
const playlistId = path.split('/')[2];
|
||||||
const content = document.querySelector('.main-content');
|
const content = document.querySelector('.main-content');
|
||||||
const scroll = content ? content.scrollTop : 0;
|
const scroll = content ? content.scrollTop : 0;
|
||||||
ui.renderPlaylistPage(playlistId, 'user').then(() => {
|
UIRenderer.instance.renderPlaylistPage(playlistId, 'user').then(() => {
|
||||||
if (content) content.scrollTop = scroll;
|
if (content) content.scrollTop = scroll;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -2788,7 +2785,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
window.addEventListener('history-changed', () => {
|
window.addEventListener('history-changed', () => {
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
if (path === '/recent') {
|
if (path === '/recent') {
|
||||||
ui.renderRecentPage();
|
UIRenderer.instance.renderRecentPage();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ import {
|
||||||
SVG_RADIO,
|
SVG_RADIO,
|
||||||
} from './icons.js';
|
} from './icons.js';
|
||||||
import { Player } from './player.js';
|
import { Player } from './player.js';
|
||||||
|
import { UIRenderer } from './ui.js';
|
||||||
|
|
||||||
const ICON_SIZE = 16;
|
const ICON_SIZE = 16;
|
||||||
|
|
||||||
|
|
@ -828,7 +829,7 @@ class CommandPalette {
|
||||||
async searchMusic(query) {
|
async searchMusic(query) {
|
||||||
if (!query || query.length < 2) return;
|
if (!query || query.length < 2) return;
|
||||||
|
|
||||||
const api = window.monochromeUi?.api;
|
const api = UIRenderer.instance.api;
|
||||||
if (!api) return;
|
if (!api) return;
|
||||||
|
|
||||||
this.cancelMusicSearch();
|
this.cancelMusicSearch();
|
||||||
|
|
@ -1174,15 +1175,15 @@ class CommandPalette {
|
||||||
|
|
||||||
const overlay = document.getElementById('fullscreen-cover-overlay');
|
const overlay = document.getElementById('fullscreen-cover-overlay');
|
||||||
if (overlay && getComputedStyle(overlay).display !== 'none') {
|
if (overlay && getComputedStyle(overlay).display !== 'none') {
|
||||||
window.monochromeUi?.closeFullscreenCover();
|
UIRenderer.instance.closeFullscreenCover();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setVisualizerPreset(preset) {
|
async setVisualizerPreset(preset) {
|
||||||
const { visualizerSettings } = await import('./storage.js');
|
const { visualizerSettings } = await import('./storage.js');
|
||||||
visualizerSettings.setPreset(preset);
|
visualizerSettings.setPreset(preset);
|
||||||
if (window.monochromeUi?.visualizer) {
|
if (UIRenderer.instance.visualizer) {
|
||||||
window.monochromeUi.visualizer.setPreset(preset);
|
UIRenderer.instance.visualizer.setPreset(preset);
|
||||||
}
|
}
|
||||||
this.notify(`Visualizer preset: ${preset}`);
|
this.notify(`Visualizer preset: ${preset}`);
|
||||||
}
|
}
|
||||||
|
|
@ -1214,7 +1215,7 @@ class CommandPalette {
|
||||||
|
|
||||||
async likeAllInQueue() {
|
async likeAllInQueue() {
|
||||||
const player = Player.instance;
|
const player = Player.instance;
|
||||||
const ui = window.monochromeUi;
|
const ui = UIRenderer.instance;
|
||||||
if (!player || !ui) return;
|
if (!player || !ui) return;
|
||||||
|
|
||||||
const queue = player.getCurrentQueue();
|
const queue = player.getCurrentQueue();
|
||||||
|
|
@ -1240,7 +1241,7 @@ class CommandPalette {
|
||||||
|
|
||||||
async downloadQueue() {
|
async downloadQueue() {
|
||||||
const player = Player.instance;
|
const player = Player.instance;
|
||||||
const ui = window.monochromeUi;
|
const ui = UIRenderer.instance;
|
||||||
if (!player || !ui) return;
|
if (!player || !ui) return;
|
||||||
|
|
||||||
const queue = player.getCurrentQueue();
|
const queue = player.getCurrentQueue();
|
||||||
|
|
@ -1269,7 +1270,7 @@ class CommandPalette {
|
||||||
}
|
}
|
||||||
|
|
||||||
async clearCache() {
|
async clearCache() {
|
||||||
const api = window.monochromeUi?.api;
|
const api = UIRenderer.instance.api;
|
||||||
if (api) {
|
if (api) {
|
||||||
await api.clearCache();
|
await api.clearCache();
|
||||||
this.notify('Cache cleared');
|
this.notify('Cache cleared');
|
||||||
|
|
|
||||||
12
js/player.js
12
js/player.js
|
|
@ -23,6 +23,8 @@ import { db } from './db.js';
|
||||||
|
|
||||||
import('./dash-media-player.js');
|
import('./dash-media-player.js');
|
||||||
import { SVG_CLOCK } from './icons.js';
|
import { SVG_CLOCK } from './icons.js';
|
||||||
|
import { UIRenderer } from './ui.js';
|
||||||
|
|
||||||
export class Player {
|
export class Player {
|
||||||
static #instance = null;
|
static #instance = null;
|
||||||
|
|
||||||
|
|
@ -811,12 +813,12 @@ export class Player {
|
||||||
const played = await this.safePlay(activeElement);
|
const played = await this.safePlay(activeElement);
|
||||||
if (!played) return;
|
if (!played) return;
|
||||||
} else if (track.type === 'video') {
|
} else if (track.type === 'video') {
|
||||||
if (window.monochromeUi) {
|
if (UIRenderer.instance) {
|
||||||
const isInFullscreen =
|
const isInFullscreen =
|
||||||
document.getElementById('fullscreen-cover-overlay')?.style.display === 'flex';
|
document.getElementById('fullscreen-cover-overlay')?.style.display === 'flex';
|
||||||
if (!isInFullscreen) {
|
if (!isInFullscreen) {
|
||||||
const lyricsManager = window.monochromeUi.lyricsManager;
|
const lyricsManager = UIRenderer.instance.lyricsManager;
|
||||||
window.monochromeUi.showFullscreenCover(
|
UIRenderer.instance.showFullscreenCover(
|
||||||
track,
|
track,
|
||||||
this.getNextTrack(),
|
this.getNextTrack(),
|
||||||
lyricsManager,
|
lyricsManager,
|
||||||
|
|
@ -1392,8 +1394,8 @@ export class Player {
|
||||||
this.originalQueueBeforeShuffle = [];
|
this.originalQueueBeforeShuffle = [];
|
||||||
this.currentQueueIndex = -1;
|
this.currentQueueIndex = -1;
|
||||||
this.saveQueueState();
|
this.saveQueueState();
|
||||||
if (window.monochromeUi) {
|
if (UIRenderer.instance) {
|
||||||
window.monochromeUi.setCurrentTrack(null);
|
UIRenderer.instance.setCurrentTrack(null);
|
||||||
}
|
}
|
||||||
if (window.renderQueueFunction) {
|
if (window.renderQueueFunction) {
|
||||||
window.renderQueueFunction();
|
window.renderQueueFunction();
|
||||||
|
|
|
||||||
17
js/ui.js
17
js/ui.js
|
|
@ -117,6 +117,16 @@ function sortTracks(tracks, sortType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UIRenderer {
|
export class UIRenderer {
|
||||||
|
static #instance = null;
|
||||||
|
|
||||||
|
static get instance() {
|
||||||
|
if (!UIRenderer.#instance) {
|
||||||
|
throw new Error('UIRenderer is not initialized. Call UIRenderer.initialize(api, player) first.');
|
||||||
|
}
|
||||||
|
return UIRenderer.#instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @private */
|
||||||
constructor(api, player) {
|
constructor(api, player) {
|
||||||
this.api = api;
|
this.api = api;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
|
@ -144,6 +154,13 @@ export class UIRenderer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async initialize(api, player) {
|
||||||
|
if (UIRenderer.#instance) {
|
||||||
|
throw new Error('UIRenderer is already initialized');
|
||||||
|
}
|
||||||
|
return (UIRenderer.#instance = new UIRenderer(api, player));
|
||||||
|
}
|
||||||
|
|
||||||
// Helper for Heart Icon
|
// Helper for Heart Icon
|
||||||
createHeartIcon(filled = false) {
|
createHeartIcon(filled = false) {
|
||||||
if (filled) {
|
if (filled) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue