From 5462cf5abe0224aad396ef46e7b92daecb9154c5 Mon Sep 17 00:00:00 2001 From: Caiyanpeng Date: Thu, 25 Dec 2025 16:16:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=E8=AE=BE=E8=AE=A1=E7=A8=BF=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=8C=E4=B8=AD=E8=8B=B1=E6=96=87=EF=BC=8Cios?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E9=97=AE=E9=A2=98=EF=BC=8Cstatusbar=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.tsx | 32 +- android/app/build.gradle | 4 +- android/app/src/main/AndroidManifest.xml | 3 +- .../app/src/main/res/values-zh/strings.xml | 3 + android/app/src/main/res/values-zh/styles.xml | 9 + android/app/src/main/res/values/strings.xml | 2 +- ios/Podfile | 2 + ios/dfuapp/Info.plist | 4 +- ios/dfuapp/en.lproj/InfoPlist.strings | 2 + ios/dfuapp/zh-Hans.lproj/InfoPlist.strings | 2 + package.json | 8 + src/DfuScreen.tsx | 105 ++- src/HomeScreen.tsx | 47 +- src/InfoScreen.tsx | 862 +++++++++--------- src/PrivacyScreen.tsx | 87 +- src/ScanScreen.tsx | 24 +- src/SettingScreen.tsx | 143 +++ src/SplashScreen.tsx | 4 +- src/component/LanguageModal.tsx | 131 +++ src/component/MyHeader.tsx | 67 ++ src/component/MyStatusbar.tsx | 41 + src/helper/helper.js | 106 +++ src/helper/myToast.tsx | 37 + src/helper/pxToDp.js | 14 + src/i18n/en-US.ts | 100 -- src/i18n/index.ts | 71 ++ src/i18n/locales/en.json | 120 +++ src/i18n/locales/zh.json | 120 +++ src/i18n/zh-CN.ts | 109 --- src/img/Return.png | Bin 0 -> 858 bytes src/img/Return2.png | Bin 0 -> 729 bytes src/img/Search.png | Bin 0 -> 76917 bytes src/img/Settings.png | Bin 0 -> 1342 bytes src/img/_PrivacyAgreement.png | Bin 0 -> 1698 bytes src/img/_SoftwareLanguage.png | Bin 0 -> 2060 bytes src/types/RootNavigationProp.tsx | 4 + yarn.lock | 353 ++++--- 37 files changed, 1641 insertions(+), 975 deletions(-) create mode 100644 android/app/src/main/res/values-zh/strings.xml create mode 100644 android/app/src/main/res/values-zh/styles.xml create mode 100644 ios/dfuapp/en.lproj/InfoPlist.strings create mode 100644 ios/dfuapp/zh-Hans.lproj/InfoPlist.strings create mode 100644 src/SettingScreen.tsx create mode 100644 src/component/LanguageModal.tsx create mode 100644 src/component/MyHeader.tsx create mode 100644 src/component/MyStatusbar.tsx create mode 100644 src/helper/helper.js create mode 100644 src/helper/myToast.tsx create mode 100644 src/helper/pxToDp.js delete mode 100644 src/i18n/en-US.ts create mode 100644 src/i18n/index.ts create mode 100644 src/i18n/locales/en.json create mode 100644 src/i18n/locales/zh.json delete mode 100644 src/i18n/zh-CN.ts create mode 100644 src/img/Return.png create mode 100644 src/img/Return2.png create mode 100644 src/img/Search.png create mode 100644 src/img/Settings.png create mode 100644 src/img/_PrivacyAgreement.png create mode 100644 src/img/_SoftwareLanguage.png create mode 100644 src/types/RootNavigationProp.tsx diff --git a/App.tsx b/App.tsx index 24207aa..b165b62 100644 --- a/App.tsx +++ b/App.tsx @@ -8,6 +8,9 @@ import InfoScreen from "./src/InfoScreen"; import DfuScreen from "./src/DfuScreen"; import PrivacyScreen from "./src/PrivacyScreen"; import SplashScreen from "./src/SplashScreen"; // ✅ 新增启动页 +import pxToDp from "./src/helper/pxToDp"; +import SettingScreen from "./src/SettingScreen"; +import './src/i18n' export type RootStackParamList = { Splash: undefined; @@ -16,6 +19,7 @@ export type RootStackParamList = { Info: { peripheral: any }; Dfu: { deviceId: string; name: string; firmware: string }; Privacy: undefined; + Setting: undefined; }; const Stack = createNativeStackNavigator(); @@ -25,13 +29,9 @@ export default function App() { + animation : 'slide_from_right' + }}> {/* 启动页(无标题) */} {/* 其他页面默认显示标题栏 */} + diff --git a/android/app/build.gradle b/android/app/build.gradle index c26acfb..11fda38 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -82,8 +82,8 @@ android { applicationId "com.zhixingpai.powerfundfuapp" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0.0" + versionCode 2 + versionName "1.0.1" } signingConfigs { debug { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index fb78f39..8527a8d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -17,7 +17,8 @@ android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" - android:exported="true"> + android:exported="true" + android:screenOrientation="portrait"> diff --git a/android/app/src/main/res/values-zh/strings.xml b/android/app/src/main/res/values-zh/strings.xml new file mode 100644 index 0000000..40d980c --- /dev/null +++ b/android/app/src/main/res/values-zh/strings.xml @@ -0,0 +1,3 @@ + + POWERFUN设置 + diff --git a/android/app/src/main/res/values-zh/styles.xml b/android/app/src/main/res/values-zh/styles.xml new file mode 100644 index 0000000..7ba83a2 --- /dev/null +++ b/android/app/src/main/res/values-zh/styles.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 40d980c..e3d0857 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - POWERFUN设置 + POWERFUN Settings diff --git a/ios/Podfile b/ios/Podfile index f79d687..4e817c4 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -20,6 +20,8 @@ end target 'dfuapp' do config = use_native_modules! + pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons' + use_react_native!( :path => config[:reactNativePath], # An absolute path to your application root. diff --git a/ios/dfuapp/Info.plist b/ios/dfuapp/Info.plist index 21ebf9b..a943636 100644 --- a/ios/dfuapp/Info.plist +++ b/ios/dfuapp/Info.plist @@ -48,10 +48,10 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance + ITSAppUsesNonExemptEncryption + diff --git a/ios/dfuapp/en.lproj/InfoPlist.strings b/ios/dfuapp/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..77f60b2 --- /dev/null +++ b/ios/dfuapp/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +CFBundleDisplayName = "POWERFUN Settings"; +CFBundleName = "POWERFUN Settings"; \ No newline at end of file diff --git a/ios/dfuapp/zh-Hans.lproj/InfoPlist.strings b/ios/dfuapp/zh-Hans.lproj/InfoPlist.strings new file mode 100644 index 0000000..9bc44c0 --- /dev/null +++ b/ios/dfuapp/zh-Hans.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +CFBundleDisplayName = "POWERFUN设置"; +CFBundleName = "POWERFUN设置"; \ No newline at end of file diff --git a/package.json b/package.json index 8667c78..56895fa 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "scripts": { "android": "react-native run-android", + "clean-a": "cd android && gradlew clean", "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", @@ -11,18 +12,25 @@ "build-a": "set NODE_OPTIONS=--openssl-legacy-provider && cd android&&gradlew assembleRelease" }, "dependencies": { + "@react-native-async-storage/async-storage": "^2.2.0", "@react-native/codegen": "0.81.4", "@react-native/new-app-screen": "0.81.4", "@react-navigation/native": "^7.1.17", "@react-navigation/native-stack": "^7.3.26", "@systemic-games/react-native-bluetooth-le": "^1.3.0", "@systemic-games/react-native-nordic-nrf5-dfu": "^1.3.0", + "@types/lodash": "^4.17.21", "base-64": "^1.0.0", + "i18next": "^25.7.3", "react": "19.1.0", + "react-i18next": "^16.5.0", "react-native": "0.81.4", + "react-native-device-info": "^15.0.1", "react-native-fs": "^2.20.0", "react-native-safe-area-context": "^5.6.1", "react-native-screens": "^4.16.0", + "react-native-status-bar-height": "^2.6.0", + "react-native-toast-message": "^2.3.3", "react-native-vector-icons": "^10.3.0" }, "devDependencies": { diff --git a/src/DfuScreen.tsx b/src/DfuScreen.tsx index a59913c..25b8c6a 100644 --- a/src/DfuScreen.tsx +++ b/src/DfuScreen.tsx @@ -4,6 +4,9 @@ import { NativeStackScreenProps } from "@react-navigation/native-stack"; import { RootStackParamList } from "../App"; import RNFS from "react-native-fs"; import { startDfu, DfuProgressEvent, DfuStateEvent } from "@systemic-games/react-native-nordic-nrf5-dfu"; +import { useTranslation } from 'react-i18next'; +import MyStatusbar from "./component/MyStatusbar"; +import MyHeader from "./component/MyHeader"; type Props = NativeStackScreenProps; @@ -14,33 +17,34 @@ interface DeviceInfo { } export default function DfuScreen({ route, navigation }: Props) { + const { t } = useTranslation(); const { deviceId, name, firmware: deviceFirmware } = route.params; const [progress, setProgress] = useState(0); - const [state, setState] = useState("准备中..."); + const [state, setState] = useState(t('dfu.preparing')); const [error, setError] = useState(); - const [latestVersion, setLatestVersion] = useState("读取中..."); + const [latestVersion, setLatestVersion] = useState(t('dfu.reading')); const [isDfuRunning, setIsDfuRunning] = useState(false); const mapDfuStateToChinese = (state: string): string => { switch (state) { - case "connecting": return "连接中…"; - case "starting": return "初始化中…"; - case "enablingDfuMode": return "启用 DFU 模式…"; - case "uploading": return "上传固件中…"; - case "validating": return "校验固件…"; - case "disconnecting": return "断开连接…"; - case "completed": return "升级完成"; - case "aborted": return "已取消"; + case "connecting": return t('dfu.stateConnecting'); + case "starting": return t('dfu.stateStarting'); + case "enablingDfuMode": return t('dfu.stateEnablingDfuMode'); + case "uploading": return t('dfu.stateUploading'); + case "validating": return t('dfu.stateValidating'); + case "disconnecting": return t('dfu.stateDisconnecting'); + case "completed": return t('dfu.stateCompleted'); + case "aborted": return t('dfu.stateAborted'); case "failed": - case "dfu_failed": return "升级失败"; - case "initializing": return "启动中…"; - case "errored": return "升级出错!"; + case "dfu_failed": return t('dfu.stateFailed'); + case "initializing": return t('dfu.stateInitializing'); + case "errored": return t('dfu.stateErrored'); default: return state; } }; - + // ✅ 拦截所有导航返回(iOS + Android) useEffect(() => { const unsubscribe = navigation.addListener("beforeRemove", (e) => { @@ -48,13 +52,13 @@ export default function DfuScreen({ route, navigation }: Props) { // 阻止返回 e.preventDefault(); - Alert.alert("请稍候", "正在升级,请勿返回或关闭应用!"); + Alert.alert(t('dfu.pleaseWait'), t('dfu.doNotReturn')); }); return unsubscribe; }, [navigation, isDfuRunning]); - + useEffect(() => { @@ -76,8 +80,8 @@ export default function DfuScreen({ route, navigation }: Props) { const deviceInfo = manifest.devices.find(d => d.hardware === deviceHW); if (!deviceInfo) { setIsDfuRunning(false); - Alert.alert("无法升级", `未找到硬件版本 ${deviceHW} 的固件`, [ - { text: "确认", onPress: () => navigation.goBack() }, + Alert.alert(t('dfu.cannotUpgrade'), t('dfu.hardwareNotFound', { hardware: deviceHW }), [ + { text: t('dfu.confirm'), onPress: () => navigation.goBack() }, ]); return; } @@ -89,8 +93,8 @@ export default function DfuScreen({ route, navigation }: Props) { if (latestFW <= deviceFW) { setIsDfuRunning(false); - Alert.alert("无需升级", "已是最新固件,无需升级", [ - { text: "确认", onPress: () => navigation.goBack() }, + Alert.alert(t('dfu.noNeedUpgrade'), t('dfu.alreadyLatest'), [ + { text: t('dfu.confirm'), onPress: () => navigation.goBack() }, ]); return; } @@ -104,14 +108,14 @@ export default function DfuScreen({ route, navigation }: Props) { }); setIsDfuRunning(false); - Alert.alert("升级成功", "升级成功,请重连设备", [ - { text: "确认", onPress: () => navigation.navigate("Home") }, + Alert.alert(t('dfu.upgradeSuccess'), t('dfu.upgradeSuccessMessage'), [ + { text: t('dfu.confirm'), onPress: () => navigation.navigate("Home") }, ]); } catch (err: any) { setIsDfuRunning(false); - setError(err.message || "DFU失败"); - Alert.alert("升级失败", err.message || "DFU失败", [ - { text: "确认", onPress: () => navigation.goBack() }, + setError(err.message || t('dfu.dfuFailed')); + Alert.alert(t('dfu.upgradeFailed'), err.message || t('dfu.dfuFailed'), [ + { text: t('dfu.confirm'), onPress: () => navigation.goBack() }, ]); } }; @@ -120,27 +124,40 @@ export default function DfuScreen({ route, navigation }: Props) { }, [deviceId, deviceFirmware, navigation]); return ( - - - 蓝牙名称: {name} - - - 最新版本: {latestVersion} - - - 当前版本: {deviceFirmware} - - - 升级状态: {mapDfuStateToChinese(state)} - + + + + - {/* 横向进度条 */} - - - {progress}% - + + + {t('dfu.bluetoothName')}: {name} + + + + + {t('dfu.latestVersion')}: {latestVersion} + + + + + {t('dfu.currentVersion')}: {deviceFirmware} + + + + + {t('dfu.upgradeStatus')}: {mapDfuStateToChinese(state)} + + - {error && {error}} + {/* 横向进度条 */} + + + {progress}% + + + {error && {error}} + ); } diff --git a/src/HomeScreen.tsx b/src/HomeScreen.tsx index 628f11e..2b35f3a 100644 --- a/src/HomeScreen.tsx +++ b/src/HomeScreen.tsx @@ -1,33 +1,36 @@ import React from "react"; -import { View, Text, TouchableOpacity, StyleSheet, StatusBar } from "react-native"; -import { NativeStackScreenProps } from "@react-navigation/native-stack"; +import { View, Text, TouchableOpacity, StyleSheet, StatusBar, Image } from "react-native"; +import { NativeStackScreenProps,NativeStackNavigationProp } from "@react-navigation/native-stack"; import { RootStackParamList } from "../App"; +import MyStatusbar from "./component/MyStatusbar"; +import MyHeader from "./component/MyHeader"; +import pxToDp from "./helper/pxToDp"; +import DeviceInfo from "react-native-device-info"; +import { useTranslation } from 'react-i18next'; -type Props = NativeStackScreenProps; +type Props = NativeStackScreenProps; export default function HomeScreen({ navigation }: Props) { + const { t } = useTranslation(); return ( {/* 设置状态栏颜色 */} - - + + navigation.navigate("Setting")}> + + }> {/* 中间按钮 */} + navigation.navigate("Scan")} > - 搜索设备 + {t('home.scan')} - - {/* 底部区域 */} - - navigation.navigate("Privacy")}> - 隐私协议 - - 版本号 v0.0.1 - ); } @@ -39,18 +42,22 @@ const styles = StyleSheet.create({ }, centerBox: { flex: 1, - justifyContent: "center", + // justifyContent: "center", alignItems: "center", + backgroundColor:'#fff', + paddingTop:pxToDp(250) }, button: { - backgroundColor: "#E7141E", // 红色按钮 - paddingVertical: 15, - paddingHorizontal: 40, - borderRadius: 10, + backgroundColor: "#E7141E", + borderRadius: pxToDp(24), + width:pxToDp(300), + height:pxToDp(96), + alignItems:'center', + justifyContent:'center' }, buttonText: { color: "#fff", - fontSize: 18, + fontSize: pxToDp(32), fontWeight: "bold", }, bottomBox: { diff --git a/src/InfoScreen.tsx b/src/InfoScreen.tsx index fead836..42352b8 100644 --- a/src/InfoScreen.tsx +++ b/src/InfoScreen.tsx @@ -19,7 +19,9 @@ import { ConnectionStatus, } from "@systemic-games/react-native-bluetooth-le"; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; - +import { useTranslation } from 'react-i18next'; +import MyStatusbar from "./component/MyStatusbar"; +import MyHeader from "./component/MyHeader"; type Props = NativeStackScreenProps; @@ -34,10 +36,9 @@ const fullUUID = (uuid: string) => : uuid; const Text = ({ children, style, ...props }: any) => { - const isDark = useColorScheme() === "dark"; return ( {children} @@ -46,6 +47,7 @@ const Text = ({ children, style, ...props }: any) => { }; export default function InfoScreen({ route, navigation }: Props) { + const { t } = useTranslation(); const { peripheral } = route.params; const deviceKey = peripheral.address || peripheral.systemId; @@ -56,11 +58,11 @@ export default function InfoScreen({ route, navigation }: Props) { const [isConnected, setIsConnected] = useState(false); const [isLoading, setIsLoading] = useState(true); - const [serial, setSerial] = useState("读取中..."); - const [firmware, setFirmware] = useState("读取中..."); - const [hardware, setHardware] = useState("读取中..."); - const [battery, setBattery] = useState("读取中..."); - const [powerTrim, setPowerTrim] = useState("读取中"); + const [serial, setSerial] = useState(t('info.reading')); + const [firmware, setFirmware] = useState(t('info.reading')); + const [hardware, setHardware] = useState(t('info.reading')); + const [battery, setBattery] = useState(t('info.reading')); + const [powerTrim, setPowerTrim] = useState(t('info.reading')); const [inputTrim, setInputTrim] = useState(""); const [readSuccessToast, setReadSuccessToast] = useState(false); // ✅ 读取成功提示 @@ -74,7 +76,7 @@ export default function InfoScreen({ route, navigation }: Props) { const prevConnectedRef = useRef(isConnected); const isActiveRef = useRef(true); - //增加校准按钮相关状态 + //增加校准按钮相关状态 const [calibrating, setCalibrating] = useState(false); const [calibrationSuccess, setCalibrationSuccess] = useState(false); const [calibrationValue, setCalibrationValue] = useState(""); @@ -82,56 +84,56 @@ export default function InfoScreen({ route, navigation }: Props) { const isCalibratingRef = useRef(false); useFocusEffect( - React.useCallback(() => { - // 页面获得焦点 - isActiveRef.current = true; - return () => { - // 页面失去焦点 - isActiveRef.current = false; - }; - }, []) -); + React.useCallback(() => { + // 页面获得焦点 + isActiveRef.current = true; + return () => { + // 页面失去焦点 + isActiveRef.current = false; + }; + }, []) + ); // ========== 监听连接状态变化,断开时提示重新连接 ========== useEffect(() => { - if (prevConnectedRef.current && !isConnected && isActiveRef.current) { - Alert.alert("提示", "设备已断开,请重新连接设备", [ - { text: "确定", onPress: () => navigation.goBack() }, - ]); - } - prevConnectedRef.current = isConnected; -}, [isConnected]); + if (prevConnectedRef.current && !isConnected && isActiveRef.current) { + Alert.alert(t('info.disconnectTitle'), t('info.disconnectMessage'), [ + { text: t('info.confirm'), onPress: () => navigation.goBack() }, + ]); + } + prevConnectedRef.current = isConnected; + }, [isConnected]); // ========== 页面即将返回时,强制断开蓝牙 ========== useEffect(() => { - const unsubscribe = navigation.addListener("beforeRemove", async (e) => { - if (disconnectingRef.current) return; - disconnectingRef.current = true; + const unsubscribe = navigation.addListener("beforeRemove", async (e) => { + if (disconnectingRef.current) return; + disconnectingRef.current = true; - const next = e.data.action?.type; - const action = e.data.action as any; + const next = e.data.action?.type; + const action = e.data.action as any; - // ✅ 判断是否跳转到 Dfu 页面 - if (next === "NAVIGATE" && action?.payload?.name === "Dfu") { - console.log("➡️ 跳转到 DFU,不断开蓝牙"); - disconnectingRef.current = false; - return; - } + // ✅ 判断是否跳转到 Dfu 页面 + if (next === "NAVIGATE" && action?.payload?.name === "Dfu") { + console.log("➡️ 跳转到 DFU,不断开蓝牙"); + disconnectingRef.current = false; + return; + } - // 🔌 其他页面离开则断开蓝牙 - console.log("📴 页面关闭,断开蓝牙..."); - try { - await Central.disconnectPeripheral(peripheral); - console.log("✅ 已断开蓝牙"); - } catch (err) { - console.warn("❌ 断开失败:", err); - } finally { - disconnectingRef.current = false; - } - }); - return unsubscribe; -}, [navigation, peripheral]); + // 🔌 其他页面离开则断开蓝牙 + console.log("📴 页面关闭,断开蓝牙..."); + try { + await Central.disconnectPeripheral(peripheral); + console.log("✅ 已断开蓝牙"); + } catch (err) { + console.warn("❌ 断开失败:", err); + } finally { + disconnectingRef.current = false; + } + }); + return unsubscribe; + }, [navigation, peripheral]); // ========== BLE notify 订阅FFF3 ========== useEffect(() => { @@ -154,7 +156,7 @@ export default function InfoScreen({ route, navigation }: Props) { peripheral, fullUUID(powerServiceUuid), fullUUID(powerNotifyUuid) - ).catch(() => {}); + ).catch(() => { }); await Central.subscribeCharacteristic( peripheral, fullUUID(powerServiceUuid), @@ -163,18 +165,18 @@ export default function InfoScreen({ route, navigation }: Props) { try { const raw = (notifyEv as any).value; if (!raw) return; - const byteArray = raw instanceof Uint8Array - ? raw - : new Uint8Array(raw); + const byteArray = raw instanceof Uint8Array + ? raw + : new Uint8Array(raw); if (byteArray[0] === 0x02 && byteArray.length >= 2) { - // 功率微调数据 - setPowerTrim(byteArray[1].toString()); - //setInputTrim(byteArray[1].toString()); - } - else if (byteArray[0] === 0x05 && byteArray.length >= 3) { - // 校准响应数据 (05XXXX格式) - handleFFF3Response(byteArray); - } + // 功率微调数据 + setPowerTrim(byteArray[1].toString()); + //setInputTrim(byteArray[1].toString()); + } + else if (byteArray[0] === 0x05 && byteArray.length >= 3) { + // 校准响应数据 (05XXXX格式) + handleFFF3Response(byteArray); + } } catch (err) { console.warn("notify parse error", err); } @@ -235,24 +237,24 @@ export default function InfoScreen({ route, navigation }: Props) { console.log("✅ info 读取完成"); - + try { - await Central.writeCharacteristic( - peripheral, - fullUUID(powerServiceUuid), - fullUUID(powerWriteUuid), - new Uint8Array([0x04]).buffer, - { withoutResponse: false } - ); - console.log("✅ 已发送 0x04,等待 notify 更新功率微调"); + await Central.writeCharacteristic( + peripheral, + fullUUID(powerServiceUuid), + fullUUID(powerWriteUuid), + new Uint8Array([0x04]).buffer, + { withoutResponse: false } + ); + console.log("✅ 已发送 0x04,等待 notify 更新功率微调"); - // notify 回调里已经订阅了,所以这里不用再重复订阅 - // 可以稍等 300ms,确保 notify 回来后 UI 会更新 - await new Promise(resolve => setTimeout(() => resolve(), 300)); - } catch (err) { - console.warn("❌ 首次读取功率微调失败", err); - } + // notify 回调里已经订阅了,所以这里不用再重复订阅 + // 可以稍等 300ms,确保 notify 回来后 UI 会更新 + await new Promise(resolve => setTimeout(() => resolve(), 300)); + } catch (err) { + console.warn("❌ 首次读取功率微调失败", err); + } } catch (e) { console.warn("❌ 读取失败", e); @@ -268,103 +270,103 @@ export default function InfoScreen({ route, navigation }: Props) { }, [peripheral]); - -// ========== 订阅 1818 服务的 2A63 特性 (通知) ========== -useEffect(() => { - const subscribeToPowerData = async () => { - try { - // 确保设备已经连接 - if (!isConnected) return; - console.log("✅ 订阅 2A63 特性通知..."); - - // 先取消之前的订阅(防止重复订阅) - await Central.unsubscribeCharacteristic( - peripheral, - fullUUID("1818"), - fullUUID("2a63") - ).catch(() => {}); + // ========== 订阅 1818 服务的 2A63 特性 (通知) ========== + useEffect(() => { + const subscribeToPowerData = async () => { + try { + // 确保设备已经连接 + if (!isConnected) return; - // 订阅 2A63 特性通知 - await Central.subscribeCharacteristic( - peripheral, - fullUUID("1818"), - fullUUID("2a63"), - (notifyEv) => { - try { - const raw = notifyEv.value; - if (raw) { - // 将 ArrayBuffer 转换为字节数组 - const byteArray = new Uint8Array(raw); - - // 解析数据 - parseData(byteArray); + console.log("✅ 订阅 2A63 特性通知..."); + + // 先取消之前的订阅(防止重复订阅) + await Central.unsubscribeCharacteristic( + peripheral, + fullUUID("1818"), + fullUUID("2a63") + ).catch(() => { }); + + // 订阅 2A63 特性通知 + await Central.subscribeCharacteristic( + peripheral, + fullUUID("1818"), + fullUUID("2a63"), + (notifyEv) => { + try { + const raw = notifyEv.value; + if (raw) { + // 将 ArrayBuffer 转换为字节数组 + const byteArray = new Uint8Array(raw); + + // 解析数据 + parseData(byteArray); + } + } catch (err) { + console.warn("❌ 处理通知数据失败", err); } - } catch (err) { - console.warn("❌ 处理通知数据失败", err); } - } - ); - - console.log("✅ 已订阅 2A63 特性通知"); - } catch (err) { - console.warn("❌ 订阅 2A63 特性失败", err); - } - }; + ); - // 只在设备已连接时进行订阅 - if (peripheral && isConnected) { - subscribeToPowerData(); - } + console.log("✅ 已订阅 2A63 特性通知"); + } catch (err) { + console.warn("❌ 订阅 2A63 特性失败", err); + } + }; - // 清理订阅(当组件卸载或者连接状态变化时) - return () => { + // 只在设备已连接时进行订阅 if (peripheral && isConnected) { - Central.unsubscribeCharacteristic(peripheral, fullUUID("1818"), fullUUID("2a63")).catch(() => {}); + subscribeToPowerData(); } - }; -}, [peripheral, isConnected]); -const cadenceStateRef = useRef({ + // 清理订阅(当组件卸载或者连接状态变化时) + return () => { + if (peripheral && isConnected) { + Central.unsubscribeCharacteristic(peripheral, fullUUID("1818"), fullUUID("2a63")).catch(() => { }); + } + }; + }, [peripheral, isConnected]); + + const cadenceStateRef = useRef({ lastCadenceCount: 0, // 上一次的踏频翻转次数,用于计算差值 lastCadenceTimestamp: 0, // 上一次的踏频时间戳(设备时间),用于计算差值 lastCadenceChangedTime: 0, // 最后一次踏频变化的时间(本地时间),用于检测超时 }); -const parseData = (byteArray: Uint8Array) => { - // 当前时间(用于超时检测) + const parseData = (byteArray: Uint8Array) => { + // 当前时间(用于超时检测) const currentTime = Date.now(); - // ========== 1. 解析功率 ========== + // ========== 1. 解析功率 ========== // 字节2-3:功率值(小端序) - const powerValue = (byteArray[3] << 8) | byteArray[2]; + const powerValue = (byteArray[3] << 8) | byteArray[2]; setPower(powerValue); // ========== 3. 解析踏频 ========== // 字节5-6:踏频翻转次数(小端序) const cadenceCount = (byteArray[6] << 8) | byteArray[5]; - + // 字节7-8:踏频时间戳(小端序) const timestamp = (byteArray[8] << 8) | byteArray[7]; - + // 获取上一次的状态 const lastState = cadenceStateRef.current; // 检测踏频翻转次数是否有变化 const hasCadenceChanged = cadenceCount !== lastState.lastCadenceCount; - + if (hasCadenceChanged) { // 踏频有变化,更新变化时间戳 cadenceStateRef.current.lastCadenceChangedTime = currentTime; } - + // 检查是否超时(3秒无变化) - if (lastState.lastCadenceChangedTime > 0 && - currentTime - lastState.lastCadenceChangedTime > 3000) { + if (lastState.lastCadenceChangedTime > 0 && + currentTime - lastState.lastCadenceChangedTime > 3000) { //setPower("0 W"); setCadence(0); setLeftBalance(0); - setRightBalance(0); + setRightBalance(0); cadenceStateRef.current = { lastCadenceCount: 0, lastCadenceTimestamp: 0, @@ -372,7 +374,7 @@ const parseData = (byteArray: Uint8Array) => { }; return; // 超时后直接返回,不再计算踏频 } - + // 如果是第一次收到踏频数据,只记录不计算 if (lastState.lastCadenceTimestamp === 0) { cadenceStateRef.current = { @@ -402,10 +404,10 @@ const parseData = (byteArray: Uint8Array) => { if (timeDiff > 0 && revDiff > 0) { // 假设时间单位是1/1024秒(蓝牙设备常用) const timeInSeconds = timeDiff / 1024.0; - + // RPM = (圈数 / 时间(秒)) * 60 const cadenceRPM = (revDiff / timeInSeconds) * 60; - + // 限制合理范围 if (cadenceRPM > 10 && cadenceRPM < 250) { setCadence(Math.round(cadenceRPM)); @@ -417,12 +419,12 @@ const parseData = (byteArray: Uint8Array) => { setCadence(0); } - // ========== 解析左平衡 ========== - // 字节4:左平衡值,单位0.5% + // ========== 解析左平衡 ========== + // 字节4:左平衡值,单位0.5% const leftBalanceValue = byteArray[4]; const leftBalancePercent = Math.round(leftBalanceValue * 0.5 * 10) / 10; setLeftBalance(leftBalancePercent); - // 计算右平衡:100% - 左平衡百分比 + // 计算右平衡:100% - 左平衡百分比 const rightBalancePercent = Math.round((100 - leftBalancePercent) * 10) / 10; setRightBalance(rightBalancePercent); @@ -442,7 +444,7 @@ const parseData = (byteArray: Uint8Array) => { const updatePowerTrim = async () => { const val = parseInt(inputTrim); if (isNaN(val) || val < 50 || val > 200) { - Alert.alert("提示", "功率微调可调整功率计的高低偏差,默认值100%。可调整的范围是50%-200%。请输入50至200的纯数字,不需要包含%符号。输入后点击下方按钮更新进功率计设备。"); + Alert.alert(t('info.disconnectTitle'), t('info.trimRangeAlert')); return; } if (val === Number(powerTrim)) { @@ -450,7 +452,7 @@ const parseData = (byteArray: Uint8Array) => { return; } if (!isConnected) { - Alert.alert("提示", "设备未连接"); + Alert.alert(t('info.disconnectTitle'), t('info.deviceNotConnected')); return; } @@ -480,281 +482,285 @@ const parseData = (byteArray: Uint8Array) => { } catch (err) { console.warn("❌ 写入失败", err); - Alert.alert("写入失败"); + Alert.alert(t('info.writeFailed')); } }; -// ========== 校准按钮逻辑 ========== -const handleCalibration = async () => { - if (!isConnected) { - Alert.alert("提示", "设备未连接"); - return; - } - - if (calibrating) { - return; // 正在校准中,不重复点击 - } - - try { - setCalibrating(true); - isCalibratingRef.current = true; - setCalibrationSuccess(false); - setCalibrationValue(""); - - console.log("🔧 开始校准,向FFF2写入05"); - - // 向FFF2写入05 - await Central.writeCharacteristic( - peripheral, - fullUUID("FFF1"), // 服务UUID - fullUUID("FFF2"), // 写入特征UUID - new Uint8Array([0x05]).buffer, - { withoutResponse: false } - ); - - console.log("✅ 已发送校准命令,等待响应..."); - - // 设置5秒超时 - calibrationTimeoutRef.current = setTimeout(() => { - if (isCalibratingRef.current) { - console.log("❌ 校准超时,未收到响应"); - Alert.alert("校准错误", "设备未响应,请重试"); - setCalibrating(false); - isCalibratingRef.current = false; - } - }, 5000); - - } catch (err) { - console.warn("❌ 发送校准命令失败", err); - Alert.alert("错误", "发送校准命令失败"); - setCalibrating(false); - isCalibratingRef.current = false; - - if (calibrationTimeoutRef.current) { - clearTimeout(calibrationTimeoutRef.current); + // ========== 校准按钮逻辑 ========== + const handleCalibration = async () => { + if (!isConnected) { + Alert.alert(t('info.disconnectTitle'), t('info.deviceNotConnected')); + return; } - } -}; -const handleFFF3Response = (byteArray: Uint8Array) => { - // 如果不是正在校准中,不处理 - if (!isCalibratingRef.current) return; - - // 清除超时定时器 - if (calibrationTimeoutRef.current) { - clearTimeout(calibrationTimeoutRef.current); - calibrationTimeoutRef.current = null; - } - - // 检查响应数据格式:05XXXX (05开头,后面至少2个字节) - // 假设响应是05 + 2字节的小端序数值 - if (byteArray[0] === 0x05 && byteArray.length >= 3) { - // 解析XXXX(小端序):低位在前,高位在后 - // byteArray[1] 是低位字节,byteArray[2] 是高位字节 - const value = Math.round (((byteArray[2] << 8) | byteArray[1])/10 ) ; //除以10发送出来 不然数据容易乱跳 和码表端处理保持一致 - console.log(`✅ 收到校准响应,值: ${value}`); - - // 更新状态 - setCalibrationValue(value.toString()); - setCalibrationSuccess(true); - - // 显示成功弹框 - Alert.alert( - "校准成功", - `校准值: ${value}`, - [ - { - text: "确定", - onPress: () => { - setCalibrating(false); - isCalibratingRef.current = false; - setCalibrationSuccess(false); - } + if (calibrating) { + return; // 正在校准中,不重复点击 + } + + try { + setCalibrating(true); + isCalibratingRef.current = true; + setCalibrationSuccess(false); + setCalibrationValue(""); + + console.log("🔧 开始校准,向FFF2写入05"); + + // 向FFF2写入05 + await Central.writeCharacteristic( + peripheral, + fullUUID("FFF1"), // 服务UUID + fullUUID("FFF2"), // 写入特征UUID + new Uint8Array([0x05]).buffer, + { withoutResponse: false } + ); + + console.log("✅ 已发送校准命令,等待响应..."); + + // 设置5秒超时 + calibrationTimeoutRef.current = setTimeout(() => { + if (isCalibratingRef.current) { + console.log("❌ 校准超时,未收到响应"); + Alert.alert(t('info.calibrationError'), t('info.calibrationTimeout')); + setCalibrating(false); + isCalibratingRef.current = false; } - ] - ); - } else { - console.warn("❌ 校准响应格式错误", byteArray); - Alert.alert("校准错误", "设备返回数据格式错误"); - setCalibrating(false); - isCalibratingRef.current = false; - } -}; + }, 5000); -useEffect(() => { - return () => { - // 清理校准超时定时器 + } catch (err) { + console.warn("❌ 发送校准命令失败", err); + Alert.alert(t('info.error'), t('info.calibrationSendError')); + setCalibrating(false); + isCalibratingRef.current = false; + + if (calibrationTimeoutRef.current) { + clearTimeout(calibrationTimeoutRef.current); + } + } + }; + + const handleFFF3Response = (byteArray: Uint8Array) => { + // 如果不是正在校准中,不处理 + if (!isCalibratingRef.current) return; + + // 清除超时定时器 if (calibrationTimeoutRef.current) { clearTimeout(calibrationTimeoutRef.current); calibrationTimeoutRef.current = null; } - }; -}, []); - + // 检查响应数据格式:05XXXX (05开头,后面至少2个字节) + // 假设响应是05 + 2字节的小端序数值 + if (byteArray[0] === 0x05 && byteArray.length >= 3) { + // 解析XXXX(小端序):低位在前,高位在后 + // byteArray[1] 是低位字节,byteArray[2] 是高位字节 + const value = Math.round(((byteArray[2] << 8) | byteArray[1]) / 10); //除以10发送出来 不然数据容易乱跳 和码表端处理保持一致 + console.log(`✅ 收到校准响应,值: ${value}`); + + // 更新状态 + setCalibrationValue(value.toString()); + setCalibrationSuccess(true); + + // 显示成功弹框 + Alert.alert( + t('info.calibrationSuccess'), + `${t('info.calibrationValue') + ": "} ${value}`, + [ + { + text: t('info.confirm'), + onPress: () => { + setCalibrating(false); + isCalibratingRef.current = false; + setCalibrationSuccess(false); + } + } + ] + ); + } else { + console.warn("❌ 校准响应格式错误", byteArray); + Alert.alert(t('info.calibrationError'), t('info.calibrationFormatError')); + setCalibrating(false); + isCalibratingRef.current = false; + } + }; + + useEffect(() => { + return () => { + // 清理校准超时定时器 + if (calibrationTimeoutRef.current) { + clearTimeout(calibrationTimeoutRef.current); + calibrationTimeoutRef.current = null; + } + }; + }, []); + + // ========== UI ========== return ( - + + + + - - 蓝牙名称: {peripheral.name} - + + {t('info.bluetoothName') + ": "} {peripheral.name} + - - ID号: {serial} - + + {t('info.idNumber') + ": "} {serial} + - - 固件版本: {firmware} - + + {t('info.firmwareVersion') + ": "} {firmware} + - - 电量: {battery} - + + {t('info.battery') + ": "} {battery} + - - 连接状态: {isConnected ? "已连接" : "未连接"} - - -{/* ====== 实时数据三卡片 ====== */} - - {/* 功率 */} - - - 功率/W - {power} - + + {t('info.connectionStatus') + ": "} {isConnected ? t('info.connected') : t('info.disconnected')} + - {/* 踏频 */} - - - 踏频/RPM - {cadence} - + {/* ====== 实时数据三卡片 ====== */} + + {/* 功率 */} + + + {t('info.power')} + {power} + - {/* 左右平衡 */} - - L / R - 左右平衡/% - - {leftbalance}/{rightbalance} - - - + {/* 踏频 */} + + + {t('info.cadence')} + {cadence} + + + {/* 左右平衡 */} + + L / R + {t('info.balance')} + + {leftbalance}/{rightbalance} + + + - {/* ========== 功率微调卡片部分 ========== */} - - - 功率微调设置 - - - - 当前微调: {powerTrim}% - - - - - 更新数值 - - + {/* ========== 功率微调卡片部分 ========== */} + + + {t('info.powerTrimTitle')} + - {/* ========== 新增校准按钮 ========== */} - - - - {calibrating ? "校准中...等待设备反应" : "校准归零"} - - + + {t('info.currentTrim') + ": "} {powerTrim}% + + + + + {t('info.updateValue')} + + + + {/* ========== 新增校准按钮 ========== */} + + + + {calibrating ? t('info.calibrating') : t('info.calibrateButton')} + + + + + + + + { + if (!isConnected) { + Alert.alert(t('info.disconnectTitle'), t('info.reconnectMessage'), [ + { + text: t('info.confirm'), + onPress: () => { + // 返回 ScanScreen + navigation.goBack(); + }, + }, + ]); + return; + } + // 蓝牙已连接,正常跳转 DFU + navigation.navigate("Dfu", { + deviceId: deviceKey, + name: peripheral.name, + firmware, + }); + }} + style={styles.pressable} + disabled={isLoading || powerTrimLoading} // ❌ 禁用点击 + > + {t('info.firmwareUpgrade')} + + + + + + {isLoading && ( + + + {t('info.readingInfo')} + + )} + + {/* ✅ 读取成功提示,固定在页面底部 */} + {readSuccessToast && ( + + + {t('info.readSuccess')} + + )} + + {/* 正在写入功率微调 */} + {powerTrimLoading && ( + + + {t('info.writingTrim')} + + )} + + {/* 功率微调写入成功 */} + {powerTrimSuccessToast && ( + + + {t('info.trimUpdateSuccess')} + + )} + + - - - - - { - if (!isConnected) { - Alert.alert("提示", "请重新连接设备", [ - { - text: "确定", - onPress: () => { - // 返回 ScanScreen - navigation.goBack(); - }, - }, - ]); - return; - } - // 蓝牙已连接,正常跳转 DFU - navigation.navigate("Dfu", { - deviceId: deviceKey, - name: peripheral.name, - firmware, - }); - }} - style={styles.pressable} - disabled={isLoading || powerTrimLoading} // ❌ 禁用点击 -> - 固件升级 - - - - - - {isLoading && ( - - - 正在读取信息... - - )} - - {/* ✅ 读取成功提示,固定在页面底部 */} - {readSuccessToast && ( - - - 读取成功! - - )} - - {/* 正在写入功率微调 */} - {powerTrimLoading && ( - - - 正在写入功率微调... - - )} - - {/* 功率微调写入成功 */} - {powerTrimSuccessToast && ( - - - 功率微调更新成功! - - )} - - ); } @@ -810,47 +816,47 @@ const styles = StyleSheet.create({ }, realtimeContainer: { - flexDirection: "row", - justifyContent: "space-between", - marginVertical: 10, -}, + flexDirection: "row", + justifyContent: "space-between", + marginVertical: 10, + }, -realtimeCard: { - flex: 1, - marginHorizontal: 4, - paddingVertical: 12, - borderRadius: 10, - backgroundColor: "#fff", - alignItems: "center", + realtimeCard: { + flex: 1, + marginHorizontal: 4, + paddingVertical: 12, + borderRadius: 10, + backgroundColor: "#fff", + alignItems: "center", - borderWidth: 1, - borderColor: "#E7141E", + borderWidth: 1, + borderColor: "#E7141E", - shadowColor: "#000", - shadowOffset: { width: 0, height: 1 }, - shadowOpacity: 0.1, - shadowRadius: 2, - elevation: 2, -}, + shadowColor: "#000", + shadowOffset: { width: 0, height: 1 }, + shadowOpacity: 0.1, + shadowRadius: 2, + elevation: 2, + }, -realtimeLabel: { - marginTop: 6, - fontSize: 14, - color: "#666", -}, + realtimeLabel: { + marginTop: 6, + fontSize: 14, + color: "#666", + }, -realtimeValue: { - marginTop: 4, - fontSize: 20, - fontWeight: "bold", - color: "#000", -}, + realtimeValue: { + marginTop: 4, + fontSize: 20, + fontWeight: "bold", + color: "#000", + }, -balanceHeader: { - fontSize: 16, - fontWeight: "bold", - color: "#E7141E", -}, + balanceHeader: { + fontSize: 16, + fontWeight: "bold", + color: "#E7141E", + }, diff --git a/src/PrivacyScreen.tsx b/src/PrivacyScreen.tsx index 14e90b8..8127891 100644 --- a/src/PrivacyScreen.tsx +++ b/src/PrivacyScreen.tsx @@ -1,80 +1,32 @@ import React from "react"; import { View, Text, ScrollView, StyleSheet } from "react-native"; +import MyStatusbar from "./component/MyStatusbar"; +import MyHeader from "./component/MyHeader"; +import { NativeStackScreenProps,NativeStackNavigationProp } from "@react-navigation/native-stack"; +import { RootStackParamList } from "../App"; +import { useTranslation } from 'react-i18next'; -export default function PrivacyScreen() { +type Props = NativeStackScreenProps; + +export default function PrivacyScreen({navigation}:Props) { + const { t } = useTranslation(); return ( - - 隐私协议 - - 本应用尊重并保护所有使用服务用户的个人隐私权。本隐私政策仅适用于无锡执行派体育文化发展有限公司的 POWERFUN 设置 APP 产品或服务。请在使用我们的产品或服务前,仔细阅读并了解本隐私政策。 - - {"\n\n"} - 一、我们如何收集和使用您的信息 - {"\n\n"} - 1. POWERFUN 设置 APP 不需要注册和登录,也不会收集任何关于个人的信息。 - {"\n\n"} - 2. 在您使用我司产品或服务过程中,我们可能会使用以下权限和信息: - {"\n"} - - Android ID:用于第三方或我们分析错误信息。 - {"\n"} - - 存储权限:用于管理本地缓存。 - {"\n"} - - 位置权限:用于设备产品与 APP 蓝牙连接。 - {"\n"} - - 蓝牙权限:用于设备产品与 APP 蓝牙连接。 - {"\n\n"} - 3. 关于第三方 SDK 使用说明: - {"\n\n"} - (1)第三方 SDK 名称:腾讯 Bugly - {"\n"} - 提供方:深圳市腾讯计算机系统有限公司 - {"\n"} - 收集类型:系统版本、设备 ID、手机型号、网络状态、系统设置、网络与 WiFi 信息、手机状态、系统日志等。 - {"\n"} - 使用目的:用于监控应用性能与稳定性,收集崩溃报告和使用数据以帮助我们识别并修复问题。 - {"\n\n"} - (2)第三方 SDK 名称:Aliyun OSS - {"\n"} - 提供方:阿里云计算有限公司 - {"\n"} - 使用目的:用于存储应用运行必要的配置和固件升级文件,确保数据可靠存储。 - - {"\n\n"} - 二、本政策如何更新 - {"\n\n"} - 我们的隐私政策可能会根据需求进行变更。未经您明确同意,我们不会削减您依据隐私政策应享有的权利。任何变更我们将在本页面公布。对于重大变更,我们会提供更为显著的通知。 - {"\n\n"} - 重大变更包括但不限于: - {"\n"} - - 服务模式发生重大变化(如用户信息处理目的、类型、方式等)。 - {"\n"} - - 在所有权或组织架构方面发生变更(如业务调整、破产并购等)。 - {"\n"} - - 用户信息安全影响评估报告显示存在高风险。 - - {"\n\n"} - 三、如何联系我们 - {"\n\n"} - 如果您对本隐私政策有任何疑问、意见或建议,可通过以下方式与我们联系: - {"\n"} - 电子邮件:bike99@qq.com - {"\n"} - 一般情况下,我们将在三十天内回复。 - - {"\n\n"} - 无锡执行派体育文化发展有限公司 - {"\n"} - 本政策自 2019 年 7 月 1 日起生效 - - + + + + + {t("privacy.title")} + {t("privacy.content")} + + ); } const styles = StyleSheet.create({ container: { flex: 1, - padding: 20, - backgroundColor: "#fff", + // padding: 20, + backgroundColor: "#f2f3f7", }, title: { fontSize: 22, @@ -85,5 +37,6 @@ const styles = StyleSheet.create({ fontSize: 16, lineHeight: 24, color: "#333", + marginBottom: 50 }, }); diff --git a/src/ScanScreen.tsx b/src/ScanScreen.tsx index 3597b78..782f7e5 100644 --- a/src/ScanScreen.tsx +++ b/src/ScanScreen.tsx @@ -17,8 +17,11 @@ import { NativeStackScreenProps } from "@react-navigation/native-stack"; import { RootStackParamList } from "../App"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; // 信号图标集 -type Props = NativeStackScreenProps; +type Props = NativeStackScreenProps; type DeviceWithTimestamp = ScannedPeripheral & { lastSeen: number }; +import { useTranslation } from 'react-i18next'; +import MyStatusbar from "./component/MyStatusbar"; +import MyHeader from "./component/MyHeader"; export default function ScanScreen({ navigation }: Props) { const [devices, setDevices] = useState([]); @@ -26,7 +29,7 @@ export default function ScanScreen({ navigation }: Props) { const [refreshing, setRefreshing] = useState(false); const handlerRef = useRef<((payload: CentralEventMap["scannedPeripheral"]) => void) | null>(null); - + const { t } = useTranslation(); // 将 RSSI 转换为信号格数(0-4) const getSignalLevel = (rssi?: number): number => { if (rssi === undefined) return 0; @@ -154,6 +157,13 @@ export default function ScanScreen({ navigation }: Props) { return ( + + item.systemId} @@ -163,7 +173,7 @@ export default function ScanScreen({ navigation }: Props) { style={styles.deviceRow} > - {item.name || "[no name]"} + {item.name || t("scan.noName")} {renderSignalIcon(item.advertisementData?.rssi)} @@ -177,13 +187,13 @@ export default function ScanScreen({ navigation }: Props) { {scanning ? ( <> - 搜索中... - (请确保设备有电且被唤醒) + {t("scan.scanning")} + {t("scan.tipScanning")} ) : ( <> - 暂无设备 - (请在设置中打开蓝牙) + {t("scan.noDevice")} + {t("scan.tipBluetooth")} )} diff --git a/src/SettingScreen.tsx b/src/SettingScreen.tsx new file mode 100644 index 0000000..b4c3ca3 --- /dev/null +++ b/src/SettingScreen.tsx @@ -0,0 +1,143 @@ +import React, { useState } from "react"; +import { View, Text, ScrollView, StyleSheet, TouchableOpacity, Image } from "react-native"; +import { useTranslation } from 'react-i18next'; +import MyStatusbar from "./component/MyStatusbar"; +import MyHeader from "./component/MyHeader"; +import LanguageModal from "./component/LanguageModal.tsx"; +import { NativeStackScreenProps } from "@react-navigation/native-stack"; +import { RootStackParamList } from "../App"; +import pxToDp from "./helper/pxToDp"; +import DeviceInfo from "react-native-device-info"; +import { LANGUAGES } from "./i18n"; + +type Props = NativeStackScreenProps; + +export default function SettingScreen({ navigation }: Props) { + const { t, i18n } = useTranslation(); + const [languageModalVisible, setLanguageModalVisible] = useState(false); + + // 获取当前语言显示名称 + const getCurrentLanguageLabel = (): string => { + const currentLang = i18n.language; + const language = LANGUAGES.find(lang => lang.key === currentLang); + return language?.label || '中文'; + }; + + return ( + + + + + + {/* 软件语言 */} + setLanguageModalVisible(true)} + > + + + {t('settings.language')} + + + {getCurrentLanguageLabel()} + + + + + {/* 隐私协议 */} + navigation.navigate("Privacy")} + > + + + {t('settings.privacy')} + + + + + + + {/* 版本号 */} + + + + {t('settings.version')} + + + {DeviceInfo.getVersion()} + + + + + {/* 语言切换弹窗 */} + setLanguageModalVisible(false)} + /> + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#f2f3f7", + }, + settingItem: { + width: pxToDp(670), + height: pxToDp(108), + borderRadius: pxToDp(24), + backgroundColor: '#fff', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingHorizontal: pxToDp(32), + }, + settingItemLeft: { + flexDirection: 'row', + alignItems: 'center', + }, + settingItemRight: { + flexDirection: 'row', + alignItems: 'center', + }, + icon: { + width: pxToDp(40), + height: pxToDp(40), + marginRight: pxToDp(12), + }, + settingLabel: { + fontSize: pxToDp(30), + color: '#333', + }, + settingValue: { + fontSize: pxToDp(30), + color: "#999", + marginRight: pxToDp(14), + }, + arrow: { + width: pxToDp(14), + height: pxToDp(24), + }, +}); \ No newline at end of file diff --git a/src/SplashScreen.tsx b/src/SplashScreen.tsx index fe798a9..ddadcea 100644 --- a/src/SplashScreen.tsx +++ b/src/SplashScreen.tsx @@ -2,8 +2,9 @@ import React, { useEffect } from "react"; import { View, Image, StyleSheet } from "react-native"; import { NativeStackScreenProps } from "@react-navigation/native-stack"; import { RootStackParamList } from "../App"; +import MyStatusbar from "./component/MyStatusbar"; -type Props = NativeStackScreenProps; +type Props = NativeStackScreenProps; export default function SplashScreen({ navigation }: Props) { useEffect(() => { @@ -16,6 +17,7 @@ export default function SplashScreen({ navigation }: Props) { return ( + void; +} + +const LanguageModal: React.FC = ({ visible, onClose }) => { + const { t, i18n } = useTranslation(); + const currentLanguage = i18n.language; + + const handleLanguageSelect = async (languageKey: string) => { + await saveLanguage(languageKey); + i18n.changeLanguage(languageKey); + onClose(); + }; + + return ( + + + e.stopPropagation()} + > + {/* 标题栏 */} + + {t('languageModal.title')} + + + + + + {/* 语言列表 */} + + {LANGUAGES.map((language) => ( + handleLanguageSelect(language.key)} + activeOpacity={0.7} + > + {language.label} + {currentLanguage === language.key && ( + + )} + + ))} + + + + + ); +}; + +const styles = StyleSheet.create({ + overlay: { + flex: 1, + backgroundColor: 'rgba(0, 0, 0, 0.5)', + justifyContent: 'center', + alignItems: 'center', + }, + modalContainer: { + width: pxToDp(630), + backgroundColor: '#fff', + borderRadius: pxToDp(24), + overflow: 'hidden', + }, + header: { + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + paddingVertical: pxToDp(32), + borderBottomWidth: pxToDp(1), + borderBottomColor: '#f0f0f0', + position: 'relative', + }, + title: { + fontSize: pxToDp(32), + fontWeight: '600', + color: '#333', + }, + closeButton: { + position: 'absolute', + right: pxToDp(32), + padding: pxToDp(8), + }, + closeIcon: { + fontSize: pxToDp(40), + color: '#666', + fontWeight: '300', + }, + languageList: { + paddingVertical: pxToDp(16), + }, + languageItem: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: pxToDp(40), + paddingVertical: pxToDp(32), + backgroundColor: '#fff', + }, + languageText: { + fontSize: pxToDp(30), + color: '#333', + }, + checkmark: { + fontSize: pxToDp(40), + color: '#FF6B35', + fontWeight: 'bold', + }, +}); + +export default LanguageModal; \ No newline at end of file diff --git a/src/component/MyHeader.tsx b/src/component/MyHeader.tsx new file mode 100644 index 0000000..b1f1a01 --- /dev/null +++ b/src/component/MyHeader.tsx @@ -0,0 +1,67 @@ +// components/Hello.tsx +import React, {ReactNode, useState} from 'react'; +import {StyleProp, Text, TouchableOpacity, View, ViewStyle, Image} from 'react-native'; +import pxToDp from '../helper/pxToDp'; +import {RootNavigationProp} from '../types/RootNavigationProp' + +export interface Props { + backgroundColor: string; + title: string; + textColor: string; + navigation: RootNavigationProp; + hideBack?: boolean; + customBackFunction?: () => void; + backIconType?: number; + rightView?: ReactNode; +} + +const MyHeader: React.FC = props => { + const containerStyle: StyleProp = { + backgroundColor: props.backgroundColor, + height: pxToDp(88), + width: '100%', + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: pxToDp(24), + }; + let backImage = + + return ( + + {props.hideBack ? ( + + ) : ( + { + if (props.customBackFunction) { + props.customBackFunction(); + } else { + props.navigation.goBack(); + } + }}> + {backImage} + + )} + + {props.title} + + + {props.rightView} + + + ); +}; + +export default MyHeader; diff --git a/src/component/MyStatusbar.tsx b/src/component/MyStatusbar.tsx new file mode 100644 index 0000000..78c2d06 --- /dev/null +++ b/src/component/MyStatusbar.tsx @@ -0,0 +1,41 @@ +// components/Hello.tsx +import React, {useState} from 'react'; +import {Button, StyleSheet, Text, View} from 'react-native'; +import {StatusBar, Platform, StatusBarProps} from 'react-native'; +import {useIsFocused} from '@react-navigation/native'; +import helper from '../helper/helper'; +export interface Props { + backgroundColor: string; + dark: Boolean; +} + +const FocusAwareStatusBar = (props: StatusBarProps) => { + const isFocused = useIsFocused(); + return isFocused ? : null; +}; +const MyStatusbar: React.FC = props => { + const height = helper.statusBarHeight; + const data: StatusBarProps = { + backgroundColor: props.backgroundColor + ? props.backgroundColor + : 'rgba(0,0,0,0)', + barStyle: props.dark ? 'dark-content' : 'light-content', + translucent: true, + }; + console.log('height', height); + return ( + + + + ); +}; + +// styles +const styles = StyleSheet.create({}); + +export default MyStatusbar; diff --git a/src/helper/helper.js b/src/helper/helper.js new file mode 100644 index 0000000..b1a6c6a --- /dev/null +++ b/src/helper/helper.js @@ -0,0 +1,106 @@ +import { Dimensions, StatusBar, Platform, Linking } from 'react-native'; +import pxToDp from './pxToDp'; +import { getStatusBarHeight } from 'react-native-status-bar-height'; +import * as _ from 'lodash'; +import myToast, { Toast } from './myToast'; +export default { + width: Dimensions.get('window').width, + height: + Platform.OS === 'ios' + ? Dimensions.get('window').height + : Dimensions.get('window').height / Dimensions.get('window').width > 1.8 + ? Dimensions.get('window').height + getStatusBarHeight() + : Dimensions.get('window').height, + statusBarHeight: getStatusBarHeight(), + bottomTabHeight: (Platform.OS === 'ios' && Dimensions.get('window').height / Dimensions.get('window').width > 1.8?34:0) + pxToDp(98), + isIOS: Platform.OS == 'ios', + isNullOrEmpty(strings) { + return !strings || String(strings).replace(/(^s*)|(s*$)/g, '').length == 0; + }, + stringToNumberStr(s) { + console.log(16, String(Number(s.replace(/[^0-9]/g, '')))); + return String(Number(s.replace(/[^0-9]/g, ''))); + }, + isIOSFullScreen() { + const dimen = Dimensions.get('window'); + return ( + Platform.OS === 'ios' && + !Platform.isPad && + !Platform.isTVOS && + (dimen.height === 780 || + dimen.width === 780 || + dimen.height === 812 || + dimen.width === 812 || + dimen.height === 844 || + dimen.width === 844 || + dimen.height === 896 || + dimen.width === 896 || + dimen.height === 926 || + dimen.width === 926) + ); + }, + //写一个方法,传入一个数组,判断数量是否是n的倍数,如果不是,补null + getNewArr(arr, n) { + let count = n - arr.length % n; + for (let i = 0; i < count; i++) { + arr.push(null); + } + return arr; + }, + //获取随机颜色 + getRandomColor() { + return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).slice(-6); + }, + goPage(navigation, type, page, params) { + console.log(44, type, page, params); + if(page === '#') { + myToast.show('敬请期待','error'); + return; + } + if (type === 2) { + console.log(57, '外链') + Linking.openURL(page); + } else { + console.log(60, '内链') + const json = this.toJSON(_.replace(params, /"/g, '"')); + navigation.navigate(page, { ...json }); + } + }, + toJSON(str) { + try { + const a = JSON.parse(str); + return a; + } catch (error) { + return {}; + } + }, + getIntegerAndDecimal(num, type = 1) { + //type 1:去掉小数点前面的0 2:去掉0.,整数部分加小数点 + let integer = Math.floor(num).toFixed(0) + let decimal = (num - integer).toFixed(1) + if (decimal === '0.0') { + return { integer, decimal: '' } + } + if (type === 1) { + decimal = decimal.replace('0', '') + } else if (type === 2) { + decimal = decimal.replace('0.', '') + integer += '.' + } + return { integer, decimal } + }, + getHideString(str){ + //写一个方法,判断如果是手机号,隐藏中间四位,如果是邮箱,隐藏@前面的,如果是汉字,隐藏后面的 + if(!str) return ''; + if(str.indexOf('@') > -1){ + let arr = str.split('@'); + return arr[0].substr(0,1) + '****' + arr[0].substr(arr[0].length-1) + '@' + arr[1]; + } + if(str.length === 11){ + return str.substr(0,3) + '****' + str.substr(7); + } + if(str.length > 1){ + return str.substr(0,1) + '**'; + } + }, +}; diff --git a/src/helper/myToast.tsx b/src/helper/myToast.tsx new file mode 100644 index 0000000..4ce6b49 --- /dev/null +++ b/src/helper/myToast.tsx @@ -0,0 +1,37 @@ +type ToastType = 'success' | 'error'; +import React from 'react'; +import _Toast from 'react-native-toast-message'; +export default { + show( + text: string, + type: ToastType = 'success', + duration: number = 3500, + hide: () => void | undefined = () => {}, + ) { + // _Toast.hide(); + _Toast.show({ + text1: '提示', + text2: text, + type, + visibilityTime: duration, + onHide: hide, + }); + }, + useBlur( + navigation: any, + customFunc: (() => void) | null = null, + ) { + React.useEffect(() => { + const unsubscribe = navigation.addListener('blur', () => { + // do something + _Toast.hide(); + if (customFunc != null) { + customFunc(); + } + }); + return unsubscribe; + }, [navigation]); + }, +}; + +export const Toast = _Toast; diff --git a/src/helper/pxToDp.js b/src/helper/pxToDp.js new file mode 100644 index 0000000..561f299 --- /dev/null +++ b/src/helper/pxToDp.js @@ -0,0 +1,14 @@ +import { + Dimensions, + PixelRatio +} from 'react-native'; +//视屏的宽度和设置像素转换 +const deviceWidthDp = Dimensions.get('window').width; + +const uiWidthPx = 750; + +function pxToDp(uiElementPx,isConvert = true) { + if(!isConvert) return uiElementPx; + return Number((uiElementPx * deviceWidthDp / uiWidthPx)); +} +export default pxToDp \ No newline at end of file diff --git a/src/i18n/en-US.ts b/src/i18n/en-US.ts deleted file mode 100644 index 0bedb68..0000000 --- a/src/i18n/en-US.ts +++ /dev/null @@ -1,100 +0,0 @@ -const enUS = { - nav: { - scan: "Scan", - info: "Device Info", - dfu: "Firmware Update", - privacy: "Privacy Policy", - }, - - home: { - scan: "Scan Devices", - privacy: "Privacy Policy", - version: "Version v0.0.1", - }, - - scan: { - scanning: "Scanning...", - noDevice: "No Devices Found", - tipScanning: "(Make sure the device is powered on and awake)", - tipBluetooth: "(Please enable Bluetooth in settings)", - noName: "[No Name]", - rssiUnit: "dBm", - }, - - dfu: { - preparing: "Preparing...", - reading: "Reading...", - wait: "Please wait", - upgrading: "Updating firmware. Do not exit the app.", - - bluetoothName: "Bluetooth Name", - latestVersion: "Latest Version", - currentVersion: "Current Version", - upgradeStatus: "Update Status", - - successTitle: "Update Successful", - successMsg: "Firmware updated successfully. Please reconnect the device.", - - failTitle: "Update Failed", - noNeedTitle: "No Update Required", - noNeedMsg: "The firmware is already up to date.", - - notFoundTitle: "Update Unavailable", - notFoundMsg: "Firmware for hardware version {{hw}} not found", - - confirm: "OK", - }, - - dfuState: { - connecting: "Connecting...", - starting: "Initializing...", - enablingDfuMode: "Enabling DFU Mode...", - uploading: "Uploading firmware...", - validating: "Validating firmware...", - disconnecting: "Disconnecting...", - completed: "Completed", - aborted: "Aborted", - failed: "Update Failed", - dfu_failed: "Update Failed", - initializing: "Starting...", - errored: "Update Error!", - }, - - privacy: { - title: "Privacy Policy", - content: `This application respects and protects the personal privacy of all users. This Privacy Policy applies only to the POWERFUN Settings App products or services provided by Wuxi Zhixingpai Sports Culture Development Co., Ltd. Please read and fully understand this policy before using our products or services. - -1. How We Collect and Use Your Information - -1. The POWERFUN Settings App does not require registration or login and does not collect any personal information. - -2. During your use of our products or services, we may use the following permissions: -- Android ID -- Storage -- Location -- Bluetooth - -3. Third-party SDK usage: - -(1) Tencent Bugly -Provider: Tencent Computer Systems Company Limited -Purpose: crash reporting and performance monitoring. - -(2) Aliyun OSS -Provider: Alibaba Cloud Computing Co., Ltd. -Purpose: storage of configuration and firmware update files. - -2. Updates to This Policy - -We may update this policy from time to time. Changes will be published on this page. - -3. Contact Us - -Email: bike99@qq.com - -Wuxi Zhixingpai Sports Culture Development Co., Ltd. -Effective date: July 1, 2019`, - }, -}; - -export default enUS; diff --git a/src/i18n/index.ts b/src/i18n/index.ts new file mode 100644 index 0000000..58edb90 --- /dev/null +++ b/src/i18n/index.ts @@ -0,0 +1,71 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import AsyncStorage from '@react-native-async-storage/async-storage'; + +import zh from './locales/zh.json'; +import en from './locales/en.json'; + +const LANGUAGE_KEY = '@app_language'; + +// 语言配置类型 +export interface LanguageOption { + key: string; + label: string; + value: string; +} + +// 语言选项 +export const LANGUAGES: LanguageOption[] = [ + { + key: 'zh', + label: '中文', + value: 'zh', + }, + { + key: 'en', + label: 'English', + value: 'en', + }, +]; + +// 获取存储的语言 +export const getStoredLanguage = async (): Promise => { + try { + const language = await AsyncStorage.getItem(LANGUAGE_KEY); + return language || 'zh'; + } catch (error) { + return 'zh'; + } +}; + +// 保存语言选择 +export const saveLanguage = async (language: string): Promise => { + try { + await AsyncStorage.setItem(LANGUAGE_KEY, language); + } catch (error) { + console.error('保存语言失败:', error); + } +}; + +// 初始化 i18n +i18n + .use(initReactI18next) + .init({ + compatibilityJSON: 'v3', + resources: { + zh: { translation: zh }, + en: { translation: en }, + }, + lng: 'zh', + fallbackLng: 'zh', + interpolation: { + escapeValue: false, + }, + }); + +// 从存储中加载语言设置 +getStoredLanguage().then((language) => { + i18n.changeLanguage(language); +}); + +export default i18n; \ No newline at end of file diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json new file mode 100644 index 0000000..078bb35 --- /dev/null +++ b/src/i18n/locales/en.json @@ -0,0 +1,120 @@ +{ + "nav": { + "scan": "Scan", + "info": "Device Info", + "dfu": "Firmware Update", + "privacy": "Privacy Policy" + }, + "home": { + "title": "POWERFUN Settings", + "scan": "Scan Devices", + "privacy": "Privacy Policy", + "version": "Version v0.0.1" + }, + "scan": { + "title": "Scan Devices", + "scanning": "Scanning...", + "noDevice": "No Devices Found", + "tipScanning": "(Make sure the device is powered on and awake)", + "tipBluetooth": "(Please enable Bluetooth in settings)", + "noName": "[No Name]", + "rssiUnit": "dBm" + }, + "dfu": { + "title": "Firmware Update", + "preparing": "Preparing...", + "reading": "Reading...", + + "bluetoothName": "Bluetooth Name", + "latestVersion": "Latest Version", + "currentVersion": "Current Version", + "upgradeStatus": "Update Status", + + "stateConnecting": "Connecting…", + "stateStarting": "Initializing…", + "stateEnablingDfuMode": "Enabling DFU Mode…", + "stateUploading": "Uploading Firmware…", + "stateValidating": "Validating Firmware…", + "stateDisconnecting": "Disconnecting…", + "stateCompleted": "Update Completed", + "stateAborted": "Aborted", + "stateFailed": "Update Failed", + "stateInitializing": "Starting…", + "stateErrored": "Update Error!", + + "pleaseWait": "Please Wait", + "doNotReturn": "Updating in progress, do not go back or close the app!", + + "cannotUpgrade": "Cannot Update", + "hardwareNotFound": "Firmware not found for hardware version {hardware}", + "noNeedUpgrade": "No Update Needed", + "alreadyLatest": "Already the latest firmware, no update needed", + + "upgradeSuccess": "Update Successful", + "upgradeSuccessMessage": "Update successful, please reconnect the device", + "upgradeFailed": "Update Failed", + "dfuFailed": "DFU Failed", + + "confirm": "OK" + }, + "privacy": { + "title": "Privacy Policy", + "content": "This application respects and protects the personal privacy of all users. This Privacy Policy applies only to the POWERFUN Settings App products or services provided by Wuxi Zhixingpai Sports Culture Development Co., Ltd. Please read and fully understand this policy before using our products or services.\n\n1. How We Collect and Use Your Information\n\n1. The POWERFUN Settings App does not require registration or login and does not collect any personal information.\n\n2. During your use of our products or services, we may use the following permissions:\n- Android ID\n- Storage\n- Location\n- Bluetooth\n\n3. Third-party SDK usage:\n\n(1) Tencent Bugly \nProvider: Tencent Computer Systems Company Limited \nPurpose: crash reporting and performance monitoring.\n\n(2) Aliyun OSS \nProvider: Alibaba Cloud Computing Co., Ltd. \nPurpose: storage of configuration and firmware update files.\n\n2. Updates to This Policy\n\nWe may update this policy from time to time. Changes will be published on this page.\n\n3. Contact Us\n\nEmail: bike99@qq.com\n\nWuxi Zhixingpai Sports Culture Development Co., Ltd. \nEffective date: July 1, 2019" + }, + "settings": { + "title": "Settings", + "language": "Language", + "privacy": "Privacy Policy", + "version": "Version" + }, + "languageModal": { + "title": "Language" + }, + "info": { + "title": "Device Info", + "bluetoothName": "Bluetooth Name", + "idNumber": "ID Number", + "firmwareVersion": "Firmware Version", + "battery": "Battery", + "connectionStatus": "Connection Status", + "connected": "Connected", + "disconnected": "Disconnected", + "reading": "Reading...", + + "power": "Power/W", + "cadence": "Cadence/RPM", + "balance": "L/R Balance/%", + "balanceHeader": "L / R", + + "powerTrimTitle": "Power Trim Settings", + "currentTrim": "Current Trim", + "trimPlaceholder": "Enter 50-200", + "updateValue": "Update Value", + + "calibrateButton": "Calibrate Zero", + "calibrating": "Calibrating... Waiting for device", + "firmwareUpgrade": "Firmware Update", + + "readingInfo": "Reading information...", + "readSuccess": "Read successfully!", + "writingTrim": "Writing power trim...", + "trimUpdateSuccess": "Power trim updated successfully!", + + "disconnectTitle": "Notice", + "disconnectMessage": "Device disconnected, please reconnect", + "reconnectMessage": "Please reconnect the device", + "confirm": "OK", + + "trimRangeAlert": "Power trim adjusts the power meter's high and low deviation. Default value is 100%. Adjustable range is 50%-200%. Please enter a number between 50 and 200 without the % symbol. Click the button below to update the power meter after entering.", + "deviceNotConnected": "Device not connected", + "writeFailed": "Write failed", + + "calibrationSuccess": "Calibration Successful", + "calibrationValue": "Calibration Value", + "calibrationError": "Calibration Error", + "calibrationTimeout": "Device not responding, please try again", + "calibrationFormatError": "Invalid response format from device", + "calibrationSendError": "Failed to send calibration command", + "error": "Error" + } + } \ No newline at end of file diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json new file mode 100644 index 0000000..a71d9cd --- /dev/null +++ b/src/i18n/locales/zh.json @@ -0,0 +1,120 @@ +{ + "nav": { + "scan": "搜索", + "info": "设备信息", + "dfu": "固件升级", + "privacy": "隐私协议" + }, + "home": { + "title": "POWERFUN设置", + "scan": "搜索设备", + "privacy": "隐私协议", + "version": "版本号 v0.0.1" + }, + "scan": { + "title": "搜索设备", + "scanning": "搜索中...", + "noDevice": "暂无设备", + "tipScanning": "(请确保设备有电且被唤醒)", + "tipBluetooth": "(请在设置中打开蓝牙)", + "noName": "[无名称]", + "rssiUnit": "dBm" + }, + "dfu": { + "title": "固件升级", + "preparing": "准备中...", + "reading": "读取中...", + + "bluetoothName": "蓝牙名称", + "latestVersion": "最新版本", + "currentVersion": "当前版本", + "upgradeStatus": "升级状态", + + "stateConnecting": "连接中…", + "stateStarting": "初始化中…", + "stateEnablingDfuMode": "启用 DFU 模式…", + "stateUploading": "上传固件中…", + "stateValidating": "校验固件…", + "stateDisconnecting": "断开连接…", + "stateCompleted": "升级完成", + "stateAborted": "已取消", + "stateFailed": "升级失败", + "stateInitializing": "启动中…", + "stateErrored": "升级出错!", + + "pleaseWait": "请稍候", + "doNotReturn": "正在升级,请勿返回或关闭应用!", + + "cannotUpgrade": "无法升级", + "hardwareNotFound": "未找到硬件版本 {hardware} 的固件", + "noNeedUpgrade": "无需升级", + "alreadyLatest": "已是最新固件,无需升级", + + "upgradeSuccess": "升级成功", + "upgradeSuccessMessage": "升级成功,请重连设备", + "upgradeFailed": "升级失败", + "dfuFailed": "DFU失败", + + "confirm": "确认" + }, + "privacy": { + "title": "隐私协议", + "content": "本应用尊重并保护所有使用服务用户的个人隐私权。本隐私政策仅适用于无锡执行派体育文化发展有限公司的 POWERFUN 设置 APP 产品或服务。请在使用我们的产品或服务前,仔细阅读并了解本隐私政策。\n\n一、我们如何收集和使用您的信息\n\n1. POWERFUN 设置 APP 不需要注册和登录,也不会收集任何关于个人的信息。\n\n2. 在您使用我司产品或服务过程中,我们可能会使用以下权限和信息:\n- Android ID:用于第三方或我们分析错误信息。\n- 存储权限:用于管理本地缓存。\n- 位置权限:用于设备产品与 APP 蓝牙连接。\n- 蓝牙权限:用于设备产品与 APP 蓝牙连接。\n\n3. 关于第三方 SDK 使用说明:\n\n(1)第三方 SDK 名称:腾讯 Bugly \n提供方:深圳市腾讯计算机系统有限公司 \n收集类型:系统版本、设备 ID、手机型号、网络状态、系统设置、网络与 WiFi 信息、手机状态、系统日志等。 \n使用目的:用于监控应用性能与稳定性,收集崩溃报告和使用数据以帮助我们识别并修复问题。\n\n(2)第三方 SDK 名称:Aliyun OSS \n提供方:阿里云计算有限公司 \n使用目的:用于存储应用运行必要的配置和固件升级文件,确保数据可靠存储。\n\n二、本政策如何更新\n\n我们的隐私政策可能会根据需求进行变更。未经您明确同意,我们不会削减您依据隐私政策应享有的权利。任何变更我们将在本页面公布。对于重大变更,我们会提供更为显著的通知。\n\n重大变更包括但不限于:\n- 服务模式发生重大变化(如用户信息处理目的、类型、方式等)。\n- 在所有权或组织架构方面发生变更(如业务调整、破产并购等)。\n- 用户信息安全影响评估报告显示存在高风险。\n\n三、如何联系我们\n\n如果您对本隐私政策有任何疑问、意见或建议,可通过以下方式与我们联系:\n电子邮件:bike99@qq.com\n\n一般情况下,我们将在三十天内回复。\n\n无锡执行派体育文化发展有限公司 \n本政策自 2019 年 7 月 1 日起生效" + }, + "settings": { + "title": "设置", + "language": "软件语言", + "privacy": "隐私协议", + "version": "版本号" + }, + "languageModal": { + "title": "软件语言" + }, + "info": { + "title": "设备信息", + "bluetoothName": "蓝牙名称", + "idNumber": "ID号", + "firmwareVersion": "固件版本", + "battery": "电量", + "connectionStatus": "连接状态", + "connected": "已连接", + "disconnected": "未连接", + "reading": "读取中...", + + "power": "功率/W", + "cadence": "踏频/RPM", + "balance": "左右平衡/%", + "balanceHeader": "L / R", + + "powerTrimTitle": "功率微调设置", + "currentTrim": "当前微调", + "trimPlaceholder": "输入50-200", + "updateValue": "更新数值", + + "calibrateButton": "校准归零", + "calibrating": "校准中...等待设备反应", + "firmwareUpgrade": "固件升级", + + "readingInfo": "正在读取信息...", + "readSuccess": "读取成功!", + "writingTrim": "正在写入功率微调...", + "trimUpdateSuccess": "功率微调更新成功!", + + "disconnectTitle": "提示", + "disconnectMessage": "设备已断开,请重新连接设备", + "reconnectMessage": "请重新连接设备", + "confirm": "确定", + + "trimRangeAlert": "功率微调可调整功率计的高低偏差,默认值100%。可调整的范围是50%-200%。请输入50至200的纯数字,不需要包含%符号。输入后点击下方按钮更新进功率计设备。", + "deviceNotConnected": "设备未连接", + "writeFailed": "写入失败", + + "calibrationSuccess": "校准成功", + "calibrationValue": "校准值", + "calibrationError": "校准错误", + "calibrationTimeout": "设备未响应,请重试", + "calibrationFormatError": "设备返回数据格式错误", + "calibrationSendError": "发送校准命令失败", + "error": "错误" + } + } \ No newline at end of file diff --git a/src/i18n/zh-CN.ts b/src/i18n/zh-CN.ts deleted file mode 100644 index bd5c2e9..0000000 --- a/src/i18n/zh-CN.ts +++ /dev/null @@ -1,109 +0,0 @@ -const zhCN = { - nav: { - scan: "搜索", - info: "设备信息", - dfu: "固件升级", - privacy: "隐私协议", - }, - - home: { - scan: "搜索设备", - privacy: "隐私协议", - version: "版本号 v0.0.1", - }, - - scan: { - scanning: "搜索中...", - noDevice: "暂无设备", - tipScanning: "(请确保设备有电且被唤醒)", - tipBluetooth: "(请在设置中打开蓝牙)", - noName: "[无名称]", - rssiUnit: "dBm", - }, - - dfu: { - preparing: "准备中...", - reading: "读取中...", - wait: "请稍候", - upgrading: "正在升级,请勿返回或关闭应用!", - - bluetoothName: "蓝牙名称", - latestVersion: "最新版本", - currentVersion: "当前版本", - upgradeStatus: "升级状态", - - successTitle: "升级成功", - successMsg: "升级成功,请重连设备", - - failTitle: "升级失败", - noNeedTitle: "无需升级", - noNeedMsg: "已是最新固件,无需升级", - - notFoundTitle: "无法升级", - notFoundMsg: "未找到硬件版本 {{hw}} 的固件", - - confirm: "确认", - }, - - dfuState: { - connecting: "连接中…", - starting: "初始化中…", - enablingDfuMode: "启用 DFU 模式…", - uploading: "上传固件中…", - validating: "校验固件…", - disconnecting: "断开连接…", - completed: "升级完成", - aborted: "已取消", - failed: "升级失败", - dfu_failed: "升级失败", - initializing: "启动中…", - errored: "升级出错!", - }, - - privacy: { - title: "隐私协议", - content: `本应用尊重并保护所有使用服务用户的个人隐私权。本隐私政策仅适用于无锡执行派体育文化发展有限公司的 POWERFUN 设置 APP 产品或服务。请在使用我们的产品或服务前,仔细阅读并了解本隐私政策。 - -一、我们如何收集和使用您的信息 - -1. POWERFUN 设置 APP 不需要注册和登录,也不会收集任何关于个人的信息。 - -2. 在您使用我司产品或服务过程中,我们可能会使用以下权限和信息: -- Android ID:用于第三方或我们分析错误信息。 -- 存储权限:用于管理本地缓存。 -- 位置权限:用于设备产品与 APP 蓝牙连接。 -- 蓝牙权限:用于设备产品与 APP 蓝牙连接。 - -3. 关于第三方 SDK 使用说明: - -(1)第三方 SDK 名称:腾讯 Bugly -提供方:深圳市腾讯计算机系统有限公司 -收集类型:系统版本、设备 ID、手机型号、网络状态、系统设置、网络与 WiFi 信息、手机状态、系统日志等。 -使用目的:用于监控应用性能与稳定性,收集崩溃报告和使用数据以帮助我们识别并修复问题。 - -(2)第三方 SDK 名称:Aliyun OSS -提供方:阿里云计算有限公司 -使用目的:用于存储应用运行必要的配置和固件升级文件,确保数据可靠存储。 - -二、本政策如何更新 - -我们的隐私政策可能会根据需求进行变更。未经您明确同意,我们不会削减您依据隐私政策应享有的权利。任何变更我们将在本页面公布。对于重大变更,我们会提供更为显著的通知。 - -重大变更包括但不限于: -- 服务模式发生重大变化(如用户信息处理目的、类型、方式等)。 -- 在所有权或组织架构方面发生变更(如业务调整、破产并购等)。 -- 用户信息安全影响评估报告显示存在高风险。 - -三、如何联系我们 - -如果您对本隐私政策有任何疑问、意见或建议,可通过以下方式与我们联系: -电子邮件:bike99@qq.com - -一般情况下,我们将在三十天内回复。 - -无锡执行派体育文化发展有限公司 -本政策自 2019 年 7 月 1 日起生效`, - }, -}; - -export default zhCN; diff --git a/src/img/Return.png b/src/img/Return.png new file mode 100644 index 0000000000000000000000000000000000000000..33501c4e18d739afa1162d7f6146e24803afa605 GIT binary patch literal 858 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRo!3HEV4DF?W6k~CayA#8@b22Z1oQl*4&op0O z1}z|)gMo!nih&iR1c>bzrQvKhMhymLus9O~LwhCz3sj9CkOqMXKn&6Yp_vyjLRACB z7BIn83oKxUvt>Zqlr>a9F61omh%9Dc5K{$VM$aIX4-5=U)t)YnAr^vDr}$?CI|>~8 z9VeG7>SMBff(FOO1tFj0mjr!Lxq3lqMMp?}Q&rHblani6FRb|RVr{4fhuoW`K`#7V zCWf4zDji%^0>avIE+I)Oo%=m&*3Zrry43o;?Ah#}Y3b!@*ClQ}@=y_Sm+Czhn_)fc z>@(G5?LQeNRo4u9TrCd&ubh9zk@-l{#@7?3i);#5>u6-4c>mbXRR&W6)gS!a$Jli6 zLC5jOJK10MIEj2Te^NZtCv9hXLxIJf%TJ4RAKNUPxWBL>cxOzWZ-KY*wkrV|Pul-T zr21^GUvd5Q?Vg*A=N>@%l? zE686xDRhGKz^P!96T$}TC8lhAP_}!y;{PB6_nchDPdwWC4ZCE#qi38>+iY&K#@Y1I z#~%`!`Pk65p5gxdzpxa;dI!8sLk?o697aX{sJ9DW$c|2jhRz!RtU!ZPk z^RMvVMkb3jzlLrIT*S;l+q7K?PZchpUs^zZ72X|GrWdfR3xOm^?s9d)hue%96~ z+fc2kb$JfCE0r4@CVD(+$edL)vuu0poceQ{)(Ec*$-3((V8$x2I3|5gxB!3Gx}N?i zl}2;@_HQ2xPWP`3 zIqvfpI;~%M;r6=df<;?co9E4NpL6xYwZ*rLnXk^w35)#5e#6kNI`HPdhmA}g2A5(N zKfE{LpUJAf)9U0c8dwx32Pp_t_#N(DeCq7pKm0Egj!I7pwA%nmqn@sQF6*2UngFIS BR+<0+ literal 0 HcmV?d00001 diff --git a/src/img/Return2.png b/src/img/Return2.png new file mode 100644 index 0000000000000000000000000000000000000000..383bcacc18e23e4ab05b3413ba69166860188a96 GIT binary patch literal 729 zcmeAS@N?(olHy`uVBq!ia0vp^d_XM0!3HEx9X}Heq!^2X+?^QKos)S9SBTp!GslE*0FjTF5lW8CkbME=){!95=MFQ1X z*mE}DpJMmKX>Z*8Ejq9Lp2tg?2deIPu9JWN_)mtsgD%<^c|zY-iEy(m+shhx-Ry2+SVx9?3=6fGNjtY)+cSe!P{7PL7cC>`j5a>#+ciW z=6$zFzGL|=Ff?>)z0J!h4`-iHpV_`ey>rjU?ec{z&KnO0@Ck2 zWL%XdhF&&#yX{DhnRGhCKL;rmz8gtj$~I(eRrz$cC`I2vzhc4J)}WPNybZq`R_0q` zS)?{$iFAuZowt%)fiUZ-lVMLfN*n8Ws;4cSZeMghXswr^)4~giy0zCuk9TZPa{XXX z;_#$sXaCkH-!20d8>KDEWlpoL5>qce{4kacj+g{@q1s(-nUHtFB@ET(q+3 T`MiRupd{ky>gTe~DWM4fb~6s# literal 0 HcmV?d00001 diff --git a/src/img/Search.png b/src/img/Search.png new file mode 100644 index 0000000000000000000000000000000000000000..ac2c6054470f48e4e9b68884d759aedb5c9b08bf GIT binary patch literal 76917 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 Z{y!B`(KC=-RX+d#002ovPDHLkV1g34BYgk> literal 0 HcmV?d00001 diff --git a/src/img/Settings.png b/src/img/Settings.png new file mode 100644 index 0000000000000000000000000000000000000000..3e2127a0adfa7344fee8a89d114974a76fac174c GIT binary patch literal 1342 zcmX|>dpOez7{`CRuyHV#NTWl{t<0sIN|a?|Myr|2a+y3%GR8wF&e4%e(MmYQw7G0W zC9O4Cxh=OR({UJc8D*m4nCH0Van$41nR9x2pXd92zVG{d-+x~Q=_FoL9jOigfF{8U zM^@57DOKMrAyY~cH z1CamrU;xOC2B6K+h0x$Ngz4!|Z0d|M4B-I!7c?U(M!9b)h@lGQ3|>B@pbuNxcPd)N!;> z0|!^QX&V`J;&m?RXBik|#-aWFwK;}a_pW}aM$sI$T2iel%6s0qq#UBu!H&)J^rW;L zs7pDR79}S8X}%B$`mv+hqoAhtbN%4uQP-)INpz})9n<^%Oi|}9$RaF~R8*|9V1HH> zUXbNX654dp=1|^_IA~v+5hB5Da8*MD3)cPRL}POX^Su}|8N?i##iX@Zs*F6UMNV`LYDf~^ujBi#e7L= zW4|4GR@pBbY=H5Ik$6=@YmL+T8}?jt3{`5Gm~7c-&5Sjr=yt3ST!YoWel+g0Aj4S6 zT`%QGpCln_O6Sz1%|9K?d^d+_aCdavs~MHQaj{TNENZL5w6V=|dPU52yt*Y1%m)uR z+b^B7_&70a*hP%Dogvp@-)W_@xr<*y{IbbM7*wk&61lm^h^8TNdNCi6tth+LQ&m>& zt(B}j2+q$KYeQojt|h))Y3Bg42ardl>~Ld&?M9GbkC&EH$8M-ShRHZ!SO`DZ zJ`Ok;&|!ODuP7)9;{8jAfI{-#gn}#+Q`xJdY_lM#%I88WSM28E7*On3K;o0U9%x1-0xH)=h=`LcP~pmV_lMTdGHe5&AcIiq-8cWxCs z#9Z;UWkpmnZA8bowa$ZgLWHY`W@eRW(&}ko?&aa91^&-2P_#Gl91j>JPg zA?V;kB5|0TAh^6?-7=6Pk;H_K*l7tkQ@@Rr1n53|7(Sn4xzsQ0Im>8Bj|k4BjvzwM z1QO(s+kVI=L5_Tr1tYz6lD*g4BA2x3vTKQY#?6&CDuDCMeVWmoZ+UwzuE(cdSQO-? z`Ywoc!Y+9X*XGorB@An~jvxmSRos_|rXUBdKaa~fthc6%-&8Ax(?6ZL%t-59D@mjJ zD449@$Og%TQlR<0t8aS0otk!HbLD!F!h zwtkErIy&bD9)Ol)K3}ste2Z{}eM|@Xx1z1I}nf3#JncazF;#sqMK{I&s@%l r>i6||y%R-1#9=WhqVdVrO-lBJqsapQaQHp!_8%g6oW$|n!?XScw-7&h literal 0 HcmV?d00001 diff --git a/src/img/_PrivacyAgreement.png b/src/img/_PrivacyAgreement.png new file mode 100644 index 0000000000000000000000000000000000000000..7a7834d374dc4633d473ca2bb2c9a0db6ea3eef7 GIT binary patch literal 1698 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 literal 0 HcmV?d00001 diff --git a/src/types/RootNavigationProp.tsx b/src/types/RootNavigationProp.tsx new file mode 100644 index 0000000..aba66c8 --- /dev/null +++ b/src/types/RootNavigationProp.tsx @@ -0,0 +1,4 @@ +import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { RootStackParamList } from "../../App"; + +export type RootNavigationProp = NativeStackNavigationProp; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index ad0d219..bbd935a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,7 +16,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz" integrity sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw== -"@babel/core@^7.0.0", "@babel/core@^7.0.0 || ^8.0.0-0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.11.0", "@babel/core@^7.11.6", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.23.9", "@babel/core@^7.25.2", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.8.0": +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.25.2": version "7.28.4" resolved "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz" integrity sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA== @@ -37,7 +37,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/eslint-parser@^7.12.0", "@babel/eslint-parser@^7.25.1": +"@babel/eslint-parser@^7.25.1": version "7.28.4" resolved "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.28.4.tgz" integrity sha512-Aa+yDiH87980jR6zvRfFuCR1+dLb00vBydhTL+zI992Rz/wQhSvuxjmOOuJOgO3XmakO6RykRGD2S1mq1AtgHA== @@ -966,7 +966,7 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/runtime@^7.25.0": +"@babel/runtime@^7.25.0", "@babel/runtime@^7.27.6", "@babel/runtime@^7.28.4": version "7.28.4" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz" integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ== @@ -1359,7 +1359,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1372,6 +1372,13 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@react-native-async-storage/async-storage@^2.2.0": + version "2.2.0" + resolved "https://repo.huaweicloud.com/repository/npm/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz#a3aa565253e46286655560172f4e366e8969f5ad" + integrity sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw== + dependencies: + merge-options "^3.0.4" + "@react-native-community/cli-clean@20.0.0": version "20.0.0" resolved "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-20.0.0.tgz" @@ -1503,7 +1510,7 @@ dependencies: joi "^17.2.1" -"@react-native-community/cli@*", "@react-native-community/cli@20.0.0": +"@react-native-community/cli@20.0.0": version "20.0.0" resolved "https://registry.npmjs.org/@react-native-community/cli/-/cli-20.0.0.tgz" integrity sha512-/cMnGl5V1rqnbElY1Fvga1vfw0d3bnqiJLx2+2oh7l9ulnXfVRWb5tU2kgBqiMxuDOKA+DQoifC9q/tvkj5K2w== @@ -1679,7 +1686,7 @@ hermes-parser "0.29.1" nullthrows "^1.1.1" -"@react-native/metro-config@*", "@react-native/metro-config@0.81.4": +"@react-native/metro-config@0.81.4": version "0.81.4" resolved "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.81.4.tgz" integrity sha512-aEXhRMsz6yN5X63Zk+cdKByQ0j3dsKv+ETRP9lLARdZ82fBOCMuK6IfmZMwK3A/3bI7gSvt2MFPn3QHy3WnByw== @@ -1893,6 +1900,11 @@ resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== +"@types/lodash@^4.17.21": + version "4.17.21" + resolved "https://repo.huaweicloud.com/repository/npm/@types/lodash/-/lodash-4.17.21.tgz#b806831543d696b14f8112db600ea9d3a1df6ea4" + integrity sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ== + "@types/node@*": version "24.5.2" resolved "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz" @@ -1936,7 +1948,7 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.0.0 || ^6.0.0 || ^7.0.0", "@typescript-eslint/eslint-plugin@^7.1.1": +"@typescript-eslint/eslint-plugin@^7.1.1": version "7.18.0" resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz" integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== @@ -1951,7 +1963,7 @@ natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@^7.0.0", "@typescript-eslint/parser@^7.1.1": +"@typescript-eslint/parser@^7.1.1": version "7.18.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz" integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg== @@ -2025,6 +2037,16 @@ semver "^7.6.0" ts-api-utils "^1.3.0" +"@typescript-eslint/utils@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/utils@^5.10.0": version "5.62.0" resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz" @@ -2039,16 +2061,6 @@ eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/utils@7.18.0": - version "7.18.0" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz" - integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "7.18.0" - "@typescript-eslint/types" "7.18.0" - "@typescript-eslint/typescript-estree" "7.18.0" - "@typescript-eslint/visitor-keys@5.62.0": version "5.62.0" resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz" @@ -2095,7 +2107,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0, acorn@^8.9.0: +acorn@^8.15.0, acorn@^8.9.0: version "8.15.0" resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz" integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== @@ -2475,7 +2487,7 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" -browserslist@^4.24.0, browserslist@^4.25.3, "browserslist@>= 4.21.0": +browserslist@^4.24.0, browserslist@^4.25.3: version "4.26.2" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz" integrity sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A== @@ -2675,16 +2687,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + color-string@^1.9.0: version "1.9.1" resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" @@ -2847,27 +2859,20 @@ dayjs@^1.8.15: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz" integrity sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA== -debug@^2.6.9: +debug@2.6.9, debug@^2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.1, debug@4: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.1: version "4.4.3" resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: ms "^2.1.3" -debug@2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" @@ -3249,7 +3254,7 @@ eslint-plugin-react@^7.30.1: string.prototype.matchall "^4.0.12" string.prototype.repeat "^1.0.0" -eslint-scope@^5.1.1, eslint-scope@5.1.1: +eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3270,22 +3275,12 @@ eslint-visitor-keys@^2.1.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0: +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint-visitor-keys@^3.4.1: - version "3.4.3" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -"eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", "eslint@^7.5.0 || ^8.0.0 || ^9.0.0", eslint@^8.1.0, eslint@^8.19.0, eslint@^8.56.0, eslint@>=4.19.1, eslint@>=7.0.0, eslint@>=8: +eslint@^8.19.0: version "8.57.1" resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz" integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== @@ -3502,15 +3497,7 @@ finalhandler@1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^4.1.0: +find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -3791,6 +3778,13 @@ html-escaper@^2.0.0: resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +html-parse-stringify@^3.0.1: + version "3.0.1" + resolved "https://repo.huaweicloud.com/repository/npm/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== + dependencies: + void-elements "3.1.0" + http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" @@ -3815,6 +3809,13 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +i18next@^25.7.3: + version "25.7.3" + resolved "https://repo.huaweicloud.com/repository/npm/i18next/-/i18next-25.7.3.tgz#88bf15b414012a53ca87b9d408108aa81cb627cc" + integrity sha512-2XaT+HpYGuc2uTExq9TVRhLsso+Dxym6PWaKpn36wfBmTI779OQ7iP/XaZHzrnGyzU4SHpFrTYLKfVyBfAhVNA== + dependencies: + "@babel/runtime" "^7.28.4" + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -3868,7 +3869,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4045,6 +4046,11 @@ is-path-inside@^3.0.3: resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://repo.huaweicloud.com/repository/npm/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + is-regex@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz" @@ -4126,14 +4132,7 @@ is-wsl@^1.1.0: resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz" integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== -is-wsl@^2.1.1: - version "2.2.0" - resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -is-wsl@^2.2.0: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -4419,7 +4418,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@*, jest-resolve@^29.7.0: +jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -4563,7 +4562,7 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@*, jest@^29.6.3: +jest@^29.6.3: version "29.7.0" resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== @@ -4806,6 +4805,13 @@ memoize-one@^5.0.0: resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== +merge-options@^3.0.4: + version "3.0.4" + resolved "https://repo.huaweicloud.com/repository/npm/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7" + integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ== + dependencies: + is-plain-obj "^2.1.0" + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" @@ -4843,7 +4849,7 @@ metro-cache@0.83.2: https-proxy-agent "^7.0.5" metro-core "0.83.2" -metro-config@^0.83.1, metro-config@0.83.2: +metro-config@0.83.2, metro-config@^0.83.1: version "0.83.2" resolved "https://registry.npmjs.org/metro-config/-/metro-config-0.83.2.tgz" integrity sha512-1FjCcdBe3e3D08gSSiU9u3Vtxd7alGH3x/DNFqWDFf5NouX4kLgbVloDDClr1UrLz62c0fHh2Vfr9ecmrOZp+g== @@ -4857,7 +4863,7 @@ metro-config@^0.83.1, metro-config@0.83.2: metro-runtime "0.83.2" yaml "^2.6.1" -metro-core@^0.83.1, metro-core@0.83.2: +metro-core@0.83.2, metro-core@^0.83.1: version "0.83.2" resolved "https://registry.npmjs.org/metro-core/-/metro-core-0.83.2.tgz" integrity sha512-8DRb0O82Br0IW77cNgKMLYWUkx48lWxUkvNUxVISyMkcNwE/9ywf1MYQUE88HaKwSrqne6kFgCSA/UWZoUT0Iw== @@ -4896,7 +4902,7 @@ metro-resolver@0.83.2: dependencies: flow-enums-runtime "^0.0.6" -metro-runtime@^0.83.1, metro-runtime@0.83.2: +metro-runtime@0.83.2, metro-runtime@^0.83.1: version "0.83.2" resolved "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.2.tgz" integrity sha512-nnsPtgRvFbNKwemqs0FuyFDzXLl+ezuFsUXDbX8o0SXOfsOPijqiQrf3kuafO1Zx1aUWf4NOrKJMAQP5EEHg9A== @@ -4904,7 +4910,7 @@ metro-runtime@^0.83.1, metro-runtime@0.83.2: "@babel/runtime" "^7.25.0" flow-enums-runtime "^0.0.6" -metro-source-map@^0.83.1, metro-source-map@0.83.2: +metro-source-map@0.83.2, metro-source-map@^0.83.1: version "0.83.2" resolved "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.2.tgz" integrity sha512-5FL/6BSQvshIKjXOennt9upFngq2lFvDakZn5LfauIVq8+L4sxXewIlSTcxAtzbtjAIaXeOSVMtCJ5DdfCt9AA== @@ -4963,7 +4969,7 @@ metro-transform-worker@0.83.2: metro-transform-plugins "0.83.2" nullthrows "^1.1.1" -metro@^0.83.1, metro@0.83.2: +metro@0.83.2, metro@^0.83.1: version "0.83.2" resolved "https://registry.npmjs.org/metro/-/metro-0.83.2.tgz" integrity sha512-HQgs9H1FyVbRptNSMy/ImchTTE5vS2MSqLoOo7hbDoBq6hPPZokwJvBMwrYSxdjQZmLXz2JFZtdvS+ZfgTc9yw== @@ -5017,16 +5023,16 @@ micromatch@^4.0.4, micromatch@^4.0.8: braces "^3.0.3" picomatch "^2.3.1" -"mime-db@>= 1.43.0 < 2": - version "1.54.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz" - integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== - mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== +"mime-db@>= 1.43.0 < 2": + version "1.54.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz" + integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" @@ -5034,43 +5040,22 @@ mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: dependencies: mime-db "1.52.0" -mime@^2.4.1: - version "2.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - mime@1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@^2.4.1: + version "2.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.0.4: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.5: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -5089,16 +5074,16 @@ mkdirp@^1.0.4: resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -ms@^2.1.3, ms@2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== +ms@2.1.3, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + nanoid@^3.3.11: version "3.3.11" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" @@ -5109,16 +5094,16 @@ natural-compare@^1.4.0: resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@~0.6.4: - version "0.6.4" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz" - integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== - negotiator@0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +negotiator@~0.6.4: + version "0.6.4" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz" + integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== + nocache@^3.0.1: version "3.0.4" resolved "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz" @@ -5220,13 +5205,6 @@ object.values@^1.1.6, object.values@^1.2.1: define-properties "^1.2.1" es-object-atoms "^1.0.0" -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" - integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== - dependencies: - ee-first "1.1.1" - on-finished@2.4.1: version "2.4.1" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" @@ -5234,6 +5212,13 @@ on-finished@2.4.1: dependencies: ee-first "1.1.1" +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + on-headers@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz" @@ -5416,7 +5401,7 @@ prelude-ls@^1.2.1: resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@>=2, prettier@2.8.8: +prettier@2.8.8: version "2.8.8" resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -5521,6 +5506,15 @@ react-freeze@^1.0.0: resolved "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz" integrity sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA== +react-i18next@^16.5.0: + version "16.5.0" + resolved "https://repo.huaweicloud.com/repository/npm/react-i18next/-/react-i18next-16.5.0.tgz#107e4323742344a2f8792feb905cea551da6fd2c" + integrity sha512-IMpPTyCTKxEj8klCrLKUTIUa8uYTd851+jcu2fJuUB9Agkk9Qq8asw4omyeHVnOXHrLgQJGTm5zTvn8HpaPiqw== + dependencies: + "@babel/runtime" "^7.27.6" + html-parse-stringify "^3.0.1" + use-sync-external-store "^1.6.0" + react-is@^16.13.1: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" @@ -5536,6 +5530,11 @@ react-is@^19.1.0: resolved "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz" integrity sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA== +react-native-device-info@^15.0.1: + version "15.0.1" + resolved "https://repo.huaweicloud.com/repository/npm/react-native-device-info/-/react-native-device-info-15.0.1.tgz#8a2716861bb8e491e0627f326bcc007c77d2e8f6" + integrity sha512-U5waZRXtT3l1SgZpZMlIvMKPTkFZPH8W7Ks6GrJhdH723aUIPxjVer7cRSij1mvQdOAAYFJV/9BDzlC8apG89A== + react-native-fs@^2.20.0: version "2.20.0" resolved "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz" @@ -5549,12 +5548,12 @@ react-native-is-edge-to-edge@^1.2.1: resolved "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz" integrity sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q== -react-native-safe-area-context@^5.6.1, "react-native-safe-area-context@>= 4.0.0": +react-native-safe-area-context@^5.6.1: version "5.6.1" resolved "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.1.tgz" integrity sha512-/wJE58HLEAkATzhhX1xSr+fostLsK8Q97EfpfMDKo8jlOc1QKESSX/FQrhk7HhQH/2uSaox4Y86sNaI02kteiA== -react-native-screens@^4.16.0, "react-native-screens@>= 4.0.0": +react-native-screens@^4.16.0: version "4.16.0" resolved "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz" integrity sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q== @@ -5563,6 +5562,16 @@ react-native-screens@^4.16.0, "react-native-screens@>= 4.0.0": react-native-is-edge-to-edge "^1.2.1" warn-once "^0.1.0" +react-native-status-bar-height@^2.6.0: + version "2.6.0" + resolved "https://repo.huaweicloud.com/repository/npm/react-native-status-bar-height/-/react-native-status-bar-height-2.6.0.tgz#b6afd25b6e3d533c43d0fcdcfd5cafd775592cea" + integrity sha512-z3SGLF0mHT+OlJDq7B7h/jXPjWcdBT3V14Le5L2PjntjjWM3+EJzq2BcXDwV+v67KFNJic5pgA26cCmseYek6w== + +react-native-toast-message@^2.3.3: + version "2.3.3" + resolved "https://repo.huaweicloud.com/repository/npm/react-native-toast-message/-/react-native-toast-message-2.3.3.tgz#e301508d386a9902ff6b4559ecc6674f8cfdf97a" + integrity sha512-4IIUHwUPvKHu4gjD0Vj2aGQzqPATiblL1ey8tOqsxOWRPGGu52iIbL8M/mCz4uyqecvPdIcMY38AfwRuUADfQQ== + react-native-vector-icons@^10.3.0: version "10.3.0" resolved "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.3.0.tgz" @@ -5571,7 +5580,7 @@ react-native-vector-icons@^10.3.0: prop-types "^15.7.2" yargs "^16.1.1" -react-native@*, react-native@0.81.4: +react-native@0.81.4: version "0.81.4" resolved "https://registry.npmjs.org/react-native/-/react-native-0.81.4.tgz" integrity sha512-bt5bz3A/+Cv46KcjV0VQa+fo7MKxs17RCcpzjftINlen4ZDUl0I6Ut+brQ2FToa5oD0IB0xvQHfmsg2EDqsZdQ== @@ -5624,7 +5633,7 @@ react-test-renderer@19.1.0: react-is "^19.1.0" scheduler "^0.26.0" -react@*, "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", react@^19.1.0, "react@>= 18.2.0", react@>=16.8, react@>=17.0.0, react@19.1.0: +react@19.1.0: version "19.1.0" resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz" integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== @@ -5798,7 +5807,7 @@ safe-array-concat@^1.1.3: has-symbols "^1.1.0" isarray "^2.0.5" -safe-buffer@~5.2.0, safe-buffer@5.2.1: +safe-buffer@5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5825,7 +5834,7 @@ safe-regex-test@^1.1.0: resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -scheduler@^0.26.0, scheduler@0.26.0: +scheduler@0.26.0, scheduler@^0.26.0: version "0.26.0" resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz" integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== @@ -5835,32 +5844,7 @@ semver@^6.3.0, semver@^6.3.1: resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.1.3: - version "7.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== - -semver@^7.3.7: - version "7.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== - -semver@^7.5.2: - version "7.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== - -semver@^7.5.3: - version "7.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== - -semver@^7.5.4: - version "7.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== - -semver@^7.6.0: +semver@^7.1.3, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: version "7.7.2" resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz" integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== @@ -6028,14 +6012,6 @@ slice-ansi@^2.0.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@0.5.13: version "0.5.13" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" @@ -6044,6 +6020,14 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map@^0.5.6: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" @@ -6083,16 +6067,16 @@ stacktrace-parser@^0.1.10: dependencies: type-fest "^0.7.1" -statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + stop-iteration-iterator@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz" @@ -6106,13 +6090,6 @@ strict-uri-encode@^2.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" @@ -6194,6 +6171,13 @@ string.prototype.trimstart@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-ansi@^5.0.0: version "5.2.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" @@ -6390,7 +6374,7 @@ typed-array-length@^1.0.7: possible-typed-array-names "^1.0.0" reflect.getprototypeof "^1.0.6" -typescript@^5.8.3, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.2.0, typescript@>=4.9.5: +typescript@^5.8.3: version "5.9.2" resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz" integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A== @@ -6438,7 +6422,7 @@ universalify@^0.1.0: resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -unpipe@~1.0.0, unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -6468,6 +6452,11 @@ use-sync-external-store@^1.5.0: resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz" integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A== +use-sync-external-store@^1.6.0: + version "1.6.0" + resolved "https://repo.huaweicloud.com/repository/npm/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" + integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== + utf8@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz" @@ -6502,6 +6491,11 @@ vlq@^1.0.0: resolved "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz" integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== +void-elements@3.1.0: + version "3.1.0" + resolved "https://repo.huaweicloud.com/repository/npm/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== + walker@^1.0.7, walker@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" @@ -6634,12 +6628,7 @@ ws@^6.2.3: dependencies: async-limiter "~1.0.0" -ws@^7: - version "7.5.10" - resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" - integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== - -ws@^7.5.10: +ws@^7, ws@^7.5.10: version "7.5.10" resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==