agora-appbuilder-core 4.1.29 → 4.1.30-beta.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.
- package/Readme.md +2 -0
- package/package.json +1 -1
- package/template/Gulpfile.js +34 -0
- package/template/_package-lock.json +2491 -3084
- package/template/android/app/build.gradle +33 -23
- package/template/android/app/src/main/AndroidManifest.xml +5 -3
- package/template/android/app/src/main/java/com/helloworld/MainApplication.java +14 -2
- package/template/android/build.gradle +42 -7
- package/template/android/gradle/wrapper/gradle-wrapper.properties +3 -3
- package/template/android/gradle.properties +0 -3
- package/template/android/settings.gradle +4 -2
- package/template/babel.config.js +1 -1
- package/template/defaultConfig.js +2 -2
- package/template/ios/HelloWorld.xcodeproj/project.pbxproj +8 -6
- package/template/ios/Podfile +3 -45
- package/template/ios/Podfile.lock +1806 -524
- package/template/metro.config.js +6 -1
- package/template/package.json +28 -20
- package/template/patches/@supersami+rn-foreground-service+1.1.1.patch +12 -0
- package/template/scripts/verify-android-native-libs.py +106 -0
- package/template/src/AppWrapper.tsx +2 -7
- package/template/src/atoms/Carousel.native.tsx +22 -5
- package/template/src/atoms/CustomSwitch.tsx +0 -1
- package/template/src/atoms/Dropdown.tsx +0 -1
- package/template/src/atoms/MeetingLink.tsx +5 -12
- package/template/src/atoms/Popup.tsx +26 -2
- package/template/src/components/AppSafeAreaView.android.tsx +15 -0
- package/template/src/components/AppSafeAreaView.tsx +1 -0
- package/template/src/components/Precall.native.tsx +40 -10
- package/template/src/components/Share.tsx +27 -6
- package/template/src/components/meeting-info-invite/MeetingInfo.tsx +21 -3
- package/template/src/components/meeting-info-invite/MeetingInfoGridTile.tsx +11 -2
- package/template/src/components/useVideoCall.tsx +35 -1
- package/template/src/language/default-labels/joinScreenLabels.ts +2 -2
- package/template/src/pages/Create.tsx +26 -3
- package/template/src/pages/video-call/ActionSheet.native.tsx +11 -11
- package/template/src/pages/video-call/VideoCallScreen.native.tsx +34 -5
- package/template/src/pages/video-call/__tests__/VideoCallScreen.native.test.tsx +95 -0
- package/template/src/subComponents/Clipboard.native.tsx +1 -1
- package/template/src/subComponents/caption/CaptionIcon.tsx +11 -14
- package/template/src/subComponents/caption/TranscriptIcon.tsx +10 -14
- package/template/src/utils/useIsTablet.ts +10 -0
- package/template/android/app/src/debug/java/com/helloworld/ReactNativeFlipper.java +0 -75
- package/template/android/app/src/release/java/com/helloworld/ReactNativeFlipper.java +0 -20
package/template/metro.config.js
CHANGED
|
@@ -6,6 +6,11 @@ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
|
|
|
6
6
|
*
|
|
7
7
|
* @type {import('metro-config').MetroConfig}
|
|
8
8
|
*/
|
|
9
|
-
const config = {
|
|
9
|
+
const config = {
|
|
10
|
+
resolver: {
|
|
11
|
+
// CI builds should not depend on a running Watchman service.
|
|
12
|
+
useWatchman: process.env.CI !== 'true',
|
|
13
|
+
},
|
|
14
|
+
};
|
|
10
15
|
|
|
11
16
|
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
|
package/template/package.json
CHANGED
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
"android:build": "npm run android:build:unix",
|
|
9
9
|
"android:build:unix": "cross-env TARGET=android gulp androidUnix",
|
|
10
10
|
"android:build:windows": "cross-env TARGET=android gulp androidWin",
|
|
11
|
+
"android:bundle": "npm run android:bundle:unix",
|
|
12
|
+
"android:bundle:unix": "cross-env TARGET=android gulp androidBundleUnix",
|
|
13
|
+
"android:bundle:windows": "cross-env TARGET=android gulp androidBundleWin",
|
|
11
14
|
"ios": "cd ios && ls | grep .xcworkspace | xargs open",
|
|
12
15
|
"ios:build": "cd ios && ls | grep .xcworkspace | xargs open",
|
|
13
16
|
"start": "react-native start",
|
|
@@ -34,7 +37,8 @@
|
|
|
34
37
|
"package:mac": "npm run mac:build && electron-builder --publish=always",
|
|
35
38
|
"release": "electron-builder --mac --windows --linux --publish always --config ./electron-builder.js ",
|
|
36
39
|
"make-rsdk-ts-defs": "cross-env TARGET=rsdk NODE_ENV=production gulp makeRsdkTsDefs",
|
|
37
|
-
"make-wsdk-ts-defs": "cross-env TARGET=wsdk NODE_ENV=production gulp makeWsdkTsDefs"
|
|
40
|
+
"make-wsdk-ts-defs": "cross-env TARGET=wsdk NODE_ENV=production gulp makeWsdkTsDefs",
|
|
41
|
+
"postinstall": "patch-package --error-on-fail"
|
|
38
42
|
},
|
|
39
43
|
"publish": [
|
|
40
44
|
{
|
|
@@ -54,10 +58,10 @@
|
|
|
54
58
|
"@netless/react-native-whiteboard": "^0.0.14",
|
|
55
59
|
"@openspacelabs/react-native-zoomable-view": "^2.1.1",
|
|
56
60
|
"@react-native-async-storage/async-storage": "1.19.2",
|
|
61
|
+
"@react-native-clipboard/clipboard": "1.16.3",
|
|
57
62
|
"@react-native-community/checkbox": "0.5.16",
|
|
58
|
-
"@react-native-community/clipboard": "1.5.1",
|
|
59
63
|
"@splinetool/runtime": "^1.9.69",
|
|
60
|
-
"@supersami/rn-foreground-service": "
|
|
64
|
+
"@supersami/rn-foreground-service": "1.1.1",
|
|
61
65
|
"add": "^2.0.6",
|
|
62
66
|
"agora-agent-client-toolkit": "2.9.0",
|
|
63
67
|
"agora-chat": "1.2.2-3",
|
|
@@ -84,29 +88,30 @@
|
|
|
84
88
|
"npm": "^9.7.2",
|
|
85
89
|
"p-queue": "^7.3.4",
|
|
86
90
|
"protobufjs": "^7.2.5",
|
|
87
|
-
"react": "18.
|
|
88
|
-
"react-dom": "18.
|
|
91
|
+
"react": "18.3.1",
|
|
92
|
+
"react-dom": "18.3.1",
|
|
89
93
|
"react-is": "18.0.0",
|
|
90
|
-
"react-native": "0.
|
|
94
|
+
"react-native": "0.77.3",
|
|
91
95
|
"react-native-agora": "4.6.4",
|
|
92
|
-
"react-native-agora-chat": "1.
|
|
96
|
+
"react-native-agora-chat": "1.4.1",
|
|
93
97
|
"react-native-document-picker": "^9.1.0",
|
|
94
98
|
"react-native-exit-app": "1.1.0",
|
|
95
99
|
"react-native-fs": "^2.20.0",
|
|
96
|
-
"react-native-gesture-handler": "2.
|
|
100
|
+
"react-native-gesture-handler": "2.25.0",
|
|
97
101
|
"react-native-get-random-values": "^1.11.0",
|
|
98
102
|
"react-native-hyperlink": "0.0.19",
|
|
99
103
|
"react-native-inappbrowser-reborn": "3.5.1",
|
|
100
104
|
"react-native-keep-awake": "4.0.0",
|
|
101
105
|
"react-native-keyboard-manager": "6.5.4-1",
|
|
102
|
-
"react-native-reanimated": "3.
|
|
106
|
+
"react-native-reanimated": "3.17.5",
|
|
103
107
|
"react-native-responsive-fontsize": "0.5.1",
|
|
108
|
+
"react-native-safe-area-context": "5.4.0",
|
|
104
109
|
"react-native-share": "10.0.2",
|
|
105
|
-
"react-native-svg": "
|
|
110
|
+
"react-native-svg": "15.11.2",
|
|
106
111
|
"react-native-vector-icons": "9.2.0",
|
|
107
112
|
"react-native-walkthrough-tooltip": "1.4.0",
|
|
108
113
|
"react-native-web": "0.19.7",
|
|
109
|
-
"react-native-webview": "13.
|
|
114
|
+
"react-native-webview": "13.13.5",
|
|
110
115
|
"react-router-dom": "5.2.0",
|
|
111
116
|
"react-router-native": "5.2.0",
|
|
112
117
|
"react-spring-bottom-sheet": "3.4.1",
|
|
@@ -117,24 +122,27 @@
|
|
|
117
122
|
"white-web-sdk": "2.16.42"
|
|
118
123
|
},
|
|
119
124
|
"devDependencies": {
|
|
120
|
-
"@babel/core": "^7.
|
|
125
|
+
"@babel/core": "^7.25.2",
|
|
121
126
|
"@babel/plugin-proposal-class-properties": "7.14.5",
|
|
122
127
|
"@babel/plugin-proposal-optional-chaining": "7.16.0",
|
|
123
128
|
"@babel/preset-env": "^7.20.0",
|
|
124
129
|
"@babel/preset-react": "7.13.13",
|
|
125
130
|
"@babel/preset-typescript": "7.13.0",
|
|
126
|
-
"@babel/runtime": "^7.
|
|
131
|
+
"@babel/runtime": "^7.25.0",
|
|
127
132
|
"@bam.tech/react-native-make": "3.0.3",
|
|
128
133
|
"@pmmmwh/react-refresh-webpack-plugin": "0.5.5",
|
|
134
|
+
"@react-native-community/cli": "15.0.1",
|
|
135
|
+
"@react-native-community/cli-platform-android": "15.0.1",
|
|
136
|
+
"@react-native-community/cli-platform-ios": "15.0.1",
|
|
129
137
|
"@react-native-community/eslint-config": "1.1.0",
|
|
130
|
-
"@react-native/
|
|
131
|
-
"@react-native/
|
|
138
|
+
"@react-native/babel-preset": "0.77.3",
|
|
139
|
+
"@react-native/eslint-config": "0.77.3",
|
|
140
|
+
"@react-native/metro-config": "0.77.3",
|
|
132
141
|
"@tsconfig/react-native": "^3.0.0",
|
|
133
142
|
"@types/hark": "^1.2.2",
|
|
134
143
|
"@types/jest": "25.2.3",
|
|
135
|
-
"@types/react": "
|
|
144
|
+
"@types/react": "^18.3.1",
|
|
136
145
|
"@types/react-is": "17.0.3",
|
|
137
|
-
"@types/react-native": "0.67.6",
|
|
138
146
|
"@types/react-native-keep-awake": "2.0.2",
|
|
139
147
|
"@types/react-router-dom": "5.1.7",
|
|
140
148
|
"@types/react-router-native": "5.1.0",
|
|
@@ -162,12 +170,12 @@
|
|
|
162
170
|
"html-webpack-plugin": "4.5.2",
|
|
163
171
|
"ignore-loader": "^0.1.2",
|
|
164
172
|
"jest": "^29.2.1",
|
|
165
|
-
"
|
|
173
|
+
"patch-package": "8.0.0",
|
|
166
174
|
"prettier": "^2.4.1",
|
|
167
175
|
"react-devtools-electron": "4.7.0",
|
|
168
176
|
"react-native-url-polyfill": "^2.0.0",
|
|
169
177
|
"react-refresh": "0.12.0",
|
|
170
|
-
"react-test-renderer": "18.
|
|
178
|
+
"react-test-renderer": "18.3.1",
|
|
171
179
|
"style-loader": "3.3.1",
|
|
172
180
|
"ts-loader": "^8.3.0",
|
|
173
181
|
"typescript": "4.8.4",
|
|
@@ -180,7 +188,7 @@
|
|
|
180
188
|
},
|
|
181
189
|
"overrides": {
|
|
182
190
|
"@netless/react-native-whiteboard": {
|
|
183
|
-
"react-native-webview": "13.
|
|
191
|
+
"react-native-webview": "13.13.5"
|
|
184
192
|
},
|
|
185
193
|
"agora-extension-ai-denoiser": {
|
|
186
194
|
"agora-rtc-sdk-ng": "4.20.1-1"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
diff --git a/node_modules/@supersami/rn-foreground-service/android/src/main/java/com/supersami/foregroundservice/NotificationHelper.java b/node_modules/@supersami/rn-foreground-service/android/src/main/java/com/supersami/foregroundservice/NotificationHelper.java
|
|
2
|
+
--- a/node_modules/@supersami/rn-foreground-service/android/src/main/java/com/supersami/foregroundservice/NotificationHelper.java
|
|
3
|
+
+++ b/node_modules/@supersami/rn-foreground-service/android/src/main/java/com/supersami/foregroundservice/NotificationHelper.java
|
|
4
|
+
@@ -59 +59 @@
|
|
5
|
+
- PendingIntent pendingIntent = PendingIntent.getActivity(context, uniqueInt1, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
6
|
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, uniqueInt1, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
|
7
|
+
@@ -66 +66 @@
|
|
8
|
+
- pendingBtnIntent = PendingIntent.getActivity(context, uniqueInt, notificationBtnIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
9
|
+
+ pendingBtnIntent = PendingIntent.getActivity(context, uniqueInt, notificationBtnIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
|
10
|
+
@@ -125 +125 @@
|
|
11
|
+
- notificationBuilder.addAction(R.drawable.redbox_top_border_background, bundle.getString("buttonText", "Button"), pendingBtnIntent);
|
|
12
|
+
+ notificationBuilder.addAction(android.R.drawable.ic_media_play, bundle.getString("buttonText", "Button"), pendingBtnIntent);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Check 64-bit ELF/APK alignment and shared Agora AOSL symbol compatibility."""
|
|
3
|
+
import argparse
|
|
4
|
+
import struct
|
|
5
|
+
import sys
|
|
6
|
+
import zipfile
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
PAGE_SIZE = 16384
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def aosl_symbols(data):
|
|
13
|
+
"""Read required and exported AOSL symbols from ELF32/ELF64 dynamic tables."""
|
|
14
|
+
if data[:4] != b'\x7fELF':
|
|
15
|
+
raise ValueError('expected an ELF library')
|
|
16
|
+
is_64 = data[4] == 2
|
|
17
|
+
endian = '<' if data[5] == 1 else '>'
|
|
18
|
+
table_offset = struct.unpack_from(endian + ('Q' if is_64 else 'I'), data, 40 if is_64 else 32)[0]
|
|
19
|
+
entry_size, entry_count = struct.unpack_from(endian + 'HH', data, 58 if is_64 else 46)
|
|
20
|
+
section_format = endian + ('IIQQQQIIQQ' if is_64 else 'IIIIIIIIII')
|
|
21
|
+
sections = [struct.unpack_from(section_format, data, table_offset + i * entry_size)
|
|
22
|
+
for i in range(entry_count)]
|
|
23
|
+
required, exported = set(), set()
|
|
24
|
+
for section in sections:
|
|
25
|
+
if section[1] != 11: # SHT_DYNSYM
|
|
26
|
+
continue
|
|
27
|
+
strings = sections[section[6]]
|
|
28
|
+
string_data = data[strings[4]:strings[4] + strings[5]]
|
|
29
|
+
for offset in range(section[4], section[4] + section[5], section[9]):
|
|
30
|
+
symbol = struct.unpack_from(endian + ('IBBHQQ' if is_64 else 'IIIBBH'), data, offset)
|
|
31
|
+
name_offset = symbol[0]
|
|
32
|
+
name_bytes = string_data[name_offset:string_data.find(b'\0', name_offset)]
|
|
33
|
+
if not name_bytes.startswith(b'aosl_'):
|
|
34
|
+
continue
|
|
35
|
+
name = name_bytes.decode('ascii')
|
|
36
|
+
info, section_index = (symbol[1], symbol[3]) if is_64 else (symbol[3], symbol[5])
|
|
37
|
+
if section_index == 0:
|
|
38
|
+
if info >> 4 == 1: # Undefined GLOBAL symbols; WEAK imports are optional.
|
|
39
|
+
required.add(name)
|
|
40
|
+
elif info >> 4 in (1, 2):
|
|
41
|
+
exported.add(name)
|
|
42
|
+
return required, exported
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def check_artifact(path):
|
|
46
|
+
failures = []
|
|
47
|
+
checked = 0
|
|
48
|
+
aosl_providers = {}
|
|
49
|
+
aosl_consumers = []
|
|
50
|
+
with zipfile.ZipFile(path) as archive, path.open('rb') as artifact:
|
|
51
|
+
for entry in archive.infolist():
|
|
52
|
+
name = entry.filename
|
|
53
|
+
if name.endswith('.so'):
|
|
54
|
+
data = archive.read(entry)
|
|
55
|
+
required, exported = aosl_symbols(data)
|
|
56
|
+
abi = name.split('/')[-2]
|
|
57
|
+
if name.endswith('/libaosl.so'):
|
|
58
|
+
aosl_providers[abi] = exported
|
|
59
|
+
if required:
|
|
60
|
+
aosl_consumers.append((name, abi, required))
|
|
61
|
+
if not name.endswith('.so') or not any(
|
|
62
|
+
f'/{abi}/' in name for abi in ('arm64-v8a', 'x86_64')
|
|
63
|
+
):
|
|
64
|
+
continue
|
|
65
|
+
checked += 1
|
|
66
|
+
data = archive.read(entry)
|
|
67
|
+
if data[:5] != b'\x7fELF\x02':
|
|
68
|
+
failures.append(f'{name}: expected a 64-bit ELF library')
|
|
69
|
+
continue
|
|
70
|
+
endian = '<' if data[5] == 1 else '>'
|
|
71
|
+
table_offset = struct.unpack_from(endian + 'Q', data, 32)[0]
|
|
72
|
+
entry_size, entry_count = struct.unpack_from(endian + 'HH', data, 54)
|
|
73
|
+
for index in range(entry_count):
|
|
74
|
+
offset = table_offset + index * entry_size
|
|
75
|
+
segment_type = struct.unpack_from(endian + 'I', data, offset)[0]
|
|
76
|
+
if segment_type == 1: # PT_LOAD
|
|
77
|
+
alignment = struct.unpack_from(endian + 'Q', data, offset + 48)[0]
|
|
78
|
+
if alignment < PAGE_SIZE:
|
|
79
|
+
failures.append(f'{name}: ELF load segment is aligned to {alignment} bytes')
|
|
80
|
+
break
|
|
81
|
+
if path.suffix == '.apk' and entry.compress_type == zipfile.ZIP_STORED:
|
|
82
|
+
artifact.seek(entry.header_offset + 26)
|
|
83
|
+
name_size, extra_size = struct.unpack('<HH', artifact.read(4))
|
|
84
|
+
data_offset = entry.header_offset + 30 + name_size + extra_size
|
|
85
|
+
if data_offset % PAGE_SIZE:
|
|
86
|
+
failures.append(f'{name}: uncompressed APK entry lacks 16 KB ZIP alignment')
|
|
87
|
+
if not checked:
|
|
88
|
+
failures.append('No 64-bit native libraries found')
|
|
89
|
+
for name, abi, required in aosl_consumers:
|
|
90
|
+
missing = required - aosl_providers.get(abi, set())
|
|
91
|
+
if missing:
|
|
92
|
+
failures.append(f'{name}: packaged libaosl.so lacks symbols: {", ".join(sorted(missing))}')
|
|
93
|
+
for failure in failures:
|
|
94
|
+
print(f'FAIL: {failure}', file=sys.stderr)
|
|
95
|
+
print(f'{path.name}: checked alignment of {checked} native libraries and '
|
|
96
|
+
f'AOSL imports in {len(aosl_consumers)} libraries; {len(failures)} failures')
|
|
97
|
+
if path.suffix == '.aab':
|
|
98
|
+
print('AAB check covers ELF alignment. Also verify ZIP alignment in generated APKs.')
|
|
99
|
+
return bool(failures)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == '__main__':
|
|
103
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
104
|
+
parser.add_argument('artifact', type=Path)
|
|
105
|
+
args = parser.parse_args()
|
|
106
|
+
sys.exit(check_artifact(args.artifact))
|
|
@@ -14,13 +14,7 @@ import {Router} from './components/Router';
|
|
|
14
14
|
import Navigation from './components/Navigation';
|
|
15
15
|
import {StorageProvider} from './components/StorageContext';
|
|
16
16
|
import {SessionProvider} from './components/SessionContext';
|
|
17
|
-
import {
|
|
18
|
-
ImageBackground,
|
|
19
|
-
SafeAreaView,
|
|
20
|
-
StatusBar,
|
|
21
|
-
Platform,
|
|
22
|
-
View,
|
|
23
|
-
} from 'react-native';
|
|
17
|
+
import {ImageBackground, StatusBar, Platform, View} from 'react-native';
|
|
24
18
|
import ColorConfigure from './components/ColorConfigure';
|
|
25
19
|
import {isValidReactComponent} from './utils/common';
|
|
26
20
|
import DimensionProvider from './components/dimension/DimensionProvider';
|
|
@@ -35,6 +29,7 @@ import {ToastContext, ToastProvider} from './components/useToast';
|
|
|
35
29
|
import {SdkApiContext} from './components/SdkApiContext';
|
|
36
30
|
import isSDK from './utils/isSDK';
|
|
37
31
|
import BlockUI from './subComponents/BlockUI';
|
|
32
|
+
import SafeAreaView from './components/AppSafeAreaView';
|
|
38
33
|
|
|
39
34
|
interface AppWrapperProps {
|
|
40
35
|
children: React.ReactNode;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import React, {useState} from 'react';
|
|
2
|
-
import {View, StyleSheet,
|
|
1
|
+
import React, {useEffect, useState} from 'react';
|
|
2
|
+
import {View, StyleSheet, useWindowDimensions, Pressable} from 'react-native';
|
|
3
3
|
import {FlatList} from 'react-native-gesture-handler';
|
|
4
4
|
|
|
5
|
-
const {width} = Dimensions.get('window');
|
|
6
|
-
|
|
7
5
|
interface CarouselItem {
|
|
8
6
|
id: string;
|
|
9
7
|
component: React.ReactNode;
|
|
@@ -14,9 +12,22 @@ interface CarouselProps {
|
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
const Carousel: React.FC<CarouselProps> = ({data}) => {
|
|
15
|
+
const {width: windowWidth} = useWindowDimensions();
|
|
16
|
+
const [width, setWidth] = useState(windowWidth);
|
|
17
17
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
18
18
|
|
|
19
19
|
const flatListRef = React.useRef<FlatList | null>(null);
|
|
20
|
+
const previousWidth = React.useRef(width);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (previousWidth.current !== width) {
|
|
24
|
+
previousWidth.current = width;
|
|
25
|
+
flatListRef.current?.scrollToOffset({
|
|
26
|
+
offset: activeIndex * width,
|
|
27
|
+
animated: false,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}, [width, activeIndex]);
|
|
20
31
|
|
|
21
32
|
const handleScroll = event => {
|
|
22
33
|
const {contentOffset} = event.nativeEvent;
|
|
@@ -37,7 +48,13 @@ const Carousel: React.FC<CarouselProps> = ({data}) => {
|
|
|
37
48
|
};
|
|
38
49
|
|
|
39
50
|
return (
|
|
40
|
-
<View
|
|
51
|
+
<View
|
|
52
|
+
style={styles.container}
|
|
53
|
+
onLayout={({nativeEvent: {layout}}) => {
|
|
54
|
+
if (layout.width > 0) {
|
|
55
|
+
setWidth(layout.width);
|
|
56
|
+
}
|
|
57
|
+
}}>
|
|
41
58
|
<FlatList
|
|
42
59
|
ref={flatListRef}
|
|
43
60
|
data={data}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {StyleSheet, Text, View} from 'react-native';
|
|
3
|
-
import {
|
|
4
|
-
SHARE_LINK_CONTENT_TYPE,
|
|
5
|
-
useShareLink,
|
|
6
|
-
} from '../components/useShareLink';
|
|
2
|
+
import {Platform, StyleSheet, Text, View} from 'react-native';
|
|
3
|
+
import {SHARE_LINK_CONTENT_TYPE} from '../components/useShareLink';
|
|
7
4
|
import platform from '../subComponents/Platform';
|
|
8
|
-
import Spacer from './Spacer';
|
|
9
5
|
import isSDKCheck from '../utils/isSDK';
|
|
6
|
+
import Spacer from './Spacer';
|
|
10
7
|
import ClipboardIconButton from './ClipboardIconButton';
|
|
11
8
|
import ThemeConfig, {FontSizes} from '../theme';
|
|
12
9
|
import hexadecimalTransparency from '../utils/hexadecimalTransparency';
|
|
@@ -41,12 +38,8 @@ const MeetingLink = (props: MeetingLinkProps) => {
|
|
|
41
38
|
} = props;
|
|
42
39
|
|
|
43
40
|
const style = useStyles(styleProps);
|
|
44
|
-
|
|
45
|
-
const {getShareLink} = useShareLink();
|
|
46
|
-
|
|
47
|
-
const isSDK = isSDKCheck();
|
|
48
41
|
const isWebCheck =
|
|
49
|
-
$config.FRONTEND_ENDPOINT || (platform === 'web' && !
|
|
42
|
+
$config.FRONTEND_ENDPOINT || (platform === 'web' && !isSDKCheck());
|
|
50
43
|
|
|
51
44
|
return (
|
|
52
45
|
<>
|
|
@@ -60,7 +53,7 @@ const MeetingLink = (props: MeetingLinkProps) => {
|
|
|
60
53
|
style={[
|
|
61
54
|
style.linkText,
|
|
62
55
|
//@ts-ignore
|
|
63
|
-
isWebCheck ? urlWeb : {opacity: 1},
|
|
56
|
+
Platform.OS === 'web' && isWebCheck ? urlWeb : {opacity: 1},
|
|
64
57
|
]}>
|
|
65
58
|
{link}
|
|
66
59
|
</Text>
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
Text,
|
|
4
4
|
View,
|
|
5
5
|
Modal,
|
|
6
|
+
ScrollView,
|
|
6
7
|
TouchableWithoutFeedback,
|
|
7
8
|
ModalProps,
|
|
8
9
|
ViewStyle,
|
|
@@ -13,6 +14,7 @@ import ThemeConfig from '../theme';
|
|
|
13
14
|
import hexadecimalTransparency from '../utils/hexadecimalTransparency';
|
|
14
15
|
import {isMobileUA, useIsDesktop} from '../../src/utils/common';
|
|
15
16
|
import Spacer from './Spacer';
|
|
17
|
+
import useIsTablet from '../utils/useIsTablet';
|
|
16
18
|
|
|
17
19
|
interface PopupProps extends ModalProps {
|
|
18
20
|
title?: string;
|
|
@@ -44,6 +46,7 @@ const Popup = (props: PopupProps) => {
|
|
|
44
46
|
} = props;
|
|
45
47
|
|
|
46
48
|
const isDesktop = useIsDesktop()('popup');
|
|
49
|
+
const isTabletView = useIsTablet();
|
|
47
50
|
|
|
48
51
|
return (
|
|
49
52
|
<Modal
|
|
@@ -67,7 +70,12 @@ const Popup = (props: PopupProps) => {
|
|
|
67
70
|
<View style={styles.backDrop} />
|
|
68
71
|
</TouchableWithoutFeedback>
|
|
69
72
|
|
|
70
|
-
<View
|
|
73
|
+
<View
|
|
74
|
+
style={[
|
|
75
|
+
styles.modalView,
|
|
76
|
+
props?.contentContainerStyle,
|
|
77
|
+
isTabletView && styles.tabletModalView,
|
|
78
|
+
]}>
|
|
71
79
|
{title || showCloseIcon || headerComponent ? (
|
|
72
80
|
<>
|
|
73
81
|
<View style={styles.header}>
|
|
@@ -111,7 +119,15 @@ const Popup = (props: PopupProps) => {
|
|
|
111
119
|
) : (
|
|
112
120
|
<></>
|
|
113
121
|
)}
|
|
114
|
-
|
|
122
|
+
{isTabletView ? (
|
|
123
|
+
<ScrollView
|
|
124
|
+
style={styles.tabletBody}
|
|
125
|
+
contentContainerStyle={bodyContainerStyle}>
|
|
126
|
+
{children}
|
|
127
|
+
</ScrollView>
|
|
128
|
+
) : (
|
|
129
|
+
<View style={bodyContainerStyle}>{children}</View>
|
|
130
|
+
)}
|
|
115
131
|
</View>
|
|
116
132
|
</View>
|
|
117
133
|
</Modal>
|
|
@@ -153,6 +169,14 @@ const styles = StyleSheet.create({
|
|
|
153
169
|
backgroundColor:
|
|
154
170
|
$config.HARD_CODED_BLACK_COLOR + hexadecimalTransparency['60%'],
|
|
155
171
|
},
|
|
172
|
+
tabletModalView: {
|
|
173
|
+
maxHeight: '90%',
|
|
174
|
+
flexShrink: 1,
|
|
175
|
+
},
|
|
176
|
+
tabletBody: {
|
|
177
|
+
flexGrow: 0,
|
|
178
|
+
flexShrink: 1,
|
|
179
|
+
},
|
|
156
180
|
header: {
|
|
157
181
|
flexDirection: 'row',
|
|
158
182
|
justifyContent: 'space-between',
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
SafeAreaProvider,
|
|
4
|
+
SafeAreaView,
|
|
5
|
+
SafeAreaViewProps,
|
|
6
|
+
initialWindowMetrics,
|
|
7
|
+
} from 'react-native-safe-area-context';
|
|
8
|
+
|
|
9
|
+
export default function AppSafeAreaView(props: SafeAreaViewProps) {
|
|
10
|
+
return (
|
|
11
|
+
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
|
|
12
|
+
<SafeAreaView {...props} />
|
|
13
|
+
</SafeAreaProvider>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {SafeAreaView as default} from 'react-native';
|
|
@@ -13,6 +13,7 @@ import React, {useState, useContext, useEffect} from 'react';
|
|
|
13
13
|
import {View, Text, StyleSheet, ScrollView} from 'react-native';
|
|
14
14
|
import {PropsContext, ClientRoleType, ToggleState} from '../../agora-rn-uikit';
|
|
15
15
|
import {isValidReactComponent, isWebInternal, trimText} from '../utils/common';
|
|
16
|
+
import useIsTablet from '../utils/useIsTablet';
|
|
16
17
|
import ColorContext from './ColorContext';
|
|
17
18
|
import {useRoomInfo} from './room-info/useRoomInfo';
|
|
18
19
|
import PreCallLogo from './common/Logo';
|
|
@@ -214,6 +215,7 @@ const JoinRoomButton = () => {
|
|
|
214
215
|
};
|
|
215
216
|
|
|
216
217
|
const Precall = (props: any) => {
|
|
218
|
+
const isTabletView = useIsTablet();
|
|
217
219
|
const {primaryColor} = useContext(ColorContext);
|
|
218
220
|
const {rtcProps} = useContext(PropsContext);
|
|
219
221
|
const [isSettingsOpen, setIsSettingsOpen] = React.useState(true);
|
|
@@ -424,16 +426,28 @@ const Precall = (props: any) => {
|
|
|
424
426
|
<></>
|
|
425
427
|
)}
|
|
426
428
|
</View>
|
|
427
|
-
<View
|
|
428
|
-
|
|
429
|
+
<View
|
|
430
|
+
style={[
|
|
431
|
+
style.content,
|
|
432
|
+
isTabletView && style.tabletContent,
|
|
433
|
+
]}>
|
|
434
|
+
<View
|
|
435
|
+
style={[
|
|
436
|
+
style.preview,
|
|
437
|
+
isTabletView && style.tabletPreview,
|
|
438
|
+
isTabletView && style.tabletFrame,
|
|
439
|
+
]}>
|
|
429
440
|
<View
|
|
430
|
-
style={
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
441
|
+
style={[
|
|
442
|
+
{
|
|
443
|
+
flex: 1,
|
|
444
|
+
position: 'relative',
|
|
445
|
+
overflow: 'hidden',
|
|
446
|
+
borderTopLeftRadius: 12,
|
|
447
|
+
borderTopRightRadius: 12,
|
|
448
|
+
},
|
|
449
|
+
isTabletView && style.tabletVideo,
|
|
450
|
+
]}>
|
|
437
451
|
{isLocalVideoON ? (
|
|
438
452
|
<View style={style.switchCamera}>
|
|
439
453
|
<LocalSwitchCamera
|
|
@@ -458,7 +472,8 @@ const Precall = (props: any) => {
|
|
|
458
472
|
/>
|
|
459
473
|
</View>
|
|
460
474
|
</View>
|
|
461
|
-
<View
|
|
475
|
+
<View
|
|
476
|
+
style={[style.footer, isTabletView && style.tabletFrame]}>
|
|
462
477
|
<JoinRoomName isDesktop={false} isOnPrecall={true} />
|
|
463
478
|
<Spacer size={8} horizontal={false} />
|
|
464
479
|
<JoinRoomButton />
|
|
@@ -495,6 +510,21 @@ const style = StyleSheet.create({
|
|
|
495
510
|
content: {
|
|
496
511
|
flex: 1,
|
|
497
512
|
},
|
|
513
|
+
tabletContent: {
|
|
514
|
+
justifyContent: 'center',
|
|
515
|
+
},
|
|
516
|
+
tabletPreview: {
|
|
517
|
+
flex: 0,
|
|
518
|
+
},
|
|
519
|
+
tabletFrame: {
|
|
520
|
+
width: '100%',
|
|
521
|
+
maxWidth: 600,
|
|
522
|
+
alignSelf: 'center',
|
|
523
|
+
},
|
|
524
|
+
tabletVideo: {
|
|
525
|
+
flex: 0,
|
|
526
|
+
aspectRatio: 4 / 3,
|
|
527
|
+
},
|
|
498
528
|
preview: {
|
|
499
529
|
// paddingHorizontal: 20,
|
|
500
530
|
// paddingBottom: 8,
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
TouchableOpacity,
|
|
19
19
|
Image,
|
|
20
20
|
Pressable,
|
|
21
|
+
Platform,
|
|
21
22
|
} from 'react-native';
|
|
22
23
|
import platform from '../subComponents/Platform';
|
|
23
24
|
import PrimaryButton from '../atoms/PrimaryButton';
|
|
@@ -25,6 +26,7 @@ import SecondaryButton from '../atoms/SecondaryButton';
|
|
|
25
26
|
import {SHARE_LINK_CONTENT_TYPE, useShareLink} from './useShareLink';
|
|
26
27
|
import {useString} from '../utils/useString';
|
|
27
28
|
import isSDKCheck from '../utils/isSDK';
|
|
29
|
+
import useIsTablet from '../utils/useIsTablet';
|
|
28
30
|
import Logo from '../components/common/Logo';
|
|
29
31
|
import {useRoomInfo} from './room-info/useRoomInfo';
|
|
30
32
|
import {useHistory} from '../components/Router';
|
|
@@ -144,7 +146,7 @@ export const CopyMeetingInfo = (props?: CopyMeetingInfoProps) => {
|
|
|
144
146
|
style.url,
|
|
145
147
|
style.urlPadding,
|
|
146
148
|
//@ts-ignore
|
|
147
|
-
isWebCheck ? urlWeb : {opacity: 1},
|
|
149
|
+
Platform.OS === 'web' && isWebCheck ? urlWeb : {opacity: 1},
|
|
148
150
|
]}>
|
|
149
151
|
{getShareLink(SHARE_LINK_CONTENT_TYPE.HOST)}
|
|
150
152
|
</Text>
|
|
@@ -178,7 +180,7 @@ export const CopyMeetingInfo = (props?: CopyMeetingInfoProps) => {
|
|
|
178
180
|
style.url,
|
|
179
181
|
style.urlPadding,
|
|
180
182
|
//@ts-ignore
|
|
181
|
-
isWebCheck ? urlWeb : {opacity: 1},
|
|
183
|
+
Platform.OS === 'web' && isWebCheck ? urlWeb : {opacity: 1},
|
|
182
184
|
]}>
|
|
183
185
|
{getShareLink(SHARE_LINK_CONTENT_TYPE.ATTENDEE)}
|
|
184
186
|
</Text>
|
|
@@ -210,7 +212,7 @@ export const CopyMeetingInfo = (props?: CopyMeetingInfoProps) => {
|
|
|
210
212
|
style={[
|
|
211
213
|
style.url,
|
|
212
214
|
//@ts-ignore
|
|
213
|
-
isWebCheck ? urlWeb : {opacity: 1},
|
|
215
|
+
Platform.OS === 'web' && isWebCheck ? urlWeb : {opacity: 1},
|
|
214
216
|
]}>
|
|
215
217
|
{shareRoomPSTNNumber} - {pstn?.number} {' | '}{' '}
|
|
216
218
|
{shareRoomPSTNPin} - {pstn?.pin}
|
|
@@ -302,7 +304,7 @@ export const ShowInputURL = (props: ShowInputURLProps) => {
|
|
|
302
304
|
style.url,
|
|
303
305
|
style.urlPadding,
|
|
304
306
|
//@ts-ignore
|
|
305
|
-
urlWeb,
|
|
307
|
+
Platform.OS === 'web' ? urlWeb : {opacity: 1},
|
|
306
308
|
]}>
|
|
307
309
|
{url}
|
|
308
310
|
</Text>
|
|
@@ -314,6 +316,7 @@ export const ShowInputURL = (props: ShowInputURLProps) => {
|
|
|
314
316
|
};
|
|
315
317
|
|
|
316
318
|
const Share = () => {
|
|
319
|
+
const isTabletView = useIsTablet();
|
|
317
320
|
const {FpeShareComponent} = useCustomization(data => {
|
|
318
321
|
let components: {
|
|
319
322
|
FpeShareComponent?: React.ElementType;
|
|
@@ -368,8 +371,12 @@ const Share = () => {
|
|
|
368
371
|
) : (
|
|
369
372
|
<></>
|
|
370
373
|
)}
|
|
371
|
-
<ScrollView
|
|
372
|
-
|
|
374
|
+
<ScrollView
|
|
375
|
+
contentContainerStyle={[
|
|
376
|
+
style.scrollMain,
|
|
377
|
+
isTabletView && style.tabletScrollMain,
|
|
378
|
+
]}>
|
|
379
|
+
<Card cardContainerStyle={isTabletView ? style.tabletCard : undefined}>
|
|
373
380
|
<View>
|
|
374
381
|
<View
|
|
375
382
|
style={{
|
|
@@ -425,6 +432,20 @@ const style = StyleSheet.create({
|
|
|
425
432
|
flexDirection: 'row',
|
|
426
433
|
justifyContent: 'center',
|
|
427
434
|
},
|
|
435
|
+
tabletScrollMain: {
|
|
436
|
+
alignItems: 'center',
|
|
437
|
+
padding: 24,
|
|
438
|
+
},
|
|
439
|
+
tabletCard: {
|
|
440
|
+
flex: 0,
|
|
441
|
+
alignSelf: 'center',
|
|
442
|
+
justifyContent: 'flex-start',
|
|
443
|
+
paddingHorizontal: 40,
|
|
444
|
+
paddingVertical: 40,
|
|
445
|
+
borderRadius: ThemeConfig.BorderRadius.extraLarge,
|
|
446
|
+
borderWidth: 1,
|
|
447
|
+
borderColor: $config.CARD_LAYER_3_COLOR,
|
|
448
|
+
},
|
|
428
449
|
heading: {
|
|
429
450
|
fontSize: ThemeConfig.FontSize.extraLarge,
|
|
430
451
|
fontWeight: '700',
|