All files / lib/providers/Bgm index.tsx

6.25% Statements 3/48
0% Branches 0/22
7.69% Functions 1/13
4.65% Lines 2/43

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106                  1x                       15x                                                                                                                                                                        
import React, { createContext, useCallback } from 'react';
import { useGameStateContext } from '@lib/providers/GameState';
import { Game } from '@uniquegood/realworld-web-interface/lib/models/game';
 
interface BgmProviderProps {
  fileList: Game['fileList'];
  children: React.ReactNode;
}
 
const BgmContext = createContext<{
  isExistBgm: boolean;
  isPlayingBgm: boolean;
  setIsPlayingBgm: (value: boolean) => unknown;
}>({
  isExistBgm: false,
  isPlayingBgm: true,
  setIsPlayingBgm: () => {
    // pass
  }
});
 
export const useBgmContext = () => React.useContext(BgmContext);
 
export function BgmProvider({ fileList, children }: BgmProviderProps) {
  const { gameStateForRender } = useGameStateContext();
  const [isPlayingBgm, setIsPlayingBgm] = React.useState(false);
  const audioRef = React.useRef<HTMLAudioElement | null>(null);
 
  React.useEffect(() => {
    if (!audioRef.current) return;
 
    if (isPlayingBgm) {
      audioRef.current.play();
    } else if (!isPlayingBgm) {
      audioRef.current.pause();
    }
  }, [isPlayingBgm]);
 
  const bgmAudioId = React.useMemo(
    () => gameStateForRender.gameMeta.currentBgmAudioId,
    [gameStateForRender.gameMeta.currentBgmAudioId]
  );
 
  React.useEffect(() => {
    if (!bgmAudioId) return;
 
    const src = fileList.find((file) => file.id === bgmAudioId)?.src;
 
    if (src) {
      if (!audioRef.current) {
        const audio = new Audio();
        audio.src = src;
        audio.loop = true;
        audioRef.current = audio;
 
        audio
          .play()
          .then(() => {
            setIsPlayingBgm(true);
          })
          .catch((e) => {
            if (e.name === 'NotAllowedError') {
              setIsPlayingBgm(false);
              alert('우측 상단의 버튼을 눌러 BGM(배경음악)을 끄거나 켤 수 있습니다.');
            }
          });
      } else {
        audioRef.current.src = src;
        if (isPlayingBgm) {
          audioRef.current.play();
        }
      }
    }
  }, [bgmAudioId]);
 
  const handleVisibilityChange = useCallback(() => {
    if (!audioRef.current) return;
 
    if (document.hidden) {
      setIsPlayingBgm(false);
    } else if (!document.hidden) {
      setIsPlayingBgm(true);
    }
  }, [isPlayingBgm, document.hidden]);
 
  // 다른 탭 이동 또는 비활성화 시 배경 음악 중단
  React.useEffect(() => {
    window.addEventListener('visibilitychange', handleVisibilityChange);
 
    return () => {
      window.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, []);
 
  const bgmContextValue = React.useMemo(
    () => ({
      isExistBgm: Boolean(bgmAudioId),
      isPlayingBgm,
      setIsPlayingBgm
    }),
    [isPlayingBgm, setIsPlayingBgm]
  );
 
  return <BgmContext.Provider value={bgmContextValue}>{children}</BgmContext.Provider>;
}