agora-appbuilder-core 4.0.0-spl.24 → 4.0.0-spl.26
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/package.json +1 -1
- package/template/_package-lock.json +12 -0
- package/template/customization-api/__tests__/module-boundaries.test.js +112 -0
- package/template/customization-api/app-state.ts +3 -4
- package/template/customization-api/core-contexts.ts +10 -0
- package/template/package-lock.json +12 -0
- package/template/package.json +2 -0
- package/template/src/SDKAppWrapper.tsx +11 -1
- package/template/src/app-state/useLocalUserInfo.ts +1 -1
- package/template/src/components/SdkApiContext.tsx +47 -17
- package/template/src/components/chat-messages/useChatMessages.tsx +2 -2
- package/template/src/components/chat-notification/useChatNotification.tsx +1 -1
- package/template/src/components/chat-ui/useChatUIControl.tsx +1 -1
- package/template/src/components/meeting-info/useMeetingInfo.tsx +1 -1
- package/template/src/components/popups/InvitePopup.tsx +9 -2
- package/template/src/components/useUserPreference.tsx +2 -2
- package/template/src/components/useVideoCall.tsx +1 -1
- package/template/src/subComponents/recording/useRecording.tsx +2 -2
- package/template/src/utils/SdkMethodEvents.ts +27 -5
- package/template/src/utils/useGetMeetingPhrase.ts +44 -41
- package/template/src/utils/useLayout.tsx +1 -1
- package/template/src/utils/useSidePanel.tsx +1 -1
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@sentry/react-native": "2.4.3",
|
|
18
18
|
"@sentry/tracing": "6.2.1",
|
|
19
19
|
"@supersami/rn-foreground-service": "^1.1.1",
|
|
20
|
+
"@types/lodash": "^4.17.6",
|
|
20
21
|
"agora-react-native-rtm": "1.5.1",
|
|
21
22
|
"agora-rtc-sdk-ng": "4.16.1",
|
|
22
23
|
"agora-rtm-sdk": "1.5.1",
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
"exponential-backoff": "3.1.0",
|
|
27
28
|
"fetch-retry": "^5.0.6",
|
|
28
29
|
"graphql": "15.5.0",
|
|
30
|
+
"lodash": "^4.17.21",
|
|
29
31
|
"nanoevents": "7.0.1",
|
|
30
32
|
"nanoid": "4.0.0",
|
|
31
33
|
"nosleep.js": "0.12.0",
|
|
@@ -6110,6 +6112,11 @@
|
|
|
6110
6112
|
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
|
6111
6113
|
"dev": true
|
|
6112
6114
|
},
|
|
6115
|
+
"node_modules/@types/lodash": {
|
|
6116
|
+
"version": "4.17.6",
|
|
6117
|
+
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz",
|
|
6118
|
+
"integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA=="
|
|
6119
|
+
},
|
|
6113
6120
|
"node_modules/@types/mime": {
|
|
6114
6121
|
"version": "3.0.1",
|
|
6115
6122
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
|
@@ -34130,6 +34137,11 @@
|
|
|
34130
34137
|
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
|
34131
34138
|
"dev": true
|
|
34132
34139
|
},
|
|
34140
|
+
"@types/lodash": {
|
|
34141
|
+
"version": "4.17.6",
|
|
34142
|
+
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz",
|
|
34143
|
+
"integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA=="
|
|
34144
|
+
},
|
|
34133
34145
|
"@types/mime": {
|
|
34134
34146
|
"version": "3.0.1",
|
|
34135
34147
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const babel = require('@babel/core');
|
|
4
|
+
|
|
5
|
+
const templateRoot = path.resolve(__dirname, '../..');
|
|
6
|
+
|
|
7
|
+
const compile = (relativePath) => {
|
|
8
|
+
const filename = path.join(templateRoot, relativePath);
|
|
9
|
+
|
|
10
|
+
return babel.transformSync(fs.readFileSync(filename, 'utf8'), {
|
|
11
|
+
babelrc: false,
|
|
12
|
+
configFile: false,
|
|
13
|
+
filename,
|
|
14
|
+
presets: [
|
|
15
|
+
'@babel/preset-react',
|
|
16
|
+
[
|
|
17
|
+
'@babel/preset-typescript',
|
|
18
|
+
{
|
|
19
|
+
allExtensions: true,
|
|
20
|
+
isTSX: true,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
'@babel/preset-env',
|
|
25
|
+
{
|
|
26
|
+
targets: {
|
|
27
|
+
node: 'current',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
],
|
|
32
|
+
}).code;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const runtimeDependencies = (compiledCode) =>
|
|
36
|
+
Array.from(compiledCode.matchAll(/require\(["']([^"']+)["']\)/g), (match) =>
|
|
37
|
+
match[1],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
describe('web module boundaries', () => {
|
|
41
|
+
test('SDK method events do not load the DeviceConfigure React component', () => {
|
|
42
|
+
const dependencies = runtimeDependencies(
|
|
43
|
+
compile('src/utils/SdkMethodEvents.ts'),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expect(dependencies).not.toContain('../components/DeviceConfigure');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('customization app state delegates core hook creation to a leaf module', () => {
|
|
50
|
+
const dependencies = runtimeDependencies(
|
|
51
|
+
compile('customization-api/app-state.ts'),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
expect(dependencies).not.toContain('../agora-rn-uikit');
|
|
55
|
+
expect(dependencies).toContain('./core-contexts');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test.each([
|
|
59
|
+
'src/app-state/useLocalUserInfo.ts',
|
|
60
|
+
'src/subComponents/recording/useRecording.tsx',
|
|
61
|
+
'src/components/chat-messages/useChatMessages.tsx',
|
|
62
|
+
'src/components/useUserPreference.tsx',
|
|
63
|
+
])('%s does not load the public customization API barrel', (filename) => {
|
|
64
|
+
const dependencies = runtimeDependencies(compile(filename));
|
|
65
|
+
|
|
66
|
+
expect(dependencies).not.toContain('customization-api');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test.each([
|
|
70
|
+
[
|
|
71
|
+
'src/components/meeting-info/useMeetingInfo.tsx',
|
|
72
|
+
'../../../customization-implementation/createHook',
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
'src/subComponents/recording/useRecording.tsx',
|
|
76
|
+
'../../../customization-implementation/createHook',
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
'src/components/chat-ui/useChatUIControl.tsx',
|
|
80
|
+
'../../../customization-implementation/createHook',
|
|
81
|
+
],
|
|
82
|
+
[
|
|
83
|
+
'src/components/chat-notification/useChatNotification.tsx',
|
|
84
|
+
'../../../customization-implementation/createHook',
|
|
85
|
+
],
|
|
86
|
+
[
|
|
87
|
+
'src/components/chat-messages/useChatMessages.tsx',
|
|
88
|
+
'../../../customization-implementation/createHook',
|
|
89
|
+
],
|
|
90
|
+
[
|
|
91
|
+
'src/components/useUserPreference.tsx',
|
|
92
|
+
'../../customization-implementation/createHook',
|
|
93
|
+
],
|
|
94
|
+
[
|
|
95
|
+
'src/utils/useLayout.tsx',
|
|
96
|
+
'../../customization-implementation/createHook',
|
|
97
|
+
],
|
|
98
|
+
[
|
|
99
|
+
'src/utils/useSidePanel.tsx',
|
|
100
|
+
'../../customization-implementation/createHook',
|
|
101
|
+
],
|
|
102
|
+
])(
|
|
103
|
+
'%s imports createHook without loading the customization implementation barrel',
|
|
104
|
+
(filename, createHookPath) => {
|
|
105
|
+
const dependencies = runtimeDependencies(compile(filename));
|
|
106
|
+
|
|
107
|
+
expect(dependencies).not.toContain('customization-implementation');
|
|
108
|
+
expect(dependencies).toContain(createHookPath);
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core contexts
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import {RtcContext, RenderContext} from '../agora-rn-uikit';
|
|
4
|
+
import {useRtc, useRender} from './core-contexts';
|
|
6
5
|
|
|
7
6
|
// commented for v1 release
|
|
8
7
|
//import {default as DeviceContext} from '../src/components/DeviceContext';
|
|
@@ -10,11 +9,11 @@ import {RtcContext, RenderContext} from '../agora-rn-uikit';
|
|
|
10
9
|
/**
|
|
11
10
|
* The RTC app state exposes the internal RtcEngine object as well as dispatch interface to perform various actions.
|
|
12
11
|
*/
|
|
13
|
-
export
|
|
12
|
+
export {useRtc};
|
|
14
13
|
/**
|
|
15
14
|
* The Render app state governs the information necessary to render each user content view displayed in the videocall screen.
|
|
16
15
|
*/
|
|
17
|
-
export
|
|
16
|
+
export {useRender};
|
|
18
17
|
|
|
19
18
|
export {useLocalUserInfo} from '../src/app-state/useLocalUserInfo';
|
|
20
19
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import createHook from '../customization-implementation/createHook';
|
|
2
|
+
import RtcContext from '../agora-rn-uikit/src/Contexts/RtcContext';
|
|
3
|
+
import RenderContext from '../agora-rn-uikit/src/Contexts/RenderContext';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Core hooks live in a dependency-free module so internal application code can
|
|
7
|
+
* consume them without evaluating the public customization API barrel.
|
|
8
|
+
*/
|
|
9
|
+
export const useRtc = createHook(RtcContext);
|
|
10
|
+
export const useRender = createHook(RenderContext);
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@sentry/react-native": "2.4.3",
|
|
18
18
|
"@sentry/tracing": "6.2.1",
|
|
19
19
|
"@supersami/rn-foreground-service": "^1.1.1",
|
|
20
|
+
"@types/lodash": "^4.17.6",
|
|
20
21
|
"agora-react-native-rtm": "1.5.1",
|
|
21
22
|
"agora-rtc-sdk-ng": "4.16.1",
|
|
22
23
|
"agora-rtm-sdk": "1.5.1",
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
"exponential-backoff": "3.1.0",
|
|
27
28
|
"fetch-retry": "^5.0.6",
|
|
28
29
|
"graphql": "15.5.0",
|
|
30
|
+
"lodash": "^4.17.21",
|
|
29
31
|
"nanoevents": "7.0.1",
|
|
30
32
|
"nanoid": "4.0.0",
|
|
31
33
|
"nosleep.js": "0.12.0",
|
|
@@ -6110,6 +6112,11 @@
|
|
|
6110
6112
|
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
|
6111
6113
|
"dev": true
|
|
6112
6114
|
},
|
|
6115
|
+
"node_modules/@types/lodash": {
|
|
6116
|
+
"version": "4.17.6",
|
|
6117
|
+
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz",
|
|
6118
|
+
"integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA=="
|
|
6119
|
+
},
|
|
6113
6120
|
"node_modules/@types/mime": {
|
|
6114
6121
|
"version": "3.0.1",
|
|
6115
6122
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
|
@@ -34130,6 +34137,11 @@
|
|
|
34130
34137
|
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
|
34131
34138
|
"dev": true
|
|
34132
34139
|
},
|
|
34140
|
+
"@types/lodash": {
|
|
34141
|
+
"version": "4.17.6",
|
|
34142
|
+
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz",
|
|
34143
|
+
"integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA=="
|
|
34144
|
+
},
|
|
34133
34145
|
"@types/mime": {
|
|
34134
34146
|
"version": "3.0.1",
|
|
34135
34147
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
package/template/package.json
CHANGED
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"@sentry/react-native": "2.4.3",
|
|
58
58
|
"@sentry/tracing": "6.2.1",
|
|
59
59
|
"@supersami/rn-foreground-service": "^1.1.1",
|
|
60
|
+
"@types/lodash": "^4.17.6",
|
|
60
61
|
"agora-react-native-rtm": "1.5.1",
|
|
61
62
|
"agora-rtc-sdk-ng": "4.16.1",
|
|
62
63
|
"agora-rtm-sdk": "1.5.1",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"exponential-backoff": "3.1.0",
|
|
67
68
|
"fetch-retry": "^5.0.6",
|
|
68
69
|
"graphql": "15.5.0",
|
|
70
|
+
"lodash": "^4.17.21",
|
|
69
71
|
"nanoevents": "7.0.1",
|
|
70
72
|
"nanoid": "4.0.0",
|
|
71
73
|
"nosleep.js": "0.12.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, {useEffect} from 'react';
|
|
2
2
|
import {
|
|
3
3
|
CustomizationApiInterface,
|
|
4
4
|
customize,
|
|
@@ -39,6 +39,7 @@ export interface AppBuilderSdkApiInterface {
|
|
|
39
39
|
createCustomization: (
|
|
40
40
|
customization: CustomizationApiInterface,
|
|
41
41
|
) => CustomizationApiInterface;
|
|
42
|
+
clearState: (stateKey: 'join' | 'all') => Promise<void>;
|
|
42
43
|
customEvents: typeof customEvents;
|
|
43
44
|
on: <T extends keyof userEventsMapInterface>(
|
|
44
45
|
userEventName: T,
|
|
@@ -81,6 +82,15 @@ export const AppBuilderSdkApi: AppBuilderSdkApiInterface = {
|
|
|
81
82
|
muteVideo: async (state) => {
|
|
82
83
|
return await SDKMethodEventsManager.emit('muteVideo', state);
|
|
83
84
|
},
|
|
85
|
+
clearState: async (stateKey) => {
|
|
86
|
+
switch (stateKey) {
|
|
87
|
+
case 'all':
|
|
88
|
+
case 'join':
|
|
89
|
+
return await SDKMethodEventsManager.emit('clearState', stateKey);
|
|
90
|
+
default:
|
|
91
|
+
throw new Error('Invalid identifier');
|
|
92
|
+
}
|
|
93
|
+
},
|
|
84
94
|
createCustomization: customize,
|
|
85
95
|
on: (userEventName, cb) => {
|
|
86
96
|
console.log('SDKEvents: Event Registered', userEventName);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {useLocalUid} from '../../agora-rn-uikit';
|
|
2
|
-
import {useRender} from 'customization-api';
|
|
2
|
+
import {useRender} from '../../customization-api/core-contexts';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The LocalUserInfo app state contains the local user information like uid, audio and video mute states etc.
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from './meeting-info/useMeetingInfo';
|
|
9
9
|
import {CustomizationApiInterface} from 'customization-api';
|
|
10
10
|
import {Unsubscribe} from 'nanoevents';
|
|
11
|
+
import {cloneDeep} from 'lodash';
|
|
11
12
|
|
|
12
13
|
type extractPromises<T extends (...p: any) => any> = {
|
|
13
14
|
res: Parameters<T>[0];
|
|
@@ -57,8 +58,8 @@ type SdkApiContextInterface = {
|
|
|
57
58
|
onMuteAudio: (callback: _InternalSDKMethodEventsMap['muteAudio']) => void;
|
|
58
59
|
onMuteVideo: (callback: _InternalSDKMethodEventsMap['muteVideo']) => void;
|
|
59
60
|
clearState: (
|
|
60
|
-
key: keyof _InternalSDKMethodEventsMap | 'enterRoom',
|
|
61
|
-
|
|
61
|
+
key: keyof _InternalSDKMethodEventsMap | 'enterRoom' | 'all',
|
|
62
|
+
hard?: boolean,
|
|
62
63
|
) => void;
|
|
63
64
|
};
|
|
64
65
|
|
|
@@ -80,7 +81,7 @@ const defaultMuteAllParticipantsListener = ((res, _, param) => {
|
|
|
80
81
|
res();
|
|
81
82
|
}) as _InternalSDKMethodEventsMap['muteAllParticipants'];
|
|
82
83
|
|
|
83
|
-
const
|
|
84
|
+
const SdkApiDefaultState: SdkApiContextInterface = {
|
|
84
85
|
enterRoom: {
|
|
85
86
|
set: () => {},
|
|
86
87
|
},
|
|
@@ -100,6 +101,19 @@ const SdkApiInitState: SdkApiContextInterface = {
|
|
|
100
101
|
onMuteAudio: (_) => {},
|
|
101
102
|
clearState: () => {},
|
|
102
103
|
};
|
|
104
|
+
const SdkApiInitState: SdkApiContextInterface = cloneDeep(SdkApiDefaultState);
|
|
105
|
+
|
|
106
|
+
export const clearStateGlobal = (
|
|
107
|
+
state: keyof SdkApiContextInterface | 'all',
|
|
108
|
+
) => {
|
|
109
|
+
if (state === 'all') {
|
|
110
|
+
for (const key in SdkApiInitState)
|
|
111
|
+
SdkApiInitState[key] = cloneDeep(SdkApiDefaultState[key]);
|
|
112
|
+
} else {
|
|
113
|
+
//@ts-expect-error
|
|
114
|
+
SdkApiInitState[state] = cloneDeep(SdkApiDefaultState[state]);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
103
117
|
|
|
104
118
|
export const READ_ONLY_SdkApiInitState = SdkApiInitState;
|
|
105
119
|
|
|
@@ -111,9 +125,10 @@ export const SdkApiContext =
|
|
|
111
125
|
let moduleEventsUnsub: any[] = [];
|
|
112
126
|
|
|
113
127
|
type commonEventHandlers = {
|
|
114
|
-
[K in keyof Omit<
|
|
115
|
-
|
|
116
|
-
|
|
128
|
+
[K in keyof Omit<
|
|
129
|
+
_InternalSDKMethodEventsMap,
|
|
130
|
+
'muteVideo' | 'muteAudio' | 'flushQueue'
|
|
131
|
+
>]?: (setter: (p: SdkApiContextInterface[K]) => void) => Unsubscribe;
|
|
117
132
|
};
|
|
118
133
|
|
|
119
134
|
const commonEventHandlers: commonEventHandlers = {
|
|
@@ -209,6 +224,10 @@ const registerListener = () => {
|
|
|
209
224
|
),
|
|
210
225
|
SDKMethodEventsManager.on('muteVideo', defaultMuteListener),
|
|
211
226
|
SDKMethodEventsManager.on('muteAudio', defaultMuteListener),
|
|
227
|
+
SDKMethodEventsManager.on('clearState', (res, _, queue) => {
|
|
228
|
+
clearStateGlobal(queue);
|
|
229
|
+
res();
|
|
230
|
+
}),
|
|
212
231
|
];
|
|
213
232
|
};
|
|
214
233
|
|
|
@@ -261,26 +280,31 @@ const SdkApiContextProvider: React.FC = (props) => {
|
|
|
261
280
|
muteAudioListener.current = value;
|
|
262
281
|
};
|
|
263
282
|
|
|
264
|
-
const clearState: SdkApiContextInterface['clearState'] = (key) => {
|
|
283
|
+
const clearState: SdkApiContextInterface['clearState'] = (key, hard) => {
|
|
284
|
+
let fallthrough = false;
|
|
265
285
|
switch (key) {
|
|
286
|
+
case 'all':
|
|
287
|
+
fallthrough = true;
|
|
266
288
|
case 'join':
|
|
267
|
-
setJoinState(SdkApiInitState.join);
|
|
268
|
-
break;
|
|
289
|
+
setJoinState(hard ? SdkApiDefaultState.join : SdkApiInitState.join);
|
|
290
|
+
if (!fallthrough) break;
|
|
269
291
|
case 'enterRoom':
|
|
270
292
|
setEnterRoom(null);
|
|
271
|
-
break;
|
|
293
|
+
if (!fallthrough) break;
|
|
272
294
|
case 'customize':
|
|
273
|
-
setUserCustomization(
|
|
274
|
-
|
|
295
|
+
setUserCustomization(
|
|
296
|
+
hard ? SdkApiDefaultState.customize : SdkApiInitState.customize,
|
|
297
|
+
);
|
|
298
|
+
if (!fallthrough) break;
|
|
275
299
|
case 'microphoneDevice':
|
|
276
300
|
setMicrophoneDeviceState({});
|
|
277
|
-
break;
|
|
301
|
+
if (!fallthrough) break;
|
|
278
302
|
case 'speakerDevice':
|
|
279
303
|
setSpeakerDeviceState({});
|
|
280
|
-
break;
|
|
304
|
+
if (!fallthrough) break;
|
|
281
305
|
case 'cameraDevice':
|
|
282
306
|
setCameraDeviceState({});
|
|
283
|
-
break;
|
|
307
|
+
if (!fallthrough) break;
|
|
284
308
|
case 'muteAllParticipants':
|
|
285
309
|
setMuteAllParticipantsState((current) => {
|
|
286
310
|
return {
|
|
@@ -288,12 +312,13 @@ const SdkApiContextProvider: React.FC = (props) => {
|
|
|
288
312
|
promise: undefined,
|
|
289
313
|
};
|
|
290
314
|
});
|
|
315
|
+
if (!fallthrough) break;
|
|
291
316
|
case 'muteVideo':
|
|
292
317
|
setMuteVideoListener(defaultMuteListener);
|
|
293
|
-
break;
|
|
318
|
+
if (!fallthrough) break;
|
|
294
319
|
case 'muteAudio':
|
|
295
320
|
setMuteVideoListener(defaultMuteListener);
|
|
296
|
-
break;
|
|
321
|
+
if (!fallthrough) break;
|
|
297
322
|
}
|
|
298
323
|
};
|
|
299
324
|
|
|
@@ -353,6 +378,11 @@ const SdkApiContextProvider: React.FC = (props) => {
|
|
|
353
378
|
SDKMethodEventsManager.on('muteAudio', (...args) => {
|
|
354
379
|
muteAudioListener.current(...args);
|
|
355
380
|
}),
|
|
381
|
+
SDKMethodEventsManager.on('clearState', (res, _, queue) => {
|
|
382
|
+
clearStateGlobal(queue);
|
|
383
|
+
clearState(queue, true);
|
|
384
|
+
res();
|
|
385
|
+
}),
|
|
356
386
|
];
|
|
357
387
|
|
|
358
388
|
return () => {
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
information visit https://appbuilder.agora.io.
|
|
10
10
|
*********************************************
|
|
11
11
|
*/
|
|
12
|
-
import
|
|
12
|
+
import createHook from '../../../customization-implementation/createHook';
|
|
13
13
|
import React, {useState, useEffect, useRef} from 'react';
|
|
14
|
-
import {useRender, useRtc} from 'customization-api';
|
|
14
|
+
import {useRender, useRtc} from '../../../customization-api/core-contexts';
|
|
15
15
|
import {SidePanelType} from '../../subComponents/SidePanelEnum';
|
|
16
16
|
import {useLocalUid, UidType, RenderInterface} from '../../../agora-rn-uikit';
|
|
17
17
|
import events, {EventPersistLevel} from '../../rtm-events-api';
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
information visit https://appbuilder.agora.io.
|
|
10
10
|
*********************************************
|
|
11
11
|
*/
|
|
12
|
-
import
|
|
12
|
+
import createHook from '../../../customization-implementation/createHook';
|
|
13
13
|
import React, {SetStateAction, useState, useEffect} from 'react';
|
|
14
14
|
|
|
15
15
|
export interface individualUnreadMessageCount {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
information visit https://appbuilder.agora.io.
|
|
10
10
|
*********************************************
|
|
11
11
|
*/
|
|
12
|
-
import
|
|
12
|
+
import createHook from '../../../customization-implementation/createHook';
|
|
13
13
|
import React, {SetStateAction, useState} from 'react';
|
|
14
14
|
import {UidType} from '../../../agora-rn-uikit';
|
|
15
15
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*********************************************
|
|
11
11
|
*/
|
|
12
12
|
import React, {createContext} from 'react';
|
|
13
|
-
import
|
|
13
|
+
import createHook from '../../../customization-implementation/createHook';
|
|
14
14
|
import {UidType} from '../../../agora-rn-uikit';
|
|
15
15
|
export interface MeetingInfoContextInterface {
|
|
16
16
|
isJoinDataFetched?: boolean;
|
|
@@ -25,6 +25,7 @@ import {isMobileUA, useIsDesktop} from '../../utils/common';
|
|
|
25
25
|
import {useVideoCall} from '../useVideoCall';
|
|
26
26
|
import {useParams} from '../Router';
|
|
27
27
|
import useGetMeetingPhrase from '../../utils/useGetMeetingPhrase';
|
|
28
|
+
import {SDK_MEETING_TAG} from '../SdkApiContext';
|
|
28
29
|
|
|
29
30
|
const InvitePopup = () => {
|
|
30
31
|
const {setShowInvitePopup, showInvitePopup} = useVideoCall();
|
|
@@ -33,8 +34,14 @@ const InvitePopup = () => {
|
|
|
33
34
|
const {phrase} = useParams<{phrase: string}>();
|
|
34
35
|
const getMeeting = useGetMeetingPhrase();
|
|
35
36
|
useEffect(() => {
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
if (!phrase || phrase === SDK_MEETING_TAG) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getMeeting(phrase).catch((error) => {
|
|
42
|
+
console.error('Unable to load invite information', error);
|
|
43
|
+
});
|
|
44
|
+
}, [getMeeting, phrase]);
|
|
38
45
|
return (
|
|
39
46
|
<Popup
|
|
40
47
|
modalVisible={showInvitePopup}
|
|
@@ -16,9 +16,9 @@ import StorageContext from './StorageContext';
|
|
|
16
16
|
import events, {EventPersistLevel} from '../rtm-events-api';
|
|
17
17
|
import {EventNames} from '../rtm-events';
|
|
18
18
|
import useLocalScreenShareUid from '../utils/useLocalShareScreenUid';
|
|
19
|
-
import
|
|
19
|
+
import createHook from '../../customization-implementation/createHook';
|
|
20
20
|
import ChatContext from './ChatContext';
|
|
21
|
-
import {useRtc} from 'customization-api';
|
|
21
|
+
import {useRtc} from '../../customization-api/core-contexts';
|
|
22
22
|
|
|
23
23
|
interface UserPreferenceContextInterface {
|
|
24
24
|
displayName: string;
|
|
@@ -21,14 +21,14 @@ import {gql, useMutation} from '@apollo/client';
|
|
|
21
21
|
import {useParams} from '../../components/Router';
|
|
22
22
|
import {PropsContext} from '../../../agora-rn-uikit';
|
|
23
23
|
import Toast from '../../../react-native-toast-message';
|
|
24
|
-
import
|
|
24
|
+
import createHook from '../../../customization-implementation/createHook';
|
|
25
25
|
import {useString} from '../../utils/useString';
|
|
26
26
|
import ChatContext from '../../components/ChatContext';
|
|
27
27
|
import events, {EventPersistLevel} from '../../rtm-events-api';
|
|
28
28
|
import {EventActions, EventNames} from '../../rtm-events';
|
|
29
29
|
import useRecordingLayoutQuery from './useRecordingLayoutQuery';
|
|
30
30
|
import {useScreenContext} from '../../components/contexts/ScreenShareContext';
|
|
31
|
-
import {useRender} from 'customization-api';
|
|
31
|
+
import {useRender} from '../../../customization-api/core-contexts';
|
|
32
32
|
import {trimText} from '../../utils/common';
|
|
33
33
|
|
|
34
34
|
export interface RecordingContextInterface {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {createNanoEvents, Emitter} from 'nanoevents';
|
|
2
|
-
import {
|
|
2
|
+
import type {
|
|
3
3
|
CustomizationApiInterface,
|
|
4
4
|
MeetingInfoContextInterface,
|
|
5
5
|
} from 'customization-api';
|
|
6
|
-
import {deviceId} from '../components/DeviceConfigure';
|
|
6
|
+
import type {deviceId} from '../components/DeviceConfigure';
|
|
7
7
|
|
|
8
8
|
export interface SdkMethodEvents {
|
|
9
9
|
customize: (customization: CustomizationApiInterface) => void;
|
|
@@ -14,9 +14,12 @@ export interface SdkMethodEvents {
|
|
|
14
14
|
microphoneDevice: (deviceId: deviceId) => void;
|
|
15
15
|
speakerDevice: (deviceId: deviceId) => void;
|
|
16
16
|
cameraDevice: (deviceId: deviceId) => void;
|
|
17
|
-
muteAllParticipants: (
|
|
17
|
+
muteAllParticipants: (
|
|
18
|
+
mute: boolean | ((currentMute: boolean) => boolean),
|
|
19
|
+
) => void;
|
|
18
20
|
muteAudio: (mute: boolean | ((currentMute: boolean) => boolean)) => void;
|
|
19
21
|
muteVideo: (mute: boolean | ((currentMute: boolean) => boolean)) => void;
|
|
22
|
+
clearState: (state: 'join' | 'all') => void;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
type EventParameterHelper<T extends keyof SdkMethodEvents> = Parameters<
|
|
@@ -61,8 +64,22 @@ class SDKMethodEvents {
|
|
|
61
64
|
event: T,
|
|
62
65
|
...params: EventParameterHelper<T>
|
|
63
66
|
) {
|
|
64
|
-
if (
|
|
65
|
-
|
|
67
|
+
if (event === 'clearState') {
|
|
68
|
+
const param = params[0];
|
|
69
|
+
switch (param) {
|
|
70
|
+
case 'join':
|
|
71
|
+
case 'clearState':
|
|
72
|
+
delete this.emitCache[param];
|
|
73
|
+
delete this.emitCacheDisabled[param];
|
|
74
|
+
break;
|
|
75
|
+
case 'all':
|
|
76
|
+
this.reset();
|
|
77
|
+
default:
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
if (this.emitCache[event]) {
|
|
81
|
+
throw new Error(`Event: ${event} already in callstack`);
|
|
82
|
+
}
|
|
66
83
|
}
|
|
67
84
|
|
|
68
85
|
const result = await new Promise<EventReturnTypeHelper<T>>((res, rej) => {
|
|
@@ -92,6 +109,11 @@ class SDKMethodEvents {
|
|
|
92
109
|
this.emitCacheDisabled[event] = true;
|
|
93
110
|
return unsub;
|
|
94
111
|
}
|
|
112
|
+
|
|
113
|
+
reset() {
|
|
114
|
+
this.emitCache = {};
|
|
115
|
+
this.emitCacheDisabled = {};
|
|
116
|
+
}
|
|
95
117
|
}
|
|
96
118
|
|
|
97
119
|
const SDKMethodEventsManager = new SDKMethodEvents();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {useContext} from 'react';
|
|
1
|
+
import {useCallback, useContext} from 'react';
|
|
2
2
|
import {gql} from '@apollo/client';
|
|
3
3
|
import {MeetingInfoContextInterface} from '../components/meeting-info/useMeetingInfo';
|
|
4
4
|
import {useSetMeetingInfo} from '../components/meeting-info/useSetMeetingInfo';
|
|
@@ -24,48 +24,51 @@ const SHARE = gql`
|
|
|
24
24
|
export default function useGetMeetingPhrase() {
|
|
25
25
|
const {setMeetingInfo} = useSetMeetingInfo();
|
|
26
26
|
const {client} = useContext(GraphQLContext);
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
query
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (data?.share?.passphrase?.view) {
|
|
44
|
-
meetingInfo.roomId.attendee = data.share.passphrase.view;
|
|
45
|
-
}
|
|
46
|
-
if (data?.share?.passphrase?.host) {
|
|
47
|
-
meetingInfo.roomId.host = data.share.passphrase.host;
|
|
48
|
-
}
|
|
49
|
-
if (data?.share?.pstn) {
|
|
50
|
-
meetingInfo.pstn = {
|
|
51
|
-
number: data.share.pstn.number,
|
|
52
|
-
pin: data.share.pstn.dtmf,
|
|
27
|
+
return useCallback(
|
|
28
|
+
async (phrase: string) => {
|
|
29
|
+
const response = await client.query({
|
|
30
|
+
query: SHARE,
|
|
31
|
+
variables: {
|
|
32
|
+
passphrase: phrase,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
if (response.error) {
|
|
36
|
+
throw response.error;
|
|
37
|
+
} else {
|
|
38
|
+
try {
|
|
39
|
+
if (response && response.data) {
|
|
40
|
+
let data = response.data;
|
|
41
|
+
let meetingInfo: Partial<MeetingInfoContextInterface['data']> = {
|
|
42
|
+
roomId: {attendee: ''},
|
|
53
43
|
};
|
|
44
|
+
if (data?.share?.passphrase?.view) {
|
|
45
|
+
meetingInfo.roomId.attendee = data.share.passphrase.view;
|
|
46
|
+
}
|
|
47
|
+
if (data?.share?.passphrase?.host) {
|
|
48
|
+
meetingInfo.roomId.host = data.share.passphrase.host;
|
|
49
|
+
}
|
|
50
|
+
if (data?.share?.pstn) {
|
|
51
|
+
meetingInfo.pstn = {
|
|
52
|
+
number: data.share.pstn.number,
|
|
53
|
+
pin: data.share.pstn.dtmf,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
setMeetingInfo((prevState) => {
|
|
57
|
+
return {
|
|
58
|
+
...prevState,
|
|
59
|
+
data: {
|
|
60
|
+
...prevState.data,
|
|
61
|
+
roomId: meetingInfo.roomId,
|
|
62
|
+
pstn: meetingInfo?.pstn,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
});
|
|
54
66
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
...prevState,
|
|
58
|
-
data: {
|
|
59
|
-
...prevState.data,
|
|
60
|
-
roomId: meetingInfo.roomId,
|
|
61
|
-
pstn: meetingInfo?.pstn,
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
});
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw new Error('An error occurred in parsing the channel data.');
|
|
65
69
|
}
|
|
66
|
-
} catch (error) {
|
|
67
|
-
throw new Error('An error occurred in parsing the channel data.');
|
|
68
70
|
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
+
},
|
|
72
|
+
[client, setMeetingInfo],
|
|
73
|
+
);
|
|
71
74
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import React, {SetStateAction} from 'react';
|
|
14
|
-
import
|
|
14
|
+
import createHook from '../../customization-implementation/createHook';
|
|
15
15
|
|
|
16
16
|
export interface LayoutContextInterface {
|
|
17
17
|
currentLayout: string;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import React, {SetStateAction} from 'react';
|
|
14
14
|
import {SidePanelType} from '../subComponents/SidePanelEnum';
|
|
15
|
-
import
|
|
15
|
+
import createHook from '../../customization-implementation/createHook';
|
|
16
16
|
|
|
17
17
|
export interface SidePanelContextInterface {
|
|
18
18
|
sidePanel: SidePanelType;
|