From 9b34b51caf1d4e04aa6d5916f3a2cafa3be34a22 Mon Sep 17 00:00:00 2001 From: gww Date: Mon, 26 Jan 2026 12:01:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=98=B5=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @share/components/ConfirmModal.tsx | 4 +- app/(tabs)/index.tsx | 4 +- app/_layout.tsx | 1 + app/profile.tsx | 186 +++++++++++++++++++++++++++++ app/settings.tsx | 165 +++++++++++++++++++++++++ 5 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 app/profile.tsx create mode 100644 app/settings.tsx diff --git a/@share/components/ConfirmModal.tsx b/@share/components/ConfirmModal.tsx index 5116292..13722bd 100644 --- a/@share/components/ConfirmModal.tsx +++ b/@share/components/ConfirmModal.tsx @@ -71,7 +71,9 @@ const ConfirmModal: React.FC = ({ onClick={handleConfirm} > {confirmText} - + {title==='确认支付?' && ( + + )} diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index b829a33..2a07e43 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -575,7 +575,9 @@ const GooActions = observer(function GooActions({ gooPoints, on {isDev && isPolling && } )} - + router.push('/settings')}> + + + ) diff --git a/app/profile.tsx b/app/profile.tsx new file mode 100644 index 0000000..8b7df88 --- /dev/null +++ b/app/profile.tsx @@ -0,0 +1,186 @@ +import { Ionicons } from '@expo/vector-icons' +import { Block, ConfirmModal, Img, Input, Text, Toast } from '@share/components' +import { router, Stack } from 'expo-router' +import { observer } from 'mobx-react-lite' +import React, { useEffect, useState } from 'react' +import { ScrollView } from 'react-native' + +import { authClient } from '@/lib/auth' +import { userStore } from '@/stores' + +type InfoItem = { + id: string + label: string + value: string + valueGray?: boolean + onPress: () => void +} + +type EditNicknameModalProps = { + initialName: string + onConfirm: (name: string) => void | Promise + onCancel: () => void +} + +function EditNicknameModal({ initialName, onConfirm, onCancel }: EditNicknameModalProps) { + const [name, setName] = useState(initialName) + + useEffect(() => { + setName(initialName) + }, [initialName]) + + return ( + + + + } + title="修改昵称" + onCancel={onCancel} + onConfirm={() => onConfirm(name)} + /> + ) +} + +export default observer(function ProfilePage() { + const { user } = userStore + + const handleEditAvatar = () => { + // TODO: 打开相册/拍照更换头像 + Toast.show({ title: '更换头像功能开发中' }) + } + + const handleEditNickname = () => { + Toast.showModal( + { + const trimmed = name.trim() + if (trimmed.length < 6 || trimmed.length > 12) { + Toast.show({ title: '请输入6-12个字符' }) + return + } + try { + const res = await authClient.updateUser({ name: trimmed }) + const err = (res as { error?: { message?: string } }).error + if (err) { + Toast.show({ title: err.message || '修改失败,请重试' }) + return + } + if (userStore.user) { + userStore.setUser({ ...userStore.user, name: trimmed }) + } + Toast.hideModal() + Toast.show({ title: '昵称已更新' }) + } catch (e) { + Toast.show({ title: '修改失败,请重试' }) + } + }} + onCancel={() => Toast.hideModal()} + />, + ) + } + + const infoItems: InfoItem[] = [ + { + id: 'nickname', + label: '昵称', + value: user?.name || '未设置', + onPress: handleEditNickname, + }, + { + id: 'phone', + label: '手机号', + value: user?.phoneNumber || '', + onPress: () => { + Toast.show({ title: '手机号不可修改' }) + }, + } + ] + + const renderHeader = () => ( + + router.back()} + > + + + 个人信息 + + + ) + + const renderAvatarSection = () => ( + + + + {user?.image ? ( + + ) : ( + + )} + + + 编辑 + + + + ) + + const renderInfoList = () => ( + + {infoItems.map((item) => ( + + {item.label} + + {item.value} + + {/*手机号 显示隐藏按钮 */} + {item.id !== 'phone' && ( + + )} + + ))} + + ) + + return ( + + + {renderHeader()} + + {renderAvatarSection()} + {renderInfoList()} + + + ) +}) diff --git a/app/settings.tsx b/app/settings.tsx new file mode 100644 index 0000000..d896547 --- /dev/null +++ b/app/settings.tsx @@ -0,0 +1,165 @@ +import { Ionicons } from '@expo/vector-icons' +import { Block, Img, Text } from '@share/components' +import { router, Stack } from 'expo-router' +import { observer } from 'mobx-react-lite' +import React from 'react' +import { ScrollView } from 'react-native' + +import { ConfirmModal, Toast } from '@share/components' +import { userStore } from '@/stores' + +type MenuItem = { + id: string + label: string + icon: keyof typeof Ionicons.glyphMap + onPress: () => void +} + +export default observer(function SettingsPage() { + const { user, isAuthenticated, signOut } = userStore + + const handleLogout = () => { + Toast.showModal( + { + await signOut() + Toast.show({ title: '已退出登录' }) + router.replace('/(tabs)') + // 关闭modal + Toast.hideModal() + }} + />, + ) + } + + const menuItems: MenuItem[] = [ + { + id: 'service', + label: '服务条款', + icon: 'document-text-outline', + onPress: () => { + router.push({ + pathname: '/webview', + params: { url: 'https://mixvideo.bowong.cc/terms', title: '服务条款' }, + }) + }, + }, + { + id: 'privacy', + label: '隐私协议', + icon: 'shield-outline', + onPress: () => { + router.push({ + pathname: '/webview', + params: { url: 'https://mixvideo.bowong.cc/privacy', title: '隐私协议' }, + }) + }, + }, + // { + // id: 'about', + // label: '关于我们', + // icon: 'information-circle-outline', + // onPress: () => { + // // TODO: 替换为实际的关于我们URL或创建关于页面 + // router.push({ + // pathname: '/webview', + // params: { url: 'https://example.com/about', title: '关于我们' }, + // }) + // }, + // }, + ] + + const handleUserProfileClick = () => { + router.push('/profile') + } + + const renderHeader = () => ( + + router.back()}> + + + 设置 + + + ) + + const renderUserSection = () => ( + + + {user?.image ? ( + + ) : ( + + )} + + + {user?.name || user?.email || '未登录'} + {user?.email && user?.name && ( + {user.email} + )} + + + + ) + + const renderMenuSection = () => ( + + 使用相关 + + {menuItems.map((item, index) => ( + + + + {item.label} + + + {index < menuItems.length - 1 && ( + + )} + + ))} + + + ) + + const renderLogoutButton = () => ( + + {isAuthenticated && ( + + 退出登录 + + )} + + ) + + return ( + + + {renderHeader()} + + {renderUserSection()} + {renderMenuSection()} + {renderLogoutButton()} + + + ) +})