mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
m
This commit is contained in:
parent
74a288bc1a
commit
6f2ccfa38b
4 changed files with 60 additions and 156 deletions
|
|
@ -18,12 +18,14 @@ interface MetadataDetailsProps {
|
|||
metadata: any;
|
||||
imdbId: string | null;
|
||||
type: 'movie' | 'series';
|
||||
renderRatings?: () => React.ReactNode;
|
||||
}
|
||||
|
||||
const MetadataDetails: React.FC<MetadataDetailsProps> = ({
|
||||
metadata,
|
||||
imdbId,
|
||||
type,
|
||||
renderRatings,
|
||||
}) => {
|
||||
const { currentTheme } = useTheme();
|
||||
const [isFullDescriptionOpen, setIsFullDescriptionOpen] = useState(false);
|
||||
|
|
@ -53,6 +55,9 @@ const MetadataDetails: React.FC<MetadataDetailsProps> = ({
|
|||
)}
|
||||
</View>
|
||||
|
||||
{/* Ratings Section */}
|
||||
{renderRatings && renderRatings()}
|
||||
|
||||
{/* Creator/Director Info */}
|
||||
<Animated.View
|
||||
entering={FadeIn.duration(500).delay(200)}
|
||||
|
|
|
|||
|
|
@ -87,21 +87,6 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
|
|||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
};
|
||||
}, [imdbId, type]);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
useEffect(() => {
|
||||
if (ratings) {
|
||||
}
|
||||
}, [ratings]);
|
||||
|
||||
useEffect(() => {
|
||||
if (ratings && Object.keys(ratings).length > 0) {
|
||||
// Start fade-in animation when ratings are loaded
|
||||
|
|
@ -114,21 +99,9 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
|
|||
}, [ratings, fadeAnim]);
|
||||
|
||||
// If MDBList is disabled, don't show anything
|
||||
if (!isMDBEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="small" color={currentTheme.colors.primary} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !ratings || Object.keys(ratings).length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (!isMDBEnabled) return null;
|
||||
if (loading) return <View style={styles.loadingContainer}><ActivityIndicator size="small" color={currentTheme.colors.primary} /></View>;
|
||||
if (error || !ratings || Object.keys(ratings).length === 0) return null;
|
||||
|
||||
// Define the order and icons/colors for the ratings
|
||||
const ratingConfig = {
|
||||
|
|
@ -136,56 +109,42 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
|
|||
icon: require('../../../assets/rating-icons/imdb.png'),
|
||||
isImage: true,
|
||||
color: '#F5C518',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
transform: (value: number) => value.toFixed(1)
|
||||
},
|
||||
tmdb: {
|
||||
icon: TMDBIcon,
|
||||
isImage: false,
|
||||
color: '#01B4E4',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
transform: (value: number) => value.toFixed(0)
|
||||
},
|
||||
trakt: {
|
||||
icon: TraktIcon,
|
||||
isImage: false,
|
||||
color: '#ED1C24',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
transform: (value: number) => value.toFixed(0)
|
||||
},
|
||||
letterboxd: {
|
||||
icon: LetterboxdIcon,
|
||||
isImage: false,
|
||||
color: '#00E054',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
transform: (value: number) => value.toFixed(1)
|
||||
},
|
||||
tomatoes: {
|
||||
icon: RottenTomatoesIcon,
|
||||
isImage: false,
|
||||
color: '#FA320A',
|
||||
prefix: '',
|
||||
suffix: '%',
|
||||
transform: (value: number) => Math.round(value).toString()
|
||||
transform: (value: number) => Math.round(value).toString() + '%'
|
||||
},
|
||||
audience: {
|
||||
icon: AudienceScoreIcon,
|
||||
isImage: true,
|
||||
color: '#FA320A',
|
||||
prefix: '',
|
||||
suffix: '%',
|
||||
transform: (value: number) => Math.round(value).toString()
|
||||
transform: (value: number) => Math.round(value).toString() + '%'
|
||||
},
|
||||
metacritic: {
|
||||
icon: MetacriticIcon,
|
||||
isImage: true,
|
||||
color: '#FFCC33',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
transform: (value: number) => Math.round(value).toString()
|
||||
}
|
||||
};
|
||||
|
|
@ -215,55 +174,30 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
|
|||
},
|
||||
]}
|
||||
>
|
||||
<View style={styles.header}>
|
||||
<Text style={[styles.title, { color: currentTheme.colors.highEmphasis }]}>Ratings</Text>
|
||||
</View>
|
||||
<View style={styles.ratingsContainer}>
|
||||
<View style={styles.compactRatingsContainer}>
|
||||
{displayRatings.map(([source, value]) => {
|
||||
const config = ratingConfig[source as keyof typeof ratingConfig];
|
||||
const displayValue = config.transform(parseFloat(value as string));
|
||||
|
||||
// Get a short display name for the rating source
|
||||
const getSourceLabel = (src: string): string => {
|
||||
switch(src) {
|
||||
case 'imdb': return 'IMDb';
|
||||
case 'tmdb': return 'TMDB';
|
||||
case 'tomatoes': return 'RT';
|
||||
case 'audience': return 'Aud';
|
||||
case 'metacritic': return 'Meta';
|
||||
case 'letterboxd': return 'LBXD';
|
||||
case 'trakt': return 'Trakt';
|
||||
default: return src;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View key={source} style={styles.ratingItem}>
|
||||
<View style={styles.ratingIconContainer}>
|
||||
{config.isImage ? (
|
||||
<Image
|
||||
source={config.icon as any}
|
||||
style={styles.ratingIconImage}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.svgContainer}>
|
||||
{React.createElement(config.icon as any, {
|
||||
width: 24,
|
||||
height: 24,
|
||||
})}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<Text
|
||||
style={[
|
||||
styles.ratingValue,
|
||||
{ color: config.color }
|
||||
]}
|
||||
>
|
||||
{config.prefix}{displayValue}{config.suffix}
|
||||
<View key={source} style={styles.compactRatingItem}>
|
||||
{config.isImage ? (
|
||||
<Image
|
||||
source={config.icon as any}
|
||||
style={styles.compactRatingIcon}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.compactSvgContainer}>
|
||||
{React.createElement(config.icon as any, {
|
||||
width: 16,
|
||||
height: 16,
|
||||
})}
|
||||
</View>
|
||||
)}
|
||||
<Text style={[styles.compactRatingValue, { color: config.color }]}>
|
||||
{displayValue}
|
||||
</Text>
|
||||
<Text style={[styles.ratingSource, { color: currentTheme.colors.mediumEmphasis }]}>{getSourceLabel(source)}</Text>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
|
|
@ -274,69 +208,35 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
|
|||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginBottom: 20,
|
||||
marginTop: 2,
|
||||
marginBottom: 8,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
loadingContainer: {
|
||||
height: 80,
|
||||
height: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
header: {
|
||||
compactRatingsContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 12,
|
||||
flexWrap: 'nowrap',
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
},
|
||||
ratingsContainer: {
|
||||
compactRatingItem: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 10,
|
||||
},
|
||||
ratingItem: {
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
width: 55,
|
||||
marginRight: 12,
|
||||
},
|
||||
ratingIconContainer: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: 4,
|
||||
compactRatingIcon: {
|
||||
width: 16,
|
||||
height: 16,
|
||||
marginRight: 4,
|
||||
},
|
||||
ratingIconImage: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
compactSvgContainer: {
|
||||
marginRight: 4,
|
||||
},
|
||||
svgContainer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
ratingValue: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
marginVertical: 2,
|
||||
},
|
||||
ratingSource: {
|
||||
fontSize: 11,
|
||||
textAlign: 'center',
|
||||
},
|
||||
noRatingsText: {
|
||||
compactRatingValue: {
|
||||
fontSize: 14,
|
||||
color: 'gray',
|
||||
fontStyle: 'italic',
|
||||
textAlign: 'center',
|
||||
marginVertical: 16,
|
||||
},
|
||||
errorText: {
|
||||
fontSize: 12,
|
||||
color: '#ff0000',
|
||||
textAlign: 'center',
|
||||
marginVertical: 8,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
|
|
@ -389,6 +389,7 @@ const WrappedScreen: React.FC<{Screen: React.ComponentType<any>}> = ({ Screen })
|
|||
const MainTabs = () => {
|
||||
// Always use dark mode
|
||||
const isDarkMode = true;
|
||||
const { currentTheme } = useTheme();
|
||||
|
||||
const renderTabBar = (props: BottomTabBarProps) => {
|
||||
return (
|
||||
|
|
@ -409,9 +410,9 @@ const MainTabs = () => {
|
|||
position: 'absolute',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
borderTopColor: 'rgba(255,255,255,0.2)',
|
||||
borderTopColor: currentTheme.colors.border,
|
||||
borderTopWidth: 0.5,
|
||||
shadowColor: '#000',
|
||||
shadowColor: currentTheme.colors.black,
|
||||
shadowOffset: { width: 0, height: -2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 3,
|
||||
|
|
@ -495,7 +496,7 @@ const MainTabs = () => {
|
|||
>
|
||||
<TabIcon
|
||||
focused={isFocused}
|
||||
color={isFocused ? colors.primary : '#FFFFFF'}
|
||||
color={isFocused ? currentTheme.colors.primary : currentTheme.colors.white}
|
||||
iconName={iconName}
|
||||
/>
|
||||
<Text
|
||||
|
|
@ -503,7 +504,7 @@ const MainTabs = () => {
|
|||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
marginTop: 4,
|
||||
color: isFocused ? colors.primary : '#FFFFFF',
|
||||
color: isFocused ? currentTheme.colors.primary : currentTheme.colors.white,
|
||||
opacity: isFocused ? 1 : 0.7,
|
||||
}}
|
||||
>
|
||||
|
|
@ -519,7 +520,7 @@ const MainTabs = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: colors.darkBackground }}>
|
||||
<View style={{ flex: 1, backgroundColor: currentTheme.colors.darkBackground }}>
|
||||
{/* Common StatusBar for all tabs */}
|
||||
<StatusBar
|
||||
translucent
|
||||
|
|
@ -550,8 +551,8 @@ const MainTabs = () => {
|
|||
|
||||
return <TabIcon focused={focused} color={color} iconName={iconName} />;
|
||||
},
|
||||
tabBarActiveTintColor: colors.primary,
|
||||
tabBarInactiveTintColor: '#FFFFFF',
|
||||
tabBarActiveTintColor: currentTheme.colors.primary,
|
||||
tabBarInactiveTintColor: currentTheme.colors.white,
|
||||
tabBarStyle: {
|
||||
position: 'absolute',
|
||||
backgroundColor: 'transparent',
|
||||
|
|
@ -583,9 +584,9 @@ const MainTabs = () => {
|
|||
position: 'absolute',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
borderTopColor: 'rgba(255,255,255,0.2)',
|
||||
borderTopColor: currentTheme.colors.border,
|
||||
borderTopWidth: 0.5,
|
||||
shadowColor: '#000',
|
||||
shadowColor: currentTheme.colors.black,
|
||||
shadowOffset: { width: 0, height: -2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 3,
|
||||
|
|
@ -612,7 +613,7 @@ const MainTabs = () => {
|
|||
headerShown: route.name === 'Home',
|
||||
// Add fixed screen styling to help with consistency
|
||||
contentStyle: {
|
||||
backgroundColor: colors.darkBackground,
|
||||
backgroundColor: currentTheme.colors.darkBackground,
|
||||
},
|
||||
})}
|
||||
// Global configuration for the tab navigator
|
||||
|
|
|
|||
|
|
@ -335,16 +335,14 @@ const MetadataScreen = () => {
|
|||
metadata={metadata}
|
||||
imdbId={imdbId}
|
||||
type={type as 'movie' | 'series'}
|
||||
renderRatings={() => imdbId ? (
|
||||
<RatingsSection
|
||||
imdbId={imdbId}
|
||||
type={type === 'series' ? 'show' : 'movie'}
|
||||
/>
|
||||
) : null}
|
||||
/>
|
||||
|
||||
{/* Add RatingsSection right under the main metadata */}
|
||||
{imdbId && (
|
||||
<RatingsSection
|
||||
imdbId={imdbId}
|
||||
type={type === 'series' ? 'show' : 'movie'}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Cast Section */}
|
||||
<CastSection
|
||||
cast={cast}
|
||||
|
|
|
|||
Loading…
Reference in a new issue