NuvioStreaming/src/components/metadata/CastSection.tsx
2025-10-12 03:02:27 +05:30

159 lines
No EOL
4.1 KiB
TypeScript

import React from 'react';
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
ActivityIndicator,
} from 'react-native';
import FastImage from '@d11/react-native-fast-image';
import Animated, {
FadeIn,
} from 'react-native-reanimated';
import { useTheme } from '../../contexts/ThemeContext';
interface CastSectionProps {
cast: any[];
loadingCast: boolean;
onSelectCastMember: (castMember: any) => void;
isTmdbEnrichmentEnabled?: boolean;
}
export const CastSection: React.FC<CastSectionProps> = ({
cast,
loadingCast,
onSelectCastMember,
isTmdbEnrichmentEnabled = true,
}) => {
const { currentTheme } = useTheme();
if (loadingCast) {
return (
<View style={styles.loadingContainer}>
<ActivityIndicator size="small" color={currentTheme.colors.primary} />
</View>
);
}
if (!cast || cast.length === 0) {
return null;
}
return (
<Animated.View
style={styles.castSection}
entering={FadeIn.duration(300).delay(150)}
>
<View style={styles.sectionHeader}>
<Text style={[styles.sectionTitle, { color: currentTheme.colors.highEmphasis }]}>Cast</Text>
</View>
<FlatList
horizontal
data={cast}
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.castList}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item, index }) => (
<Animated.View
entering={FadeIn.duration(300).delay(50 + index * 30)}
>
<TouchableOpacity
style={styles.castCard}
onPress={() => onSelectCastMember(item)}
activeOpacity={0.7}
>
<View style={styles.castImageContainer}>
{item.profile_path ? (
<FastImage
source={{
uri: `https://image.tmdb.org/t/p/w185${item.profile_path}`,
}}
style={styles.castImage}
resizeMode={FastImage.resizeMode.cover}
/>
) : (
<View style={[styles.castImagePlaceholder, { backgroundColor: currentTheme.colors.darkBackground }]}>
<Text style={[styles.placeholderText, { color: currentTheme.colors.textMuted }]}>
{item.name.split(' ').reduce((prev: string, current: string) => prev + current[0], '').substring(0, 2)}
</Text>
</View>
)}
</View>
<Text style={[styles.castName, { color: currentTheme.colors.text }]} numberOfLines={1}>{item.name}</Text>
{isTmdbEnrichmentEnabled && item.character && (
<Text style={[styles.characterName, { color: currentTheme.colors.textMuted }]} numberOfLines={1}>{item.character}</Text>
)}
</TouchableOpacity>
</Animated.View>
)}
/>
</Animated.View>
);
};
const styles = StyleSheet.create({
castSection: {
marginBottom: 24,
paddingHorizontal: 0,
},
loadingContainer: {
paddingVertical: 20,
alignItems: 'center',
justifyContent: 'center',
},
sectionHeader: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 12,
paddingHorizontal: 16,
},
sectionTitle: {
fontSize: 18,
fontWeight: '700',
},
castList: {
paddingHorizontal: 16,
paddingBottom: 4,
},
castCard: {
marginRight: 16,
width: 90,
alignItems: 'center',
},
castImageContainer: {
width: 80,
height: 80,
borderRadius: 40,
overflow: 'hidden',
marginBottom: 8,
},
castImage: {
width: '100%',
height: '100%',
},
castImagePlaceholder: {
width: '100%',
height: '100%',
borderRadius: 40,
alignItems: 'center',
justifyContent: 'center',
},
placeholderText: {
fontSize: 24,
fontWeight: '600',
},
castName: {
fontSize: 14,
fontWeight: '600',
textAlign: 'center',
width: 90,
},
characterName: {
fontSize: 12,
textAlign: 'center',
width: 90,
marginTop: 2,
},
});