Skip to content

feat(voip): tablet and landscape layout#7110

Merged
diegolmello merged 29 commits into
feat.voip-lib-newfrom
feat.voip-tablet-layout-2
Apr 8, 2026
Merged

feat(voip): tablet and landscape layout#7110
diegolmello merged 29 commits into
feat.voip-lib-newfrom
feat.voip-tablet-layout-2

Conversation

@diegolmello

@diegolmello diegolmello commented Apr 7, 2026

Copy link
Copy Markdown
Member

Proposed changes

Adds a wide ("landscape/tablet") layout mode to CallView so the in-call UI adapts beyond the original portrait-phone design:

  • New useCallLayoutMode hook centralizes layout decisions (portrait vs wide) based on orientation and tablet master-detail state, with LayoutMode extracted to CallView/types.ts.
  • CallButtons was refactored to a config-array driven component, tightening types and making it trivial to reflow rows between layouts.
  • Dialpad portrait and landscape variants were collapsed into a single component that positions the keypad side-by-side in wide mode.
  • CallView is now registered in the tablet master-detail stack and shown from RoomsListView's list header entry.
  • Snapshots, unit tests and stories updated (including CallView.stories.tsx, Dialpad.stories.tsx, CallButtons.test.tsx, index.test.tsx); tests switched to within() for row-membership assertions.
  • Test infra: global TrueSheet mock added to jest.setup.js; deprecated bottomSheet prop removed from tests.

Issue(s)

https://rocketchat.atlassian.net/browse/VMUX-22

How to test or reproduce

  1. yarn && yarn pod-install
  2. Run on an iPad / Android tablet, or rotate a phone to landscape.
  3. Start (or mock via simulateCall) a VoIP call and open CallView.
  4. Verify:
    • Portrait phone: unchanged layout.
    • Landscape / tablet: caller info and dialpad sit side-by-side; CallButtons reflow into the wide row config.
    • Rotating mid-call swaps layouts without losing call state.
    • On tablet, opening CallView from the rooms list header keeps master-detail intact.
  5. yarn test and yarn lint both pass.

Screenshots

Simulator.Screen.Recording.-.iPad.Pro.13-inch.M4.-.2026-04-07.at.15.26.49.mov
Simulator.Screen.Recording.-.iPad.Pro.13-inch.M4.-.2026-04-07.at.15.26.42.mov
Simulator.Screen.Recording.-.iPhone.16e.-.2026-04-07.at.15.26.31.mov
Simulator.Screen.Recording.-.iPhone.16e.-.2026-04-07.at.15.26.19.mov

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

This PR stacks on the base VoIP work (feat.voip-lib-new line) and should merge after those land. The layout mode is intentionally a 2-value enum (portrait | wide) rather than raw breakpoints so the
hook stays the single source of truth — if we need more variants later, extend LayoutMode in CallView/types.ts.

@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds responsive tablet ("wide") layout support for CallView, a mock call dev utility and navigation route, refactors Dialpad and CallButtons for layout-aware rendering, updates styles and Storybook stories, and removes a bottomSheet prop from a NewMediaCall input.

Changes

