This commit is contained in:
imeepos 2026-01-29 18:33:03 +08:00
parent 5e4a9c82cd
commit 5a4d1ac1bd
4 changed files with 86 additions and 63 deletions

View File

@ -22,7 +22,7 @@ import LoadingState from '@/components/LoadingState'
import ErrorState from '@/components/ErrorState' import ErrorState from '@/components/ErrorState'
import PaginationLoader from '@/components/PaginationLoader' import PaginationLoader from '@/components/PaginationLoader'
import { MessageCard } from '@/components/message/MessageCard' import { MessageCard, type Message as MessageCardMessage } from '@/components/message/MessageCard'
import { MessageTabBar, type MessageType, TAB_ITEMS } from '@/components/message/MessageTabBar' import { MessageTabBar, type MessageType, TAB_ITEMS } from '@/components/message/MessageTabBar'
import { AnnouncementBanner } from '@/components/message/AnnouncementBanner' import { AnnouncementBanner } from '@/components/message/AnnouncementBanner'
import { SwipeToDelete } from '@/components/message/SwipeToDelete' import { SwipeToDelete } from '@/components/message/SwipeToDelete'
@ -76,7 +76,7 @@ export default function MessageScreen() {
const { const {
announcements, announcements,
execute: executeAnnouncements, execute: executeAnnouncements,
} = useAnnouncements({ limit: 10 }) } = useAnnouncements()
// Filter messages based on active tab // Filter messages based on active tab
const filteredMessages = filterMessagesByTab(allMessages, activeTab) const filteredMessages = filterMessagesByTab(allMessages, activeTab)
@ -153,7 +153,7 @@ export default function MessageScreen() {
const queryString = Object.keys(params).length > 0 const queryString = Object.keys(params).length > 0
? `?${new URLSearchParams(params).toString()}` ? `?${new URLSearchParams(params).toString()}`
: '' : ''
router.push(`${route}${queryString}`) router.push(`${route}${queryString}` as any)
} }
}, [markRead, router]) }, [markRead, router])

View File

