import React, { useEffect, useState, useRef } from "react"; import { View, Text, StyleSheet, TouchableOpacity, StatusBar, Platform, BackHandler, TextInput, Animated, Easing, FlatList, Keyboard, Modal, InteractionManager, Image, Alert } 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"; import useUserStore from "../store/user"; 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 { setSettings, settings, user, setUser } = useUserStore(); // 邮箱登录状态 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 () => { const params = { grant_type: "password", username: "lifei", password: "123456", client_id: "2", client_secret: "", scope: "", }; try { const res = await userApi.login(params); if (res.access_token) { const token = res.token_type + " " + res.access_token; await AsyncStorage.setItem("token", token); // const data = await settingApi.postFirstLogin(221); // setSettings(data); const user = await userApi.getProfile() setUser(user); navigation.navigate("MainTabs", { screen: "Home" }); } } catch (error) { Alert.alert(t("loginFailed")); } }; 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, }, });