mirror of
https://github.com/vector-im/element-call.git
synced 2026-07-12 18:39:19 +00:00
per member tiles
This commit is contained in:
@@ -146,6 +146,7 @@
|
|||||||
"feedback_tab_thank_you": "Thanks, we received your feedback!",
|
"feedback_tab_thank_you": "Thanks, we received your feedback!",
|
||||||
"feedback_tab_title": "Feedback",
|
"feedback_tab_title": "Feedback",
|
||||||
"more_tab_title": "More",
|
"more_tab_title": "More",
|
||||||
|
"non_member_tiles": "Show non member tiles",
|
||||||
"opt_in_description": "<0></0><1></1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.",
|
"opt_in_description": "<0></0><1></1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.",
|
||||||
"preferences_tab_body": "Here you can configure extra options for an improved experience",
|
"preferences_tab_body": "Here you can configure extra options for an improved experience",
|
||||||
"preferences_tab_h4": "Preferences",
|
"preferences_tab_h4": "Preferences",
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import { Initializer } from "./initializer";
|
|||||||
import { MediaDevicesProvider } from "./livekit/MediaDevicesContext";
|
import { MediaDevicesProvider } from "./livekit/MediaDevicesContext";
|
||||||
import { widget } from "./widget";
|
import { widget } from "./widget";
|
||||||
import { useTheme } from "./useTheme";
|
import { useTheme } from "./useTheme";
|
||||||
|
import { nonMemberTiles } from "./settings/settings";
|
||||||
|
import { Config } from "./config/Config";
|
||||||
|
|
||||||
const SentryRoute = Sentry.withSentryRouting(Route);
|
const SentryRoute = Sentry.withSentryRouting(Route);
|
||||||
|
|
||||||
@@ -71,6 +73,13 @@ export const App: FC<AppProps> = ({ history }) => {
|
|||||||
.catch(logger.error);
|
.catch(logger.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update settings to use the non member tile information from the config if set
|
||||||
|
useEffect(() => {
|
||||||
|
if (loaded && Config.get().show_non_member_tiles) {
|
||||||
|
nonMemberTiles.setValue(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const errorPage = <CrashView />;
|
const errorPage = <CrashView />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ interface RoomHeaderInfoProps {
|
|||||||
avatarUrl: string | null;
|
avatarUrl: string | null;
|
||||||
encrypted: boolean;
|
encrypted: boolean;
|
||||||
participantCount: number | null;
|
participantCount: number | null;
|
||||||
|
nonMemberItemCount: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({
|
export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({
|
||||||
@@ -125,6 +126,7 @@ export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({
|
|||||||
avatarUrl,
|
avatarUrl,
|
||||||
encrypted,
|
encrypted,
|
||||||
participantCount,
|
participantCount,
|
||||||
|
nonMemberItemCount,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const size = useMediaQuery("(max-width: 550px)") ? "sm" : "lg";
|
const size = useMediaQuery("(max-width: 550px)") ? "sm" : "lg";
|
||||||
@@ -157,7 +159,8 @@ export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({
|
|||||||
aria-label={t("header_participants_label")}
|
aria-label={t("header_participants_label")}
|
||||||
/>
|
/>
|
||||||
<Text as="span" size="sm" weight="medium">
|
<Text as="span" size="sm" weight="medium">
|
||||||
{t("participant_count", { count: participantCount ?? 0 })}
|
{t("participant_count", { count: participantCount ?? 0 })}{" "}
|
||||||
|
{(nonMemberItemCount ?? 0) > 0 && <>(+ {nonMemberItemCount})</>}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ export interface ResolvedConfigOptions extends ConfigOptions {
|
|||||||
enable_video: boolean;
|
enable_video: boolean;
|
||||||
};
|
};
|
||||||
app_prompt: boolean;
|
app_prompt: boolean;
|
||||||
show_non_member_participants: boolean;
|
show_non_member_tiles: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_CONFIG: ResolvedConfigOptions = {
|
export const DEFAULT_CONFIG: ResolvedConfigOptions = {
|
||||||
@@ -128,5 +128,5 @@ export const DEFAULT_CONFIG: ResolvedConfigOptions = {
|
|||||||
enable_video: true,
|
enable_video: true,
|
||||||
},
|
},
|
||||||
app_prompt: true,
|
app_prompt: true,
|
||||||
show_non_member_participants: false,
|
show_non_member_tiles: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
|||||||
}
|
}
|
||||||
}, [connState, onLeave]);
|
}, [connState, onLeave]);
|
||||||
|
|
||||||
|
const nonMemberItemCount = useObservableEagerState(vm.nonMemberItemCount);
|
||||||
const containerRef1 = useRef<HTMLDivElement | null>(null);
|
const containerRef1 = useRef<HTMLDivElement | null>(null);
|
||||||
const [containerRef2, bounds] = useMeasure();
|
const [containerRef2, bounds] = useMeasure();
|
||||||
const boundsValid = bounds.height > 0;
|
const boundsValid = bounds.height > 0;
|
||||||
@@ -633,6 +634,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
|||||||
avatarUrl={matrixInfo.roomAvatar}
|
avatarUrl={matrixInfo.roomAvatar}
|
||||||
encrypted={matrixInfo.e2eeSystem.kind !== E2eeType.NONE}
|
encrypted={matrixInfo.e2eeSystem.kind !== E2eeType.NONE}
|
||||||
participantCount={participantCount}
|
participantCount={participantCount}
|
||||||
|
nonMemberItemCount={nonMemberItemCount}
|
||||||
/>
|
/>
|
||||||
</LeftNav>
|
</LeftNav>
|
||||||
<RightNav>
|
<RightNav>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
useSetting,
|
useSetting,
|
||||||
developerSettingsTab as developerSettingsTabSetting,
|
developerSettingsTab as developerSettingsTabSetting,
|
||||||
duplicateTiles as duplicateTilesSetting,
|
duplicateTiles as duplicateTilesSetting,
|
||||||
|
nonMemberTiles as nonMemberTilesSetting,
|
||||||
useOptInAnalytics,
|
useOptInAnalytics,
|
||||||
} from "./settings";
|
} from "./settings";
|
||||||
import { isFirefox } from "../Platform";
|
import { isFirefox } from "../Platform";
|
||||||
@@ -68,6 +69,8 @@ export const SettingsModal: FC<Props> = ({
|
|||||||
);
|
);
|
||||||
const [duplicateTiles, setDuplicateTiles] = useSetting(duplicateTilesSetting);
|
const [duplicateTiles, setDuplicateTiles] = useSetting(duplicateTilesSetting);
|
||||||
|
|
||||||
|
const [nonMemberTiles, setNonMemberTiles] = useSetting(nonMemberTilesSetting);
|
||||||
|
|
||||||
// Generate a `SelectInput` with a list of devices for a given device kind.
|
// Generate a `SelectInput` with a list of devices for a given device kind.
|
||||||
const generateDeviceSelection = (
|
const generateDeviceSelection = (
|
||||||
devices: MediaDevice,
|
devices: MediaDevice,
|
||||||
@@ -236,6 +239,20 @@ export const SettingsModal: FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
|
<FieldRow>
|
||||||
|
<InputField
|
||||||
|
id="nonMemberTiles"
|
||||||
|
type="checkbox"
|
||||||
|
label={t("settings.non_member_tiles")}
|
||||||
|
checked={nonMemberTiles}
|
||||||
|
onChange={useCallback(
|
||||||
|
(event: ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
setNonMemberTiles(event.target.checked);
|
||||||
|
},
|
||||||
|
[setNonMemberTiles],
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FieldRow>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ export const developerSettingsTab = new Setting(
|
|||||||
|
|
||||||
export const duplicateTiles = new Setting("duplicate-tiles", 0);
|
export const duplicateTiles = new Setting("duplicate-tiles", 0);
|
||||||
|
|
||||||
|
export const nonMemberTiles = new Setting("non-member-tiles", true);
|
||||||
|
|
||||||
export const audioInput = new Setting<string | undefined>(
|
export const audioInput = new Setting<string | undefined>(
|
||||||
"audio-input",
|
"audio-input",
|
||||||
undefined,
|
undefined,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ import {
|
|||||||
} from "./MediaViewModel";
|
} from "./MediaViewModel";
|
||||||
import { accumulate, finalizeValue } from "../utils/observable";
|
import { accumulate, finalizeValue } from "../utils/observable";
|
||||||
import { ObservableScope } from "./ObservableScope";
|
import { ObservableScope } from "./ObservableScope";
|
||||||
import { duplicateTiles } from "../settings/settings";
|
import { duplicateTiles, nonMemberTiles } from "../settings/settings";
|
||||||
import { isFirefox } from "../Platform";
|
import { isFirefox } from "../Platform";
|
||||||
import { setPipEnabled } from "../controls";
|
import { setPipEnabled } from "../controls";
|
||||||
import { EncryptionSystem } from "../e2ee/sharedKeyManagement";
|
import { EncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
@@ -177,6 +177,7 @@ class UserMedia {
|
|||||||
member: RoomMember | undefined,
|
member: RoomMember | undefined,
|
||||||
participant: LocalParticipant | RemoteParticipant | undefined,
|
participant: LocalParticipant | RemoteParticipant | undefined,
|
||||||
encryptionSystem: EncryptionSystem,
|
encryptionSystem: EncryptionSystem,
|
||||||
|
rtcSession: MatrixRTCSession,
|
||||||
) {
|
) {
|
||||||
this.participant = new BehaviorSubject(participant);
|
this.participant = new BehaviorSubject(participant);
|
||||||
|
|
||||||
@@ -186,6 +187,7 @@ class UserMedia {
|
|||||||
member,
|
member,
|
||||||
this.participant.asObservable() as Observable<LocalParticipant>,
|
this.participant.asObservable() as Observable<LocalParticipant>,
|
||||||
encryptionSystem,
|
encryptionSystem,
|
||||||
|
rtcSession,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.vm = new RemoteUserMediaViewModel(
|
this.vm = new RemoteUserMediaViewModel(
|
||||||
@@ -195,6 +197,7 @@ class UserMedia {
|
|||||||
RemoteParticipant | undefined
|
RemoteParticipant | undefined
|
||||||
>,
|
>,
|
||||||
encryptionSystem,
|
encryptionSystem,
|
||||||
|
rtcSession,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,6 +365,7 @@ export class CallViewModel extends ViewModel {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public readonly nonMemberItemCount = new BehaviorSubject<number>(0);
|
||||||
private readonly mediaItems: Observable<MediaItem[]> = combineLatest([
|
private readonly mediaItems: Observable<MediaItem[]> = combineLatest([
|
||||||
this.remoteParticipants,
|
this.remoteParticipants,
|
||||||
observeParticipantMedia(this.livekitRoom.localParticipant),
|
observeParticipantMedia(this.livekitRoom.localParticipant),
|
||||||
@@ -371,15 +375,18 @@ export class CallViewModel extends ViewModel {
|
|||||||
this.matrixRTCSession,
|
this.matrixRTCSession,
|
||||||
MatrixRTCSessionEvent.MembershipsChanged,
|
MatrixRTCSessionEvent.MembershipsChanged,
|
||||||
).pipe(startWith(null)),
|
).pipe(startWith(null)),
|
||||||
// fromEvent(
|
nonMemberTiles.value,
|
||||||
// this.matrixRTCSession,
|
|
||||||
// MatrixRTCSessionEvent.EncryptionKeyChanged,
|
|
||||||
// ).pipe(startWith(null)),
|
|
||||||
]).pipe(
|
]).pipe(
|
||||||
scan(
|
scan(
|
||||||
(
|
(
|
||||||
prevItems,
|
prevItems,
|
||||||
[remoteParticipants, { participant: localParticipant }, duplicateTiles],
|
[
|
||||||
|
remoteParticipants,
|
||||||
|
{ participant: localParticipant },
|
||||||
|
duplicateTiles,
|
||||||
|
_participantChange,
|
||||||
|
nonMemberTiles,
|
||||||
|
],
|
||||||
) => {
|
) => {
|
||||||
const newItems = new Map(
|
const newItems = new Map(
|
||||||
function* (this: CallViewModel): Iterable<[string, MediaItem]> {
|
function* (this: CallViewModel): Iterable<[string, MediaItem]> {
|
||||||
@@ -423,6 +430,7 @@ export class CallViewModel extends ViewModel {
|
|||||||
member,
|
member,
|
||||||
participant,
|
participant,
|
||||||
this.encryptionSystem,
|
this.encryptionSystem,
|
||||||
|
this.matrixRTCSession,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -455,27 +463,28 @@ export class CallViewModel extends ViewModel {
|
|||||||
// - If one wants to test scalability using the livekit cli.
|
// - If one wants to test scalability using the livekit cli.
|
||||||
// - If an experimental project does not yet do the matrixRTC bits.
|
// - If an experimental project does not yet do the matrixRTC bits.
|
||||||
// - If someone wants to debug if the LK connection works but matrixRTC room state failed to arrive.
|
// - If someone wants to debug if the LK connection works but matrixRTC room state failed to arrive.
|
||||||
const debugShowNonMember = Config.get().show_non_member_participants;
|
const debugShowNonMember = nonMemberTiles; //Config.get().show_non_member_tiles;
|
||||||
const newNonMemberItems = debugShowNonMember
|
const newNonMemberItems = debugShowNonMember
|
||||||
? new Map(
|
? new Map(
|
||||||
function* (this: CallViewModel): Iterable<[string, MediaItem]> {
|
function* (this: CallViewModel): Iterable<[string, MediaItem]> {
|
||||||
for (let p = 0; p < remoteParticipants.length; p++) {
|
for (const participant of remoteParticipants) {
|
||||||
for (let i = 0; i < 1 + duplicateTiles; i++) {
|
for (let i = 0; i < 1 + duplicateTiles; i++) {
|
||||||
const participant = remoteParticipants[p];
|
const maybeNonMemberParticipantId =
|
||||||
const maybeNoMemberParticipantId =
|
|
||||||
participant.identity + ":" + i;
|
participant.identity + ":" + i;
|
||||||
if (!newItems.has(maybeNoMemberParticipantId)) {
|
if (!newItems.has(maybeNonMemberParticipantId)) {
|
||||||
|
const nonMemberId = maybeNonMemberParticipantId;
|
||||||
yield [
|
yield [
|
||||||
maybeNoMemberParticipantId,
|
nonMemberId,
|
||||||
// We create UserMedia with or without a participant.
|
// We create UserMedia with or without a participant.
|
||||||
// This will be the initial value of a BehaviourSubject.
|
// This will be the initial value of a BehaviourSubject.
|
||||||
// Once a participant appears we will update the BehaviourSubject. (see above)
|
// Once a participant appears we will update the BehaviourSubject. (see above)
|
||||||
prevItems.get(maybeNoMemberParticipantId) ??
|
prevItems.get(nonMemberId) ??
|
||||||
new UserMedia(
|
new UserMedia(
|
||||||
maybeNoMemberParticipantId,
|
nonMemberId,
|
||||||
undefined,
|
undefined,
|
||||||
participant,
|
participant,
|
||||||
this.encrypted,
|
this.encrypted,
|
||||||
|
this.matrixRTCSession,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -487,13 +496,18 @@ export class CallViewModel extends ViewModel {
|
|||||||
if (newNonMemberItems.size > 0) {
|
if (newNonMemberItems.size > 0) {
|
||||||
logger.debug("Added NonMember items: ", newNonMemberItems);
|
logger.debug("Added NonMember items: ", newNonMemberItems);
|
||||||
}
|
}
|
||||||
|
const newNonMemberItemCount =
|
||||||
|
newNonMemberItems.size / (1 + duplicateTiles);
|
||||||
|
if (this.nonMemberItemCount.value !== newNonMemberItemCount)
|
||||||
|
this.nonMemberItemCount.next(newNonMemberItemCount);
|
||||||
|
|
||||||
const combinedNew = new Map([
|
const combinedNew = new Map([
|
||||||
...newNonMemberItems.entries(),
|
...newNonMemberItems.entries(),
|
||||||
...newItems.entries(),
|
...newItems.entries(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
for (const [id, t] of prevItems) if (!combinedNew.has(id)) t.destroy();
|
for (const [id, t] of prevItems) if (!combinedNew.has(id)) t.destroy();
|
||||||
return newItems;
|
return combinedNew;
|
||||||
},
|
},
|
||||||
new Map<string, MediaItem>(),
|
new Map<string, MediaItem>(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ import {
|
|||||||
switchMap,
|
switchMap,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import {
|
||||||
|
MatrixRTCSession,
|
||||||
|
MatrixRTCSessionEvent,
|
||||||
|
} from "matrix-js-sdk/src/matrixrtc";
|
||||||
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import { ViewModel } from "./ViewModel";
|
import { ViewModel } from "./ViewModel";
|
||||||
import { useReactiveState } from "../useReactiveState";
|
import { useReactiveState } from "../useReactiveState";
|
||||||
@@ -196,11 +201,16 @@ abstract class BaseUserMediaViewModel extends BaseMediaViewModel {
|
|||||||
*/
|
*/
|
||||||
public readonly cropVideo: Observable<boolean> = this._cropVideo;
|
public readonly cropVideo: Observable<boolean> = this._cropVideo;
|
||||||
|
|
||||||
|
public readonly keys = new BehaviorSubject(
|
||||||
|
[] as { index: number; key: Uint8Array }[],
|
||||||
|
);
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
id: string,
|
id: string,
|
||||||
member: RoomMember | undefined,
|
member: RoomMember | undefined,
|
||||||
participant: Observable<LocalParticipant | RemoteParticipant | undefined>,
|
participant: Observable<LocalParticipant | RemoteParticipant | undefined>,
|
||||||
encryptionSystem: EncryptionSystem,
|
encryptionSystem: EncryptionSystem,
|
||||||
|
rtcSession: MatrixRTCSession,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
id,
|
id,
|
||||||
@@ -211,7 +221,18 @@ abstract class BaseUserMediaViewModel extends BaseMediaViewModel {
|
|||||||
Track.Source.Camera,
|
Track.Source.Camera,
|
||||||
);
|
);
|
||||||
|
|
||||||
// const media = observeParticipantMedia(participant).pipe(this.scope.state());
|
// rtcSession.on(
|
||||||
|
// MatrixRTCSessionEvent.EncryptionKeyChanged,
|
||||||
|
// (key, index, participantId) => {
|
||||||
|
// if (id.startsWith(participantId))
|
||||||
|
// logger.info("got new keys: ", participant, { index, key });
|
||||||
|
// logger.info("All keys for participant ", participant, " - ", [
|
||||||
|
// ...this.keys.value,
|
||||||
|
// { index, key },
|
||||||
|
// ]);
|
||||||
|
// this.keys.next([...this.keys.value, { index, key }]);
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
const media = participant.pipe(
|
const media = participant.pipe(
|
||||||
switchMap((p) => (p && observeParticipantMedia(p)) ?? of(undefined)),
|
switchMap((p) => (p && observeParticipantMedia(p)) ?? of(undefined)),
|
||||||
@@ -263,8 +284,9 @@ export class LocalUserMediaViewModel extends BaseUserMediaViewModel {
|
|||||||
member: RoomMember | undefined,
|
member: RoomMember | undefined,
|
||||||
participant: Observable<LocalParticipant | undefined>,
|
participant: Observable<LocalParticipant | undefined>,
|
||||||
encryptionSystem: EncryptionSystem,
|
encryptionSystem: EncryptionSystem,
|
||||||
|
rtcSession: MatrixRTCSession,
|
||||||
) {
|
) {
|
||||||
super(id, member, participant, encryptionSystem);
|
super(id, member, participant, encryptionSystem, rtcSession);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,8 +345,9 @@ export class RemoteUserMediaViewModel extends BaseUserMediaViewModel {
|
|||||||
member: RoomMember | undefined,
|
member: RoomMember | undefined,
|
||||||
participant: Observable<RemoteParticipant | undefined>,
|
participant: Observable<RemoteParticipant | undefined>,
|
||||||
encryptionSystem: EncryptionSystem,
|
encryptionSystem: EncryptionSystem,
|
||||||
|
rtcSession: MatrixRTCSession,
|
||||||
) {
|
) {
|
||||||
super(id, member, participant, encryptionSystem);
|
super(id, member, participant, encryptionSystem, rtcSession);
|
||||||
|
|
||||||
// Sync the local volume with LiveKit
|
// Sync the local volume with LiveKit
|
||||||
combineLatest([
|
combineLatest([
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ const UserMediaTile = forwardRef<HTMLDivElement, UserMediaTileProps>(
|
|||||||
const videoEnabled = useObservableEagerState(vm.videoEnabled);
|
const videoEnabled = useObservableEagerState(vm.videoEnabled);
|
||||||
const speaking = useObservableEagerState(vm.speaking);
|
const speaking = useObservableEagerState(vm.speaking);
|
||||||
const cropVideo = useObservableEagerState(vm.cropVideo);
|
const cropVideo = useObservableEagerState(vm.cropVideo);
|
||||||
|
const keys = useObservableEagerState(vm.keys);
|
||||||
const isRTCParticipantAvailable = useObservableEagerState(
|
const isRTCParticipantAvailable = useObservableEagerState(
|
||||||
vm.isRTCParticipantAvailable,
|
vm.isRTCParticipantAvailable,
|
||||||
);
|
);
|
||||||
@@ -121,6 +122,7 @@ const UserMediaTile = forwardRef<HTMLDivElement, UserMediaTileProps>(
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
video={video}
|
video={video}
|
||||||
member={vm.member}
|
member={vm.member}
|
||||||
|
keys={keys}
|
||||||
unencryptedWarning={unencryptedWarning}
|
unencryptedWarning={unencryptedWarning}
|
||||||
videoEnabled={videoEnabled && showVideo}
|
videoEnabled={videoEnabled && showVideo}
|
||||||
videoFit={cropVideo ? "cover" : "contain"}
|
videoFit={cropVideo ? "cover" : "contain"}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ interface Props extends ComponentProps<typeof animated.div> {
|
|||||||
videoFit: "cover" | "contain";
|
videoFit: "cover" | "contain";
|
||||||
mirror: boolean;
|
mirror: boolean;
|
||||||
member: RoomMember | undefined;
|
member: RoomMember | undefined;
|
||||||
|
keys: { index: number; key: Uint8Array }[];
|
||||||
videoEnabled: boolean;
|
videoEnabled: boolean;
|
||||||
unencryptedWarning: boolean;
|
unencryptedWarning: boolean;
|
||||||
nameTagLeadingIcon?: ReactNode;
|
nameTagLeadingIcon?: ReactNode;
|
||||||
@@ -48,6 +49,7 @@ export const MediaView = forwardRef<HTMLDivElement, Props>(
|
|||||||
videoFit,
|
videoFit,
|
||||||
mirror,
|
mirror,
|
||||||
member,
|
member,
|
||||||
|
keys,
|
||||||
videoEnabled,
|
videoEnabled,
|
||||||
unencryptedWarning,
|
unencryptedWarning,
|
||||||
nameTagLeadingIcon,
|
nameTagLeadingIcon,
|
||||||
@@ -98,11 +100,18 @@ export const MediaView = forwardRef<HTMLDivElement, Props>(
|
|||||||
minature={avatarSize < 96}
|
minature={avatarSize < 96}
|
||||||
showTimer={handRaiseTimerVisible}
|
showTimer={handRaiseTimerVisible}
|
||||||
/>
|
/>
|
||||||
|
{/* {keys &&
|
||||||
|
keys.map(({ index, key }) => (
|
||||||
|
<Text as="span" size="sm">
|
||||||
|
index:{index}, key:{key}
|
||||||
|
</Text>
|
||||||
|
))} */}
|
||||||
<div className={styles.nameTag}>
|
<div className={styles.nameTag}>
|
||||||
{nameTagLeadingIcon}
|
{nameTagLeadingIcon}
|
||||||
<Text as="span" size="sm" weight="medium" className={styles.name}>
|
<Text as="span" size="sm" weight="medium" className={styles.name}>
|
||||||
{displayName}
|
{displayName}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{unencryptedWarning && (
|
{unencryptedWarning && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
label={t("common.unencrypted")}
|
label={t("common.unencrypted")}
|
||||||
|
|||||||
Reference in New Issue
Block a user