Skip to content

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

Merged
diegolmello merged 2 commits into
feat.voip-lib-newfrom
refactor/voip-pr3-service-boundary-rest-tests
Apr 20, 2026
Merged

refactor(voip): decouple navigateToCallRoom from Redux and backfill REST/connect tests#7176
diegolmello merged 2 commits into
feat.voip-lib-newfrom
refactor/voip-pr3-service-boundary-rest-tests

Conversation

@diegolmello

@diegolmello diegolmello commented Apr 17, 2026

Copy link
Copy Markdown
Member

Proposed changes

Removes the hidden Redux dependency from the VoIP navigateToCallRoom helper and backfills unit coverage around REST push-token registration, the connect → VoIP media-session lifecycle, and the iOS-specific connect branch.

  • app/lib/services/voip/navigateToCallRoom.ts no longer reads auxStore; it now takes { isMasterDetail } as an argument. Callers — CallButtons and MediaCallHeader/Content — read state.app.isMasterDetail via useAppSelector and pass it in.
  • app/lib/services/voip/navigateToCallRoom.test.ts drops the auxStore mock and adds a case asserting that isMasterDetail: false is forwarded into goRoom.
  • app/lib/services/restApi.test.ts adds coverage for registerPushToken: early return when there is no device token, iOS registers the apn payload without voipToken when the VoIP token is missing (matches current feat.voip-lib-new behavior after the guard drop), Android registration without a VoIP token (no voipToken in payload), dedup on repeated calls, and the iOS APNs payload shape when both tokens are present.
  • app/lib/services/connect.test.ts now asserts mediaSessionInstance.reset is called exactly once when disconnect() runs.
  • app/lib/services/connect.ios.test.ts mocks ../methods/helpers/deviceInfo instead of ../methods/helpers so the isIOS override matches the module connect.ts actually imports.

Branch was rebased onto feat.voip-lib-new to pick up the iOS early-return removal; the iOS-no-voip test was flipped accordingly.

No behavior change for end users: the navigation UX is identical, and the VoIP lifecycle assertions pin existing behavior that was previously untested.

Issue(s)

Part of the voip-lib-new cleanup track (PR-3: service boundary + REST/connect test backfill).

How to test or reproduce

TZ=UTC yarn test --testPathPattern='restApi.test|navigateToCallRoom.test|connect.test.ts|connect.ios.test'

Manual smoke: place/receive a VoIP call, tap the message/header button — it should still navigate to the call's DM on both phone and tablet (master-detail) layouts.

Screenshots

N/A — refactor + tests only.

Types of changes

  • Bugfix (non-breaking change which fixes an issue) — iOS connect test was mocking the wrong module path
  • Improvement (non-breaking change which improves a current function) — removes hidden Redux coupling in VoIP nav helper; adds missing unit coverage
  • 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

navigateToCallRoom was previously importable from anywhere but silently required the Redux auxStore to be populated. Injecting isMasterDetail makes the dependency explicit and matches how other navigation helpers already read layout state at the call site. The connect.ios.test mock fix is small but load-bearing — the previous mock targeted ../methods/helpers, which re-exports isIOS from ./deviceInfo, so the override never reached the copy imported by connect.ts.

Summary by CodeRabbit

  • Refactor

    • Improved call navigation to better manage master detail layout state through explicit parameter passing.
  • Tests

    • Expanded push token registration coverage with platform-specific iOS and Android behavior validation.
    • Enhanced VoIP service initialization and disconnect handling test scenarios.

@coderabbitai

coderabbitai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

navigateToCallRoom was changed to accept an explicit isMasterDetail parameter (caller-provided) instead of reading from the store. Call sites in UI components were updated to read state and pass that value. Tests and mocks were adjusted and expanded, including new registerPushToken tests and mediaSessionInstance reset assertions.

Changes

Cohort / File(s) Summary
VoIP Navigation Refactor
app/lib/services/voip/navigateToCallRoom.ts, app/lib/services/voip/navigateToCallRoom.test.ts
Function signature now requires { isMasterDetail }; removed internal store read. Tests updated to pass explicit { isMasterDetail: ... } and include a case asserting false is forwarded to goRoom.
UI Callers Updated
app/containers/MediaCallHeader/components/Content.tsx, app/views/CallView/components/CallButtons.tsx
Both components now select state.app.isMasterDetail via useAppSelector and pass it to navigateToCallRoom({ isMasterDetail }) in their press handlers; other handler behavior unchanged.
VoIP/connect Tests & Mocks
app/lib/services/connect.test.ts, app/lib/services/connect.ios.test.ts
Jest mocks for ./voip/MediaSessionInstance simplified to keep only reset. iOS test mocking narrowed to .../methods/helpers/deviceInfo with isIOS: true. Added test asserting disconnect() calls mediaSessionInstance.reset() once.
REST API / Push Token Tests
app/lib/services/restApi.test.ts
Added sdk.post mock and mocks for getDeviceToken, getLastVoipToken, and react-native-device-info. Introduced helper to load registerPushToken under different Platform.OS values and tests covering early exit on missing token, platform-specific payloads, deduplication, and inclusion/omission of voipToken.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

