Repository: 4ian/GDevelop
File: newIDE/app/src/UI/SoundPlayer/CompactSoundPlayer.js (JavaScript)

Code before:
      () => {
        if (!mobileAudioRef.current) return;
        if (onSoundLoaded) onSoundLoaded();
      },
      [onSoundLoaded]
    );

    React.useImperativeHandle(ref, () => ({
      playPause: onPlayPause,
    }));

    React.useEffect(
      () => {
        if (!mobileAudioRef.current) return;
        if (isPlaying) {
          mobileAudioRef.current.play();
        } else {
          mobileAudioRef.current.pause();
        }
      },
      [isPlaying]
    );

    React.useEffect(
      () => {
        if (soundSrc) {
          if (mobileAudioRef.current) {
            mobileAudioRef.current.pause();
          }
          const audio = new Audio(soundSrc);
          audio.loop = true;
          audio.addEventListener('loadstart', onLoad);
          audio.addEventListener('loadedmetadata', onAudioReady);
          audio.addEventListener('error', () => {
            if (onSoundError) onSoundError();
          });
          mobileAudioRef.current = audio;
        }
        onLoad();
      },
      [soundSrc, onLoad, onAudioReady, onSoundError]
    );

    if (!soundSrc) {
      return null;
    }

    return (
      <IconButton size="small" onClick={() => onPlayPause()}>
        {isPlaying ? <Pause /> : <Play />}
      </IconButton>

Review comment (suggestion):
This will force the browser to load the audio source anytime the button is displayed. For a large game/long session, this means the browser may have to load dozens of audio files, wasting computing and network. 

Can you adapt this component so that it only load the audio file when play is pressed? 
- Default state: no audio loaded. Play button is shown
- You press play: audio is loaded. While it's the case, a loading spinner is shown (`CircularProgress`). Same size as the button so no layout shift.
- If the component is dismounted, stop the audio. (use a `useIsMounted` hook).
- When the audio plays, the button is now showing pause. If you pause it, and press play again, it resumes.

So there is a bit more logic here to handle all of this, but it's doable.

Code after:
    audioRef.current = null;
    abortControllerRef.current = null;
    setIsPlaying(false);
    setIsLoading(false);
    setIsAudioLoaded(false);
  }, []);

  const initializeAudio = React.useCallback(
    () => {
      if (!soundSrc || audioRef.current) return;

      setIsLoading(true);
      const audio = new Audio(soundSrc);
      audio.loop = false;

      const abortController = new AbortController();
      abortControllerRef.current = abortController;

      const handleLoadedMetadata = () => {
        if (!isMountedRef.current) return;
        setIsLoading(false);
        setIsAudioLoaded(true);
        if (onSoundLoaded) onSoundLoaded();
      };

      const handleError = () => {
        if (!isMountedRef.current) return;
        setIsLoading(false);
        setIsPlaying(false);
        setIsAudioLoaded(false);
        if (onSoundError) onSoundError();
      };

      const handleEnded = () => {
        if (!isMountedRef.current) return;
        setIsPlaying(false);
      };

      audio.addEventListener('loadedmetadata', handleLoadedMetadata, {
        signal: abortController.signal,
      });
      audio.addEventListener('error', handleError, {
        signal: abortController.signal,
      });
      audio.addEventListener('ended', handleEnded, {
        signal: abortController.signal,
      });

      audioRef.current = audio;
      audio.play().catch(() => {
        if (isMountedRef.current) {