Refactor CatalogSection, ContinueWatchingSection, and ThisWeekSection for improved styling and layout consistency

This update enhances the CatalogSection, ContinueWatchingSection, and ThisWeekSection components by refining styles, adjusting layout properties, and improving text visibility. Key changes include updated font sizes, weights, and colors for better readability, as well as modifications to button styles and spacing for a more cohesive user interface. Additionally, the gradient overlays and item containers have been optimized for a more polished appearance.
This commit is contained in:
tapframe 2025-06-21 16:01:34 +05:30
parent 14d8f92b8e
commit bc9f397ada
3 changed files with 258 additions and 138 deletions

View file

@ -80,13 +80,8 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
>
<View style={styles.catalogHeader}>
<View style={styles.titleContainer}>
<Text style={[styles.catalogTitle, { color: currentTheme.colors.highEmphasis }]}>{catalog.name}</Text>
<LinearGradient
colors={[currentTheme.colors.primary, currentTheme.colors.secondary]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.titleUnderline}
/>
<Text style={[styles.catalogTitle, { color: currentTheme.colors.text }]}>{catalog.name}</Text>
<View style={[styles.titleUnderline, { backgroundColor: currentTheme.colors.primary }]} />
</View>
<TouchableOpacity
onPress={() =>
@ -96,10 +91,10 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
addonId: catalog.addon
})
}
style={styles.seeAllButton}
style={styles.viewAllButton}
>
<Text style={[styles.seeAllText, { color: currentTheme.colors.primary }]}>See More</Text>
<MaterialIcons name="arrow-forward" color={currentTheme.colors.primary} size={16} />
<Text style={[styles.viewAllText, { color: currentTheme.colors.textMuted }]}>View All</Text>
<MaterialIcons name="chevron-right" size={20} color={currentTheme.colors.textMuted} />
</TouchableOpacity>
</View>
@ -130,41 +125,45 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
const styles = StyleSheet.create({
catalogContainer: {
marginBottom: 24,
marginBottom: 28,
},
catalogHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: 16,
marginBottom: 12,
marginBottom: 16,
},
titleContainer: {
position: 'relative',
},
catalogTitle: {
fontSize: 19,
fontWeight: '700',
letterSpacing: 0.2,
fontSize: 24,
fontWeight: '800',
letterSpacing: 0.5,
marginBottom: 4,
},
titleUnderline: {
position: 'absolute',
bottom: -2,
left: 0,
width: 35,
height: 2,
borderRadius: 1,
width: 40,
height: 3,
borderRadius: 2,
opacity: 0.8,
},
seeAllButton: {
viewAllButton: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
paddingVertical: 8,
paddingHorizontal: 10,
borderRadius: 20,
backgroundColor: 'rgba(255,255,255,0.1)',
},
seeAllText: {
viewAllText: {
fontSize: 14,
fontWeight: '600',
marginRight: 4,
},
catalogList: {
paddingHorizontal: 16,

View file

@ -277,13 +277,8 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
<Animated.View entering={FadeIn.duration(400).delay(250)} style={styles.container}>
<View style={styles.header}>
<View style={styles.titleContainer}>
<Text style={[styles.title, { color: currentTheme.colors.highEmphasis }]}>Continue Watching</Text>
<LinearGradient
colors={[currentTheme.colors.primary, currentTheme.colors.secondary]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.titleUnderline}
/>
<Text style={[styles.title, { color: currentTheme.colors.text }]}>Continue Watching</Text>
<View style={[styles.titleUnderline, { backgroundColor: currentTheme.colors.primary }]} />
</View>
</View>
@ -386,7 +381,7 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
const styles = StyleSheet.create({
container: {
marginBottom: 24,
marginBottom: 28,
paddingTop: 0,
marginTop: 12,
},
@ -395,15 +390,15 @@ const styles = StyleSheet.create({
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: 16,
marginBottom: 12,
marginBottom: 16,
},
titleContainer: {
position: 'relative',
},
title: {
fontSize: 20,
fontWeight: '700',
letterSpacing: 0.3,
fontSize: 24,
fontWeight: '800',
letterSpacing: 0.5,
marginBottom: 4,
},
titleUnderline: {
@ -411,8 +406,8 @@ const styles = StyleSheet.create({
bottom: -2,
left: 0,
width: 40,
height: 2,
borderRadius: 1,
height: 3,
borderRadius: 2,
opacity: 0.8,
},
wideList: {

View file

@ -22,8 +22,8 @@ import { parseISO, isThisWeek, format, isAfter, isBefore } from 'date-fns';
import Animated, { FadeIn, FadeInRight } from 'react-native-reanimated';
const { width } = Dimensions.get('window');
const ITEM_WIDTH = width * 0.85;
const ITEM_HEIGHT = 180;
const ITEM_WIDTH = width * 0.75; // Reduced width for better spacing
const ITEM_HEIGHT = 220; // Increased height for better proportions
interface ThisWeekEpisode {
id: string;
@ -163,7 +163,10 @@ export const ThisWeekSection = () => {
if (loading) {
return (
<View style={styles.loadingContainer}>
<ActivityIndicator size="small" color={currentTheme.colors.primary} />
<ActivityIndicator size="large" color={currentTheme.colors.primary} />
<Text style={[styles.loadingText, { color: currentTheme.colors.textMuted }]}>
Loading this week's episodes...
</Text>
</View>
);
}
@ -186,84 +189,134 @@ export const ThisWeekSection = () => {
return (
<Animated.View
entering={FadeInRight.delay(index * 100).duration(400)}
entering={FadeInRight.delay(index * 150).duration(600)}
style={styles.episodeItemContainer}
>
<TouchableOpacity
style={styles.episodeItem}
style={[
styles.episodeItem,
{
shadowColor: currentTheme.colors.black,
backgroundColor: currentTheme.colors.background,
}
]}
onPress={() => handleEpisodePress(item)}
activeOpacity={0.7}
activeOpacity={0.8}
>
<Image
source={{ uri: imageUrl }}
style={styles.poster}
contentFit="cover"
transition={300}
/>
<LinearGradient
colors={['transparent', 'rgba(0,0,0,0.8)', 'rgba(0,0,0,0.9)']}
style={styles.gradient}
>
<View style={styles.badgeContainer}>
<View style={[
styles.badge,
isReleased ? styles.releasedBadge : styles.upcomingBadge,
{ backgroundColor: isReleased ? currentTheme.colors.success + 'CC' : currentTheme.colors.primary + 'CC' }
]}>
<MaterialIcons
name={isReleased ? "check-circle" : "event"}
size={12}
color={currentTheme.colors.white}
/>
<Text style={[styles.badgeText, { color: currentTheme.colors.white }]}>
{isReleased ? 'Released' : 'Coming Soon'}
</Text>
</View>
{item.vote_average > 0 && (
<View style={[styles.ratingBadge, { backgroundColor: 'rgba(0,0,0,0.8)' }]}>
<View style={styles.imageContainer}>
<Image
source={{ uri: imageUrl }}
style={styles.poster}
contentFit="cover"
transition={400}
/>
{/* Enhanced gradient overlay */}
<LinearGradient
colors={[
'transparent',
'rgba(0,0,0,0.3)',
'rgba(0,0,0,0.7)',
'rgba(0,0,0,0.9)'
]}
style={styles.gradient}
locations={[0, 0.3, 0.7, 1]}
>
{/* Top badges */}
<View style={styles.topBadgeContainer}>
<View style={[
styles.statusBadge,
isReleased ? styles.releasedBadge : styles.upcomingBadge,
{
backgroundColor: isReleased
? currentTheme.colors.success + 'E6'
: currentTheme.colors.primary + 'E6',
borderColor: isReleased
? currentTheme.colors.success
: currentTheme.colors.primary,
}
]}>
<MaterialIcons
name="star"
size={12}
color={currentTheme.colors.primary}
name={isReleased ? "check-circle" : "schedule"}
size={14}
color={currentTheme.colors.white}
/>
<Text style={[styles.ratingText, { color: currentTheme.colors.primary }]}>
{item.vote_average.toFixed(1)}
<Text style={styles.statusBadgeText}>
{isReleased ? 'Available' : 'Upcoming'}
</Text>
</View>
)}
</View>
<View style={styles.content}>
<Text style={[styles.seriesName, { color: currentTheme.colors.text }]} numberOfLines={1}>
{item.seriesName}
</Text>
<Text style={[styles.episodeTitle, { color: currentTheme.colors.lightGray }]} numberOfLines={2}>
S{item.season}:E{item.episode} - {item.title}
</Text>
{item.overview ? (
<Text style={[styles.overview, { color: currentTheme.colors.lightGray, opacity: 0.8 }]} numberOfLines={2}>
{item.overview}
{item.vote_average > 0 && (
<View style={[
styles.ratingBadge,
{
backgroundColor: 'rgba(255,193,7,0.9)',
borderColor: '#FFD700',
}
]}>
<MaterialIcons
name="star"
size={14}
color="#FFF"
/>
<Text style={styles.ratingText}>
{item.vote_average.toFixed(1)}
</Text>
</View>
)}
</View>
{/* Content area */}
<View style={styles.contentArea}>
<View style={styles.seriesHeader}>
<Text style={[styles.seriesName, { color: currentTheme.colors.white }]} numberOfLines={1}>
{item.seriesName}
</Text>
<View style={[styles.episodeNumber, { backgroundColor: currentTheme.colors.primary + '40' }]}>
<Text style={[styles.episodeNumberText, { color: currentTheme.colors.primary }]}>
S{item.season}:E{item.episode}
</Text>
</View>
</View>
<Text style={[styles.episodeTitle, { color: currentTheme.colors.lightGray }]} numberOfLines={2}>
{item.title}
</Text>
) : null}
<Text style={[styles.releaseDate, { color: currentTheme.colors.primary }]}>
{formattedDate}
</Text>
</View>
</LinearGradient>
{item.overview && (
<Text style={[styles.overview, { color: currentTheme.colors.lightGray }]} numberOfLines={2}>
{item.overview}
</Text>
)}
<View style={styles.dateContainer}>
<MaterialIcons
name="event"
size={14}
color={currentTheme.colors.primary}
/>
<Text style={[styles.releaseDate, { color: currentTheme.colors.primary }]}>
{formattedDate}
</Text>
</View>
</View>
</LinearGradient>
</View>
</TouchableOpacity>
</Animated.View>
);
};
return (
<Animated.View entering={FadeIn.duration(300)} style={styles.container}>
<Animated.View entering={FadeIn.duration(400)} style={styles.container}>
<View style={styles.header}>
<Text style={[styles.title, { color: currentTheme.colors.text }]}>This Week</Text>
<View style={styles.titleContainer}>
<Text style={[styles.title, { color: currentTheme.colors.text }]}>This Week</Text>
<View style={[styles.titleUnderline, { backgroundColor: currentTheme.colors.primary }]} />
</View>
<TouchableOpacity onPress={handleViewAll} style={styles.viewAllButton}>
<Text style={[styles.viewAllText, { color: currentTheme.colors.lightGray }]}>View All</Text>
<MaterialIcons name="chevron-right" size={18} color={currentTheme.colors.lightGray} />
<Text style={[styles.viewAllText, { color: currentTheme.colors.textMuted }]}>View All</Text>
<MaterialIcons name="chevron-right" size={20} color={currentTheme.colors.textMuted} />
</TouchableOpacity>
</View>
@ -274,8 +327,10 @@ export const ThisWeekSection = () => {
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.listContent}
snapToInterval={ITEM_WIDTH + 12}
snapToInterval={ITEM_WIDTH + 16}
decelerationRate="fast"
snapToAlignment="start"
ItemSeparatorComponent={() => <View style={{ width: 16 }} />}
/>
</Animated.View>
);
@ -283,109 +338,180 @@ export const ThisWeekSection = () => {
const styles = StyleSheet.create({
container: {
marginVertical: 16,
marginVertical: 20,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: 16,
marginBottom: 12,
marginBottom: 16,
},
titleContainer: {
position: 'relative',
},
title: {
fontSize: 19,
fontWeight: '700',
letterSpacing: 0.2,
fontSize: 24,
fontWeight: '800',
letterSpacing: 0.5,
marginBottom: 4,
},
titleUnderline: {
position: 'absolute',
bottom: -2,
left: 0,
width: 40,
height: 3,
borderRadius: 2,
opacity: 0.8,
},
viewAllButton: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 8,
paddingHorizontal: 10,
borderRadius: 20,
backgroundColor: 'rgba(255,255,255,0.1)',
},
viewAllText: {
fontSize: 14,
fontWeight: '600',
marginRight: 4,
},
listContent: {
paddingHorizontal: 8,
paddingHorizontal: 20,
paddingBottom: 8,
},
loadingContainer: {
padding: 20,
padding: 32,
alignItems: 'center',
},
loadingText: {
marginTop: 12,
fontSize: 16,
fontWeight: '500',
},
episodeItemContainer: {
width: ITEM_WIDTH,
height: ITEM_HEIGHT,
marginHorizontal: 6,
},
episodeItem: {
width: '100%',
height: '100%',
borderRadius: 8,
borderRadius: 16,
overflow: 'hidden',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.3,
shadowRadius: 12,
elevation: 12,
},
imageContainer: {
width: '100%',
height: '100%',
position: 'relative',
},
poster: {
width: '100%',
height: '100%',
borderRadius: 16,
},
gradient: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
height: '80%',
justifyContent: 'flex-end',
padding: 16,
},
badgeContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 12,
padding: 16,
borderRadius: 16,
},
badge: {
topBadgeContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
},
statusBadge: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
borderRadius: 20,
borderWidth: 1,
backgroundColor: 'rgba(0,0,0,0.3)',
},
releasedBadge: {},
upcomingBadge: {},
badgeText: {
fontSize: 10,
fontWeight: 'bold',
marginLeft: 4,
statusBadgeText: {
fontSize: 11,
fontWeight: '700',
color: '#FFFFFF',
marginLeft: 6,
textTransform: 'uppercase',
letterSpacing: 0.5,
},
ratingBadge: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 4,
borderRadius: 16,
borderWidth: 1,
backgroundColor: 'rgba(0,0,0,0.3)',
},
ratingText: {
fontSize: 10,
fontWeight: 'bold',
fontSize: 11,
fontWeight: '700',
color: '#FFFFFF',
marginLeft: 4,
},
content: {
width: '100%',
contentArea: {
justifyContent: 'flex-end',
},
seriesHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 8,
},
seriesName: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 4,
fontSize: 18,
fontWeight: '700',
flex: 1,
marginRight: 8,
},
episodeNumber: {
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 12,
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.2)',
},
episodeNumberText: {
fontSize: 12,
fontWeight: '700',
letterSpacing: 0.5,
},
episodeTitle: {
fontSize: 14,
marginBottom: 4,
fontSize: 15,
fontWeight: '600',
marginBottom: 6,
lineHeight: 20,
},
overview: {
fontSize: 12,
marginBottom: 4,
fontSize: 13,
lineHeight: 18,
marginBottom: 8,
opacity: 0.9,
},
dateContainer: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 4,
},
releaseDate: {
fontSize: 12,
fontWeight: 'bold',
fontSize: 13,
fontWeight: '600',
marginLeft: 6,
letterSpacing: 0.3,
},
});