Refactor ContentItem and MetadataScreen for improved loading handling and UI consistency

This update removes unnecessary state management for image loading in the ContentItem component, streamlining the image display logic. In the MetadataScreen, loading states are now handled more effectively, ensuring a loading screen is shown when metadata is not ready. The overall structure has been simplified for better readability and maintainability.
This commit is contained in:
tapframe 2025-06-30 19:28:28 +05:30
parent 8cbda5c902
commit 0e9426b6c6
2 changed files with 23 additions and 71 deletions

View file

@ -53,8 +53,6 @@ const POSTER_WIDTH = posterLayout.posterWidth;
const ContentItem = React.memo(({ item, onPress }: ContentItemProps) => {
const [menuVisible, setMenuVisible] = useState(false);
const [isWatched, setIsWatched] = useState(false);
const [imageLoaded, setImageLoaded] = useState(false);
const [imageError, setImageError] = useState(false);
const { currentTheme } = useTheme();
const handleLongPress = useCallback(() => {
@ -108,25 +106,7 @@ const ContentItem = React.memo(({ item, onPress }: ContentItemProps) => {
placeholder={{ uri: 'https://via.placeholder.com/300x450' }}
placeholderContentFit="cover"
recyclingKey={item.id}
onLoadStart={() => {
setImageLoaded(false);
setImageError(false);
}}
onLoadEnd={() => setImageLoaded(true)}
onError={() => {
setImageError(true);
setImageLoaded(true);
}}
/>
{(!imageLoaded || imageError) && (
<View style={[styles.loadingOverlay, { backgroundColor: currentTheme.colors.elevation2 }]}>
{!imageError ? (
<ActivityIndicator color={currentTheme.colors.primary} size="small" />
) : (
<MaterialIcons name="broken-image" size={24} color={currentTheme.colors.lightGray} />
)}
</View>
)}
{isWatched && (
<View style={styles.watchedIndicator}>
<MaterialIcons name="check-circle" size={22} color={currentTheme.colors.success} />

View file

@ -281,6 +281,11 @@ const MetadataScreen: React.FC = () => {
return ErrorComponent;
}
// Show loading screen if metadata is not yet available
if (loading || !isContentReady) {
return <MetadataLoadingScreen type={type as 'movie' | 'series'} />;
}
return (
<SafeAreaView
style={[containerStyle, styles.container, { backgroundColor: currentTheme.colors.darkBackground }]}
@ -352,64 +357,31 @@ const MetadataScreen: React.FC = () => {
/>
{/* Cast Section with skeleton when loading */}
{loadingCast ? (
<View style={styles.skeletonSection}>
<View style={[styles.skeletonTitle, { backgroundColor: currentTheme.colors.elevation1 }]} />
<View style={styles.skeletonCastRow}>
{[...Array(4)].map((_, index) => (
<View key={index} style={[styles.skeletonCastItem, { backgroundColor: currentTheme.colors.elevation1 }]} />
))}
</View>
</View>
) : (
<CastSection
cast={cast}
loadingCast={loadingCast}
onSelectCastMember={handleSelectCastMember}
/>
)}
<CastSection
cast={cast}
loadingCast={loadingCast}
onSelectCastMember={handleSelectCastMember}
/>
{/* Recommendations Section with skeleton when loading */}
{type === 'movie' && (
loadingRecommendations ? (
<View style={styles.skeletonSection}>
<View style={[styles.skeletonTitle, { backgroundColor: currentTheme.colors.elevation1 }]} />
<View style={styles.skeletonRecommendationsRow}>
{[...Array(3)].map((_, index) => (
<View key={index} style={[styles.skeletonRecommendationItem, { backgroundColor: currentTheme.colors.elevation1 }]} />
))}
</View>
</View>
) : (
<MoreLikeThisSection
recommendations={recommendations}
loadingRecommendations={loadingRecommendations}
/>
)
<MoreLikeThisSection
recommendations={recommendations}
loadingRecommendations={loadingRecommendations}
/>
)}
{/* Series/Movie Content with episode skeleton when loading */}
{type === 'series' ? (
(loadingSeasons || Object.keys(groupedEpisodes).length === 0) ? (
<View style={styles.skeletonSection}>
<View style={[styles.skeletonTitle, { backgroundColor: currentTheme.colors.elevation1 }]} />
<View style={styles.skeletonEpisodesContainer}>
{[...Array(6)].map((_, index) => (
<View key={index} style={[styles.skeletonEpisodeItem, { backgroundColor: currentTheme.colors.elevation1 }]} />
))}
</View>
</View>
) : (
<SeriesContent
episodes={Object.values(groupedEpisodes).flat()}
selectedSeason={selectedSeason}
loadingSeasons={loadingSeasons}
onSeasonChange={handleSeasonChangeWithHaptics}
onSelectEpisode={handleEpisodeSelect}
groupedEpisodes={groupedEpisodes}
metadata={metadata || undefined}
/>
)
<SeriesContent
episodes={Object.values(groupedEpisodes).flat()}
selectedSeason={selectedSeason}
loadingSeasons={loadingSeasons}
onSeasonChange={handleSeasonChangeWithHaptics}
onSelectEpisode={handleEpisodeSelect}
groupedEpisodes={groupedEpisodes}
metadata={metadata || undefined}
/>
) : (
metadata && <MovieContent metadata={metadata} />
)}