feat: 下载页面

This commit is contained in:
jinyaqiu 2025-07-22 16:43:51 +08:00
parent 06a579cf04
commit ea5f0d05e9
11 changed files with 718 additions and 59 deletions

View File

@ -316,6 +316,17 @@ export default function TabLayout() {
}}
/>
)}
{/* 下载页面 */}
<Tabs.Screen
name="download"
options={{
title: 'download',
tabBarButton: () => null, // 隐藏底部标签栏
headerShown: false, // 隐藏导航栏
tabBarStyle: { display: 'none' } // 确保在标签栏中不显示
}}
/>
</Tabs >
);
}

View File

@ -1,63 +1,53 @@
import AndroidLogo from '@/assets/icons/svg/android.svg';
import AppleLogo from '@/assets/icons/svg/apple.svg';
import MemoIP from '@/assets/icons/svg/memo-ip.svg';
import { LinearGradient } from 'expo-linear-gradient';
import { useTranslation } from 'react-i18next';
import { Linking, Text, TouchableOpacity, View } from 'react-native';
import { AppDownload } from '@/components/download/app';
import PCDownload from '@/components/download/pc';
import React, { useEffect, useState } from 'react';
import { Platform, Text, View } from 'react-native';
const IOS_APP_STORE_URL = 'https://apps.apple.com/cn/app/id6748205761';
const ANDROID_APK_URL = 'https://cdn.memorywake.com/apks/application-f086a38c-dac1-43f1-9d24-e4378c2ce121.apk';
export default function DownloadScreen() {
const handleIOSDownload = () => {
Linking.openURL(IOS_APP_STORE_URL);
};
const handleAndroidDownload = () => {
Linking.openURL(ANDROID_APK_URL);
};
const [loading, setLoading] = useState(false)
const [platform, setPlatform] = useState('')
// 判断是什么平台
const getPlatform = () => {
let platform;
if (Platform.OS === 'ios') {
platform = 'ios';
} else if (Platform.OS === 'android') {
platform = 'android';
} else {
platform = 'pc';
}
return platform;
}
const { t } = useTranslation();
useEffect(() => {
setLoading(true)
const platform = getPlatform();
setPlatform(platform)
setLoading(false)
}, [])
if (loading) {
return (
<View className="flex-1 bg-bgPrimary justify-center items-center">
<Text className="text-white">loading...</Text>
</View>
);
}
return (
<LinearGradient
colors={['#FFB645', '#E2793F']}
className="flex-1 items-center justify-center p-6"
>
<View className="absolute top-0 left-0 w-full h-full">
<MemoIP width="100%" height="100%" style={{ opacity: 0.1 }} />
</View>
<View className="items-center mb-12">
<Text className="text-white text-5xl font-extrabold tracking-tight">
MemoWake
</Text>
<Text className="text-white/90 text-lg mt-4 text-center max-w-xs">
{t('desc', { ns: 'download' })}
</Text>
</View>
<View style={{ flex: 1 }}>
{
platform === 'pc' && <PCDownload IOS_APP_STORE_URL={IOS_APP_STORE_URL} ANDROID_APK_URL={ANDROID_APK_URL} />
}
{
(platform === 'ios' || platform === 'android') && (
<AppDownload IOS_APP_STORE_URL={IOS_APP_STORE_URL} ANDROID_APK_URL={ANDROID_APK_URL} platform={platform} />
)
}
</View>
<View className="w-full max-w-xs">
<TouchableOpacity
className="bg-white/90 rounded-xl px-6 py-4 flex-row items-center justify-center shadow-lg mb-5"
onPress={handleIOSDownload}
activeOpacity={0.8}
>
<AppleLogo width={24} height={24} fill="black" />
<Text className="text-black font-bold text-lg ml-3">
{t('ios', { ns: 'download' })}
</Text>
</TouchableOpacity>
<TouchableOpacity
className="bg-black/80 rounded-xl px-6 py-4 flex-row items-center justify-center shadow-lg"
onPress={handleAndroidDownload}
activeOpacity={0.8}
>
<AndroidLogo width={24} height={24} fill="#3DDC84" />
<Text className="text-white font-bold text-lg ml-3">
{t('android', { ns: 'download' })}
</Text>
</TouchableOpacity>
</View>
</LinearGradient>
);
)
}

