Files
cinny/src/app/hooks/useSoundboardPacks.ts
T

161 lines
4.4 KiB
TypeScript
Raw Normal View History

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]);
};