mirror of
https://github.com/9x/sheetmusictrainer.git
synced 2026-09-02 09:34:33 +02:00
Fix success animation blocking new note
This commit is contained in:
22
src/App.tsx
22
src/App.tsx
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user