26
assets/icons/svg/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 952 KiB

175
components/download/app.tsx Normal file
View File

@ -0,0 +1,175 @@
import HandlersSvg from "@/assets/icons/svg/handers.svg";
import LogoSvg from "@/assets/icons/svg/logo.svg";
import UserinfoTotalSvg from "@/assets/icons/svg/userinfoTotal.svg";
import { useTranslation } from 'react-i18next';
import { Linking, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import QRDownloadScreen from "./qrCode";
interface AppDownloadProps {
IOS_APP_STORE_URL: string,
ANDROID_APK_URL: string,
platform: string
}
export const AppDownload = (props: AppDownloadProps) => {
const { t } = useTranslation();
const insets = useSafeAreaInsets();
const { IOS_APP_STORE_URL, ANDROID_APK_URL, platform } = props
const handleAppStoreDownload = () => {
Linking.openURL(IOS_APP_STORE_URL);
};
const handlePlayStoreDownload = () => {
Linking.openURL(ANDROID_APK_URL);
};
return (
<View style={[styles.container, { paddingTop: insets.top }]}>
{/* Main Content */}
<View style={styles.content}>
{/* App Icon */}
<LogoSvg />
{/* App Name */}
<Text style={styles.appName}>MemoWake</Text>
{/* QRCode */}
<View style={styles.qrCodeContainer}>
<UserinfoTotalSvg style={{ marginBottom: -20, zIndex: 1 }} />
<HandlersSvg style={{ marginBottom: -4, zIndex: 3 }} />
<View style={styles.qrCode}>
<QRDownloadScreen url={platform == "ios" ? IOS_APP_STORE_URL : ANDROID_APK_URL} />
</View>
</View>
{/* Description */}
<Text style={styles.description}>
{t('mobileDescription', { ns: 'download' })}
</Text>
{/* Download Button */}
<TouchableOpacity
style={styles.downloadButton}
onPress={Platform.OS === 'ios' ? handleAppStoreDownload : handlePlayStoreDownload}
>
<Text style={styles.downloadButtonText}>
{t('download', { ns: 'download' })}
</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#FFB645'
},
qrCodeContainer: {
justifyContent: 'center',
alignItems: 'center',
},
qrCodeBg: {
justifyContent: 'center',
alignItems: 'center'
},
qrCode: {
justifyContent: 'center',
alignItems: 'center',
padding: 16,
borderRadius: 12,
zIndex: 2,
backgroundColor: '#fff',
},
closeButton: {
width: 30,
height: 30,
borderRadius: 15,
backgroundColor: 'rgba(255, 255, 255, 0.3)',
justifyContent: 'center',
alignItems: 'center',
},
closeButtonText: {
color: '#fff',
fontSize: 18,
lineHeight: 24,
},
content: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingBottom: 40,
},
appIconImage: {
width: 100,
height: 100
},
appIconText: {
fontSize: 50,
},
appName: {
fontSize: 32,
fontWeight: 'bold',
color: '#fff',
marginBottom: 12,
},
description: {
fontSize: 16,
color: 'rgba(255, 255, 255, 0.9)',
textAlign: 'center',
marginBottom: 32,
paddingHorizontal: 40,
lineHeight: 24,
marginVertical: 32
},
downloadButton: {
backgroundColor: '#fff',
borderRadius: 30,
paddingVertical: 16,
paddingHorizontal: 40,
width: "90%",
alignItems: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 5,
marginTop: 40
},
downloadButtonText: {
color: '#4C320C',
fontSize: 18,
fontWeight: 'bold',
},
badgesContainer: {
alignItems: 'center',
paddingBottom: 40,
},
availableOnText: {
color: 'rgba(255, 255, 255, 0.8)',
fontSize: 14,
marginBottom: 12,
},
badgesRow: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
badgeButton: {
backgroundColor: '#fff',
borderRadius: 8,
paddingVertical: 8,
paddingHorizontal: 16,
marginHorizontal: 8,
minWidth: 120,
alignItems: 'center',
justifyContent: 'center',
height: 40,
},
badgeText: {
fontSize: 14,
fontWeight: '600',
},
});

