diff --git a/app/(tabs)/owner.tsx b/app/(tabs)/owner.tsx
index 1c6ec85..40f5d46 100644
--- a/app/(tabs)/owner.tsx
+++ b/app/(tabs)/owner.tsx
@@ -16,7 +16,7 @@ import { fetchApi } from '@/lib/server-api-util';
import { CountData, UserInfoDetails } from '@/types/user';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { ScrollView, StyleSheet, View } from 'react-native';
+import { FlatList, ScrollView, StyleSheet, View } from 'react-native';
import { useSafeAreaInsets } from "react-native-safe-area-context";
export default function OwnerPage() {
const insets = useSafeAreaInsets();
@@ -59,54 +59,57 @@ export default function OwnerPage() {
return (
-
- {/* 用户信息 */}
-
+ ListHeaderComponent={
+
+ {/* 用户信息 */}
+
- {/* 设置栏 */}
-
+ {/* 设置栏 */}
+
- {/* 资源数据 */}
-
- } style={{ flex: 1 }} isFormatBytes={true} />
- } style={{ flex: 1 }} />
-
- {/* 数据统计 */}
-
+ {/* 资源数据 */}
+
+ } style={{ flex: 1 }} isFormatBytes={true} />
+ } style={{ flex: 1 }} />
+
+ {/* 数据统计 */}
+
- {/* 分类 */}
-
-
- {countData?.counter?.category_count && Object.entries(countData?.counter?.category_count).map(([key, value], index) => {
- return (
-
- )
- })}
-
-
+ {/* 分类 */}
+
+
+ {countData?.counter?.category_count && Object.entries(countData?.counter?.category_count).map(([key, value], index) => {
+ return (
+
+ )
+ })}
+
+
- {/* 作品数据 */}
-
- } number={userInfoDetails.stories_count} />
- } number={userInfoDetails.conversations_count} />
-
-
- {/* 排行榜 */}
-
-
-
+ {/* 作品数据 */}
+
+ } number={userInfoDetails.stories_count} />
+ } number={userInfoDetails.conversations_count} />
+
+ {/* 排行榜 */}
+
+
+ }
+ />
{/* 设置弹窗 */}
@@ -122,6 +125,9 @@ const styles = StyleSheet.create({
backgroundColor: 'white',
paddingBottom: 86,
},
+ contentContainer: {
+ paddingHorizontal: 16,
+ },
resourceContainer: {
flexDirection: 'row',
gap: 16
diff --git a/components/copy.tsx b/components/copy.tsx
new file mode 100644
index 0000000..476058f
--- /dev/null
+++ b/components/copy.tsx
@@ -0,0 +1,38 @@
+import Ionicons from '@expo/vector-icons/Ionicons';
+import * as Clipboard from 'expo-clipboard';
+import React, { useState } from 'react';
+import { StyleSheet, TouchableOpacity } from 'react-native';
+
+const CopyButton = ({ textToCopy }: { textToCopy: string }) => {
+ const [isCopied, setIsCopied] = useState(false);
+
+ const handleCopy = async () => {
+ await Clipboard.setStringAsync(textToCopy);
+ setIsCopied(true);
+ setTimeout(() => setIsCopied(false), 2000);
+ };
+
+ return (
+
+ {isCopied ? (
+
+ ) : (
+
+ )}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ button: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ padding: 4,
+ },
+ text: {
+ marginLeft: 8,
+ fontSize: 16,
+ },
+});
+
+export default CopyButton;
\ No newline at end of file
diff --git a/components/login/signUp.tsx b/components/login/signUp.tsx
index 0c3782b..6f5c441 100644
--- a/components/login/signUp.tsx
+++ b/components/login/signUp.tsx
@@ -7,6 +7,7 @@ import { useAuth } from "../../contexts/auth-context";
import { fetchApi } from "../../lib/server-api-util";
import { User } from "../../types/user";
import { ThemedText } from "../ThemedText";
+import PrivacyModal from "../owner/qualification/privacy";
interface LoginProps {
updateUrlParam: (status: string, value: string) => void;
@@ -25,7 +26,9 @@ const SignUp = ({ updateUrlParam, setError, setShowPassword, showPassword }: Log
const [passwordsMatch, setPasswordsMatch] = useState(true);
const [loading, setLoading] = useState(false);
const [checked, setChecked] = useState(false);
-
+ const [modalType, setModalType] = useState<'ai' | 'terms' | 'privacy' | 'user'>('ai');
+ // 协议弹窗
+ const [privacyModalVisible, setPrivacyModalVisible] = useState(false);
// 从 URL 参数中获取 task_id 和 steps
const params = useLocalSearchParams<{ task_id?: string; steps?: string }>();
const taskId = params.task_id;
@@ -263,10 +266,10 @@ const SignUp = ({ updateUrlParam, setError, setShowPassword, showPassword }: Log
{t("auth.telLogin.agree", { ns: 'login' })}
- router.push({
- pathname: '/agreement',
- params: { type: 'service' }
- } as any)}>
+ {
+ setModalType('terms');
+ setPrivacyModalVisible(true);
+ }}>
{t("auth.telLogin.terms", { ns: 'login' })}
@@ -274,10 +277,10 @@ const SignUp = ({ updateUrlParam, setError, setShowPassword, showPassword }: Log
{t("auth.telLogin.and", { ns: 'login' })}
- router.push({
- pathname: '/agreement',
- params: { type: 'privacy' }
- } as any)}>
+ {
+ setModalType('privacy');
+ setPrivacyModalVisible(true);
+ }}>
{t("auth.telLogin.privacyPolicy", { ns: 'login' })}
@@ -285,14 +288,25 @@ const SignUp = ({ updateUrlParam, setError, setShowPassword, showPassword }: Log
{t("auth.telLogin.and", { ns: 'login' })}
- router.push({
- pathname: '/agreement',
- params: { type: 'user' }
- } as any)}>
+ {
+ setModalType('user');
+ setPrivacyModalVisible(true);
+ }}>
{t("auth.telLogin.userAgreement", { ns: 'login' })}
+
+ {t("auth.telLogin.and", { ns: 'login' })}
+
+ {
+ setModalType('ai');
+ setPrivacyModalVisible(true);
+ }}>
+
+ {t("auth.telLogin.aiAgreement", { ns: 'login' })}
+
+
{t("auth.telLogin.agreement", { ns: 'login' })}
@@ -319,6 +333,9 @@ const SignUp = ({ updateUrlParam, setError, setShowPassword, showPassword }: Log
+
+ {/* 协议弹窗 */}
+
}
diff --git a/components/owner/qualification/privacy.tsx b/components/owner/qualification/privacy.tsx
index 75a6078..7af7259 100644
--- a/components/owner/qualification/privacy.tsx
+++ b/components/owner/qualification/privacy.tsx
@@ -1,7 +1,7 @@
import { fetchApi } from '@/lib/server-api-util';
import { Policy } from '@/types/personal-info';
import React, { useEffect, useState } from 'react';
-import { Modal, Pressable, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
+import { Modal, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import RenderHtml from 'react-native-render-html';
const PrivacyModal = (props: { modalVisible: boolean, setModalVisible: (visible: boolean) => void, type: string }) => {
@@ -62,12 +62,8 @@ const PrivacyModal = (props: { modalVisible: boolean, setModalVisible: (visible:
onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
- setModalVisible(false)}>
- e.stopPropagation()}>
+
+
Settings
{type === 'ai' ? 'AI Policy' : type === 'terms' ? 'Terms of Service' : type === 'privacy' ? 'Privacy Policy' : 'User Agreement'}
@@ -85,9 +81,8 @@ const PrivacyModal = (props: { modalVisible: boolean, setModalVisible: (visible:
}}
/>
-
-
-
+
+
);
};
diff --git a/components/owner/userName.tsx b/components/owner/userName.tsx
index ab64c68..691c276 100644
--- a/components/owner/userName.tsx
+++ b/components/owner/userName.tsx
@@ -1,25 +1,26 @@
import UserSvg from '@/assets/icons/svg/ataver.svg';
import { ThemedText } from '@/components/ThemedText';
import { UserInfoDetails } from '@/types/user';
-// import { Image } from 'expo-image';
+import { useState } from 'react';
import { Image, ScrollView, View } from 'react-native';
export default function UserInfo({ userInfo }: { userInfo: UserInfoDetails }) {
-
+ // 添加状态来跟踪图片加载状态
+ const [imageError, setImageError] = useState(false);
return (
-
+
{/* 用户名 */}
-
+
-
+
{userInfo?.user_info?.nickname}
-
- User ID:{userInfo?.user_info?.user_id}
-
+
+
+ User ID: {userInfo?.user_info?.user_id}
+
+ {/* */}
+
+
{/* 头像 */}
-
- {userInfo?.user_info?.avatar_file_url
- ?
+
+ {userInfo?.user_info?.avatar_file_url && !imageError ? (
{
+ console.log('图片加载失败:', userInfo.user_info.avatar_file_url);
+ setImageError(true);
+ }}
+ onLoad={() => {
+ console.log('图片加载成功');
+ }}
/>
- :
+ ) : (
- }
+ )}
);
diff --git a/i18n/locales/en/login.json b/i18n/locales/en/login.json
index ea568c7..bd71809 100644
--- a/i18n/locales/en/login.json
+++ b/i18n/locales/en/login.json
@@ -48,7 +48,8 @@
"codeVaild": "The code you entered is invalid",
"sendAgain": "Did’nt receive a code?",
"resend": "Resend",
- "goBack": "Go Back"
+ "goBack": "Go Back",
+ "aiAgreement": "AI Function Usage Norms"
},
"login": {
"title": "Log in",
diff --git a/i18n/locales/zh/login.json b/i18n/locales/zh/login.json
index fa391b5..3daf77c 100644
--- a/i18n/locales/zh/login.json
+++ b/i18n/locales/zh/login.json
@@ -48,7 +48,8 @@
"codeValid": "您输入的验证码无效",
"sendAgain": "没有收到验证码?",
"resend": "重新发送",
- "goBack": "返回"
+ "goBack": "返回",
+ "aiAgreement": "《AI功能使用规范》"
},
"login": {
"title": "登录",
diff --git a/package-lock.json b/package-lock.json
index 068ae76..6070e55 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"expo-audio": "~0.4.7",
"expo-background-fetch": "^13.1.6",
"expo-blur": "~14.1.5",
+ "expo-clipboard": "~7.1.5",
"expo-constants": "~17.1.6",
"expo-dev-client": "~5.2.1",
"expo-device": "~7.1.4",
@@ -3360,18 +3361,6 @@
}
}
},
- "node_modules/@react-native-async-storage/async-storage": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz",
- "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==",
- "license": "MIT",
- "dependencies": {
- "merge-options": "^3.0.4"
- },
- "peerDependencies": {
- "react-native": "^0.0.0-0 || >=0.65 <1.0"
- }
- },
"node_modules/@react-native-picker/picker": {
"version": "2.11.1",
"resolved": "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.11.1.tgz",
@@ -7835,6 +7824,17 @@
"react-native": "*"
}
},
+ "node_modules/expo-clipboard": {
+ "version": "7.1.5",
+ "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-7.1.5.tgz",
+ "integrity": "sha512-TCANUGOxouoJXxKBW5ASJl2WlmQLGpuZGemDCL2fO5ZMl57DGTypUmagb0CVUFxDl0yAtFIcESd78UsF9o64aw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/expo-constants": {
"version": "17.1.7",
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-17.1.7.tgz",
@@ -9743,15 +9743,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-plain-obj": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
- "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -10819,18 +10810,6 @@
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
"license": "MIT"
},
- "node_modules/merge-options": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
- "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
- "license": "MIT",
- "dependencies": {
- "is-plain-obj": "^2.1.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -15896,4 +15875,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/package.json b/package.json
index bc50a88..268a95e 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,6 @@
"expo-file-system": "~18.1.10",
"expo-font": "~13.3.1",
"expo-haptics": "~14.1.4",
- "expo-image": "~2.3.2",
"expo-image-manipulator": "~13.1.7",
"expo-image-picker": "~16.1.4",
"expo-linking": "~7.1.5",
@@ -69,7 +68,8 @@
"react-native-uuid": "^2.0.3",
"react-native-web": "~0.20.0",
"react-native-webview": "13.13.5",
- "react-redux": "^9.2.0"
+ "react-redux": "^9.2.0",
+ "expo-clipboard": "~7.1.5"
},
"devDependencies": {
"@babel/core": "^7.25.2",