mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-05 19:59:20 +00:00
Refactored to use reaction and redaction events
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
This commit is contained in:
@@ -10,14 +10,11 @@ import {
|
|||||||
RoomContext,
|
RoomContext,
|
||||||
useLocalParticipant,
|
useLocalParticipant,
|
||||||
} from "@livekit/components-react";
|
} from "@livekit/components-react";
|
||||||
|
import { ConnectionState, Room } from "livekit-client";
|
||||||
import {
|
import {
|
||||||
ConnectionState,
|
MatrixEvent,
|
||||||
// eslint-disable-next-line camelcase
|
RoomEvent as MatrixRoomEvent,
|
||||||
DataPacket_Kind,
|
} from "matrix-js-sdk/src/matrix";
|
||||||
Participant,
|
|
||||||
Room,
|
|
||||||
RoomEvent,
|
|
||||||
} from "livekit-client";
|
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import {
|
import {
|
||||||
FC,
|
FC,
|
||||||
@@ -37,6 +34,8 @@ import classNames from "classnames";
|
|||||||
import { BehaviorSubject, of } from "rxjs";
|
import { BehaviorSubject, of } from "rxjs";
|
||||||
import { useObservableEagerState } from "observable-hooks";
|
import { useObservableEagerState } from "observable-hooks";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import { EventType, RelationType } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { ReactionEventContent } from "matrix-js-sdk/src/types";
|
||||||
|
|
||||||
import LogoMark from "../icons/LogoMark.svg?react";
|
import LogoMark from "../icons/LogoMark.svg?react";
|
||||||
import LogoType from "../icons/LogoType.svg?react";
|
import LogoType from "../icons/LogoType.svg?react";
|
||||||
@@ -87,6 +86,7 @@ import { makeSpotlightExpandedLayout } from "../grid/SpotlightExpandedLayout";
|
|||||||
import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout";
|
import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout";
|
||||||
import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout";
|
import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout";
|
||||||
import { RaisedHandsProvider, useRaisedHands } from "./useRaisedHands";
|
import { RaisedHandsProvider, useRaisedHands } from "./useRaisedHands";
|
||||||
|
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
|
||||||
|
|
||||||
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
|
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
|
||||||
|
|
||||||
@@ -309,33 +309,36 @@ export const InCallView: FC<InCallViewProps> = ({
|
|||||||
[vm],
|
[vm],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const memberships = useMatrixRTCSessionMemberships(rtcSession);
|
||||||
const { raisedHands, setRaisedHands } = useRaisedHands();
|
const { raisedHands, setRaisedHands } = useRaisedHands();
|
||||||
const isHandRaised = raisedHands.includes(
|
const [reactionId, setReactionId] = useState<string | null>(null);
|
||||||
localParticipant.identity.split(":")[0] +
|
const [username, localpart] = localParticipant.identity.split(":");
|
||||||
":" +
|
const userId = `${username}:${localpart}`;
|
||||||
localParticipant.identity.split(":")[1],
|
const isHandRaised = raisedHands.includes(userId);
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleDataReceived = (
|
const handleReactionEvent = (event: MatrixEvent): void => {
|
||||||
payload: Uint8Array,
|
if (event.getType() === EventType.Reaction) {
|
||||||
participant?: Participant,
|
// TODO: check if target of reaction is a call membership event
|
||||||
// eslint-disable-next-line camelcase
|
const content = event.getContent() as ReactionEventContent;
|
||||||
kind?: DataPacket_Kind,
|
if (content?.["m.relates_to"].key === "🖐️") {
|
||||||
): void => {
|
setRaisedHands([...raisedHands, event.getSender()!]);
|
||||||
const decoder = new TextDecoder();
|
}
|
||||||
const strData = decoder.decode(payload);
|
}
|
||||||
// get json object from strData
|
if (event.getType() === EventType.RoomRedaction) {
|
||||||
const data = JSON.parse(strData);
|
// TODO: check target of redaction event
|
||||||
setRaisedHands(data.raisedHands);
|
setRaisedHands(raisedHands.filter((id) => id !== event.getSender()));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
livekitRoom.on(RoomEvent.DataReceived, handleDataReceived);
|
client.on(MatrixRoomEvent.Timeline, handleReactionEvent);
|
||||||
|
client.on(MatrixRoomEvent.Redaction, handleReactionEvent);
|
||||||
|
|
||||||
return (): void => {
|
return (): void => {
|
||||||
livekitRoom.off(RoomEvent.DataReceived, handleDataReceived);
|
client.on(MatrixRoomEvent.Timeline, handleReactionEvent);
|
||||||
|
client.off(MatrixRoomEvent.Redaction, handleReactionEvent);
|
||||||
};
|
};
|
||||||
}, [livekitRoom, setRaisedHands]);
|
}, [client, raisedHands, setRaisedHands]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
widget?.api.transport
|
widget?.api.transport
|
||||||
@@ -518,35 +521,54 @@ export const InCallView: FC<InCallViewProps> = ({
|
|||||||
.catch(logger.error);
|
.catch(logger.error);
|
||||||
}, [localParticipant, isScreenShareEnabled]);
|
}, [localParticipant, isScreenShareEnabled]);
|
||||||
|
|
||||||
const toggleRaisedHand = useCallback(() => {
|
const toggleRaisedHand = useCallback(async () => {
|
||||||
// TODO: wtf
|
|
||||||
const userId =
|
|
||||||
localParticipant.identity.split(":")[0] +
|
|
||||||
":" +
|
|
||||||
localParticipant.identity.split(":")[1];
|
|
||||||
const raisedHand = raisedHands.includes(userId);
|
|
||||||
let result = raisedHands;
|
|
||||||
if (raisedHand) {
|
|
||||||
result = raisedHands.filter((id) => id !== userId);
|
|
||||||
} else {
|
|
||||||
result = [...raisedHands, userId];
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const strData = JSON.stringify({
|
if (isHandRaised) {
|
||||||
raisedHands: result,
|
try {
|
||||||
});
|
if (reactionId) {
|
||||||
const encoder = new TextEncoder();
|
await client.redactEvent(rtcSession.room.roomId, reactionId);
|
||||||
const data = encoder.encode(strData);
|
setReactionId(null);
|
||||||
livekitRoom.localParticipant.publishData(data, { reliable: true });
|
setRaisedHands(raisedHands.filter((id) => id !== userId));
|
||||||
setRaisedHands(result);
|
logger.debug("Redacted reaction event");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.error("Failed to redact reaction event", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const m = memberships.filter((m) => m.sender === userId);
|
||||||
|
const eventId = m[0].eventId!;
|
||||||
|
try {
|
||||||
|
const reaction = await client.sendEvent(
|
||||||
|
rtcSession.room.roomId,
|
||||||
|
EventType.Reaction,
|
||||||
|
{
|
||||||
|
"m.relates_to": {
|
||||||
|
rel_type: RelationType.Annotation,
|
||||||
|
event_id: eventId,
|
||||||
|
key: "🖐️",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
setReactionId(reaction.event_id);
|
||||||
|
setRaisedHands([...raisedHands, userId]);
|
||||||
|
logger.debug("Sent reaction event", reaction.event_id);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error("Failed to send reaction event", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
livekitRoom.localParticipant,
|
client,
|
||||||
localParticipant.identity,
|
isHandRaised,
|
||||||
|
memberships,
|
||||||
raisedHands,
|
raisedHands,
|
||||||
|
reactionId,
|
||||||
|
rtcSession.room.roomId,
|
||||||
setRaisedHands,
|
setRaisedHands,
|
||||||
|
setReactionId,
|
||||||
|
userId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let footer: JSX.Element | null;
|
let footer: JSX.Element | null;
|
||||||
|
|||||||
Reference in New Issue
Block a user