Skip to content

Commit b036bb4

Browse files
committed
Introduce condigurable auto leave option
1 parent 30eea63 commit b036bb4

File tree

2 files changed

+56
-26
lines changed

2 files changed

+56
-26
lines changed

src/room/InCallView.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ import useMeasure from "react-use-measure";
2525
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
2626
import classNames from "classnames";
2727
import { BehaviorSubject, map } from "rxjs";
28-
import { useObservable, useObservableEagerState } from "observable-hooks";
28+
import {
29+
useObservable,
30+
useObservableEagerState,
31+
useSubscription,
32+
} from "observable-hooks";
2933
import { logger } from "matrix-js-sdk/lib/logger";
3034
import { RoomAndToDeviceEvents } from "matrix-js-sdk/lib/matrixrtc/RoomAndToDeviceKeyTransport";
3135
import {
@@ -165,7 +169,10 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
165169
props.rtcSession,
166170
livekitRoom,
167171
mediaDevices,
168-
props.e2eeSystem,
172+
{
173+
encryptionSystem: props.e2eeSystem,
174+
autoLeaveWhenOthersLeft: undefined,
175+
},
169176
connStateObservable$,
170177
reactionsReader.raisedHands$,
171178
reactionsReader.reactions$,
@@ -302,6 +309,8 @@ export const InCallView: FC<InCallViewProps> = ({
302309
() => void toggleRaisedHand(),
303310
);
304311

312+
useSubscription(vm.autoLeaveWhenOthersLeft$, onLeave);
313+
305314
const windowMode = useObservableEagerState(vm.windowMode$);
306315
const layout = useObservableEagerState(vm.layout$);
307316
const tileStoreGeneration = useObservableEagerState(vm.tileStoreGeneration$);

src/state/CallViewModel.ts

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ import { shallowEquals } from "../utils/array";
9595
import { calculateDisplayName, shouldDisambiguate } from "../utils/displayname";
9696
import { type MediaDevices } from "./MediaDevices";
9797

98+
interface CallViewModelOptions {
99+
encryptionSystem: EncryptionSystem;
100+
autoLeaveWhenOthersLeft?: boolean;
101+
}
98102
// How long we wait after a focus switch before showing the real participant
99103
// list again
100104
const POST_FOCUS_PARTICIPANT_UPDATE_DELAY_MS = 3000;
@@ -461,21 +465,27 @@ export class CallViewModel extends ViewModel {
461465
},
462466
);
463467

464-
/**
465-
* Displaynames for each member of the call. This will disambiguate
466-
* any displaynames that clashes with another member. Only members
467-
* joined to the call are considered here.
468-
*/
469-
public readonly memberDisplaynames$ = merge(
468+
private readonly memberships$: Observable<CallMembership[]> = merge(
470469
// Handle call membership changes.
471470
fromEvent(this.matrixRTCSession, MatrixRTCSessionEvent.MembershipsChanged),
472471
// Handle room membership changes (and displayname updates)
473472
fromEvent(this.matrixRTCSession.room, RoomStateEvent.Members),
474473
).pipe(
475-
startWith(null),
474+
startWith(this.matrixRTCSession.memberships),
476475
map(() => {
476+
return this.matrixRTCSession.memberships;
477+
}),
478+
);
479+
480+
/**
481+
* Displaynames for each member of the call. This will disambiguate
482+
* any displaynames that clashes with another member. Only members
483+
* joined to the call are considered here.
484+
*/
485+
public readonly memberDisplaynames$ = this.memberships$.pipe(
486+
map((memberships) => {
477487
const displaynameMap = new Map<string, string>();
478-
const { room, memberships } = this.matrixRTCSession;
488+
const { room } = this.matrixRTCSession;
479489

480490
// We only consider RTC members for disambiguation as they are the only visible members.
481491
for (const rtcMember of memberships) {
@@ -577,7 +587,7 @@ export class CallViewModel extends ViewModel {
577587
indexedMediaId,
578588
member,
579589
participant,
580-
this.encryptionSystem,
590+
this.options.encryptionSystem,
581591
this.livekitRoom,
582592
this.memberDisplaynames$.pipe(
583593
map((m) => m.get(matrixIdentifier) ?? "[👻]"),
@@ -600,7 +610,7 @@ export class CallViewModel extends ViewModel {
600610
screenShareId,
601611
member,
602612
participant,
603-
this.encryptionSystem,
613+
this.options.encryptionSystem,
604614
this.livekitRoom,
605615
this.memberDisplaynames$.pipe(
606616
map((m) => m.get(matrixIdentifier) ?? "[👻]"),
@@ -641,7 +651,7 @@ export class CallViewModel extends ViewModel {
641651
nonMemberId,
642652
undefined,
643653
participant,
644-
this.encryptionSystem,
654+
this.options.encryptionSystem,
645655
this.livekitRoom,
646656
this.memberDisplaynames$.pipe(
647657
map((m) => m.get(participant.identity) ?? "[👻]"),
@@ -686,18 +696,29 @@ export class CallViewModel extends ViewModel {
686696
),
687697
);
688698

689-
public readonly memberChanges$ = this.userMedia$
690-
.pipe(map((mediaItems) => mediaItems.map((m) => m.id)))
691-
.pipe(
692-
scan<string[], { ids: string[]; joined: string[]; left: string[] }>(
693-
(prev, ids) => {
694-
const left = prev.ids.filter((id) => !ids.includes(id));
695-
const joined = ids.filter((id) => !prev.ids.includes(id));
696-
return { ids, joined, left };
697-
},
698-
{ ids: [], joined: [], left: [] },
699-
),
700-
);
699+
public readonly memberChanges$ = this.userMedia$.pipe(
700+
map((mediaItems) => mediaItems.map((m) => m.id)),
701+
scan<string[], { ids: string[]; joined: string[]; left: string[] }>(
702+
(prev, ids) => {
703+
const left = prev.ids.filter((id) => !ids.includes(id));
704+
const joined = ids.filter((id) => !prev.ids.includes(id));
705+
return { ids, joined, left };
706+
},
707+
{ ids: [], joined: [], left: [] },
708+
),
709+
);
710+
711+
public readonly allOthersLeft$ = this.memberChanges$.pipe(
712+
map(({ ids, left }) => ids.length === 0 && left.length > 0),
713+
startWith(false),
714+
distinctUntilChanged(),
715+
);
716+
717+
public readonly autoLeaveWhenOthersLeft$ = this.allOthersLeft$.pipe(
718+
distinctUntilChanged(),
719+
filter((leave) => (leave && this.options.autoLeaveWhenOthersLeft) ?? false),
720+
map(() => {}),
721+
);
701722

702723
/**
703724
* List of MediaItems that we want to display, that are of type ScreenShare
@@ -1383,7 +1404,7 @@ export class CallViewModel extends ViewModel {
13831404
private readonly matrixRTCSession: MatrixRTCSession,
13841405
private readonly livekitRoom: LivekitRoom,
13851406
private readonly mediaDevices: MediaDevices,
1386-
private readonly encryptionSystem: EncryptionSystem,
1407+
private readonly options: CallViewModelOptions,
13871408
private readonly connectionState$: Observable<ECConnectionState>,
13881409
private readonly handsRaisedSubject$: Observable<
13891410
Record<string, RaisedHandInfo>

0 commit comments

Comments
 (0)