View File

@ -0,0 +1,69 @@
import AndroidLogo from '@/assets/icons/svg/android.svg';
import AppleLogo from '@/assets/icons/svg/apple.svg';
import MemoIP from '@/assets/icons/svg/memo-ip.svg';
import { LinearGradient } from 'expo-linear-gradient';
import { useTranslation } from 'react-i18next';
import { Linking, Text, TouchableOpacity, View } from 'react-native';
interface PCDownloadProps {
IOS_APP_STORE_URL: string,
ANDROID_APK_URL: string
}
const PCDownload = (props: PCDownloadProps) => {
const { IOS_APP_STORE_URL, ANDROID_APK_URL } = props
const handleIOSDownload = () => {
Linking.openURL(IOS_APP_STORE_URL);
};
const handleAndroidDownload = () => {
Linking.openURL(ANDROID_APK_URL);
};
const { t } = useTranslation();
return (
<LinearGradient
colors={['#FFB645', '#E2793F']}
className="flex-1 items-center justify-center p-6"
>
<View className="absolute top-0 left-0 w-full h-full">
<MemoIP width="100%" height="100%" style={{ opacity: 0.1 }} />
</View>
<View className="items-center mb-12">
<Text className="text-white text-5xl font-extrabold tracking-tight">
MemoWake
</Text>
<Text className="text-white/90 text-lg mt-4 text-center max-w-xs">
{t('desc', { ns: 'download' })}
</Text>
</View>
<View className="w-full max-w-xs">
<TouchableOpacity
className="bg-white/90 rounded-xl px-6 py-4 flex-row items-center justify-center shadow-lg mb-5"
onPress={handleIOSDownload}
activeOpacity={0.8}
>
<AppleLogo width={24} height={24} fill="black" />
<Text className="text-black font-bold text-lg ml-3">
{t('ios', { ns: 'download' })}
</Text>
</TouchableOpacity>
<TouchableOpacity
className="bg-black/80 rounded-xl px-6 py-4 flex-row items-center justify-center shadow-lg"
onPress={handleAndroidDownload}
activeOpacity={0.8}
>
<AndroidLogo width={24} height={24} fill="#3DDC84" />
<Text className="text-white font-bold text-lg ml-3">
{t('android', { ns: 'download' })}
</Text>
</TouchableOpacity>
</View>
</LinearGradient>
)
}
export default PCDownload

View File

@ -0,0 +1,71 @@
import * as Haptics from 'expo-haptics';
import * as MediaLibrary from 'expo-media-library';
import React, { useRef } from 'react';
import { Alert, StyleSheet, TouchableOpacity, View } from 'react-native';
import QRCode from 'react-native-qrcode-svg';
import { captureRef } from 'react-native-view-shot';
export default function QRDownloadScreen(prop: { url: string }) {
const qrViewRef = useRef<View>(null); // 用于截图的引用
const [qrValue] = React.useState(prop.url); // 二维码内容
const saveQRToGallery = async () => {
try {
// 触发轻震,提升交互感
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
// 请求相册写入权限
const { status } = await MediaLibrary.requestPermissionsAsync();
if (status !== 'granted') {
Alert.alert('权限被拒绝', '需要保存图片到相册的权限');
return;
}
if (!qrViewRef.current) return;
// 截取二维码视图
const uri = await captureRef(qrViewRef, {
format: 'png',
quality: 1,
result: 'tmpfile', // 返回临时文件路径
});
// 保存到相册
await MediaLibrary.saveToLibraryAsync(uri);
Alert.alert('✅ 成功', '二维码已保存到相册!');
} catch (error) {
console.error('保存失败:', error);
Alert.alert('❌ 失败', '无法保存图片,请重试');
}
};
return (
<View style={styles.container}>
{/* 可截图的容器 */}
<TouchableOpacity onLongPress={saveQRToGallery} activeOpacity={0.8}>
<View ref={qrViewRef} style={styles.qrContainer}>
<QRCode value={qrValue} size={200} />
</View>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
// flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
qrContainer: {
padding: 16,
backgroundColor: '#fff',
borderRadius: 12,
},
tip: {
marginTop: 20,
color: '#666',
fontSize: 14,
},
});

