From 4a561a0c78618fff17b532a0e4584f1b6e5a9a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Dr=C3=B3=C5=BCd=C5=BC?= Date: Wed, 15 Jul 2026 14:57:45 +0200 Subject: [PATCH] Fixed bug with the audio track skipping on Windows (#143) Co-authored-by: /home/neo <158327205+neoapps-dev@users.noreply.github.com> --- src/components/views/SettingsView.tsx | 11 +++++++++-- src/hooks/useAudioController.ts | 25 ++++++++++--------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/components/views/SettingsView.tsx b/src/components/views/SettingsView.tsx index 92de37c..a220e92 100644 --- a/src/components/views/SettingsView.tsx +++ b/src/components/views/SettingsView.tsx @@ -46,7 +46,7 @@ const SettingsView = memo(function SettingsView() { } = useConfig(); const { currentTrack, - setCurrentTrack, + skipTrack, tracks, playPressSound, playBackSound, @@ -73,6 +73,8 @@ const SettingsView = memo(function SettingsView() { const [showModal, setShowModal] = useState< "args" | "prefix" | "envVars" | null >(null); + //jandrozdz: Added so track doesn't skip forever after pressing once + const isSkippingRef = useRef(false); useEffect(() => { TauriService.getAvailableRunners().then(setRunners); }, [isRunnerDownloading]); @@ -136,8 +138,13 @@ const SettingsView = memo(function SettingsView() { }; const handleTrackToggle = () => { + if (isSkippingRef.current) return; playPressSound(); - setCurrentTrack((currentTrack + 1) % tracks.length); + isSkippingRef.current = true; + skipTrack(); //jandrozdz: Use skipTrack here + setTimeout(() => { + isSkippingRef.current = false; + }, 100); }; const handleResetSetup = () => { diff --git a/src/hooks/useAudioController.ts b/src/hooks/useAudioController.ts index f095d04..687ae6f 100644 --- a/src/hooks/useAudioController.ts +++ b/src/hooks/useAudioController.ts @@ -45,7 +45,7 @@ export function useAudioController({ } return audioContextRef.current; }, []); - + const isManualSkipRef = useRef(false); const ensureAudioContextReady = useCallback(async () => { const ctx = getAudioContext(); if (ctx.state === "suspended") { @@ -116,21 +116,16 @@ export function useAudioController({ async (buffer: AudioBuffer, startTime: number = 0) => { const ctx = await ensureAudioContextReady(); stopMusic(); - const source = ctx.createBufferSource(); const gainNode = ctx.createGain(); - source.buffer = buffer; gainNode.gain.value = 0; source.connect(gainNode); gainNode.connect(ctx.destination); - const offset = startTime % buffer.duration; source.start(0, offset); - musicSourceRef.current = source; musicGainRef.current = gainNode; - const steps = 5; const stepDuration = 100; let currentStep = 0; @@ -148,11 +143,11 @@ export function useAudioController({ } } }, stepDuration); - source.onended = () => { - if (musicSourceRef.current) { + if (musicSourceRef.current && !isManualSkipRef.current) { setCurrentTrack((prev) => (prev + 1) % TRACKS.length); } + isManualSkipRef.current = false; }; }, [stopMusic, ensureAudioContextReady], @@ -197,24 +192,19 @@ export function useAudioController({ async (buffer: AudioBuffer, targetVolume: number, duration: number = 500) => { const ctx = await ensureAudioContextReady(); stopMusic(); - const source = ctx.createBufferSource(); const gainNode = ctx.createGain(); - source.buffer = buffer; gainNode.gain.value = 0; source.connect(gainNode); gainNode.connect(ctx.destination); source.start(); - musicSourceRef.current = source; musicGainRef.current = gainNode; targetVolumeRef.current = targetVolume; - const steps = 5; const stepDuration = duration / steps; let currentStep = 0; - fadeIntervalRef.current = window.setInterval(() => { currentStep++; const progress = currentStep / steps; @@ -231,9 +221,10 @@ export function useAudioController({ }, stepDuration); source.onended = () => { - if (musicSourceRef.current) { + if (musicSourceRef.current && !isManualSkipRef.current) { setCurrentTrack((prev) => (prev + 1) % TRACKS.length); } + isManualSkipRef.current = false; }; }, [stopMusic, ensureAudioContextReady], @@ -247,7 +238,10 @@ export function useAudioController({ } while (newIndex === splashIndex && SPLASHES.length > 1); setSplashIndex(newIndex); }, [playSplashSound, splashIndex]); - + const skipTrack = useCallback(() => { + isManualSkipRef.current = true; + setCurrentTrack((prev) => (prev + 1) % TRACKS.length); + }, []); const [isMusicStarted, setIsMusicStarted] = useState(false); const startMusic = useCallback(() => { @@ -342,6 +336,7 @@ export function useAudioController({ return { currentTrack, setCurrentTrack, + skipTrack, splashIndex, setSplashIndex, cycleSplash,