Show the wait for the first background effect on its tile

- The first effect chosen in a session shows a spinner on its own tile,
  in place of the tick, until a frame carrying it is drawn. Later changes
  show nothing, having nothing to prepare.
- Ended by the frame, not the promises, which resolve while the segmenter
  is still being built. The transformer reports the first frame that went
  through the segmenter; one passed through untouched doesn't count.
- The pipeline publishes the wait with its state, and both footer view
  models take it as an input.
- The lobby tests' provider mock gains the observable hook, built once: a
  fresh observable per render rebuilt the footer on every render.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
fkwp
2026-10-08 14:35:23 +02:00
co-authored by Claude Opus 5.5
parent 00402b54b5
commit deef868cd0
16 changed files with 231 additions and 29 deletions
+12 -1
View File
@@ -24,6 +24,7 @@ import {
type LocalVideoTrack,
Track,
} from "livekit-client";
import { map } from "rxjs";
import inCallStyles from "./InCallView.module.css";
import styles from "./LobbyView.module.css";
@@ -41,6 +42,7 @@ import { ObservableScope } from "../state/ObservableScope";
import { useInitial } from "../useInitial";
import {
useBackgroundEffects,
useBackgroundEffectsState$,
useSyncBackgroundEffects,
} from "../livekit/BackgroundEffectsContext";
import { getValue } from "../utils/observable";
@@ -137,6 +139,7 @@ export const LobbyView: FC<Props> = ({
);
const { processor } = useBackgroundEffects();
const backgroundEffectsState$ = useBackgroundEffectsState$();
const initialProcessor = useInitial(() => processor);
const localTrackOptions = useMemo<CreateLocalTracksOptions>(
@@ -195,6 +198,7 @@ export const LobbyView: FC<Props> = ({
footerScope,
muteStates,
devices,
backgroundEffectsState$.pipe(map(({ settling }) => settling ?? false)),
openSettings,
hangup,
// Logo and header are connected: only show the logo in SPA with header.
@@ -204,7 +208,14 @@ export const LobbyView: FC<Props> = ({
return (): void => {
footerScope.end();
};
}, [devices, hangup, hideHeader, muteStates, openSettings]);
}, [
devices,
backgroundEffectsState$,
hangup,
hideHeader,
muteStates,
openSettings,
]);
// TODO: Unify this component with InCallView, so we can get slick joining
// animations and don't have to feel bad about reusing its CSS