Commit Graph
1182 Commits
Author SHA1 Message Date
Lotus CIandClaude Fable 5.1 c6f9727870 merge: upstream v0.25.0 into lotus
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
2026-09-12 11:35:57 -04:00
Timo K. 2a7c6c3c06 Oh dear test coverage... 2026-08-28 16:22:08 +02:00
Timo K. 5bab17b668 Update InCallView.tsx 2026-08-28 15:52:52 +02:00
Timo K. b0d098e065 Merge branch 'main' into toger5/add-key-rotation-participant-limit 2026-08-28 15:27:43 +02:00
Timo K. 1146d3820a review. Dont pass full vm to developer settings 2026-08-28 15:20:49 +02:00
Robin 1c03ad335c Hide reactions interface in PiP mode 2026-08-19 17:44:45 +02:00
Robin 33a0653ea5 Fix lobby video preview losing its rounded corners in Firefox
Same fix as e1bc4a096b, but for the video preview in the lobby.
2026-08-18 17:49:14 +02:00
Robin b5bcb9aeed Merge pull request #4160 from alexmaras/room-joining/assume-public
Room joining: if join_rule is absent, assume public
2026-08-17 14:40:07 +02:00
Timo K. 43ce68e80a Fix: error screen cannot be closed in embedded mode. 2026-08-17 12:08:30 +02:00
Timo K. f2622f0032 Add vm to developer settings tab 2026-08-17 11:17:22 +02:00
Alex Maras 1bb342e9e1 Room joining: if join_rule is absent, assume public 2026-08-11 21:24:38 +08:00
Robin 2de7fdde10 Fix layout switches not showing their state on the combined docs page
On the combined Storybook docs page for the call footer, the layout switches would not show the correct state until you hovered over them because they all shared the same input name and thus were interpreted as belonging to the same radio group.
2026-07-28 15:06:15 +02:00
Robin a443a55bec Factor out a layout switch view + view model
So it can easily be shown and hidden wholesale.
2026-07-28 15:06:15 +02:00
Robin 05ad9b2475 Merge pull request #4128 from element-hq/landscape-default-grid
Use a proper one-on-one layout for landscape mobile calls
2026-07-28 14:08:48 +02:00
Robin 0b21cff020 Rename one-on-one layouts to be orientation-agnostic 2026-07-27 18:28:52 +02:00
Valere 53ae78c609 break ratio when tile bigger than screen 2026-07-27 17:25:56 +02:00
Valere b046c4b569 fix: Safari preview tile no video is 16px wide only 2026-07-27 15:43:35 +02:00
Robin d33dedd038 Hide the browser's default placeholder image for videos
Source: https://stackoverflow.com/a/79058682
2026-07-15 17:26:02 +02:00
Robin 2d2e85e340 Merge pull request #4107 from element-hq/spotlight-icon
Update spotlight icon
2026-07-14 09:34:50 +02:00
Robin c433c36687 Update snapshots 2026-07-13 18:20:56 +02:00
Robin bff41ad66a Update spotlight icon 2026-07-13 12:22:44 +02:00
Robin 0afefa4889 Merge branch 'livekit' into remove-stopgap-styles 2026-07-09 16:21:06 +02:00
Robin 32e30dd4f5 Merge branch 'livekit' into mobile-gradient 2026-07-09 12:56:28 +02:00
Robin bb06905aa2 Merge pull request #4099 from element-hq/stable-class-names
Use vitest's default for scoped class names
2026-07-09 12:54:19 +02:00
Robin 2684fa1d62 Remove unused class for end call button 2026-07-09 12:46:45 +02:00
Robin 11fadebb87 Fix test failures due to scoped class names 2026-07-08 17:06:25 +02:00
Robin 943ce5b853 Update test snapshots to use scoped class names 2026-07-08 17:06:09 +02:00
Robin 27315a7090 Rename bgStyle to 'background' 2026-07-08 14:01:38 +02:00
Timo K. eefa6f843d fmt 2026-07-07 19:52:50 +02:00
Timo K. a6921e2bfb all the other logs 2026-07-07 19:12:11 +02:00
Lotus CIandClaude Opus 4.8 02666c0c04 feat(lotus): io.lotus.set_deafen action — deafen remote audio at the source
CI / Build embedded bundle (push) Successful in 39s
CI / Publish to Gitea npm registry (push) Has been skipped
New toWidget action { deafened, screenshareAudioMuted } that sets each remote
RemoteParticipant.setVolume per source (Microphone + ScreenShareAudio), applied
to existing participants + re-applied to late joiners via
RoomEvent.ParticipantConnected (subscribed through vm.livekitRoomItems$). Closure-
scoped state, matching the sibling lotus modules; the cinny host re-sends on join
so a fresh call never inherits stale deafen state.

Replaces cinny's brittle iframe-DOM <audio>.muted hack (which broke on EC
re-render / late tracks). Folded into unpublished 0.20.1-lotus.2.

Note: injected/soundboard audio (Track.Source.Unknown) is not silenced — the
livekit-client setVolume type only accepts Microphone|ScreenShareAudio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:12:08 -04:00
Lotus CIandClaude Opus 4.8 d71d8d6799 chore(lotus): fix stale denoise flag docs + prep 0.20.1-lotus.2
CI / Build embedded bundle (push) Successful in 40s
CI / Publish to Gitea npm registry (push) Has been skipped
The in-source ML denoiser is gated on lotusDenoiseSource (see lotusDenoise.ts
gate), not the legacy build-time shim flag lotusDenoise=ml. Correct the two
stale references (lotusDenoise.ts JSDoc + InCallView.tsx comment) to
lotusDenoiseSource=1.

