mirror of
https://github.com/vector-im/element-call.git
synced 2026-06-30 18:02:56 +00:00
Merge pull request #4054 from element-hq/johannes/pip-border
Add PiP border in 1on1 layouts
This commit is contained in:
@@ -74,6 +74,7 @@ import {
|
||||
useAppBarSubtitle,
|
||||
} from "../AppBar.tsx";
|
||||
import { useBehavior } from "../useBehavior.ts";
|
||||
import { constant } from "../state/Behavior.ts";
|
||||
import { Toast } from "../Toast.tsx";
|
||||
import overlayStyles from "../Overlay.module.css";
|
||||
import { useTrackProcessorObservable$ } from "../livekit/TrackProcessorContext.tsx";
|
||||
@@ -433,6 +434,11 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
const showSpeakingIndicators = useBehavior(vm.showSpeakingIndicators$);
|
||||
const showNameTags = useBehavior(vm.showNameTags$);
|
||||
const showRingingStatus = vm.ringingStatusLocation === "tile";
|
||||
const showOutline = useBehavior(
|
||||
model instanceof GridTileViewModel
|
||||
? model.showOutline$
|
||||
: constant(false),
|
||||
);
|
||||
|
||||
return model instanceof GridTileViewModel ? (
|
||||
<GridTile
|
||||
@@ -446,6 +452,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
showSpeakingIndicators={showSpeakingIndicators}
|
||||
showNameTags={showNameTags}
|
||||
showRingingStatus={showRingingStatus}
|
||||
showOutline={showOutline}
|
||||
focusable={!contentObscured}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -155,6 +155,7 @@ import {
|
||||
createRingingMedia,
|
||||
type RingingMediaViewModel,
|
||||
} from "../media/RingingMediaViewModel.ts";
|
||||
import { type GridTileViewModel } from "../TileViewModel.ts";
|
||||
|
||||
const logger = rootLogger.getChild("[CallViewModel]");
|
||||
//TODO
|
||||
@@ -1482,6 +1483,7 @@ export function createCallViewModel$(
|
||||
({ tiles: prevTiles }, [media, visibleTiles]) => {
|
||||
let layout: Layout;
|
||||
let newTiles: TileStore;
|
||||
let pip: GridTileViewModel | undefined;
|
||||
switch (media.type) {
|
||||
case "grid":
|
||||
case "spotlight-landscape":
|
||||
@@ -1507,6 +1509,7 @@ export function createCallViewModel$(
|
||||
landscapePipAlignment$,
|
||||
prevTiles,
|
||||
);
|
||||
pip = layout.pip;
|
||||
break;
|
||||
case "one-on-one-portrait":
|
||||
[layout, newTiles] = oneOnOnePortraitLayout(
|
||||
@@ -1515,12 +1518,17 @@ export function createCallViewModel$(
|
||||
portraitPipAlignment$,
|
||||
prevTiles,
|
||||
);
|
||||
pip = layout.pip;
|
||||
break;
|
||||
case "pip":
|
||||
[layout, newTiles] = pipLayout(media, prevTiles);
|
||||
break;
|
||||
}
|
||||
|
||||
for (const tile of newTiles.gridTiles) {
|
||||
tile.setShowOutline(tile === pip);
|
||||
}
|
||||
|
||||
return { layout, tiles: newTiles };
|
||||
},
|
||||
{ layout: null, tiles: TileStore.empty() },
|
||||
|
||||
@@ -5,6 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { type Behavior } from "./Behavior";
|
||||
import { type MediaViewModel } from "./media/MediaViewModel";
|
||||
import { type RingingMediaViewModel } from "./media/RingingMediaViewModel";
|
||||
@@ -17,12 +19,18 @@ function createId(): string {
|
||||
|
||||
export class GridTileViewModel {
|
||||
public readonly id = createId();
|
||||
private readonly _showOutline$ = new BehaviorSubject(false);
|
||||
public readonly showOutline$: Behavior<boolean> = this._showOutline$;
|
||||
|
||||
public constructor(
|
||||
public readonly media$: Behavior<
|
||||
UserMediaViewModel | RingingMediaViewModel
|
||||
>,
|
||||
) {}
|
||||
|
||||
public setShowOutline(value: boolean): void {
|
||||
this._showOutline$.next(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class SpotlightTileViewModel {
|
||||
|
||||
@@ -66,6 +66,11 @@ borders don't support gradients */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tile.outline {
|
||||
outline: var(--cpd-border-width-1) solid
|
||||
var(--cpd-color-border-interactive-secondary);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.tile:hover {
|
||||
outline: var(--cpd-border-width-2) solid
|
||||
|
||||
@@ -78,6 +78,7 @@ test("GridTile is accessible", async () => {
|
||||
showSpeakingIndicators
|
||||
showNameTags
|
||||
showRingingStatus
|
||||
showOutline
|
||||
focusable
|
||||
/>
|
||||
</ReactionsSenderProvider>,
|
||||
@@ -110,6 +111,7 @@ test("GridTile displays ringing media", async () => {
|
||||
showSpeakingIndicators
|
||||
showNameTags
|
||||
showRingingStatus
|
||||
showOutline
|
||||
focusable
|
||||
/>
|
||||
</ReactionsSenderProvider>,
|
||||
|
||||
@@ -398,6 +398,7 @@ interface GridTileProps {
|
||||
showSpeakingIndicators: boolean;
|
||||
showNameTags: boolean;
|
||||
showRingingStatus: boolean;
|
||||
showOutline: boolean;
|
||||
focusable: boolean;
|
||||
}
|
||||
|
||||
@@ -406,7 +407,9 @@ export const GridTile: FC<GridTileProps> = ({
|
||||
vm,
|
||||
showSpeakingIndicators,
|
||||
showRingingStatus,
|
||||
showOutline,
|
||||
onOpenProfile,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const ourRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -423,6 +426,7 @@ export const GridTile: FC<GridTileProps> = ({
|
||||
displayName={displayName}
|
||||
mxcAvatarUrl={mxcAvatarUrl}
|
||||
showStatus={showRingingStatus}
|
||||
className={classNames(className, { [styles.outline]: showOutline })}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@@ -435,6 +439,7 @@ export const GridTile: FC<GridTileProps> = ({
|
||||
onOpenProfile={onOpenProfile}
|
||||
displayName={displayName}
|
||||
mxcAvatarUrl={mxcAvatarUrl}
|
||||
className={classNames(className, { [styles.outline]: showOutline })}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@@ -446,6 +451,7 @@ export const GridTile: FC<GridTileProps> = ({
|
||||
showSpeakingIndicators={showSpeakingIndicators}
|
||||
displayName={displayName}
|
||||
mxcAvatarUrl={mxcAvatarUrl}
|
||||
className={classNames(className, { [styles.outline]: showOutline })}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user