@cometchat/calls-sdk-react-native 5.0.0-beta.3 → 5.0.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -35,6 +35,8 @@ let react = require("react");
35
35
  react = __toESM(react);
36
36
  let lib_jitsi_meet = require("lib-jitsi-meet");
37
37
  lib_jitsi_meet = __toESM(lib_jitsi_meet);
38
+ let __react_native_async_storage_async_storage = require("@react-native-async-storage/async-storage");
39
+ __react_native_async_storage_async_storage = __toESM(__react_native_async_storage_async_storage);
38
40
  let react_native = require("react-native");
39
41
  let react_native_webrtc = require("react-native-webrtc");
40
42
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -142,10 +144,12 @@ const VIDEO_QUALITY_LEVELS = {
142
144
  LOW: 180,
143
145
  NONE: 0
144
146
  };
145
- const PLATFORM = {
147
+ const SDK_PLATFORM = {
146
148
  WEB: "web",
147
149
  ANDROID: "android",
148
- IOS: "ios"
150
+ IOS: "ios",
151
+ REACT_NATIVE_ANDROID: "react-native-android",
152
+ REACT_NATIVE_IOS: "react-native-ios"
149
153
  };
150
154
  const EVENT_LISTENER_METHODS = {
151
155
  SessionStatusListener: {
@@ -260,7 +264,7 @@ function calculateTileLayout(containerWidth, containerHeight, numberOfTiles) {
260
264
  const tileArea = totalArea / numberOfTiles;
261
265
  const minArea = MIN_TILE_WIDTH * MIN_TILE_WIDTH * MIN_ASPECT_RATIO;
262
266
  if (tileArea < minArea) {
263
- const columnCount$1 = Math.floor(containerWidth / MIN_TILE_WIDTH);
267
+ const columnCount$1 = Math.max(2, Math.floor(containerWidth / MIN_TILE_WIDTH));
264
268
  const rowCount$1 = Math.ceil(numberOfTiles / columnCount$1);
265
269
  const totalHorizontalGap$1 = columnCount$1 * GRID_GAP;
266
270
  const tileWidth$1 = (containerWidth - totalHorizontalGap$1) / columnCount$1;
@@ -443,6 +447,31 @@ function isDeviceEqual(device1, device2) {
443
447
  function getDefaultDevice(devices) {
444
448
  return devices.find((device) => device.deviceId === "default") || devices[0];
445
449
  }
450
+ /**
451
+ * Returns a promise that resolves when the given Zustand store
452
+ * satisfies the provided predicate. Resolves immediately if the
453
+ * condition is already met. Includes a timeout to avoid hanging
454
+ * forever (defaults to 5 000 ms).
455
+ */
456
+ function waitForStoreState(store, predicate, timeoutMs = 5e3) {
457
+ return new Promise((resolve, reject) => {
458
+ if (predicate(store.getState())) {
459
+ resolve();
460
+ return;
461
+ }
462
+ const timer = setTimeout(() => {
463
+ unsubscribe();
464
+ reject(new Error("waitForStoreState timed out"));
465
+ }, timeoutMs);
466
+ const unsubscribe = store.subscribe((state) => {
467
+ if (predicate(state)) {
468
+ clearTimeout(timer);
469
+ unsubscribe();
470
+ resolve();
471
+ }
472
+ });
473
+ });
474
+ }
446
475
 
447
476
  //#endregion
448
477
  //#region calls-sdk-core/utils/try-catch.ts
@@ -505,6 +534,13 @@ var SessionMethodsCore = class {
505
534
  unMuteAudioTrack();
506
535
  }
507
536
  /**
537
+ * Toggles the local user's audio mute state.
538
+ * If audio is muted, it will be unmuted, and vice versa.
539
+ */
540
+ static toggleAudio() {
541
+ toggleAudioTrack();
542
+ }
543
+ /**
508
544
  * Pauses the local user's video stream.
509
545
  */
510
546
  static pauseVideo() {
@@ -517,6 +553,13 @@ var SessionMethodsCore = class {
517
553
  resumeVideoTrack();
518
554
  }
519
555
  /**
556
+ * Toggles the local user's video stream.
557
+ * If video is paused, it will be resumed, and vice versa.
558
+ */
559
+ static toggleVideo() {
560
+ toggleVideoTrack();
561
+ }
562
+ /**
520
563
  * Local user leaves the current session.
521
564
  */
522
565
  static leaveSession() {
@@ -535,6 +578,13 @@ var SessionMethodsCore = class {
535
578
  lowerHandLocal();
536
579
  }
537
580
  /**
581
+ * Toggles the user's virtual hand state.
582
+ * If the hand is raised, it will be lowered, and vice versa.
583
+ */
584
+ static toggleHand() {
585
+ toggleRaiseHand();
586
+ }
587
+ /**
538
588
  * Switches between the front and rear camera.
539
589
  */
540
590
  static switchCamera() {
@@ -550,11 +600,22 @@ var SessionMethodsCore = class {
550
600
  /**
551
601
  * Starts recording the call.
552
602
  */
553
- static startRecording() {}
603
+ static startRecording() {
604
+ startRecording();
605
+ }
554
606
  /**
555
607
  * Stops the ongoing call recording.
556
608
  */
557
- static stopRecording() {}
609
+ static stopRecording() {
610
+ stopRecording();
611
+ }
612
+ /**
613
+ * Toggles the call recording state.
614
+ * If recording is active, it will be stopped, and vice versa.
615
+ */
616
+ static toggleRecording() {
617
+ toggleRecording();
618
+ }
558
619
  /**
559
620
  * Pins a participant's video to focus on them.
560
621
  * @param participantId - The ID of the participant to pin.
@@ -591,6 +652,24 @@ var SessionMethodsCore = class {
591
652
  setChatButtonUnreadCount(count);
592
653
  }
593
654
  /**
655
+ * Toggles the visibility of the participant list panel.
656
+ */
657
+ static toggleParticipantList() {
658
+ toggleParticipantList();
659
+ }
660
+ /**
661
+ * Shows the participant list panel.
662
+ */
663
+ static showParticipantList() {
664
+ showParticipantList();
665
+ }
666
+ /**
667
+ * Hides the participant list panel.
668
+ */
669
+ static hideParticipantList() {
670
+ hideParticipantList();
671
+ }
672
+ /**
594
673
  * @deprecated switchToVideoCall is deprecated and not supported.
595
674
  */
596
675
  static switchToVideoCall() {
@@ -947,10 +1026,16 @@ const initialState$6 = {
947
1026
  };
948
1027
  const useParticipantStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$6, (set, get$1) => ({
949
1028
  addParticipant: (participant) => {
950
- set((state) => ({ participants: [...state.participants, participant] }));
1029
+ set((state) => ({ participants: state.participants.some((p) => p.pid === participant.pid) ? state.participants.map((p) => p.pid === participant.pid ? {
1030
+ ...p,
1031
+ ...participant
1032
+ } : p) : [...state.participants, participant] }));
951
1033
  },
952
1034
  addVirtualParticipant: (participant) => {
953
- set((state) => ({ virtualParticipants: [...state.virtualParticipants, participant] }));
1035
+ set((state) => ({ virtualParticipants: state.virtualParticipants.some((p) => p.pid === participant.pid && p.type === participant.type) ? state.virtualParticipants.map((p) => p.pid === participant.pid && p.type === participant.type ? {
1036
+ ...p,
1037
+ ...participant
1038
+ } : p) : [...state.virtualParticipants, participant] }));
954
1039
  },
955
1040
  clearParticipants: () => set({
956
1041
  participants: [],
@@ -1187,6 +1272,8 @@ const useConferenceStore = (0, zustand.create)()((0, zustand_middleware.subscrib
1187
1272
  sendParticipantEvent(EVENT_LISTENER_METHODS.ParticipantEventsListner.onParticipantHandRaised, participantId);
1188
1273
  },
1189
1274
  lowerHand: (participantId) => {
1275
+ const hasRaisedHand = useConferenceStore.getState().raiseHandMap.has(participantId);
1276
+ if (!hasRaisedHand) return;
1190
1277
  set((state) => {
1191
1278
  const raiseHandMap = new Map(state.raiseHandMap);
1192
1279
  raiseHandMap.delete(participantId);
@@ -1384,6 +1471,12 @@ const useTracksStore = (0, zustand.create)()((0, zustand_middleware.subscribeWit
1384
1471
  muted: originalTrack.isMuted() ? 1 : 0,
1385
1472
  originalTrack
1386
1473
  };
1474
+ const existingIdx = state.tracks.findIndex((t) => t.pid === participantId && t.mediaType === track.mediaType && t.local === isLocal);
1475
+ if (existingIdx !== -1) {
1476
+ const tracks = [...state.tracks];
1477
+ tracks[existingIdx] = track;
1478
+ return { tracks };
1479
+ }
1387
1480
  return { tracks: [...state.tracks, track] };
1388
1481
  }),
1389
1482
  removeTrack: (originalTrack) => set((state) => ({ tracks: state.tracks.filter((track) => track.originalTrack !== originalTrack) })),
@@ -1585,8 +1678,13 @@ useTracksStore.subscribe((state) => state.tracks.find((t) => t.mediaType === MED
1585
1678
  }
1586
1679
  if (track) {
1587
1680
  const deviceId = track.getDeviceId();
1588
- const device = useBaseStore.getState().audioInputDevices.find((d) => d.deviceId === deviceId);
1589
- updateAudioInputDeviceState(device, true);
1681
+ waitForStoreState(useBaseStore, (state) => state.audioInputDevices.length > 0).then(() => {
1682
+ const audioInputDevices = useBaseStore.getState().audioInputDevices;
1683
+ const device = audioInputDevices.find((d) => d.deviceId === deviceId);
1684
+ updateAudioInputDeviceState(device, true);
1685
+ }).catch(() => {
1686
+ updateAudioInputDeviceState(undefined, true);
1687
+ });
1590
1688
  }
1591
1689
  });
1592
1690
  useTracksStore.subscribe((state) => state.tracks.find((t) => t.mediaType === MEDIA_TYPE.VIDEO && t.local)?.originalTrack, (track, prevTrack) => {
@@ -1768,7 +1866,7 @@ const initialState$3 = {
1768
1866
  desktopSharingFrameRate: 5,
1769
1867
  chatButtonUnreadCount: 0,
1770
1868
  enableNoiseReduction: true,
1771
- sdkPlatform: PLATFORM.WEB,
1869
+ sdkPlatform: SDK_PLATFORM.WEB,
1772
1870
  webOSName: "unknown",
1773
1871
  isMobileBrowser: false,
1774
1872
  visibleParticipants: {
@@ -1792,11 +1890,11 @@ const useBaseStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithS
1792
1890
  toggleParticipantListVisible: () => set((state) => ({ participantListVisible: !state.participantListVisible })),
1793
1891
  incrementConnectionRetryCount: () => set((state) => ({ connectionRetryCount: state.connectionRetryCount + 1 })),
1794
1892
  isMobileSDK: () => {
1795
- const isMobileSDK = get$1().sdkPlatform === "android" || get$1().sdkPlatform === "ios";
1893
+ const isMobileSDK = get$1().sdkPlatform !== "web";
1796
1894
  return isMobileSDK;
1797
1895
  },
1798
1896
  isMobile: () => {
1799
- const isMobileSDK = get$1().sdkPlatform === "android" || get$1().sdkPlatform === "ios";
1897
+ const isMobileSDK = get$1().sdkPlatform !== "web";
1800
1898
  const isMobileBrowser = get$1().isMobileBrowser;
1801
1899
  return isMobileSDK || isMobileBrowser;
1802
1900
  },
@@ -1842,6 +1940,7 @@ const useBaseStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithS
1842
1940
  const toggleParticipantListVisible = useBaseStore.getState().toggleParticipantListVisible;
1843
1941
  const hideParticipantList = () => useBaseStore.setState({ participantListVisible: false });
1844
1942
  const showParticipantList = () => useBaseStore.setState({ participantListVisible: true });
1943
+ const toggleParticipantList = () => useBaseStore.setState((state) => ({ participantListVisible: !state.participantListVisible }));
1845
1944
  const toggleMoreMenuVisible = useBaseStore.getState().toggleMoreMenuVisible;
1846
1945
  const toggleAudioModeMenuVisible = () => {
1847
1946
  useBaseStore.setState((state) => ({ audioModeMenuVisible: !state.audioModeMenuVisible }));
@@ -1890,6 +1989,9 @@ const toggleEnableNoiseReduction = () => {
1890
1989
  const setChatButtonUnreadCount = (count) => {
1891
1990
  useBaseStore.setState({ chatButtonUnreadCount: count });
1892
1991
  };
1992
+ const setAudioMode = (mode) => {
1993
+ useBaseStore.setState({ selectedAudioModeType: mode });
1994
+ };
1893
1995
  const getLayout = () => {
1894
1996
  return useBaseStore.getState().layout;
1895
1997
  };
@@ -2150,8 +2252,21 @@ const getMainParticipant = () => {
2150
2252
  const useIsReconnecting = () => {
2151
2253
  const connectionStatus = useConnectionStore((state) => state.connectionStatus);
2152
2254
  const conferenceStatus = useConferenceStore((state) => state.conferenceStatus);
2153
- const reconnecting = connectionStatus === "connected" && conferenceStatus === "interrupted";
2154
- return reconnecting;
2255
+ const isP2P = useConferenceStore((state) => state.p2p);
2256
+ const [isOnline, setIsOnline] = (0, react.useState)(true);
2257
+ (0, react.useEffect)(() => {
2258
+ if (typeof window === "undefined") return;
2259
+ const controller = new AbortController();
2260
+ const { signal } = controller;
2261
+ window.addEventListener("online", () => setIsOnline(true), { signal });
2262
+ window.addEventListener("offline", () => setIsOnline(false), { signal });
2263
+ return () => controller.abort();
2264
+ }, []);
2265
+ const interrupted = connectionStatus === "connected" && conferenceStatus === "interrupted";
2266
+ if (isP2P && interrupted && isOnline) {
2267
+ return false;
2268
+ }
2269
+ return interrupted;
2155
2270
  };
2156
2271
  const useHideRecordingButton = () => {
2157
2272
  const hideRecordingButton = useConfigStore((state) => state.hideRecordingButton);
@@ -2229,6 +2344,11 @@ const useIsVideoInputSelectionSupported = () => {
2229
2344
  const isVideoInputSelectionSupported = hasVideoPermission && videoInputDevices.length > 0;
2230
2345
  return isVideoInputSelectionSupported;
2231
2346
  };
2347
+ const useShouldMirrorLocalVideo = () => {
2348
+ const mirrorLocalVideo = useBaseStore((state) => state.mirrorLocalVideo);
2349
+ const cameraFacing = useBaseStore((state) => state.cameraFacing);
2350
+ return cameraFacing === "user" && mirrorLocalVideo;
2351
+ };
2232
2352
 
2233
2353
  //#endregion
2234
2354
  //#region calls-sdk-core/store/utils/switch-camera.ts
@@ -2453,17 +2573,19 @@ var ConferenceListener = class {
2453
2573
  useConferenceStore.setState({ p2p });
2454
2574
  }
2455
2575
  onTrackMuteChanged(track, participantThatMutedUs) {
2456
- if (participantThatMutedUs) {
2457
- useTracksStore.getState().updateTrack(track, { muted: track.isMuted() ? 1 : 0 });
2458
- const displayName = participantThatMutedUs.getDisplayName();
2459
- if (displayName) {
2460
- eventBus.publish({
2461
- type: INTERNAL_EVENTS.notification,
2462
- payload: {
2463
- type: "info",
2464
- message: `${displayName} has muted you.`
2465
- }
2466
- });
2576
+ if (track.isLocal()) {
2577
+ useTracksStore.getState().updateLocalTrack(track.getType(), { muted: track.isMuted() ? 1 : 0 });
2578
+ if (participantThatMutedUs) {
2579
+ const displayName = participantThatMutedUs.getDisplayName();
2580
+ if (displayName) {
2581
+ eventBus.publish({
2582
+ type: INTERNAL_EVENTS.notification,
2583
+ payload: {
2584
+ type: "info",
2585
+ message: `${displayName} has muted you.`
2586
+ }
2587
+ });
2588
+ }
2467
2589
  }
2468
2590
  }
2469
2591
  }
@@ -2518,6 +2640,24 @@ var ConferenceListener = class {
2518
2640
  useParticipantStore.getState().updateParticipant(participantId, { role: newRole });
2519
2641
  }
2520
2642
  }
2643
+ onTrackUnmuteRejected(track) {
2644
+ if (!track.isLocal()) {
2645
+ return;
2646
+ }
2647
+ const mediaType = track.getType();
2648
+ track.dispose().catch(() => {});
2649
+ useTracksStore.getState().updateLocalTrack(mediaType, {
2650
+ originalTrack: undefined,
2651
+ muted: 1
2652
+ });
2653
+ eventBus.publish({
2654
+ type: INTERNAL_EVENTS.notification,
2655
+ payload: {
2656
+ type: "info",
2657
+ message: `Your ${mediaType} unmute was rejected.`
2658
+ }
2659
+ });
2660
+ }
2521
2661
  onTalkWhileMuted() {}
2522
2662
  onConferenceError(error) {
2523
2663
  console.error("Conference error:", error);
@@ -2596,6 +2736,7 @@ function addConferenceListeners(conference) {
2596
2736
  conference.on(lib_jitsi_meet.default.events.conference.PARTICIPANT_PROPERTY_CHANGED, conferenceListener.onParticipantPropertyChanged);
2597
2737
  conference.on(lib_jitsi_meet.default.events.conference.USER_ROLE_CHANGED, conferenceListener.onUserRoleChanged);
2598
2738
  conference.on(lib_jitsi_meet.default.events.conference.TALK_WHILE_MUTED, conferenceListener.onTalkWhileMuted);
2739
+ conference.on(lib_jitsi_meet.default.events.conference.TRACK_UNMUTE_REJECTED, conferenceListener.onTrackUnmuteRejected);
2599
2740
  conference.on(lib_jitsi_meet.default.events.conference.TRACK_AUDIO_LEVEL_CHANGED, conferenceListener.onTrackAudioLevelChanged);
2600
2741
  conference.addCommandListener(CONFERENCE_COMMANDS.userInfo, (data, id) => {
2601
2742
  const vData = valibot.safeParse(UserInfoCommandSchema, safeParseJson(data.value));
@@ -2883,6 +3024,7 @@ var Mutex = class {
2883
3024
  //#region calls-sdk-core/handlers/init.ts
2884
3025
  function initializeLib() {
2885
3026
  lib_jitsi_meet.default.init();
3027
+ lib_jitsi_meet.default.setLogLevel(lib_jitsi_meet.default.logLevels.ERROR);
2886
3028
  console.log("JitsiMeetJS initialized successfully.");
2887
3029
  }
2888
3030
 
@@ -4040,6 +4182,7 @@ const PopupMenu = ({ visible, onClose, options, anchorLayout }) => {
4040
4182
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Pressable, {
4041
4183
  style: styles$27.backdrop,
4042
4184
  onPress: onClose,
4185
+ testID: "cometchat-popup-menu-backdrop",
4043
4186
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
4044
4187
  style: [styles$27.menu, {
4045
4188
  [isBelowMiddle ? "bottom" : "top"]: isBelowMiddle ? callContainerDimension.height - (y - 4) : y + height + 4,
@@ -4060,6 +4203,7 @@ const PopupMenu = ({ visible, onClose, options, anchorLayout }) => {
4060
4203
  },
4061
4204
  activeOpacity: option.selected ? DISABLED_OPTION_OPACITY : .2,
4062
4205
  style: [styles$27.menuItem, option.selected ? styles$27.menuItemSelected : {}],
4206
+ testID: `cometchat-popup-menu-option-${index}`,
4063
4207
  children: [option.iconName && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
4064
4208
  name: option.iconName,
4065
4209
  size: 24,
@@ -4221,6 +4365,7 @@ const MoreOptionButton = ({ ruid }) => {
4221
4365
  ref: buttonRef,
4222
4366
  style: styles$4.moreButton,
4223
4367
  onPress: showMenu,
4368
+ testID: "cometchat-participant-more-options-button",
4224
4369
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
4225
4370
  name: "more",
4226
4371
  size: 20,
@@ -4390,6 +4535,7 @@ const Tile = ({ participant, style, zOrder, showLabel = true, disablePress = fal
4390
4535
  const videoTrack = useTrackByParticipantId(pid, type === "screen-share" ? MEDIA_TYPE.SCREENSHARE : MEDIA_TYPE.VIDEO)?.originalTrack;
4391
4536
  const videoMuted = useTrackMuted(type === "screen-share" ? MEDIA_TYPE.SCREENSHARE : MEDIA_TYPE.VIDEO, pid);
4392
4537
  const enableParticipantContextMenu = useEnableParticipantContextMenu();
4538
+ const shouldMirror = useShouldMirrorLocalVideo();
4393
4539
  const [size, fontSize] = react.default.useMemo(() => {
4394
4540
  const flatStyle = react_native.StyleSheet.flatten(style);
4395
4541
  const width$1 = flatStyle?.width;
@@ -4407,6 +4553,7 @@ const Tile = ({ participant, style, zOrder, showLabel = true, disablePress = fal
4407
4553
  activeOpacity: 1,
4408
4554
  disabled: disablePress,
4409
4555
  style: [styles$24.callScreen, style],
4556
+ testID: `cometchat-tile-${pid}`,
4410
4557
  children: [
4411
4558
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
4412
4559
  style: styles$24.tileAvatar,
@@ -4422,7 +4569,7 @@ const Tile = ({ participant, style, zOrder, showLabel = true, disablePress = fal
4422
4569
  objectFit: type === "screen-share" ? "contain" : "cover",
4423
4570
  muted: videoMuted,
4424
4571
  zOrder,
4425
- mirror: isLocal
4572
+ mirror: isLocal && type !== "screen-share" && shouldMirror
4426
4573
  }),
4427
4574
  showLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label_native_default, { participant }),
4428
4575
  enableParticipantContextMenu && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
@@ -4481,6 +4628,7 @@ const GroupAvatarTile = ({ startIndex = 4, style }) => {
4481
4628
  const overflowCount = Math.max(0, participantCount - startIndex - 3);
4482
4629
  const visible = participants.slice(startIndex, startIndex + (overflowCount === 1 ? 4 : 3));
4483
4630
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
4631
+ testID: "cometchat-group-avatar-tile",
4484
4632
  style: [styles$23.container, style],
4485
4633
  onPress: toggleParticipantListVisible,
4486
4634
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
@@ -4588,6 +4736,7 @@ function SidebarLayout() {
4588
4736
  const mainParticipant = useMainParticipant();
4589
4737
  const participants = allParticipants.length > 1 ? [mainParticipant].concat(allParticipants) : [mainParticipant];
4590
4738
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
4739
+ testID: "cometchat-sidebar-layout",
4591
4740
  style: styles$22.container,
4592
4741
  children: [
4593
4742
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
@@ -4724,23 +4873,26 @@ const Spotlight = () => {
4724
4873
  if (otherParticipant) {
4725
4874
  spotlightParticipants.push(otherParticipant);
4726
4875
  }
4727
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4728
- participant: spotlightParticipants[0],
4729
- disablePress: true
4730
- }, spotlightParticipants[0].ruid), spotlightParticipants[1] && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pan, {
4731
- disableDrag: !enableSpotlightDrag,
4732
- layout: {
4733
- width: mainAreaDimension.width,
4734
- height: mainAreaDimension.height
4735
- },
4736
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4737
- showLabel: false,
4738
- disablePress: !enableSpotlightSwap,
4739
- participant: spotlightParticipants[1],
4740
- style: styles$20.panTile,
4741
- zOrder: 1
4742
- }, spotlightParticipants[1].ruid)
4743
- })] });
4876
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
4877
+ testID: "cometchat-spotlight-layout",
4878
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4879
+ participant: spotlightParticipants[0],
4880
+ disablePress: true
4881
+ }, spotlightParticipants[0].ruid), spotlightParticipants[1] && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pan, {
4882
+ disableDrag: !enableSpotlightDrag,
4883
+ layout: {
4884
+ width: mainAreaDimension.width,
4885
+ height: mainAreaDimension.height
4886
+ },
4887
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4888
+ showLabel: false,
4889
+ disablePress: !enableSpotlightSwap,
4890
+ participant: spotlightParticipants[1],
4891
+ style: styles$20.panTile,
4892
+ zOrder: 1
4893
+ }, spotlightParticipants[1].ruid)
4894
+ })]
4895
+ });
4744
4896
  };
4745
4897
  const styles$20 = react_native.StyleSheet.create({ panTile: {
4746
4898
  borderColor: "#1A1A1A",
@@ -4773,6 +4925,7 @@ function TileLayout() {
4773
4925
  participantCount: isPIPLayoutEnabled ? 1 : participants.length
4774
4926
  });
4775
4927
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.FlatList, {
4928
+ testID: "cometchat-tile-layout",
4776
4929
  data: isPIPLayoutEnabled ? [mainParticipant] : participants,
4777
4930
  renderItem: ({ item }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4778
4931
  participant: item,
@@ -5131,6 +5284,7 @@ function ConfirmationDialog() {
5131
5284
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Pressable, {
5132
5285
  style: styles$15.backdrop,
5133
5286
  onPress: handleBackdropPress,
5287
+ testID: "cometchat-confirmation-dialog-backdrop",
5134
5288
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
5135
5289
  style: styles$15.dialog,
5136
5290
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
@@ -5173,7 +5327,7 @@ function ConfirmationDialog() {
5173
5327
  //#endregion
5174
5328
  //#region src/ui/bottom-sheet/BottomSheet.native.tsx
5175
5329
  const SCREEN_HEIGHT = react_native.Dimensions.get("window").height;
5176
- const BottomSheet = ({ children, isVisible, onClose, maxHeight = SCREEN_HEIGHT * .4 }) => {
5330
+ const BottomSheet = ({ children, isVisible, onClose, maxHeight = SCREEN_HEIGHT * .4, testID }) => {
5177
5331
  const visibleTranslateY = SCREEN_HEIGHT - maxHeight;
5178
5332
  const hiddenTranslateY = (0, react.useRef)(SCREEN_HEIGHT).current;
5179
5333
  const animatedValue = (0, react.useRef)(new react_native.Animated.Value(hiddenTranslateY)).current;
@@ -5199,8 +5353,10 @@ const BottomSheet = ({ children, isVisible, onClose, maxHeight = SCREEN_HEIGHT *
5199
5353
  const bottomSheetAnimation = { transform: [{ translateY: animatedValue }] };
5200
5354
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [isVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableWithoutFeedback, {
5201
5355
  onPress: onClose,
5356
+ testID: "cometchat-bottom-sheet-backdrop",
5202
5357
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: styles$14.backdrop })
5203
5358
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.Animated.View, {
5359
+ testID,
5204
5360
  style: [
5205
5361
  styles$14.bottomSheet,
5206
5362
  bottomSheetAnimation,
@@ -5258,8 +5414,9 @@ var BottomSheet_native_default = BottomSheet;
5258
5414
 
5259
5415
  //#endregion
5260
5416
  //#region src/ui/control-pane/MenuItem.native.tsx
5261
- const MenuItem = ({ iconName, label, onPress, selected = false }) => {
5417
+ const MenuItem = ({ iconName, label, onPress, selected = false, testID }) => {
5262
5418
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
5419
+ testID,
5263
5420
  onPress: () => {
5264
5421
  hideAllBottomSheets();
5265
5422
  onPress();
@@ -5312,6 +5469,7 @@ const AudioModesMenu = ({ isVisible, onClose }) => {
5312
5469
  style: [commonStyles.bodyRegular, styles$12.noItemsText],
5313
5470
  children: "No audio modes available"
5314
5471
  }), audioModes.map((mode, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItem_native_default, {
5472
+ testID: `cometchat-menu-item-audio-${mode.type.toLowerCase()}`,
5315
5473
  iconName: AUDIO_MODE_TYPE_ICON_MAP[mode.type],
5316
5474
  label: mode.type,
5317
5475
  selected: mode.selected,
@@ -5363,6 +5521,7 @@ const AudioModeButton = () => {
5363
5521
  style: controlPaneStyles.controlButton,
5364
5522
  onPress: toggleAudioModeMenuVisible,
5365
5523
  activeOpacity: .7,
5524
+ testID: "cometchat-audio-mode-button",
5366
5525
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5367
5526
  name: "speaker-fill",
5368
5527
  fill: "#FFF",
@@ -5388,6 +5547,7 @@ const AudioControl = () => {
5388
5547
  style: [controlPaneStyles.controlButton, muted && controlPaneStyles.toggledButton],
5389
5548
  onPress,
5390
5549
  activeOpacity: .7,
5550
+ testID: "cometchat-audio-toggle-button",
5391
5551
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5392
5552
  name: muted ? "mic-off-fill" : "mic-fill",
5393
5553
  fill: muted ? "#9F3032" : "#FFF",
@@ -5413,6 +5573,7 @@ const VideoControl = () => {
5413
5573
  style: [controlPaneStyles.controlButton, videoMuted && controlPaneStyles.toggledButton],
5414
5574
  onPress,
5415
5575
  activeOpacity: .7,
5576
+ testID: "cometchat-video-toggle-button",
5416
5577
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5417
5578
  name: videoMuted ? "video-off-fill" : "video-fill",
5418
5579
  fill: videoMuted ? "#9F3032" : "#FFF",
@@ -5437,6 +5598,7 @@ const LeaveSessionButton = () => {
5437
5598
  style: [controlPaneStyles.controlButton, controlPaneStyles.leaveSessionButton],
5438
5599
  onPress,
5439
5600
  activeOpacity: .7,
5601
+ testID: "cometchat-leave-session-button",
5440
5602
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5441
5603
  name: "call-end",
5442
5604
  fill: "#FFF",
@@ -5453,6 +5615,7 @@ const MoreMenuButton = () => {
5453
5615
  style: controlPaneStyles.controlButton,
5454
5616
  onPress: toggleMoreMenuVisible,
5455
5617
  activeOpacity: .7,
5618
+ testID: "cometchat-more-menu-button",
5456
5619
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5457
5620
  name: "more",
5458
5621
  fill: "#FFF",
@@ -5528,22 +5691,26 @@ const MoreMenu = ({ isVisible, onClose }) => {
5528
5691
  toggleParticipantListVisible();
5529
5692
  }, []);
5530
5693
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BottomSheet_native_default, {
5694
+ testID: "cometchat-more-menu-bottom-sheet",
5531
5695
  maxHeight: bottomSheetMaxHeight,
5532
5696
  isVisible,
5533
5697
  onClose,
5534
5698
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.ScrollView, { children: [
5535
5699
  numberOfVisibleItems === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5700
+ testID: "cometchat-more-menu-empty-state",
5536
5701
  style: [commonStyles.bodyRegular, styles$11.noItemsText],
5537
5702
  children: "No options available"
5538
5703
  }),
5539
5704
  !hideScreenSharingButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScreenShareButton_default, {}),
5540
5705
  !hideRaiseHandButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItem_native_default, {
5706
+ testID: "cometchat-menu-item-raise-hand",
5541
5707
  iconName: "raise-hand-fill",
5542
5708
  label: raiseHandTimestamp ? "Lower Hand" : "Raise Hand",
5543
5709
  onPress: onRaiseHandPress,
5544
5710
  selected: Boolean(raiseHandTimestamp)
5545
5711
  }),
5546
5712
  !hideRecordingButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItem_native_default, {
5713
+ testID: isRecording ? "cometchat-menu-item-stop-recording" : "cometchat-menu-item-start-recording",
5547
5714
  iconName: isRecording ? "record-stop-fill" : "record-fill",
5548
5715
  label: isRecording ? "Stop Recording" : "Start Recording",
5549
5716
  onPress: () => {
@@ -5554,6 +5721,7 @@ const MoreMenu = ({ isVisible, onClose }) => {
5554
5721
  }
5555
5722
  }),
5556
5723
  !hideParticipantListButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItem_native_default, {
5724
+ testID: "cometchat-menu-item-participants",
5557
5725
  iconName: "participants",
5558
5726
  label: "Participants",
5559
5727
  onPress: onParticipantListPress
@@ -5680,6 +5848,7 @@ const ChangeLayout = () => {
5680
5848
  eventBus.publish({ type: EVENT_LISTENER_METHODS.ButtonClickListener.onChangeLayoutButtonClicked });
5681
5849
  showMenu();
5682
5850
  },
5851
+ testID: "cometchat-change-layout-button",
5683
5852
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5684
5853
  name: "tile-fill",
5685
5854
  fill: "#FFFFFF"
@@ -5732,6 +5901,7 @@ const ChatButton = () => {
5732
5901
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
5733
5902
  style: [styles$9.iconButton],
5734
5903
  onPress,
5904
+ testID: "cometchat-chat-button",
5735
5905
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5736
5906
  name: "chat",
5737
5907
  fill: "#FFFFFF"
@@ -5788,6 +5958,7 @@ const SwitchCamera = () => {
5788
5958
  return null;
5789
5959
  }
5790
5960
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
5961
+ testID: "cometchat-switch-camera-button",
5791
5962
  disabled,
5792
5963
  style: [styles$8.iconButton, disabled && styles$8.iconButtonDisabled],
5793
5964
  onPress,
@@ -5820,6 +5991,7 @@ const SessionTimer = () => {
5820
5991
  return null;
5821
5992
  }
5822
5993
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5994
+ testID: "cometchat-session-timer",
5823
5995
  style: [commonStyles.caption1Regular, styles$7.meetingTime],
5824
5996
  children: miliSecondsToMMSS(conferenceElapsedTime)
5825
5997
  });
@@ -5939,66 +6111,72 @@ const IdealTimeoutModal = ({ style = {} }) => {
5939
6111
  statusBarTranslucent: true,
5940
6112
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableWithoutFeedback, {
5941
6113
  onPress: handleOverlayPress,
6114
+ testID: "cometchat-idle-timeout-overlay",
5942
6115
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
5943
6116
  style: [styles$6.overlay, { opacity: fadeAnim }],
5944
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableWithoutFeedback, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
5945
- style: [
5946
- styles$6.modal,
5947
- style,
5948
- {
5949
- opacity: fadeAnim,
5950
- transform: [{ scale: scaleAnim }]
5951
- }
5952
- ],
5953
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
5954
- style: styles$6.content,
5955
- children: [
5956
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
5957
- style: styles$6.timerIcon,
5958
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5959
- style: [commonStyles.heading3Bold, styles$6.timerText],
5960
- children: formattedTime
5961
- })
5962
- }),
5963
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
5964
- style: styles$6.textContent,
5965
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5966
- style: [commonStyles.heading2Medium, styles$6.title],
5967
- children: "Are you still there?"
5968
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.Text, {
5969
- style: [commonStyles.bodyRegular, styles$6.subtitle],
5970
- children: [
5971
- "You are the only one here, so this call will end in less than ",
5972
- ceilMinutes,
5973
- " minute",
5974
- ceilMinutes > 1 ? "s" : "",
5975
- ". Do you want to stay in this call?"
5976
- ]
5977
- })]
5978
- }),
5979
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
5980
- style: styles$6.actions,
5981
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
5982
- style: [styles$6.button, styles$6.buttonSecondary],
5983
- onPress: onStayInCall,
5984
- activeOpacity: .8,
5985
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5986
- style: [commonStyles.bodyMedium, styles$6.buttonSecondaryText],
5987
- children: "Stay on the call"
5988
- })
5989
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
5990
- style: [styles$6.button, styles$6.buttonPrimary],
5991
- onPress: () => leaveSession(),
5992
- activeOpacity: .8,
6117
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableWithoutFeedback, {
6118
+ testID: "cometchat-idle-timeout-modal",
6119
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
6120
+ style: [
6121
+ styles$6.modal,
6122
+ style,
6123
+ {
6124
+ opacity: fadeAnim,
6125
+ transform: [{ scale: scaleAnim }]
6126
+ }
6127
+ ],
6128
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
6129
+ style: styles$6.content,
6130
+ children: [
6131
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
6132
+ style: styles$6.timerIcon,
5993
6133
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5994
- style: [commonStyles.bodyMedium, styles$6.buttonPrimaryText],
5995
- children: "Leave now"
6134
+ style: [commonStyles.heading3Bold, styles$6.timerText],
6135
+ children: formattedTime
5996
6136
  })
5997
- })]
5998
- })
5999
- ]
6137
+ }),
6138
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
6139
+ style: styles$6.textContent,
6140
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6141
+ style: [commonStyles.heading2Medium, styles$6.title],
6142
+ children: "Are you still there?"
6143
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.Text, {
6144
+ style: [commonStyles.bodyRegular, styles$6.subtitle],
6145
+ children: [
6146
+ "You are the only one here, so this call will end in less than ",
6147
+ ceilMinutes,
6148
+ " minute",
6149
+ ceilMinutes > 1 ? "s" : "",
6150
+ ". Do you want to stay in this call?"
6151
+ ]
6152
+ })]
6153
+ }),
6154
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
6155
+ style: styles$6.actions,
6156
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
6157
+ style: [styles$6.button, styles$6.buttonSecondary],
6158
+ onPress: onStayInCall,
6159
+ activeOpacity: .8,
6160
+ testID: "cometchat-idle-timeout-stay-button",
6161
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6162
+ style: [commonStyles.bodyMedium, styles$6.buttonSecondaryText],
6163
+ children: "Stay on the call"
6164
+ })
6165
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
6166
+ style: [styles$6.button, styles$6.buttonPrimary],
6167
+ onPress: () => leaveSession(),
6168
+ activeOpacity: .8,
6169
+ testID: "cometchat-idle-timeout-leave-button",
6170
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6171
+ style: [commonStyles.bodyMedium, styles$6.buttonPrimaryText],
6172
+ children: "Leave now"
6173
+ })
6174
+ })]
6175
+ })
6176
+ ]
6177
+ })
6000
6178
  })
6001
- }) })
6179
+ })
6002
6180
  })
6003
6181
  })
6004
6182
  });
@@ -6096,6 +6274,7 @@ const ShareInviteButton = () => {
6096
6274
  style: styles$5.shareButtonContainer,
6097
6275
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
6098
6276
  style: styles$5.shareButton,
6277
+ testID: "cometchat-share-invite-button",
6099
6278
  onPress: () => {
6100
6279
  eventBus.publish({ type: "onShareInviteButtonClicked" });
6101
6280
  },
@@ -6232,6 +6411,7 @@ const ParticipantList = () => {
6232
6411
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
6233
6412
  onPress: toggleParticipantListVisible,
6234
6413
  accessibilityLabel: "Close participants list",
6414
+ testID: "cometchat-participant-list-close-button",
6235
6415
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
6236
6416
  name: "close",
6237
6417
  size: 24,
@@ -6253,7 +6433,8 @@ const ParticipantList = () => {
6253
6433
  style: styles$3.searchInput,
6254
6434
  value: searchTerm,
6255
6435
  onChangeText: setSearchTerm,
6256
- placeholderTextColor: "#858585"
6436
+ placeholderTextColor: "#858585",
6437
+ testID: "cometchat-participant-search-input"
6257
6438
  })]
6258
6439
  })
6259
6440
  }),
@@ -6507,6 +6688,7 @@ function ToastItemView({ toast, onDismiss }) {
6507
6688
  }), toast.action && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Pressable, {
6508
6689
  style: styles$2.actionButton,
6509
6690
  onPress: handleActionPress,
6691
+ testID: "cometchat-toast-action-button",
6510
6692
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6511
6693
  style: styles$2.actionText,
6512
6694
  children: toast.action.label
@@ -6565,7 +6747,11 @@ function CallUI(props) {
6565
6747
  };
6566
6748
  }, [props.sessionSettings]);
