- A catalogue of what can be chosen: no effect, blur, and two shipped
backgrounds, the app's own gradients flattened onto its canvas colour.
Their ids are what a saved choice stores, so they are named for the
pictures.
- One setting for the choice, typed as the ids an effect can have and
defaulting to blur for anyone who had it on. A stored value we no
longer ship, or one that isn't even a string, reads as no effect: it
comes from storage another build or a hand may have written.
- The pipeline follows it, switching in place to a picture as readily as
to blur, and the camera menu's blur toggle reads and writes it.
- So does Settings' blur checkbox: a picture reads as blur off, and
checking it replaces the picture with blur. The old on/off setting is
only read, to carry blur over. First tests for the Settings modal,
which fail with the checkbox on the old setting.
- The transformer's own init loads a picture chosen before it was built,
as the base init does and it had not: the first effect always is, and
the picture was drawn black.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The menu asked the browser; the pipeline asked the browser and for a
desktop. On a phone whose browser can run them, blur was offered and
then refused: the toggle moved and the video did not change.
- Both now ask one function, and it asks the browser alone. The platform
was the wrong measure: a phone on the fast route held 99% of its frame
rate and was refused, a desktop on the slow one held 73% and was
allowed.
- The in-call device switcher is still withheld on a phone; that is the
device menu's own rule and is unchanged.
- The provider tests run as a phone, and fail with the desktop test back.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Give the microphone level its own observable
* Add a microphone level meter
* Show speakers and microphones in the quick audio menu
* Wire speaker selection through the call footer
* Add stories for the meter and the device menu
* Add end-to-end specs for the quick audio menu
* Keep the footer while a menu opened from it is open
* Use the shared audio capture stub in the lobby test
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The view models reached for getUrlParams() — and so window.location —
from deep inside the call path: CallViewModel, MediaDevices, Publisher,
LocalMember and the footer view model. An embedded Element Call has no URL
of its own, so these values have to arrive as arguments instead.
Add the relevant options to CallViewModelOptions, to the MediaDevices and
Publisher constructors, to createLocalMembership$ and enterRTCSession, and
to createCallFooterViewModel. The remaining React consumers read the
context added in the previous commit. AppViewModel now takes its audio
output options too, moving that URL read out to main.tsx, where the app
shell can act as the adapter.
The new CallViewModelOptions fields are optional, defaulting to what the
URL parameters resolve to outside widget mode; the MediaDevices and
Publisher arguments are required, so that every construction site has to
be explicit.
useTheme.test.ts mocked the UrlParams module with a factory, so it needed
updating to mock the hook rather than getUrlParams.
No functional change.
On mobile, the ringing status indicator is supposed to display in the header rather than on a tile. The exact layout differs between Android and iOS. To get it right I had to refactor AppBar to use CSS grid templates.
(Also, I changed my mind about the exact ringing data I needed out of CallViewModel - sorry. A little move of the ringtone audio renderer into its own component was necessary to accommodate that.)