|
|
@@ -1,25 +1,31 @@
|
|
|
+import type { CaptchaRes } from '@/components/captcha-box';
|
|
|
+import CaptchaBox from '@/components/captcha-box';
|
|
|
+import { site } from '@/config.json';
|
|
|
+import { useInterval } from '@/hooks/hooks';
|
|
|
+import api, { ApiError } from '@/utils/api';
|
|
|
+import { signUp, useAuth } from '@/utils/auth';
|
|
|
import { Button, Toast } from '@ant-design/react-native';
|
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
|
import { Link, router, useLocalSearchParams } from 'expo-router';
|
|
|
-import { openBrowserAsync } from 'expo-web-browser';
|
|
|
-import React, { useRef, useState } from 'react';
|
|
|
+import React, { useEffect, useRef, useState } from 'react';
|
|
|
import {
|
|
|
KeyboardAvoidingView,
|
|
|
Platform,
|
|
|
Pressable,
|
|
|
+ ScrollView,
|
|
|
StyleSheet,
|
|
|
Text,
|
|
|
TextInput,
|
|
|
View
|
|
|
} from 'react-native';
|
|
|
-import Animated, { scrollTo, useAnimatedRef, useDerivedValue, useSharedValue } from 'react-native-reanimated';
|
|
|
+import Animated, {
|
|
|
+ interpolateColor,
|
|
|
+ useAnimatedStyle,
|
|
|
+ useSharedValue,
|
|
|
+ withSequence,
|
|
|
+ withTiming,
|
|
|
+} from 'react-native-reanimated';
|
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
-import CaptchaBox from '@/components/captcha-box';
|
|
|
-import { site } from '@/config.json';
|
|
|
-import { useInterval } from '@/hooks/hooks';
|
|
|
-import api, { ApiError } from '@/utils/api';
|
|
|
-import { signUp, useAuth } from '@/utils/auth';
|
|
|
-import type { CaptchaRes } from '@/components/captcha-box';
|
|
|
|
|
|
function FieldLabel({ children }: { children: React.ReactNode }) {
|
|
|
return (
|
|
|
@@ -41,12 +47,30 @@ export default function SignUpScreen() {
|
|
|
const [agreementHighlight, setFlushAgree] = useState(false);
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
- const scrollViewRef = useAnimatedRef();
|
|
|
- const scrollY = useSharedValue(0);
|
|
|
+ const scrollViewRef = useRef<ScrollView>(null);
|
|
|
+
|
|
|
+ const agreeHighlight = useSharedValue(0);
|
|
|
+ useEffect(() => {
|
|
|
+ if (agreementHighlight) {
|
|
|
+ agreeHighlight.value = withSequence(
|
|
|
+ withTiming(1, { duration: 140 }),
|
|
|
+ withTiming(0, { duration: 140 }),
|
|
|
+ withTiming(1, { duration: 140 }),
|
|
|
+ withTiming(0, { duration: 140 }),
|
|
|
+ withTiming(1, { duration: 200 }),
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ agreeHighlight.value = withTiming(0, { duration: 200 });
|
|
|
+ }
|
|
|
+ }, [agreementHighlight, agreeHighlight]);
|
|
|
|
|
|
- useDerivedValue(() => {
|
|
|
- scrollTo(scrollViewRef, 0, scrollY.value, true);
|
|
|
- });
|
|
|
+ const agreeBoxStyle = useAnimatedStyle(() => ({
|
|
|
+ borderColor: interpolateColor(
|
|
|
+ agreeHighlight.value,
|
|
|
+ [0, 1],
|
|
|
+ ['rgba(37, 99, 235, 0)', 'rgba(37, 99, 235, 0.5)'],
|
|
|
+ ),
|
|
|
+ }));
|
|
|
|
|
|
const [captchaVisible, setCaptchaVisible] = useState<boolean>(false);
|
|
|
const [smsTtl, setSmsTtl] = useState(0);
|
|
|
@@ -120,7 +144,7 @@ export default function SignUpScreen() {
|
|
|
const handleRegister = async () => {
|
|
|
|
|
|
setFlushAgree(false);
|
|
|
- scrollY.value = 0;
|
|
|
+ scrollViewRef.current?.scrollTo({ y: 0, animated: true });
|
|
|
if (mobile.trim().length !== 11) {
|
|
|
Toast.fail('请输入正确的手机号');
|
|
|
return;
|
|
|
@@ -153,7 +177,7 @@ export default function SignUpScreen() {
|
|
|
|
|
|
|
|
|
if (!agreed) {
|
|
|
- scrollY.value = 99999;
|
|
|
+ scrollViewRef.current?.scrollToEnd({ animated: true });
|
|
|
setFlushAgree(true);
|
|
|
|
|
|
Toast.fail('请先阅读并同意协议');
|
|
|
@@ -191,7 +215,7 @@ export default function SignUpScreen() {
|
|
|
className="flex-1"
|
|
|
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
|
|
>
|
|
|
- <Animated.ScrollView
|
|
|
+ <ScrollView
|
|
|
ref={scrollViewRef}
|
|
|
className="flex-1"
|
|
|
contentContainerClassName="px-8"
|
|
|
@@ -360,7 +384,10 @@ export default function SignUpScreen() {
|
|
|
</View>
|
|
|
</View>
|
|
|
|
|
|
- <View className={`flex-row items-start gap-3 px-2 rounded-md border-2 transition-colors duration-700 ${agreementHighlight ? ' border-primary/50' : 'border-transparent'}`}>
|
|
|
+ <Animated.View
|
|
|
+ style={agreeBoxStyle}
|
|
|
+ className="flex-row items-start gap-3 px-2 rounded-lg border-2"
|
|
|
+ >
|
|
|
<Pressable
|
|
|
onPress={() => setAgreed((value) => !value)}
|
|
|
hitSlop={8}
|
|
|
@@ -386,12 +413,17 @@ export default function SignUpScreen() {
|
|
|
<Text className="font-semibold text-primary">《用户服务协议》</Text>
|
|
|
</Link>
|
|
|
、
|
|
|
- <Text className="font-semibold text-primary cursor-pointer" onPress={() => openBrowserAsync(`${site}`)}>《隐私政策》</Text>
|
|
|
+ <Link href={{
|
|
|
+ pathname: '/web',
|
|
|
+ params: { uri: site }
|
|
|
+ }}>
|
|
|
+ <Text className="font-semibold text-primary cursor-pointer">《隐私政策》</Text>
|
|
|
+ </Link>
|
|
|
,以及授权该应用获取您的公开信息。
|
|
|
</Text>
|
|
|
- </View>
|
|
|
+ </Animated.View>
|
|
|
</View>
|
|
|
- </Animated.ScrollView>
|
|
|
+ </ScrollView>
|
|
|
</KeyboardAvoidingView>
|
|
|
<CaptchaBox visible={captchaVisible} onClose={handleCaptcha} />
|
|
|
</View>
|