mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
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:
parent
14d8f92b8e
commit
bc9f397ada
3 changed files with 258 additions and 138 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
Loading…
Reference in a new issue