This update introduces a new optional prop,

This commit is contained in:
tapframe 2025-05-04 02:37:39 +05:30
parent 6f2ccfa38b
commit 9ab154f8b8
4 changed files with 54 additions and 83 deletions

View file

@ -5,7 +5,7 @@ import { MaterialIcons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import Animated, { FadeIn } from 'react-native-reanimated';
import { CatalogContent, StreamingContent } from '../../services/catalogService';
import { colors } from '../../styles/colors';
import { useTheme } from '../../contexts/ThemeContext';
import ContentItem from './ContentItem';
import { RootStackParamList } from '../../navigation/AppNavigator';
@ -18,6 +18,7 @@ const POSTER_WIDTH = (width - 50) / 3;
const CatalogSection = ({ catalog }: CatalogSectionProps) => {
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
const { currentTheme } = useTheme();
const handleContentPress = (id: string, type: string) => {
navigation.navigate('Metadata', { id, type });
@ -43,9 +44,9 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
>
<View style={styles.catalogHeader}>
<View style={styles.titleContainer}>
<Text style={styles.catalogTitle}>{catalog.name}</Text>
<Text style={[styles.catalogTitle, { color: currentTheme.colors.highEmphasis }]}>{catalog.name}</Text>
<LinearGradient
colors={[colors.primary, colors.secondary]}
colors={[currentTheme.colors.primary, currentTheme.colors.secondary]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.titleUnderline}
@ -61,8 +62,8 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
}
style={styles.seeAllButton}
>
<Text style={styles.seeAllText}>See More</Text>
<MaterialIcons name="arrow-forward" color={colors.primary} size={16} />
<Text style={[styles.seeAllText, { color: currentTheme.colors.primary }]}>See More</Text>
<MaterialIcons name="arrow-forward" color={currentTheme.colors.primary} size={16} />
</TouchableOpacity>
</View>
@ -94,8 +95,6 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
const styles = StyleSheet.create({
catalogContainer: {
marginBottom: 24,
paddingTop: 0,
marginTop: 16,
},
catalogHeader: {
flexDirection: 'row',
@ -110,7 +109,6 @@ const styles = StyleSheet.create({
catalogTitle: {
fontSize: 18,
fontWeight: '800',
color: colors.highEmphasis,
textTransform: 'uppercase',
letterSpacing: 0.5,
marginBottom: 6,
@ -126,21 +124,14 @@ const styles = StyleSheet.create({
seeAllButton: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.elevation1,
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 16,
gap: 4,
},
seeAllText: {
color: colors.primary,
fontSize: 13,
fontWeight: '700',
marginRight: 4,
fontSize: 14,
fontWeight: '600',
},
catalogList: {
paddingHorizontal: 16,
paddingBottom: 12,
paddingTop: 6,
},
});

View file

@ -15,7 +15,7 @@ import { RootStackParamList } from '../../navigation/AppNavigator';
import { StreamingContent, catalogService } from '../../services/catalogService';
import { LinearGradient } from 'expo-linear-gradient';
import { Image as ExpoImage } from 'expo-image';
import { colors } from '../../styles/colors';
import { useTheme } from '../../contexts/ThemeContext';
import { storageService } from '../../services/storageService';
import { logger } from '../../utils/logger';
@ -39,6 +39,7 @@ const POSTER_WIDTH = (width - 40) / 2.7;
// Create a proper imperative handle with React.forwardRef and updated type
const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, ref) => {
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
const { currentTheme } = useTheme();
const [continueWatchingItems, setContinueWatchingItems] = useState<ContinueWatchingItem[]>([]);
const [loading, setLoading] = useState(true);
const appState = useRef(AppState.currentState);
@ -213,9 +214,9 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
<View style={styles.container}>
<View style={styles.header}>
<View style={styles.titleContainer}>
<Text style={styles.title}>Continue Watching</Text>
<Text style={[styles.title, { color: currentTheme.colors.highEmphasis }]}>Continue Watching</Text>
<LinearGradient
colors={[colors.primary, colors.secondary]}
colors={[currentTheme.colors.primary, currentTheme.colors.secondary]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.titleUnderline}
@ -227,7 +228,10 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
data={continueWatchingItems}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.contentItem}
style={[styles.contentItem, {
borderColor: currentTheme.colors.border,
shadowColor: currentTheme.colors.black
}]}
activeOpacity={0.7}
onPress={() => handleContentPress(item.id, item.type)}
>
@ -240,12 +244,12 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
cachePolicy="memory-disk"
/>
{item.type === 'series' && item.season && item.episode && (
<View style={styles.episodeInfoContainer}>
<Text style={styles.episodeInfo}>
<View style={[styles.episodeInfoContainer, { backgroundColor: 'rgba(0, 0, 0, 0.7)' }]}>
<Text style={[styles.episodeInfo, { color: currentTheme.colors.white }]}>
S{item.season.toString().padStart(2, '0')}E{item.episode.toString().padStart(2, '0')}
</Text>
{item.episodeTitle && (
<Text style={styles.episodeTitle} numberOfLines={1}>
<Text style={[styles.episodeTitle, { color: currentTheme.colors.white, opacity: 0.9 }]} numberOfLines={1}>
{item.episodeTitle}
</Text>
)}
@ -256,7 +260,7 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
<View
style={[
styles.progressBar,
{ width: `${item.progress}%` }
{ width: `${item.progress}%`, backgroundColor: currentTheme.colors.primary }
]}
/>
</View>
@ -295,7 +299,6 @@ const styles = StyleSheet.create({
title: {
fontSize: 18,
fontWeight: '800',
color: colors.highEmphasis,
textTransform: 'uppercase',
letterSpacing: 0.5,
marginBottom: 6,
@ -321,12 +324,10 @@ const styles = StyleSheet.create({
overflow: 'hidden',
position: 'relative',
elevation: 8,
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.1)',
},
contentItemContainer: {
width: '100%',
@ -347,17 +348,13 @@ const styles = StyleSheet.create({
right: 0,
padding: 4,
paddingHorizontal: 8,
backgroundColor: 'rgba(0, 0, 0, 0.7)',
},
episodeInfo: {
fontSize: 12,
fontWeight: 'bold',
color: colors.white,
},
episodeTitle: {
fontSize: 10,
color: colors.white,
opacity: 0.9,
},
progressBarContainer: {
position: 'absolute',
@ -365,20 +362,10 @@ const styles = StyleSheet.create({
left: 0,
right: 0,
height: 3,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
backgroundColor: 'rgba(0,0,0,0.5)',
},
progressBar: {
height: '100%',
backgroundColor: colors.primary,
},
emptyContainer: {
paddingHorizontal: 16,
justifyContent: 'center',
alignItems: 'center',
},
emptyText: {
color: colors.textMuted,
fontSize: 14,
},
});

View file

@ -32,7 +32,6 @@ import { useSettings } from '../../hooks/useSettings';
import { TMDBService } from '../../services/tmdbService';
import { logger } from '../../utils/logger';
import { useTheme } from '../../contexts/ThemeContext';
import type { Theme } from '../../contexts/ThemeContext';
interface FeaturedContentProps {
featuredContent: StreamingContent | null;
@ -47,10 +46,18 @@ const { width, height } = Dimensions.get('window');
const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: FeaturedContentProps) => {
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
const { settings } = useSettings();
const { currentTheme } = useTheme();
const [logoUrl, setLogoUrl] = useState<string | null>(null);
const [bannerUrl, setBannerUrl] = useState<string | null>(null);
const [logoUrl, setLogoUrl] = useState<string | null>(null);
const [logoLoaded, setLogoLoaded] = useState(false);
const [bannerLoaded, setBannerLoaded] = useState(false);
const [showSkeleton, setShowSkeleton] = useState(true);
const [logoError, setLogoError] = useState(false);
const [bannerError, setBannerError] = useState(false);
const { settings } = useSettings();
const logoOpacity = useSharedValue(0);
const bannerOpacity = useSharedValue(0);
const posterOpacity = useSharedValue(0);
const prevContentIdRef = useRef<string | null>(null);
// Add state for tracking logo load errors
const [logoLoadError, setLogoLoadError] = useState(false);
@ -58,11 +65,6 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
const logoFetchInProgress = useRef<boolean>(false);
// Animation values
const posterOpacity = useSharedValue(0);
const logoOpacity = useSharedValue(0);
const contentOpacity = useSharedValue(1); // Start visible
const buttonsOpacity = useSharedValue(1);
const posterAnimatedStyle = useAnimatedStyle(() => ({
opacity: posterOpacity.value,
}));
@ -71,6 +73,9 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
opacity: logoOpacity.value,
}));
const contentOpacity = useSharedValue(1); // Start visible
const buttonsOpacity = useSharedValue(1);
const contentAnimatedStyle = useAnimatedStyle(() => ({
opacity: contentOpacity.value,
}));

View file

@ -13,7 +13,7 @@ import { NavigationProp } from '@react-navigation/native';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import { MaterialIcons } from '@expo/vector-icons';
import { colors } from '../../styles/colors';
import { useTheme } from '../../contexts/ThemeContext';
import { stremioService } from '../../services/stremioService';
import { tmdbService } from '../../services/tmdbService';
import { useLibrary } from '../../hooks/useLibrary';
@ -47,6 +47,7 @@ export const ThisWeekSection = () => {
const { libraryItems, loading: libraryLoading } = useLibrary();
const [episodes, setEpisodes] = useState<ThisWeekEpisode[]>([]);
const [loading, setLoading] = useState(true);
const { currentTheme } = useTheme();
const fetchThisWeekEpisodes = useCallback(async () => {
if (libraryItems.length === 0) {
@ -172,7 +173,7 @@ export const ThisWeekSection = () => {
if (loading) {
return (
<View style={styles.loadingContainer}>
<ActivityIndicator size="small" color={colors.primary} />
<ActivityIndicator size="small" color={currentTheme.colors.primary} />
</View>
);
}
@ -217,26 +218,27 @@ export const ThisWeekSection = () => {
<View style={styles.badgeContainer}>
<View style={[
styles.badge,
isReleased ? styles.releasedBadge : styles.upcomingBadge
isReleased ? styles.releasedBadge : styles.upcomingBadge,
{ backgroundColor: isReleased ? currentTheme.colors.success + 'CC' : currentTheme.colors.primary + 'CC' }
]}>
<MaterialIcons
name={isReleased ? "check-circle" : "event"}
size={12}
color={isReleased ? "#ffffff" : "#ffffff"}
color={currentTheme.colors.white}
/>
<Text style={styles.badgeText}>
<Text style={[styles.badgeText, { color: currentTheme.colors.white }]}>
{isReleased ? 'Released' : 'Coming Soon'}
</Text>
</View>
{item.vote_average > 0 && (
<View style={styles.ratingBadge}>
<View style={[styles.ratingBadge, { backgroundColor: 'rgba(0,0,0,0.8)' }]}>
<MaterialIcons
name="star"
size={12}
color={colors.primary}
color={currentTheme.colors.primary}
/>
<Text style={styles.ratingText}>
<Text style={[styles.ratingText, { color: currentTheme.colors.primary }]}>
{item.vote_average.toFixed(1)}
</Text>
</View>
@ -244,18 +246,18 @@ export const ThisWeekSection = () => {
</View>
<View style={styles.content}>
<Text style={styles.seriesName} numberOfLines={1}>
<Text style={[styles.seriesName, { color: currentTheme.colors.text }]} numberOfLines={1}>
{item.seriesName}
</Text>
<Text style={styles.episodeTitle} numberOfLines={2}>
<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} numberOfLines={2}>
<Text style={[styles.overview, { color: currentTheme.colors.lightGray, opacity: 0.8 }]} numberOfLines={2}>
{item.overview}
</Text>
) : null}
<Text style={styles.releaseDate}>
<Text style={[styles.releaseDate, { color: currentTheme.colors.primary }]}>
{formattedDate}
</Text>
</View>
@ -268,10 +270,10 @@ export const ThisWeekSection = () => {
return (
<Animated.View entering={FadeIn.duration(300)} style={styles.container}>
<View style={styles.header}>
<Text style={styles.title}>This Week</Text>
<Text style={[styles.title, { color: currentTheme.colors.text }]}>This Week</Text>
<TouchableOpacity onPress={handleViewAll} style={styles.viewAllButton}>
<Text style={styles.viewAllText}>View All</Text>
<MaterialIcons name="chevron-right" size={18} color={colors.lightGray} />
<Text style={[styles.viewAllText, { color: currentTheme.colors.lightGray }]}>View All</Text>
<MaterialIcons name="chevron-right" size={18} color={currentTheme.colors.lightGray} />
</TouchableOpacity>
</View>
@ -303,7 +305,6 @@ const styles = StyleSheet.create({
title: {
fontSize: 18,
fontWeight: 'bold',
color: colors.text,
},
viewAllButton: {
flexDirection: 'row',
@ -311,7 +312,6 @@ const styles = StyleSheet.create({
},
viewAllText: {
fontSize: 14,
color: colors.lightGray,
marginRight: 4,
},
listContent: {
@ -358,14 +358,9 @@ const styles = StyleSheet.create({
paddingVertical: 4,
borderRadius: 4,
},
releasedBadge: {
backgroundColor: colors.success + 'CC', // 80% opacity
},
upcomingBadge: {
backgroundColor: colors.primary + 'CC', // 80% opacity
},
releasedBadge: {},
upcomingBadge: {},
badgeText: {
color: '#ffffff',
fontSize: 10,
fontWeight: 'bold',
marginLeft: 4,
@ -373,13 +368,11 @@ const styles = StyleSheet.create({
ratingBadge: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.8)',
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 4,
},
ratingText: {
color: colors.primary,
fontSize: 10,
fontWeight: 'bold',
marginLeft: 4,
@ -388,24 +381,19 @@ const styles = StyleSheet.create({
width: '100%',
},
seriesName: {
color: colors.text,
fontSize: 16,
fontWeight: 'bold',
marginBottom: 4,
},
episodeTitle: {
color: colors.lightGray,
fontSize: 14,
marginBottom: 4,
},
overview: {
color: colors.lightGray,
fontSize: 12,
marginBottom: 4,
opacity: 0.8,
},
releaseDate: {
color: colors.primary,
fontSize: 12,
fontWeight: 'bold',
},