Merge upstream element-hq/element-call tag v0.25.0 into the Lotus fork
(previous base: v0.20.1; actual merge-base v0.20.1-rc.1). Every Lotus
feature and all six io.lotus.* widget actions are preserved. Version
bumped to 0.25.0-lotus.1.
Conflict files and how each Lotus hunk was re-expressed:
* src/state/CallViewModel/remoteMembers/ConnectionFactory.ts
Upstream moved echoCancellation/noiseSuppression/autoGainControl from
constructor params (fed by URL params) to persisted Settings
(settings.ts) with a developer-settings UI. The cinny host still drives
these per call via URL params (noiseSuppression=false /
autoGainControl=false when the in-source ML denoiser is active, so the
model gets a raw mic) - taking upstream verbatim would silently break
the ML denoise tier. Re-wired as AND semantics in generateRoomOption():
a constraint is enabled only if BOTH the Setting and the URL param
allow it. Params default to true, so with no params this is
byte-for-byte upstream behaviour. Upstream's own echoCancellation /
noiseSuppression URL params (still parsed but dead in v0.25.0) work
again as a side effect. Lotus autoGainControl URL param kept in
UrlParams.ts (auto-merged, unchanged).
* src/state/CallViewModel/remoteMembers/ECConnectionFactory.test.ts
Took upstream (tests now drive via Settings). The lost Lotus coverage
is restored in a NEW colocated file src/lotus/lotusAudioConstraints.test.ts
(3 tests) so the upstream test file stays pristine. Verified the new
test fails against pure-upstream ConnectionFactory and passes with the
re-wiring.
* src/state/CallViewModel/CallViewModel.ts
Three small hunks: kept both the Lotus `userMedia$` interface member
and upstream's new `keyRotationSuppressed$`; dropped the three Lotus
audio constructor args (mechanism removed upstream, see above); kept
both in the returned object. The [lotus #4] overrideSpotlight$ routing,
manualSpotlightUserId$ and setManualSpotlight auto-merged; verified
against upstream's changed ringingMedia$ (now single-or-null instead
of array) - the merge correctly took upstream's outer branch and the
inner screenShares$/spotlightSpeaker$ logic that lotusSpotlight.ts
mirrors is unchanged upstream.
* src/index.css
Kept both: Lotus lotus-transparent / lotus-theme blocks and upstream's
new body[data-background="gradient"]::before full-viewport gradient.
The naive merge swallowed the closing brace of body.lotus-theme -
restored. Added a rule hiding the new gradient pseudo-element under
body.lotus-transparent, since it would otherwise paint over the
transparent body and hide the host wallpaper.
* src/components/CallFooterViewModel.tsx, src/components/CallFooter.stories.tsx
No Lotus content - pure upstream-vs-upstream conflicts caused by the
merge base being v0.20.1-rc.1. Took upstream (layoutMode ->
layoutSwitchVm; setLayoutMode removed). No Lotus code uses
setGridMode/layoutMode.
Non-conflicting but reviewed:
* src/widget.ts auto-merged cleanly. Upstream's removal of .well-known
transport advertisement and the new RTC-transport capability request
did not touch the action registration loop the LOTUS_TO_WIDGET_ACTIONS
spread and widget.lazyActions ride on - nothing to re-wire.
* src/room/InCallView.tsx, src/useAudioContext.tsx, src/useTheme.ts,
src/tile/MediaView.tsx(+.module.css), src/UrlParams.ts(+test),
all *.module.css and .gitea/workflows/ci.yml auto-merged; each diff
against v0.25.0 was checked to equal the original Lotus hunk.
* src/button/Button.module.css: the merge appended an exact duplicate
of upstream's `.rotate`/`@keyframes spin` block (rc.1 merge-base
artefact) - reset to upstream verbatim.
* src/grid/OneOnOnePortraitLayout.module.css was renamed upstream to
OneOnOneMobileLayout.module.css; git followed the rename and the Lotus
safe-area PiP inset fix applies there (the --content-inset-* vars it
uses still exist upstream).
Tooling changes inherited from upstream that affect the fork:
* eslint + prettier were replaced by oxlint + oxfmt (`pnpm lint:oxlint`,
`pnpm format:check`). oxlint flagged 10 issues, all in src/lotus/*:
8x no-meaningless-void-operator (dropped the `void` before void-typed
widget transport.reply / callbacks - no behaviour change), 1x
consistent-type-imports (lotusWidget.ts: `import type`), and 2x
unicorn/no-useless-spread in lotusAudioInject.ts which are FALSE
POSITIVES - `[...activeClips]` is a required defensive copy because
abort() deletes from the Set during iteration; suppressed with an
explanatory eslint-disable-next-line. oxfmt reformatted 7 Lotus
touched files (whitespace only).
* packageManager bumped by upstream to pnpm@11.21.0, which requires
Node >= 22.13 (uses node:sqlite). Node 20 cannot run it; pnpm 10.33
cannot read the new lockfile either (matrix-js-sdk is now a git
dependency on develop, using a version-union pnpm 10 rejects). Fork CI
already uses Node 24 (.node-version), so CI is unaffected.
* matrix-js-sdk is now github:matrix-org/matrix-js-sdk#develop (pinned
by commit in pnpm-lock.yaml).
Lotus behaviour NOT preserved: none found.
Verification (Node 24.11.1, pnpm 11.21.0): pnpm install --frozen-lockfile
OK (lockfile taken from upstream unchanged, no regeneration needed);
tsc clean; oxlint clean; oxfmt --check clean; knip exit 0 (2 config
hints in upstream knip.ts only); vitest unit 84 files / 627 passed /
9 skipped; build:embedded OK, staged to embedded/web/dist (44M), all
six io.lotus.* action strings present in the bundle.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
AEC/AGC audit fix + two hardening items from the engine review.
- Add an `autoGainControl` capture param (UrlParams -> CallViewModel ->
ConnectionFactory audioCaptureDefaults), mirroring echoCancellation/
noiseSuppression. Defaults true (unchanged); the host sets it false only for
the ML tier so the browser's auto gain control doesn't fight the in-source ML
denoiser (pumping). Echo cancellation stays on. Tests cover the URL parse and
the audioCaptureDefaults wiring.
- L1: init() now closes the owned AudioContext on a build failure (was orphaned;
browsers cap live contexts, so repeated failures could exhaust them).
- L2: buildGraph() disposes its partially-built nodes on failure (disposeGraph
previously only cleaned the prior graph).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This adds two new intents: start_call_voice and join_existing_voice. I need the latter in order to implement Element Web's new incoming call toasts, in which you can turn off your video before joining a group call. The other one, start_call_voice, exists more for completeness than anything; we don't currently want to allow users to start voice calls in group chats in our messenger clients, but maybe Cinny would, for instance.
* Add ring notification to UserIntent.StartNewCallDM
Signed-off-by: Timo K <toger5@hotmail.de>
* Add more tests (refactor to compute + get)
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
* refactor UrlParams to use a preset intent system
* change defaults for intend headers
* add: getEnumParam to ParamParser
* remove deprecated url params
* only allow skip lobby in widget (more strict needs test adjustment)
* fix tests that now require the url to be a widget url
Co-authored-by: Robin <robin@robin.town>
---------
Co-authored-by: Robin <robin@robin.town>
* Add a global control for toggling earpiece mode
This will be used by Element X to show an earpiece toggle button in the header.
* Add an earpiece overlay
* Fix header
The header needs to be passed forward as a string to some components and as a bool (hideHeader) to others.
Also use a enum instead of string options.
* fix top clipping with header
* hide app bar in pip
* revert android overlay app_bar
* Modernize AppBarContext
* Style header icon color as desired and switch earpice/speaker icon
* fix initial selection when using controlled media
* Add "Back to video" button
* fix tests
* remove dead code
* add snapshot test
* fix back to video button
* Request capability to learn the room name
We now need the room name in order to implement the mobile (widget-based) designs with the app bar.
* Test the CallViewModel output switcher directly
---------
Co-authored-by: Timo <toger5@hotmail.de>
* Introduce `intent` URL param and make it change the default lobby behaviour
* Mark skipLobby as deprecated
* Add support for unknown intent which is default for when not specified
* Refactor URL parameters into table
This is for readability and ahead of some possible changes
* Whitespace
* Lint
* The preload URL param shouldn't be used in SPA mode, so ignore it
* Fix coverage reporting
Codecov hasn't been working recently because Vitest doesn't report coverage by default.
* Suppress some noisy log lines
Closes https://github.com/element-hq/element-call/issues/686
* Store test files alongside source files
This way we benefit from not having to maintain the same directory structure twice, and our linters etc. will actually lint test files by default.
* Stop using Vitest globals
Vitest provides globals primarily to make the transition from Jest more smooth. But importing its functions explicitly is considered a better pattern, and we have so few tests right now that it's trivial to migrate them all.
* Remove Storybook directory
We no longer use Storybook.
* Configure Codecov
Add a coverage gate for all new changes and disable its comments.
* upgrade vitest
---------
Co-authored-by: Timo <toger5@hotmail.de>