6567
6749
  (0, react.useEffect)(() => {
6568
- useBaseStore.setState({ sdkPlatform: react_native.Platform.OS });
6750
+ if (props.sessionSettings.sdkPlatform) {
6751
+ useBaseStore.setState({ sdkPlatform: props.sessionSettings.sdkPlatform });
6752
+ } else {
6753
+ useBaseStore.setState({ sdkPlatform: react_native.Platform.OS === "ios" ? "react-native-ios" : "react-native-android" });
6754
+ }
6569
6755
  startSession();
6570
6756
  }, []);
6571
6757
  (0, react.useEffect)(() => {
@@ -6715,10 +6901,10 @@ const convertLegacyCallSettingsToV5Props = (callSettings) => {
6715
6901
  if (cs.defaultAudioMode === "BLUETOOTH" || cs.defaultAudioMode === "EARPIECE" || cs.defaultAudioMode === "HEADPHONES" || cs.defaultAudioMode === "SPEAKER") {
6716
6902
  v5Props.audioMode = cs.defaultAudioMode;
6717
6903
  }
6718
- if (cs.mode === "SPOTLIGHT") {
6719
- v5Props.layout = "SPOTLIGHT";
6720
- } else {
6721
- v5Props.layout = "SIDEBAR";
6904
+ if (typeof cs.layout === "string") {
6905
+ v5Props.layout = cs.layout;
6906
+ } else if (cs.mode === "SPOTLIGHT" || cs.mode === "SIDEBAR") {
6907
+ v5Props.layout = cs.mode;
6722
6908
  }
6723
6909
  if (cs.idleTimeoutPeriod) {
6724
6910
  v5Props.idleTimeoutPeriodAfterPrompt = 6e4;
@@ -10718,7 +10904,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10718
10904
  }
10719
10905
  this.appSettings = parsedAppSettings.output;
10720
10906
  this.isInitialized = true;
10721
- const savedUser = this.getSavedUser();
10907
+ const savedUser = await this.getSavedUser();
10722
10908
  if (savedUser) {
10723
10909
  let parsedUser;
10724
10910
  if (typeof savedUser === "string") {
@@ -10791,7 +10977,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10791
10977
  const user = await this.authenticateWithToken(authToken);
10792
10978
  this.loginInProgress = false;
10793
10979
  this.loggedInUser = user;
10794
- this.saveUser(user);
10980
+ await this.saveUser(user);
10795
10981
  this.notifyLoginSuccess(user);
10796
10982
  return user;
10797
10983
  } catch (error) {
@@ -10839,7 +11025,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10839
11025
  const user = await this.authenticateWithToken(authToken);
10840
11026
  this.loginInProgress = false;
10841
11027
  this.loggedInUser = user;
10842
- this.saveUser(user);
11028
+ await this.saveUser(user);
10843
11029
  this.notifyLoginSuccess(user);
10844
11030
  return user;
10845
11031
  } catch (error) {
@@ -10972,7 +11158,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10972
11158
  appId
10973
11159
  },
10974
11160
  body: {
10975
- platform: "web",
11161
+ platform: "react-native",
10976
11162
  deviceId: this.generateDeviceId()
10977
11163
  }
10978
11164
  });
@@ -10993,7 +11179,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10993
11179
  appId
10994
11180
  },
10995
11181
  body: {
10996
- platform: "web",
11182
+ platform: "react-native",
10997
11183
  deviceId: this.generateDeviceId()
10998
11184
  }
10999
11185
  });
