Lotus toWidget actions with no handler used to sit in the LazyEventEmitter
backlog forever (host timed out; stale replay on remount). They now get
an immediate {} reply. Adds RequestState and DenoiseState to the enum
(fromWidget) with a test pinning the toWidget/fromWidget split.
Fixes#18
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
Six fix(lotus) commits reached `lotus` while the upstream merge was in
progress (deafen via global output mute, denoise race/fallback fixes,
strictOriginCheck on the widget transport, call_state standalone skip,
set_quality null-clears-cap, plus four new src/lotus/*.test.ts files).
Merged them on top of the v0.25.0 sync so this branch is a superset of
current `lotus`.
One conflict, src/lotus/lotusDenoiseProcessor.ts: the sync commit had
dropped a meaningless `void` (oxlint no-meaningless-void-operator) on a
line the incoming commit also touched; kept the void-less form so oxlint
stays clean.
Verification after the fold-in (Node 24.11.1 / pnpm 11.21.0): tsc clean;
oxlint clean; oxfmt --check clean; knip exit 0; vitest unit 88 files /
639 passed / 9 skipped; build:embedded OK, staged to embedded/web/dist,
all six io.lotus.* actions present in the bundle.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
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
matrix-widget-api's PostmessageTransport accepts toWidget actions from any
origin by default; the fork added actions that inject audio, deafen, retune
the encoder and render images. EC is served same-origin with the cinny
host, so globalThis.origin === parentOrigin and the strict check passes.
Fixes#15
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
Adds io.lotus.focus_participant (toWidget): the host can pin a participant
to the spotlight by Matrix user id (or clear with userId:null), via a
manual override injected into CallViewModel.spotlightSpeaker$. Replaces
cinny's fragile DOM .click() tile-selector focus hack. Extracts the action
enum into lotusActions.ts (no circular import) and allow-lists Lotus
toWidget actions in initializeWidget. Additive: no-op unless the host
sends the action.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add camera video quality controls (resolution/framerate/bitrate/codec)
to Settings > Video, mirroring the screen share settings UI
- Add audio processing toggles (echo cancellation, noise suppression,
auto gain control) to Settings > Audio, replacing URL-param-only controls
- Display raw values inline on all sliders (framerate, bitrate, volume)
- Add config-seeded defaults: config.json media_quality values now seed
Setting defaults for users who haven't explicitly set preferences
- Camera settings are applied when joining a call via ConnectionFactory
Signed-off-by: Ryan Emmick <ryanemmick4@gmail.com>
* bump js-sdk to Allow multiple rtc sessions per room (with different sessionDescriptions)
* Allow new state key string-packing format for widget mode
* bump js-sdk to latest version (with merged multi session PR)
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Timo K <toger5@hotmail.de>
0e0fba6575 added the ability to send call notification events when starting a call, but I forgot to give the widget the right capabilities to do this. The effect was that notifications just wouldn't send in widget mode.
* 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>
By keeping 'hangup' and 'close' as separate actions, we can allow Element Call widgets to stay on an error screen after the user has been disconnected without the widget completely disappearing from the host's UI. We don't have to request any additional capabilities to use a custom widget action like this one.
* Initial support for Hand Raise feature
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Refactored to use reaction and redaction events
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Replacing button svg with raised hand emoji
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* SpotlightTile should not duplicate the raised hand
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Update src/room/useRaisedHands.tsx
Element Call recently changed to AGPL-3.0
* Use relations to load existing reactions when joining the call
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Links to sha commit of matrix-js-sdk that exposes the call membership event id and refactors some async code
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Removing RaiseHand.svg
* Check for reaction & redaction capabilities in widget mode
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Fix failing GridTile test
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Center align hand raise.
* Add support for displaying the duration of a raised hand.
* Add a sound for when a hand is raised.
* Refactor raised hand indicator and add tests.
* lint
* Refactor into own files.
* Redact the right thing.
* Tidy up useEffect
* Lint tests
* Remove extra layer
* Add better sound. (woosh)
* Add a small mode for spotlight
* Fix timestamp calculation on relaod.
* Fix call border resizing video
* lint
* Fix and update tests
* Allow timer to be configurable.
* Add preferences tab for choosing to enable timer.
* Drop border from raised hand icon
* Handle cases when a new member event happens.
* Prevent infinite loop
* Major refactor to support various state problems.
* Tidy up and finish test rewrites
* Add some explanation comments.
* Even more comments.
* Use proper duration formatter
* Remove rerender
* Fix redactions not working because they pick up events in transit.
* More tidying
* Use deferred value
* linting
* Add tests for cases where we got a reaction from someone else.
* Be even less brittle.
* Transpose border to GridTile.
* First PoC for reactions
* hide menu by default
* Add lightbulb.
* Add reaction indicator.
* Add sounds.
* Tidy up + add support for floating emoji.
* Linting and general stability improvements.
* Subscribe to the ecall reaction event type.
* fix import
* Center emoji picker
* Overflow buttons when screen is too narrow
* lint
* Add settings for disabling animations / sounds.
* Make vertical divider more visually distinct.
* Make event listener more resillient.
* lint
* Fix some tests.
* Remove old raised hand component
* Add new icon
* Update text
* Update compound hand raised icon.
* Add deer.
* Fix case where you could send larger strings as emoji
* Const the active time.
* Document time in css.
* Add rock emoji
* Add licence file.
* Add type def for custom reaction type.
* better reaction description
* Factor out reactions test structure to utils file.
* Add tests for ReactionToggleButton
* Add keyboard shortcuts for reaction sending.
* type tidyups
* lint
* Add tests for ReactionAudioRenderer
* lint
* prettier
* i18n sort
* final lint?
* Preload reaction sounds to prevent delays.
* Update rock sounds
* add onclick back
* Fix test
* lint
* simplify
* Tweak line height
* modal impl
* Modal refactor attempts.
* Remove closed menu test since we're using Modal.
* Swap icon, make mobile view better.
* Fix mobile view for emoji picker.
* Use Intl.Segmenter
* Clear timeouts on component close.
* Remove useless useCallback
* Use prefers-reduced-motion
* Add toggle for raise hand.
* Add lower hand text
* Add lower motion mode.
* Decomplicate className system for Modal
* Add error for failured to send reaction.
* i18n
* Spacing for emoji buttons search
* Remove unrequired media query
* Fix generic sound not playing.
* Clear reactions if we're clearing timeouts.
* Fix tests
* Relabel lower hand
* More translations
* Add comments on reaction interface
* Move polyfill.
* lint
* Replace deer sound
* Another attempt to fix the sizing of the reactions
* cleanup
* fix button
* fix
---------
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
Co-authored-by: Milton Moura <miltonmoura@gmail.com>
Co-authored-by: fkwp <fkwp@users.noreply.github.com>
* Initial support for Hand Raise feature
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Refactored to use reaction and redaction events
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Replacing button svg with raised hand emoji
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* SpotlightTile should not duplicate the raised hand
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Update src/room/useRaisedHands.tsx
Element Call recently changed to AGPL-3.0
* Use relations to load existing reactions when joining the call
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Links to sha commit of matrix-js-sdk that exposes the call membership event id and refactors some async code
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Removing RaiseHand.svg
* Check for reaction & redaction capabilities in widget mode
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Fix failing GridTile test
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
* Center align hand raise.
* Add support for displaying the duration of a raised hand.
* Add a sound for when a hand is raised.
* Refactor raised hand indicator and add tests.
* lint
* Refactor into own files.
* Redact the right thing.
* Tidy up useEffect
* Lint tests
* Remove extra layer
* Add better sound. (woosh)
* Add a small mode for spotlight
* Fix timestamp calculation on relaod.
* Fix call border resizing video
* lint
* Fix and update tests
* Allow timer to be configurable.
* Add preferences tab for choosing to enable timer.
* Drop border from raised hand icon
* Handle cases when a new member event happens.
* Prevent infinite loop
* Major refactor to support various state problems.
* Tidy up and finish test rewrites
* Add some explanation comments.
* Even more comments.
* Use proper duration formatter
* Remove rerender
* Fix redactions not working because they pick up events in transit.
* More tidying
* Use deferred value
* linting
* Add tests for cases where we got a reaction from someone else.
* Be even less brittle.
* Transpose border to GridTile.
* lint
---------
Signed-off-by: Milton Moura <miltonmoura@gmail.com>
Co-authored-by: fkwp <fkwp@users.noreply.github.com>
Co-authored-by: Half-Shot <will@half-shot.uk>
Co-authored-by: Will Hunt <github@half-shot.uk>
* Enable lint rules for Promise handling to discourage misuse of them.
Squashed all of Hugh's commits into one.
---------
Co-authored-by: Hugh Nimmo-Smith <hughns@element.io>
* Install Knip
* Clarify an import that was confusing Knip
* Fix issues detected by Knip
Including cleaning up some unused code and dependencies, using a React hook that we unintentionally stopped using, and also adding some previously undeclared dependencies.
* Run dead code analysis in lint script and CI
---------
Co-authored-by: Timo <toger5@hotmail.de>
* 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>
* Add DeviceMute widget action `io.element.device_mute`.
This allows to send mute requests ("toWidget") and get the current mute state as a response.
And it will update the client about each change of mute states.
* review + better explanation
* review
* add comments
* use `useCallback`
* Load focus information from well known and use client config only as a fallback.
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>
* Add joining with knock room creation flow.
Also add `WaitForInviteView` after knocking.
And appropriate error views when knock failed or gets rejected.
Signed-off-by: Timo K <toger5@hotmail.de>
* Refactor encryption information.
We had lots of enums and booleans to describe the encryption situation.
Now we only use the `EncryptionSystem` "enum" which contains the
additional information like sharedKey. (and we don't use the isRoomE2EE
function that is somewhat confusing since it checks `return widget ===
null && !room.getCanonicalAlias();` which is only indirectly related to
e2ee)
Signed-off-by: Timo K <toger5@hotmail.de>
* Update recent list.
- Don't use deprecated `groupCallEventHander` anymore (it used the old
`m.call` state event.)
- make the recent list reactive (getting removed from a call removes the
item from the list)
- support having rooms without shared secret but actual matrix
encryption in the recent list
- change the share link creation button so that we create a link with
pwd for sharedKey rooms and with `perParticipantE2EE=true` for matrix
encrypted rooms.
Signed-off-by: Timo K <toger5@hotmail.de>
* fix types
Signed-off-by: Timo K <toger5@hotmail.de>
* patch js-sdk for linter
Signed-off-by: Timo K <toger5@hotmail.de>
* ignore ts expect error
Signed-off-by: Timo K <toger5@hotmail.de>
* Fix error in widget mode.
We cannot call client.getRoomSummary in widget mode. The code path needs
to throw before reaching this call. (In general we should never call
getRoomSummary if getRoom returns a room)
Signed-off-by: Timo K <toger5@hotmail.de>
* tempDemo
Signed-off-by: Timo K <toger5@hotmail.de>
* remove wait for invite view
Signed-off-by: Timo K <toger5@hotmail.de>
* yarn i18n
Signed-off-by: Timo K <toger5@hotmail.de>
* reset back mute participant count
* add logic to show error view when getting removed
* include reason whenever someone gets removed from a call.
* fix activeRoom not beeing early enough
* fix lints
* add comment about encryption situation
Signed-off-by: Timo K <toger5@hotmail.de>
* Fix lockfile
* Use (unmerged!) RoomSummary type from the js-sdk
Temporarily change the js-sdk dependency to the PR branch that provides
that type
* review
Signed-off-by: Timo K <toger5@hotmail.de>
* review (remove participant count unknown)
Signed-off-by: Timo K <toger5@hotmail.de>
* remove error for unencrypted calls (allow intentional unencrypted calls)
Signed-off-by: Timo K <toger5@hotmail.de>
* update js-sdk
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>