@ -210,10 +210,6 @@ export const VideoItem = memo(({ item, videoHeight }: { item: TemplateDetail; vi
likeCount={likeCount} likeCount={likeCount}
favoriteCount={favoriteCount} favoriteCount={favoriteCount}
loading={likeLoading || favoriteLoading} loading={likeLoading || favoriteLoading}
onLike={onLike}
onUnlike={onUnlike}
onFavorite={onFavorite}
onUnfavorite={onUnfavorite}
testID="video-social-button" testID="video-social-button"
/> />
</View> </View>

View File

@ -65,6 +65,10 @@ jest.mock('@/components/ui/video', () => ({
VideoPlayer: ({ source }: any) => <View testID="video-player" />, VideoPlayer: ({ source }: any) => <View testID="video-player" />,
})) }))
jest.mock('expo-linear-gradient', () => ({
LinearGradient: ({ children }: any) => <View testID="linear-gradient">{children}</View>,
}))
jest.mock('@/hooks', () => ({ jest.mock('@/hooks', () => ({
useGenerationDetail: jest.fn(), useGenerationDetail: jest.fn(),
useDeleteGeneration: jest.fn(), useDeleteGeneration: jest.fn(),

View File

@ -8,13 +8,13 @@ import {
StatusBar as RNStatusBar, StatusBar as RNStatusBar,
Alert, Alert,
ScrollView, ScrollView,
Platform,
} from 'react-native' } from 'react-native'
import { StatusBar } from 'expo-status-bar' import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context' import { SafeAreaView } from 'react-native-safe-area-context'
import { Image } from 'expo-image' import { Image } from 'expo-image'
import { useRouter, useLocalSearchParams } from 'expo-router' import { useRouter, useLocalSearchParams } from 'expo-router'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { LinearGradient } from 'expo-linear-gradient'
import { LeftArrowIcon, DeleteIcon, EditIcon, ChangeIcon, WhiteStarIcon } from '@/components/icon' import { LeftArrowIcon, DeleteIcon, EditIcon, ChangeIcon, WhiteStarIcon } from '@/components/icon'
import { DeleteConfirmDialog } from '@/components/ui/delete-confirm-dialog' import { DeleteConfirmDialog } from '@/components/ui/delete-confirm-dialog'
@ -128,13 +128,13 @@ export default function GenerationRecordScreen() {
switch (status?.toLowerCase()) { switch (status?.toLowerCase()) {
case 'completed': case 'completed':
case 'success': case 'success':
return '#4CAF50' return '#4ADE80'
case 'pending': case 'pending':
case 'processing': case 'processing':
return '#FF9800' return '#FF9966'
case 'failed': case 'failed':
case 'error': case 'error':
return '#F44336' return '#FF6B6B'
default: default:
return '#8A8A8A' return '#8A8A8A'
} }
@ -277,50 +277,61 @@ export default function GenerationRecordScreen() {
{/* 操作按钮 */} {/* 操作按钮 */}
<View style={styles.actionSection}> <View style={styles.actionSection}>
{/* 下载按钮 */} {/* 下载按钮 - 主要操作使用渐变色 */}
{hasResult && ( {hasResult && (
<Pressable <Pressable
style={[styles.actionButton, styles.downloadButton, downloading && styles.buttonDisabled]} style={[styles.primaryButtonContainer, downloading && styles.buttonDisabled]}
onPress={handleDownload} onPress={handleDownload}
disabled={downloading} disabled={downloading}
> >
<Text style={styles.downloadButtonText}> <LinearGradient
{downloading colors={['#9966FF', '#FF6699', '#FF9966']}
? `${t('generationRecord.downloading')} ${Math.round(progress * 100)}%` locations={[0.0015, 0.4985, 0.9956]}
: t('generationRecord.download')} start={{ x: 1, y: 0 }}
</Text> end={{ x: 0, y: 0 }}
style={styles.gradientButton}
>
<Text style={styles.primaryButtonText}>
{downloading
? `${t('generationRecord.downloading')} ${Math.round(progress * 100)}%`
: t('generationRecord.download')}
</Text>
</LinearGradient>
</Pressable> </Pressable>
)} )}
{/* 重新生成按钮 */} {/* 次要操作按钮行 */}
<Pressable <View style={styles.secondaryButtonRow}>
style={[styles.actionButton, styles.rerunButton, rerunning && styles.buttonDisabled]} {/* 重新生成按钮 */}
onPress={handleRerun}
disabled={rerunning}
>
<ChangeIcon />
<Text style={styles.actionButtonText}>{t('generationRecord.regenerate')}</Text>
</Pressable>
{/* 再来一次按钮 */}
{generation.template && (
<Pressable <Pressable
style={[styles.actionButton, styles.tryAgainButton]} style={[styles.secondaryButton, rerunning && styles.buttonDisabled]}
onPress={handleTryAgain} onPress={handleRerun}
disabled={rerunning}
> >
<EditIcon /> <ChangeIcon />
<Text style={styles.actionButtonText}>{t('generationRecord.reEdit')}</Text> <Text style={styles.secondaryButtonText}>{t('generationRecord.regenerate')}</Text>
</Pressable> </Pressable>
)}
{/* 删除按钮 */} {/* 再来一次按钮 */}
<Pressable {generation.template && (
style={[styles.actionButton, styles.deleteActionButton, deleting && styles.buttonDisabled]} <Pressable
onPress={() => setDeleteDialogOpen(true)} style={styles.secondaryButton}
disabled={deleting} onPress={handleTryAgain}
> >
<DeleteIcon /> <EditIcon />
</Pressable> <Text style={styles.secondaryButtonText}>{t('generationRecord.reEdit')}</Text>
</Pressable>
)}
{/* 删除按钮 */}
<Pressable
style={[styles.deleteButton, deleting && styles.buttonDisabled]}
onPress={() => setDeleteDialogOpen(true)}
disabled={deleting}
>
<DeleteIcon />
</Pressable>
</View>
</View> </View>
</ScrollView> </ScrollView>
@ -438,40 +449,52 @@ const styles = StyleSheet.create({
paddingHorizontal: 12, paddingHorizontal: 12,
gap: 12, gap: 12,
}, },
actionButton: { // 主要按钮 - 渐变色
primaryButtonContainer: {
height: 48,
borderRadius: 12,
overflow: 'hidden',
},
gradientButton: {
flex: 1,
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
paddingHorizontal: 16,
paddingVertical: 12,
borderRadius: 12, borderRadius: 12,
backgroundColor: '#1C1E22',
gap: 8,
}, },
downloadButton: { primaryButtonText: {
backgroundColor: '#4CAF50',
},
downloadButtonText: {
color: '#FFFFFF', color: '#FFFFFF',
fontSize: 14, fontSize: 16,
fontWeight: '600', fontWeight: '600',
}, },
rerunButton: { // 次要按钮行
backgroundColor: '#1C1E22', secondaryButtonRow: {
flexDirection: 'row',
gap: 8,
}, },
tryAgainButton: { secondaryButton: {
backgroundColor: '#1C1E22', flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
height: 48,
borderRadius: 12,
backgroundColor: '#262A31',
gap: 6,
}, },
deleteActionButton: { secondaryButtonText: {
backgroundColor: '#1C1E22',
width: 48,
alignSelf: 'flex-end',
},
actionButtonText: {
color: '#F5F5F5', color: '#F5F5F5',
fontSize: 14, fontSize: 14,
fontWeight: '500', fontWeight: '500',
}, },
deleteButton: {
width: 48,
height: 48,
borderRadius: 12,
backgroundColor: '#262A31',
alignItems: 'center',
justifyContent: 'center',
},
buttonDisabled: { buttonDisabled: {
opacity: 0.5, opacity: 0.5,
}, },