@100mslive/react-native-room-kit 1.2.0 → 1.2.2

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.
Files changed (120) hide show
  1. package/README.md +5 -4
  2. package/lib/commonjs/HMSInstanceSetup.js +2 -1
  3. package/lib/commonjs/HMSInstanceSetup.js.map +1 -1
  4. package/lib/commonjs/HMSRoomSetup.js +31 -1
  5. package/lib/commonjs/HMSRoomSetup.js.map +1 -1
  6. package/lib/commonjs/components/Chat/ChatBanner.js +8 -7
  7. package/lib/commonjs/components/Chat/ChatBanner.js.map +1 -1
  8. package/lib/commonjs/components/CustomButton.js +2 -0
  9. package/lib/commonjs/components/CustomButton.js.map +1 -1
  10. package/lib/commonjs/components/DisplayView.js +1 -1
  11. package/lib/commonjs/components/DisplayView.js.map +1 -1
  12. package/lib/commonjs/components/HMSManageNoiseCancellation.js +11 -0
  13. package/lib/commonjs/components/HMSManageNoiseCancellation.js.map +1 -1
  14. package/lib/commonjs/components/HMSPreviewHLSLiveIndicator.js +2 -0
  15. package/lib/commonjs/components/HMSPreviewHLSLiveIndicator.js.map +1 -1
  16. package/lib/commonjs/components/MeetingScreenContent.js +13 -2
  17. package/lib/commonjs/components/MeetingScreenContent.js.map +1 -1
  18. package/lib/commonjs/components/MenuModal/MenuDivider.js +2 -0
  19. package/lib/commonjs/components/MenuModal/MenuDivider.js.map +1 -1
  20. package/lib/commonjs/components/Modals.js +45 -24
  21. package/lib/commonjs/components/Modals.js.map +1 -1
  22. package/lib/commonjs/components/Participants/ParticipantsItemOptions.js +26 -0
  23. package/lib/commonjs/components/Participants/ParticipantsItemOptions.js.map +1 -1
  24. package/lib/commonjs/components/PeerSettingsModalContent.js +13 -1
  25. package/lib/commonjs/components/PeerSettingsModalContent.js.map +1 -1
  26. package/lib/commonjs/components/RoomSettingsModalContent.js +1 -1
  27. package/lib/commonjs/components/VirtualBackgroundModalContent.js +1 -1
  28. package/lib/commonjs/components/VirtualBackgroundModalContent.js.map +1 -1
  29. package/lib/commonjs/components/WebrtcView.js +1 -1
  30. package/lib/commonjs/components/WebrtcView.js.map +1 -1
  31. package/lib/commonjs/components/styles.js +1 -0
  32. package/lib/commonjs/components/styles.js.map +1 -1
  33. package/lib/commonjs/hooks-util.js +48 -21
  34. package/lib/commonjs/hooks-util.js.map +1 -1
  35. package/lib/commonjs/utils.js +2 -2
  36. package/lib/module/HMSInstanceSetup.js +2 -1
  37. package/lib/module/HMSInstanceSetup.js.map +1 -1
  38. package/lib/module/HMSRoomSetup.js +32 -2
  39. package/lib/module/HMSRoomSetup.js.map +1 -1
  40. package/lib/module/components/Chat/ChatBanner.js +2 -1
  41. package/lib/module/components/Chat/ChatBanner.js.map +1 -1
  42. package/lib/module/components/CustomButton.js +1 -0
  43. package/lib/module/components/CustomButton.js.map +1 -1
  44. package/lib/module/components/DisplayView.js +2 -2
  45. package/lib/module/components/DisplayView.js.map +1 -1
  46. package/lib/module/components/HMSManageNoiseCancellation.js +11 -0
  47. package/lib/module/components/HMSManageNoiseCancellation.js.map +1 -1
  48. package/lib/module/components/HMSPreviewHLSLiveIndicator.js +1 -0
  49. package/lib/module/components/HMSPreviewHLSLiveIndicator.js.map +1 -1
  50. package/lib/module/components/MeetingScreenContent.js +14 -3
  51. package/lib/module/components/MeetingScreenContent.js.map +1 -1
  52. package/lib/module/components/MenuModal/MenuDivider.js +1 -0
  53. package/lib/module/components/MenuModal/MenuDivider.js.map +1 -1
  54. package/lib/module/components/Modals.js +47 -25
  55. package/lib/module/components/Modals.js.map +1 -1
  56. package/lib/module/components/Participants/ParticipantsItemOptions.js +28 -2
  57. package/lib/module/components/Participants/ParticipantsItemOptions.js.map +1 -1
  58. package/lib/module/components/PeerSettingsModalContent.js +14 -2
  59. package/lib/module/components/PeerSettingsModalContent.js.map +1 -1
  60. package/lib/module/components/RoomSettingsModalContent.js +1 -1
  61. package/lib/module/components/VirtualBackgroundModalContent.js +1 -1
  62. package/lib/module/components/VirtualBackgroundModalContent.js.map +1 -1
  63. package/lib/module/components/WebrtcView.js +2 -2
  64. package/lib/module/components/WebrtcView.js.map +1 -1
  65. package/lib/module/components/styles.js +1 -0
  66. package/lib/module/components/styles.js.map +1 -1
  67. package/lib/module/hooks-util.js +53 -29
  68. package/lib/module/hooks-util.js.map +1 -1
  69. package/lib/module/utils.js +2 -2
  70. package/lib/typescript/HMSInstanceSetup.d.ts.map +1 -1
  71. package/lib/typescript/HMSRoomSetup.d.ts.map +1 -1
  72. package/lib/typescript/components/Chat/ChatBanner.d.ts +1 -1
  73. package/lib/typescript/components/Chat/ChatBanner.d.ts.map +1 -1
  74. package/lib/typescript/components/CustomButton.d.ts.map +1 -1
  75. package/lib/typescript/components/HMSManageNoiseCancellation.d.ts.map +1 -1
  76. package/lib/typescript/components/HMSPreviewHLSLiveIndicator.d.ts.map +1 -1
  77. package/lib/typescript/components/MeetingScreenContent.d.ts.map +1 -1
  78. package/lib/typescript/components/MenuModal/MenuDivider.d.ts.map +1 -1
  79. package/lib/typescript/components/Modals.d.ts +1 -1
  80. package/lib/typescript/components/Modals.d.ts.map +1 -1
  81. package/lib/typescript/components/Participants/ParticipantsItemOptions.d.ts.map +1 -1
  82. package/lib/typescript/components/PeerSettingsModalContent.d.ts.map +1 -1
  83. package/lib/typescript/components/styles.d.ts +1 -0
  84. package/lib/typescript/components/styles.d.ts.map +1 -1
  85. package/lib/typescript/hooks-sdk-selectors.d.ts +2 -2
  86. package/lib/typescript/hooks-sdk.d.ts.map +1 -1
  87. package/lib/typescript/hooks-util.d.ts +8 -9
  88. package/lib/typescript/hooks-util.d.ts.map +1 -1
  89. package/lib/typescript/redux/actions/index.d.ts +39 -39
  90. package/lib/typescript/redux/actions/index.d.ts.map +1 -1
  91. package/lib/typescript/redux/index.d.ts +13 -15
  92. package/lib/typescript/redux/index.d.ts.map +1 -1
  93. package/lib/typescript/redux/reducers/index.d.ts +13 -15
  94. package/lib/typescript/redux/reducers/index.d.ts.map +1 -1
  95. package/lib/typescript/types.d.ts +0 -1
  96. package/lib/typescript/types.d.ts.map +1 -1
  97. package/lib/typescript/utils/dimension.d.ts.map +1 -1
  98. package/lib/typescript/utils/functions.d.ts +1 -1
  99. package/lib/typescript/utils/functions.d.ts.map +1 -1
  100. package/lib/typescript/utils/hooks.d.ts +2 -2
  101. package/lib/typescript/utils.d.ts.map +1 -1
  102. package/package.json +3 -3
  103. package/src/HMSInstanceSetup.tsx +2 -1
  104. package/src/HMSRoomSetup.tsx +49 -2
  105. package/src/components/Chat/ChatBanner.tsx +2 -2
  106. package/src/components/CustomButton.tsx +1 -0
  107. package/src/components/DisplayView.tsx +2 -2
  108. package/src/components/HMSManageNoiseCancellation.tsx +15 -0
  109. package/src/components/HMSPreviewHLSLiveIndicator.tsx +1 -0
  110. package/src/components/MeetingScreenContent.tsx +23 -3
  111. package/src/components/MenuModal/MenuDivider.tsx +1 -0
  112. package/src/components/Modals.tsx +56 -31
  113. package/src/components/Participants/ParticipantsItemOptions.tsx +28 -1
  114. package/src/components/PeerSettingsModalContent.tsx +17 -1
  115. package/src/components/RoomSettingsModalContent.tsx +1 -1
  116. package/src/components/VirtualBackgroundModalContent.tsx +1 -1
  117. package/src/components/WebrtcView.tsx +2 -2
  118. package/src/components/styles.ts +1 -0
  119. package/src/hooks-util.ts +89 -48
  120. package/src/utils.ts +2 -2
