ipanel-rnapp-ajb-base 1.0.0

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 (155) hide show
  1. package/app/.local_dev/DemoPage.js +46 -0
  2. package/app/.local_dev/env.js +1 -0
  3. package/app/.local_dev/polyfill.js +83 -0
  4. package/app/App.js +485 -0
  5. package/app/api/homedApi.js +42 -0
  6. package/app/api/index.js +2 -0
  7. package/app/api/ipanelCloudApi.js +796 -0
  8. package/app/assets/img/add.png +0 -0
  9. package/app/assets/img/add_img.png +0 -0
  10. package/app/assets/img/album.png +0 -0
  11. package/app/assets/img/album2.png +0 -0
  12. package/app/assets/img/album3.png +0 -0
  13. package/app/assets/img/album@2x.png +0 -0
  14. package/app/assets/img/album@3x.png +0 -0
  15. package/app/assets/img/audioRecordBar.png +0 -0
  16. package/app/assets/img/bootom_bar_bg.png +0 -0
  17. package/app/assets/img/close.png +0 -0
  18. package/app/assets/img/computer.png +0 -0
  19. package/app/assets/img/confirm.png +0 -0
  20. package/app/assets/img/delete_pic.png +0 -0
  21. package/app/assets/img/disabled.png +0 -0
  22. package/app/assets/img/goBack.png +0 -0
  23. package/app/assets/img/goBack2.png +0 -0
  24. package/app/assets/img/ischeck.png +0 -0
  25. package/app/assets/img/launch_bg.png +0 -0
  26. package/app/assets/img/launch_bg_panyu.png +0 -0
  27. package/app/assets/img/launch_logo.png +0 -0
  28. package/app/assets/img/launch_logo_panyu.png +0 -0
  29. package/app/assets/img/launch_text.png +0 -0
  30. package/app/assets/img/launch_text_panyu.png +0 -0
  31. package/app/assets/img/link.png +0 -0
  32. package/app/assets/img/login_bg.png +0 -0
  33. package/app/assets/img/login_bg_new.png +0 -0
  34. package/app/assets/img/login_left.png +0 -0
  35. package/app/assets/img/login_right.png +0 -0
  36. package/app/assets/img/nocheck.png +0 -0
  37. package/app/assets/img/personal.png +0 -0
  38. package/app/assets/img/photo.png +0 -0
  39. package/app/assets/img/photo@2x.png +0 -0
  40. package/app/assets/img/photo@3x.png +0 -0
  41. package/app/assets/img/protocol_checked.png +0 -0
  42. package/app/assets/img/qiehuan.png +0 -0
  43. package/app/assets/img/scan_border_bottom_left.png +0 -0
  44. package/app/assets/img/scan_border_bottom_right.png +0 -0
  45. package/app/assets/img/scan_border_top_left.png +0 -0
  46. package/app/assets/img/scan_border_top_right.png +0 -0
  47. package/app/assets/img/scan_move.png +0 -0
  48. package/app/assets/img/szjt.png +0 -0
  49. package/app/assets/img/tab.png +0 -0
  50. package/app/assets/img/tykz.png +0 -0
  51. package/app/assets/img/update_bg.png +0 -0
  52. package/app/assets/img/video.png +0 -0
  53. package/app/assets/img/video@2x.png +0 -0
  54. package/app/assets/img/video@3x.png +0 -0
  55. package/app/assets/img/worker.png +0 -0
  56. package/app/assets/img/wx.png +0 -0
  57. package/app/assets/img/ykq.png +0 -0
  58. package/app/assets/img/zfb.png +0 -0
  59. package/app/base.js +342 -0
  60. package/app/components/VersionUpdateConfirm.js +117 -0
  61. package/app/components/common/AccordionCell/index.js +67 -0
  62. package/app/components/common/ActionPicker/BasicPicker.js +136 -0
  63. package/app/components/common/ActionPicker/index.js +106 -0
  64. package/app/components/common/AddressPicker/index.js +211 -0
  65. package/app/components/common/Card/index.js +19 -0
  66. package/app/components/common/Cell/index.js +381 -0
  67. package/app/components/common/CustomDialog/index.js +120 -0
  68. package/app/components/common/CustomTabBar/index.js +157 -0
  69. package/app/components/common/CustomTabBar_bak/TabBarInput.js +210 -0
  70. package/app/components/common/CustomTabBar_bak/index.js +832 -0
  71. package/app/components/common/DateTimingPicker/index.js +254 -0
  72. package/app/components/common/Dialog/Notify.js +36 -0
  73. package/app/components/common/Dialog/baseDialog.js +146 -0
  74. package/app/components/common/Dialog/index.js +113 -0
  75. package/app/components/common/Dialog/prompt.js +145 -0
  76. package/app/components/common/Dialog/quickSelect.js +54 -0
  77. package/app/components/common/Dialog/select.js +125 -0
  78. package/app/components/common/Dialog/styles.js +167 -0
  79. package/app/components/common/Loading/index.js +71 -0
  80. package/app/components/common/LoginType/index.js +171 -0
  81. package/app/components/common/LoginType/protocol.js +160 -0
  82. package/app/components/common/Notify/index.js +68 -0
  83. package/app/components/common/OnceTouchable/index.js +33 -0
  84. package/app/components/common/PaymentPicker/index.js +264 -0
  85. package/app/components/common/ProductOrderPicker/index.js +524 -0
  86. package/app/components/common/ScreenBackHeader/index.js +144 -0
  87. package/app/components/common/ScrollPicker/index.js +232 -0
  88. package/app/components/common/SelectPicker/index.js +171 -0
  89. package/app/components/common/SmsCodeInput/index.js +93 -0
  90. package/app/components/common/SmsCodeInput/indexNew.js +101 -0
  91. package/app/components/common/Steps/index.js +126 -0
  92. package/app/components/common/Tag/index.js +17 -0
  93. package/app/components/common/Toast/index.js +103 -0
  94. package/app/components/common/WeekDaysPicker/index.js +196 -0
  95. package/app/components/index.js +8 -0
  96. package/app/components/iot/AddDeviceActionSheet/index.js +934 -0
  97. package/app/components/iot/AddressActionSheet/index.js +91 -0
  98. package/app/components/iot/RoomActionSheet/index.js +205 -0
  99. package/app/components/iot/ViewDeviceActionSheet/index.js +834 -0
  100. package/app/components/sheets.js +30 -0
  101. package/app/eventBus/index.js +54 -0
  102. package/app/hooks/checkLogin.js +30 -0
  103. package/app/hooks/shopMessageManager.js +308 -0
  104. package/app/hooks/useAddress.js +179 -0
  105. package/app/hooks/useAddress2.js +587 -0
  106. package/app/hooks/useDebounceFn.js +6 -0
  107. package/app/hooks/useDynamicPackages.js +22 -0
  108. package/app/hooks/useKeyboard.js +25 -0
  109. package/app/hooks/useLatest.js +10 -0
  110. package/app/hooks/useMessageManager.js +368 -0
  111. package/app/hooks/useNavigationFocus.js +19 -0
  112. package/app/hooks/useUser.js +56 -0
  113. package/app/screens/BaseScreen.js +389 -0
  114. package/app/screens/CommonScreens/BindPhoneScreen/index.js +179 -0
  115. package/app/screens/CommonScreens/BossScreen/index.js +138 -0
  116. package/app/screens/CommonScreens/DeviceAnswerDetailScreen/index.js +50 -0
  117. package/app/screens/CommonScreens/DeviceFeedbackScreen/index.js +365 -0
  118. package/app/screens/CommonScreens/EditInvoiceTitleScreen/index.js +279 -0
  119. package/app/screens/CommonScreens/FamilyDetailScreen/index.js +421 -0
  120. package/app/screens/CommonScreens/InvoiceTitleListScreen/index.js +118 -0
  121. package/app/screens/CommonScreens/OperatorSelectScreen/index.js +315 -0
  122. package/app/screens/CommonScreens/PersonalScreen/index.js +348 -0
  123. package/app/screens/CommonScreens/ScanQRCodeScreen/index.js +407 -0
  124. package/app/screens/CommonScreens/TvAlbumScreen/index.js +407 -0
  125. package/app/screens/LoginScreen/OpenLogSheet.js +241 -0
  126. package/app/screens/LoginScreen/index.js +920 -0
  127. package/app/screens/LoginScreen/indexNew.js +1354 -0
  128. package/app/screens/ResePassword/index.js +364 -0
  129. package/app/screens/SbkScreen.js +19 -0
  130. package/app/screens/WebviewScreen.js +41 -0
  131. package/app/storage/index.js +166 -0
  132. package/app/utils/EventEmitter.js +43 -0
  133. package/app/utils/RootNavigation.js +32 -0
  134. package/app/utils/SBK_plugin/convert.js +90 -0
  135. package/app/utils/SBK_plugin/convertStatus.js +250 -0
  136. package/app/utils/SBK_plugin/eventProcess.js +339 -0
  137. package/app/utils/SBK_plugin/index.js +32 -0
  138. package/app/utils/SBK_plugin/ipanelDeviceToSbkDevice.js +68 -0
  139. package/app/utils/SBK_plugin/sbk_defs.js +191 -0
  140. package/app/utils/StyleComposite.js +37 -0
  141. package/app/utils/applyPermissions.js +251 -0
  142. package/app/utils/bundleUpdater.js +46 -0
  143. package/app/utils/common.js +380 -0
  144. package/app/utils/config.js +47 -0
  145. package/app/utils/errCodes.js +3 -0
  146. package/app/utils/homedData.js +57 -0
  147. package/app/utils/http.js +178 -0
  148. package/app/utils/notice.js +15 -0
  149. package/app/utils/priceConversion.js +30 -0
  150. package/app/utils/registerDialog.js +90 -0
  151. package/app/utils/scaleSize.js +12 -0
  152. package/app/utils/soundPlayer.js +85 -0
  153. package/bin/local-dev.js +7 -0
  154. package/index.js +8 -0
  155. package/package.json +18 -0
