Use finnish notation for observables (#2905)

To help make our usage of the observables more readable/intuitive.
This commit is contained in:
Hugh Nimmo-Smith
2024-12-17 04:01:56 +00:00
committed by GitHub
parent e4bd9d7cf9
commit 79c40f198c
30 changed files with 491 additions and 490 deletions

View File

@@ -100,13 +100,13 @@ function getMockEnv(
): {
vm: CallViewModel;
session: MockRTCSession;
remoteRtcMemberships: BehaviorSubject<CallMembership[]>;
remoteRtcMemberships$: BehaviorSubject<CallMembership[]>;
} {
const matrixRoomMembers = new Map(members.map((p) => [p.userId, p]));
const remoteParticipants = of([aliceParticipant]);
const remoteParticipants$ = of([aliceParticipant]);
const liveKitRoom = mockLivekitRoom(
{ localParticipant },
{ remoteParticipants },
{ remoteParticipants$ },
);
const matrixRoom = mockMatrixRoom({
client: {
@@ -118,14 +118,14 @@ function getMockEnv(
getMember: (userId) => matrixRoomMembers.get(userId) ?? null,
});
const remoteRtcMemberships = new BehaviorSubject<CallMembership[]>(
const remoteRtcMemberships$ = new BehaviorSubject<CallMembership[]>(
initialRemoteRtcMemberships,
);
const session = new MockRTCSession(
matrixRoom,
localRtcMember,
).withMemberships(remoteRtcMemberships);
).withMemberships(remoteRtcMemberships$);
const vm = new CallViewModel(
session as unknown as MatrixRTCSession,
@@ -135,7 +135,7 @@ function getMockEnv(
},
of(ConnectionState.Connected),
);
return { vm, session, remoteRtcMemberships };
return { vm, session, remoteRtcMemberships$ };
}
/**
@@ -146,33 +146,33 @@ function getMockEnv(
* a noise every time.
*/
test("plays one sound when entering a call", () => {
const { session, vm, remoteRtcMemberships } = getMockEnv([local, alice]);
const { session, vm, remoteRtcMemberships$ } = getMockEnv([local, alice]);
render(<TestComponent rtcSession={session} vm={vm} />);
// Joining a call usually means remote participants are added later.
act(() => {
remoteRtcMemberships.next([aliceRtcMember, bobRtcMember]);
remoteRtcMemberships$.next([aliceRtcMember, bobRtcMember]);
});
expect(playSound).toHaveBeenCalledOnce();
});
// TODO: Same test?
test("plays a sound when a user joins", () => {
const { session, vm, remoteRtcMemberships } = getMockEnv([local, alice]);
const { session, vm, remoteRtcMemberships$ } = getMockEnv([local, alice]);
render(<TestComponent rtcSession={session} vm={vm} />);
act(() => {
remoteRtcMemberships.next([aliceRtcMember, bobRtcMember]);
remoteRtcMemberships$.next([aliceRtcMember, bobRtcMember]);
});
// Play a sound when joining a call.
expect(playSound).toBeCalledWith("join");
});
test("plays a sound when a user leaves", () => {
const { session, vm, remoteRtcMemberships } = getMockEnv([local, alice]);
const { session, vm, remoteRtcMemberships$ } = getMockEnv([local, alice]);
render(<TestComponent rtcSession={session} vm={vm} />);
act(() => {
remoteRtcMemberships.next([]);
remoteRtcMemberships$.next([]);
});
expect(playSound).toBeCalledWith("left");
});
@@ -185,7 +185,7 @@ test("plays no sound when the participant list is more than the maximum size", (
);
}
const { session, vm, remoteRtcMemberships } = getMockEnv(
const { session, vm, remoteRtcMemberships$ } = getMockEnv(
[local, alice],
mockRtcMemberships,
);
@@ -193,7 +193,7 @@ test("plays no sound when the participant list is more than the maximum size", (
render(<TestComponent rtcSession={session} vm={vm} />);
expect(playSound).not.toBeCalled();
act(() => {
remoteRtcMemberships.next(
remoteRtcMemberships$.next(
mockRtcMemberships.slice(0, MAX_PARTICIPANT_COUNT_FOR_SOUND - 1),
);
});

View File

@@ -65,7 +65,7 @@ export function CallEventAudioRenderer({
}, [audioEngineRef, previousRaisedHandCount, raisedHandCount]);
useEffect(() => {
const joinSub = vm.memberChanges
const joinSub = vm.memberChanges$
.pipe(
filter(
({ joined, ids }) =>
@@ -77,7 +77,7 @@ export function CallEventAudioRenderer({
void audioEngineRef.current?.playSound("join");
});
const leftSub = vm.memberChanges
const leftSub = vm.memberChanges$
.pipe(
filter(
({ ids, left }) =>

View File

@@ -110,8 +110,8 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
sfuConfig,
props.e2eeSystem,
);
const connStateObservable = useObservable(
(inputs) => inputs.pipe(map(([connState]) => connState)),
const connStateObservable$ = useObservable(
(inputs$) => inputs$.pipe(map(([connState]) => connState)),
[connState],
);
const [vm, setVm] = useState<CallViewModel | null>(null);
@@ -131,12 +131,12 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
props.rtcSession,
livekitRoom,
props.e2eeSystem,
connStateObservable,
connStateObservable$,
);
setVm(vm);
return (): void => vm.destroy();
}
}, [props.rtcSession, livekitRoom, props.e2eeSystem, connStateObservable]);
}, [props.rtcSession, livekitRoom, props.e2eeSystem, connStateObservable$]);
if (livekitRoom === undefined || vm === null) return null;
@@ -225,14 +225,14 @@ export const InCallView: FC<InCallViewProps> = ({
() => void toggleRaisedHand(),
);
const windowMode = useObservableEagerState(vm.windowMode);
const layout = useObservableEagerState(vm.layout);
const tileStoreGeneration = useObservableEagerState(vm.tileStoreGeneration);
const windowMode = useObservableEagerState(vm.windowMode$);
const layout = useObservableEagerState(vm.layout$);
const tileStoreGeneration = useObservableEagerState(vm.tileStoreGeneration$);
const [debugTileLayout] = useSetting(debugTileLayoutSetting);
const gridMode = useObservableEagerState(vm.gridMode);
const showHeader = useObservableEagerState(vm.showHeader);
const showFooter = useObservableEagerState(vm.showFooter);
const switchCamera = useSwitchCamera(vm.localVideo);
const gridMode = useObservableEagerState(vm.gridMode$);
const showHeader = useObservableEagerState(vm.showHeader$);
const showFooter = useObservableEagerState(vm.showFooter$);
const switchCamera = useSwitchCamera(vm.localVideo$);
// Ideally we could detect taps by listening for click events and checking
// that the pointerType of the event is "touch", but this isn't yet supported
@@ -317,15 +317,15 @@ export const InCallView: FC<InCallViewProps> = ({
windowMode,
],
);
const gridBoundsObservable = useObservable(
(inputs) => inputs.pipe(map(([gridBounds]) => gridBounds)),
const gridBoundsObservable$ = useObservable(
(inputs$) => inputs$.pipe(map(([gridBounds]) => gridBounds)),
[gridBounds],
);
const spotlightAlignment = useInitial(
const spotlightAlignment$ = useInitial(
() => new BehaviorSubject(defaultSpotlightAlignment),
);
const pipAlignment = useInitial(
const pipAlignment$ = useInitial(
() => new BehaviorSubject(defaultPipAlignment),
);
@@ -383,15 +383,17 @@ export const InCallView: FC<InCallViewProps> = ({
{ className, style, targetWidth, targetHeight, model },
ref,
) {
const spotlightExpanded = useObservableEagerState(vm.spotlightExpanded);
const spotlightExpanded = useObservableEagerState(
vm.spotlightExpanded$,
);
const onToggleExpanded = useObservableEagerState(
vm.toggleSpotlightExpanded,
vm.toggleSpotlightExpanded$,
);
const showSpeakingIndicatorsValue = useObservableEagerState(
vm.showSpeakingIndicators,
vm.showSpeakingIndicators$,
);
const showSpotlightIndicatorsValue = useObservableEagerState(
vm.showSpotlightIndicators,
vm.showSpotlightIndicators$,
);
return model instanceof GridTileViewModel ? (
@@ -424,9 +426,9 @@ export const InCallView: FC<InCallViewProps> = ({
const layouts = useMemo(() => {
const inputs = {
minBounds: gridBoundsObservable,
spotlightAlignment,
pipAlignment,
minBounds$: gridBoundsObservable$,
spotlightAlignment$,
pipAlignment$,
};
return {
grid: makeGridLayout(inputs),
@@ -435,7 +437,7 @@ export const InCallView: FC<InCallViewProps> = ({
"spotlight-expanded": makeSpotlightExpandedLayout(inputs),
"one-on-one": makeOneOnOneLayout(inputs),
};
}, [gridBoundsObservable, spotlightAlignment, pipAlignment]);
}, [gridBoundsObservable$, spotlightAlignment$, pipAlignment$]);
const renderContent = (): JSX.Element => {
if (layout.type === "pip") {

View File

@@ -148,7 +148,7 @@ export const LobbyView: FC<Props> = ({
const switchCamera = useSwitchCamera(
useObservable(
(inputs) => inputs.pipe(map(([video]) => video)),
(inputs$) => inputs$.pipe(map(([video]) => video)),
[videoTrack],
),
);

View File

@@ -31,17 +31,17 @@ import { useLatest } from "../useLatest";
* producing a callback if so.
*/
export function useSwitchCamera(
video: Observable<LocalVideoTrack | null>,
video$: Observable<LocalVideoTrack | null>,
): (() => void) | null {
const mediaDevices = useMediaDevices();
const setVideoInput = useLatest(mediaDevices.videoInput.select);
// Produce an observable like the input 'video' observable, except make it
// emit whenever the track is muted or the device changes
const videoTrack: Observable<LocalVideoTrack | null> = useObservable(
(inputs) =>
inputs.pipe(
switchMap(([video]) => video),
const videoTrack$: Observable<LocalVideoTrack | null> = useObservable(
(inputs$) =>
inputs$.pipe(
switchMap(([video$]) => video$),
switchMap((video) => {
if (video === null) return of(null);
return merge(
@@ -53,15 +53,15 @@ export function useSwitchCamera(
);
}),
),
[video],
[video$],
);
const switchCamera: Observable<(() => void) | null> = useObservable(
(inputs) =>
const switchCamera$: Observable<(() => void) | null> = useObservable(
(inputs$) =>
platform === "desktop"
? of(null)
: inputs.pipe(
switchMap(([track]) => track),
: inputs$.pipe(
switchMap(([track$]) => track$),
map((track) => {
if (track === null) return null;
const facingMode = facingModeFromLocalTrack(track).facingMode;
@@ -86,8 +86,8 @@ export function useSwitchCamera(
);
}),
),
[videoTrack],
[videoTrack$],
);
return useObservableEagerState(switchCamera);
return useObservableEagerState(switchCamera$);
}