@@ -11033,7 +11219,7 @@ var CometChatCalls = class extends SessionMethodsCore {
11033
11219
  }
11034
11220
  }
11035
11221
  this.loggedInUser = null;
11036
- this.clearSavedUser();
11222
+ await this.clearSavedUser();
11037
11223
  }
11038
11224
  static async callGenerateTokenAPI(sessionId, authToken) {
11039
11225
  const appId = this.appSettings?.appId || "";
@@ -11061,9 +11247,11 @@ var CometChatCalls = class extends SessionMethodsCore {
11061
11247
  baseURL: this.getBaseURL()
11062
11248
  });
11063
11249
  }
11064
- static saveUser(user) {
11250
+ static getStorageKey() {
11251
+ return `${this.appSettings?.appId}:common_store/user`;
11252
+ }
11253
+ static async saveUser(user) {
11065
11254
  try {
11066
- const key = `${this.appSettings?.appId}:common_store/user`;
11067
11255
  const userWithDefaults = {
11068
11256
  hasBlockedMe: false,
11069
11257
  blockedByMe: false,
@@ -11072,31 +11260,28 @@ var CometChatCalls = class extends SessionMethodsCore {
11072
11260
  role: user.role || "default",
11073
11261
  wsChannel: user.wsChannel || { identity: `[${this.appSettings?.appId}]${user.uid}` }
11074
11262
  };
11075
- localStorage.setItem(key, JSON.stringify(userWithDefaults));
11263
+ await __react_native_async_storage_async_storage.default.setItem(this.getStorageKey(), JSON.stringify(userWithDefaults));
11076
11264
  } catch (error) {
11077
- console.warn("Failed to save user to localStorage:", error);
11265
+ console.warn("Failed to save user to AsyncStorage:", error);
11078
11266
  }
11079
11267
  }
11080
- static getSavedUser() {
11268
+ static async getSavedUser() {
11081
11269
  try {
11082
- const key = `${this.appSettings?.appId}:common_store/user`;
11083
- const savedUser = localStorage.getItem(key);
11084
- return savedUser ? savedUser : null;
11270
+ return await __react_native_async_storage_async_storage.default.getItem(this.getStorageKey());
11085
11271
  } catch (error) {
11086
- console.warn("Failed to get saved user from localStorage:", error);
11272
+ console.warn("Failed to get saved user from AsyncStorage:", error);
11087
11273
  return null;
11088
11274
  }
11089
11275
  }
11090
- static clearSavedUser() {
11276
+ static async clearSavedUser() {
11091
11277
  try {
11092
- const key = `${this.appSettings?.appId}:common_store/user`;
11093
- localStorage.removeItem(key);
11278
+ await __react_native_async_storage_async_storage.default.removeItem(this.getStorageKey());
11094
11279
  } catch (error) {
11095
- console.warn("Failed to clear saved user from localStorage:", error);
11280
+ console.warn("Failed to clear saved user from AsyncStorage:", error);
11096
11281
  }
11097
11282
  }
11098
11283
  static generateDeviceId() {
11099
- return "web_" + Math.random().toString(36).substr(2, 9);
11284
+ return "rn_" + Math.random().toString(36).substring(2, 11);
11100
11285
  }
11101
11286
  static createError(error) {
11102
11287
  if (error.errorCode && error.errorDescription) {
@@ -11162,6 +11347,13 @@ var CometChatCalls = class extends SessionMethodsCore {
11162
11347
  return eventBus.subscribe(eventType, listener, options);
11163
11348
  }
11164
11349
  /**
11350
+ * Sets the audio output mode (mobile only).
11351
+ * @param mode - The audio mode to set (e.g., 'SPEAKER', 'EARPIECE', 'BLUETOOTH', 'HEADPHONES').
11352
+ */
11353
+ static setAudioMode(mode) {
11354
+ setAudioMode(mode);
11355
+ }
11356
+ /**
11165
11357
  * Enables Picture-in-Picture (PIP) layout during the call.
11166
11358
  */
11167
11359
  static enablePictureInPictureLayout() {
@@ -11176,5 +11368,4 @@ var CometChatCalls = class extends SessionMethodsCore {
11176
11368
  };
11177
11369
 
11178
11370
  //#endregion
11179
- exports.CometChatCalls = CometChatCalls;
11180
- //# sourceMappingURL=index.js.map
11371
+ exports.CometChatCalls = CometChatCalls;