@@ -7,7 +7,16 @@ import {
7
7
  HMSWhiteboardUpdateType,
8
8
  } from '@100mslive/react-native-hms';
9
9
  import React, { useCallback, useEffect, useRef, useState } from 'react';
10
- import { Alert, Keyboard, StatusBar, StyleSheet, View } from 'react-native';
10
+ import {
11
+ Alert,
12
+ Keyboard,
13
+ PermissionsAndroid,
14
+ Platform,
15
+ StatusBar,
16
+ StyleSheet,
17
+ View,
18
+ } from 'react-native';
19
+ import type { Permission } from 'react-native';
11
20
  import Toast from 'react-native-simple-toast';
12
21
  import { batch, useDispatch, useSelector, useStore } from 'react-redux';
13
22
 
@@ -366,6 +375,44 @@ export const HMSRoomSetup = () => {
366
375
  };
367
376
  }, [startHLSStreaming, hmsInstance]);
368
377
 
378
+ if (Platform.OS === 'android') {
379
+ /**
380
+ * Sets up a listener for permissions requests on Android devices.
381
+ *
382
+ * This listener is activated when the HMS SDK requests permissions, such as camera or microphone access.
383
+ * It uses the `PermissionsAndroid` API to request these permissions from the user asynchronously.
384
+ * Upon receiving the permissions, it notifies the HMS SDK that the permissions have been accepted,
385
+ * allowing the SDK to proceed with operations that require these permissions.
386
+ *
387
+ * Note: This listener is only set up and functional on Android devices, as indicated by the `Platform.OS` check.
388
+ */
389
+ useEffect(() => {
390
+ const onPermissionsRequested = async ({
391
+ permissions,
392
+ }: {
393
+ permissions: Array<string>;
394
+ }) => {
395
+ // Requests multiple permissions using the PermissionsAndroid API.
396
+ await PermissionsAndroid.requestMultiple(permissions as Permission[]);
397
+ // Notifies the HMS SDK that the permissions have been accepted.
398
+ await hmsInstance.setPermissionsAcceptedOnAndroid();
399
+ };
400
+
401
+ // Adds the permissions requested listener to the HMS SDK.
402
+ hmsInstance.addEventListener(
403
+ HMSUpdateListenerActions.ON_PERMISSIONS_REQUESTED,
404
+ onPermissionsRequested
405
+ );
406
+
407
+ // Cleanup function to remove the listener when the component unmounts or dependencies change.
408
+ return () => {
409
+ hmsInstance.removeEventListener(
410
+ HMSUpdateListenerActions.ON_PERMISSIONS_REQUESTED
411
+ );
412
+ };
413
+ }, [hmsInstance]);
414
+ }
415
+
369
416
  // HMS Active Speaker Listener
