Hand raise feature (#2542)

* Initial support for Hand Raise feature

Signed-off-by: Milton Moura <miltonmoura@gmail.com>

* Refactored to use reaction and redaction events

Signed-off-by: Milton Moura <miltonmoura@gmail.com>

* Replacing button svg with raised hand emoji

Signed-off-by: Milton Moura <miltonmoura@gmail.com>

* SpotlightTile should not duplicate the raised hand

Signed-off-by: Milton Moura <miltonmoura@gmail.com>

* Update src/room/useRaisedHands.tsx

Element Call recently changed to AGPL-3.0

* Use relations to load existing reactions when joining the call

Signed-off-by: Milton Moura <miltonmoura@gmail.com>

* Links to sha commit of matrix-js-sdk that exposes the call membership event id and refactors some async code

Signed-off-by: Milton Moura <miltonmoura@gmail.com>

* Removing RaiseHand.svg

* Check for reaction & redaction capabilities in widget mode

Signed-off-by: Milton Moura <miltonmoura@gmail.com>

* Fix failing GridTile test

Signed-off-by: Milton Moura <miltonmoura@gmail.com>

* Center align hand raise.

* Add support for displaying the duration of a raised hand.

* Add a sound for when a hand is raised.

* Refactor raised hand indicator and add tests.

* lint

* Refactor into own files.

* Redact the right thing.

* Tidy up useEffect

* Lint tests

* Remove extra layer

* Add better sound. (woosh)

* Add a small mode for spotlight

* Fix timestamp calculation on relaod.

* Fix call border resizing video

* lint

* Fix and update tests

* Allow timer to be configurable.

* Add preferences tab for choosing to enable timer.

* Drop border from raised hand icon

* Handle cases when a new member event happens.

* Prevent infinite loop

* Major refactor to support various state problems.

* Tidy up and finish test rewrites

* Add some explanation comments.

* Even more comments.

* Use proper duration formatter

* Remove rerender

* Fix redactions not working because they pick up events in transit.

* More tidying

* Use deferred value

* linting

* Add tests for cases where we got a reaction from someone else.

* Be even less brittle.

* Transpose border to GridTile.

* lint

---------

Signed-off-by: Milton Moura <miltonmoura@gmail.com>
Co-authored-by: fkwp <fkwp@users.noreply.github.com>
Co-authored-by: Half-Shot <will@half-shot.uk>
Co-authored-by: Will Hunt <github@half-shot.uk>
This commit is contained in:
Milton Moura
2024-11-04 08:54:13 -01:00
committed by GitHub
parent f2ed07c258
commit 1897210a60
24 changed files with 1149 additions and 30 deletions

View File

@@ -19,6 +19,7 @@ import {
TouchEvent,
forwardRef,
useCallback,
useDeferredValue,
useEffect,
useMemo,
useRef,
@@ -40,6 +41,7 @@ import {
VideoButton,
ShareScreenButton,
SettingsButton,
RaiseHandToggleButton,
SwitchCameraButton,
} from "../button";
import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header";
@@ -79,6 +81,9 @@ import { makeOneOnOneLayout } from "../grid/OneOnOneLayout";
import { makeSpotlightExpandedLayout } from "../grid/SpotlightExpandedLayout";
import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout";
import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout";
import { ReactionsProvider, useReactions } from "../useReactions";
import handSoundOgg from "../sound/raise_hand.ogg?url";
import handSoundMp3 from "../sound/raise_hand.mp3?url";
import { useSwitchCamera } from "./useSwitchCamera";
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
@@ -132,12 +137,14 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
return (
<RoomContext.Provider value={livekitRoom}>
<InCallView
{...props}
vm={vm}
livekitRoom={livekitRoom}
connState={connState}
/>
<ReactionsProvider rtcSession={props.rtcSession}>
<InCallView
{...props}
vm={vm}
livekitRoom={livekitRoom}
connState={connState}
/>
</ReactionsProvider>
</RoomContext.Provider>
);
};
@@ -170,6 +177,13 @@ export const InCallView: FC<InCallViewProps> = ({
connState,
onShareClick,
}) => {
const { supportsReactions, raisedHands } = useReactions();
const raisedHandCount = useMemo(
() => Object.keys(raisedHands).length,
[raisedHands],
);
const previousRaisedHandCount = useDeferredValue(raisedHandCount);
useWakeLock();
useEffect(() => {
@@ -308,6 +322,19 @@ export const InCallView: FC<InCallViewProps> = ({
[vm],
);
// Play a sound when the raised hand count increases.
const handRaisePlayer = useRef<HTMLAudioElement>(null);
useEffect(() => {
if (!handRaisePlayer.current) {
return;
}
if (previousRaisedHandCount < raisedHandCount) {
handRaisePlayer.current.play().catch((ex) => {
logger.warn("Failed to play raise hand sound", ex);
});
}
}, [raisedHandCount, handRaisePlayer, previousRaisedHandCount]);
useEffect(() => {
widget?.api.transport
.send(
@@ -527,6 +554,15 @@ export const InCallView: FC<InCallViewProps> = ({
/>,
);
}
if (supportsReactions) {
buttons.push(
<RaiseHandToggleButton
client={client}
rtcSession={rtcSession}
key="4"
/>,
);
}
buttons.push(<SettingsButton key="settings" onClick={openSettings} />);
}
@@ -608,6 +644,10 @@ export const InCallView: FC<InCallViewProps> = ({
))}
<RoomAudioRenderer />
{renderContent()}
<audio ref={handRaisePlayer} hidden>
<source src={handSoundOgg} type="audio/ogg; codecs=vorbis" />
<source src={handSoundMp3} type="audio/mpeg" />
</audio>
{footer}
{!noControls && <RageshakeRequestModal {...rageshakeRequestModalProps} />}
<SettingsModal