feat: 下载页面

This commit is contained in:
jinyaqiu 2025-07-22 16:43:51 +08:00
parent 06a579cf04
commit f3d6f36662
9 changed files with 336 additions and 54 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,56 @@
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 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 onClose={() => {
// Handle close action if needed
}} />
)
} */}
<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>
<AppDownload IOS_APP_STORE_URL={IOS_APP_STORE_URL} ANDROID_APK_URL={ANDROID_APK_URL} platform={platform} />
</View>
<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

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

@ -0,0 +1,167 @@
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';
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={{ zIndex: 2 }}>
<svg width="285" height="285" viewBox="0 0 285 285" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="285" height="285" rx="36" fill="white" />
</svg>
</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'
},
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,
},
downloadButton: {
backgroundColor: '#fff',
borderRadius: 30,
paddingVertical: 16,
paddingHorizontal: 40,
minWidth: 240,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 5,
},
downloadButtonText: {
color: '#FF8C00',
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

@ -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"
}

11
package-lock.json generated
View File

@ -56,6 +56,7 @@
"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",
@ -14764,6 +14765,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",

View File

@ -62,6 +62,7 @@
"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",