370
417
  // dev-note: This is added here because we have `setPeerTrackNodes` here
371
418
  useHMSActiveSpeakerUpdates(setPeerTrackNodes, meetingJoined);
@@ -452,7 +499,7 @@ export const HMSRoomSetup = () => {
452
499
  // Show notification only if poll is started 20 or more seconds ago
453
500
  if (
454
501
  poll.startedAt &&
455
- Date.now() - poll.startedAt.getTime() >= 20_000
502
+ Date.now() - poll.startedAt.getTime() >= 20000
456
503
  ) {
457
504
  dispatch(
458
505
  addNotification({
@@ -1,6 +1,6 @@
1
- import * as React from 'react';
1
+ // @ts-ignore - Ignoring React import as it is generating error while running prepack script
2
+ import React from 'react';
2
3
  import { View, StyleSheet, Text, Image } from 'react-native';
3
-
4
4
  import { useHMSRoomStyleSheet } from '../../hooks-util';
5
5
  import { useIsLandscapeOrientation } from '../../utils/dimension';
6
6
 
@@ -1,3 +1,4 @@
1
+ // @ts-ignore - Ignoring React import as it is generating error while running prepack script
1
2
  import React from 'react';
2
3
  import {
3
4
  StyleSheet,
@@ -1,6 +1,6 @@
1
1
  import React, { useRef, useState } from 'react';
2
2
  import { useSelector } from 'react-redux';
3
- import { InteractionManager, View } from 'react-native';
3
+ import { InteractionManager, Platform, View } from 'react-native';
4
4
  import { HMSTrack, HMSCameraControl } from '@100mslive/react-native-hms';
5
5
  import type { SharedValue } from 'react-native-reanimated';
6
6
 
@@ -134,7 +134,7 @@ export const DisplayView: React.FC<DisplayViewProps> = ({
134
134
  handlePeerTileMorePress={handlePeerTileMorePress}
135
135
  />
136
136
 
137
- {isPipModeActive ? null : (
137
+ {isPipModeActive && Platform.OS === 'android' ? null : (
138
138
  <>
139
139
  <LeaveRoomBottomSheet />
140
140
 
@@ -4,6 +4,7 @@ import { PressableIcon } from './PressableIcon';
4
4
  import { styles } from './styles';
5
5
  import { useSelector } from 'react-redux';
6
6
  import type { RootState } from '../redux';
7
+ import { useHMSLayoutConfig } from '../hooks-util';
7
8
 
8
9
  export const HMSManageNoiseCancellation = () => {
9
10
  const noiseCancellationPlugin = useSelector(
@@ -12,6 +13,20 @@ export const HMSManageNoiseCancellation = () => {
12
13
  const [isNoiseCancellationEnabled, setIsNoiseCancellationEnabled] =
13
14
  React.useState(false);
14
15
 
16
+ const enabledByDefault = useHMSLayoutConfig((layoutConfig) => {
17
+ return (
18
+ layoutConfig?.screens?.preview?.default?.elements?.noise_cancellation
19
+ ?.enabled_by_default || false
20
+ );
21
+ });
22
+
23
+ React.useEffect(() => {
24
+ if (enabledByDefault) {
25
+ noiseCancellationPlugin?.enable();
26
+ setIsNoiseCancellationEnabled(true);
27
+ }
28
+ }, []);
29
+
15
30
  const handleButtonPress = async () => {
16
31
  const isAvailable =
17
32
  await noiseCancellationPlugin?.isNoiseCancellationAvailable();
@@ -1,3 +1,4 @@
1
+ // @ts-ignore - Ignoring React import as it is generating error while running prepack script
1
2
  import * as React from 'react';
2
3
  import { View, Text, StyleSheet } from 'react-native';
3
4
 
@@ -17,7 +17,7 @@ import type { RootState } from '../redux';
17
17
  import { Footer } from './Footer';
18
18
  import { DisplayView } from './DisplayView';
19
19
  import { Header } from './Header';
20
- import { useKeyboardState } from '../hooks-util';
20
+ import { useHMSLayoutConfig, useKeyboardState } from '../hooks-util';
21
21
  import { HMSStatusBar } from './StatusBar';
22
22
  import { AnimatedFooter } from './AnimatedFooter';
23
23
  import { AnimatedHeader } from './AnimatedHeader';
@@ -138,13 +138,33 @@ export const MeetingScreenContent: React.FC<MeetingScreenContentProps> = ({
138
138
  .onEnd(() => toggleControls())
139
139
  .requireExternalGestureToFail();
140
140
 
141
+ const enabledByDefault = useHMSLayoutConfig((layoutConfig) => {
142
+ return (
143
+ layoutConfig?.screens?.preview?.default?.elements?.noise_cancellation
144
+ ?.enabled_by_default || false
145
+ );
146
+ });
147
+
148
+ const shouldEnableNoiseCancellation =
149
+ Platform.OS === 'ios' && enabledByDefault;
150
+
151
+ const noiseCancellationPlugin = useSelector(
152
+ (state: RootState) => state.hmsStates.noiseCancellationPlugin
153
+ );
154
+
155
+ React.useEffect(() => {
156
+ if (shouldEnableNoiseCancellation) {
157
+ noiseCancellationPlugin?.enable();
158
+ }
159
+ }, []);
160
+
141
161
  return (
142
162
  <View style={styles.container}>
143
163
  <HMSStatusBar hidden={controlsHidden} barStyle={'light-content'} />
144
164
 
145
165
  <GestureDetector gesture={tapGesture}>
146
166
  <View collapsable={false} style={styles.container}>
147
- {isPipModeActive ? null : (
167
+ {isPipModeActive && Platform.OS === 'android' ? null : (
148
168
  <AnimatedHeader offset={offset}>
149
169
  <Header />
150
170
  </AnimatedHeader>
@@ -152,7 +172,7 @@ export const MeetingScreenContent: React.FC<MeetingScreenContentProps> = ({
152
172
 
153
173
  <DisplayView offset={offset} peerTrackNodes={peerTrackNodes} />
154
174
 
155
- {isPipModeActive ? null : (
175
+ {isPipModeActive && Platform.OS === 'android' ? null : (
156
176
  <AnimatedFooter offset={offset}>
157
177
  <Footer />
158
178
  </AnimatedFooter>
@@ -1,3 +1,4 @@
1
+ // @ts-ignore - Ignoring React import as it is generating error while running prepack script
1
2
  import React from 'react';
2
3
 
3
4
  import { StyleSheet, View } from 'react-native';
@@ -10,7 +10,6 @@ import {
10
10
  useWindowDimensions,
11
11
  } from 'react-native';
12
12
  import type { ImageURISource } from 'react-native';
13
- import Toast from 'react-native-simple-toast';
14
13
  import { useDispatch, useSelector } from 'react-redux';
15
14
  import {
16
15
  HMSTrack,
@@ -34,53 +33,75 @@ import { styles } from './styles';
34
33
  import { CustomButton } from './CustomButton';
35
34
  import { Menu, MenuItem } from './MenuModal';
36
35
 
37
- import { changeHLSAspectRatio, changeShowStats } from '../redux/actions';
36
+ import {
37
+ addNotification,
38
+ changeHLSAspectRatio,
39
+ changeShowStats,
40
+ } from '../redux/actions';
38
41
  import { getTime } from '../utils/functions';
39
42
  import { ModalTypes, SUPPORTED_ASPECT_RATIOS } from '../utils/types';
40
43
  import { COLORS } from '../utils/theme';
41
44
  import type { RootState } from '../redux';
42
45
  import { SwitchRow } from './SwitchRow';
43
- import { useHMSConferencingScreenConfig, useHMSInstance } from '../hooks-util';
46
+ import { useHMSInstance } from '../hooks-util';
47
+ import { ChevronIcon } from '../Icons';
48
+ import { NotificationTypes } from '../types';
44
49
 
45
50
  export const ChangeRoleModal = ({ cancelModal }: { cancelModal: Function }) => {
46
51
  const instance = useHMSInstance();
47
- const peer = useSelector((state: RootState) => state.app.peerToUpdate);
48
- const roles = useSelector((state: RootState) => state.hmsStates.roles);
49
-
50
- const [newRole, setNewRole] = useState<HMSRole>(peer?.role!);
51
- const [visible, setVisible] = useState<boolean>(false);
52
+ const dispatch = useDispatch();
53
+ const allRoles = useSelector((state: RootState) => state.hmsStates.roles);
54
+ let peer = useSelector((state: RootState) => state.app.peerToUpdate);
52
55
 
53
- const skipPreviewForRoleChange = useHMSConferencingScreenConfig(
54
- (conferencingScreenConfig) => {
55
- if (
56
- conferencingScreenConfig?.elements &&
57
- 'on_stage_exp' in conferencingScreenConfig.elements
58
- ) {
59
- return (
60
- conferencingScreenConfig.elements.on_stage_exp
61
- ?.skip_preview_for_role_change || false
62
- );
63
- }
64
- return false;
56
+ useEffect(() => {
57
+ let validRoles = allRoles.filter(
58
+ (role) =>
59
+ role.name !== peer?.role?.name && role.name !== '__internal_recorder'
60
+ );
61
+ setValidRoles(validRoles);
62
+ if (validRoles.length > 0) {
63
+ setNewRole(validRoles[0]);
65
64
  }
65
+ }, [allRoles, peer]);
66
+
67
+ const [validRoles, setValidRoles] = useState<HMSRole[] | undefined>(
68
+ undefined
66
69
  );
70
+ const [newRole, setNewRole] = useState<HMSRole | undefined>(undefined);
71
+
72
+ const [visible, setVisible] = useState<boolean>(false);
73
+
67
74
  const hideMenu = () => setVisible(false);
68
75
  const showMenu = () => setVisible(true);
69
- const changeRole = () => {
70
- instance
71
- ?.changeRoleOfPeer(peer!, newRole, skipPreviewForRoleChange)
72
- .catch((e) => {
73
- console.log('Change Role of Peer Error: ', e);
74
- Toast.showWithGravity((e as Error).message, Toast.LONG, Toast.TOP);
76
+ const switchRole = () => {
77
+ if (newRole) {
78
+ instance?.changeRoleOfPeer(peer!, newRole, true).catch((e) => {
79
+ console.log('Switch Role of Peer Error: ', e);
80
+ dispatch(
81
+ addNotification({
82
+ id: Math.random().toString(16).slice(2),
83
+ type: NotificationTypes.ERROR,
84
+ title: e.message,
85
+ })
86
+ );
75
87
  });
88
+ } else {
89
+ dispatch(
90
+ addNotification({
91
+ id: Math.random().toString(16).slice(2),
92
+ type: NotificationTypes.ERROR,
93
+ title: 'Please select a role',
94
+ })
95
+ );
96
+ }
76
97
  cancelModal();
77
98
  };
78
99
 
79
100
  return (
80
101
  <View style={styles.roleChangeModal}>
81
- <Text style={styles.roleChangeModalHeading}>Change Role</Text>
102
+ <Text style={styles.roleChangeModalHeading}>Switch Role</Text>
82
103
  <Text style={styles.roleChangeModalDescription}>
83
- Change the role of '{peer?.name}' to
104
+ Switch the role of '{peer?.name}' from '{peer?.role?.name}' to
84
105
  </Text>
85
106
  <Menu
86
107
  visible={visible}
@@ -88,16 +109,20 @@ export const ChangeRoleModal = ({ cancelModal }: { cancelModal: Function }) => {
88
109
  <TouchableOpacity
89
110
  style={styles.participantChangeRoleContainer}
90
111
  onPress={showMenu}
112
+ disabled={validRoles && validRoles?.length <= 1}
91
113
  >
92
114
  <Text style={styles.participantFilterText} numberOfLines={1}>
93
115
  {newRole?.name}
94
116
  </Text>
117
+ {validRoles && validRoles?.length > 1 && (
118
+ <ChevronIcon direction={'down'} />
119
+ )}
95
120
  </TouchableOpacity>
96
121
  }
97
122
  onRequestClose={hideMenu}
98
123
  style={styles.participantsMenuContainer}
99
124
  >
100
- {roles?.map((knownRole) => {
125
+ {validRoles?.map((knownRole) => {
101
126
  return (
102
127
  <MenuItem
103
128
  onPress={() => {
@@ -123,8 +148,8 @@ export const ChangeRoleModal = ({ cancelModal }: { cancelModal: Function }) => {
123
148
  textStyle={styles.roleChangeModalButtonText}
124
149
  />
125
150
  <CustomButton
126
- title="Change"
127
- onPress={changeRole}
151
+ title="Switch Role"
152
+ onPress={switchRole}
128
153
  viewStyle={styles.roleChangeModalSuccessButton}
129
154
  textStyle={styles.roleChangeModalButtonText}
130
155
  />
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { StyleSheet, View } from 'react-native';
3
- import { useSelector } from 'react-redux';
3
+ import { useDispatch, useSelector } from 'react-redux';
4
4
  import type { HMSLocalPeer, HMSPeer } from '@100mslive/react-native-hms';
5
5
  import { HMSPeerType } from '@100mslive/react-native-hms';
6
6
 
@@ -8,12 +8,15 @@ import {
8
8
  useHMSInstance,
9
9
  useHMSLayoutConfig,
10
10
  useHMSRoomStyleSheet,
11
+ useModalType,
11
12
  } from '../../hooks-util';
12
13
  import { CameraIcon, HandIcon, MicIcon, PersonIcon } from '../../Icons';
13
14
  import { ParticipantsItemOption } from './ParticipantsItemOption';
14
15
  import type { RootState } from '../../redux';
15
16
  import { selectCanPublishTrackForRole } from '../../hooks-sdk-selectors';
16
17
  import { parseMetadata } from '../../utils/functions';
18
+ import { ModalTypes } from '../../utils/types';
19
+ import { setPeerToUpdate } from '../../redux/actions';
17
20
 
18
21
  interface ParticipantsItemOptionsProps {
19
22
  insideHandRaiseGroup: boolean;
@@ -33,12 +36,16 @@ const _ParticipantsItemOptions: React.FC<ParticipantsItemOptionsProps> = ({
33
36
  (state: RootState) => state.hmsStates.localPeer?.role?.permissions
34
37
  );
35
38
 
39
+ const roles = useSelector((state: RootState) => state.hmsStates.roles);
40
+
36
41
  const localPeerCanMuteTrack =
37
42
  localPeerPermissions && localPeerPermissions.mute;
38
43
  const localPeerCanUnmuteTrack =
39
44
  localPeerPermissions && localPeerPermissions.unmute;
40
45
  const localPeerCanRemove =
41
46
  localPeerPermissions && localPeerPermissions.removeOthers;
47
+ const localPeerCanChangeRole =
48
+ localPeerPermissions && localPeerPermissions.changeRole && roles.length > 1;
42
49
 
43
50
  // Selected Peer Permissions related states
44
51
  const peerCanPublishAudio = selectCanPublishTrackForRole(peer.role!, 'audio');
@@ -153,6 +160,16 @@ const _ParticipantsItemOptions: React.FC<ParticipantsItemOptionsProps> = ({
153
160
  onItemPress();
154
161
  };
155
162
 
163
+ const { handleModalVisibleType: setModalVisible } = useModalType();
164
+
165
+ const dispatch = useDispatch();
166
+
167
+ const handleChangeRolePress = () => {
168
+ setModalVisible(ModalTypes.CHANGE_ROLE, true);
169
+ dispatch(setPeerToUpdate(peer));
170
+ onItemPress();
171
+ };
172
+
156
173
  const showMuteAudioOption =
157
174
  !insideHandRaiseGroup &&
158
175
  localPeerCanMuteTrack &&
@@ -249,6 +266,16 @@ const _ParticipantsItemOptions: React.FC<ParticipantsItemOptionsProps> = ({
249
266
  isActive: false,
250
267
  hide: Boolean(!onStageRoleStr || peer.role?.name !== onStageRoleStr),
251
268
  },
269
+ {
270
+ id: 'change-role',
271
+ icon: (
272
+ <PersonIcon type="rectangle" style={{ width: 20, height: 20 }} />
273
+ ),
274
+ label: 'Switch Role',
275
+ pressHandler: handleChangeRolePress,
276
+ isActive: false,
277
+ hide: !localPeerCanChangeRole,
278
+ },
252
279
  {
253
280
  id: 'remove-participant',
254
281
  icon: <PersonIcon type="left" style={{ width: 20, height: 20 }} />,
@@ -14,7 +14,7 @@ import { HMSPeerType, HMSTrack } from '@100mslive/react-native-hms';
14
14
  import type { RootState } from '../redux';
15
15
  import type { PeerTrackNode } from '../utils/types';
16
16
  import { ModalTypes } from '../utils/types';
17
- import { setInsetViewMinimized } from '../redux/actions';
17
+ import { setInsetViewMinimized, setPeerToUpdate } from '../redux/actions';
18
18
  import { useHMSRoomStyle, useModalType } from '../hooks-util';
19
19
  import {
20
20
  CameraIcon,
@@ -40,6 +40,7 @@ export const PeerSettingsModalContent: React.FC<
40
40
  > = ({ peerTrackNode, peerTrackNodesListEmpty, cancelModal }) => {
41
41
  const dispatch = useDispatch();
42
42
  const hmsInstance = useSelector((state: RootState) => state.user.hmsInstance);
43
+ const allRoles = useSelector((state: RootState) => state.hmsStates.roles);
43
44
  const localPeer = useSelector(
44
45
  (state: RootState) => state.hmsStates.localPeer
45
46
  );
@@ -92,6 +93,11 @@ export const PeerSettingsModalContent: React.FC<
92
93
  );
93
94
  };
94
95
 
96
+ const switchRole = () => {
97
+ setModalVisible(ModalTypes.CHANGE_ROLE, true);
98
+ dispatch(setPeerToUpdate(peerTrackNode.peer));
99
+ };
100
+
95
101
  const changeName = () => {
96
102
  setModalVisible(ModalTypes.CHANGE_NAME, true);
97
103
  };
@@ -194,6 +200,16 @@ export const PeerSettingsModalContent: React.FC<
194
200
  </>
195
201
  ) : null}
196
202
 
203
+ {allRoles.length > 1 &&
204
+ !peer.isLocal &&
205
+ localPeerPermissions?.changeRole ? (
206
+ <SettingItem
207
+ text={'Switch Role'}
208
+ icon={<PersonIcon type="rectangle" style={styles.customIcon} />}
209
+ onPress={switchRole}
210
+ />
211
+ ) : null}
212
+
197
213
  {!peer.isLocal && localPeerPermissions?.removeOthers ? (
198
214
  <SettingItem
199
215
  text="Remove Participant"
@@ -252,7 +252,7 @@ export const RoomSettingsModalContent: React.FC<
252
252
  }, [noiseCancellationPlugin]);
253
253
 
254
254
  const handleNoiseCancellation = () => {
255
- // Register callback to be called when bottom sheet is hiddden
255
+ // Register callback to be called when bottom sheet is hidden
256
256
  registerOnModalHideAction(() => {
257
257
  if (!noiseCancellationPlugin || !isNoiseCancellationAvailable) return;
258
258
 
@@ -109,7 +109,7 @@ export const VirtualBackgroundModalContent: React.FC<
109
109
  // If PIP is enabled, disable it
110
110
  if (pipModeEnabled) {
111
111
  dispatch(setAutoEnterPipMode(false));
112
- disableAutoPip();
112
+ disableAutoPip({});
113
113
  }
114
114
 
115
115
  const imageLibraryResponse = await ImagePicker.launchImageLibrary({
@@ -24,7 +24,7 @@ import { OverlayContainer } from './OverlayContainer';
24
24
  import { OverlayedViews } from './OverlayedViews';
25
25
  import { useFooterHeight } from './Footer';
26
26
  import { useHeaderHeight } from './Header';
27
- import { View } from 'react-native';
27
+ import { Platform, View } from 'react-native';
28
28
  import { WebrtcTranscriptOverlayView } from './WebrtcTranscriptOverlayView';
29
29
 
30
30
  interface WebrtcViewProps {
@@ -111,7 +111,7 @@ export const WebrtcView = React.forwardRef<GridViewRefAttrs, WebrtcViewProps>(
111
111
  };
112
112
  }, [isPortrait, bottom]);
113
113
 
114
- if (isPipModeActive) {
114
+ if (isPipModeActive && Platform.OS === 'android') {
115
115
  return (
116
116
  <PIPView
117
117
  peerTrackNodes={peerTrackNodes}
@@ -766,6 +766,7 @@ const styles = StyleSheet.create({
766
766
  padding: 8,
767
767
  flexDirection: 'row',
768
768
  alignItems: 'center',
769
+ justifyContent: 'space-between',
769
770
  width: '100%',
770
771
  marginTop: 24,
771
772
  borderWidth: 1,