type: chore

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: decoupling navigateToCallRoom from Redux and adding test coverage for REST/connect services.

✏️ 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.

🧹 Nitpick comments (1)
app/lib/services/restApi.test.ts (1)

42-57: Consider making Platform.OS mutation explicit by requiring Platform after jest.resetModules()

While the current pattern works because jest-expo's Platform mock is a stable singleton that persists across module resets, re-requiring Platform after jest.resetModules() makes the intent clearer and removes reliance on implementation details:

♻️ More explicit approach
 function loadRegisterPushToken(platform: 'ios' | 'android' = 'android') {
 	jest.resetModules();
-	Object.defineProperty(Platform, 'OS', { configurable: true, writable: true, value: platform });
 	// eslint-disable-next-line `@typescript-eslint/no-require-imports`
+	const { Platform: FreshPlatform } = require('react-native');
+	Object.defineProperty(FreshPlatform, 'OS', { configurable: true, writable: true, value: platform });
+	// eslint-disable-next-line `@typescript-eslint/no-require-imports`
 	const notifications = require('../notifications');

This also aligns the afterEach pattern: update line 109 to restore from the fresh Platform instance if you adopt this change.

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

In `@app/lib/services/restApi.test.ts` around lines 42 - 57, The test mutates
Platform.OS using a Platform instance that may be stale after
jest.resetModules(); update loadRegisterPushToken to require/import Platform
immediately after jest.resetModules() and then set Platform.OS (i.e., re-require
Platform inside loadRegisterPushToken before Object.defineProperty), so the
mutation targets the fresh mock instance; also update the corresponding
afterEach restore to read/reset Platform from a freshly required Platform (the
same pattern referenced on line ~109) to restore OS on the new instance.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/lib/services/restApi.test.ts`:
- Around line 42-57: The test mutates Platform.OS using a Platform instance that
may be stale after jest.resetModules(); update loadRegisterPushToken to
require/import Platform immediately after jest.resetModules() and then set
Platform.OS (i.e., re-require Platform inside loadRegisterPushToken before
Object.defineProperty), so the mutation targets the fresh mock instance; also
update the corresponding afterEach restore to read/reset Platform from a freshly
required Platform (the same pattern referenced on line ~109) to restore OS on
the new instance.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 958cd412-5203-4185-a50c-82217885025a

📥 Commits

Reviewing files that changed from the base of the PR and between 9c84d4c and 6860d53.

📒 Files selected for processing (7)
  • app/containers/MediaCallHeader/components/Content.tsx
  • app/lib/services/connect.ios.test.ts
  • app/lib/services/connect.test.ts
  • app/lib/services/restApi.test.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
  • app/lib/services/voip/navigateToCallRoom.ts
  • app/views/CallView/components/CallButtons.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). (1)
  • GitHub Check: ESLint and Test / run-eslint-and-test
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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/lib/services/connect.test.ts
  • app/views/CallView/components/CallButtons.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
  • app/lib/services/connect.ios.test.ts
  • app/lib/services/voip/navigateToCallRoom.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
  • app/lib/services/restApi.test.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/lib/services/connect.test.ts
  • app/views/CallView/components/CallButtons.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
  • app/lib/services/connect.ios.test.ts
  • app/lib/services/voip/navigateToCallRoom.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
  • app/lib/services/restApi.test.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/lib/services/connect.test.ts
  • app/views/CallView/components/CallButtons.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
  • app/lib/services/connect.ios.test.ts
  • app/lib/services/voip/navigateToCallRoom.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
  • app/lib/services/restApi.test.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/lib/services/connect.test.ts
  • app/views/CallView/components/CallButtons.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
  • app/lib/services/connect.ios.test.ts
  • app/lib/services/voip/navigateToCallRoom.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
  • app/lib/services/restApi.test.ts
app/views/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Place screen components in app/views/ directory

Files:

  • app/views/CallView/components/CallButtons.tsx
app/containers/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Place reusable UI components in app/containers/ directory

Files:

  • app/containers/MediaCallHeader/components/Content.tsx
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/navigateToCallRoom.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
🧠 Learnings (12)
📓 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/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.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 app/lib/services/connect.ts : Manage server connection in app/lib/services/connect.ts

Applied to files:

  • app/lib/services/connect.test.ts
📚 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 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/lib/services/connect.test.ts
  • app/views/CallView/components/CallButtons.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
  • app/lib/services/connect.ios.test.ts
  • app/lib/services/voip/navigateToCallRoom.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
  • app/lib/services/restApi.test.ts
📚 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/lib/services/connect.test.ts
  • app/lib/services/connect.ios.test.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
  • app/lib/services/restApi.test.ts
📚 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/components/CallButtons.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
📚 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 app/AppContainer.tsx : Implement root navigation container logic in app/AppContainer.tsx to switch between authentication states

Applied to files:

  • app/views/CallView/components/CallButtons.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
  • app/lib/services/voip/navigateToCallRoom.ts
📚 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 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/CallButtons.tsx
📚 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 app/theme.tsx : Configure theming context in app/theme.tsx

Applied to files:

  • app/views/CallView/components/CallButtons.tsx
📚 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 app/index.tsx : Configure Redux provider, theme, navigation, and notifications in app/index.tsx

Applied to files:

  • app/views/CallView/components/CallButtons.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
📚 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 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/containers/MediaCallHeader/components/Content.tsx
  • app/lib/services/voip/navigateToCallRoom.ts
📚 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 app/lib/store/**/*.{ts,tsx} : Configure Redux store in app/lib/store/ with middleware for saga, app state, and internet state

Applied to files:

  • app/lib/services/voip/navigateToCallRoom.test.ts
📚 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 app/lib/services/sdk.ts : Use Rocket.Chat JS SDK in app/lib/services/sdk.ts for WebSocket real-time subscriptions

Applied to files:

  • app/lib/services/restApi.test.ts
🔇 Additional comments (7)
app/lib/services/connect.test.ts (1)

309-314: LGTM!

The new test correctly verifies that disconnect() invokes mediaSessionInstance.reset() exactly once, matching the simplified mock shape above.

app/lib/services/connect.ios.test.ts (1)

7-10: LGTM — mock target fix aligns test isIOS with connect.ts.

Narrowing the mock to ../methods/helpers/deviceInfo (instead of the barrel) ensures the isIOS consumed by connect.ts is the mocked value, which is the intended bugfix for this PR.

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

31-60: LGTM!

Cleanly threads isMasterDetail from Redux via useAppSelector into navigateToCallRoom, removing the hidden store coupling inside the VoIP service.

app/containers/MediaCallHeader/components/Content.tsx (1)

3-34: LGTM!

Matches the new navigateToCallRoom API and the wiring mirrors CallButtons.tsx. Disabled state and error swallowing are preserved.

app/lib/services/voip/navigateToCallRoom.ts (1)

10-40: Nice boundary cleanup.

Making isMasterDetail an explicit parameter removes the direct auxStore dependency from the VoIP service, aligning with the PR-3 goal of keeping the VoIP layer framework-/store-agnostic. Signature is a non-breaking refactor confined to the two internal call sites updated in this PR.

app/lib/services/voip/navigateToCallRoom.test.ts (1)

210-226: Good coverage addition.

The new case asserting isMasterDetail: false is forwarded into goRoom complements the existing true assertions and guards against regressions where the argument might be dropped or hardcoded. Removal of the auxStore mock is consistent with the updated signature.

app/lib/services/restApi.test.ts (1)

105-186: Nice coverage on registerPushToken.

Good split across the four behaviors that matter (missing push token early-exit, iOS-only VoIP gating, Android voipToken omission with an explicit hasOwnProperty check on line 154, dedup across repeated calls with identical tokens, and the full iOS APN payload shape on lines 175-184). Using jest.resetModules() inside the helper so the dedup-cache state is per-test is the right call, and capturing mockSdkPost in the ./sdk mock factory closure keeps assertions consistent across module resets.

…d tests.

navigateToCallRoom no longer reads Redux; CallButtons and MediaCallHeader pass layout from useAppSelector. registerPushToken and disconnect VoIP lifecycle are covered by unit tests. connect.ios tests now mock deviceInfo so isIOS matches connect.ts.

Made-with: Cursor
Base branch feat.voip-lib-new removed the iOS early-return when
voipToken is missing. Flip the test to assert registerPushToken
now posts an apn payload without voipToken.
@diegolmello diegolmello force-pushed the refactor/voip-pr3-service-boundary-rest-tests branch from 6860d53 to 0a7c7e9 Compare April 20, 2026 19:18
@diegolmello diegolmello had a problem deploying to official_android_build April 20, 2026 19:22 — with GitHub Actions Failure
@diegolmello diegolmello had a problem deploying to experimental_android_build April 20, 2026 19:22 — with GitHub Actions Failure
@diegolmello diegolmello had a problem deploying to experimental_ios_build April 20, 2026 19:22 — with GitHub Actions Failure
@diegolmello diegolmello changed the title refactor(voip): PR-3 service boundary + REST/connect test backfill refactor(voip): decouple navigateToCallRoom from Redux and backfill REST/connect tests Apr 20, 2026
@diegolmello diegolmello merged commit 39d4ddb into feat.voip-lib-new Apr 20, 2026
5 of 11 checks passed
@diegolmello diegolmello deleted the refactor/voip-pr3-service-boundary-rest-tests branch April 20, 2026 19:23
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