agora-appbuilder-core 2.0.1 → 2.0.3-rc2

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 (79) hide show
  1. package/Readme.md +2 -1
  2. package/package.json +1 -1
  3. package/template/_package-lock.json +8853 -8806
  4. package/template/agora-rn-uikit/.git/index +0 -0
  5. package/template/agora-rn-uikit/.git/logs/HEAD +2 -2
  6. package/template/agora-rn-uikit/.git/logs/refs/heads/ab-dev-auto +1 -1
  7. package/template/agora-rn-uikit/.git/logs/refs/heads/master +1 -1
  8. package/template/agora-rn-uikit/.git/logs/refs/remotes/origin/HEAD +1 -1
  9. package/template/agora-rn-uikit/.git/objects/pack/pack-2a0122bf5a3199f941e5a52535f43881623f752c.idx +0 -0
  10. package/template/agora-rn-uikit/.git/objects/pack/{pack-f379286d0537eb68377220b4929979324b8d5d1c.pack → pack-2a0122bf5a3199f941e5a52535f43881623f752c.pack} +0 -0
  11. package/template/agora-rn-uikit/.git/packed-refs +4 -2
  12. package/template/agora-rn-uikit/.git/refs/heads/ab-dev-auto +1 -1
  13. package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +21 -0
  14. package/template/agora-rn-uikit/src/Controls/BtnTemplate.tsx +22 -14
  15. package/template/agora-rn-uikit/src/Controls/ImageIcon.tsx +17 -13
  16. package/template/agora-rn-uikit/src/Controls/types.ts +4 -0
  17. package/template/agora-rn-uikit/src/Rtc/Create.tsx +117 -19
  18. package/template/agora-rn-uikit/src/RtcConfigure.tsx +24 -13
  19. package/template/{src/utils/isSafariBrowser.tsx → agora-rn-uikit/src/Utils/isSafariBrowser.ts} +3 -0
  20. package/template/{src → agora-rn-uikit/src}/hooks/useImageDelay.tsx +5 -2
  21. package/template/agora-rn-uikit/src/index.ts +2 -0
  22. package/template/bridge/rtc/webNg/RtcEngine.ts +73 -70
  23. package/template/bridge/rtc/webNg/Types.ts +59 -5
  24. package/template/bridge/rtm/web/Types.ts +13 -0
  25. package/template/bridge/rtm/web/index.ts +78 -1
  26. package/template/global.d.ts +2 -0
  27. package/template/package-lock.json +8853 -8806
  28. package/template/package.json +3 -4
  29. package/template/react-native-toast-message/src/components/base/styles.js +4 -2
  30. package/template/src/assets/icons.ts +41 -28
  31. package/template/src/components/Chat.tsx +70 -184
  32. package/template/src/components/ChatContext.ts +13 -2
  33. package/template/src/components/Controls.native.tsx +37 -76
  34. package/template/src/components/Controls.tsx +50 -158
  35. package/template/src/components/DeviceConfigure.native.tsx +5 -1
  36. package/template/src/components/DeviceConfigure.tsx +38 -20
  37. package/template/src/components/Navbar.tsx +185 -226
  38. package/template/src/components/ParticipantsView.tsx +176 -184
  39. package/template/src/components/Precall.native.tsx +83 -69
  40. package/template/src/components/Precall.tsx +174 -191
  41. package/template/src/components/RTMConfigure.tsx +264 -78
  42. package/template/src/components/SettingsView.tsx +9 -19
  43. package/template/src/components/livestream/LiveStreamContext.tsx +411 -0
  44. package/template/src/components/livestream/Types.ts +69 -0
  45. package/template/src/components/livestream/index.ts +9 -0
  46. package/template/src/components/livestream/views/LiveStreamControls.tsx +27 -0
  47. package/template/src/components/participants/AllAudienceParticipants.tsx +53 -0
  48. package/template/src/components/participants/AllHostParticipants.tsx +65 -0
  49. package/template/src/components/participants/MeParticipant.tsx +37 -0
  50. package/template/src/components/participants/ParticipantName.tsx +47 -0
  51. package/template/src/components/participants/ParticipantSectionTitle.tsx +29 -0
  52. package/template/src/components/participants/RemoteParticipants.tsx +69 -0
  53. package/template/src/components/participants/ScreenshareParticipants.tsx +28 -0
  54. package/template/src/components/participants/context/ParticipantContext.tsx +97 -0
  55. package/template/src/components/styles.ts +13 -0
  56. package/template/src/pages/Create.tsx +25 -14
  57. package/template/src/pages/VideoCall.tsx +197 -159
  58. package/template/src/subComponents/ChatBubble.tsx +4 -1
  59. package/template/src/subComponents/ChatContainer.tsx +44 -20
  60. package/template/src/subComponents/ChatInput.tsx +4 -12
  61. package/template/src/subComponents/Checkbox.native.tsx +6 -5
  62. package/template/src/subComponents/Checkbox.tsx +1 -0
  63. package/template/src/subComponents/Recording.tsx +23 -9
  64. package/template/src/subComponents/RemoteVideoMute.tsx +2 -3
  65. package/template/src/subComponents/SelectDevice.tsx +70 -35
  66. package/template/src/subComponents/chat/ChatParticipants.tsx +121 -0
  67. package/template/src/subComponents/livestream/ApprovedLiveStreamControlsView.tsx +23 -0
  68. package/template/src/subComponents/livestream/CurrentLiveStreamRequestsView.tsx +70 -0
  69. package/template/src/subComponents/livestream/controls/LocalRaiseHand.tsx +57 -0
  70. package/template/src/subComponents/livestream/controls/RemoteLiveStreamApprovedRequestRecall.tsx +24 -0
  71. package/template/src/subComponents/livestream/controls/RemoteLiveStreamRequestApprove.tsx +38 -0
  72. package/template/src/subComponents/livestream/controls/RemoteLiveStreamRequestReject.tsx +37 -0
  73. package/template/src/subComponents/livestream/index.ts +18 -0
  74. package/template/src/subComponents/screenshare/ScreenshareButton.tsx +80 -0
  75. package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +24 -0
  76. package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +200 -0
  77. package/template/src/subComponents/screenshare/ScreenshareContext.tsx +21 -0
  78. package/template/src/utils/index.tsx +48 -0
  79. package/template/agora-rn-uikit/.git/objects/pack/pack-f379286d0537eb68377220b4929979324b8d5d1c.idx +0 -0
