Use an actual one-on-one layout in landscape on mobile

This commit is contained in:
Robin
2026-07-14 16:48:45 +02:00
parent 0b21cff020
commit aa6732da19
2 changed files with 77 additions and 13 deletions

View File

@@ -532,6 +532,58 @@ describe.each([
}); });
}); });
test("landscape mobile layouts show screen shares and group call participants", () => {
withTestScheduler(({ behavior, expectObservable }) => {
// Starts as a one-on-one call, then Alice shares her screen, then Bob
// joins, and finally Alice stops sharing her screen
const participantInputMarbles = " a--b";
const aliceSharingInputMarbles = "ny-n";
// Starts in one-on-one mobile layout, then goes to spotlight layout for
// the screen sharing and group call cases
const expectedLayoutMarbles = " ab-c";
withCallViewModel(
{
remoteParticipants$: behavior(participantInputMarbles, {
a: [aliceParticipant],
b: [aliceParticipant, bobParticipant],
}),
roomMembers: [local, alice, bob],
rtcMembers$: behavior(participantInputMarbles, {
a: [localRtcMember, aliceRtcMember],
b: [localRtcMember, aliceRtcMember, bobRtcMember],
}),
sharingScreen: new Map([
[aliceParticipant, behavior(aliceSharingInputMarbles, yesNo)],
]),
windowSize$: constant({ width: 700, height: 380 }), // Mobile phone in landscape
},
(vm) => {
expectObservable(summarizeLayout$(vm.layout$)).toBe(
expectedLayoutMarbles,
{
a: {
type: "one-on-one-mobile",
spotlight: [`${aliceId}:0`],
pip: undefined,
pipSize: "sm",
},
b: {
type: "spotlight-expanded",
spotlight: [`${aliceId}:0:screen-share`],
pip: `${aliceId}:0`,
},
c: {
type: "spotlight-expanded",
spotlight: [`${aliceId}:0`],
pip: undefined,
},
},
);
},
);
});
});
test("participants stay in the same order unless to appear/disappear", () => { test("participants stay in the same order unless to appear/disappear", () => {
withTestScheduler(({ behavior, schedule, expectObservable }) => { withTestScheduler(({ behavior, schedule, expectObservable }) => {
const visibilityInputMarbles = "a"; const visibilityInputMarbles = "a";
@@ -1066,7 +1118,7 @@ describe.each([
}); });
test("expanded spotlight layout hides PiP tile in one-on-one voice call", () => { test("expanded spotlight layout hides PiP tile in one-on-one voice call", () => {
withTestScheduler(({ expectObservable }) => { withTestScheduler(({ schedule, expectObservable }) => {
withCallViewModel( withCallViewModel(
{ {
remoteParticipants$: constant([aliceParticipant]), remoteParticipants$: constant([aliceParticipant]),
@@ -1076,9 +1128,15 @@ describe.each([
[localParticipant, constant(false)], [localParticipant, constant(false)],
[aliceParticipant, constant(false)], [aliceParticipant, constant(false)],
]), ]),
windowSize$: constant({ width: 700, height: 380 }), // Mobile phone in landscape
}, },
(vm) => { (vm) => {
schedule("s", {
s: () => vm.setGridMode("spotlight"),
});
schedule("a", {
a: () => vm.toggleSpotlightExpanded$.value!(),
});
// Layout should show remote tile only // Layout should show remote tile only
expectObservable(summarizeLayout$(vm.layout$)).toBe("a", { expectObservable(summarizeLayout$(vm.layout$)).toBe("a", {
a: { a: {

View File

@@ -1257,17 +1257,23 @@ export function createCallViewModel$(
), ),
); );
case "flat": case "flat":
return gridMode$.pipe( return oneOnOneMobileLayoutMedia$.pipe(
switchMap((gridMode) => { switchMap((oneOnOne) =>
switch (gridMode) { oneOnOne === null
case "grid": ? gridMode$.pipe(
// Yes, grid mode actually gets you a "spotlight" layout in switchMap((gridMode) => {
// this window mode. switch (gridMode) {
return spotlightLandscapeLayoutMedia$(true); case "grid":
case "spotlight": // Yes, grid mode actually gets you a "spotlight" layout in
return spotlightExpandedLayoutMedia$(true); // this window mode.
} return spotlightLandscapeLayoutMedia$(true);
}), case "spotlight":
return spotlightExpandedLayoutMedia$(true);
}
}),
)
: of(oneOnOne),
),
); );
case "pip": case "pip":
return pipLayoutMedia$; return pipLayoutMedia$;