import { Room } from 'matrix-js-sdk'; import { useCallback, useMemo, useState } from 'react'; import { AccountDataEvent } from '../../types/matrix/accountData'; import { StateEvent } from '../../types/matrix/room'; import { getGlobalSoundboardPacks, getRoomSoundboardPack, getRoomSoundboardPacks, getUserSoundboardPack, SoundboardPack, } from '../plugins/soundboard'; import { useMatrixClient } from './useMatrixClient'; import { useAccountDataCallback } from './useAccountDataCallback'; import { useStateEventCallback } from './useStateEventCallback'; // Parallels hooks/useImagePacks.ts (custom emoji). Same aggregation shape. export const useUserSoundboardPack = (): SoundboardPack | undefined => { const mx = useMatrixClient(); const [userPack, setUserPack] = useState(() => getUserSoundboardPack(mx)); useAccountDataCallback( mx, useCallback( (mEvent) => { if (mEvent.getType() === AccountDataEvent.LotusSoundboard) { setUserPack(getUserSoundboardPack(mx)); } }, [mx], ), ); return userPack; }; export const useGlobalSoundboardPacks = (): SoundboardPack[] => { const mx = useMatrixClient(); const [globalPacks, setGlobalPacks] = useState(() => getGlobalSoundboardPacks(mx)); useAccountDataCallback( mx, useCallback( (mEvent) => { if (mEvent.getType() === AccountDataEvent.LotusSoundboardRooms) { setGlobalPacks(getGlobalSoundboardPacks(mx)); } }, [mx], ), ); useStateEventCallback( mx, useCallback( (mEvent) => { const roomId = mEvent.getRoomId(); const stateKey = mEvent.getStateKey(); if ( mEvent.getType() === StateEvent.LotusSoundboardRoom && roomId && typeof stateKey === 'string' ) { const isGlobal = !!globalPacks.find( (pack) => pack.address && pack.address.roomId === roomId && pack.address.stateKey === stateKey, ); if (isGlobal) setGlobalPacks(getGlobalSoundboardPacks(mx)); } }, [mx, globalPacks], ), ); return globalPacks; }; export const useRoomSoundboardPack = (room: Room, stateKey: string): SoundboardPack | undefined => { const mx = useMatrixClient(); const [roomPack, setRoomPack] = useState(() => getRoomSoundboardPack(room, stateKey)); useStateEventCallback( mx, useCallback( (mEvent) => { if ( mEvent.getRoomId() === room.roomId && mEvent.getType() === StateEvent.LotusSoundboardRoom && mEvent.getStateKey() === stateKey ) { setRoomPack(getRoomSoundboardPack(room, stateKey)); } }, [room, stateKey], ), ); return roomPack; }; export const useRoomSoundboardPacks = (room: Room): SoundboardPack[] => { const mx = useMatrixClient(); const [roomPacks, setRoomPacks] = useState(() => getRoomSoundboardPacks(room)); useStateEventCallback( mx, useCallback( (mEvent) => { if ( mEvent.getRoomId() === room.roomId && mEvent.getType() === StateEvent.LotusSoundboardRoom ) { setRoomPacks(getRoomSoundboardPacks(room)); } }, [room], ), ); return roomPacks; }; export const useRoomsSoundboardPacks = (rooms: Room[]): SoundboardPack[] => { const mx = useMatrixClient(); const [roomPacks, setRoomPacks] = useState(() => rooms.flatMap(getRoomSoundboardPacks)); useStateEventCallback( mx, useCallback( (mEvent) => { if ( rooms.find((room) => room.roomId === mEvent.getRoomId()) && mEvent.getType() === StateEvent.LotusSoundboardRoom ) { setRoomPacks(rooms.flatMap(getRoomSoundboardPacks)); } }, [rooms], ), ); return roomPacks; }; /** User ∪ global ∪ room packs, deduped by id, keeping only packs with clips. */ export const useRelevantSoundboardPacks = (rooms: Room[]): SoundboardPack[] => { const userPack = useUserSoundboardPack(); const globalPacks = useGlobalSoundboardPacks(); const roomsPacks = useRoomsSoundboardPacks(rooms); return useMemo(() => { const packs = userPack ? [userPack] : []; const globalPackIds = new Set(globalPacks.map((pack) => pack.id)); const relPacks = packs.concat( globalPacks, roomsPacks.filter((pack) => !globalPackIds.has(pack.id)), ); return relPacks.filter((pack) => pack.getClips().length > 0); }, [userPack, globalPacks, roomsPacks]); };