Fix success animation blocking new note

This commit is contained in:
2025-12-28 14:17:42 +01:00
parent febb55cf5a
commit c76a172c1c

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback, useMemo } from 'react'; import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { SheetMusic } from './components/SheetMusic'; import { SheetMusic } from './components/SheetMusic';
import { Controls, type AppSettings } from './components/Controls'; import { Controls, type AppSettings } from './components/Controls';
import { SettingsModal } from './components/SettingsModal'; import { SettingsModal } from './components/SettingsModal';
@@ -68,6 +68,7 @@ function App() {
const [virtualNote, setVirtualNote] = useState<number | null>(null); const [virtualNote, setVirtualNote] = useState<number | null>(null);
const [isSettingsOpen, setIsSettingsOpen] = useState(false); const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const [isOpenSourceModalOpen, setIsOpenSourceModalOpen] = useState(false); const [isOpenSourceModalOpen, setIsOpenSourceModalOpen] = useState(false);
const feedbackTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const currentTuning = TUNINGS[settings.tuningId]; const currentTuning = TUNINGS[settings.tuningId];
const currentInstrumentDef = INSTRUMENT_DEFINITIONS[settings.instrument]; const currentInstrumentDef = INSTRUMENT_DEFINITIONS[settings.instrument];
@@ -223,6 +224,10 @@ function App() {
// Common success handler // Common success handler
const handleMatchSuccess = useCallback(() => { const handleMatchSuccess = useCallback(() => {
// Success! // Success!
if (feedbackTimeoutRef.current) {
clearTimeout(feedbackTimeoutRef.current);
}
const noteDetails = getNoteDetails(targetMidi); const noteDetails = getNoteDetails(targetMidi);
setFeedbackMessage(`Good! ${noteDetails.name}`); setFeedbackMessage(`Good! ${noteDetails.name}`);
setRevealed(true); setRevealed(true);
@@ -241,7 +246,7 @@ function App() {
setRevealed(false); setRevealed(false);
} else { } else {
// Allow visual feedback to persist for a moment before clearing text // Allow visual feedback to persist for a moment before clearing text
setTimeout(() => { feedbackTimeoutRef.current = setTimeout(() => {
setFeedbackMessage(""); setFeedbackMessage("");
}, 1500); }, 1500);
} }
@@ -253,7 +258,7 @@ function App() {
restartMetronome(); // Reset the countdown restartMetronome(); // Reset the countdown
// Immediate transition here too? // Immediate transition here too?
generateNewNote(true); generateNewNote(true);
setTimeout(() => { feedbackTimeoutRef.current = setTimeout(() => {
setFeedbackMessage(""); setFeedbackMessage("");
}, 1500); }, 1500);
@@ -263,7 +268,7 @@ function App() {
// Logic handled by tick // Logic handled by tick
} }
} }
}, [settings.rhythm, restartMetronome, generateNewNote]); }, [targetMidi, settings.rhythm, settings.disableAnimation, restartMetronome, generateNewNote]);
// Virtual Instrument Handler (Guitar or Piano) // Virtual Instrument Handler (Guitar or Piano)
const handleVirtualInstrumentPlay = useCallback((playedMidi: number) => { const handleVirtualInstrumentPlay = useCallback((playedMidi: number) => {
@@ -279,9 +284,7 @@ function App() {
if (playedMidi === targetMidi) { if (playedMidi === targetMidi) {
// Instant match // Instant match
if (!feedbackMessage.startsWith("Good!")) { handleMatchSuccess();
handleMatchSuccess();
}
} }
}, [playNote, targetMidi, feedbackMessage, handleMatchSuccess, settings]); }, [playNote, targetMidi, feedbackMessage, handleMatchSuccess, settings]);
@@ -293,8 +296,7 @@ function App() {
} }
if (pitchData.midi === targetMidi) { if (pitchData.midi === targetMidi) {
// Prevent re-triggering success if we're already in a success state
if (feedbackMessage.startsWith("Good!")) return;
if (matchStartTime === null) { if (matchStartTime === null) {
setMatchStartTime(Date.now()); setMatchStartTime(Date.now());
@@ -445,7 +447,7 @@ function App() {
{!settings.zenMode && ( {!settings.zenMode && (
<div className="feedback-area"> <div className="feedback-area">
{feedbackMessage ? ( {feedbackMessage ? (
<div className="success-message animate-pop"> <div key={feedbackMessage} className="success-message animate-pop">
{feedbackMessage.startsWith("Good! ") ? ( {feedbackMessage.startsWith("Good! ") ? (
<> <>
<div className="success-prefix">Good!</div> <div className="success-prefix">Good!</div>