This commit is contained in:
Timo K
2026-05-15 18:37:25 +02:00
parent e10bc6c7cf
commit 88f660e43f
12 changed files with 192 additions and 118 deletions

View File

@@ -15,6 +15,7 @@ import {
} from "livekit-client";
import { type Room as MatrixRoom } from "matrix-js-sdk";
import {
BehaviorSubject,
catchError,
combineLatest,
distinctUntilChanged,
@@ -352,6 +353,9 @@ export interface CallViewModel {
showHeader$: Behavior<boolean>;
showFooter$: Behavior<boolean>;
settingsOpen$: Behavior<boolean>;
setSettingsOpen$: Behavior<(open: boolean) => void>;
// audio routing
/**
* Whether audio is currently being output through the earpiece.
@@ -1332,6 +1336,7 @@ export function createCallViewModel$(
const showFooterUrlParams = !(
urlParams.header === HeaderStyle.None && urlParams.showControls === false
);
// candidat to move into the FooterViewModel
const showFooterLayout$ = scope.behavior<boolean>(
windowMode$.pipe(
switchMap((mode) => {
@@ -1386,11 +1391,18 @@ export function createCallViewModel$(
}),
),
);
// candidat to move into the FooterViewModel
const showFooter$ = scope.behavior(
showFooterLayout$.pipe(
map((showFooter) => showFooter && showFooterUrlParams),
),
);
const settingsOpen$ = new BehaviorSubject(false);
const setSettingsOpen$ = constant((open: boolean) => {
settingsOpen$.next(open);
});
/**
* Whether audio is currently being output through the earpiece.
*/
@@ -1622,6 +1634,8 @@ export function createCallViewModel$(
showSpeakingIndicators$: showSpeakingIndicators$,
showHeader$: showHeader$,
showFooter$: showFooter$,
settingsOpen$: settingsOpen$,
setSettingsOpen$: setSettingsOpen$,
earpieceMode$: earpieceMode$,
audioOutputSwitcher$: audioOutputSwitcher$,
reconnecting$: localMembership.reconnecting$,

View File

@@ -6,26 +6,14 @@ Please see LICENSE in the repository root for full details.
*/
import { BehaviorSubject } from "rxjs";
import { useState, useEffect } from "react";
import { useBehavior } from "../useBehavior";
import { type Behavior } from "./Behavior";
export type ViewModel<Snapshot> = {
[K in keyof Snapshot as `${string & K}$`]: Behavior<Snapshot[K]>;
};
export function useViewModel<Snapshot>(vm: ViewModel<Snapshot>): Snapshot {
const snapshot = {} as Snapshot;
for (const key in vm) {
const value$ = (vm as Record<string, Behavior<unknown>>)[key];
const snapshotKey = key.slice(0, -1) as keyof Snapshot;
// we allow using hooks in a loop here because we know the shape of the vm is static and won't change between renders, so the order of hooks calls will always be the same.
// eslint-disable-next-line react-hooks/rules-of-hooks
snapshot[snapshotKey] = useBehavior(value$) as Snapshot[keyof Snapshot];
}
return snapshot;
}
/**
* This allows to build a view model (or Partial view model)
* with BehaviorSubjects.
@@ -45,3 +33,17 @@ export function createStaticViewModel<Snapshot>(
}
return vm;
}
export function useStaticViewModel<Snapshot>(
snapshot: Snapshot,
): ViewModel<Snapshot> {
const [vm] = useState(createStaticViewModel(snapshot));
useEffect(() => {
for (const key in snapshot) {
(vm as unknown as Record<string, BehaviorSubject<unknown>>)[
`${key}$`
].next(snapshot[key]);
}
}, [snapshot, vm]);
return vm;
}