Login.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import type { RootScreenProps } from '@/navigation/types';
  2. import { Paths } from '@/navigation/paths';
  3. import { useTranslation } from 'react-i18next';
  4. import { Alert, Platform, ScrollView, Text, TouchableOpacity, View } from 'react-native';
  5. import { GoogleSignin } from '@react-native-google-signin/google-signin';
  6. import { appleAuth } from '@invertase/react-native-apple-authentication';
  7. import DeviceInfo from 'react-native-device-info';
  8. import { AUTH_CONFIG } from '@/config/auth';
  9. import { useI18n } from '@/hooks';
  10. import { useTheme } from '@/theme';
  11. import { AssetByVariant, IconByVariant, Skeleton } from '@/components/atoms';
  12. import { SafeScreen } from '@/components/templates';
  13. function Login({ navigation }: RootScreenProps<Paths.Login>) {
  14. const { toggleLanguage } = useI18n();
  15. const {
  16. backgrounds,
  17. changeTheme,
  18. colors,
  19. components,
  20. fonts,
  21. gutters,
  22. layout,
  23. variant,
  24. } = useTheme();
  25. const onChangeTheme = () => {
  26. changeTheme(variant === 'default' ? 'dark' : 'default');
  27. };
  28. const onGoHome = () => {
  29. navigation.navigate(Paths.Home);
  30. }
  31. const onGoPage = (page: Paths) => {
  32. navigation.navigate(page);
  33. }
  34. const handleLogin = async () => {
  35. try {
  36. const deviceId = await DeviceInfo.getUniqueId();
  37. console.log('设备ID:', deviceId);
  38. if (Platform.OS === 'ios') {
  39. // iOS使用Apple登录
  40. await handleAppleLogin();
  41. } else {
  42. // Android使用Google登录
  43. await handleGoogleLogin();
  44. }
  45. } catch (error) {
  46. console.error('登录失败:', error);
  47. Alert.alert('登录失败', '请稍后重试');
  48. }
  49. };
  50. const handleAppleLogin = async () => {
  51. try {
  52. // 执行Apple登录请求
  53. const appleAuthRequestResponse = await appleAuth.performRequest({
  54. requestedOperation: appleAuth.Operation.LOGIN,
  55. requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
  56. });
  57. // 获取凭证状态
  58. const credentialState = await appleAuth.getCredentialStateForUser(
  59. appleAuthRequestResponse.user,
  60. );
  61. if (credentialState === appleAuth.State.AUTHORIZED) {
  62. console.log('Apple登录成功:', appleAuthRequestResponse);
  63. Alert.alert('登录成功', `欢迎 ${appleAuthRequestResponse.fullName?.givenName || '用户'}`);
  64. }
  65. } catch (error) {
  66. console.error('Apple登录失败:', error);
  67. throw error;
  68. }
  69. };
  70. const handleGoogleLogin = async () => {
  71. try {
  72. // 配置Google登录
  73. await GoogleSignin.configure({
  74. webClientId: AUTH_CONFIG.GOOGLE.WEB_CLIENT_ID,
  75. offlineAccess: true,
  76. });
  77. // 检查是否已登录
  78. await GoogleSignin.hasPlayServices();
  79. // 执行登录
  80. const userInfo = await GoogleSignin.signIn();
  81. console.log('Google登录成功:', userInfo);
  82. Alert.alert('登录成功', `欢迎 ${userInfo.data?.user.name || '用户'}`);
  83. } catch (error) {
  84. console.error('Google登录失败:', error);
  85. throw error;
  86. }
  87. };
  88. return (
  89. <SafeScreen>
  90. <ScrollView>
  91. <View
  92. style={[
  93. layout.justifyCenter,
  94. layout.itemsCenter,
  95. gutters.marginTop_80,
  96. ]}
  97. >
  98. <View
  99. style={[layout.relative, backgrounds.gray100, components.circle250]}
  100. />
  101. <View style={[layout.absolute, gutters.paddingTop_80]}>
  102. <AssetByVariant
  103. path="tom"
  104. resizeMode="contain"
  105. style={{ height: 300, width: 300 }}
  106. />
  107. </View>
  108. </View>
  109. <View style={[gutters.paddingHorizontal_32, gutters.marginTop_40]}>
  110. <View style={[gutters.marginTop_40]}>
  111. <Text style={[fonts.size_40, fonts.gray800, fonts.bold]}>
  112. 欢迎使用
  113. </Text>
  114. <Text
  115. style={[fonts.size_16, fonts.gray200, gutters.marginBottom_40]}
  116. >
  117. {/* {t('screen_example.description')} */}
  118. </Text>
  119. </View>
  120. <View
  121. style={[
  122. layout.row,
  123. layout.justifyBetween,
  124. layout.fullWidth,
  125. gutters.marginTop_16,
  126. ]}
  127. >
  128. <Skeleton
  129. height={64}
  130. loading={false}
  131. style={{ borderRadius: components.buttonCircle.borderRadius }}
  132. width={64}
  133. >
  134. <TouchableOpacity
  135. onPress={handleLogin}
  136. style={[components.buttonCircle, gutters.marginBottom_16]}
  137. testID="fetch-user-button"
  138. >
  139. <IconByVariant path="user" stroke={colors.purple500} />
  140. </TouchableOpacity>
  141. </Skeleton>
  142. <TouchableOpacity
  143. onPress={onGoHome}
  144. style={[components.buttonCircle, gutters.marginBottom_16]}
  145. testID="change-theme-button"
  146. >
  147. <IconByVariant path="home" stroke={colors.purple500} />
  148. </TouchableOpacity>
  149. <TouchableOpacity
  150. onPress={() => onGoPage(Paths.Pay)}
  151. style={[components.buttonCircle, gutters.marginBottom_16]}
  152. testID="change-theme-button"
  153. >
  154. <View>支付</View>
  155. </TouchableOpacity>
  156. <TouchableOpacity
  157. onPress={() => onGoPage(Paths.SubList)}
  158. style={[components.buttonCircle, gutters.marginBottom_16]}
  159. testID="change-theme-button"
  160. >
  161. <View>订阅</View>
  162. </TouchableOpacity>
  163. <TouchableOpacity
  164. onPress={onChangeTheme}
  165. style={[components.buttonCircle, gutters.marginBottom_16]}
  166. testID="change-theme-button"
  167. >
  168. <IconByVariant path="theme" stroke={colors.purple500} />
  169. </TouchableOpacity>
  170. <TouchableOpacity
  171. onPress={toggleLanguage}
  172. style={[components.buttonCircle, gutters.marginBottom_16]}
  173. testID="change-language-button"
  174. >
  175. <IconByVariant path="language" stroke={colors.purple500} />
  176. </TouchableOpacity>
  177. </View>
  178. </View>
  179. </ScrollView>
  180. </SafeScreen>
  181. );
  182. }
  183. export default Login;