@trtc/calls-uikit-react 4.5.3-beta.1 → 4.5.8

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 (90) hide show
  1. package/package.json +4 -3
  2. package/src/Components/TUICallKit/TUICallKit.tsx +19 -0
  3. package/src/Components/components/SingleCall/MediaContainer/hooks/useGetLargeViewName.ts +9 -2
  4. package/src/Components/components/common/AutoPlayDialog/AutoPlayDialog.module.scss +33 -0
  5. package/src/Components/components/common/AutoPlayDialog/AutoPlayDialog.tsx +57 -0
  6. package/src/Components/components/common/AutoPlayDialog/index.ts +3 -0
  7. package/src/TUICallService/CallService/UIKitModal.ts +50 -12
  8. package/src/TUICallService/CallService/engineEventHandler.ts +4 -2
  9. package/src/TUICallService/CallService/index.ts +14 -14
  10. package/src/TUICallService/CallService/miniProgram.ts +4 -1
  11. package/src/TUICallService/UIKitModal/UIKitModal.ts +14 -5
  12. package/src/TUICallService/locales/en.ts +3 -0
  13. package/src/TUICallService/locales/ja_JP.ts +4 -2
  14. package/src/TUICallService/locales/zh-cn.ts +3 -0
  15. package/src/TUICallService/utils/env.ts +11 -1
  16. package/src/TUICallService/utils/permission.ts +294 -0
  17. package/src/TUICallService/utils/validate/avoidRepeatedCall.ts +5 -1
  18. package/src/index.ts +1 -1
  19. package/tuicall-uikit-react.es.js +2951 -2627
  20. package/tuicall-uikit-react.umd.js +4 -4
  21. package/types/Components/TUICallKit/TUICallKit.d.ts +2 -2
  22. package/types/Components/components/GroupCall/GroupCall.d.ts +1 -2
  23. package/types/Components/components/GroupCall/MediaContainer/AudioStream/AudioStream.d.ts +1 -2
  24. package/types/Components/components/GroupCall/MediaContainer/MediaContainer.d.ts +1 -2
  25. package/types/Components/components/GroupCall/MediaContainer/StreamLoading/StreamLoading.d.ts +1 -1
  26. package/types/Components/components/GroupCall/Waiting/Waiting.d.ts +1 -2
  27. package/types/Components/components/SingleCall/MediaContainer/AudioStream/AudioStream.d.ts +1 -2
  28. package/types/Components/components/SingleCall/MediaContainer/MediaContainer.d.ts +1 -2
  29. package/types/Components/components/SingleCall/SingleCall.d.ts +1 -1
  30. package/types/Components/components/SingleCall/Waiting/Waiting.d.ts +1 -2
  31. package/types/Components/components/base/Avatar/Avatar.d.ts +2 -2
  32. package/types/Components/components/base/Drag/Drag.d.ts +2 -2
  33. package/types/Components/components/base/Grid/Col/Col.d.ts +2 -2
  34. package/types/Components/components/base/Grid/Row/Row.d.ts +1 -1
  35. package/types/Components/components/base/GridLayout/GridLayout.d.ts +1 -2
  36. package/types/Components/components/base/GridLayout/GridPlusItem/GridPlusItem.d.ts +2 -2
  37. package/types/Components/components/base/Icon/Icon.d.ts +2 -2
  38. package/types/Components/components/base/Loading/Circle/Cilrcle.d.ts +1 -2
  39. package/types/Components/components/base/Loading/Dot/Dot.d.ts +1 -2
  40. package/types/Components/components/base/Loading/Loading.d.ts +2 -2
  41. package/types/Components/components/base/Message/Message.d.ts +2 -2
  42. package/types/Components/components/base/Message/MessageIcon/Error.d.ts +1 -1
  43. package/types/Components/components/base/Message/MessageIcon/Info.d.ts +1 -1
  44. package/types/Components/components/base/Message/MessageIcon/Success.d.ts +1 -1
  45. package/types/Components/components/base/Message/MessageIcon/Warning.d.ts +1 -1
  46. package/types/Components/components/base/Overlayer/Overlayer.d.ts +2 -2
  47. package/types/Components/components/base/Text/Text.d.ts +1 -2
  48. package/types/Components/components/base/Time/Time.d.ts +1 -2
  49. package/types/Components/components/base/ToggleWindow/ToggleWindow.d.ts +1 -1
  50. package/types/Components/components/base/ToggleWindow/ToggleWindowItem/ToggleWindowItem.d.ts +1 -2
  51. package/types/Components/components/common/AutoPlayDialog/AutoPlayDialog.d.ts +1 -0
  52. package/types/Components/components/common/AutoPlayDialog/index.d.ts +2 -0
  53. package/types/Components/components/common/ButtonPanel/ButtonPanel.d.ts +1 -2
  54. package/types/Components/components/common/ButtonPanel/ButtonPanelH5/ButtonPanelH5.d.ts +2 -2
  55. package/types/Components/components/common/ButtonPanel/ButtonPanelPC/ButtonPanelPC.d.ts +1 -2
  56. package/types/Components/components/common/ButtonPanel/button/Accept/Accept.d.ts +1 -2
  57. package/types/Components/components/common/ButtonPanel/button/BackgroundBlur/BackgroundBlur.d.ts +1 -2
  58. package/types/Components/components/common/ButtonPanel/button/Camera.d.ts +1 -2
  59. package/types/Components/components/common/ButtonPanel/button/FullScreen/FullScreen.d.ts +1 -2
  60. package/types/Components/components/common/ButtonPanel/button/Hangup/Hangup.d.ts +1 -2
  61. package/types/Components/components/common/ButtonPanel/button/Microphone.d.ts +1 -2
  62. package/types/Components/components/common/ButtonPanel/button/Minimize/Minimize.d.ts +1 -2
  63. package/types/Components/components/common/ButtonPanel/button/Reject/Reject.d.ts +1 -2
  64. package/types/Components/components/common/ButtonPanel/button/Speaker.d.ts +1 -2
  65. package/types/Components/components/common/ButtonPanel/button/SwitchAudioCall.d.ts +1 -2
  66. package/types/Components/components/common/ButtonPanel/button/SwitchCamera.d.ts +1 -2
  67. package/types/Components/components/common/CallMessage/CallMessage.d.ts +1 -1
  68. package/types/Components/components/common/CallMessage/CallMessageC2C/CallMessageC2C.d.ts +1 -2
  69. package/types/Components/components/common/CallMessage/CallMessageGroup/CallMessageGroup.d.ts +1 -2
  70. package/types/Components/components/common/DeviceSelector/DeviceSelector.d.ts +1 -2
  71. package/types/Components/components/common/FloatingWindow/FloatingWindow.d.ts +2 -2
  72. package/types/Components/components/common/FloatingWindow/FloatingWindowGroupCall/FloatingWindowGroupCall.d.ts +2 -2
  73. package/types/Components/components/common/FloatingWindow/FloatingWindowSingleCall/FloatingWindowSingleCall.d.ts +2 -2
  74. package/types/Components/components/common/MicrophoneVolumn/MicrophoneVolumn.d.ts +2 -2
  75. package/types/Components/components/common/OverlayStream/OverlayStream.d.ts +2 -2
  76. package/types/Components/components/common/Player/Player.d.ts +2 -2
  77. package/types/Components/components/common/Pusher/Pusher.d.ts +1 -1
  78. package/types/Components/components/common/StreamInfo/StreamInfo.d.ts +1 -2
  79. package/types/Components/components/common/StreamInfo/StreamInfoH5/StreamInfoH5.d.ts +1 -2
  80. package/types/Components/components/common/StreamInfo/StreamInfoPC/StreamInfoPC.d.ts +1 -2
  81. package/types/Components/components/common/Tip/Tip.d.ts +2 -2
  82. package/types/Components/components/common/TopBar/TopBar.d.ts +1 -2
  83. package/types/Components/components/common/TopBar/h5/TopBarH5.d.ts +1 -2
  84. package/types/Components/components/common/TopBar/pc/TopBarPC.d.ts +1 -2
  85. package/types/TUICallService/CallService/UIKitModal.d.ts +1 -1
  86. package/types/TUICallService/locales/en.d.ts +3 -0
  87. package/types/TUICallService/locales/ja_JP.d.ts +2 -0
  88. package/types/TUICallService/locales/zh-cn.d.ts +3 -0
  89. package/types/TUICallService/utils/env.d.ts +1 -0
  90. package/types/TUICallService/utils/permission.d.ts +88 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trtc/calls-uikit-react",
