diff --git a/components/blocks/ui/VideoSocialButton.test.tsx b/components/blocks/ui/VideoSocialButton.test.tsx
new file mode 100644
index 0000000..9ad16e5
--- /dev/null
+++ b/components/blocks/ui/VideoSocialButton.test.tsx
@@ -0,0 +1,193 @@
+import React from 'react'
+import { render, fireEvent } from '@testing-library/react-native'
+import { VideoSocialButton } from './VideoSocialButton'
+
+describe('VideoSocialButton Component', () => {
+ describe('组件导出', () => {
+ it('应该被定义', () => {
+ expect(VideoSocialButton).toBeDefined()
+ })
+
+ it('应该使用 React.memo 包装', () => {
+ expect(typeof VideoSocialButton).toBe('object')
+ })
+ })
+
+ describe('Props 接口', () => {
+ it('应该接受 templateId 属性', () => {
+ const props = { templateId: 'test-template-1' }
+ expect(props.templateId).toBe('test-template-1')
+ })
+
+ it('应该接受 liked 属性', () => {
+ const props = { liked: true }
+ expect(props.liked).toBe(true)
+ })
+
+ it('应该接受 favorited 属性', () => {
+ const props = { favorited: true }
+ expect(props.favorited).toBe(true)
+ })
+
+ it('应该接受 likeCount 属性', () => {
+ const props = { likeCount: 100 }
+ expect(props.likeCount).toBe(100)
+ })
+
+ it('应该接受 favoriteCount 属性', () => {
+ const props = { favoriteCount: 50 }
+ expect(props.favoriteCount).toBe(50)
+ })
+
+ it('应该接受 loading 属性', () => {
+ const props = { loading: true }
+ expect(props.loading).toBe(true)
+ })
+
+ it('应该接受 onLike 回调', () => {
+ const onLike = jest.fn()
+ expect(typeof onLike).toBe('function')
+ })
+
+ it('应该接受 onFavorite 回调', () => {
+ const onFavorite = jest.fn()
+ expect(typeof onFavorite).toBe('function')
+ })
+ })
+
+ describe('渲染', () => {
+ it('应该成功渲染', () => {
+ const { getByTestId } = render(
+
+ )
+ expect(getByTestId('video-social-button')).toBeTruthy()
+ })
+
+ it('应该渲染点赞按钮', () => {
+ const { getByTestId } = render(
+
+ )
+ expect(getByTestId('video-social-like-like-button')).toBeTruthy()
+ })
+
+ it('应该渲染收藏按钮', () => {
+ const { getByTestId } = render(
+
+ )
+ expect(getByTestId('video-social-favorite-favorite-button')).toBeTruthy()
+ })
+
+ it('应该显示点赞数量', () => {
+ const { getByText } = render(
+
+ )
+ expect(getByText('100')).toBeTruthy()
+ })
+
+ it('应该显示收藏数量', () => {
+ const { getByText } = render(
+
+ )
+ expect(getByText('50')).toBeTruthy()
+ })
+ })
+
+ describe('交互', () => {
+ it('点击点赞按钮应该调用 onLike', () => {
+ const onLike = jest.fn()
+ const { getByTestId } = render(
+
+ )
+ const likeButton = getByTestId('video-social-on-like-like-button')
+ fireEvent.press(likeButton)
+ expect(onLike).toHaveBeenCalledTimes(1)
+ })
+
+ it('点击收藏按钮应该调用 onFavorite', () => {
+ const onFavorite = jest.fn()
+ const { getByTestId } = render(
+
+ )
+ const favoriteButton = getByTestId('video-social-on-favorite-favorite-button')
+ fireEvent.press(favoriteButton)
+ expect(onFavorite).toHaveBeenCalledTimes(1)
+ })
+
+ it('loading 状态下应该禁用按钮', () => {
+ const onLike = jest.fn()
+ const onFavorite = jest.fn()
+ const { getByTestId } = render(
+
+ )
+ const likeButton = getByTestId('video-social-loading-like-button')
+ const favoriteButton = getByTestId('video-social-loading-favorite-button')
+
+ fireEvent.press(likeButton)
+ fireEvent.press(favoriteButton)
+
+ expect(onLike).not.toHaveBeenCalled()
+ expect(onFavorite).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('样式', () => {
+ it('应该使用垂直布局', () => {
+ const { getByTestId } = render(
+
+ )
+ const container = getByTestId('video-social-vertical')
+ expect(container).toBeTruthy()
+ })
+
+ it('应该使用圆形背景样式', () => {
+ const { getByTestId } = render(
+
+ )
+ const container = getByTestId('video-social-round')
+ expect(container).toBeTruthy()
+ })
+ })
+
+ 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(
+
+ )
+ const likeButton = getByTestId('video-social-no-callback-like-button')
+ const favoriteButton = getByTestId('video-social-no-callback-favorite-button')
+
+ expect(() => {
+ fireEvent.press(likeButton)
+ fireEvent.press(favoriteButton)
+ }).not.toThrow()
+ })
+
+ it('应该同时处理已点赞和已收藏状态', () => {
+ const { getByTestId } = render(
+
+ )
+ expect(getByTestId('video-social-both')).toBeTruthy()
+ })
+ })
+})
diff --git a/components/blocks/ui/VideoSocialButton.tsx b/components/blocks/ui/VideoSocialButton.tsx
new file mode 100644
index 0000000..5d1be25
--- /dev/null
+++ b/components/blocks/ui/VideoSocialButton.tsx
@@ -0,0 +1,115 @@
+import React, { memo, useCallback, useMemo } from 'react'
+import { View, StyleSheet } from 'react-native'
+import { LikeButton, LikeButtonProps } from './LikeButton'
+import { FavoriteButton, FavoriteButtonProps } from './FavoriteButton'
+
+export interface VideoSocialButtonProps {
+ templateId: string
+ liked?: boolean
+ favorited?: boolean
+ likeCount?: number
+ favoriteCount?: number
+ loading?: boolean
+ onLike?: () => void
+ onUnlike?: () => void
+ onFavorite?: () => void
+ onUnfavorite?: () => void
+ testID?: string
+}
+
+const VideoSocialButtonComponent: React.FC = ({
+ templateId,
+ liked = false,
+ favorited = false,
+ likeCount,
+ favoriteCount,
+ loading = false,
+ onLike,
+ onUnlike,
+ onFavorite,
+ onUnfavorite,
+ testID,
+}) => {
+ // 处理点赞按钮点击
+ const handleLikePress = useCallback(() => {
+ if (!loading) {
+ if (liked) {
+ onUnlike?.()
+ } else {
+ onLike?.()
+ }
+ }
+ }, [loading, liked, onLike, onUnlike])
+
+ // 处理收藏按钮点击
+ const handleFavoritePress = useCallback(() => {
+ if (!loading) {
+ if (favorited) {
+ onUnfavorite?.()
+ } else {
+ onFavorite?.()
+ }
+ }
+ }, [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]
+ )
+
+ return (
+
+ {/* 点赞按钮 */}
+
+
+
+
+ {/* 收藏按钮 */}
+
+
+
+
+ )
+}
+
+export const VideoSocialButton = memo(VideoSocialButtonComponent)
+
+const styles = StyleSheet.create({
+ container: {
+ position: 'absolute',
+ right: 13,
+ bottom: 100,
+ flexDirection: 'column',
+ alignItems: 'center',
+ gap: 16,
+ },
+ button: {
+ width: 48,
+ height: 48,
+ borderRadius: 24,
+ backgroundColor: 'rgba(25, 27, 31, 0.8)',
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderWidth: 1,
+ borderColor: 'rgba(47, 49, 52, 1)',
+ },
+})