@@ -22,6 +22,7 @@ const Checkbox = (props: any) => {
22
22
  const setUrlCheckbox = props.onValueChange;
23
23
  return (
24
24
  <CheckBox
25
+ disabled={props?.disabled}
25
26
  value={urlCheckbox}
26
27
  onValueChange={setUrlCheckbox}
27
28
  //@ts-ignore Color prop exists on react-native-web but it not present in @react-native-community/checkbox
@@ -9,9 +9,8 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React, {useContext, useEffect} from 'react';
13
- import {Image, TouchableOpacity, StyleSheet, View, Text} from 'react-native';
14
- import icons from '../assets/icons';
12
+ import React, {useContext, useEffect, useRef} from 'react';
13
+ import {TouchableOpacity, StyleSheet, View, Text} from 'react-native';
15
14
  import ChatContext, {controlMessageEnum} from '../components/ChatContext';
16
15
  import ColorContext from '../components/ColorContext';
17
16
  import {gql, useMutation} from '@apollo/client';
@@ -37,6 +36,14 @@ const STOP_RECORDING = gql`
37
36
  * Sends a control message to all users in the channel over RTM to indicate that
38
37
  * Cloud recording has started/stopped.
39
38
  */
39
+ function usePrevious(value: any) {
40
+ const ref = useRef();
41
+ useEffect(() => {
42
+ ref.current = value;
43
+ });
44
+ return ref.current;
45
+ }
46
+
40
47
  const Recording = (props: any) => {
41
48
  const {rtcProps} = useContext(PropsContext);
42
49
  const {primaryColor} = useContext(ColorContext);
@@ -46,12 +53,19 @@ const Recording = (props: any) => {
46
53
  const [startRecordingQuery] = useMutation(START_RECORDING);
47
54
  const [stopRecordingQuery] = useMutation(STOP_RECORDING);
48
55
  const {sendControlMessage} = useContext(ChatContext);
56
+ const prevRecordingState = usePrevious({recordingActive});
49
57
 
50
58
  useEffect(() => {
51
- if (recordingActive)
59
+ /**
60
+ * The below check makes sure the notification is triggered
61
+ * only once. In native apps, this componenet is mounted everytime
62
+ * when chat icon is toggle, as Controls component is hidden and
63
+ * shown
64
+ */
65
+ if (prevRecordingState && recordingActive) {
66
+ if (prevRecordingState?.recordingActive === recordingActive) return;
52
67
  Toast.show({text1: 'Recording Started', visibilityTime: 1000});
53
- // else if(!recordingActive)
54
- // Toast.show({text1: 'Recording Finished', visibilityTime: 1000})
68
+ }
55
69
  }, [recordingActive]);
56
70
 
57
71
  return (
@@ -103,7 +117,7 @@ const Recording = (props: any) => {
103
117
  <ImageIcon
104
118
  name={recordingActive ? 'recordingActiveIcon' : 'recordingIcon'}
105
119
  style={[style.buttonIcon]}
106
- color={recordingActive ? '#FD0845': $config.PRIMARY_COLOR}
120
+ color={recordingActive ? '#FD0845' : $config.PRIMARY_COLOR}
107
121
  />
108
122
  </View>
109
123
  <Text
@@ -132,8 +146,8 @@ const style = StyleSheet.create({
132
146
  justifyContent: 'center',
133
147
  },
134
148
  buttonIcon: {
135
- width: '100%',
136
- height: '100%',
149
+ width: '90%',
150
+ height: '90%',
137
151
  },
138
152
  });
139
153
 
@@ -24,9 +24,9 @@ const RemoteVideoMute = (props: {
24
24
  video: boolean;
25
25
  isHost: boolean;
26
26
  }) => {
27
- const {primaryColor} = useContext(ColorContext);
28
27
  const {isHost = false} = props;
29
28
  const {sendControlMessageToUid} = useContext(ChatContext);
29
+
30
30
  return String(props.uid)[0] !== '1' ? (
31
31
  <BtnTemplate
32
32
  disabled={!isHost}
@@ -43,9 +43,8 @@ const RemoteVideoMute = (props: {
43
43
 
44
44
  const style = StyleSheet.create({
45
45
  buttonIconCam: {
46
- width: 28,
46
+ width: 25,
47
47
  height: 25,
48
- marginHorizontal: 2,
49
48
  },
50
49
  });
51
50
 
@@ -10,7 +10,8 @@
10
10
  *********************************************
11
11
  */
12
12
  import React, {useContext} from 'react';
13
- import {Picker, StyleSheet} from 'react-native';
13
+ import {Picker, StyleSheet, View, Text} from 'react-native';
14
+ import {PropsContext, ClientRole} from '../../agora-rn-uikit';
14
15
  import DeviceContext from '../components/DeviceContext';
15
16
  import ColorContext from '../components/ColorContext';
16
17
  // import {dropdown} from '../../theme.json';
@@ -19,45 +20,74 @@ import ColorContext from '../components/ColorContext';
19
20
  * It will add the selected device to the device context.
20
21
  */
21
22
  const SelectDevice = () => {
23
+ // Contexts
24
+ const {rtcProps} = useContext(PropsContext);
22
25
  const {primaryColor} = useContext(ColorContext);
23
26
  const {selectedCam, setSelectedCam, selectedMic, setSelectedMic, deviceList} =
24
27
  useContext(DeviceContext);
28
+ // States
29
+ const [isPickerDisabled, setPickerDisabled] = React.useState<boolean>(false);
30
+ const [btnTheme, setBtnTheme] = React.useState<string>(primaryColor);
31
+
32
+ React.useEffect(() => {
33
+ if ($config.EVENT_MODE && rtcProps.role === ClientRole.Audience) {
34
+ setPickerDisabled(true);
35
+ setBtnTheme('rgba(16, 16, 16, 0.3)');
36
+ } else {
37
+ setPickerDisabled(false);
38
+ setBtnTheme(primaryColor);
39
+ }
40
+ }, [rtcProps?.role]);
25
41
 
26
42
  return (
27
- <>
28
- <Picker
29
- selectedValue={selectedCam}
30
- style={[{borderColor: primaryColor}, style.popupPicker]}
31
- onValueChange={(itemValue) => setSelectedCam(itemValue)}>
32
- {deviceList.map((device: any) => {
33
- if (device.kind === 'videoinput') {
34
- return (
35
- <Picker.Item
36
- label={device.label}
37
- value={device.deviceId}
38
- key={device.deviceId}
39
- />
40
- );
41
- }
42
- })}
43
- </Picker>
44
- <Picker
45
- selectedValue={selectedMic}
46
- style={[{borderColor: primaryColor}, style.popupPicker]}
47
- onValueChange={(itemValue) => setSelectedMic(itemValue)}>
48
- {deviceList.map((device: any) => {
49
- if (device.kind === 'audioinput') {
50
- return (
51
- <Picker.Item
52
- label={device.label}
53
- value={device.deviceId}
54
- key={device.deviceId}
55
- />
56
- );
57
- }
58
- })}
59
- </Picker>
60
- </>
43
+ <View>
44
+ <View style={{marginTop: 15}}></View>
45
+ <View>
46
+ <Picker
47
+ enabled={!isPickerDisabled}
48
+ selectedValue={selectedCam}
49
+ style={[{borderColor: btnTheme}, style.popupPicker]}
50
+ onValueChange={(itemValue) => setSelectedCam(itemValue)}>
51
+ {deviceList.map((device: any) => {
52
+ if (device.kind === 'videoinput') {
53
+ return (
54
+ <Picker.Item
55
+ label={device.label}
56
+ value={device.deviceId}
57
+ key={device.deviceId}
58
+ />
59
+ );
60
+ }
61
+ })}
62
+ </Picker>
63
+ <Picker
64
+ enabled={!isPickerDisabled}
65
+ selectedValue={selectedMic}
66
+ style={[{borderColor: btnTheme}, style.popupPicker]}
67
+ onValueChange={(itemValue) => setSelectedMic(itemValue)}>
68
+ {deviceList.map((device: any) => {
69
+ if (device.kind === 'audioinput') {
70
+ return (
71
+ <Picker.Item
72
+ label={device.label}
73
+ value={device.deviceId}
74
+ key={device.deviceId}
75
+ />
76
+ );
77
+ }
78
+ })}
79
+ </Picker>
80
+ </View>
81
+ <View style={{marginTop: 15}}></View>
82
+ {$config.EVENT_MODE && isPickerDisabled && (
83
+ <View>
84
+ <Text style={style.infoTxt}>
85
+ Video and Audio sharing is disabled for attendees. Raise hand to
86
+ request permission to share
87
+ </Text>
88
+ </View>
89
+ )}
90
+ </View>
61
91
  );
62
92
  };
63
93
 
@@ -70,6 +100,11 @@ const style = StyleSheet.create({
70
100
  fontSize: 15,
71
101
  minHeight: 35,
72
102
  },
103
+ infoTxt: {
104
+ textAlign: 'center',
105
+ fontSize: 12,
106
+ color: '#FF0000',
107
+ },
73
108
  });
74
109
 
75
110
  export default SelectDevice;
@@ -0,0 +1,121 @@
1
+ import React, {useContext} from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ ScrollView,
7
+ useWindowDimensions,
8
+ StyleSheet,
9
+ Platform,
10
+ } from 'react-native';
11
+ import {RFValue} from 'react-native-responsive-fontsize';
12
+ import {UserType} from '../../components/RTMConfigure';
13
+ import TextWithTooltip from '../TextWithTooltip';
14
+ import chatContext from '../../components/ChatContext';
15
+
16
+ const ChatParticipants = (props: any) => {
17
+ const {
18
+ selectUser,
19
+ setPrivateMessageLastSeen,
20
+ privateMessageCountMap,
21
+ lastCheckedPrivateState,
22
+ } = props;
23
+ const {height, width} = useWindowDimensions();
24
+ const {userList, localUid} = useContext(chatContext);
25
+
26
+ const isChatUser = (userId: string, userInfo: any) => {
27
+ return (
28
+ userId !== localUid &&
29
+ parseInt(userId) !== 1 &&
30
+ userInfo?.type !== UserType.ScreenShare &&
31
+ !userInfo?.offline
32
+ );
33
+ };
34
+
35
+ return (
36
+ <ScrollView>
37
+ {Object.entries(userList).map(([uid, value]) => {
38
+ if (isChatUser(uid, value)) {
39
+ return (
40
+ <TouchableOpacity
41
+ style={style.participantContainer}
42
+ key={uid}
43
+ onPress={() => {
44
+ selectUser(uid);
45
+ setPrivateMessageLastSeen({
46
+ userId: uid,
47
+ lastSeenCount: privateMessageCountMap[uid],
48
+ });
49
+ }}>
50
+ {(privateMessageCountMap[uid] || 0) -
51
+ (lastCheckedPrivateState[uid] || 0) !==
52
+ 0 ? (
53
+ <View style={style.chatNotificationPrivate}>
54
+ <Text>
55
+ {(privateMessageCountMap[uid] || 0) -
56
+ (lastCheckedPrivateState[uid] || 0)}
57
+ </Text>
58
+ </View>
59
+ ) : null}
60
+ <View style={{flex: 1}}>
61
+ <TextWithTooltip
62
+ touchable={false}
63
+ style={[
64
+ style.participantText,
65
+ {
66
+ fontSize: RFValue(16, height > width ? height : width),
67
+ },
68
+ ]}
69
+ value={userList[uid] ? userList[uid].name + ' ' : 'User '}
70
+ />
71
+ </View>
72
+ <View>
73
+ <Text
74
+ style={{
75
+ color: $config.PRIMARY_FONT_COLOR,
76
+ fontSize: 18,
77
+ }}>{`>`}</Text>
78
+ </View>
79
+ </TouchableOpacity>
80
+ );
81
+ }
82
+ })}
83
+ </ScrollView>
84
+ );
85
+ };
86
+
87
+ const style = StyleSheet.create({
88
+ participantContainer: {
89
+ flexDirection: 'row',
90
+ flex: 1,
91
+ height: 20,
92
+ marginTop: 10,
93
+ backgroundColor: $config.SECONDARY_FONT_COLOR,
94
+ overflow: 'hidden',
95
+ marginHorizontal: 10,
96
+ },
97
+ participantText: {
98
+ flex: 1,
99
+ fontWeight: Platform.OS === 'web' ? '500' : '700',
100
+ flexDirection: 'row',
101
+ color: $config.PRIMARY_FONT_COLOR,
102
+ textAlign: 'left',
103
+ flexShrink: 1,
104
+ marginRight: 30,
105
+ },
106
+ chatNotificationPrivate: {
107
+ width: 20,
108
+ height: 20,
109
+ display: 'flex',
110
+ alignItems: 'center',
111
+ justifyContent: 'center',
112
+ backgroundColor: $config.PRIMARY_COLOR,
113
+ color: $config.SECONDARY_FONT_COLOR,
114
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica' : 'sans-serif',
115
+ borderRadius: 10,
116
+ position: 'absolute',
117
+ right: 20,
118
+ top: 0,
119
+ },
120
+ });
121
+ export default ChatParticipants;
@@ -0,0 +1,23 @@
1
+ import React, {useContext} from 'react';
2
+ import {View} from 'react-native';
3
+ import RemoteLiveStreamApprovedRequestRecall from './controls/RemoteLiveStreamApprovedRequestRecall';
4
+ import LiveStreamContext, {requestStatus} from '../../components/livestream';
5
+
6
+ const ApprovedLiveStreamControlsView = (props: {
7
+ uid: number;
8
+ p_styles: any;
9
+ }) => {
10
+ const {uid, p_styles} = props;
11
+ const {currLiveStreamRequest} = useContext(LiveStreamContext);
12
+
13
+ if (currLiveStreamRequest[uid]?.status === requestStatus.Approved) {
14
+ return (
15
+ <View style={[p_styles.actionBtnIcon, {marginRight: 10}]}>
16
+ <RemoteLiveStreamApprovedRequestRecall uid={uid} />
17
+ </View>
18
+ );
19
+ }
20
+ return <></>;
21
+ };
22
+
23
+ export default ApprovedLiveStreamControlsView;
@@ -0,0 +1,70 @@
1
+ import React, {useContext, useEffect, useState} from 'react';
2
+ import {View, Text} from 'react-native';
3
+ import RemoteLiveStreamRequestApprove from './controls/RemoteLiveStreamRequestApprove';
4
+ import RemoteLiveStreamRequestReject from './controls/RemoteLiveStreamRequestReject';
5
+ import ParticipantName from '../../components/participants/ParticipantName';
6
+ import LiveStreamContext, {requestStatus} from '../../components/livestream';
7
+ import {filterObject} from '../../utils/index';
8
+ import ParticipantSectionTitle from '../../components/participants/ParticipantSectionTitle';
9
+
10
+ const CurrentLiveStreamRequestsView = (props: any) => {
11
+ const {userList, p_style} = props;
12
+ const {currLiveStreamRequest, setLastCheckedRequestTimestamp} =
13
+ useContext(LiveStreamContext);
14
+ const [activeLiveStreamRequests, setActiveLiveStreamRequests] =
15
+ React.useState({});
16
+
17
+ useEffect(() => {
18
+ setActiveLiveStreamRequests(
19
+ filterObject(
20
+ currLiveStreamRequest,
21
+ ([k, v]) => v?.status === requestStatus.AwaitingAction,
22
+ ),
23
+ );
24
+ }, [currLiveStreamRequest]);
25
+
26
+ React.useEffect(() => {
27
+ // On unmount update the timestamp, if the user was already active in this view
28
+ return () => {
29
+ setLastCheckedRequestTimestamp(new Date().getTime());
30
+ };
31
+ }, []);
32
+
33
+ return (
34
+ <>
35
+ <ParticipantSectionTitle
36
+ title="Streaming Request "
37
+ count={Object.keys(activeLiveStreamRequests).length}
38
+ />
39
+ <View style={p_style.participantContainer}>
40
+ {Object.keys(currLiveStreamRequest).length == 0 ||
41
+ Object.keys(activeLiveStreamRequests).length == 0 ? (
42
+ <Text style={p_style.infoText}>No streaming request(s)</Text>
43
+ ) : (
44
+ Object.keys(activeLiveStreamRequests).map(
45
+ (userUID: any, index: number) =>
46
+ userList[userUID] ? (
47
+ <View style={p_style.participantRow} key={index}>
48
+ <ParticipantName value={userList[userUID]?.name || 'User'} />
49
+ <View style={p_style.participantActionContainer}>
50
+ <RemoteLiveStreamRequestApprove
51
+ user={{...userList[userUID], uid: userUID}}
52
+ />
53
+ <RemoteLiveStreamRequestReject
54
+ user={{...userList[userUID], uid: userUID}}
55
+ />
56
+ </View>
57
+ </View>
58
+ ) : (
59
+ <View style={p_style.participantRow} key={index}>
60
+ <ParticipantName value={'User not found'} />
61
+ </View>
62
+ ),
63
+ )
64
+ )}
65
+ </View>
66
+ </>
67
+ );
68
+ };
69
+
70
+ export default CurrentLiveStreamRequestsView;
@@ -0,0 +1,57 @@
1
+ /*
2
+ ********************************************
3
+ Copyright © 2021 Agora Lab, Inc., all rights reserved.
4
+ AppBuilder and all associated components, source code, APIs, services, and documentation
5
+ (the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
6
+ accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
7
+ Use without a license or in violation of any license terms and conditions (including use for
8
+ any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
9
+ information visit https://appbuilder.agora.io.
10
+ *********************************************
11
+ */
12
+ import React, {useContext} from 'react';
13
+ import {StyleSheet} from 'react-native';
14
+ import LiveStreamContext from '../../../components/livestream';
15
+ import {PropsContext} from '../../../../agora-rn-uikit';
16
+ import {BtnTemplate} from '../../../../agora-rn-uikit';
17
+ import icons from '../../../assets/icons';
18
+
19
+ const LocalRaiseHand = () => {
20
+ const {styleProps} = useContext(PropsContext);
21
+ const {audienceSendsRequest, audienceRecallsRequest, raiseHandRequestActive} =
22
+ useContext(LiveStreamContext);
23
+ const {localBtnStyles} = styleProps || {};
24
+ const {theme} = styleProps || {};
25
+ const {muteLocalAudio} = localBtnStyles || {};
26
+
27
+ return (
28
+ <BtnTemplate
29
+ icon={icons['raiseHandIcon']}
30
+ btnText={raiseHandRequestActive ? 'Lower hand' : 'Raise Hand'}
31
+ color={raiseHandRequestActive ? '#FD0845' : theme}
32
+ style={{
33
+ ...style.localBtn,
34
+ ...(localBtnStyles as object),
35
+ ...(muteLocalAudio as object),
36
+ }}
37
+ onPress={() => {
38
+ if (!raiseHandRequestActive) {
39
+ audienceSendsRequest();
40
+ } else {
41
+ audienceRecallsRequest();
42
+ }
43
+ }}
44
+ />
45
+ );
46
+ };
47
+
48
+ const style = StyleSheet.create({
49
+ localBtn: {
50
+ borderRadius: 23,
51
+ borderWidth: 4 * StyleSheet.hairlineWidth,
52
+ borderColor: '#007aff',
53
+ backgroundColor: '#007aff',
54
+ },
55
+ });
56
+
57
+ export default LocalRaiseHand;
@@ -0,0 +1,24 @@
1
+ import React, {useContext} from 'react';
2
+ import ChatContext from '../../../components/ChatContext';
3
+ import {BtnTemplate} from '../../../../agora-rn-uikit';
4
+ import {LiveStreamControlMessageEnum} from '../../../components/livestream';
5
+ import icons from '../../../assets/icons';
6
+
7
+ const RemoteLiveStreamApprovedRequestRecall = (props: {uid: number}) => {
8
+ const {sendControlMessageToUid} = useContext(ChatContext);
9
+ return (
10
+ <BtnTemplate
11
+ style={{width: 24, height: 22}}
12
+ onPress={() => {
13
+ sendControlMessageToUid(
14
+ LiveStreamControlMessageEnum.raiseHandApprovedRequestRecall,
15
+ props.uid,
16
+ );
17
+ }}
18
+ color="#FD0845"
19
+ icon={icons['demoteIcon']}
20
+ />
21
+ );
22
+ };
23
+
24
+ export default RemoteLiveStreamApprovedRequestRecall;
@@ -0,0 +1,38 @@
1
+ import React, {useContext} from 'react';
2
+ import {View} from 'react-native';
3
+ import {
4
+ BtnTemplate,
5
+ PropsContext,
6
+ UidInterface,
7
+ } from '../../../../agora-rn-uikit';
8
+ import LiveStreamContext from '../../../components/livestream';
9
+ import icons from '../../../assets/icons';
10
+
11
+ interface RemoteLiveStreamControlInterface {
12
+ user: UidInterface;
13
+ }
14
+
15
+ const RemoteLiveStreamRequestApprove: React.FC<RemoteLiveStreamControlInterface> =
16
+ (props) => {
17
+ const {user} = props;
18
+ const {hostApprovesRequestOfUID} = useContext(LiveStreamContext);
19
+ const {styleProps} = useContext(PropsContext);
20
+ const {remoteBtnStyles} = styleProps || {};
21
+
22
+ const {liveStreamHostControlBtns} = remoteBtnStyles || {};
23
+
24
+ return (
25
+ <View style={{...(liveStreamHostControlBtns as object), marginRight: 15}}>
26
+ <BtnTemplate
27
+ disabled={!user?.uid}
28
+ icon={icons['checkCircleIcon']}
29
+ style={{...(liveStreamHostControlBtns as object)}}
30
+ onPress={() => {
31
+ hostApprovesRequestOfUID(user?.uid);
32
+ }}
33
+ />
34
+ </View>
35
+ );
36
+ };
37
+
38
+ export default RemoteLiveStreamRequestApprove;
@@ -0,0 +1,37 @@
1
+ import React, {useContext} from 'react';
2
+ import {View} from 'react-native';
3
+ import {
4
+ BtnTemplate,
5
+ PropsContext,
6
+ UidInterface,
7
+ } from '../../../../agora-rn-uikit';
8
+ import LiveStreamContext from '../../../components/livestream';
9
+ import icons from '../../../assets/icons';
10
+
11
+ interface RemoteLiveStreamControlInterface {
12
+ user: UidInterface;
13
+ }
14
+
15
+ const RemoteLiveStreamRequestReject: React.FC<RemoteLiveStreamControlInterface> =
16
+ (props) => {
17
+ const {user} = props;
18
+ const {hostRejectsRequestOfUID} = useContext(LiveStreamContext);
19
+ const {styleProps} = useContext(PropsContext);
20
+ const {remoteBtnStyles} = styleProps || {};
21
+ const {liveStreamHostControlBtns} = remoteBtnStyles || {};
22
+
23
+ return (
24
+ <View style={{...(liveStreamHostControlBtns as object)}}>
25
+ <BtnTemplate
26
+ disabled={!user?.uid}
27
+ icon={icons['crossCircleIcon']}
28
+ style={{...(liveStreamHostControlBtns as object)}}
29
+ onPress={() => {
30
+ hostRejectsRequestOfUID(user.uid);
31
+ }}
32
+ />
33
+ </View>
34
+ );
35
+ };
36
+
37
+ export default RemoteLiveStreamRequestReject;
@@ -0,0 +1,18 @@
1
+ // Remote controls
2
+ import RemoteLiveStreamApprovedRequestRecall from './controls/RemoteLiveStreamApprovedRequestRecall';
3
+ import RemoteLiveStreamRequestApprove from './controls/RemoteLiveStreamRequestApprove';
4
+ import RemoteLiveStreamRequestReject from './controls/RemoteLiveStreamRequestReject';
5
+ // Local controls
6
+ import LocalRaiseHand from './controls/LocalRaiseHand';
7
+ // Views
8
+ import CurrentLiveStreamRequestsView from './CurrentLiveStreamRequestsView';
9
+ import ApprovedLiveStreamControlsView from './ApprovedLiveStreamControlsView';
10
+
11
+ export {
12
+ RemoteLiveStreamApprovedRequestRecall,
13
+ RemoteLiveStreamRequestApprove,
14
+ RemoteLiveStreamRequestReject,
15
+ LocalRaiseHand,
16
+ CurrentLiveStreamRequestsView,
17
+ ApprovedLiveStreamControlsView,
18
+ };