Loading packages/client/src/components/App.tsx +10 −7 Original line number Diff line number Diff line Loading @@ -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__); Loading Loading @@ -76,6 +77,7 @@ const App = () => { }} > <AppContext> <AudioContext> <DialogContext> <ModeratorContext> <TemplateContext> Loading @@ -83,6 +85,7 @@ const App = () => { </TemplateContext> </ModeratorContext> </DialogContext> </AudioContext> </AppContext> </SWRConfig> </ChatContext> Loading packages/client/src/components/Settings/AudioSettings.tsx +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"; Loading @@ -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); Loading @@ -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"> Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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)](); } Loading packages/client/src/contexts/AppContext.tsx +0 −38 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 && ( Loading packages/client/src/contexts/AudioContext.tsx 0 → 100644 +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); Loading
packages/client/src/components/App.tsx +10 −7 Original line number Diff line number Diff line Loading @@ -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__); Loading Loading @@ -76,6 +77,7 @@ const App = () => { }} > <AppContext> <AudioContext> <DialogContext> <ModeratorContext> <TemplateContext> Loading @@ -83,6 +85,7 @@ const App = () => { </TemplateContext> </ModeratorContext> </DialogContext> </AudioContext> </AppContext> </SWRConfig> </ChatContext> Loading
packages/client/src/components/Settings/AudioSettings.tsx +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"; Loading @@ -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); Loading @@ -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"> Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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(); } Loading @@ -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)](); } Loading
packages/client/src/contexts/AppContext.tsx +0 −38 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 && ( Loading
packages/client/src/contexts/AudioContext.tsx 0 → 100644 +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);