cetirizine

An experimental matrix client written in reactjs utilizing tailwind and storybook
git clone git://archive.git.mtrnord.blog/MTRNord/cetirizine.git
Log | Files | Refs | README | LICENSE

commit b0f7d12a96be6651243b35a5aa9729f51308a034
parent ff17a4da7dbbb1acf182151321b124d1584022ec
Author: MTRNord <mtrnord1@gmail.com>
Date:   Wed,  7 Jun 2023 20:26:26 +0200

Handle video events

Diffstat:
Achangelog.d/video.feature | 2++
Msrc/app/sdk/api/events.ts | 10++++++++++
Msrc/components/events/messageEvent.tsx | 52+++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/changelog.d/video.feature b/changelog.d/video.feature @@ -0,0 +1 @@ +Add a video player to video events +\ No newline at end of file diff --git a/src/app/sdk/api/events.ts b/src/app/sdk/api/events.ts @@ -30,6 +30,12 @@ export interface IRoomMessageImageContent extends IRoomMessageContent<"m.image"> file?: IEncryptedFile; } +export interface IRoomMessageVideoContent extends IRoomMessageContent<"m.video"> { + info?: IImageInfo; + url?: string; + file?: IEncryptedFile; +} + export interface IRoomMessageAudioContent extends IRoomMessageContent<"m.audio"> { info?: IAudioInfo; url?: string; @@ -54,6 +60,10 @@ export function isRoomMessageImageEvent(event: IRoomEvent): event is IRoomMessag return event.type === "m.room.message" && event.content.msgtype === "m.image"; } +export function isRoomMessageVideoEvent(event: IRoomEvent): event is IRoomMessageEvent<IRoomMessageVideoContent> { + return event.type === "m.room.message" && event.content.msgtype === "m.video"; +} + export function isRoomMessageAudioEvent(event: IRoomEvent): event is IRoomMessageEvent<IRoomMessageAudioContent> { return event.type === "m.room.message" && event.content.msgtype === "m.audio"; } diff --git a/src/components/events/messageEvent.tsx b/src/components/events/messageEvent.tsx @@ -1,5 +1,5 @@ import { memo, useContext, useEffect, useState } from "react"; -import { IRoomEvent, isRoomMessageAudioEvent, isRoomMessageImageEvent, isRoomMessageNoticeEvent, isRoomMessageTextEvent } from "../../app/sdk/api/events"; +import { IRoomEvent, isRoomMessageAudioEvent, isRoomMessageImageEvent, isRoomMessageNoticeEvent, isRoomMessageTextEvent, isRoomMessageVideoEvent } from "../../app/sdk/api/events"; import { FC } from "react"; import { MatrixClient, MatrixContext } from "../../app/sdk/client"; import Linkify from "linkify-react"; @@ -178,6 +178,56 @@ const MessageEvent: FC<MessageEventProps> = memo(({ event, room, hasPreviousEven {url && <Waveform src_url={url} />} </MessageWrapper> ) + } else if (isRoomMessageVideoEvent(event)) { + const [url, setUrl] = useState<string | undefined>(undefined); + const [unableToDecrypt, setUnableToDecrypt] = useState<boolean>(event.content.file !== undefined); + + useEffect(() => { + if (isRoomMessageVideoEvent(event)) { + if (event.content.url) { + setUrl(client.convertMXC(event.content.url)); + } else { + // Image is encrypted and we need to download and decrypt it + if (event.content.file) { + decryptMedia( + client, + event, + (url) => { + setUrl(url); + setUnableToDecrypt(false); + }, + (_error) => { + setUnableToDecrypt(true); + } + ); + } + } + } + }, [event]) + + if (unableToDecrypt) { + return (<UndecryptableEvent event={event} room={room} hasPreviousEvent={hasPreviousEvent} />) + } + + return ( + <MessageWrapper + displayname={room?.getMemberName(event.sender) || event.sender} + avatar_url={room?.getMemberAvatar(event.sender) || ""} + onlineState={room?.presence || OnlineState.Unknown} + isBot={room?.isBot(event.sender) || false} + dm={room?.isDM() || false} + hasPreviousEvent={hasPreviousEvent} + > + {/* TODO: Loading circle while video is loading */} + <video controls preload="metadata" + title={event.content.body} + className="rounded-md border-slate-400 border-2 max-h-[40rem] max-w-[40rem] h-[unset]" + > + <source src={url} /> + <meta name="description" content={event.content.body} /> + </video> + </MessageWrapper> + ) } else { return ( <MessageWrapper