Bump the embedded package to 0.20.1-lotus.2 for the next publish and update the
CI comment: the checked-in version now tracks the intended release, while a
pushed tag still wins (npm version "$TAG" overwrites at publish time).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 23:56:28 -04:00
Robin 900d0abd27 Let page background shine through the footer
By visually separating it from other page content with an additional gradient background only when necessary.
2026-06-30 16:29:20 +02:00
Lotus CIandClaude Opus 4.8 39b57db3b2 lotus(#1): ML denoise as a first-class audio TrackProcessor (fixes A7)
CI / Build embedded bundle (push) Successful in 58s
CI / Publish to Gitea npm registry (push) Has been skipped
Implements RNNoise/Speex noise suppression as a LiveKit audio
TrackProcessor attached to the local mic track, replacing the host's
build-time getUserMedia monkeypatch. Because EC re-attaches the processor
on every (re)publish (LocalTrackPublished), denoise now survives EC's
mid-call reconnect — the root cause of A7 "mic dead after reconnect".
Reuses the worklet/wasm assets already shipped under ./denoise/ (no new EC
dependency); model/gate configured via lotusDenoise/lotusModel/lotusGate
URL params. Additive: no-op unless lotusDenoise=ml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:54:46 -04:00
Lotus CIandClaude Opus 4.8 70358d442b lotus(#6): render avatar decorations on in-call tiles
CI / Build embedded bundle (push) Failing after 12m11s
CI / Publish to Gitea npm registry (push) Has been skipped
Adds io.lotus.decorations (toWidget): the host pushes a userId->image-URL
map and EC overlays the profile decoration on each tile avatar
(TileAvatar), keyed by userId, with a useSyncExternalStore-backed store.
Makes A6 first-class in-call instead of absent. URLs are validated
https/blob. Additive: no-op unless the host sends decorations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:38:45 -04:00
Lotus CIandClaude Opus 4.8 6d739db8b8 lotus(#7): audio/screenshare quality controls via widget action
Adds io.lotus.set_quality (toWidget): caps mic audio bitrate and
screenshare bitrate/framerate via RTCRtpSender.setParameters (no
republish). Settings are sticky and re-applied on LocalTrackPublished so
they survive mute/unmute and reconnects. These encoding controls lived in
EC's module scope, unreachable from the host against the prebuilt bundle.
Additive: no-op unless the host sends the action.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:24:57 -04:00
Lotus CIandClaude Opus 4.8 c73eec0781 lotus(#3): soundboard audio injection via widget action
CI / Build embedded bundle (push) Successful in 43s
CI / Publish to Gitea npm registry (push) Has been skipped
Adds io.lotus.inject_audio (toWidget): mixes a soundboard clip into the
call so other participants hear it. Publishes the clip as a separate
Unknown-source LiveKit track (rendered by MatrixAudioRenderer) rather than
splicing into the mic track, so the denoise pipeline is untouched; the
track is unpublished when the clip ends (with a 30s safety cap). This is
the real call-audio injection that was impossible against the prebuilt EC
bundle. Additive: no-op unless the host sends the action.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:18:43 -04:00
Lotus CIandClaude Opus 4.8 9d7784b9bc lotus(#4): focus-participant spotlight via widget action
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>
2026-06-29 23:10:16 -04:00
Lotus CIandClaude Opus 4.8 444af5f7ac lotus(#2): stream per-participant call state over widget API
CI / Build embedded bundle (push) Successful in 1m45s
CI / Publish to Gitea npm registry (push) Has been skipped
Opt-in (lotusCallState=1) bridge that emits io.lotus.call_state with each
participant's speaking/audio/video state, so the Lotus host can drive
speaking rings / mute badges / PiP from real events instead of scraping
EC's rendered DOM. Exposes vm.userMedia$ on the public CallViewModel.
Additive: no-op without the flag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:05:20 -04:00
Johannes Marbach da942ea900 Fix formatting 2026-06-23 12:19:40 +02:00
Johannes Marbach d534c617d2 Eliminate noOutline constant 2026-06-23 11:42:14 +02:00
Johannes Marbach 93fae5dd67 Add PiP border in 1on1 layouts
Fixes: #4008
2026-06-23 08:56:41 +02:00
Robin a456e47796 Show ringing status even on spotlight tiles (except in app bar mode) 2026-06-22 12:55:37 +02:00
Robin c6188a8345 Improve test coverage 2026-06-22 11:59:16 +02:00
Robin e11c04ac87 Move ringing status indicator to header on mobile
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.)
2026-06-18 17:41:35 +02:00
Timo 9b070052a0 Merge pull request #4032 from element-hq/toger5/lobby-remove-minimise-add-back-button
Add primary button icon configuration and set it left arrow in lobby
2026-06-18 23:02:03 +08:00
Johannes Marbach bb3d2cd95c Merge pull request #4048 from element-hq/johannes/oxfmt
Switch from prettier to oxfmt
2026-06-18 13:06:55 +02:00
Robin 3a598ffe43 Restore ability to play sound with custom volume
This was missing from the revert in 8b0f5054dd.
2026-06-18 11:35:46 +02:00
Robin 8b0f5054dd Revert to original fix for duplicate leave sounds
My attempted simpler fix of applying takeUntil(autoLeave$) to leaveSoundEffect$ didn't work.
2026-06-18 11:05:55 +02:00
Robin 8cda9777a5 Merge branch 'livekit' into ringing-intent 2026-06-18 06:41:17 +02:00