@@ -0,0 +1,832 @@
1
+ import React, { useState, useEffect, useRef, useCallback } from "react";
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ TouchableHighlight,
8
+ KeyboardAvoidingView,
9
+ Platform,
10
+ Dimensions,
11
+ Modal,
12
+ } from "react-native";
13
+ import { Icon, Image } from "@rneui/themed";
14
+ import { AudioRecorder, AudioUtils } from "react-native-audio";
15
+ import RNFS from "react-native-fs";
16
+
17
+ import TabBarInput from "./TabBarInput";
18
+ import { launchImageLibrary, launchCamera } from "react-native-image-picker";
19
+
20
+ import { baiduAsr } from "../../api";
21
+ import { MSG_TYPES, genMsg } from "../../utils/common";
22
+
23
+ const { eventBus, EVENTS, storage } = global.base;
24
+
25
+ const INPUT_TYPE = {
26
+ TEXT: "text",
27
+ VOICE: "voice",
28
+ };
29
+
30
+ let isChatTabActivedBeforeTouchStart = false;
31
+
32
+ let touchTimer;
33
+
34
+ let speakingStartTime = 0;
35
+
36
+ let isRecordTouching = false;
37
+ let isRecording = false;
38
+
39
+ // let isTouchingBottomArc = false;
40
+
41
+ let audioPath = AudioUtils.DocumentDirectoryPath + "/test.aac";
42
+
43
+ function CustomTabBar({
44
+ state,
45
+ descriptors,
46
+ navigation,
47
+ onInputSubmit,
48
+ onMediaSelect,
49
+ }) {
50
+ const inputRef = useRef();
51
+ const [showMoreArea, setShowMoreArea] = useState(false);
52
+ const [inputType, setInputType] = useState(INPUT_TYPE.VOICE);
53
+
54
+ const [speakingMaskVisible, setSpeakingMaskVisible] = useState(false);
55
+ const [touchPosition, setTouchPosition] = useState({});
56
+ const [speakingText, setSpeakingText] = useState("");
57
+ // 底部圆弧圆心距离屏幕左边的距离
58
+ const [arcCenterX, setArcCenterX] = useState(0);
59
+ // 底部圆弧圆心距离屏幕顶边的距离
60
+ const [arcCenterY, setArcCenterY] = useState(0);
61
+
62
+ const [isTouchingBottomArc, setIsTouchingBottomArc] = useState(true);
63
+
64
+ const getDistanceToArcCenter = useCallback(
65
+ (x, y) => {
66
+ return Math.sqrt(
67
+ Math.pow(Math.abs(arcCenterX - x), 2) +
68
+ Math.pow(Math.abs(arcCenterY - y), 2)
69
+ );
70
+ },
71
+ [arcCenterX, arcCenterY]
72
+ );
73
+
74
+ useEffect(() => {
75
+ setIsTouchingBottomArc(
76
+ typeof touchPosition.pageX !== "undefined"
77
+ ? getDistanceToArcCenter(touchPosition.pageX, touchPosition.pageY) <
78
+ bottomArvRadius
79
+ : true
80
+ );
81
+ }, [touchPosition]);
82
+
83
+ const handleBottomArcCenterCalc = useCallback(({ centerX, centerY }) => {
84
+ setArcCenterX(centerX);
85
+ setArcCenterY(centerY);
86
+ }, []);
87
+
88
+ const requestAudioPermission = useCallback(() => {
89
+ AudioRecorder.requestAuthorization().then((isAuthor) => {
90
+ // console.log('是否授权: ' + isAuthor);
91
+ if (!isAuthor) {
92
+ return global.toast.showToast(
93
+ "APP需要使用录音,请打开录音权限允许APP使用"
94
+ );
95
+ }
96
+ prepareRecordingPath(audioPath);
97
+ // 录音进展
98
+ AudioRecorder.onProgress = async (data) => {
99
+ // console.log('onProgress', data);
100
+ };
101
+ // 完成录音
102
+ // AudioRecorder.onFinished = async data => {
103
+ // // data 录音数据,可以在此存储需要传给接口的路径数据
104
+ // // console.log('onFinished', data);
105
+ // };
106
+ });
107
+ }, []);
108
+
109
+ const handleTouchMove = useCallback((touchPositon) => {
110
+ setTouchPosition(touchPositon);
111
+ }, []);
112
+
113
+ const onTouchChange = async (touchStatus) => {
114
+ isRecordTouching = touchStatus === true;
115
+
116
+ if (touchStatus) {
117
+ touchTimer = setTimeout(async () => {
118
+ setIsTouchingBottomArc(true);
119
+ setSpeakingText("");
120
+ isRecording = true;
121
+ // console.log("录音开始todo");
122
+
123
+ // 开始录音
124
+ prepareRecordingPath(audioPath);
125
+ try {
126
+ await AudioRecorder.startRecording();
127
+ } catch (err) {
128
+ console.log("start err", err);
129
+ }
130
+ setSpeakingMaskVisible(touchStatus);
131
+
132
+ console.log("开始录音", new Date().getTime());
133
+ speakingStartTime = new Date().getTime();
134
+
135
+ console.log("isRecordTouching", isRecordTouching);
136
+
137
+ if (!isRecordTouching) {
138
+ // 注意! startRecording是异步的,有可能在touchend后才触发!!会导致之后一直录音!!这种情况需要取消录音!
139
+ // 通过判断isRecordTouching的状态来判断当前是否正在录音触摸状态,如果没有在触摸,则即使录音onStart触发也需要立即停止
140
+ setSpeakingMaskVisible(false);
141
+ speakingStartTime = 0;
142
+ if (isChatTabActivedBeforeTouchStart) {
143
+ inputRef.current?.toggleInputType();
144
+ }
145
+ try {
146
+ AudioRecorder.stopRecording();
147
+ } catch (error) {
148
+ console.log("stop err", error);
149
+ }
150
+ }
151
+ }, 100);
152
+ } else {
153
+ clearTimeout(touchTimer);
154
+ if (isRecording) {
155
+ isRecording = false;
156
+ console.log("结束录音", new Date().getTime());
157
+
158
+ AudioRecorder.onFinished = async (data) => {
159
+ // data 录音数据,可以在此存储需要传给接口的路径数据
160
+ // console.log('onFinished', data);
161
+ if (new Date() - speakingStartTime >= 300) {
162
+ // 重置
163
+ speakingStartTime = 0;
164
+ // 发送录音结果
165
+ console.log("录制结束", isTouchingBottomArc ? "发送" : "取消");
166
+ if (isTouchingBottomArc) {
167
+ // 已录到语音
168
+ setTimeout(async () => {
169
+ let text = await transAudioToText(audioPath);
170
+ if (text) {
171
+ // 显示识别到的文本,用户确认后发送
172
+ setSpeakingText(text);
173
+ } else {
174
+ setSpeakingMaskVisible(false);
175
+ global.toast.showToast("未识别到语音内容,请再说一次吧");
176
+ }
177
+ });
178
+ } else {
179
+ // 取消
180
+ setSpeakingMaskVisible(false);
181
+ }
182
+ } else {
183
+ // 说话太短了
184
+ // 重置
185
+ speakingStartTime = 0;
186
+ setSpeakingMaskVisible(false);
187
+ }
188
+ };
189
+
190
+ if (speakingStartTime !== 0) {
191
+ try {
192
+ await AudioRecorder.stopRecording();
193
+ } catch (error) {
194
+ console.log("stop err", error);
195
+ }
196
+ }
197
+ } else {
198
+ if (isChatTabActivedBeforeTouchStart) {
199
+ inputRef.current?.toggleInputType();
200
+ }
201
+ }
202
+ }
203
+ };
204
+
205
+ const handleHideMoreArea = () => {
206
+ setShowMoreArea(false);
207
+ };
208
+
209
+ useEffect(() => {
210
+ requestAudioPermission();
211
+
212
+ eventBus.on(EVENTS.CUSTOM_TAB_BAR.HIDE_MORE_AREA, handleHideMoreArea);
213
+ return () => {
214
+ eventBus.off(EVENTS.CUSTOM_TAB_BAR.HIDE_MORE_AREA, handleHideMoreArea);
215
+ };
216
+ }, []);
217
+
218
+ const handleOpenAlbum = async () => {
219
+ const result = await launchImageLibrary({
220
+ mediaType: "mixed",
221
+ });
222
+ if (result.didCancel) {
223
+ console.log("cancel");
224
+ } else if (result.errorCode) {
225
+ console.log("error", result);
226
+ } else {
227
+ onMediaSelect && onMediaSelect(result.assets[0]);
228
+ }
229
+ setShowMoreArea(false);
230
+ };
231
+ const handleOpenCamara = async (mediaType) => {
232
+ const result = await launchCamera({
233
+ mediaType: mediaType,
234
+ });
235
+ if (result.didCancel) {
236
+ console.log("cancel");
237
+ } else if (result.errorCode) {
238
+ console.log("error", result);
239
+ } else {
240
+ console.log(result);
241
+ onMediaSelect && onMediaSelect(result.assets[0]);
242
+ }
243
+ setShowMoreArea(false);
244
+ };
245
+
246
+ const render = () => {
247
+ return (
248
+ <View style={styles.container}>
249
+ <View style={styles.innerContainer}>
250
+ {state.routes.map((route, index) => {
251
+ const { options } = descriptors[route.key];
252
+ const label =
253
+ options.tabBarLabel !== undefined
254
+ ? options.tabBarLabel
255
+ : options.title !== undefined
256
+ ? options.title
257
+ : route.name;
258
+
259
+ const isFocused = state.index === index;
260
+
261
+ const emitTabNavigate = () => {
262
+ const event = navigation.emit({
263
+ type: "tabPress",
264
+ target: route.key,
265
+ canPreventDefault: true,
266
+ });
267
+
268
+ if (route.name === "MainScreen") {
269
+ navigation.navigate("MainScreen", {
270
+ viewId: "MyChat",
271
+ });
272
+ } else if (!isFocused && !event.defaultPrevented) {
273
+ // The `merge: true` option makes sure that the params inside the tab screen are preserved
274
+ navigation.navigate({ name: route.name, merge: true });
275
+ }
276
+ };
277
+
278
+ const onLongPress = () => {
279
+ navigation.emit({
280
+ type: "tabLongPress",
281
+ target: route.key,
282
+ });
283
+ };
284
+
285
+ const onMenuPress = (e) => {
286
+ if (route.name === "ShopIndexScreen") {
287
+ global.dialog.confirm({
288
+ title: "升级中,敬请期待",
289
+ confirmButtonText: "确定",
290
+ confirmCallback: async () => {},
291
+ });
292
+ } else {
293
+ emitTabNavigate(e);
294
+ inputRef.current?.blur();
295
+ }
296
+ };
297
+
298
+ if (index === global.base.smartHomeTabIndex) {
299
+ const onResponderGrant = () => {
300
+ // console.log("开始触摸");
301
+ isChatTabActivedBeforeTouchStart =
302
+ state.index === global.base.smartHomeTabIndex;
303
+ emitTabNavigate();
304
+ onTouchChange(true);
305
+ };
306
+ const onResponderMove = (event) => {
307
+ // console.log(
308
+ // '触摸移动',
309
+ // event.nativeEvent.pageX,
310
+ // event.nativeEvent.pageY,
311
+ // );
312
+ handleTouchMove({
313
+ pageX: event.nativeEvent.pageX,
314
+ pageY: event.nativeEvent.pageY,
315
+ });
316
+ };
317
+ const onResponderRelease = () => {
318
+ // console.log("触摸结束");
319
+ onTouchChange(false);
320
+ // 重置touchPosition
321
+ handleTouchMove({});
322
+ };
323
+ const onInputTypeChange = (type) => {
324
+ if (type === "voice") {
325
+ emitTabNavigate();
326
+ }
327
+ setInputType(type);
328
+ };
329
+ const onInputFocus = () => {
330
+ if (!showMoreArea) {
331
+ emitTabNavigate();
332
+ }
333
+ };
334
+ const onInputBlur = () => {
335
+ inputRef.current?.toggleInputType();
336
+ };
337
+ const onMoreBtnPress = () => {
338
+ if (!showMoreArea) {
339
+ emitTabNavigate();
340
+ setTimeout(() => {
341
+ setShowMoreArea(true);
342
+ }, 100);
343
+ } else {
344
+ setShowMoreArea(false);
345
+ }
346
+ };
347
+
348
+ const focusInputBarStyle = {};
349
+ if (inputType === INPUT_TYPE.TEXT) {
350
+ focusInputBarStyle.width = "100%";
351
+ } else {
352
+ focusInputBarStyle.flex = 1;
353
+ }
354
+
355
+ return (
356
+ <TabBarInput
357
+ style={[focusInputBarStyle]}
358
+ showMoreArea={showMoreArea}
359
+ key={index}
360
+ ref={inputRef}
361
+ onResponderGrant={onResponderGrant}
362
+ onResponderMove={onResponderMove}
363
+ onResponderRelease={onResponderRelease}
364
+ onInputTypeChange={onInputTypeChange}
365
+ onInputFocus={onInputFocus}
366
+ onInputBlur={onInputBlur}
367
+ onInputSubmit={onInputSubmit}
368
+ onMoreBtnPress={onMoreBtnPress}
369
+ />
370
+ );
371
+ }
372
+
373
+ const focusNavBtnTextStyle = {
374
+ color: isFocused ? "#EA6000" : "#333",
375
+ fontSize: inputType === INPUT_TYPE.TEXT ? 0 : 18,
376
+ };
377
+
378
+ return (
379
+ <TouchableOpacity
380
+ accessibilityRole="button"
381
+ accessibilityState={isFocused ? { selected: true } : {}}
382
+ onPress={onMenuPress}
383
+ onLongPress={onLongPress}
384
+ activeOpacity={0.8}
385
+ style={styles.navBtn}
386
+ key={index}
387
+ >
388
+ <Text style={[styles.navBtnText, focusNavBtnTextStyle]}>
389
+ {label}
390
+ </Text>
391
+ </TouchableOpacity>
392
+ );
393
+ })}
394
+ </View>
395
+
396
+ {showMoreArea && (
397
+ <View style={styles.moreArea}>
398
+ <View style={styles.featureItem}>
399
+ <TouchableHighlight
400
+ onPress={handleOpenAlbum}
401
+ activeOpacity={0.9}
402
+ underlayColor="#fcfcfc"
403
+ >
404
+ <View style={styles.featureItemInner}>
405
+ <View style={styles.featureIcon}>
406
+ <Image
407
+ source={require("../../../assets/img/album.png")}
408
+ style={styles.featureIconImg}
409
+ />
410
+ </View>
411
+ <Text style={styles.featureName}>相册</Text>
412
+ </View>
413
+ </TouchableHighlight>
414
+ </View>
415
+
416
+ <View style={styles.featureItem}>
417
+ <TouchableHighlight
418
+ onPress={() => handleOpenCamara("photo")}
419
+ activeOpacity={0.9}
420
+ underlayColor="#fcfcfc"
421
+ >
422
+ <View style={styles.featureItemInner}>
423
+ <View style={styles.featureIcon}>
424
+ <Image
425
+ source={require("../../../assets/img/photo.png")}
426
+ style={styles.featureIconImg}
427
+ />
428
+ </View>
429
+ <Text style={styles.featureName}>拍照</Text>
430
+ </View>
431
+ </TouchableHighlight>
432
+ </View>
433
+
434
+ <View style={styles.featureItem}>
435
+ <TouchableHighlight
436
+ onPress={() => handleOpenCamara("video")}
437
+ activeOpacity={0.9}
438
+ underlayColor="#fcfcfc"
439
+ >
440
+ <View style={styles.featureItemInner}>
441
+ <View style={styles.featureIcon}>
442
+ <Image
443
+ source={require("../../assets/img/video.png")}
444
+ style={styles.featureIconImg}
445
+ />
446
+ </View>
447
+ <Text style={styles.featureName}>短视频</Text>
448
+ </View>
449
+ </TouchableHighlight>
450
+ </View>
451
+ </View>
452
+ )}
453
+
454
+ <SpeakingMask
455
+ speakingMaskVisible={speakingMaskVisible}
456
+ isTouchingBottomArc={isTouchingBottomArc}
457
+ speakingText={speakingText}
458
+ onBottomArcCenterCalc={handleBottomArcCenterCalc}
459
+ onSubmitCancel={() => setSpeakingMaskVisible(false)}
460
+ onSubmitVoice={() => {
461
+ setSpeakingMaskVisible(false);
462
+ // 发送原语音--待开发
463
+ console.log(audioPath);
464
+ }}
465
+ onSubmitText={(text) => {
466
+ setSpeakingMaskVisible(false);
467
+ // 发送文本
468
+ onInputSubmit(text);
469
+ }}
470
+ onEditText={(text) => {
471
+ setSpeakingMaskVisible(false);
472
+ global.dialog.prompt({
473
+ title: "修改文字并发送",
474
+ input: text,
475
+ confirmButtonText: "确定",
476
+ confirmCallback: (val) => {
477
+ // 发送文本
478
+ onInputSubmit(val);
479
+ },
480
+ cancelButtonText: "取消",
481
+ cancelCallback: () => {},
482
+ });
483
+ }}
484
+ />
485
+ </View>
486
+ );
487
+ };
488
+
489
+ return Platform.OS === "ios" ? (
490
+ <KeyboardAvoidingView behavior="position" style={styles.container}>
491
+ {render()}
492
+ </KeyboardAvoidingView>
493
+ ) : (
494
+ render()
495
+ );
496
+ }
497
+
498
+ function prepareRecordingPath(path) {
499
+ const option = {
500
+ SampleRate: 16000, //采样率
501
+ Channels: 1, //通道
502
+ AudioQuality: "High", //音质
503
+ AudioEncoding: "aac", //音频编码
504
+ // OutputFormat: 'mpeg_4', //输出格式
505
+ MeteringEnabled: false, //是否计量
506
+ MeasurementMode: false, //测量模式
507
+ AudioEncodingBitRate: 96000, //音频编码比特率
508
+ IncludeBase64: true, //是否是base64格式
509
+ AudioSource: 0, //音频源
510
+ };
511
+ AudioRecorder.prepareRecordingAtPath(path, option);
512
+ }
513
+
514
+ function SpeakingMask({
515
+ speakingMaskVisible,
516
+ isTouchingBottomArc,
517
+ speakingText,
518
+ onBottomArcCenterCalc,
519
+ onSubmitCancel,
520
+ onSubmitVoice,
521
+ onSubmitText,
522
+ onEditText,
523
+ }) {
524
+ const handleBottomArcLayout = useCallback(({ nativeEvent: { layout } }) => {
525
+ let centerX = Dimensions.get("window").width / 2;
526
+ let centerY = layout.y + bottomArvRadius;
527
+
528
+ onBottomArcCenterCalc({
529
+ centerX,
530
+ centerY,
531
+ });
532
+ }, []);
533
+
534
+ return (
535
+ <Modal
536
+ transparent={true}
537
+ statusBarTranslucent={true}
538
+ visible={speakingMaskVisible}
539
+ >
540
+ <View style={styles.speakingMask}>
541
+ <View style={styles.audio2textContent}>
542
+ <Text style={styles.audioText}>{speakingText}</Text>
543
+ {!!speakingText && (
544
+ <Icon
545
+ style={styles.audioTextEditBtn}
546
+ name="mode-edit"
547
+ type="material"
548
+ size={30}
549
+ color="#ccc"
550
+ onPress={() => onEditText(speakingText)}
551
+ />
552
+ )}
553
+ </View>
554
+
555
+ {speakingText ? (
556
+ <View style={styles.recordButtons}>
557
+ <View style={styles.recordConfirmButton}>
558
+ <TouchableOpacity activeOpacity={0.8} onPress={onSubmitCancel}>
559
+ <View style={styles.recorConfirmBtn}>
560
+ <Icon
561
+ name="return-down-back-outline"
562
+ type="ionicon"
563
+ size={40}
564
+ color="#fff"
565
+ />
566
+ <Text style={styles.recorConfirmBtnText}>取消</Text>
567
+ </View>
568
+ </TouchableOpacity>
569
+ </View>
570
+ <View style={styles.recordConfirmButton}>
571
+ {/* <TouchableOpacity activeOpacity={0.8} onPress={onSubmitVoice}>
572
+ <View style={styles.recorConfirmBtn}>
573
+ <Icon
574
+ name="keyboard-voice"
575
+ type="material"
576
+ size={40}
577
+ color="#fff"
578
+ />
579
+ <Text style={styles.recorConfirmBtnText}>发送原语音</Text>
580
+ </View>
581
+ </TouchableOpacity> */}
582
+ </View>
583
+ <View style={styles.recordConfirmButton}>
584
+ <TouchableOpacity
585
+ activeOpacity={0.8}
586
+ onPress={() => onSubmitText(speakingText)}
587
+ >
588
+ <View style={styles.recorConfirmBtn}>
589
+ <Icon
590
+ name="md-send-sharp"
591
+ type="ionicon"
592
+ size={44}
593
+ color="#fff"
594
+ />
595
+ </View>
596
+ </TouchableOpacity>
597
+ </View>
598
+ </View>
599
+ ) : (
600
+ <View style={styles.recordButtons}>
601
+ <View style={styles.recordButtonLeft}>
602
+ <View style={styles.leftBtn}>
603
+ {!isTouchingBottomArc && (
604
+ <Text style={styles.cancelRecordLabel}>松开 取消</Text>
605
+ )}
606
+ <Icon
607
+ style={styles.cancelRecordBtn}
608
+ name="cancel"
609
+ type="material"
610
+ size={60}
611
+ color={isTouchingBottomArc ? "#313131" : "#ededed"}
612
+ />
613
+ </View>
614
+ </View>
615
+ </View>
616
+ )}
617
+
618
+ {!speakingText && (
619
+ <View
620
+ style={[
621
+ styles.bottomArc,
622
+ isTouchingBottomArc && styles.activeBottomArc,
623
+ ]}
624
+ onLayout={handleBottomArcLayout}
625
+ >
626
+ {/* {isTouchingBottomArc && <Text style={styles.asrLabel}>实时转文字</Text>} */}
627
+ <View style={styles.iconSaying}>
628
+ <Icon
629
+ name="keyboard-voice"
630
+ type="material"
631
+ size={40}
632
+ color="#111"
633
+ />
634
+ </View>
635
+ </View>
636
+ )}
637
+ </View>
638
+ </Modal>
639
+ );
640
+ }
641
+
642
+ // 录音界面底部圆弧半径
643
+ const bottomArvRadius = 500;
644
+
645
+ async function transAudioToText(audioPath) {
646
+ const activeAddr = await storage.get("activeAddr");
647
+ const fileStat = await RNFS.stat(audioPath);
648
+ const base64 = await RNFS.readFile(audioPath, "base64");
649
+ // console.log(fileStat);
650
+ const result = await baiduAsr(activeAddr.user_id, fileStat.size, base64);
651
+ let text = "";
652
+ if (result.err_no === 0) {
653
+ text = result.result[0];
654
+ } else {
655
+ console.log("audio trans err", result);
656
+ }
657
+
658
+ // 去掉末尾句号
659
+ if (text.endsWith("。")) {
660
+ text = text.slice(0, -1);
661
+ }
662
+
663
+ // 去掉其它字符,只保留汉字
664
+ // const matchChinese = text.match(/[\u4e00-\u9fa5]+/g);
665
+ // text = matchChinese ? matchChinese.join('') : '';
666
+
667
+ console.log("text", text);
668
+
669
+ return text;
670
+ }
671
+
672
+ const MORE_AREA_HEIGHT = 120;
673
+
674
+ const styles = StyleSheet.create({
675
+ container: {
676
+ position: "relative",
677
+ // borderTopWidth: 1,
678
+ // borderTopColor: "#efefef",
679
+ backgroundColor: "#fff",
680
+ maxHeight: 300,
681
+ },
682
+ innerContainer: {
683
+ flexDirection: "row",
684
+ // borderTopWidth: 1,
685
+ // borderTopColor: "#efefef",
686
+ backgroundColor: "#fff",
687
+ maxHeight: 300,
688
+ paddingVertical: 5,
689
+ },
690
+ navBtn: {
691
+ flex: 1,
692
+ alignItems: "center",
693
+ justifyContent: "center",
694
+ minHeight: 50,
695
+ },
696
+ navBtnText: {
697
+ color: "#333",
698
+ fontSize: 18,
699
+ fontWeight: "bold",
700
+ },
701
+ moreArea: {
702
+ height: MORE_AREA_HEIGHT,
703
+ flexDirection: "row",
704
+ },
705
+ featureItem: {
706
+ width: "20%",
707
+ height: "100%",
708
+ alignItems: "center",
709
+ justifyContent: "center",
710
+ },
711
+ featureItemInner: {
712
+ alignItems: "center",
713
+ justifyContent: "center",
714
+ },
715
+ featureIcon: {
716
+ backgroundColor: "#fff",
717
+ width: 50,
718
+ height: 50,
719
+ marginBottom: 5,
720
+ borderRadius: 5,
721
+ alignItems: "center",
722
+ justifyContent: "center",
723
+ borderWidth: 0.5,
724
+ borderStyle: "dashed",
725
+ borderColor: "#aaa",
726
+ },
727
+ featureIconImg: {
728
+ width: 49,
729
+ height: 49,
730
+ },
731
+ featureName: {
732
+ textAlign: "center",
733
+ },
734
+ // speakMask
735
+ speakingMask: {
736
+ flex: 1,
737
+ backgroundColor: "rgba(0,0,0,0.6)",
738
+ },
739
+ audio2textContent: {
740
+ position: "absolute",
741
+ bottom: 330,
742
+ left: 0,
743
+ right: 0,
744
+ paddingHorizontal: 60,
745
+ flexDirection: "row",
746
+ alignItems: "center",
747
+ },
748
+ audioText: {
749
+ flex: 1,
750
+ color: "#e5f752",
751
+ fontSize: 24,
752
+ },
753
+ audioTextEditBtn: {
754
+ marginLeft: 10,
755
+ },
756
+ recordButtons: {
757
+ position: "absolute",
758
+ bottom: 200,
759
+ left: 0,
760
+ right: 0,
761
+ flexDirection: "row",
762
+ },
763
+ recordButtonLeft: {
764
+ width: "50%",
765
+ alignItems: "flex-start",
766
+ },
767
+ leftBtn: {
768
+ paddingLeft: "30%",
769
+ },
770
+ recordConfirmButton: {
771
+ flex: 1,
772
+ alignItems: "center",
773
+ justifyContent: "center",
774
+ },
775
+ recorConfirmBtnText: {
776
+ fontSize: 14,
777
+ color: "#fff",
778
+ textAlign: "center",
779
+ },
780
+ cancelRecordLabel: {
781
+ fontSize: 16,
782
+ color: "#fff",
783
+ },
784
+ cancelRecordBtn: {
785
+ transform: [
786
+ {
787
+ rotate: "-30deg",
788
+ },
789
+ ],
790
+ },
791
+ bottomArc: {
792
+ width: bottomArvRadius * 2,
793
+ height: bottomArvRadius * 2,
794
+ borderRadius: bottomArvRadius,
795
+ backgroundColor: "#313131",
796
+ position: "absolute",
797
+ top: "100%",
798
+ left: "50%",
799
+ transform: [
800
+ {
801
+ translateX: -bottomArvRadius,
802
+ },
803
+ ],
804
+ marginTop: -150,
805
+ },
806
+ activeBottomArc: {
807
+ backgroundColor: "#e9e9e9",
808
+ },
809
+ asrLabel: {
810
+ position: "absolute",
811
+ top: 0,
812
+ left: 0,
813
+ width: "100%",
814
+ textAlign: "center",
815
+ color: "#fff",
816
+ fontSize: 18,
817
+ transform: [
818
+ {
819
+ translateY: -30,
820
+ },
821
+ ],
822
+ },
823
+ iconSaying: {
824
+ position: "absolute",
825
+ top: 55,
826
+ left: 0,
827
+ width: "100%",
828
+ textAlign: "center",
829
+ },
830
+ });
831
+
832
+ export default CustomTabBar;