diff --git a/components/download/app.tsx b/components/download/app.tsx
index d0f2ddd..40de423 100644
--- a/components/download/app.tsx
+++ b/components/download/app.tsx
@@ -3,8 +3,8 @@ 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 QRCode from 'react-native-qrcode-svg';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import QRDownloadScreen from "./qrCode";
interface AppDownloadProps {
IOS_APP_STORE_URL: string,
@@ -39,7 +39,8 @@ export const AppDownload = (props: AppDownloadProps) => {
-
+ {/* {
logoSize={50}
logoBorderRadius={10}
logoBackgroundColor="#f0f0f0"
- />
+ /> */}
{/* Description */}
diff --git a/components/download/qrCode.tsx b/components/download/qrCode.tsx
new file mode 100644
index 0000000..419fd8c
--- /dev/null
+++ b/components/download/qrCode.tsx
@@ -0,0 +1,90 @@
+import * as Haptics from 'expo-haptics';
+import * as MediaLibrary from 'expo-media-library';
+import React, { useRef } from 'react';
+import { Alert, StyleSheet, Text, 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(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 (
+
+ 长按保存二维码
+
+ {/* 可截图的容器 */}
+
+
+
+
+
+
+ 👉 长按二维码即可保存
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: 20,
+ backgroundColor: '#f8f8f8',
+ },
+ title: {
+ fontSize: 18,
+ fontWeight: 'bold',
+ marginBottom: 20,
+ textAlign: 'center',
+ },
+ qrContainer: {
+ padding: 16,
+ backgroundColor: '#fff',
+ borderRadius: 12,
+ borderWidth: 1,
+ borderColor: '#ddd',
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.1,
+ shadowRadius: 4,
+ elevation: 3,
+ },
+ tip: {
+ marginTop: 20,
+ color: '#666',
+ fontSize: 14,
+ },
+});
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 7d9d7bf..1a876dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -69,6 +69,7 @@
"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"
@@ -6150,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",
@@ -7066,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",
@@ -10002,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",
@@ -15166,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",
@@ -17009,6 +17054,15 @@
"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",
@@ -17683,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",
diff --git a/package.json b/package.json
index 20247a6..1d563ba 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,8 @@
"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",