Add crop to fit toggle to context menu. (#2107)

Signed-off-by: Timo K <toger5@hotmail.de>
This commit is contained in:
Timo
2024-02-12 16:49:32 +01:00
committed by GitHub
parent 242d2dc2bc
commit bcd8890f0a
4 changed files with 38 additions and 1 deletions

View File

@@ -143,6 +143,7 @@
"unmute_microphone_button_label": "Unmute microphone",
"version": "Version: {{version}}",
"video_tile": {
"change_fit_contain": "Crop to fit",
"exit_full_screen": "Exit full screen",
"full_screen": "Full screen",
"mute_for_me": "Mute for me",

View File

@@ -167,6 +167,12 @@ export class UserMediaTileViewModel extends BaseTileViewModel {
*/
public readonly videoEnabled: StateObservable<boolean>;
private readonly _cropVideo = new BehaviorSubject(true);
/**
* Whether the tile video should be contained inside the tile or be cropped to fit.
*/
public readonly cropVideo = state(this._cropVideo);
public constructor(
id: string,
member: RoomMember | undefined,
@@ -205,6 +211,10 @@ export class UserMediaTileViewModel extends BaseTileViewModel {
this._locallyMuted.next(!this._locallyMuted.value);
}
public toggleFitContain(): void {
this._cropVideo.next(!this._cropVideo.value);
}
public setLocalVolume(value: number): void {
this._localVolume.next(value);
}

View File

@@ -73,7 +73,7 @@ borders don't support gradients */
.videoTile video {
inline-size: 100%;
block-size: 100%;
object-fit: cover;
object-fit: contain;
background-color: var(--cpd-color-bg-subtle-primary);
/* This transform is a no-op, but it forces Firefox to use a different
rendering path, one that actually clips the corners of <video> elements into
@@ -89,6 +89,10 @@ borders don't support gradients */
object-fit: contain;
}
.videoTile.cropVideo video {
object-fit: cover;
}
.videoTile.videoMuted video {
display: none;
}

View File

@@ -206,9 +206,16 @@ const UserMediaTile = subscribe<UserMediaTileProps, HTMLDivElement>(
const mirror = useStateObservable(vm.mirror);
const speaking = useStateObservable(vm.speaking);
const locallyMuted = useStateObservable(vm.locallyMuted);
const cropVideo = useStateObservable(vm.cropVideo);
const localVolume = useStateObservable(vm.localVolume);
const onChangeMute = useCallback(() => vm.toggleLocallyMuted(), [vm]);
const onChangeFitContain = useCallback(() => vm.toggleFitContain(), [vm]);
const onSelectMute = useCallback((e: Event) => e.preventDefault(), []);
const onSelectFitContain = useCallback(
(e: Event) => e.preventDefault(),
[],
);
const onChangeLocalVolume = useCallback(
(v: number) => vm.setLocalVolume(v),
[vm],
@@ -225,6 +232,13 @@ const UserMediaTile = subscribe<UserMediaTileProps, HTMLDivElement>(
label={t("common.profile")}
onSelect={onOpenProfile}
/>
<ToggleMenuItem
Icon={ExpandIcon}
label={t("video_tile.change_fit_contain")}
checked={cropVideo}
onChange={onChangeFitContain}
onSelect={onSelectFitContain}
/>
</>
) : (
<>
@@ -235,6 +249,13 @@ const UserMediaTile = subscribe<UserMediaTileProps, HTMLDivElement>(
onChange={onChangeMute}
onSelect={onSelectMute}
/>
<ToggleMenuItem
Icon={ExpandIcon}
label={t("video_tile.change_fit_contain")}
checked={cropVideo}
onChange={onChangeFitContain}
onSelect={onSelectFitContain}
/>
{/* TODO: Figure out how to make this slider keyboard accessible */}
<MenuItem as="div" Icon={VolumeIcon} label={null} onSelect={null}>
<Slider
@@ -257,6 +278,7 @@ const UserMediaTile = subscribe<UserMediaTileProps, HTMLDivElement>(
className={classNames(className, {
[styles.mirror]: mirror,
[styles.speaking]: showSpeakingIndicator && speaking,
[styles.cropVideo]: cropVideo,
})}
style={style}
targetWidth={targetWidth}