Implement volume control with mute functionality; update PlayerState to manage muted state

This commit is contained in:
2026-09-23 21:28:17 +02:00
parent 7b72db8a24
commit f8d431a0d7
2 changed files with 32 additions and 2 deletions
@@ -6,7 +6,9 @@
import { player } from '$lib/player/player.svelte'; import { player } from '$lib/player/player.svelte';
import { queuePanel } from '$lib/player/queuePanel.svelte'; import { queuePanel } from '$lib/player/queuePanel.svelte';
import { fmtTime } from '$lib/utils/format'; import { fmtTime } from '$lib/utils/format';
import Volume1 from '@lucide/svelte/icons/volume-1';
import Volume2 from '@lucide/svelte/icons/volume-2'; import Volume2 from '@lucide/svelte/icons/volume-2';
import VolumeX from '@lucide/svelte/icons/volume-x';
import ListMusic from '@lucide/svelte/icons/list-music'; import ListMusic from '@lucide/svelte/icons/list-music';
function seek(value: number) { function seek(value: number) {
@@ -48,9 +50,22 @@
</div> </div>
</div> </div>
<div class="hidden w-(--mf-player-side-w) shrink-0 items-center justify-end gap-3.5 sm:flex"> <div class="hidden w-(--mf-player-side-w) shrink-0 items-center justify-end gap-3.5 sm:flex">
<Volume2 class="size-icon-sm shrink-0 text-fg-2" strokeWidth={1.8} /> <IconButton
label={player.muted ? 'Activar sonido' : 'Silenciar'}
tone="plain"
size="xs"
onclick={() => player.toggleMute()}
>
{#if player.muted || player.volume === 0}
<VolumeX class="size-icon-sm" strokeWidth={1.8} />
{:else if player.volume < 50}
<Volume1 class="size-icon-sm" strokeWidth={1.8} />
{:else}
<Volume2 class="size-icon-sm" strokeWidth={1.8} />
{/if}
</IconButton>
<Slider <Slider
value={player.volume} value={player.muted ? 0 : player.volume}
max={100} max={100}
label="Volumen" label="Volumen"
oninput={(value) => player.setVolume(value)} oninput={(value) => player.setVolume(value)}
@@ -119,6 +119,7 @@ class PlayerState {
playing = $state(false); playing = $state(false);
progress = $state(0); progress = $state(0);
volume = $state(browser ? Number(localStorage.getItem('player.volume') ?? 100) : 100); volume = $state(browser ? Number(localStorage.getItem('player.volume') ?? 100) : 100);
muted = $state(browser ? localStorage.getItem('player.muted') === 'true' : false);
loading = $state(false); loading = $state(false);
recentlyPlayed = $state<PlayerTrack[]>([]); recentlyPlayed = $state<PlayerTrack[]>([]);
playlists = $state<Playlist[]>([]); playlists = $state<Playlist[]>([]);
@@ -148,6 +149,7 @@ class PlayerState {
const audio = new Audio(); const audio = new Audio();
audio.preload = 'auto'; audio.preload = 'auto';
audio.volume = this.volume / 100; audio.volume = this.volume / 100;
audio.muted = this.muted;
audio.addEventListener('durationchange', () => this.#syncDuration(audio.duration)); audio.addEventListener('durationchange', () => this.#syncDuration(audio.duration));
audio.addEventListener('loadedmetadata', () => this.#syncDuration(audio.duration)); audio.addEventListener('loadedmetadata', () => this.#syncDuration(audio.duration));
audio.addEventListener('play', () => { audio.addEventListener('play', () => {
@@ -401,6 +403,18 @@ class PlayerState {
else audio.pause(); else audio.pause();
} }
toggleMute() {
this.#applyMuted(!this.muted);
if (!this.muted && this.volume === 0) this.setVolume(50);
}
#applyMuted(value: boolean) {
this.muted = value;
const audio = this.#audioEl();
if (audio) audio.muted = value;
if (browser) localStorage.setItem('player.muted', String(value));
}
next() { next() {
if (this.tracks.length === 0) return; if (this.tracks.length === 0) return;
const idx = this.#index(); const idx = this.#index();
@@ -459,6 +473,7 @@ class PlayerState {
setVolume(value: number) { setVolume(value: number) {
this.volume = Math.min(100, Math.max(0, Math.round(value))); this.volume = Math.min(100, Math.max(0, Math.round(value)));
if (this.muted && this.volume > 0) this.#applyMuted(false);
const audio = this.#audioEl(); const audio = this.#audioEl();
if (audio) { if (audio) {
audio.volume = this.volume / 100; audio.volume = this.volume / 100;