diff --git a/components/blocks/ui/VideoSocialButton.test.tsx b/components/blocks/ui/VideoSocialButton.test.tsx index 9ad16e5..74be1d5 100644 --- a/components/blocks/ui/VideoSocialButton.test.tsx +++ b/components/blocks/ui/VideoSocialButton.test.tsx @@ -90,6 +90,20 @@ describe('VideoSocialButton Component', () => { ) expect(getByText('50')).toBeTruthy() }) + + it('应该在已点赞状态显示实心心形图标', () => { + const { getByTestId } = render( + + ) + expect(getByTestId('video-social-liked-like-button')).toBeTruthy() + }) + + it('应该在已收藏状态显示实心星形图标', () => { + const { getByTestId } = render( + + ) + expect(getByTestId('video-social-favorited-favorite-button')).toBeTruthy() + }) }) describe('交互', () => { @@ -113,6 +127,26 @@ describe('VideoSocialButton Component', () => { expect(onFavorite).toHaveBeenCalledTimes(1) }) + it('已点赞状态点击应该调用 onUnlike', () => { + const onUnlike = jest.fn() + const { getByTestId } = render( + + ) + const likeButton = getByTestId('video-social-on-unlike-like-button') + fireEvent.press(likeButton) + expect(onUnlike).toHaveBeenCalledTimes(1) + }) + + it('已收藏状态点击应该调用 onUnfavorite', () => { + const onUnfavorite = jest.fn() + const { getByTestId } = render( + + ) + const favoriteButton = getByTestId('video-social-on-unfavorite-favorite-button') + fireEvent.press(favoriteButton) + expect(onUnfavorite).toHaveBeenCalledTimes(1) + }) + it('loading 状态下应该禁用按钮', () => { const onLike = jest.fn() const onFavorite = jest.fn() @@ -136,6 +170,46 @@ describe('VideoSocialButton Component', () => { }) }) + describe('数量格式化', () => { + it('应该显示零数量', () => { + const { getByText } = render( + + ) + expect(getByText('0')).toBeTruthy() + }) + + it('应该格式化千位数量', () => { + const { getByText } = render( + + ) + expect(getByText('1.5k')).toBeTruthy() + expect(getByText('2.8k')).toBeTruthy() + }) + + it('应该格式化万位数量', () => { + const { getByText } = render( + + ) + expect(getByText('1.5w')).toBeTruthy() + expect(getByText('2.8w')).toBeTruthy() + }) + + it('应该处理大数量', () => { + const { getByText } = render( + + ) + expect(getByText('9999')).toBeTruthy() + expect(getByText('8888')).toBeTruthy() + }) + + it('应该处理 undefined 数量', () => { + const { getAllByText } = render( + + ) + expect(getAllByText('0').length).toBe(2) + }) + }) + describe('样式', () => { it('应该使用垂直布局', () => { const { getByTestId } = render( @@ -155,21 +229,6 @@ describe('VideoSocialButton Component', () => { }) describe('边界情况', () => { - it('应该处理零数量', () => { - const { getByText } = render( - - ) - expect(getByText('0')).toBeTruthy() - }) - - it('应该处理大数量', () => { - const { getByText } = render( - - ) - expect(getByText('9999')).toBeTruthy() - expect(getByText('8888')).toBeTruthy() - }) - it('应该处理缺失的回调函数', () => { const { getByTestId } = render( diff --git a/components/blocks/ui/VideoSocialButton.tsx b/components/blocks/ui/VideoSocialButton.tsx index 5d1be25..13f4ffd 100644 --- a/components/blocks/ui/VideoSocialButton.tsx +++ b/components/blocks/ui/VideoSocialButton.tsx @@ -1,7 +1,6 @@ -import React, { memo, useCallback, useMemo } from 'react' -import { View, StyleSheet } from 'react-native' -import { LikeButton, LikeButtonProps } from './LikeButton' -import { FavoriteButton, FavoriteButtonProps } from './FavoriteButton' +import React, { memo, useCallback } from 'react' +import { View, StyleSheet, Text, Pressable } from 'react-native' +import { Ionicons } from '@expo/vector-icons' export interface VideoSocialButtonProps { templateId: string @@ -52,41 +51,53 @@ const VideoSocialButtonComponent: React.FC = ({ } }, [loading, favorited, onFavorite, onUnfavorite]) - // LikeButton 的 props - const likeButtonProps: LikeButtonProps = useMemo( - () => ({ - liked, - loading, - count: likeCount, - onPress: handleLikePress, - testID: testID ? `${testID}-like-button` : undefined, - }), - [liked, loading, likeCount, handleLikePress, testID] - ) - - // FavoriteButton 的 props - const favoriteButtonProps: FavoriteButtonProps = useMemo( - () => ({ - favorited, - loading, - count: favoriteCount, - onPress: handleFavoritePress, - testID: testID ? `${testID}-favorite-button` : undefined, - }), - [favorited, loading, favoriteCount, handleFavoritePress, testID] - ) + // 格式化数量显示 + const formatCount = (count?: number): string => { + if (count === undefined || count === null) return '0' + if (count >= 10000) { + return `${(count / 10000).toFixed(1)}w` + } + if (count >= 1000) { + return `${(count / 1000).toFixed(1)}k` + } + return count.toString() + } return ( {/* 点赞按钮 */} - - - + + + + + {formatCount(likeCount)} + {/* 收藏按钮 */} - - - + + + + + {formatCount(favoriteCount)} + ) } @@ -96,20 +107,33 @@ export const VideoSocialButton = memo(VideoSocialButtonComponent) const styles = StyleSheet.create({ container: { position: 'absolute', - right: 13, - bottom: 100, + right: 12, + bottom: 180, flexDirection: 'column', alignItems: 'center', - gap: 16, + gap: 20, }, - button: { - width: 48, - height: 48, - borderRadius: 24, - backgroundColor: 'rgba(25, 27, 31, 0.8)', + buttonWrapper: { + alignItems: 'center', + gap: 4, + }, + iconContainer: { + width: 52, + height: 52, + borderRadius: 26, + backgroundColor: 'rgba(0, 0, 0, 0.3)', justifyContent: 'center', alignItems: 'center', - borderWidth: 1, - borderColor: 'rgba(47, 49, 52, 1)', + }, + iconContainerActive: { + backgroundColor: 'rgba(255, 255, 255, 0.15)', + }, + count: { + color: '#FFFFFF', + fontSize: 12, + fontWeight: '600', + textShadowColor: 'rgba(0, 0, 0, 0.5)', + textShadowOffset: { width: 0, height: 1 }, + textShadowRadius: 2, }, })