View File

@ -1,4 +1,5 @@
import SettingSvg from '@/assets/icons/svg/setting.svg';
import { useRouter } from 'expo-router';
import { useTranslation } from 'react-i18next';
import { StyleProp, StyleSheet, TouchableOpacity, View, ViewStyle } from "react-native";
import { ThemedText } from "../ThemedText";
@ -9,9 +10,11 @@ interface CategoryProps {
const AlbumComponent = ({ setModalVisible, style }: CategoryProps) => {
const { t } = useTranslation();
const router = useRouter();
return (
<View style={[styles.container, style]}>
<TouchableOpacity style={{ flex: 3 }}>
<TouchableOpacity style={{ flex: 3 }} onPress={() => { router.push("/download") }}>
<ThemedText style={styles.text}>{t('generalSetting.album', { ns: 'personal' })}</ThemedText>
</TouchableOpacity>
<TouchableOpacity style={{ flex: 3 }}>

View File

@ -2,5 +2,7 @@
"title": "Download Our App",
"desc": "Get the full experience by downloading our app on your favorite platform.",
"ios": "Download for iOS",
"android": "Download for Android"
"android": "Download for Android",
"mobileDescription": "Scan the QR Code to awaken your precious memories",
"download": "Download MemoWake"
}

View File

@ -2,5 +2,7 @@
"title": "下载我们的应用",
"desc": "在您喜欢的平台上下载我们的应用,以获得完整的体验。",
"ios": "下载 iOS 版",
"android": "下载 Android 版"
"android": "下载 Android 版",
"mobileDescription": "扫描二维码唤醒珍贵记忆",
"download": "下载 MemoWake"
}

309
package-lock.json generated
View File

@ -56,17 +56,20 @@
"react-i18next": "^15.5.3",
"react-native": "0.79.5",
"react-native-gesture-handler": "~2.24.0",
"react-native-linear-gradient": "^2.8.3",
"react-native-modal": "^14.0.0-rc.1",
"react-native-picker-select": "^9.3.1",
"react-native-progress": "^5.0.1",
"react-native-qrcode-svg": "^6.3.15",
"react-native-reanimated": "~3.17.4",
"react-native-reanimated-carousel": "^4.0.2",
"react-native-render-html": "^6.3.4",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "~4.11.1",
"react-native-svg": "15.11.2",
"react-native-svg": "^15.11.2",
"react-native-toast-message": "^2.3.0",
"react-native-uuid": "^2.0.3",
"react-native-view-shot": "4.0.3",
"react-native-web": "~0.20.0",
"react-native-webview": "13.13.5",
"react-redux": "^9.2.0"
@ -6148,6 +6151,15 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -7064,6 +7076,15 @@
"hyphenate-style-name": "^1.0.3"
}
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/css-select": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
@ -7250,6 +7271,15 @@
}
}
},
"node_modules/decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/decode-uri-component": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
@ -7421,6 +7451,12 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
"license": "MIT"
},
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
@ -9985,6 +10021,19 @@
"void-elements": "3.1.0"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"license": "MIT",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/htmlparser2": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
@ -14422,6 +14471,23 @@
],
"license": "MIT"
},
"node_modules/qrcode": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
"license": "MIT",
"dependencies": {
"dijkstrajs": "^1.0.1",
"pngjs": "^5.0.0",
"yargs": "^15.3.1"
},
"bin": {
"qrcode": "bin/qrcode"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/qrcode-terminal": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz",
@ -14430,6 +14496,165 @@
"qrcode-terminal": "bin/qrcode-terminal.js"
}
},
"node_modules/qrcode/node_modules/cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"node_modules/qrcode/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/qrcode/node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"license": "MIT",
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"license": "MIT",
"dependencies": {
"p-locate": "^4.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/qrcode/node_modules/p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"license": "MIT",
"dependencies": {
"p-limit": "^2.2.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/pngjs": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
"license": "MIT",
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/qrcode/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"license": "ISC"
},
"node_modules/qrcode/node_modules/yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"license": "MIT",
"dependencies": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"license": "ISC",
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/query-string": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
@ -14764,6 +14989,16 @@
"react-native": "*"
}
},
"node_modules/react-native-linear-gradient": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
"integrity": "sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==",
"license": "MIT",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-modal": {
"version": "14.0.0-rc.1",
"resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-14.0.0-rc.1.tgz",
@ -14802,6 +15037,22 @@
"react-native-svg": "*"
}
},
"node_modules/react-native-qrcode-svg": {
"version": "6.3.15",
"resolved": "https://registry.npmjs.org/react-native-qrcode-svg/-/react-native-qrcode-svg-6.3.15.tgz",
"integrity": "sha512-vLuNImGfstE8u+rlF4JfFpq65nPhmByuDG6XUPWh8yp8MgLQX11rN5eQ8nb/bf4OB+V8XoLTJB/AZF2g7jQSSQ==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.8.0",
"qrcode": "^1.5.4",
"text-encoding": "^0.7.0"
},
"peerDependencies": {
"react": "*",
"react-native": ">=0.63.4",
"react-native-svg": ">=14.0.0"
}
},
"node_modules/react-native-reanimated": {
"version": "3.17.5",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.17.5.tgz",
@ -14947,6 +15198,19 @@
"npm": ">=6.0.0"
}
},
"node_modules/react-native-view-shot": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/react-native-view-shot/-/react-native-view-shot-4.0.3.tgz",
"integrity": "sha512-USNjYmED7C0me02c1DxKA0074Hw+y/nxo+xJKlffMvfUWWzL5ELh/TJA/pTnVqFurIrzthZDPtDM7aBFJuhrHQ==",
"license": "MIT",
"dependencies": {
"html2canvas": "^1.4.1"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-web": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.20.0.tgz",
@ -15289,6 +15553,12 @@
"node": ">=0.10.0"
}
},
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"license": "ISC"
},
"node_modules/requireg": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/requireg/-/requireg-0.2.2.tgz",
@ -15804,6 +16074,12 @@
"integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==",
"license": "MIT"
},
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@ -16771,6 +17047,22 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/text-encoding": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz",
"integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==",
"deprecated": "no longer maintained",
"license": "(Unlicense OR Apache-2.0)"
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@ -17445,6 +17737,15 @@
"node": ">= 0.4.0"
}
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"license": "MIT",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/uuid": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
@ -17660,6 +17961,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
"license": "ISC"
},
"node_modules/which-typed-array": {
"version": "1.1.19",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",

View File

@ -62,20 +62,23 @@
"react-i18next": "^15.5.3",
"react-native": "0.79.5",
"react-native-gesture-handler": "~2.24.0",
"react-native-linear-gradient": "^2.8.3",
"react-native-modal": "^14.0.0-rc.1",
"react-native-picker-select": "^9.3.1",
"react-native-progress": "^5.0.1",
"react-native-qrcode-svg": "^6.3.15",
"react-native-reanimated": "~3.17.4",
"react-native-reanimated-carousel": "^4.0.2",
"react-native-render-html": "^6.3.4",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "~4.11.1",
"react-native-svg": "15.11.2",
"react-native-svg": "^15.11.2",
"react-native-toast-message": "^2.3.0",
"react-native-uuid": "^2.0.3",
"react-native-web": "~0.20.0",
"react-native-webview": "13.13.5",
"react-redux": "^9.2.0"
"react-redux": "^9.2.0",
"react-native-view-shot": "4.0.3"
},
"devDependencies": {
"@babel/core": "^7.25.2",