mirror of
https://github.com/vector-im/element-call.git
synced 2026-07-18 18:59:23 +00:00
Prototyping of showing video tile for every call membership
...even if they don't have a LK participant
This commit is contained in:
@@ -53,6 +53,7 @@ import {
|
||||
Menu,
|
||||
} from "@vector-im/compound-web";
|
||||
import { useStateObservable } from "@react-rxjs/core";
|
||||
import useRelativeTime from "@nkzw/use-relative-time";
|
||||
|
||||
import { Avatar } from "../Avatar";
|
||||
import styles from "./VideoTile.module.css";
|
||||
@@ -61,6 +62,7 @@ import {
|
||||
ScreenShareViewModel,
|
||||
MediaViewModel,
|
||||
UserMediaViewModel,
|
||||
MembershipOnlyViewModel,
|
||||
} from "../state/MediaViewModel";
|
||||
import { subscribe } from "../state/subscribe";
|
||||
import { useMergedRefs } from "../useMergedRefs";
|
||||
@@ -72,7 +74,7 @@ interface TileProps {
|
||||
style?: ComponentProps<typeof animated.div>["style"];
|
||||
targetWidth: number;
|
||||
targetHeight: number;
|
||||
video: TrackReferenceOrPlaceholder;
|
||||
video?: TrackReferenceOrPlaceholder;
|
||||
member: RoomMember | undefined;
|
||||
videoEnabled: boolean;
|
||||
maximised: boolean;
|
||||
@@ -110,6 +112,10 @@ const Tile = forwardRef<HTMLDivElement, TileProps>(
|
||||
const { t } = useTranslation();
|
||||
const mergedRef = useMergedRefs(tileRef, ref);
|
||||
|
||||
const joinedCallTime = member?.events.member?.getTs() ?? 0;
|
||||
|
||||
const joinedCallAgo = useRelativeTime(joinedCallTime ?? 0);
|
||||
|
||||
return (
|
||||
<animated.div
|
||||
className={classNames(styles.videoTile, className, {
|
||||
@@ -129,7 +135,7 @@ const Tile = forwardRef<HTMLDivElement, TileProps>(
|
||||
src={member?.getMxcAvatarUrl()}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
{video.publication !== undefined && (
|
||||
{video?.publication !== undefined && (
|
||||
<VideoTrack
|
||||
trackRef={video}
|
||||
// There's no reason for this to be focusable
|
||||
@@ -137,12 +143,21 @@ const Tile = forwardRef<HTMLDivElement, TileProps>(
|
||||
disablePictureInPicture
|
||||
/>
|
||||
)}
|
||||
{!video && member && joinedCallTime > 0 && (
|
||||
<div style={{ textAlign: "center" }}>
|
||||
<span title={member.userId}>{nameTag}</span> joined the call{" "}
|
||||
<span title={new Date(joinedCallTime).toLocaleString()}>
|
||||
{joinedCallAgo}
|
||||
</span>{" "}
|
||||
but is currently unreachable. Are they having connection problems?
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.fg}>
|
||||
<div className={styles.nameTag}>
|
||||
{nameTagLeadingIcon}
|
||||
<Text as="span" size="sm" weight="medium" className={styles.name}>
|
||||
{nameTag}
|
||||
<span title={member?.userId}>{nameTag}</span>{" "}
|
||||
</Text>
|
||||
{unencryptedWarning && (
|
||||
<Tooltip
|
||||
@@ -402,6 +417,75 @@ const ScreenShareTile = subscribe<ScreenShareTileProps, HTMLDivElement>(
|
||||
|
||||
ScreenShareTile.displayName = "ScreenShareTile";
|
||||
|
||||
interface MembershipOnlyTileProps {
|
||||
vm: MembershipOnlyViewModel;
|
||||
className?: string;
|
||||
style?: ComponentProps<typeof animated.div>["style"];
|
||||
targetWidth: number;
|
||||
targetHeight: number;
|
||||
nameTag: string;
|
||||
displayName: string;
|
||||
maximised: boolean;
|
||||
fullscreen: boolean;
|
||||
onToggleFullscreen: (itemId: string) => void;
|
||||
}
|
||||
|
||||
const MembershipOnlyTile = subscribe<MembershipOnlyTileProps, HTMLDivElement>(
|
||||
(
|
||||
{
|
||||
vm,
|
||||
className,
|
||||
style,
|
||||
targetWidth,
|
||||
targetHeight,
|
||||
nameTag,
|
||||
displayName,
|
||||
maximised,
|
||||
fullscreen,
|
||||
onToggleFullscreen,
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const { t } = useTranslation();
|
||||
const onClickFullScreen = useCallback(
|
||||
() => onToggleFullscreen(vm.id),
|
||||
[onToggleFullscreen, vm],
|
||||
);
|
||||
|
||||
const FullScreenIcon = fullscreen ? CollapseIcon : ExpandIcon;
|
||||
|
||||
return (
|
||||
<Tile
|
||||
ref={ref}
|
||||
className={classNames(className, styles.membershipOnly)}
|
||||
style={style}
|
||||
targetWidth={targetWidth}
|
||||
targetHeight={targetHeight}
|
||||
member={vm.member}
|
||||
videoEnabled={true}
|
||||
maximised={maximised}
|
||||
unencryptedWarning={false}
|
||||
nameTag={nameTag}
|
||||
displayName={displayName}
|
||||
primaryButton={
|
||||
<button
|
||||
aria-label={
|
||||
fullscreen
|
||||
? t("video_tile.full_screen")
|
||||
: t("video_tile.exit_full_screen")
|
||||
}
|
||||
onClick={onClickFullScreen}
|
||||
>
|
||||
<FullScreenIcon aria-hidden width={20} height={20} />
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
MembershipOnlyTile.displayName = "MembershipOnlyTile";
|
||||
|
||||
interface Props {
|
||||
vm: MediaViewModel;
|
||||
maximised: boolean;
|
||||
@@ -471,7 +555,7 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
|
||||
showSpeakingIndicator={showSpeakingIndicator}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
} else if (vm instanceof ScreenShareViewModel) {
|
||||
return (
|
||||
<ScreenShareTile
|
||||
ref={ref}
|
||||
@@ -487,6 +571,22 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
|
||||
onToggleFullscreen={onToggleFullscreen}
|
||||
/>
|
||||
);
|
||||
} else if (vm instanceof MembershipOnlyViewModel) {
|
||||
return (
|
||||
<MembershipOnlyTile
|
||||
ref={ref}
|
||||
className={className}
|
||||
style={style}
|
||||
vm={vm}
|
||||
targetWidth={targetWidth}
|
||||
targetHeight={targetHeight}
|
||||
nameTag={nameTag}
|
||||
displayName={displayName}
|
||||
maximised={maximised}
|
||||
fullscreen={fullscreen}
|
||||
onToggleFullscreen={onToggleFullscreen}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user