Add support for specifying custom sounds via state events.

This commit is contained in:
Will Hunt
2024-11-11 14:50:26 +00:00
parent 8f05331703
commit ce2b4c3cca
4 changed files with 27 additions and 5 deletions

View File

@@ -33,7 +33,6 @@ import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMembership
import styles from "./ReactionToggleButton.module.css"; import styles from "./ReactionToggleButton.module.css";
import { import {
ReactionOption, ReactionOption,
ReactionSet,
ElementCallReactionEventType, ElementCallReactionEventType,
} from "../reactions"; } from "../reactions";
import { Modal } from "../Modal"; import { Modal } from "../Modal";
@@ -77,9 +76,10 @@ export function ReactionPopupMenu({
}): ReactNode { }): ReactNode {
const { t } = useTranslation(); const { t } = useTranslation();
const [isFullyExpanded, setExpanded] = useState(false); const [isFullyExpanded, setExpanded] = useState(false);
const { allReactions } = useReactions();
const filteredReactionSet = useMemo( const filteredReactionSet = useMemo(
() => (isFullyExpanded ? ReactionSet : ReactionSet.slice(0, 6)), () => (isFullyExpanded ? allReactions : allReactions.slice(0, 6)),
[isFullyExpanded], [isFullyExpanded],
); );

View File

@@ -64,6 +64,10 @@ export interface ECallReactionEventContent {
name: string; name: string;
} }
export interface ECallReactionSoundsEventContent {
reactions: ReactionOption[],
}
export const GenericReaction: ReactionOption = { export const GenericReaction: ReactionOption = {
name: "generic", name: "generic",
emoji: "", // Filled in by user emoji: "", // Filled in by user

View File

@@ -13,10 +13,10 @@ import {
soundEffectVolumeSetting as effectSoundVolumeSetting, soundEffectVolumeSetting as effectSoundVolumeSetting,
useSetting, useSetting,
} from "../settings/settings"; } from "../settings/settings";
import { GenericReaction, ReactionSet } from "../reactions"; import { GenericReaction } from "../reactions";
export function ReactionsAudioRenderer(): ReactNode { export function ReactionsAudioRenderer(): ReactNode {
const { reactions } = useReactions(); const { reactions, allReactions } = useReactions();
const [shouldPlay] = useSetting(playReactionsSound); const [shouldPlay] = useSetting(playReactionsSound);
const [effectSoundVolume] = useSetting(effectSoundVolumeSetting); const [effectSoundVolume] = useSetting(effectSoundVolumeSetting);
const audioElements = useRef<Record<string, HTMLAudioElement | null>>({}); const audioElements = useRef<Record<string, HTMLAudioElement | null>>({});
@@ -52,7 +52,7 @@ export function ReactionsAudioRenderer(): ReactNode {
// be delayed. // be delayed.
return ( return (
<> <>
{[GenericReaction, ...ReactionSet].map( {[GenericReaction, ...allReactions].map(
(r) => (r) =>
r.sound && ( r.sound && (
<audio <audio

View File

@@ -11,6 +11,7 @@ import {
RelationType, RelationType,
RoomEvent as MatrixRoomEvent, RoomEvent as MatrixRoomEvent,
MatrixEventEvent, MatrixEventEvent,
Direction,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { ReactionEventContent } from "matrix-js-sdk/src/types"; import { ReactionEventContent } from "matrix-js-sdk/src/types";
import { import {
@@ -29,7 +30,9 @@ import { useMatrixRTCSessionMemberships } from "./useMatrixRTCSessionMemberships
import { useClientState } from "./ClientContext"; import { useClientState } from "./ClientContext";
import { import {
ECallReactionEventContent, ECallReactionEventContent,
ECallReactionSoundsEventContent,
ElementCallReactionEventType, ElementCallReactionEventType,
ElementCallReactionsEventType,
GenericReaction, GenericReaction,
ReactionOption, ReactionOption,
ReactionSet, ReactionSet,
@@ -37,6 +40,7 @@ import {
import { useLatest } from "./useLatest"; import { useLatest } from "./useLatest";
interface ReactionsContextType { interface ReactionsContextType {
allReactions: ReactionOption[],
raisedHands: Record<string, Date>; raisedHands: Record<string, Date>;
supportsReactions: boolean; supportsReactions: boolean;
reactions: Record<string, ReactionOption>; reactions: Record<string, ReactionOption>;
@@ -96,6 +100,19 @@ export const ReactionsProvider = ({
{}, {},
); );
// TODO: Refetch if the timeline changes.
const allReactions = useMemo(() => {
const result = room.getLiveTimeline().getState(Direction.Forward)?.getStateEvents(ElementCallReactionsEventType, '');
if (!result) {
return ReactionSet;
}
const content = result.getContent() as ECallReactionSoundsEventContent;
if (!content.reactions || !Array.isArray(content.reactions)) {
logger.warn(`Reactions event ${result.event.event_id} was not correctly formatted, ignoring`);
}
return [...ReactionSet, ...content.reactions];
}, [room])
// Reduce the data down for the consumers. // Reduce the data down for the consumers.
const resultRaisedHands = useMemo( const resultRaisedHands = useMemo(
() => () =>
@@ -345,6 +362,7 @@ export const ReactionsProvider = ({
supportsReactions, supportsReactions,
reactions, reactions,
lowerHand, lowerHand,
allReactions,
}} }}
> >
{children} {children}