This commit is contained in:
imeepos
2026-01-28 17:30:01 +08:00
parent 0399bba83f
commit d6cc74ab00
11 changed files with 439 additions and 375 deletions

View File

@@ -21,11 +21,12 @@ import { PointsIcon, SearchIcon, SettingsIcon } from '@/components/icon'
import EditProfileDrawer from '@/components/drawer/EditProfileDrawer'
import Dropdown from '@/components/ui/dropdown'
import Toast from '@/components/ui/Toast'
import { signOut , useSession } from '@/lib/auth'
import { signOut, useSession } from '@/lib/auth'
import { useTemplateGenerations, type TemplateGeneration } from '@/hooks'
import { MySkeleton } from '@/components/skeleton/MySkeleton'
import { useUserBalance } from '@/hooks/use-user-balance'
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller'
const { width: screenWidth } = Dimensions.get('window')
const GALLERY_GAP = 2
@@ -173,7 +174,7 @@ export default function My() {
return t('my.languageSwitchEn')
}
}
const settingsOptions = [
{ label: t('my.changePassword'), value: 'changePassword' },
{ label: getLanguageLabel(), value: 'language' },
@@ -182,168 +183,175 @@ export default function My() {
return (
<SafeAreaView style={styles.container} edges={['top', 'bottom']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
{/* 顶部积分与设置 */}
<View style={styles.topBar}>
<Pressable
style={styles.pointsPill}
onPress={() => router.push('/membership' as any)}
>
<PointsIcon />
<Text style={styles.pointsPillText}>{balance}</Text>
</Pressable>
<Dropdown
options={settingsOptions}
onSelect={(value) => handleSettingsSelect(value)}
renderTrigger={(selectedOption, isOpen, toggle) => (
<Pressable onPress={toggle}>
<SettingsIcon />
</Pressable>
)}
dropdownStyle={{
minWidth: 160,
right: 10,
backgroundColor: '#2A2A2A80',
<KeyboardAwareScrollView bottomOffset={50}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
{/* 顶部积分与设置 */}
<View style={styles.topBar}>
<Pressable
style={styles.pointsPill}
onPress={() => router.push('/membership' as any)}
>
<PointsIcon />
<Text style={styles.pointsPillText}>{balance}</Text>
</Pressable>
<Dropdown
options={settingsOptions}
onSelect={(value) => handleSettingsSelect(value)}
renderTrigger={(selectedOption, isOpen, toggle) => (
<Pressable onPress={toggle}>
<SettingsIcon />
</Pressable>
)}
dropdownStyle={{
minWidth: 160,
right: 10,
backgroundColor: '#2A2A2A80',
}}
/>
</View>
{/* 个人信息区 */}
<View style={styles.profileSection}>
<Image
source={session?.user?.image ? { uri: session.user.image } : require('@/assets/images/icon.png')}
style={styles.avatar}
contentFit="cover"
/>
<View style={styles.profileInfo}>
<Text style={styles.profileName}>{profileName}</Text>
<Text style={styles.profileSubTitle}>ID {session?.user?.id?.slice(0, 8) || '--------'}</Text>
</View>
<Pressable
style={styles.editButton}
onPress={() => {
console.log('[my.tsx] Edit Profile button pressed')
setEditDrawerVisible(true)
}}
>
<Text style={styles.editButtonText}>{t('my.editProfile')}</Text>
</Pressable>
</View>
{/* "生成作品" 标题行 */}
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>{t('my.generatedWorks')}</Text>
<Pressable
style={styles.sectionMoreButton}
onPress={() => router.push('/worksList' as any)}
>
<SearchIcon />
</Pressable>
</View>
{/* 作品九宫格 */}
{loading ? (
<MySkeleton />
) : (
<ScrollView
testID="my-scroll-view"
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
showsVerticalScrollIndicator={false}
onScroll={handleScroll}
scrollEventThrottle={16}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
tintColor="#9966FF"
colors={['#9966FF', '#FF6699', '#FF9966']}
progressBackgroundColor="#1C1E22"
progressViewOffset={10}
/>
}
>
<View style={styles.galleryGrid}>
{generations.map((item, index) => (
<Pressable
key={item.id}
style={[
styles.galleryItem,
index % 3 !== 2 && styles.galleryItemMarginRight,
styles.galleryItemMarginBottom,
]}
onPress={() => {
if (item.status === 'completed') {
router.push({
pathname: '/generationRecord' as any,
params: { id: item.id },
})
}
}}
disabled={item.status !== 'completed'}
>
<Image
source={getCoverUrl(item) ? { uri: getCoverUrl(item) } : require('@/assets/images/membership.png')}
style={styles.galleryImage}
contentFit="cover"
/>
{/* 遮罩:非完成状态 */}
{item.status !== 'completed' && (
<View style={styles.generatingOverlay} />
)}
{/* 数量角标:已完成且有结果 */}
{item.status === 'completed' && (item.resultUrl?.length || 0) > 0 && (
<View style={styles.counterBadge}>
<Text style={styles.counterText}>
{item.resultUrl?.length || 1}
</Text>
</View>
)}
{/* 状态角标 */}
{item.status === 'running' && (
<View style={styles.generatingBadge}>
<Text style={styles.generatingBadgeText}>{t('my.generating')}</Text>
</View>
)}
{item.status === 'pending' && (
<View style={styles.generatingBadge}>
<Text style={styles.generatingBadgeText}>{t('my.queuing')}</Text>
</View>
)}
</Pressable>
))}
{/* 加载更多指示器 */}
{loadingMore && (
<View style={styles.loadingMoreContainer}>
<ActivityIndicator size="small" color="#9966FF" />
</View>
)}
{/* 空状态提示 */}
{!loading && generations.length === 0 && (
<View style={styles.emptyState}>
<Text style={styles.emptyStateText}>
{t('my.noWorks')}
</Text>
</View>
)}
</View>
</ScrollView>
)}
{/* 编辑资料抽屉 */}
<EditProfileDrawer
visible={editDrawerVisible}
onClose={() => setEditDrawerVisible(false)}
initialName={profileName}
initialAvatar={session?.user?.image}
onSave={(data) => {
setProfileName(data.name)
}}
/>
</View>
{/* 个人信息区 */}
<View style={styles.profileSection}>
<Image
source={session?.user?.image ? { uri: session.user.image } : require('@/assets/images/icon.png')}
style={styles.avatar}
contentFit="cover"
/>
<View style={styles.profileInfo}>
<Text style={styles.profileName}>{profileName}</Text>
<Text style={styles.profileSubTitle}>ID {session?.user?.id?.slice(0, 8) || '--------'}</Text>
</View>
<Pressable
style={styles.editButton}
onPress={() => setEditDrawerVisible(true)}
>
<Text style={styles.editButtonText}>{t('my.editProfile')}</Text>
</Pressable>
</View>
{/* "生成作品" 标题行 */}
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>{t('my.generatedWorks')}</Text>
<Pressable
style={styles.sectionMoreButton}
onPress={() => router.push('/worksList' as any)}
>
<SearchIcon />
</Pressable>
</View>
{/* 作品九宫格 */}
{loading ? (
<MySkeleton />
) : (
<ScrollView
testID="my-scroll-view"
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
showsVerticalScrollIndicator={false}
onScroll={handleScroll}
scrollEventThrottle={16}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
tintColor="#9966FF"
colors={['#9966FF', '#FF6699', '#FF9966']}
progressBackgroundColor="#1C1E22"
progressViewOffset={10}
/>
}
>
<View style={styles.galleryGrid}>
{generations.map((item, index) => (
<Pressable
key={item.id}
style={[
styles.galleryItem,
index % 3 !== 2 && styles.galleryItemMarginRight,
styles.galleryItemMarginBottom,
]}
onPress={() => {
if (item.status === 'completed') {
router.push({
pathname: '/generationRecord' as any,
params: { id: item.id },
})
}
}}
disabled={item.status !== 'completed'}
>
<Image
source={getCoverUrl(item) ? { uri: getCoverUrl(item) } : require('@/assets/images/membership.png')}
style={styles.galleryImage}
contentFit="cover"
/>
{/* 遮罩:非完成状态 */}
{item.status !== 'completed' && (
<View style={styles.generatingOverlay} />
)}
{/* 数量角标:已完成且有结果 */}
{item.status === 'completed' && (item.resultUrl?.length || 0) > 0 && (
<View style={styles.counterBadge}>
<Text style={styles.counterText}>
{item.resultUrl?.length || 1}
</Text>
</View>
)}
{/* 状态角标 */}
{item.status === 'running' && (
<View style={styles.generatingBadge}>
<Text style={styles.generatingBadgeText}>{t('my.generating')}</Text>
</View>
)}
{item.status === 'pending' && (
<View style={styles.generatingBadge}>
<Text style={styles.generatingBadgeText}>{t('my.queuing')}</Text>
</View>
)}
</Pressable>
))}
{/* 加载更多指示器 */}
{loadingMore && (
<View style={styles.loadingMoreContainer}>
<ActivityIndicator size="small" color="#9966FF" />
</View>
)}
{/* 空状态提示 */}
{!loading && generations.length === 0 && (
<View style={styles.emptyState}>
<Text style={styles.emptyStateText}>
{t('my.noWorks')}
</Text>
</View>
)}
</View>
</ScrollView>
)}
{/* 编辑资料抽屉 */}
<EditProfileDrawer
visible={editDrawerVisible}
onClose={() => setEditDrawerVisible(false)}
initialName={profileName}
initialAvatar={session?.user?.image}
onSave={(data) => {
setProfileName(data.name)
}}
/>
</KeyboardAwareScrollView>
</SafeAreaView>
)
}