Cohort / File(s) Summary
Mock Call Dev Utilities
app/lib/services/voip/mockCall.ts, app/views/RoomsListView/components/ListHeader.tsx
New mock call module and dev-only list entry to seed a mock call and navigate to CallView (createMockCall, seedMockCall, launchMockCallView).
Navigation Stack
app/stacks/MasterDetailStack/index.tsx, app/stacks/MasterDetailStack/types.ts
Registered new CallView route in InsideStack and added CallView: undefined to the stack types.
Layout Mode Foundation
app/views/CallView/types.ts, app/views/CallView/useCallLayoutMode.ts
Introduced LayoutMode type (`'narrow'
CallButtons Responsive Refactor
app/views/CallView/components/CallButtons.tsx, app/views/CallView/components/CallButtons.test.tsx
CallButtons now accepts layoutMode, renders buttons from a shared config into one wide row or two narrow rows, adds row testIDs; tests updated/added for layout behavior and button placement.
Dialpad Refactor & State Hook
app/views/CallView/components/Dialpad/Dialpad.tsx, app/views/CallView/components/Dialpad/useDialpadState.ts, app/views/CallView/components/Dialpad/styles.ts, app/views/CallView/components/Dialpad/Dialpad.test.tsx
Added useDialpadState hook and DialpadGrid component; Dialpad uses useCallLayoutMode to render a landscape layout for wide, removed bottomSheet prop from the input, added landscape styles; tests control useCallLayoutMode.
CallView Root & Styles
app/views/CallView/index.tsx, app/views/CallView/index.test.tsx, app/views/CallView/styles.ts
CallView obtains layoutMode via useCallLayoutMode and passes it to CallButtons. Footer/buttons layout changed to an absolute footer; tests extended for wide/narrow responsive scenarios.
Storybook: CallView & Components
app/views/CallView/CallView.stories.tsx, app/views/CallView/components/CallActionButton.stories.tsx, app/views/CallView/components/CallerInfo.stories.tsx, app/views/CallView/components/Dialpad/Dialpad.stories.tsx
Added tablet/wide stories and variants, updated story titles to CallView/*, added decorators/helpers to force layout mode, and new tablet-specific stories.
New Hook for Dialpad State
app/views/CallView/components/Dialpad/useDialpadState.ts
New IDialpadState and useDialpadState returning { colors, dialpadValue }.
Minor / Misc
app/containers/NewMediaCall/FilterHeader.tsx, .gitignore, CLAUDE.md
Removed bottomSheet prop from a FormTextInput, updated .gitignore, and added CLAUDE.md documentation.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Mock as MockCall
    participant Store as CallStore
    participant Nav as Navigation
    participant View as CallView
    participant Buttons as CallButtons

    Dev->>Mock: call launchMockCallView(overrides)
    Mock->>Store: seedMockCall(overrides) — set call, flags, start time
    Mock->>Nav: Navigation.navigate("CallView")
    Nav->>View: mount CallView
    View->>Store: read call & state
    View->>View: useCallLayoutMode() -> layoutMode
    View->>Buttons: render CallButtons(layoutMode)
    Buttons->>Buttons: render single row (wide) or two rows (narrow)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(voip): tablet and landscape layout' accurately and concisely describes the primary change across the changeset, which adds responsive layout support for tablet/wide views and landscape orientation throughout the VoIP call UI.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
app/views/CallView/components/CallButtons.tsx (1)

13-15: Reduce reverse dependency by moving LayoutMode to a shared local type module.

CallButtons importing a type from its parent screen (..) couples component and screen layers. A types.ts in app/views/CallView/ (or components/) would keep boundaries cleaner.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/views/CallView/components/CallButtons.tsx` around lines 13 - 15, Move the
LayoutMode type out of the parent screen and into a shared local types module to
avoid the reverse dependency: create a types.ts (or index types file) in
app/views/CallView/ (or components/) exporting LayoutMode, update the
CallButtons component to import LayoutMode from that new module (the component
is CallButtons), and update the original parent screen and any other consumers
to import LayoutMode from the new shared types file instead of '..' so the
screen no longer depends on the child component.
app/views/CallView/components/Dialpad/Dialpad.test.tsx (1)

13-16: Mock useWindowDimensions from the public react-native module instead of the internal path.

React Native 0.79 deprecated deep imports into Libraries/... paths. The stable public API surface is the root react-native module. Change the mock from 'react-native/Libraries/Utilities/useWindowDimensions' to 'react-native' to ensure compatibility across React Native version upgrades.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/views/CallView/components/Dialpad/Dialpad.test.tsx` around lines 13 - 16,
The test currently mocks the internal path
'react-native/Libraries/Utilities/useWindowDimensions'; change the jest.mock
call to mock the public 'react-native' module instead and provide a
useWindowDimensions export that returns { width: mockWindowWidth, height:
mockWindowHeight, scale: 1, fontScale: 1 }; update the jest.mock invocation that
references useWindowDimensions, mockWindowWidth and mockWindowHeight so the mock
is attached to the root 'react-native' export (optionally preserving other
exports via jest.requireActual if needed).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/lib/services/voip/mockCall.ts`:
- Around line 20-25: The default mock contact currently sets sipExtension:
'2244' which, without an explicit roomId, disables the Message action; update
the mock defaults so Message is enabled by either clearing sipExtension (set to
'') or adding a default roomId (e.g., 'mock-room') in the DEFAULT_CONTACT object
and mirror the same change in the other default mock state block (the
DEFAULT_STATE / similar defaults around lines 65-76) so the dev helper UI
includes the Message path by default.

---

Nitpick comments:
In `@app/views/CallView/components/CallButtons.tsx`:
- Around line 13-15: Move the LayoutMode type out of the parent screen and into
a shared local types module to avoid the reverse dependency: create a types.ts
(or index types file) in app/views/CallView/ (or components/) exporting
LayoutMode, update the CallButtons component to import LayoutMode from that new
module (the component is CallButtons), and update the original parent screen and
any other consumers to import LayoutMode from the new shared types file instead
of '..' so the screen no longer depends on the child component.

In `@app/views/CallView/components/Dialpad/Dialpad.test.tsx`:
- Around line 13-16: The test currently mocks the internal path
'react-native/Libraries/Utilities/useWindowDimensions'; change the jest.mock
call to mock the public 'react-native' module instead and provide a
useWindowDimensions export that returns { width: mockWindowWidth, height:
mockWindowHeight, scale: 1, fontScale: 1 }; update the jest.mock invocation that
references useWindowDimensions, mockWindowWidth and mockWindowHeight so the mock
is attached to the root 'react-native' export (optionally preserving other
exports via jest.requireActual if needed).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 408c51d1-5456-466b-805e-80a261a3f610

📥 Commits

Reviewing files that changed from the base of the PR and between 58e91f1 and eb1f951.

⛔ Files ignored due to path filters (14)
  • app/containers/MediaCallHeader/__snapshots__/MediaCallHeader.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/FilterHeader.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/PeerItem.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/PeerList.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/SelectedPeer.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/__snapshots__/index.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/components/Dialpad/__snapshots__/Dialpad.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/components/__snapshots__/CallerInfo.test.tsx.snap is excluded by !**/*.snap
  • app/views/DiscussionsView/__snapshots__/Item.test.tsx.snap is excluded by !**/*.snap
  • app/views/NewMessageView/__snapshots__/Item.test.tsx.snap is excluded by !**/*.snap
  • app/views/RoomInfoView/components/__snapshots__/RoomInfoButtons.test.tsx.snap is excluded by !**/*.snap
  • app/views/RoomView/LoadMore/__snapshots__/LoadMore.test.tsx.snap is excluded by !**/*.snap
  • app/views/ThreadMessagesView/__snapshots__/Item.test.tsx.snap is excluded by !**/*.snap
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (17)
  • app/containers/NewMediaCall/FilterHeader.tsx
  • app/lib/services/voip/mockCall.ts
  • app/sagas/deepLinking.js
  • app/stacks/MasterDetailStack/index.tsx
  • app/stacks/MasterDetailStack/types.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/Dialpad/styles.ts
  • app/views/CallView/index.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/styles.ts
  • app/views/RoomsListView/components/ListHeader.tsx
  • index.js
  • jest.config.js
  • jest.setup.js
💤 Files with no reviewable changes (1)
  • app/containers/NewMediaCall/FilterHeader.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

Configure Prettier with tabs, single quotes, 130 character width, no trailing commas, arrow parens avoid, and bracket same line

Files:

  • index.js
  • app/sagas/deepLinking.js
  • jest.config.js
  • app/views/RoomsListView/components/ListHeader.tsx
  • app/stacks/MasterDetailStack/index.tsx
  • app/views/CallView/components/Dialpad/styles.ts
  • jest.setup.js
  • app/stacks/MasterDetailStack/types.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/styles.ts
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/lib/services/voip/mockCall.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @rocket.chat/eslint-config base configuration including React, React Native, TypeScript, and Jest plugins

Files:

  • index.js
  • app/sagas/deepLinking.js
  • jest.config.js
  • app/views/RoomsListView/components/ListHeader.tsx
  • app/stacks/MasterDetailStack/index.tsx
  • app/views/CallView/components/Dialpad/styles.ts
  • jest.setup.js
  • app/stacks/MasterDetailStack/types.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/styles.ts
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/lib/services/voip/mockCall.ts
index.js

📄 CodeRabbit inference engine (CLAUDE.md)

Register app entry point in index.js with conditional Storybook loading

Files:

  • index.js
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use descriptive names for functions, variables, and classes that clearly convey their purpose
Write comments that explain the 'why' behind code decisions, not the 'what'
Keep functions small and focused on a single responsibility
Use const by default, let when reassignment is needed, and avoid var
Prefer async/await over .then() chains for handling asynchronous operations
Use explicit error handling with try/catch blocks for async operations
Avoid deeply nested code; refactor complex logic into helper functions

Files:

  • index.js
  • app/sagas/deepLinking.js
  • jest.config.js
  • app/views/RoomsListView/components/ListHeader.tsx
  • app/stacks/MasterDetailStack/index.tsx
  • app/views/CallView/components/Dialpad/styles.ts
  • jest.setup.js
  • app/stacks/MasterDetailStack/types.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/styles.ts
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/lib/services/voip/mockCall.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript with strict mode enabled and configure baseUrl to app/ for import resolution

**/*.{ts,tsx}: Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Prefer interfaces over type aliases for defining object shapes in TypeScript
Use enums for sets of related constants rather than magic strings or numbers

Files:

  • app/views/RoomsListView/components/ListHeader.tsx
  • app/stacks/MasterDetailStack/index.tsx
  • app/views/CallView/components/Dialpad/styles.ts
  • app/stacks/MasterDetailStack/types.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/styles.ts
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/lib/services/voip/mockCall.ts
app/views/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Place screen components in app/views/ directory

Files:

  • app/views/RoomsListView/components/ListHeader.tsx
  • app/views/CallView/components/Dialpad/styles.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/styles.ts
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/CallButtons.tsx
app/stacks/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Navigation 7 for navigation with stacks for InsideStack (authenticated), OutsideStack (login/register), MasterDetailStack (tablets), and ShareExtensionStack

Files:

  • app/stacks/MasterDetailStack/index.tsx
  • app/stacks/MasterDetailStack/types.ts
app/lib/services/voip/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate

Files:

  • app/lib/services/voip/mockCall.ts
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/hooks/useResponsiveLayout/**/*.{ts,tsx} : Use responsive layout with master-detail on tablets and single stack on phones via useResponsiveLayout hook
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate

Applied to files:

  • index.js
  • app/sagas/deepLinking.js
  • app/views/RoomsListView/components/ListHeader.tsx
  • app/stacks/MasterDetailStack/index.tsx
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/lib/services/voip/mockCall.ts
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use ESLint with rocket.chat/eslint-config base configuration including React, React Native, TypeScript, and Jest plugins

Applied to files:

  • jest.config.js
📚 Learning: 2026-03-30T15:49:30.957Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6875
File: app/containers/RoomItem/Actions.tsx:12-12
Timestamp: 2026-03-30T15:49:30.957Z
Learning: In RocketChat/Rocket.Chat.ReactNative, `react-native-worklets` version 0.6.1 does NOT export a built-in Jest mock (e.g., no `react-native-worklets/lib/module/mock`). The correct Jest mock approach for this version is to add a manual mock in `jest.setup.js`: `jest.mock('react-native-worklets', () => ({ scheduleOnRN: jest.fn((fn, ...args) => fn(...args)) }))`.

Applied to files:

  • jest.config.js
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/index.test.tsx
  • app/lib/services/voip/mockCall.ts
📚 Learning: 2026-04-07T17:49:17.518Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.518Z
Learning: Applies to **/*.{js,jsx,ts,tsx,json} : Configure Prettier with tabs, single quotes, 130 character width, no trailing commas, arrow parens avoid, and bracket same line

Applied to files:

  • jest.config.js
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/index.tsx : Configure Redux provider, theme, navigation, and notifications in app/index.tsx

Applied to files:

  • app/views/RoomsListView/components/ListHeader.tsx
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/theme.tsx : Configure theming context in app/theme.tsx

Applied to files:

  • app/views/RoomsListView/components/ListHeader.tsx
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/stacks/**/*.{ts,tsx} : Use React Navigation 7 for navigation with stacks for InsideStack (authenticated), OutsideStack (login/register), MasterDetailStack (tablets), and ShareExtensionStack

Applied to files:

  • app/stacks/MasterDetailStack/index.tsx
  • app/stacks/MasterDetailStack/types.ts
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/views/**/*.{ts,tsx} : Place screen components in app/views/ directory

Applied to files:

  • app/stacks/MasterDetailStack/index.tsx
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/hooks/useResponsiveLayout/**/*.{ts,tsx} : Use responsive layout with master-detail on tablets and single stack on phones via useResponsiveLayout hook

Applied to files:

  • app/views/CallView/components/Dialpad/styles.ts
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/CallButtons.tsx
📚 Learning: 2026-03-30T15:49:26.708Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6875
File: app/containers/RoomItem/Actions.tsx:12-12
Timestamp: 2026-03-30T15:49:26.708Z
Learning: In Rocket.Chat.ReactNative, do not rely on `react-native-worklets` v0.6.1 exporting a built-in Jest mock (e.g., `react-native-worklets/lib/module/mock` does not exist for this version). Instead, add the Jest manual mock in your repo’s `jest.setup.js`/`jest.setup.ts`, mocking `react-native-worklets` to provide `scheduleOnRN: jest.fn((fn, ...args) => fn(...args))`. This ensures Jest can import the module and that `scheduleOnRN` executes the passed function during tests.

Applied to files:

  • jest.setup.js
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Support React 19, React Native 0.79, and Expo 53

Applied to files:

  • jest.setup.js
📚 Learning: 2026-03-17T19:15:30.463Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6970
File: .maestro/tests/room/share-message.yaml:77-79
Timestamp: 2026-03-17T19:15:30.463Z
Learning: In `.maestro/tests/room/share-message.yaml` (Rocket.Chat React Native), the `tapOn: point: 5%,10%` step is intentional: it taps the empty area above the bottom sheet and keyboard to dismiss both simultaneously. Using `action-sheet-handle` instead would only close the sheet but not the keyboard. This pattern is acceptable when both need to be dismissed together in a single step.

Applied to files:

  • app/views/CallView/components/CallButtons.test.tsx
📚 Learning: 2026-03-10T15:21:45.098Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 7046
File: app/containers/InAppNotification/NotifierComponent.stories.tsx:46-75
Timestamp: 2026-03-10T15:21:45.098Z
Learning: In `app/containers/InAppNotification/NotifierComponent.tsx` (React Native, Rocket.Chat), `NotifierComponent` is exported as a Redux-connected component via `connect(mapStateToProps)`. The `isMasterDetail` prop is automatically injected from `state.app.isMasterDetail` and does not need to be passed explicitly at call sites or in Storybook stories that use the default (connected) export.

Applied to files:

  • app/views/CallView/index.tsx
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to index.js : Register app entry point in index.js with conditional Storybook loading

Applied to files:

  • app/views/CallView/index.test.tsx
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to @(app/sagas/videoConf.ts|app/lib/methods/videoConf.ts) : Manage video conferencing via Redux actions/reducers/sagas in app/sagas/videoConf.ts and app/lib/methods/videoConf.ts using server-managed Jitsi integration; do not conflate with VoIP

Applied to files:

  • app/lib/services/voip/mockCall.ts
🔇 Additional comments (18)
index.js (1)

50-50: Good stylistic cleanup; no behavior change.

This update matches the repo’s Prettier rule (arrow parens avoid) and keeps error handling intact.

app/sagas/deepLinking.js (1)

116-121: Looks good — stylistic cleanup only.

This change keeps behavior intact and improves consistency with single-arg arrow callback style.

app/views/CallView/components/Dialpad/styles.ts (1)

44-56: LGTM!

The landscape styles are well-structured, using flexDirection: 'row' for side-by-side layout and equal flex: 1 distribution between input and grid sections. The implementation follows the existing style patterns in this file.

app/views/CallView/components/Dialpad/Dialpad.tsx (2)

37-47: LGTM!

Good extraction of DialpadGrid into a reusable component, following the single responsibility principle. Using rowIndex as key is acceptable here since DIALPAD_KEYS is a static constant that never reorders.


49-75: LGTM!

The landscape detection logic using useWindowDimensions is clean and the conditional rendering properly handles both orientations. The side-by-side layout with separate input and grid sections provides good tablet UX.

app/stacks/MasterDetailStack/index.tsx (2)

57-57: LGTM!

Import is correctly placed with the InsideStackNavigator view imports.


238-238: LGTM!

The CallView screen registration follows the same pattern as JitsiMeetView — a full-screen call interface with headerShown: false. This correctly integrates into the InsideStack for authenticated users on tablets.

app/stacks/MasterDetailStack/types.ts (1)

225-225: LGTM!

The CallView: undefined type is appropriate since the view retrieves call state from the Zustand store rather than navigation params. Based on learnings, VoIP uses Zustand stores instead of Redux, which aligns with this parameterless route design.

jest.config.js (1)

3-5: LGTM!

Adding @lodev09/react-native-true-sheet to the transformIgnorePatterns allowlist is necessary to ensure Jest can process the package before the mock in jest.setup.js takes effect.

app/views/RoomsListView/components/ListHeader.tsx (1)

43-54: LGTM!

The __DEV__ guard ensures this mock call button only appears in development builds. This provides a convenient way to test the CallView without requiring a real SIP session. The implementation follows the existing List.Item pattern used elsewhere in this component.

jest.setup.js (1)

208-213: LGTM!

The TrueSheet mock follows the established pattern used for similar native components like @discord/bottom-sheet (mapping to View). This allows tests to render without requiring the native implementation.

app/views/CallView/index.test.tsx (2)

12-16: LGTM!

The mutable mockWindowWidth variable provides a clean way to test responsive behavior by allowing each test to set the desired screen width before rendering.


403-425: LGTM!

Good coverage for the responsive layout feature. The tests clearly verify the expected behavior:

  • Narrow layout (350px): buttons split across two rows
  • Wide layout (800px): all buttons in a single row

The assertions use appropriate getByTestId for expected elements and queryByTestId with toBeNull() for elements that should not exist.

app/views/CallView/index.tsx (1)

18-20: Responsive layout mode wiring looks good.

layoutMode is derived clearly and passed down cleanly to CallButtons, which keeps the screen logic straightforward.

Also applies to: 28-28

app/views/CallView/components/Dialpad/Dialpad.test.tsx (1)

133-156: Landscape/portrait coverage is a good addition.

These assertions validate both branches explicitly and make the responsive Dialpad behavior safer to refactor.

app/views/CallView/components/CallButtons.test.tsx (1)

14-18: Test updates are aligned with the new CallButtons API.

Good adjustment to pass layoutMode consistently and keep behavior assertions intact.

Also applies to: 48-96

app/views/CallView/styles.ts (1)

56-70: Button container/row style refactor matches the new layout behavior.

The updated spacing and row alignment are coherent with the responsive button composition.

app/views/CallView/components/CallButtons.tsx (1)

126-148: Wide vs narrow rendering structure is clean and easy to verify.

The branch layout is straightforward, and row-level testIDs make this easy to test and maintain.

Comment thread app/lib/services/voip/mockCall.ts
diegolmello and others added 8 commits April 7, 2026 16:10
Slice 1 of PROGRESS-layout-review.md.

Co-Authored-By: Diego Mello <diegolmello@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Slice 6 of PROGRESS-layout-review.md.

Snapshots updated to reflect the removal of redundant alignContent: 'flex-start'
from callerInfoContainer style and the trimmed TabletCallView comment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Slice 4 of PROGRESS-layout-review.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Slice 4 refactor inferred the buttons array as `Array<{ icon: string; ... }>`,
which broke `CustomIcon`'s `TIconsName` constraint and tripped TS1355 on the
`(cond ? 'active' : 'default') as const` pattern. Annotate the array with an
explicit ICallButtonConfig interface so icons stay typed and variants are a
plain string union.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
app/views/CallView/components/CallActionButton.stories.tsx (1)

42-50: Avoid double wrapper nesting in stories

The decorator wraps with <Wrapper>, but each story already wraps with <Wrapper>. This adds redundant padding/alignment and can skew visual baselines/snapshots.

Proposed fix
 	decorators: [
 		(Story: React.ComponentType) => (
 			<ResponsiveLayoutContext.Provider value={responsiveLayoutProviderLargeFontValue(1)}>
-				<Wrapper>
-					<Story />
-				</Wrapper>
+				<Story />
 			</ResponsiveLayoutContext.Provider>
 		)
 	]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/views/CallView/components/CallActionButton.stories.tsx` around lines 42 -
50, The decorator currently double-wraps stories by nesting <Story /> inside
<Wrapper> within the decorators array; remove the redundant <Wrapper> from the
decorator so it only provides the ResponsiveLayoutContext.Provider and renders
<Story /> directly, leaving per-story <Wrapper> usage intact—update the
decorators definition that references ResponsiveLayoutContext.Provider, Wrapper,
and Story accordingly.
app/views/CallView/CallView.stories.tsx (1)

121-162: Drive the tablet stories through the real responsive path.

These variants bypass CallView and only force CallButtons wide while the shared decorator still provides a narrow width. That works today, but the stories will drift as soon as any other CallView child starts reading useResponsiveLayout. Rendering <CallView /> under a wide responsive provider would keep the stories and snapshots aligned with production behavior.

Based on learnings, "Use responsive layout with master-detail on tablets and single stack on phones via useResponsiveLayout hook."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/views/CallView/CallView.stories.tsx` around lines 121 - 162, The Tablet
stories are bypassing CallView by composing CallerInfo and CallButtons directly;
change TabletCallView to render the real CallView wrapped in the app's wide
responsive provider (so CallView and its children read useResponsiveLayout as in
production) instead of returning <CallerInfo /> and <CallButtons />; remove the
manual composition in TabletCallView and ensure the wide/layoutMode='wide' is
provided via the responsive provider or by making useResponsiveLayout return
'wide' for these stories so all TabletConnectedCall, TabletConnectingCall,
TabletMutedCall, TabletOnHoldCall, TabletMutedAndOnHold and TabletSpeakerOn
continue to return <TabletCallView /> but now exercise the real CallView
component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/views/CallView/components/CallActionButton.stories.tsx`:
- Around line 27-35: The mocked responsive layout helper
responsiveLayoutProviderLargeFontValue must mirror useResponsiveLayout's logic:
compute fontScaleLimited by clamping the incoming fontScale to the same min/max
constants used in useResponsiveLayout (use the same clamp logic or import the
constants), derive isLargeFontScale using the same LARGE_FONT_THRESHOLD (i.e.,
compare against the limited value as useResponsiveLayout does), and use
fontScaleLimited (not the raw fontScale) when computing rowHeight and
rowHeightCondensed; update the function to follow those same symbols
(fontScaleLimited, isLargeFontScale, BASE_ROW_HEIGHT, BASE_ROW_HEIGHT_CONDENSED
or the shared constants) so stories match production behavior.

In `@app/views/CallView/components/Dialpad/Dialpad.stories.tsx`:
- Around line 20-30: forceLayoutMode() is ineffective in Storybook because it
only alters a Jest mock; replace it by wrapping each story render with a
deterministic responsive context provider. Create a small LayoutWrapper
component that renders ResponsiveLayoutContext.Provider with value
responsiveValue(width) (use the widths you want for Default and
TabletLandscape), then wrap the story components (or add a story-level
decorator) with LayoutWrapper instead of calling forceLayoutMode; update any
references to forceLayoutMode in this file so stories use LayoutWrapper to
control layout deterministically.

In `@app/views/CallView/index.test.tsx`:
- Around line 12-16: The tests mock react-native's useWindowDimensions with a
static object (mockWindowWidth = 350) which causes
ResponsiveLayoutContext/useCallLayoutMode to always resolve to 'narrow',
breaking assertions for wider layouts; fix by either (A) mocking
useResponsiveLayout (the hook used by ResponsiveLayoutContext) to return an
object that reads the mutable mockWindowWidth so changing mockWindowWidth
affects layout, or (B) stop mocking the context and wrap the test Wrapper with
ResponsiveLayoutProvider so it consumes the mocked useWindowDimensions, or (C)
directly mock useCallLayoutMode to return 'narrow' or 'wide' based on
mockWindowWidth; update tests around Wrapper, useResponsiveLayout,
ResponsiveLayoutProvider, or useCallLayoutMode accordingly so width=800 yields
the expected single-row layout.

---

Nitpick comments:
In `@app/views/CallView/CallView.stories.tsx`:
- Around line 121-162: The Tablet stories are bypassing CallView by composing
CallerInfo and CallButtons directly; change TabletCallView to render the real
CallView wrapped in the app's wide responsive provider (so CallView and its
children read useResponsiveLayout as in production) instead of returning
<CallerInfo /> and <CallButtons />; remove the manual composition in
TabletCallView and ensure the wide/layoutMode='wide' is provided via the
responsive provider or by making useResponsiveLayout return 'wide' for these
stories so all TabletConnectedCall, TabletConnectingCall, TabletMutedCall,
TabletOnHoldCall, TabletMutedAndOnHold and TabletSpeakerOn continue to return
<TabletCallView /> but now exercise the real CallView component.

In `@app/views/CallView/components/CallActionButton.stories.tsx`:
- Around line 42-50: The decorator currently double-wraps stories by nesting
<Story /> inside <Wrapper> within the decorators array; remove the redundant
<Wrapper> from the decorator so it only provides the
ResponsiveLayoutContext.Provider and renders <Story /> directly, leaving
per-story <Wrapper> usage intact—update the decorators definition that
references ResponsiveLayoutContext.Provider, Wrapper, and Story accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 63770d96-dd8f-4436-85f4-38af714eb285

📥 Commits

Reviewing files that changed from the base of the PR and between eb1f951 and 13f532c.

⛔ Files ignored due to path filters (6)
  • app/containers/NewMediaCall/__snapshots__/FilterHeader.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/__snapshots__/index.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/components/Dialpad/__snapshots__/Dialpad.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/components/__snapshots__/CallActionButton.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/components/__snapshots__/CallerInfo.test.tsx.snap is excluded by !**/*.snap
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (16)
  • .gitignore
  • .rnstorybook/storybook.requires.ts
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/views/CallView/components/CallerInfo.stories.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/Dialpad/useDialpadState.ts
  • app/views/CallView/index.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/styles.ts
  • app/views/CallView/types.ts
  • app/views/CallView/useCallLayoutMode.ts
✅ Files skipped from review due to trivial changes (4)
  • app/views/CallView/types.ts
  • .gitignore
  • app/views/CallView/components/CallerInfo.stories.tsx
  • .rnstorybook/storybook.requires.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • app/views/CallView/styles.ts
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/index.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: format
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

Configure Prettier with tabs, single quotes, 130 character width, no trailing commas, arrow parens avoid, and bracket same line

Files:

  • app/views/CallView/useCallLayoutMode.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
  • app/views/CallView/components/Dialpad/useDialpadState.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @rocket.chat/eslint-config base configuration including React, React Native, TypeScript, and Jest plugins

Files:

  • app/views/CallView/useCallLayoutMode.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
  • app/views/CallView/components/Dialpad/useDialpadState.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript with strict mode enabled and configure baseUrl to app/ for import resolution

**/*.{ts,tsx}: Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Prefer interfaces over type aliases for defining object shapes in TypeScript
Use enums for sets of related constants rather than magic strings or numbers

Files:

  • app/views/CallView/useCallLayoutMode.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
  • app/views/CallView/components/Dialpad/useDialpadState.ts
app/views/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Place screen components in app/views/ directory

Files:

  • app/views/CallView/useCallLayoutMode.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
  • app/views/CallView/components/Dialpad/useDialpadState.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use descriptive names for functions, variables, and classes that clearly convey their purpose
Write comments that explain the 'why' behind code decisions, not the 'what'
Keep functions small and focused on a single responsibility
Use const by default, let when reassignment is needed, and avoid var
Prefer async/await over .then() chains for handling asynchronous operations
Use explicit error handling with try/catch blocks for async operations
Avoid deeply nested code; refactor complex logic into helper functions

Files:

  • app/views/CallView/useCallLayoutMode.ts
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
  • app/views/CallView/components/Dialpad/useDialpadState.ts
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/hooks/useResponsiveLayout/**/*.{ts,tsx} : Use responsive layout with master-detail on tablets and single stack on phones via useResponsiveLayout hook
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/hooks/useResponsiveLayout/**/*.{ts,tsx} : Use responsive layout with master-detail on tablets and single stack on phones via useResponsiveLayout hook

Applied to files:

  • app/views/CallView/useCallLayoutMode.ts
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
📚 Learning: 2026-03-30T15:49:30.957Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6875
File: app/containers/RoomItem/Actions.tsx:12-12
Timestamp: 2026-03-30T15:49:30.957Z
Learning: In RocketChat/Rocket.Chat.ReactNative, `react-native-worklets` version 0.6.1 does NOT export a built-in Jest mock (e.g., no `react-native-worklets/lib/module/mock`). The correct Jest mock approach for this version is to add a manual mock in `jest.setup.js`: `jest.mock('react-native-worklets', () => ({ scheduleOnRN: jest.fn((fn, ...args) => fn(...args)) }))`.

Applied to files:

  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/index.test.tsx
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate

Applied to files:

  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/index.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
  • app/views/CallView/components/Dialpad/useDialpadState.ts
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/index.tsx : Configure Redux provider, theme, navigation, and notifications in app/index.tsx

Applied to files:

  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/index.test.tsx
📚 Learning: 2026-03-17T19:15:30.463Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6970
File: .maestro/tests/room/share-message.yaml:77-79
Timestamp: 2026-03-17T19:15:30.463Z
Learning: In `.maestro/tests/room/share-message.yaml` (Rocket.Chat React Native), the `tapOn: point: 5%,10%` step is intentional: it taps the empty area above the bottom sheet and keyboard to dismiss both simultaneously. Using `action-sheet-handle` instead would only close the sheet but not the keyboard. This pattern is acceptable when both need to be dismissed together in a single step.

Applied to files:

  • app/views/CallView/components/CallButtons.test.tsx
📚 Learning: 2026-03-10T15:21:45.098Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 7046
File: app/containers/InAppNotification/NotifierComponent.stories.tsx:46-75
Timestamp: 2026-03-10T15:21:45.098Z
Learning: In `app/containers/InAppNotification/NotifierComponent.tsx` (React Native, Rocket.Chat), `NotifierComponent` is exported as a Redux-connected component via `connect(mapStateToProps)`. The `isMasterDetail` prop is automatically injected from `state.app.isMasterDetail` and does not need to be passed explicitly at call sites or in Storybook stories that use the default (connected) export.

Applied to files:

  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to app/AppContainer.tsx : Implement root navigation container logic in app/AppContainer.tsx to switch between authentication states

Applied to files:

  • app/views/CallView/CallView.stories.tsx
📚 Learning: 2026-03-15T13:55:42.038Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6911
File: app/containers/markdown/Markdown.stories.tsx:104-104
Timestamp: 2026-03-15T13:55:42.038Z
Learning: In Rocket.Chat React Native, the markdown parser requires a space between the underscore wrapping italic text and a mention sigil (_ mention _ instead of _mention_). Ensure stories and tests that include italic-wrapped mentions follow this form to guarantee proper parsing. Specifically, for files like app/containers/markdown/Markdown.stories.tsx, and any test/content strings that exercise italic-mentions, use the pattern _ mention _ (with spaces) to prevent the mention from being treated as plain text. Validate any test strings or story content accordingly.

Applied to files:

  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
📚 Learning: 2026-04-07T17:49:17.519Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.519Z
Learning: Applies to index.js : Register app entry point in index.js with conditional Storybook loading

Applied to files:

  • app/views/CallView/index.test.tsx
🔇 Additional comments (4)
app/views/CallView/components/CallActionButton.stories.tsx (1)

94-105: Nice addition for tablet/wide visual coverage

This story cleanly captures the single-row tablet action layout and keeps stable testIDs for inspection.

app/views/CallView/useCallLayoutMode.ts (1)

5-7: Nice extraction of the layout breakpoint.

Centralizing the wide/narrow switch here keeps the CallView pieces on one responsive rule.

Based on learnings, "Use responsive layout with master-detail on tablets and single stack on phones via useResponsiveLayout hook."

app/views/CallView/components/Dialpad/useDialpadState.ts (1)

4-12: Clean view-state wrapper.

Bundling theme colors and the dialpad value behind one hook keeps Dialpad focused on rendering.

app/views/CallView/components/CallButtons.test.tsx (1)

102-179: Good use of within() for row membership.

These assertions pin the actual wide/narrow grouping instead of only checking that the buttons exist somewhere.

Comment thread app/views/CallView/components/CallActionButton.stories.tsx Outdated
Comment thread app/views/CallView/components/Dialpad/Dialpad.stories.tsx Outdated
Comment thread app/views/CallView/index.test.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CLAUDE.md`:
- Line 69: Update the platform name in the documentation string
`.github/PULL_REQUEST_TEMPLATE.md` so it reads "GitHub" with a capital H; locate
the occurrence of "Follow `.github/PULL_REQUEST_TEMPLATE.md` when opening PRs."
in CLAUDE.md (the exact quoted text) and change the platform name to "GitHub" to
match official capitalization in contributor-facing docs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2cd9fcab-4656-4e98-8ad2-5029c720d4f3

📥 Commits

Reviewing files that changed from the base of the PR and between 9f53e6f and fdd2229.

📒 Files selected for processing (2)
  • .gitignore
  • CLAUDE.md
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: format
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/hooks/useResponsiveLayout/**/*.{ts,tsx} : Use responsive layout with master-detail on tablets and single stack on phones via useResponsiveLayout hook
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Use Yarn as the package manager (npm will not work)
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Node >= 18 required (CONTRIBUTING specifies 22.14.0)
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Run `yarn lint` which executes both `eslint .` and `tsc` type-checking; both must pass
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Run Jest tests with `TZ=UTC` environment variable
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Use Redux for primary state management with reducers in `app/reducers/`, sagas in `app/sagas/`, and actions in `app/actions/`
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Use Zustand for newer state management slices alongside Redux
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Use WatermelonDB (nozbe/watermelondb) for local database of messages/rooms with code in `app/lib/database/`
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Use react-navigation v7 (native-stack + drawer) for navigation with stacks in `app/stacks/`
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Tablet layouts should gate on `MIN_WIDTH_MASTER_DETAIL_LAYOUT` and `isTablet` for master-detail layout
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Do not bypass pre-commit hooks with `--no-verify`
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Follow `.github/PULL_REQUEST_TEMPLATE.md` when opening PRs
Learnt from: CR
URL: 
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:35:41.091Z
Learning: Normalize translations by running `yarn organize-translations` in `app/i18n/`
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use ESLint with rocket.chat/eslint-config base configuration including React, React Native, TypeScript, and Jest plugins

Applied to files:

  • CLAUDE.md
🪛 LanguageTool
CLAUDE.md

[uncategorized] ~69-~69: The official name of this software platform is spelled with a capital “H”.
Context: ...not bypass with --no-verify. - Follow .github/PULL_REQUEST_TEMPLATE.md when opening ...

(GITHUB)

Comment thread CLAUDE.md Outdated
@diegolmello diegolmello changed the title feat: tablet support feat(voip): tablet and landscape layout Apr 8, 2026
- Add roomId?: string | null to MockCallOverrides so callers can
  override the seeded roomId.
- Change DEFAULT_CONTACT.sipExtension from '2244' to '' so the
  Message-button predicate (Boolean(sipExtension) || roomId == null)
  evaluates to false by default.
- Seed roomId as overrides.roomId ?? 'mock-room-id' in seedMockCall()
  so CallView's Message action button is enabled out of the box.

Verification: CallButtons.tsx:50 messageDisabled = Boolean(contact.sipExtension) || roomId == null
With sipExtension='' and roomId='mock-room-id', both operands are false → button enabled.
Replace the forceLayoutMode() hack (which patched the jest mock at render
time and was a no-op in Storybook UI) with a LayoutWrapper component that
supplies a fixed width via ResponsiveLayoutContext.Provider:

  width=350  → narrow  (< MIN_WIDTH_MASTER_DETAIL_LAYOUT=700)
  width=800  → wide    (≥ MIN_WIDTH_MASTER_DETAIL_LAYOUT=700)

In Storybook UI the real useCallLayoutMode hook reads from this context,
making the Default/TabletLandscape stories deterministic regardless of host
device width. In Jest, useCallLayoutMode is already mocked at module level
in Dialpad.test.tsx so the context provider is inert there.

Removed: import of callLayoutModule and forceLayoutMode helper.
Previous mock replaced the ResponsiveLayoutContext export, but
useResponsiveLayout's closure captured the original context, so
components never saw the mocked values (fontScale ended up undefined,
producing NaN font sizes in snapshots).

Mock useResponsiveLayout directly and drive it from useWindowDimensions
so that flipping mockWindowWidth between 350 and 800 actually toggles
layoutMode. Regenerate snapshots with the now-correct font metrics.
Mirror useResponsiveLayout's FONT_SCALE_LIMIT clamp so stories render
with the same layout math as production for non-default font scales.
Drop useDialpadState wrapper and inline useTheme + useDialpadValue
directly in Dialpad. Move useCallLayoutMode out of CallView/index and
into CallButtons so resize re-renders only the buttons subtree instead
of the entire CallView.
@diegolmello diegolmello had a problem deploying to approve_e2e_testing April 8, 2026 17:02 — with GitHub Actions Failure
@diegolmello diegolmello had a problem deploying to experimental_ios_build April 8, 2026 17:07 — with GitHub Actions Failure
@diegolmello diegolmello had a problem deploying to official_android_build April 8, 2026 17:07 — with GitHub Actions Failure
@diegolmello diegolmello had a problem deploying to experimental_android_build April 8, 2026 17:07 — with GitHub Actions Failure
@diegolmello diegolmello merged commit e05a7aa into feat.voip-lib-new Apr 8, 2026
6 of 11 checks passed
@diegolmello diegolmello deleted the feat.voip-tablet-layout-2 branch April 8, 2026 17:21
diegolmello added a commit that referenced this pull request Apr 9, 2026
Add layout-land/activity_incoming_call.xml so Android auto-selects a
two-column layout when the device is in landscape. Header stays centered
at the top (32dp padding), caller info fills the left half, and decline/
accept buttons sit side-by-side on the right half — matching the iOS
landscape design shipped in #7110.

Zero changes to IncomingCallActivity.kt, AndroidManifest.xml, or the
existing portrait layout. All 12 view IDs required by the Activity are
preserved with the same widget types.
diegolmello added a commit that referenced this pull request Apr 22, 2026
…/Decline (#7215)

* merge feat.voip-lib

* feat(voip): enhance call handling with UUID mapping and event listeners

* Base call UI

* feat(voip): integrate Zustand for call state management and enhance CallView UI

* feat(voip): add simulateCall function for mock call handling in UI development

* refactor(CallView): update button handlers and improve UI responsiveness

* Add pause-shape-unfilled icon

* Base CallHeader

* toggleFocus

* collapse buttons

* Header components

* Hide header when no call

* Timer

* Add use memo

* Add voice call item on sidebar

* cleanup

* Temp use @rocket.chat/media-signaling from .tgz

* cleanup

* Check module and permissions to enable voip

* Refactor stop method to use optional chaining for media signal listeners

* voip push first test

* Add VoIP call handling with pending call management

- Implemented VoIP push notification handling in index.js, including storing call info for later processing.
- Added CallKeep event handlers for answering and ending calls from a cold start.
- Introduced a new CallIdUUID module to convert call IDs to deterministic UUIDs for compatibility with CallKit.
- Created a pending call store to manage incoming calls when the app is not fully initialized.
- Updated deep linking actions to include VoIP call handling.
- Enhanced MediaSessionInstance to process pending calls and manage call states effectively.

* Remove pending store and create getInitialEvents on app/index

* Attempt to make iOS calls work from cold state

* lint and format

* Patch callkeep ios

* Temp send iOS voip push token on gcm

* Temp fix require cycle

* chore: format code and fix lint issues [skip ci]

* CallIDUUID module on android and voip push

* Add setCallUUID on useCallStore to persist calls accepted on native Android

* remove callkeep from notification

* Android Incoming Call UI POC

* Refactor VoIP handling: Migrate VoIP-related classes to a new package structure, removing deprecated modules and consolidating functionality. Update imports in MainApplication and NotificationIntentHandler to reflect changes. This cleanup enhances code organization and prepares for future VoIP feature enhancements.

* Remove VoipForegroundService

* cleanup and use caller instead of callerName

* Cleanup and make iOS build again

* Refactor VoIP handling: Remove unused event emissions for call answered and declined, switch from SharedPreferences to in-memory storage for pending VoIP call data, and update method signatures for better clarity. This cleanup enhances performance and prepares for future VoIP feature improvements.

* Refactor VoIP handling: Introduce a new VoipPayload class to encapsulate call data, streamline notification processing, and enhance method signatures across the VoIP module. This update improves code clarity and prepares for future feature enhancements.

* Migrate react-native-voip-push-notifications to VoipModule

* Refactor VoIP module: Update package structure by moving VoipTurboPackage to the main package and removing the obsolete NativeVoipSpec class. Adjust imports in MainApplication and VoipModule to reflect these changes, enhancing code organization and maintainability.

* Unify emitters

* Move CallKeep listeners from MediaSessionInstance to getInitialEvents

* Clear callkeep on endcall

* Unify getInitialEvents logic

* getInitialEvents -> MediaCallEvents

* chore: format code and fix lint issues [skip ci]

* feat(Android): Add full screen incoming call (#6977)

* feat: Update call UI (#6990)

* feat: Handle audio routing, e.g., Bluetooth headset vs. internal speaker switching (#6992)

* fix: empty space when not on call (#6993)

* feat: Dialpad (#7000)

* action: organized translations

* feat: start call (#7024)

* chore: format code and fix lint issues

* feat: Pre flight (#7038)

* action: organized translations

* feat: Receive voip push notifications from backend (#7045)

* feat: Refactor media session handling and improve disconnect logic (#7065)

* feat: Control incoming call from native (#7066)

* feat: Voice message blocks (#7057)

* feat: native accept success event (#7068)

* feat(voip): call waiting, busy detection, and videoconf blocking (#7077)

* action: organized translations

* feat(voip): tap-to-hide call controls with animations (#7078)

* feat(voip): navigate to call DM from message button and header (#7082)

* feat(voip): tablet and landscape layout (#7110)

* chore: develop into feat.voip-lib-new (RN 81 + Expo 54 + reanimated 4 + true-sheet + iOS 26) (#7114)

* chore: format code and fix lint issues

* feat(voip): android landscape layout for IncomingCallActivity (#7116)

* Update agents files

* feat(voip): Support a11y (#7106)

* Fix content cutting on iOS on some edge cases

* pods

* Ignore .worktrees on jest

* chore: Merge develop into feat.voip-lib-new (#7129)

* fix(voip): show CallKit UI when call is active in background (#7128)

* chore: Update media-signaling to 0.2.0 (#7153)

* feat(voip): migrate iOS accept/reject from DDP to REST (#7124)

* Fix icons

* feat(voip): migrate Android accept/reject from DDP to REST (#7127)

* test(voip): integration tests for CallView pipeline (#7161)

* feat(voip): display video conf provider as subtitle (#7160)

* fix(voip): CallView button grid and correct landscape/dialpad layouts (#7164)

* fix(voip): prevent stale MMKV cache on Android first-install accept

MMKVKeyManager.initialize ran in MainApplication.onCreate before the JS
engine started and opened the default MMKV file via the Tencent 1.2 JAR
when it was still empty. Tencent caches instances per-ID in a singleton
registry, so that empty-state view was held for the rest of the process.
JS later wrote credentials through react-native-mmkv (MMKV Core 2.0),
which has its own separate registry. When a VoIP push arrived,
Ejson.getMMKV() got the cached empty Tencent instance and reported
"No userId found in MMKV for server". Closing and reopening the app
cleared the cache, which is why only the very first call after install
failed.

Drop the open/verify block — the encryption key is already cached from
SecureKeystore, so no MMKV handle is needed here. The first Tencent
instance is now created inside Ejson.getMMKV() after JS has written,
so it scans the file fresh.

* fix(voip): prevent duplicate ringtone on Android incoming call (#7158)

* fix(voip): set explicit snaps for NewMediaCall bottom sheet (#7165)

* Update app/lib/services/voip/MediaSessionStore.ts

Co-authored-by: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com>

* fix: make startVoipFork reactive to permissions-changed (#7151)

* fix(android): remove MediaProjectionService from merged manifest (#7190)

* fix(voip): Phone account creation (#7170)

* feat: add Enable Mobile Ringing toggle in user preferences (#7155)

* fix(voip): ship blockers for PushKit, licensing, outbound calls, push tokens (#7167)

* fix(android): Play Store mic discoverability, safer FCM logs, avatar auth via headers (#7171)

* fix(ios): serialize VoipService bridge statics (#7169)

* fix(voip): Android DDP thread safety and VoipPayload bundle parity (#7168)

* chore(voip): dead-code and hygiene sweep (#7174)

* refactor(voip): decouple navigateToCallRoom from Redux and backfill REST/connect tests (#7176)

* test(voip): tighten ringing endCall assertion and add VideoConf VoIP-lock saga coverage (#7177)

* fix(ios): harden VoIP DDP WebSocket client on receive failures and TLS (#7173)

* refactor(voip): MediaCallEvents Redux adapters and resetVoipState (#7178)

* refactor(voip): decouple peer autocomplete from Redux; simplify NewMediaCall (#7175)

* fix(ios): add NS_SWIFT_NAME to Challenge.runChallenge for Swift 6.2 compatibility

Swift 6.2 (Xcode 26.x / macos-26 runner) auto-renames the Objective-C
method runChallenge:didReceiveChallenge:completionHandler: to
run(_:didReceive:completionHandler:) when imported into Swift.

Add NS_SWIFT_NAME to explicitly pin the Swift import name, preventing
the compiler from applying its heuristics. This keeps the existing
Swift call site in DDPClient.swift working without changes.

* fix(ios): cancel old URLSession/webSocketTask before reconnecting in DDPClient.connect (#7197)

* fix(ios): add NSLock to nativeAcceptHandledCallIds and 10s REST timeout to handleNativeAccept (#7198)

* feat(android): create VoipCallService with FOREGROUND_SERVICE_MICROPHONE (#7199)

* fix(android): start VoipCallService on accept, stop on hangup/timeout, install end-call listener (#7200)

* fix(voip): enable DM nav for users with SIP extension (#7203)

* fix(android): handle null VoiceConnection in answerIncomingCall, notify JS (#7201)

* fix(voip): resolve closure capture ordering in handleNativeAccept (#7209)

* fix(android): integrate VoIP modules with SSL-pinned OkHttpClient (#7208)

* fix(push): gate id and voipToken behind server version checks, fix VideoConf caller extra (#7210)

* fix(voip): remove sensitive data from production logs (#7207)

* fix(android): remove isRunning guard + add double-tap guard on Accept/Decline

- VoipCallService: remove if (!isRunning) guard, call startForeground unconditionally
  (idempotent on Android, fixes Android 14+ foreground service requirement)
- IncomingCallActivity: add AtomicBoolean guard on handleAccept/handleDecline
  to prevent double-tap from triggering multiple service starts

---------

Co-authored-by: diegolmello <diegolmello@users.noreply.github.com>
Co-authored-by: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant