Commit f82f294f authored by Grant's avatar Grant
Browse files

Extract audio related ctx to AudioContext

parent 82585fef
Loading
Loading
Loading
Loading
Loading
+10 −7
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import { ChatInfoDialog } from "./Chat/ChatInfoDialog";
import { LoginModal } from "./Login/LoginModal";
import { Chat, ChatContext } from "./Chat/utils";
import { EventInfoModal } from "./EventInfo/EventInfo";
import AudioContext from "@/contexts/AudioContext";

console.log("Client init with version " + __COMMIT_HASH__);

@@ -76,6 +77,7 @@ const App = () => {
        }}
      >
        <AppContext>
          <AudioContext>
            <DialogContext>
              <ModeratorContext>
                <TemplateContext>
@@ -83,6 +85,7 @@ const App = () => {
                </TemplateContext>
              </ModeratorContext>
            </DialogContext>
          </AudioContext>
        </AppContext>
      </SWRConfig>
    </ChatContext>
+69 −102
Original line number Diff line number Diff line
import { useAppContext } from "../../contexts/AppContext";
import useSound from "use-sound";
import Coffee1 from "../../sounds/Coffee1.mp3";
import Coffee2 from "../../sounds/Coffee2.mp3";
@@ -9,28 +8,16 @@ import African4 from "../../sounds/African4.mp3";
import WoodBlock1 from "../../sounds/Wood Block1.mp3";
import WoodBlock2 from "../../sounds/Wood Block2.mp3";
import WoodBlock3 from "../../sounds/Wood Block3.mp3";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import network from "../../lib/network";
import { useRef } from "react";
import { Switch } from "../core/Switch";
import { useAudio } from "@/contexts/AudioContext";

const _ = (v: boolean) => (v ? "enable" : "disable");

export const AudioSettings = () => {
  const {
    placeSound,
    setPlaceSound,
    globalPlaceSound,
    setGlobalPlaceSound,
    disconnectSound,
    setDisconnectSound,
    reconnectSound,
    setReconnectSound,
    pixelAvailableSound,
    setPixelAvailableSound,
    pixelUndoSound,
    setPixelUndoSound,
    uiClickSound,
    setUiClickSound,
  } = useAppContext();
  const { state, dispatch } = useAudio();

  const coffee2Ref = useRef<(() => void) | null>(null);

@@ -56,127 +43,107 @@ export const AudioSettings = () => {

  const [pixelsAvailable, setPixelsAvailable] = useState(0);

  const pixelsAvailableRef = useRef(pixelsAvailable);
  const pixelAvailableSoundRef = useRef(pixelAvailableSound);

  const WoodSounds = [WoodBlock1Sound, WoodBlock2Sound, WoodBlock3Sound];

  useEffect(() => {
    coffee2Ref.current = Coffee2Sound;
  }, [Coffee2Sound]);

  useEffect(() => {
    pixelsAvailableRef.current = pixelsAvailable;
  }, [pixelsAvailable]);

  useEffect(() => {
    pixelAvailableSoundRef.current = pixelAvailableSound;
  }, [pixelAvailableSound]);

  useEffect(() => {
    function handleAvailable(number: number, undo: boolean) {
      if (
        number > pixelsAvailableRef.current &&
        pixelAvailableSoundRef.current &&
        coffee2Ref.current &&
        !undo
      ) {
        coffee2Ref.current();
  const handleAvailable = useCallback(
    (available: number, isUndo: boolean) => {
      if (available > pixelsAvailable && state.pixelAvailable && !isUndo) {
        Coffee2Sound();
      }

      setPixelsAvailable(number);
    }
      setPixelsAvailable(available);
    },
    [pixelsAvailable, state.pixelAvailable],
  );

  useEffect(() => {
    network.socket.on("availablePixels", handleAvailable);

    return () => {
      network.socket.off("availablePixels", handleAvailable);
    };
  }, []);
  }, [handleAvailable]);

  useEffect(() => {
    if (!placeSound) {
      return;
    }
  const handlePlace = useCallback(() => {
    if (!state.place) return;

    function handlePlace() {
    Coffee1Sound();
    }
  }, [state.place]);

  useEffect(() => {
    network.on("placeSuccessful", handlePlace);

    return () => {
      network.off("placeSuccessful", handlePlace);
    };
  }, [placeSound]);
  }, [handlePlace]);

  useEffect(() => {
    if (!pixelUndoSound) {
      return;
    }
  const handleUndo = useCallback(
    ({ available }: { available: boolean }) => {
      if (!state.pixelUndo) return;

    function handleUndo(
      data: { available: false } | { available: true; expireAt: number },
    ) {
      if (!data.available) {
      // undo state becoming unavailable means it was used
      if (!available) {
        African1Sound();
      }
    }
    },
    [state.pixelUndo],
  );

  useEffect(() => {
    network.socket.on("undo", handleUndo);

    return () => {
      network.socket.off("undo", handleUndo);
    };
  }, [pixelUndoSound]);
  }, [handleUndo]);

  useEffect(() => {
    if (!globalPlaceSound) {
      return;
    }
  const handleGlobalPlace = useCallback(() => {
    if (!state.globalPlace) return;

    function handlePlace() {
      WoodSounds[Math.floor(Math.random() * WoodSounds.length)]();
    }
    const variant = Math.floor(Math.random() * WoodSounds.length);
    WoodSounds[variant]();
  }, [state.globalPlace]);

    network.socket.on("pixel", handlePlace);
  useEffect(() => {
    network.socket.on("pixel", handleGlobalPlace);

    return () => {
      network.socket.off("pixel", handlePlace);
      network.socket.off("pixel", handleGlobalPlace);
    };
  }, [globalPlaceSound]);
  }, [handleGlobalPlace]);

  useEffect(() => {
    if (!disconnectSound) {
      return;
    }
  const handleDisconnect = useCallback(() => {
    if (!state.disconnected) return;

    function handleDisconnect() {
    African2Sound();
    }
  }, [state.disconnected]);

  useEffect(() => {
    network.socket.on("disconnect", handleDisconnect);

    return () => {
      network.socket.off("disconnect", handleDisconnect);
    };
  }, [disconnectSound]);
  }, [handleDisconnect]);

  useEffect(() => {
    if (!reconnectSound) {
      return;
    }
  const handleReconnect = useCallback(() => {
    if (!state.reconnected) return;

    function handleConnect() {
    African4Sound();
    }
  }, [state.reconnected]);

    network.socket.on("connect", handleConnect);
  useEffect(() => {
    network.socket.on("connect", handleReconnect);

    return () => {
      network.socket.off("connect", handleConnect);
      network.socket.off("connect", handleReconnect);
    };
  }, [reconnectSound]);
  }, [handleReconnect]);

  return (
    <div className="flex flex-col gap-4 p-2">
@@ -187,9 +154,9 @@ export const AudioSettings = () => {
      <section className="flex flex-col gap-2">
        <Switch
          silent
          isSelected={pixelAvailableSound}
          isSelected={state.pixelAvailable}
          onValueChange={(v) => {
            setPixelAvailableSound(v);
            dispatch([_(v), "pixelAvailable"]);
            if (v) {
              Coffee2Sound();
            }
@@ -199,9 +166,9 @@ export const AudioSettings = () => {
        </Switch>
        <Switch
          silent
          isSelected={placeSound}
          isSelected={state.place}
          onValueChange={(v) => {
            setPlaceSound(v);
            dispatch([_(v), "place"]);
            if (v) {
              Coffee1Sound();
            }
@@ -211,9 +178,9 @@ export const AudioSettings = () => {
        </Switch>
        <Switch
          silent
          isSelected={pixelUndoSound}
          isSelected={state.pixelUndo}
          onValueChange={(v) => {
            setPixelUndoSound(v);
            dispatch([_(v), "pixelUndo"]);
            if (v) {
              African1Sound();
            }
@@ -223,9 +190,9 @@ export const AudioSettings = () => {
        </Switch>
        <Switch
          silent
          isSelected={uiClickSound}
          isSelected={state.uiClick}
          onValueChange={(v) => {
            setUiClickSound(v);
            dispatch([_(v), "uiClick"]);
            if (v) {
              African3Sound();
            }
@@ -235,9 +202,9 @@ export const AudioSettings = () => {
        </Switch>
        <Switch
          silent
          isSelected={disconnectSound}
          isSelected={state.disconnected}
          onValueChange={(v) => {
            setDisconnectSound(v);
            dispatch([_(v), "disconnected"]);
            if (v) {
              African2Sound();
            }
@@ -247,9 +214,9 @@ export const AudioSettings = () => {
        </Switch>
        <Switch
          silent
          isSelected={reconnectSound}
          isSelected={state.reconnected}
          onValueChange={(v) => {
            setReconnectSound(v);
            dispatch([_(v), "reconnected"]);
            if (v) {
              African4Sound();
            }
@@ -259,9 +226,9 @@ export const AudioSettings = () => {
        </Switch>
        <Switch
          silent
          isSelected={globalPlaceSound}
          isSelected={state.globalPlace}
          onValueChange={(v) => {
            setGlobalPlaceSound(v);
            dispatch([_(v), "globalPlace"]);
            if (v) {
              WoodSounds[Math.floor(Math.random() * WoodSounds.length)]();
            }
+0 −38
Original line number Diff line number Diff line
@@ -58,21 +58,6 @@ interface IAppContext {
  loadChat: boolean;
  setLoadChat: (v: boolean) => void;

  placeSound: boolean;
  setPlaceSound: (v: boolean) => void;
  globalPlaceSound: boolean;
  setGlobalPlaceSound: (v: boolean) => void;
  disconnectSound: boolean;
  setDisconnectSound: (v: boolean) => void;
  reconnectSound: boolean;
  setReconnectSound: (v: boolean) => void;
  pixelAvailableSound: boolean;
  setPixelAvailableSound: (v: boolean) => void;
  pixelUndoSound: boolean;
  setPixelUndoSound: (v: boolean) => void;
  uiClickSound: boolean;
  setUiClickSound: (v: boolean) => void;

  infoSidebar: boolean;
  setInfoSidebar: (v: boolean) => void;
  settingsSidebar: boolean;
@@ -153,15 +138,6 @@ export const AppContext = ({ children }: PropsWithChildren) => {
  const [pixels, setPixels] = useState({ available: 0 });
  const [undo, setUndo] = useState<{ available: true; expireAt: number }>();

  // --- audio ---
  const [placeSound, setPlaceSound] = useState(false);
  const [globalPlaceSound, setGlobalPlaceSound] = useState(false);
  const [disconnectSound, setDisconnectSound] = useState(false);
  const [reconnectSound, setReconnectSound] = useState(false);
  const [pixelAvailableSound, setPixelAvailableSound] = useState(false);
  const [pixelUndoSound, setPixelUndoSound] = useState(false);
  const [uiClickSound, setUiClickSound] = useState(false);

  // overlays visible
  const [infoSidebar, setInfoSidebar] = useState(false);
  const [settingsSidebar, setSettingsSidebar] = useState(false);
@@ -365,20 +341,6 @@ export const AppContext = ({ children }: PropsWithChildren) => {
        setProfile,
        infoSidebar,
        setInfoSidebar,
        placeSound,
        setPlaceSound,
        globalPlaceSound,
        setGlobalPlaceSound,
        disconnectSound,
        setDisconnectSound,
        reconnectSound,
        setReconnectSound,
        pixelAvailableSound,
        setPixelAvailableSound,
        pixelUndoSound,
        setPixelUndoSound,
        uiClickSound,
        setUiClickSound,
      }}
    >
      {!config && (
+50 −0
Original line number Diff line number Diff line
import React, { createContext, useContext, useReducer } from "react";

interface IAudioState {
  place: boolean;
  globalPlace: boolean;
  disconnected: boolean;
  reconnected: boolean;
  pixelAvailable: boolean;
  pixelUndo: boolean;
  uiClick: boolean;
}

const Defaults: IAudioState = {
  place: false,
  globalPlace: false,
  disconnected: false,
  reconnected: false,
  pixelAvailable: false,
  pixelUndo: false,
  uiClick: false,
};

type AudioActions =
  | ["enable", keyof IAudioState]
  | ["disable", keyof IAudioState];

const context = createContext<{
  state: IAudioState;
  dispatch: React.ActionDispatch<[AudioActions]>;
}>({} as any);

export const useAudio = () => useContext(context);

const AudioContext = ({ children }: React.PropsWithChildren) => {
  const [state, dispatch] = useReducer<IAudioState, [AudioActions]>(
    (state, [enable, key]) => {
      return {
        ...state,
        [key]: enable === "enable",
      };
    },
    Defaults,
  );

  return (
    <context.Provider value={{ state, dispatch }}>{children}</context.Provider>
  );
};

export default React.memo(AudioContext);