import React, { useEffect, useState, useRef } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, StatusBar, Platform, BackHandler, TextInput, Animated, Easing, FlatList, Keyboard, Modal, InteractionManager, Image, } from 'react-native'; import { useTranslation } from 'react-i18next'; import { useNavigation } from '@react-navigation/native'; import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { Country, countries } from '../constants/countries'; import { useAuth } from '../contexts/AuthContext'; import { settingApi } from "../services/api/setting"; import { userApi } from "../services/api/userApi"; import AsyncStorage from "@react-native-async-storage/async-storage"; type RootStackParamList = { Login: undefined; EmailLogin: undefined; MainTabs: { screen: string }; Google: undefined; Home: { screen: string }; }; // 常见邮箱后缀列表 const EMAIL_DOMAINS = [ 'gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'icloud.com', 'mail.com', 'protonmail.com', 'qq.com', '163.com', '126.com', ]; type LoginScreenProps = { onClose?: () => void; isModal?: boolean; }; export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => { const { t } = useTranslation(); const navigation = useNavigation>(); const { login } = useAuth(); // 邮箱登录状态 const [showEmailLogin, setShowEmailLogin] = useState(false); const [email, setEmail] = useState(''); const [emailPassword, setEmailPassword] = useState(''); const [emailPasswordError, setEmailPasswordError] = useState(false); const [showSuggestions, setShowSuggestions] = useState(false); const [suggestions, setSuggestions] = useState([]); // 手机号登录状态 const [showPhoneLogin, setShowPhoneLogin] = useState(false); const [phoneNumber, setPhoneNumber] = useState(''); const [password, setPassword] = useState(''); const [passwordError, setPasswordError] = useState(false); const [showCountryModal, setShowCountryModal] = useState(false); const [selectedCountry, setSelectedCountry] = useState({ name: 'Republic of Congo', code: 'CG', flag: '🇨🇬', userCount: 300000, phoneCode: '+242' }); // 动画值 const emailSlideAnim = useRef(new Animated.Value(400)).current; const phoneSlideAnim = useRef(new Animated.Value(400)).current; const [emailLoginMounted, setEmailLoginMounted] = useState(false); const [phoneLoginMounted, setPhoneLoginMounted] = useState(false); // 处理邮箱输入变化,生成邮箱建议 const handleEmailChange = (text: string) => { setEmail(text); // 检查是否包含@符号 if (text.includes('@')) { const [username, domain] = text.split('@'); if (domain) { // 如果已经输入了部分域名,过滤匹配的域名 const filteredDomains = EMAIL_DOMAINS.filter(item => item.toLowerCase().startsWith(domain.toLowerCase()) ); // 生成完整的邮箱建议列表 const emailSuggestions = filteredDomains.map(d => `${username}@${d}`); setSuggestions(emailSuggestions); setShowSuggestions(emailSuggestions.length > 0); } else { // 如果只输入了@,显示所有域名建议 const emailSuggestions = EMAIL_DOMAINS.map(d => `${username}@${d}`); setSuggestions(emailSuggestions); setShowSuggestions(true); } } else if (text.length > 0) { // 没有@符号但有输入内容,显示常见邮箱后缀建议 const emailSuggestions = EMAIL_DOMAINS.map(d => `${text}@${d}`); setSuggestions(emailSuggestions); setShowSuggestions(true); } else { // 输入为空,不显示建议 setShowSuggestions(false); } }; // 选择一个邮箱建议 const handleSelectSuggestion = (suggestion: string) => { setEmail(suggestion); setShowSuggestions(false); }; // 验证邮箱格式 const isValidEmail = (email: string): boolean => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }; // 渲染单个邮箱建议项 const renderSuggestionItem = ({ item }: { item: string }) => ( handleSelectSuggestion(item)} > {item} ); // 选择国家 const handleCountrySelect = (country: Country) => { setSelectedCountry(country); setShowCountryModal(false); }; // 渲染国家列表项 - 添加性能优化 const renderCountryItem = React.useCallback(({ item }: { item: Country }) => ( handleCountrySelect(item)} activeOpacity={0.7} > {item.flag} {item.name} {item.phoneCode} ), []); // 添加Android返回按钮处理 useEffect(() => { const backAction = () => { if (showEmailLogin) { closeEmailLogin(); return true; } if (showPhoneLogin) { closePhoneLogin(); return true; } if (showCountryModal) { setShowCountryModal(false); return true; } handleClose(); return true; }; const backHandler = BackHandler.addEventListener( 'hardwareBackPress', backAction ); return () => backHandler.remove(); }, [showEmailLogin, showPhoneLogin, showCountryModal]); // 初始化动画配置 useEffect(() => { // React Native Animated API不支持直接设置useNativeDriver // 这些配置会在动画函数中使用 }, []); // 打开邮箱登录面板 const openEmailLogin = () => { emailSlideAnim.setValue(400); setEmailLoginMounted(true); // 等待组件挂载后启动动画 requestAnimationFrame(() => { setShowEmailLogin(true); Animated.spring(emailSlideAnim, { toValue: 0, useNativeDriver: true, friction: 8, tension: 40, restDisplacementThreshold: 0.01, restSpeedThreshold: 0.01, }).start(); }); }; // 关闭邮箱登录面板 const closeEmailLogin = () => { Keyboard.dismiss(); // 使用更简单的配置减少计算复杂度 Animated.timing(emailSlideAnim, { toValue: 400, duration: 200, useNativeDriver: true, easing: Easing.cubic, }).start(); // 先隐藏建议列表,减少布局计算 setShowSuggestions(false); // 使用InteractionManager确保动画完成后再执行耗时操作 InteractionManager.runAfterInteractions(() => { setShowEmailLogin(false); setEmail(''); setEmailPassword(''); setEmailPasswordError(false); // 延迟卸载组件 setTimeout(() => { setEmailLoginMounted(false); }, 50); }); }; // 打开手机号登录面板 const openPhoneLogin = () => { phoneSlideAnim.setValue(400); setPhoneLoginMounted(true); // 等待组件挂载后启动动画 requestAnimationFrame(() => { setShowPhoneLogin(true); Animated.spring(phoneSlideAnim, { toValue: 0, useNativeDriver: true, friction: 8, tension: 40, restDisplacementThreshold: 0.01, restSpeedThreshold: 0.01, }).start(); }); }; // 关闭手机号登录面板 const closePhoneLogin = () => { Keyboard.dismiss(); // 使用更简单的配置减少计算复杂度 Animated.timing(phoneSlideAnim, { toValue: 400, duration: 200, useNativeDriver: true, easing: Easing.cubic, }).start(); // 使用InteractionManager确保动画完成后再执行耗时操作 InteractionManager.runAfterInteractions(() => { setShowPhoneLogin(false); setPhoneNumber(''); // 延迟卸载组件 setTimeout(() => { setPhoneLoginMounted(false); }, 50); }); }; // 修改关闭按钮处理函数 const handleClose = () => { if (isModal && onClose) { onClose(); } else { navigation.goBack(); } }; // 处理谷歌登录 const handleGoogleLogin = async () => { navigation.navigate('Google'); }; const handleFacebookLogin = () => { // 处理Facebook登录 }; const handleAppleLogin = () => { // 处理Apple登录 }; const handleInstagramLogin = () => { // 处理Instagram登录 }; const handleEmailLogin = () => { // 处理邮箱登录 - 显示邮箱登录面板 openEmailLogin(); }; // const handleEmailContinue = async () => { // if (emailPassword === '123') { // setEmailPasswordError(false); // await login(); // closeEmailLogin(); // navigation.replace('MainTabs'); // } else { // setEmailPasswordError(true); // } const params = { grant_type: "password", username: "test", password: "string", client_id: "2", client_secret: "", scope: "", }; const res = await userApi.login(params); const token = res.token_type + " " + res.access_token; await AsyncStorage.setItem("token", token); navigation.navigate('MainTabs', { screen: 'Home' }); const data = await settingApi.postFirstLogin(221); console.log(data); }; const handlePhoneLogin = () => { // 处理手机号登录 - 显示手机号登录面板 openPhoneLogin(); }; const handlePhoneVerificationSuccess = async () => { await login(); closePhoneLogin(); navigation.replace('MainTabs', { screen: 'Home' }); }; const handlePhoneContinue = async () => { if (phoneNumber.trim() && password) { if (password === '123') { await login(); closePhoneLogin(); navigation.replace('MainTabs', { screen: 'Home' }); } else { setPasswordError(true); } } }; const handleForgotPassword = () => { // 处理忘记密码 }; return ( {/* 顶部蓝色背景区域 */} brainnel 💰 {t('wholesalePrice')} 🚚 {t('fastShipping')} {/* 登录区域 */} × {/* Login For brainnel */} {t('loginSubtitle')} {/* 登录按钮 */} {t('continueWithGoogle')} f {t('continueWithFacebook')} {Platform.OS === 'ios' && ( 🍎 {t('continueWithApple')} )} 📷 {t('continueWithInstagram')} ✉️ {t('continueWithEmail')} 📱 {t('continueWithPhone')} {/* 忘记密码 */} {t('forgotPassword')} {/* 服务条款 */} {t('termsText')} {t('termsOfUse')} {t('and')} {t('privacyPolicy')} {/* 邮箱登录面板 - 从底部滑出 */} {emailLoginMounted && ( {t('logInOrSignUp')} { handleEmailChange(text); setEmailPasswordError(false); }} keyboardType="email-address" autoCapitalize="none" autoCorrect={false} autoFocus maxLength={50} /> {email.length > 0 && ( { setEmail(''); setShowSuggestions(false); setEmailPasswordError(false); }} activeOpacity={0.7} > )} {/* 邮箱后缀建议列表 */} {showSuggestions && ( item} style={styles.suggestionsList} keyboardShouldPersistTaps="handled" removeClippedSubviews={true} initialNumToRender={5} maxToRenderPerBatch={5} windowSize={5} getItemLayout={(data, index) => ( {length: 44, offset: 44 * index, index} )} /> )} {/* 密码输入框 */} { setEmailPassword(text); setEmailPasswordError(false); }} secureTextEntry={true} autoCapitalize="none" /> {emailPasswordError && ( ! )} {/* 密码错误提示 */} {emailPasswordError && ( <> {t('passwordIncorrect')} {t('forgotPassword')} )} {t('continue')} )} {/* 手机号登录面板 - 从底部滑出 */} {phoneLoginMounted && ( {t('logInOrSignUp')} setShowCountryModal(true)} activeOpacity={0.7} > {selectedCountry.flag} {selectedCountry.phoneCode} { setPhoneNumber(text); setPasswordError(false); }} keyboardType="phone-pad" autoFocus maxLength={15} /> {phoneNumber.length > 0 && ( { setPhoneNumber(''); setPasswordError(false); }} activeOpacity={0.7} > )} {/* 密码输入框 */} { setPassword(text); setPasswordError(false); }} secureTextEntry={true} autoCapitalize="none" /> {passwordError && ( ! )} {/* 密码错误提示 */} {passwordError && ( <> {t('passwordIncorrect')} {t('forgotPassword')} )} {t('continue')} )} {/* 国家选择模态框 */} setShowCountryModal(false)} hardwareAccelerated={true} statusBarTranslucent={true} presentationStyle="overFullScreen" > setShowCountryModal(false)} activeOpacity={0.7} > {t('selectCountry')} item.code} style={styles.countryList} showsVerticalScrollIndicator={false} removeClippedSubviews={true} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={10} getItemLayout={(data, index) => ( {length: 69, offset: 69 * index, index} )} /> ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', }, closeButton: { position: 'absolute', top: 15, left: 10, width: 24, height: 24, justifyContent: 'center', alignItems: 'center', zIndex: 1, }, closeButtonText: { color: '#000', fontSize: 24, fontWeight: '300', }, blueHeader: { backgroundColor: '#0066FF', paddingHorizontal: 20, paddingBottom: 20, paddingTop: Platform.OS === 'ios' ? 60 : 40, borderBottomLeftRadius: 24, borderBottomRightRadius: 24, }, logo: { fontSize: 28, fontWeight: 'bold', color: '#fff', marginBottom: 15, }, features: { flexDirection: 'row', gap: 16, }, featureItem: { flexDirection: 'row', alignItems: 'center', gap: 8, }, featureIconContainer: { backgroundColor: 'rgba(255, 255, 255, 0.2)', borderRadius: 8, width: 24, height: 24, justifyContent: 'center', alignItems: 'center', }, featureIcon: { fontSize: 12, }, featureText: { fontSize: 14, color: '#fff', }, loginContainer: { flex: 1, paddingHorizontal: 20, paddingTop: Platform.OS === 'ios' ? 40 : 20, }, titleContainer: { alignItems: 'center', marginBottom: 30, paddingTop: 20, position: 'relative', }, title: { fontSize: 24, fontWeight: 'bold', color: '#000', marginBottom: 8, textAlign: 'center', }, subtitle: { fontSize: 14, color: '#666', textAlign: 'center', }, loginButton: { flexDirection: 'row', height: 50, borderRadius: 25, borderWidth: 1, borderColor: '#E1E1E1', alignItems: 'center', marginBottom: 12, paddingHorizontal: 16, backgroundColor: '#fff', }, loginButtonIcon: { width: 24, height: 24, borderRadius: 12, justifyContent: 'center', alignItems: 'center', marginRight: 16, }, facebookIcon: { backgroundColor: '#3b5998', }, appleIconBg: { backgroundColor: '#000', }, instagramIcon: { backgroundColor: '#E1306C', }, loginButtonText: { flex: 1, fontSize: 16, color: '#000', textAlign: 'center', marginRight: 16, }, forgotPassword: { alignItems: 'center', marginVertical: 20, }, forgotPasswordText: { color: '#0066FF', fontSize: 14, }, termsContainer: { alignItems: 'center', marginTop: 10, }, terms: { fontSize: 12, color: '#666', textAlign: 'center', lineHeight: 18, }, link: { color: '#0066FF', }, // 邮箱登录样式 emailLoginContainer: { position: 'absolute', top: Platform.OS === 'ios' ? 60 : 40, height: Platform.OS === 'ios' ? 'auto' : '100%', bottom: 0, left: 0, right: 0, backgroundColor: '#fff', borderTopLeftRadius: 20, borderTopRightRadius: 20, shadowColor: '#000', shadowOffset: { width: 0, height: -2 }, shadowOpacity: 0.1, shadowRadius: 5, elevation: 5, zIndex: 10, }, emailLoginHeader: { flexDirection: 'row', alignItems: 'center', paddingTop: 20, paddingHorizontal: 16, paddingBottom: 15, borderBottomWidth: 1, borderBottomColor: '#f0f0f0', }, emailLoginCloseButton: { padding: 8, width: 36, height: 36, justifyContent: 'center', alignItems: 'center', }, emailLoginCloseButtonText: { fontSize: 18, color: '#000', }, emailLoginTitle: { flex: 1, fontSize: 18, fontWeight: '600', color: '#000', textAlign: 'center', marginRight: 36, }, emailLoginContent: { padding: 20, paddingBottom: Platform.OS === 'ios' ? 50 : 30, flex: 1, }, emailInputContainer: { flexDirection: 'row', alignItems: 'center', borderWidth: 1, borderColor: '#E1E1E1', borderRadius: 25, height: 50, marginBottom: 20, }, emailInput: { flex: 1, height: '100%', paddingHorizontal: 16, fontSize: 16, paddingRight: 36, }, emailClearButton: { position: 'absolute', right: 12, top: '50%', transform: [{ translateY: -12 }], height: 24, width: 24, justifyContent: 'center', alignItems: 'center', }, emailClearButtonText: { fontSize: 16, color: '#999', fontWeight: '500', textAlign: 'center', }, suggestionsContainer: { borderWidth: 1, borderColor: '#E1E1E1', borderRadius: 10, marginTop: -10, marginBottom: 20, maxHeight: 200, backgroundColor: '#fff', }, suggestionsList: { padding: 8, }, suggestionItem: { paddingVertical: 12, paddingHorizontal: 16, borderBottomWidth: 1, borderBottomColor: '#F0F0F0', }, suggestionText: { fontSize: 16, color: '#333', }, emailContinueButton: { height: 50, backgroundColor: '#0039CB', borderRadius: 25, justifyContent: 'center', alignItems: 'center', marginTop: 20, }, emailDisabledButton: { backgroundColor: '#CCCCCC', }, emailContinueButtonText: { color: '#fff', fontSize: 16, fontWeight: '600', }, // 手机号登录样式 phoneLoginContainer: { position: 'absolute', top: Platform.OS === 'ios' ? 60 : 40, height: Platform.OS === 'ios' ? 'auto' : '100%', bottom: 0, left: 0, right: 0, backgroundColor: '#fff', borderTopLeftRadius: 20, borderTopRightRadius: 20, shadowColor: '#000', shadowOffset: { width: 0, height: -2 }, shadowOpacity: 0.1, shadowRadius: 5, elevation: 5, zIndex: 10, }, phoneLoginHeader: { flexDirection: 'row', alignItems: 'center', paddingTop: 20, paddingHorizontal: 16, paddingBottom: 15, borderBottomWidth: 1, borderBottomColor: '#f0f0f0', }, phoneLoginCloseButton: { padding: 8, width: 36, height: 36, justifyContent: 'center', alignItems: 'center', }, phoneLoginCloseButtonText: { fontSize: 18, color: '#000', }, phoneLoginTitle: { flex: 1, fontSize: 18, fontWeight: '600', color: '#000', textAlign: 'center', marginRight: 36, }, phoneLoginContent: { padding: 20, paddingBottom: Platform.OS === 'ios' ? 50 : 30, flex: 1, }, phoneInputContainer: { flexDirection: 'row', alignItems: 'center', borderWidth: 1, borderColor: '#E1E1E1', borderRadius: 25, height: 50, marginBottom: 20, position: 'relative', }, countrySelector: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 12, borderRightWidth: 1, borderRightColor: '#E1E1E1', backgroundColor: '#F7F7F7', height: '100%', minWidth: 90, width: 90, justifyContent: 'center', }, countryFlag: { fontSize: 18, marginRight: 4, }, countryCode: { fontSize: 12, color: '#333', marginRight: 4, }, downArrow: { fontSize: 8, color: '#666', }, phoneInput: { flex: 1, height: '100%', paddingHorizontal: 16, fontSize: 16, paddingRight: 36, }, phoneClearButton: { position: 'absolute', right: 12, top: '50%', transform: [{ translateY: -12 }], height: 24, width: 24, justifyContent: 'center', alignItems: 'center', }, phoneClearButtonText: { fontSize: 16, color: '#999', fontWeight: '500', textAlign: 'center', }, phoneInfoText: { fontSize: 14, color: '#666', marginBottom: 32, lineHeight: 20, }, phoneContinueButton: { height: 50, backgroundColor: '#0039CB', borderRadius: 25, justifyContent: 'center', alignItems: 'center', }, phoneDisabledButton: { backgroundColor: '#CCCCCC', }, phoneContinueButtonText: { color: '#fff', fontSize: 16, fontWeight: '600', }, // 国家选择模态框样式 countryModalContainer: { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end', zIndex: 999, }, countryModalContent: { backgroundColor: '#fff', borderTopLeftRadius: 20, borderTopRightRadius: 20, maxHeight: '80%', zIndex: 1000, }, countryModalHeader: { flexDirection: 'row', alignItems: 'center', padding: 16, borderBottomWidth: 1, borderBottomColor: '#E5E5E5', }, countryModalCloseButton: { padding: 4, }, countryModalCloseButtonText: { fontSize: 18, color: '#999', }, countryModalTitle: { flex: 1, fontSize: 18, fontWeight: '600', textAlign: 'center', marginRight: 24, }, countryList: { padding: 8, }, countryItem: { flexDirection: 'row', alignItems: 'center', padding: 16, borderBottomWidth: 1, borderBottomColor: '#F0F0F0', }, countryItemFlag: { fontSize: 24, marginRight: 16, }, countryItemContent: { flex: 1, }, countryItemName: { fontSize: 16, color: '#333', }, countryItemCode: { fontSize: 14, color: '#666', marginTop: 4, }, // 密码输入框样式 passwordInput: { flex: 1, height: '100%', paddingHorizontal: 16, fontSize: 16, }, passwordErrorContainer: { borderColor: '#FF3B30', }, passwordErrorIcon: { position: 'absolute', right: 12, top: '50%', transform: [{ translateY: -12 }], width: 24, height: 24, backgroundColor: '#FF3B30', borderRadius: 12, justifyContent: 'center', alignItems: 'center', }, passwordErrorIconText: { color: 'white', fontWeight: 'bold', fontSize: 16, }, passwordErrorText: { color: '#FF3B30', fontSize: 14, marginTop: -12, marginBottom: 16, paddingHorizontal: 5, }, forgotPasswordLink: { alignItems: 'center', marginTop: 5, }, forgotPasswordLinkText: { color: '#0066FF', fontSize: 14, }, });