3
- "version": "4.5.3-beta.1",
3
+ "version": "4.5.8",
4
4
  "main": "./tuicall-uikit-react.umd.js",
5
5
  "module": "./tuicall-uikit-react.es.js",
6
6
  "types": "./types/index.d.ts",
@@ -14,8 +14,9 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@tencentcloud/tui-core-lite": "~1.0.1",
17
- "@trtc/call-engine-lite-js": "4.0.5-beta.1",
18
- "@tencentcloud/lite-chat": "^1.6.3"
17
+ "@trtc/call-engine-lite-js": "~4.0.9",
18
+ "@tencentcloud/lite-chat": "^1.6.3",
19
+ "@trtc/call-engine-lite-wx": "~5.0.6"
19
20
  },
20
21
  "bugs": {
21
22
  "url": "https://github.com/tencentyun/TUICallKit/issues"
@@ -15,6 +15,7 @@ import {
15
15
  import SingleCall from '../components/SingleCall/SingleCall';
16
16
  import GroupCall from '../components/GroupCall/GroupCall';
17
17
  import { AISubtitle } from '../components/common/AIAssistant';
18
+ import AutoPlayDialog from '../components/common/AutoPlayDialog';
18
19
  import { classNames } from '../util/classnames';
19
20
  import {
20
21
  CallInfoContext,
@@ -25,6 +26,7 @@ import {
25
26
  } from '../context';
26
27
  import { MessagePlugin } from '../components/base/Message/MessagePlugin';
27
28
  import FloatingWindow from '../components/common/FloatingWindow';
29
+ import { UIKitModal } from '../components/common/UIKitModal';
28
30
  import useGetSpeakers from '../hooks/useGetSpeakers';
29
31
  import TUICallKitStyle from './TUICallKit.module.scss';
30
32
  import Portal from '../components/base/Portal/Portal';
@@ -176,6 +178,21 @@ export default function TUICallKit(props: ITUICallKitProps) {
176
178
  setTranslateContextValue({ t: value });
177
179
  }
178
180
 
181
+ // Consume the MODAL_ERROR store written by handleModalError (e.g. package errors
182
+ // -1001/-1002, no camera/microphone 60003/60004). UIKitModal.openModal is imperative
183
+ // and mounts its own portal on document.body, so it works even when callStatus is IDLE
184
+ // and the component tree below returns null.
185
+ const handleModalErrorChange = (value) => {
186
+ if (value) {
187
+ UIKitModal.openModal({
188
+ id: value?.id,
189
+ title: value?.title,
190
+ content: value?.content,
191
+ type: 'error',
192
+ });
193
+ }
194
+ };
195
+
179
196
  const watchOptions = {
180
197
  [NAME.CALL_STATUS]: handleCallStatusChange,
181
198
  [NAME.IS_GROUP]: handleIsGroupChange,
@@ -191,6 +208,7 @@ export default function TUICallKit(props: ITUICallKitProps) {
191
208
  [NAME.IS_SHOW_ENABLE_VIRTUAL_BACKGROUND]: handleIsShowEnableVirtualBackgroundChange,
192
209
  [NAME.IS_MUTE_SPEAKER]: handleMuteSpeakerChange,
193
210
  [NAME.TRANSLATE]: handleTranslateChange,
211
+ [NAME.MODAL_ERROR]: handleModalErrorChange,
194
212
  };
195
213
 
196
214
  useLayoutEffect(() => {
@@ -249,6 +267,7 @@ export default function TUICallKit(props: ITUICallKitProps) {
249
267
  <div style={{ ...style }} className={classnames} id='tuicallkit-id'>
250
268
  {!isGroupCall && <SingleCall />}
251
269
  {isGroupCall && <GroupCall />}
270
+ <AutoPlayDialog />
252
271
  <AISubtitle />
253
272
  </div>
254
273
  <Portal attach="body">
@@ -8,6 +8,13 @@ export default function useGetLargeViewName() {
8
8
  const { callStatus } = useContext(CallInfoContext);
9
9
  const [largeViewName, setLargeViewName] = useState(ViewName.LOCAL);
10
10
 
11
+ // Only depend on the primitive `isEnter` flag (plus layoutMode & callStatus),
12
+ // instead of the whole remoteList reference. Otherwise every mutation on
13
+ // remote user info (e.g. isAudioAvailable / isVideoAvailable toggled by
14
+ // remote mic/camera off) would re-run this effect and forcibly reset
15
+ // `largeViewName` to REMOTE, overriding the user's manual large-view choice.
16
+ const remoteIsEnter = !!remoteList?.[0]?.isEnter;
17
+
11
18
  useEffect(() => {
12
19
  if (callStatus === CallStatus.CALLING) {
13
20
  return;
@@ -20,10 +27,10 @@ export default function useGetLargeViewName() {
20
27
  return;
21
28
  }
22
29
 
23
- if (remoteList?.[0]?.isEnter) {
30
+ if (remoteIsEnter) {
24
31
  setLargeViewName(ViewName.REMOTE);
25
32
  }
26
- }, [remoteList, layoutMode, callStatus]);
33
+ }, [remoteIsEnter, layoutMode, callStatus]);
27
34
 
28
35
  return [largeViewName, setLargeViewName] as const;
29
36
  }
@@ -0,0 +1,33 @@
1
+ @use "../../../style/theme/util" as *;
2
+
3
+ .auto-play-dialog {
4
+ position: absolute;
5
+ top: 5.2%;
6
+ left: 50%;
7
+ transform: translateX(-50%);
8
+ z-index: 2;
9
+ width: 90%;
10
+ height: 40px;
11
+ display: flex;
12
+ justify-content: space-between;
13
+ align-items: center;
14
+ padding: 0 10px;
15
+ border-radius: 6px;
16
+ font-size: 14px;
17
+ font-weight: 400;
18
+ font-family: PingFang SC;
19
+
20
+ @include theme() {
21
+ background-color: get(floating-color-default);
22
+ color: get(text-color-primary);
23
+ }
24
+
25
+ .auto-play-action {
26
+ flex-shrink: 0;
27
+ margin-left: 10px;
28
+
29
+ @include theme() {
30
+ color: get(text-color-link);
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,57 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import {
3
+ TUIStore,
4
+ StoreName,
5
+ NAME,
6
+ TUIGlobal,
7
+ TUICallKitAPI,
8
+ } from '../../../../TUICallService';
9
+ import { useTranslate } from '../../../hooks';
10
+ import AutoPlayDialogStyle from './AutoPlayDialog.module.scss';
11
+
12
+ export default function AutoPlayDialog() {
13
+ const { t } = useTranslate();
14
+ // The onAutoPlayFailed event is listened in CallService at initialization time and its result is
15
+ // stored in TUIStore, so here we only need to sync the visibility from the store.
16
+ const [
17
+ isAutoPlayDialogVisible,
18
+ setIsAutoPlayDialogVisible,
19
+ ] = useState(TUIStore.getData(StoreName.CALL, NAME.IS_SHOW_AUTO_PLAY_DIALOG));
20
+
21
+ const handleAutoPlayDialogVisibleChange = (value: boolean) => {
22
+ setIsAutoPlayDialogVisible(value);
23
+ };
24
+
25
+ useEffect(() => {
26
+ TUIStore.watch(StoreName.CALL, {
27
+ [NAME.IS_SHOW_AUTO_PLAY_DIALOG]: handleAutoPlayDialogVisibleChange,
28
+ });
29
+
30
+ return () => {
31
+ TUIStore.unwatch(StoreName.CALL, {
32
+ [NAME.IS_SHOW_AUTO_PLAY_DIALOG]: handleAutoPlayDialogVisibleChange,
33
+ });
34
+ };
35
+ }, []);
36
+
37
+ const handleResumePlaybackClick = () => {
38
+ TUIStore.update(StoreName.CALL, NAME.IS_SHOW_AUTO_PLAY_DIALOG, false);
39
+ (TUICallKitAPI as any)?._autoPlayResume?.();
40
+ };
41
+
42
+ if (!isAutoPlayDialogVisible || !TUIGlobal.isH5) {
43
+ return null;
44
+ }
45
+
46
+ return (
47
+ <div className={AutoPlayDialogStyle['auto-play-dialog']}>
48
+ <div>{typeof t === 'function' ? t('auto play failed') : ''}</div>
49
+ <div
50
+ className={AutoPlayDialogStyle['auto-play-action']}
51
+ onClick={handleResumePlaybackClick}
52
+ >
53
+ {typeof t === 'function' ? t('click to resume') : ''}
54
+ </div>
55
+ </div>
56
+ );
57
+ }
@@ -0,0 +1,3 @@
1
+ import AutoPlayDialog from './AutoPlayDialog';
2
+
3
+ export default AutoPlayDialog;
@@ -1,6 +1,9 @@
1
1
 
2
- // @if process.env.BUILD_TARGET ='MINI'
3
- import { UIKitModal } from '../UIKitModal';
2
+ // @if process.env.BUILD_TARGET='MINI'
3
+ // Use the explicit `/index` path so the WeChat mini-program `require`, which
4
+ // only appends `.js` and does not resolve a directory to its `index.js`, can
5
+ // locate the module.
6
+ import { UIKitModal } from '../UIKitModal/index';
4
7
  // @endif
5
8
  // @if process.env.BUILD_TARGET!='MINI'
6
9
  import TuiStore from '../TUIStore/tuiStore';
@@ -22,16 +25,18 @@ const WEB_MODAL_ERROR_CODES = [
22
25
  30000,
23
26
  20007,
24
27
  101002,
28
+ 101011,
29
+ -3301,
25
30
  ];
26
31
 
27
32
  const WEB_MODAL_ERROR_MAP = {
28
33
  '-1001': {
29
34
  id: 10001,
30
- key: 'error.10001'
35
+ key: 'error.10001',
31
36
  },
32
37
  '-1002': {
33
38
  id: 10002,
34
- key: 'error.10002'
39
+ key: 'error.10002',
35
40
  },
36
41
  '-1101': {
37
42
  id: 10004,
@@ -64,15 +69,29 @@ const WEB_MODAL_ERROR_MAP = {
64
69
  '101002': {
65
70
  id: 10014,
66
71
  key: 'error.10014'
72
+ },
73
+ // 101011: package ability not supported, needs an upgrade on the console.
74
+ // Message references the engine's ERROR_PACKAGE_NOT_SUPPORTED wording.
75
+ '101011': {
76
+ id: 10016,
77
+ key: 'error.10016'
78
+ },
79
+ '-3301': {
80
+ id: 10015,
81
+ key: 'error.10015',
82
+ // Message shown when the call is initiated from the Chat + TUICallKit integrated scenario.
83
+ chatKey: 'error.10015.chat'
67
84
  }
68
85
  };
69
86
  // @endif
70
87
 
71
- // @if process.env.BUILD_TARGET ='MINI'
88
+ // @if process.env.BUILD_TARGET='MINI'
72
89
  const MINI_MODAL_ERROR_CODES = [
73
90
  -1001,
74
91
  -1002,
75
92
  101002,
93
+ 101011,
94
+ -3301,
76
95
  ];
77
96
 
78
97
  const MINI_MODAL_ERROR_MAP = {
@@ -87,33 +106,50 @@ const MINI_MODAL_ERROR_MAP = {
87
106
  '101002': {
88
107
  id: 10014,
89
108
  content: '发起通话失败,用户 ID 无效,请确认该用户已注册'
109
+ },
110
+ // 101011: package ability not supported, needs an upgrade on the console.
111
+ // Content references the engine's ERROR_PACKAGE_NOT_SUPPORTED wording.
112
+ '101011': {
113
+ id: 10016,
114
+ content: '您的应用还未开通音视频通话(TUICallKit)能力,您可以去控制台申请免费体验:https://console.cloud.tencent.com/im/detail 或购买通话能力套餐包:https://buy.cloud.tencent.com/avc 有疑问请参考:https://cloud.tencent.com/document/product/647/104662'
115
+ },
116
+ '-3301': {
117
+ id: 10015,
118
+ content: '未开通 TRTC 服务导致进房失败,请到控制台为您的应用开通 TRTC 服务',
119
+ // Content shown when the call is initiated from the Chat + TUICallKit integrated scenario.
120
+ chatContent: '当前为 Chat 融合场景,未开通 TRTC 服务导致进房失败,请到 IM 控制台为您的应用开通 TRTC 服务'
90
121
  }
91
122
  }
92
123
  // @endif
93
124
 
94
- export function handleModalError(error) {
125
+ // `isFromChat` marks whether the current call is initiated from the Chat + TUICallKit
126
+ // integrated scenario (true) or from standalone TUICallKit (false), so the modal can
127
+ // show source-specific guidance for package errors such as -1001 / -1002.
128
+ export function handleModalError(error, isFromChat = false) {
95
129
  if (!error || !error?.code) {
96
130
  return;
97
131
  }
98
132
 
99
133
  // @if process.env.BUILD_TARGET!='MINI'
100
- handleWebModalError(error);
134
+ handleWebModalError(error, isFromChat);
101
135
  // @endif
102
136
 
103
137
  // @if process.env.BUILD_TARGET='MINI'
104
- handleMiniModalError(error);
138
+ handleMiniModalError(error, isFromChat);
105
139
  // @endif
106
140
  }
107
141
 
108
142
  // @if process.env.BUILD_TARGET!='MINI'
109
- function handleWebModalError(error) {
143
+ function handleWebModalError(error, isFromChat = false) {
110
144
  if (!WEB_MODAL_ERROR_CODES.includes(error.code)) {
111
145
  return;
112
146
  }
113
147
 
114
148
  const errorInfo = WEB_MODAL_ERROR_MAP[error.code.toString()];
115
149
  if (errorInfo) {
116
- let content = t(errorInfo.key);
150
+ // Prefer the Chat-integrated message when available and the call comes from Chat.
151
+ const messageKey = isFromChat && errorInfo.chatKey ? errorInfo.chatKey : errorInfo.key;
152
+ let content = t(messageKey);
117
153
  TUIStore.update(StoreName.CALL, NAME.MODAL_ERROR, {
118
154
  id: errorInfo.id,
119
155
  content: content,
@@ -124,16 +160,18 @@ function handleWebModalError(error) {
124
160
  // @endif
125
161
 
126
162
  // @if process.env.BUILD_TARGET='MINI'
127
- function handleMiniModalError(error) {
163
+ function handleMiniModalError(error, isFromChat = false) {
128
164
  if (!MINI_MODAL_ERROR_CODES.includes(error.code)) {
129
165
  return;
130
166
  }
131
167
 
132
168
  const errorInfo = MINI_MODAL_ERROR_MAP[error.code.toString()];
133
169
  if (errorInfo) {
170
+ // Prefer the Chat-integrated content when available and the call comes from Chat.
171
+ const content = isFromChat && errorInfo.chatContent ? errorInfo.chatContent : errorInfo.content;
134
172
  UIKitModal.openModal({
135
173
  id: errorInfo.id,
136
- content: errorInfo.content,
174
+ content: content,
137
175
  title: '错误',
138
176
  type: 'error'
139
177
  });
@@ -48,6 +48,7 @@ export default class EngineEventHandler {
48
48
  callEngine.on(TUICallEvent.ON_USER_INVITING, this._handleOnUserInviting, this); // 通话存在邀请他人时, 通话里的所有人都会抛出
49
49
  callEngine.on(TUICallEvent.SDK_READY, this._handleSDKReady, this); // SDK Ready 回调
50
50
  callEngine.on(TUICallEvent.KICKED_OUT, this._handleKickedOut, this); // 未开启多端登录时, 多端登录收到的被踢事件
51
+ // @ts-ignore
51
52
  callEngine.on(TUICallEvent.MESSAGE_SENT_BY_ME, this._messageSentByMe, this);
52
53
  // @ts-ignore
53
54
  TUICallEvent.CALL_MESSAGE && callEngine.on(TUICallEvent.CALL_MESSAGE, this._handleCallMessage, this); // call message card display event
@@ -75,6 +76,7 @@ export default class EngineEventHandler {
75
76
  callEngine.off(TUICallEvent.ON_USER_INVITING, this._handleOnUserInviting, this);
76
77
  callEngine.off(TUICallEvent.SDK_READY, this._handleSDKReady, this);
77
78
  callEngine.off(TUICallEvent.KICKED_OUT, this._handleKickedOut, this);
79
+ // @ts-ignore
78
80
  callEngine.off(TUICallEvent.MESSAGE_SENT_BY_ME, this._messageSentByMe, this);
79
81
  // @ts-ignore
80
82
  TUICallEvent.ON_USER_NETWORK_QUALITY_CHANGED && callEngine.off(TUICallEvent.ON_USER_NETWORK_QUALITY_CHANGED, this._handleNetworkQuality, this);
@@ -342,7 +344,7 @@ export default class EngineEventHandler {
342
344
  private async _handleUserVideoAvailable(event: any): Promise<any> {
343
345
  const { userID: userId, isVideoAvailable } = analyzeEventData(event);
344
346
  console.log(`${NAME.PREFIX}_handleUserVideoAvailable event data: ${JSON.stringify(event)}.`);
345
-
347
+
346
348
  this._setRemoteUserInfoAudioVideoAvailable(isVideoAvailable, NAME.VIDEO, userId);
347
349
  try {
348
350
  isVideoAvailable && await this._startRemoteView(userId);
@@ -393,7 +395,7 @@ export default class EngineEventHandler {
393
395
  remoteUserInfoList.push({ userId });
394
396
  TUIStore.update(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST, remoteUserInfoList);
395
397
  TUIStore.update(StoreName.CALL, NAME.REMOTE_USER_INFO_EXCLUDE_VOLUMN_LIST, remoteUserInfoList);
396
-
398
+
397
399
  const [userInfo] = await getRemoteUserProfile([userId], this._callService?.getTim());
398
400
  remoteUserInfoList = TUIStore.getData(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST);
399
401
  remoteUserInfoList.forEach((obj) => {
@@ -27,7 +27,7 @@ const TUIGlobal: ITUIGlobal = TuiGlobal.getInstance();
27
27
  const TUIStore: ITUIStore = TuiStore.getInstance();
28
28
  const uiDesign = UIDesign.getInstance();
29
29
  uiDesign.setTUIStore(TUIStore);
30
- const version = '4.5.3-beta.1';
30
+ const version = '4.5.8';
31
31
  import AIAssistant from './AIAssistant'; // 仅 web 支持 AI 实时字幕
32
32
  const frameWork = 'react';
33
33
  export { TUIGlobal, TUIStore, uiDesign };
@@ -52,10 +52,12 @@ export default class TUICallService {
52
52
  private _wasmReadyResolve;
53
53
  private _isInitialized = false;
54
54
  // Use an arrow function to keep the `this` binding when registering/unregistering the listener.
55
- private _handleAutoPlayFailed = () => {
55
+ private _handleAutoPlayFailed = (event: any) => {
56
56
  this._tuiCallEngine?.reportLog?.({
57
57
  name: 'TUICallkit.onAutoPlayFailed',
58
58
  });
59
+ // @ts-ignore
60
+ this._autoPlayResume = event?.resume; // webrtc 自动恢复播放失败需要自己调用
59
61
  TUIStore.update(StoreName.CALL, NAME.IS_SHOW_AUTO_PLAY_DIALOG, true);
60
62
  };
61
63
 
@@ -63,8 +65,8 @@ export default class TUICallService {
63
65
  console.log(`${NAME.PREFIX}version: ${version}`);
64
66
  this._wasmReadyPromise = new Promise(resolve => {
65
67
  this._wasmReadyResolve = resolve;
66
- });
67
- this._loadWasm();
68
+ });
69
+ this._loadWasm();
68
70
  this._watchTUIStore();
69
71
  this._engineEventHandler = EngineEventHandler.getInstance({ callService: this });
70
72
 
@@ -88,7 +90,7 @@ export default class TUICallService {
88
90
  return;
89
91
  }
90
92
  await this._wasmReadyPromise;
91
-
93
+
92
94
  if (!this._isInitialized) {
93
95
  await this._doInit(params);
94
96
  this._isInitialized = true;
@@ -116,6 +118,7 @@ export default class TUICallService {
116
118
  frameWork,
117
119
  // @ts-ignore
118
120
  language: 7,
121
+ // @ts-ignore
119
122
  callkitVersion: version,
120
123
  isFromChat: isFromChat || false,
121
124
  component,
@@ -212,7 +215,7 @@ export default class TUICallService {
212
215
  const response = await this._tuiCallEngine.calls(callsParams);
213
216
  await this._updateCallStoreAfterCall(userIDList, response);
214
217
  } catch (error: any) {
215
- handleModalError(error);
218
+ handleModalError(error, this._isFromChat);
216
219
  this._handleCallError(error, 'calls');
217
220
  }
218
221
  }
@@ -248,7 +251,7 @@ export default class TUICallService {
248
251
  // setLocalUserInfoAudioVideoAvailable(true, NAME.VIDEO);
249
252
  // }
250
253
  } catch (error) {
251
- handleModalError(error);
254
+ handleModalError(error, this._isFromChat);
252
255
  this._handleCallError(error, 'join');
253
256
  }
254
257
  }
@@ -350,9 +353,6 @@ export default class TUICallService {
350
353
  const { enable } = params;
351
354
  TUIStore.update(StoreName.CALL, NAME.IS_FORCE_USE_V2_API, !!enable);
352
355
  break;
353
- case 'setWaterMark':
354
- this._tuiCallEngine?.callExperimentalAPI?.(jsonStr);
355
- break;
356
356
  default:
357
357
  break;
358
358
  }
@@ -381,7 +381,7 @@ export default class TUICallService {
381
381
  error,
382
382
  });
383
383
  if (handleRepeatedCallError(error)) return;
384
- handleModalError(error);
384
+ handleModalError(error, this._isFromChat);
385
385
  noDevicePermissionToast(error, CallMediaType.AUDIO, this._tuiCallEngine);
386
386
  this._resetCallStore();
387
387
  }
@@ -412,7 +412,7 @@ export default class TUICallService {
412
412
  }
413
413
  });
414
414
  } catch (error) {
415
- handleModalError(error);
415
+ handleModalError(error, this._isFromChat);
416
416
  console.debug(error);
417
417
  }
418
418
  this._resetCallStore();
@@ -426,7 +426,7 @@ export default class TUICallService {
426
426
  this._chatCombine?.callTUIService({ message: response?.data?.message });
427
427
  }
428
428
  } catch (error) {
429
- handleModalError(error);
429
+ handleModalError(error, this._isFromChat);
430
430
  console.debug(error);
431
431
  }
432
432
  this._resetCallStore();
@@ -759,7 +759,7 @@ export default class TUICallService {
759
759
  private _resetCallStore() {
760
760
  this._cleanupAvoidRepeatCallState();
761
761
  this._bellContext?.stop();
762
-
762
+
763
763
  const oldStatusStr = generateStatusChangeText();
764
764
  this._stopTimer();
765
765
  // localUserInfo, language 在通话结束后不需要清除
@@ -1,4 +1,5 @@
1
1
  import { CallMediaType, CallStatus } from '../const/index';
2
+ import { checkDevicePermission } from '../utils/permission';
2
3
 
3
4
  export function initialUI() {
4
5
  // 收起键盘
@@ -34,7 +35,9 @@ export async function beforeCall(type: CallMediaType, that: any) {
34
35
  microphone: true,
35
36
  camera: type === CallMediaType.VIDEO,
36
37
  };
37
- const hasDevicePermission = await that._tuiCallEngine.deviceCheck(deviceMap); // miniProgram 检查设备权限
38
+ // `deviceCheck` is not implemented by @trtc/call-engine-lite-wx, so use the
39
+ // mini-program permission utility to pre-check microphone/camera access.
40
+ const hasDevicePermission = await checkDevicePermission(deviceMap); // miniProgram 检查设备权限
38
41
  return hasDevicePermission ? CallStatus.CALLING : CallStatus.IDLE;
39
42
  } catch (error) {
40
43
  console.debug(error);
@@ -1,12 +1,21 @@
1
1
  // @ts-nocheck
2
2
  import type { UIKitModalOptions, UIKitModalResult } from './type';
3
- import TUICallKitServer from '../CallService';
3
+ // Use the explicit `/index` path so the WeChat mini-program `require`, which
4
+ // only appends `.js` and does not resolve a directory to its `index.js`, can
5
+ // locate the module.
6
+ import TUICallKitServer from '../CallService/index';
7
+
8
+ // Native WeChat mini-program only exposes `wx`, while uniapp exposes `uni`.
9
+ // Fall back to `wx` when `uni` is not defined so the modal works in both.
10
+ const platform: any = typeof uni !== 'undefined'
11
+ ? uni
12
+ : (typeof wx !== 'undefined' ? wx : undefined);
4
13
 
5
14
  const URL_REGEX = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/i;
6
15
  const FULL_URL_REGEX = /(https?:\/\/[^\s]+)/g;
7
16
 
8
17
  function isDevEnvironment(): boolean {
9
- const accountInfo = uni.getAccountInfoSync?.();
18
+ const accountInfo = platform.getAccountInfoSync?.();
10
19
  const envVersion = accountInfo?.miniProgram?.envVersion;
11
20
  return envVersion === 'develop' || envVersion === 'trial';
12
21
  }
@@ -82,7 +91,7 @@ const createUIKitModal = (options: UIKitModalOptions): Promise<UIKitModalResult>
82
91
  const processedContent = processContent(options.content);
83
92
  const hasLink = !!url;
84
93
 
85
- uni.showModal({
94
+ platform.showModal({
86
95
  title: options.title || '',
87
96
  content: processedContent,
88
97
  cancelText: '取消',
@@ -91,10 +100,10 @@ const createUIKitModal = (options: UIKitModalOptions): Promise<UIKitModalResult>
91
100
  const action = res.confirm ? 'confirm' : 'cancel';
92
101
  if (res.confirm) {
93
102
  if (hasLink && url) {
94
- uni.setClipboardData({
103
+ platform.setClipboardData({
95
104
  data: url,
96
105
  success: () => {
97
- uni.showToast({ title: '链接已复制', icon: 'success' });
106
+ platform.showToast({ title: '链接已复制', icon: 'success' });
98
107
  },
99
108
  });
100
109
  }
@@ -145,6 +145,9 @@ export const en = {
145
145
  'error.10012': "Detected that the current page is under HTTP protocol. To ensure smooth access and full functionality of TUICallEngine SDK for production environment users, please use HTTPS protocol (or localhost) to access the audio/video application page. For details, please visit: <a href='https://web.sdk.qcloud.com/trtc/webrtc/v5/doc/zh-cn/tutorial-05-info-browser.html#h2-3'>View Documentation</a>",
146
146
  'error.10013': "Call failed: You have been blocked by the other party or you have blocked the other party",
147
147
  'error.10014': "Call initiation failed. User ID is invalid. Please confirm that the user is registered.",
148
+ 'error.10015': "Failed to enter the room because the TRTC service is not activated. Please go to the <a href='https://console.cloud.tencent.com/trtc'>console</a> to activate the TRTC service for your application",
149
+ 'error.10015.chat': "You are currently in the Chat + TUICallKit integrated scenario. Failed to enter the room because the TRTC service is not activated. Please go to the <a href='https://console.cloud.tencent.com/im/rtc-config'>IM console</a> to activate the TRTC service for your application",
150
+ 'error.10016': "Your application has not enabled the audio and video call (TUICallKit) capability. You can apply for a free trial in the <a href='https://console.cloud.tencent.com/im/detail'>console</a>, or purchase the <a href='https://buy.cloud.tencent.com/avc'>call capability package</a>. If you have any questions, please refer to the <a href='https://cloud.tencent.com/document/product/647/104662'>documentation</a>",
148
151
  'error': 'Error',
149
152
  // AI Subtitle Settings
150
153
  'ai-subtitle': 'AI Subtitle',
@@ -1,5 +1,5 @@
1
1
  export const ja_JP = {
2
- // 按钮文案
2
+ // 按钮文案
3
3
  'hangup': '通話終了',
4
4
  'reject': '拒否',
5
5
  'accept': '応答',
@@ -55,7 +55,7 @@ export const ja_JP = {
55
55
  'open camera': 'オープンカメラ',
56
56
  'close camera': 'カメラを閉じる',
57
57
  'open microphone': 'オープンマイク',
58
- 'close microphone': 'マイクを閉じる',
58
+ 'close microphone': 'マイクを閉じる',
59
59
  'camera enabled': 'カメラオン',
60
60
  'camera disabled': 'カメラオフ',
61
61
  'microphone enabled': 'マイクオン',
@@ -144,6 +144,8 @@ export const ja_JP = {
144
144
  'error.10012': "現在のページがHTTPプロトコル下にあることが検出されました。本番環境のユーザーがTUICallEngine SDKの全機能をスムーズに利用できるようにするため、音声・ビデオアプリケーションページにはHTTPSプロトコル(またはlocalhost)を使用してアクセスしてください。詳細については、<a href='https://web.sdk.qcloud.com/trtc/webrtc/v5/doc/zh-cn/tutorial-05-info-browser.html#h2-3'>ドキュメントを確認</a>してください",
145
145
  'error.10013': "通話失敗:相手にブロックされているか、または相手をブロックしています",
146
146
  'error.10014': "通話の開始に失敗しました。ユーザーIDが無効です。ユーザーが登録されていることを確認してください。",
147
+ 'error.10015.chat': "現在は Chat と TUICallKit の統合シナリオです。TRTC サービスが有効化されていないため、ルームへの入室に失敗しました。<a href='https://console.cloud.tencent.com/im/rtc-config'>IM コンソール</a>でアプリケーションの TRTC サービスを有効化してください",
148
+ 'error.10016': "あなたのアプリケーションは音声・ビデオ通話(TUICallKit)機能を有効にしていません。<a href='https://console.cloud.tencent.com/im/detail'>コンソール</a>で無料体験を申請するか、<a href='https://buy.cloud.tencent.com/avc'>通話機能パッケージ</a>を購入してください。ご不明な点がある場合は、<a href='https://cloud.tencent.com/document/product/647/104662'>ドキュメント</a>をご参照ください",
147
149
  'error': 'エラー',
148
150
  // AI Subtitle Settings
149
151
  'ai-subtitle': 'AI字幕',
@@ -140,6 +140,9 @@ export const zh = {
140
140
  'error.10012': "检测到当前页面正处于 http 协议下,为确保生产环境用户顺畅接入和体验 TUICallEngine SDK 的全部功能,请使用 https 协议(或 localhost)访问音视频应用页面。详情请前往:<a href='https://web.sdk.qcloud.com/trtc/webrtc/v5/doc/zh-cn/tutorial-05-info-browser.html#h2-3'>查看文档</a>",
141
141
  'error.10013': "呼叫失败:您已被对方拉黑或您拉黑了对方",
142
142
  'error.10014': "发起通话失败,用户 ID 无效,请确认该用户已注册。",
143
+ 'error.10015': "未开通 TRTC 服务导致进房失败,请前往<a href='https://console.cloud.tencent.com/trtc'>控制台</a>为您的应用开通 TRTC 服务",
144
+ 'error.10015.chat': "当前为 Chat 与 TUICallKit 融合场景,未开通 TRTC 服务导致进房失败,请前往 <a href='https://console.cloud.tencent.com/im/rtc-config'>IM 控制台</a>为您的应用开通 TRTC 服务",
145
+ 'error.10016': "您的应用还未开通音视频通话(TUICallKit)能力,您可以去<a href='https://console.cloud.tencent.com/im/detail'>控制台</a>申请免费体验,或购买<a href='https://buy.cloud.tencent.com/avc'>通话能力套餐包</a>,有疑问请参考<a href='https://cloud.tencent.com/document/product/647/104662'>相关文档</a>",
143
146
  'error': '错误',
144
147
  // AI Subtitle Settings
145
148
  'ai-subtitle': 'AI 字幕',
@@ -43,8 +43,18 @@ const IS_ANDROID = /Android/i.test(USER_AGENT);
43
43
  const IS_WIN_PHONE = /(?:Windows Phone)/.test(USER_AGENT);
44
44
  const IS_SYMBIAN = /(?:SymbianOS)/.test(USER_AGENT);
45
45
  const IS_IOS = /iPad/i.test(USER_AGENT) || /iPhone/i.test(USER_AGENT) || /iPod/i.test(USER_AGENT);
46
+ // HarmonyOS webview (e.g. ArkWeb inside a WeChat H5 page). The UA of every
47
+ // HarmonyOS form factor contains "OpenHarmony"/"HarmonyOS"/"ArkWeb", so the
48
+ // system keyword alone cannot tell phones/tablets from 2-in-1 PCs. HarmonyOS
49
+ // puts the device type in the UA parenthesis: "Phone" / "Tablet" / "PC", and
50
+ // mobile webviews additionally carry a "Mobile" token. Therefore only treat
51
+ // HarmonyOS phones/tablets (Phone/Tablet/Mobile and NOT PC) as H5, so that
52
+ // HarmonyOS 2-in-1 PCs still fall back to the desktop layout.
53
+ const IS_HARMONY = /OpenHarmony|HarmonyOS|ArkWeb/i.test(USER_AGENT);
54
+ const IS_HARMONY_PC = IS_HARMONY && /\bPC\b/i.test(USER_AGENT);
55
+ export const IS_HARMONY_WEBVIEW = IS_HARMONY && /Phone|Tablet|Mobile/i.test(USER_AGENT) && !IS_HARMONY_PC;
46
56
 
47
- export const IS_H5 = IS_ANDROID || IS_WIN_PHONE || IS_SYMBIAN || IS_IOS;
57
+ export const IS_H5 = IS_ANDROID || IS_WIN_PHONE || IS_SYMBIAN || IS_IOS || IS_HARMONY_WEBVIEW;
48
58
 
49
59
  export const IS_PC = IN_BROWSER && !IS_H5;
50
60
  export const IS_WIN = IS_PC && USER_AGENT.includes('Windows NT');