some UI changes
This commit is contained in:
parent
99dc34cb65
commit
e912149ff6
8 changed files with 229 additions and 183 deletions
|
|
@ -93,19 +93,6 @@ const CatalogSection = ({ catalog, onPosterPress, onPosterFocus }: CatalogSectio
|
|||
<Text style={[styles.catalogTitle, { color: currentTheme.colors.text }]} numberOfLines={1}>{catalog.name}</Text>
|
||||
<View style={[styles.titleUnderline, { backgroundColor: currentTheme.colors.primary }]} />
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={() =>
|
||||
navigation.navigate('Catalog', {
|
||||
id: catalog.id,
|
||||
type: catalog.type,
|
||||
addonId: catalog.addon
|
||||
})
|
||||
}
|
||||
style={styles.viewAllButton}
|
||||
>
|
||||
<Text style={[styles.viewAllText, { color: currentTheme.colors.textMuted }]}>View All</Text>
|
||||
<MaterialIcons name="chevron-right" size={20} color={currentTheme.colors.textMuted} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<FlashList
|
||||
|
|
|
|||
|
|
@ -106,27 +106,27 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 12,
|
||||
paddingHorizontal: 16,
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
fontSize: 22,
|
||||
fontWeight: '800',
|
||||
},
|
||||
castList: {
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 4,
|
||||
paddingHorizontal: 24,
|
||||
paddingBottom: 8,
|
||||
},
|
||||
castCard: {
|
||||
marginRight: 16,
|
||||
width: 90,
|
||||
marginRight: 20,
|
||||
width: 110,
|
||||
alignItems: 'center',
|
||||
},
|
||||
castImageContainer: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 40,
|
||||
width: 96,
|
||||
height: 96,
|
||||
borderRadius: 48,
|
||||
overflow: 'hidden',
|
||||
marginBottom: 8,
|
||||
marginBottom: 10,
|
||||
},
|
||||
castImage: {
|
||||
width: '100%',
|
||||
|
|
@ -135,24 +135,24 @@ const styles = StyleSheet.create({
|
|||
castImagePlaceholder: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: 40,
|
||||
borderRadius: 48,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
placeholderText: {
|
||||
fontSize: 24,
|
||||
fontWeight: '600',
|
||||
fontSize: 28,
|
||||
fontWeight: '700',
|
||||
},
|
||||
castName: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
textAlign: 'center',
|
||||
width: 90,
|
||||
width: 110,
|
||||
},
|
||||
characterName: {
|
||||
fontSize: 12,
|
||||
fontSize: 13,
|
||||
textAlign: 'center',
|
||||
width: 90,
|
||||
marginTop: 2,
|
||||
width: 110,
|
||||
marginTop: 4,
|
||||
},
|
||||
});
|
||||
|
|
@ -73,29 +73,53 @@ const ActionButtons = React.memo(({
|
|||
const { currentTheme } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.actionButtons}>
|
||||
<View style={[
|
||||
styles.actionButtons,
|
||||
Platform.isTV && { paddingHorizontal: 0, gap: 16 }
|
||||
]}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.actionButton,
|
||||
isWatched ? styles.watchedPlayButton : styles.playButton
|
||||
isWatched ? styles.watchedPlayButton : styles.playButton,
|
||||
Platform.isTV && { paddingVertical: 16, paddingHorizontal: 26, minWidth: 240 }
|
||||
]}
|
||||
onPress={handleShowStreams}
|
||||
hasTVPreferredFocus
|
||||
tvParallaxProperties={Platform.isTV ? {
|
||||
enabled: true,
|
||||
shiftDistanceX: 3.0,
|
||||
shiftDistanceY: 3.0,
|
||||
tiltAngle: 0.06,
|
||||
magnification: 1.08,
|
||||
} : undefined}
|
||||
>
|
||||
<MaterialIcons
|
||||
name="play-arrow"
|
||||
size={20}
|
||||
size={Platform.isTV ? 26 : 20}
|
||||
color={isWatched ? "#fff" : "#000"}
|
||||
/>
|
||||
<Text style={[
|
||||
isWatched ? styles.watchedPlayButtonText : styles.playButtonText
|
||||
isWatched ? styles.watchedPlayButtonText : styles.playButtonText,
|
||||
Platform.isTV && { fontSize: 18 }
|
||||
]}>
|
||||
{playButtonText}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[styles.iconButton, { backgroundColor: 'rgba(255,255,255,0.1)' }]}
|
||||
style={[
|
||||
styles.iconButton,
|
||||
{ backgroundColor: 'rgba(255,255,255,0.1)' },
|
||||
Platform.isTV && { width: 60, height: 60, borderRadius: 30 }
|
||||
]}
|
||||
onPress={toggleLibrary}
|
||||
tvParallaxProperties={Platform.isTV ? {
|
||||
enabled: true,
|
||||
shiftDistanceX: 2.0,
|
||||
shiftDistanceY: 2.0,
|
||||
tiltAngle: 0.05,
|
||||
magnification: 1.06,
|
||||
} : undefined}
|
||||
>
|
||||
{Platform.OS === 'ios' ? (
|
||||
<ExpoBlurView intensity={50} tint="dark" style={styles.blurBackgroundRound} />
|
||||
|
|
@ -104,7 +128,7 @@ const ActionButtons = React.memo(({
|
|||
)}
|
||||
<MaterialIcons
|
||||
name={inLibrary ? 'bookmark' : 'bookmark-border'}
|
||||
size={22}
|
||||
size={Platform.isTV ? 24 : 22}
|
||||
color={currentTheme.colors.highEmphasis}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
|
@ -238,18 +262,22 @@ const HeroSection: React.FC<HeroSectionProps> = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<View style={[styles.heroSection, { height: height * 0.5 }]}>
|
||||
<View style={[styles.heroSection, { height: height * 0.65 }]}>
|
||||
{/* Background Image */}
|
||||
{bannerImage && !imageLoadError && (
|
||||
<Image
|
||||
source={{ uri: bannerImage }}
|
||||
style={styles.absoluteFill}
|
||||
contentFit="cover"
|
||||
transition={300}
|
||||
onLoad={handleImageLoad}
|
||||
onError={handleImageError}
|
||||
/>
|
||||
)}
|
||||
{(() => {
|
||||
const fallback = (metadata && (metadata.banner || metadata.poster)) || null;
|
||||
const uriToUse = !imageLoadError && bannerImage ? bannerImage : fallback;
|
||||
return uriToUse ? (
|
||||
<Image
|
||||
source={{ uri: uriToUse }}
|
||||
style={styles.absoluteFill}
|
||||
contentFit="cover"
|
||||
transition={300}
|
||||
onLoad={handleImageLoad}
|
||||
onError={handleImageError}
|
||||
/>
|
||||
) : null;
|
||||
})()}
|
||||
|
||||
{/* Gradient Overlay */}
|
||||
<LinearGradient
|
||||
|
|
@ -345,9 +373,9 @@ const styles = StyleSheet.create({
|
|||
paddingBottom: 20,
|
||||
},
|
||||
heroContent: {
|
||||
padding: 16,
|
||||
paddingTop: 8,
|
||||
paddingBottom: 8,
|
||||
padding: Platform.isTV ? 24 : 16,
|
||||
paddingTop: Platform.isTV ? 12 : 8,
|
||||
paddingBottom: Platform.isTV ? 12 : 8,
|
||||
},
|
||||
logoContainer: {
|
||||
alignItems: 'center',
|
||||
|
|
@ -361,12 +389,12 @@ const styles = StyleSheet.create({
|
|||
width: '100%',
|
||||
},
|
||||
titleLogo: {
|
||||
width: width * 0.75,
|
||||
height: 90,
|
||||
width: Platform.isTV ? width * 0.5 : width * 0.75,
|
||||
height: Platform.isTV ? 120 : 90,
|
||||
alignSelf: 'center',
|
||||
},
|
||||
heroTitle: {
|
||||
fontSize: 26,
|
||||
fontSize: Platform.isTV ? 44 : 26,
|
||||
fontWeight: '900',
|
||||
marginBottom: 8,
|
||||
textShadowColor: 'rgba(0,0,0,0.8)',
|
||||
|
|
@ -385,12 +413,12 @@ const styles = StyleSheet.create({
|
|||
gap: 6,
|
||||
},
|
||||
genreText: {
|
||||
fontSize: 12,
|
||||
fontSize: Platform.isTV ? 16 : 12,
|
||||
fontWeight: '500',
|
||||
opacity: 0.9,
|
||||
},
|
||||
genreDot: {
|
||||
fontSize: 12,
|
||||
fontSize: Platform.isTV ? 16 : 12,
|
||||
fontWeight: '500',
|
||||
opacity: 0.6,
|
||||
marginHorizontal: 2,
|
||||
|
|
@ -410,7 +438,7 @@ const styles = StyleSheet.create({
|
|||
paddingVertical: 11,
|
||||
paddingHorizontal: 16,
|
||||
borderRadius: 26,
|
||||
flex: 1,
|
||||
flex: Platform.isTV ? 0 : 1,
|
||||
},
|
||||
playButton: {
|
||||
backgroundColor: '#fff',
|
||||
|
|
@ -657,12 +685,12 @@ const styles = StyleSheet.create({
|
|||
marginBottom: 2,
|
||||
},
|
||||
watchProgressMainText: {
|
||||
fontSize: 11,
|
||||
fontSize: Platform.isTV ? 14 : 11,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
},
|
||||
watchProgressSubText: {
|
||||
fontSize: 9,
|
||||
fontSize: Platform.isTV ? 12 : 9,
|
||||
textAlign: 'center',
|
||||
opacity: 0.8,
|
||||
marginBottom: 1,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
Platform,
|
||||
} from 'react-native';
|
||||
import { MaterialIcons } from '@expo/vector-icons';
|
||||
import { Image } from 'expo-image';
|
||||
|
|
@ -112,11 +113,11 @@ const styles = StyleSheet.create({
|
|||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
paddingHorizontal: 16,
|
||||
paddingHorizontal: 24,
|
||||
marginBottom: 12,
|
||||
},
|
||||
metaText: {
|
||||
fontSize: 15,
|
||||
fontSize: Platform.isTV ? 30 : 15,
|
||||
fontWeight: '700',
|
||||
letterSpacing: 0.3,
|
||||
textTransform: 'uppercase',
|
||||
|
|
@ -127,18 +128,18 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
},
|
||||
imdbLogo: {
|
||||
width: 35,
|
||||
height: 18,
|
||||
marginRight: 4,
|
||||
width: Platform.isTV ? 44 : 35,
|
||||
height: Platform.isTV ? 22 : 18,
|
||||
marginRight: Platform.isTV ? 6 : 4,
|
||||
},
|
||||
ratingText: {
|
||||
fontWeight: '700',
|
||||
fontSize: 15,
|
||||
fontSize: Platform.isTV ? 18 : 15,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
creatorContainer: {
|
||||
marginBottom: 2,
|
||||
paddingHorizontal: 16,
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
creatorSection: {
|
||||
flexDirection: 'row',
|
||||
|
|
@ -147,23 +148,23 @@ const styles = StyleSheet.create({
|
|||
height: 20
|
||||
},
|
||||
creatorLabel: {
|
||||
fontSize: 14,
|
||||
fontSize: Platform.isTV ? 16 : 14,
|
||||
fontWeight: '600',
|
||||
marginRight: 8,
|
||||
lineHeight: 20
|
||||
},
|
||||
creatorText: {
|
||||
fontSize: 14,
|
||||
fontSize: Platform.isTV ? 16 : 14,
|
||||
flex: 1,
|
||||
lineHeight: 20
|
||||
},
|
||||
descriptionContainer: {
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 16,
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
description: {
|
||||
fontSize: 15,
|
||||
lineHeight: 24,
|
||||
fontSize: Platform.isTV ? 25 : 17,
|
||||
lineHeight: Platform.isTV ? 30 : 26,
|
||||
},
|
||||
showMoreButton: {
|
||||
flexDirection: 'row',
|
||||
|
|
@ -172,7 +173,7 @@ const styles = StyleSheet.create({
|
|||
paddingVertical: 4,
|
||||
},
|
||||
showMoreText: {
|
||||
fontSize: 14,
|
||||
fontSize: Platform.isTV ? 17 : 15,
|
||||
marginRight: 4,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { View, Text, StyleSheet, ActivityIndicator, Image, Animated } from 'react-native';
|
||||
import { View, Text, StyleSheet, ActivityIndicator, Image, Animated, Platform } from 'react-native';
|
||||
import { useTheme } from '../../contexts/ThemeContext';
|
||||
import { useMDBListRatings } from '../../hooks/useMDBListRatings';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
|
@ -190,8 +190,8 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
|
|||
) : (
|
||||
<View style={styles.compactSvgContainer}>
|
||||
{React.createElement(config.icon as any, {
|
||||
width: 16,
|
||||
height: 16,
|
||||
width: Platform.isTV ? 22 : 16,
|
||||
height: Platform.isTV ? 22 : 16,
|
||||
})}
|
||||
</View>
|
||||
)}
|
||||
|
|
@ -209,8 +209,8 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginTop: 2,
|
||||
marginBottom: 8,
|
||||
paddingHorizontal: 16,
|
||||
marginBottom: 10,
|
||||
paddingHorizontal: Platform.isTV ? 24 : 16,
|
||||
},
|
||||
loadingContainer: {
|
||||
height: 40,
|
||||
|
|
@ -225,18 +225,18 @@ const styles = StyleSheet.create({
|
|||
compactRatingItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginRight: 12,
|
||||
marginRight: Platform.isTV ? 16 : 12,
|
||||
},
|
||||
compactRatingIcon: {
|
||||
width: 16,
|
||||
height: 16,
|
||||
marginRight: 4,
|
||||
width: Platform.isTV ? 22 : 16,
|
||||
height: Platform.isTV ? 22 : 16,
|
||||
marginRight: Platform.isTV ? 6 : 4,
|
||||
},
|
||||
compactSvgContainer: {
|
||||
marginRight: 4,
|
||||
marginRight: Platform.isTV ? 6 : 4,
|
||||
},
|
||||
compactRatingValue: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
fontSize: Platform.isTV ? 18 : 14,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, ActivityIndicator, Dimensions, useWindowDimensions, useColorScheme, FlatList } from 'react-native';
|
||||
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, ActivityIndicator, Dimensions, useWindowDimensions, useColorScheme, FlatList, Platform } from 'react-native';
|
||||
import { Image } from 'expo-image';
|
||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
|
|
@ -231,7 +231,10 @@ export const SeriesContent: React.FC<SeriesContentProps> = ({
|
|||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={styles.seasonSelectorContainer}
|
||||
contentContainerStyle={styles.seasonSelectorContent}
|
||||
contentContainerStyle={[
|
||||
styles.seasonSelectorContent,
|
||||
Platform.isTV && { paddingVertical: 10, paddingHorizontal: 24 }
|
||||
]}
|
||||
initialNumToRender={5}
|
||||
maxToRenderPerBatch={5}
|
||||
windowSize={3}
|
||||
|
|
@ -250,18 +253,31 @@ export const SeriesContent: React.FC<SeriesContentProps> = ({
|
|||
key={season}
|
||||
style={[
|
||||
styles.seasonButton,
|
||||
Platform.isTV && { width: 140, marginRight: 24 },
|
||||
selectedSeason === season && [styles.selectedSeasonButton, { borderColor: currentTheme.colors.primary }]
|
||||
]}
|
||||
onPress={() => onSeasonChange(season)}
|
||||
hasTVPreferredFocus={Platform.isTV && selectedSeason === season}
|
||||
activeOpacity={0.85}
|
||||
tvParallaxProperties={Platform.isTV ? {
|
||||
enabled: true,
|
||||
shiftDistanceX: 2.0,
|
||||
shiftDistanceY: 2.0,
|
||||
tiltAngle: 0.05,
|
||||
magnification: 1.08,
|
||||
} : undefined}
|
||||
>
|
||||
<View style={styles.seasonPosterContainer}>
|
||||
<View style={[
|
||||
styles.seasonPosterContainer,
|
||||
Platform.isTV && { width: 140, height: 210, borderRadius: 12 }
|
||||
]}>
|
||||
<Image
|
||||
source={{ uri: seasonPoster }}
|
||||
style={styles.seasonPoster}
|
||||
contentFit="cover"
|
||||
/>
|
||||
{selectedSeason === season && (
|
||||
<View style={[styles.selectedSeasonIndicator, { backgroundColor: currentTheme.colors.primary }]} />
|
||||
<View style={[styles.selectedSeasonIndicator, { backgroundColor: currentTheme.colors.primary, height: 6 }]} />
|
||||
)}
|
||||
{/* Show episode count badge, including when there are no episodes */}
|
||||
<View style={[styles.episodeCountBadge, { backgroundColor: currentTheme.colors.elevation2 }]}>
|
||||
|
|
@ -274,6 +290,7 @@ export const SeriesContent: React.FC<SeriesContentProps> = ({
|
|||
style={[
|
||||
styles.seasonButtonText,
|
||||
{ color: currentTheme.colors.mediumEmphasis },
|
||||
Platform.isTV && { fontSize: 18, marginTop: 6 },
|
||||
selectedSeason === season && [styles.selectedSeasonButtonText, { color: currentTheme.colors.primary }]
|
||||
]}
|
||||
>
|
||||
|
|
@ -340,14 +357,24 @@ export const SeriesContent: React.FC<SeriesContentProps> = ({
|
|||
style={[
|
||||
styles.episodeCardVertical,
|
||||
isTablet && styles.episodeCardVerticalTablet,
|
||||
{ backgroundColor: currentTheme.colors.elevation2 }
|
||||
{ backgroundColor: currentTheme.colors.elevation2 },
|
||||
Platform.isTV && { height: 150 }
|
||||
]}
|
||||
onPress={() => onSelectEpisode(episode)}
|
||||
activeOpacity={0.7}
|
||||
hasTVPreferredFocus={Platform.isTV && episode === episodes[0]}
|
||||
tvParallaxProperties={Platform.isTV ? {
|
||||
enabled: true,
|
||||
shiftDistanceX: 2.0,
|
||||
shiftDistanceY: 2.0,
|
||||
tiltAngle: 0.05,
|
||||
magnification: 1.05,
|
||||
} : undefined}
|
||||
>
|
||||
<View style={[
|
||||
styles.episodeImageContainer,
|
||||
isTablet && styles.episodeImageContainerTablet
|
||||
isTablet && styles.episodeImageContainerTablet,
|
||||
Platform.isTV && { width: 150, height: 150 }
|
||||
]}>
|
||||
<Image
|
||||
source={{ uri: episodeImage }}
|
||||
|
|
@ -488,6 +515,14 @@ export const SeriesContent: React.FC<SeriesContentProps> = ({
|
|||
]}
|
||||
onPress={() => onSelectEpisode(episode)}
|
||||
activeOpacity={0.85}
|
||||
hasTVPreferredFocus={Platform.isTV && episode === episodes[0]}
|
||||
tvParallaxProperties={Platform.isTV ? {
|
||||
enabled: true,
|
||||
shiftDistanceX: 2.0,
|
||||
shiftDistanceY: 2.0,
|
||||
tiltAngle: 0.05,
|
||||
magnification: 1.06,
|
||||
} : undefined}
|
||||
>
|
||||
{/* Gradient Border Container */}
|
||||
<View style={{
|
||||
|
|
@ -644,7 +679,8 @@ export const SeriesContent: React.FC<SeriesContentProps> = ({
|
|||
entering={FadeIn.duration(300).delay(100 + index * 30)}
|
||||
style={[
|
||||
styles.episodeCardWrapperHorizontal,
|
||||
isTablet && styles.episodeCardWrapperHorizontalTablet
|
||||
isTablet && styles.episodeCardWrapperHorizontalTablet,
|
||||
Platform.isTV && { width: width * 0.3, marginRight: 24 }
|
||||
]}
|
||||
>
|
||||
{renderHorizontalEpisodeCard(episode)}
|
||||
|
|
@ -653,9 +689,12 @@ export const SeriesContent: React.FC<SeriesContentProps> = ({
|
|||
keyExtractor={episode => episode.id.toString()}
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.episodeListContentHorizontal}
|
||||
contentContainerStyle={[
|
||||
styles.episodeListContentHorizontal,
|
||||
Platform.isTV && { paddingLeft: 24, paddingRight: 24 }
|
||||
]}
|
||||
decelerationRate="fast"
|
||||
snapToInterval={isTablet ? width * 0.4 + 16 : width * 0.85 + 16}
|
||||
snapToInterval={Platform.isTV ? width * 0.3 + 24 : (isTablet ? width * 0.4 + 16 : width * 0.85 + 16)}
|
||||
snapToAlignment="start"
|
||||
initialNumToRender={3}
|
||||
maxToRenderPerBatch={3}
|
||||
|
|
@ -721,7 +760,7 @@ const styles = StyleSheet.create({
|
|||
opacity: 0.8,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontSize: 22,
|
||||
fontWeight: '700',
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 16,
|
||||
|
|
@ -756,22 +795,22 @@ const styles = StyleSheet.create({
|
|||
shadowRadius: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255,255,255,0.1)',
|
||||
height: 120,
|
||||
height: 130,
|
||||
},
|
||||
episodeCardVerticalTablet: {
|
||||
width: '47%',
|
||||
flexDirection: 'row',
|
||||
height: 140,
|
||||
height: 160,
|
||||
marginBottom: 0,
|
||||
},
|
||||
episodeImageContainer: {
|
||||
position: 'relative',
|
||||
width: 120,
|
||||
height: 120,
|
||||
width: 130,
|
||||
height: 130,
|
||||
},
|
||||
episodeImageContainerTablet: {
|
||||
width: 140,
|
||||
height: 140,
|
||||
width: 160,
|
||||
height: 160,
|
||||
},
|
||||
episodeImage: {
|
||||
width: '100%',
|
||||
|
|
@ -811,14 +850,14 @@ const styles = StyleSheet.create({
|
|||
marginBottom: 6,
|
||||
},
|
||||
episodeTitle: {
|
||||
fontSize: 15,
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
letterSpacing: 0.3,
|
||||
marginBottom: 2,
|
||||
},
|
||||
episodeTitleTablet: {
|
||||
fontSize: 16,
|
||||
marginBottom: 4,
|
||||
fontSize: 18,
|
||||
marginBottom: 6,
|
||||
},
|
||||
episodeMetadata: {
|
||||
flexDirection: 'row',
|
||||
|
|
@ -843,7 +882,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
ratingText: {
|
||||
color: '#01b4e4',
|
||||
fontSize: 13,
|
||||
fontSize: 14,
|
||||
fontWeight: '700',
|
||||
marginLeft: 4,
|
||||
},
|
||||
|
|
@ -856,22 +895,22 @@ const styles = StyleSheet.create({
|
|||
borderRadius: 4,
|
||||
},
|
||||
runtimeText: {
|
||||
fontSize: 13,
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
marginLeft: 4,
|
||||
},
|
||||
airDateText: {
|
||||
fontSize: 12,
|
||||
fontSize: 13,
|
||||
opacity: 0.8,
|
||||
},
|
||||
episodeOverview: {
|
||||
fontSize: 13,
|
||||
lineHeight: 18,
|
||||
},
|
||||
episodeOverviewTablet: {
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
},
|
||||
episodeOverviewTablet: {
|
||||
fontSize: 15,
|
||||
lineHeight: 22,
|
||||
},
|
||||
progressBarContainer: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
|
|
@ -919,13 +958,13 @@ const styles = StyleSheet.create({
|
|||
shadowRadius: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255,255,255,0.05)',
|
||||
height: 200,
|
||||
height: Platform.isTV ? 200 : 220,
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
episodeCardHorizontalTablet: {
|
||||
height: 180,
|
||||
height: 250,
|
||||
},
|
||||
episodeBackgroundImage: {
|
||||
width: '100%',
|
||||
|
|
@ -963,7 +1002,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
episodeTitleHorizontal: {
|
||||
color: '#fff',
|
||||
fontSize: 15,
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
letterSpacing: -0.3,
|
||||
marginBottom: 4,
|
||||
|
|
@ -971,8 +1010,8 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
episodeDescriptionHorizontal: {
|
||||
color: 'rgba(255,255,255,0.85)',
|
||||
fontSize: 12,
|
||||
lineHeight: 16,
|
||||
fontSize: Platform.isTV ? 14 : 13,
|
||||
lineHeight: 18,
|
||||
marginBottom: 8,
|
||||
opacity: 0.9,
|
||||
},
|
||||
|
|
@ -991,7 +1030,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
runtimeTextHorizontal: {
|
||||
color: 'rgba(255,255,255,0.8)',
|
||||
fontSize: 11,
|
||||
fontSize: 12,
|
||||
fontWeight: '500',
|
||||
},
|
||||
ratingContainerHorizontal: {
|
||||
|
|
@ -1005,7 +1044,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
ratingTextHorizontal: {
|
||||
color: '#FFD700',
|
||||
fontSize: 11,
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
},
|
||||
progressBarContainerHorizontal: {
|
||||
|
|
|
|||
|
|
@ -363,17 +363,6 @@ const MetadataScreen: React.FC = () => {
|
|||
|
||||
{metadata && (
|
||||
<>
|
||||
{/* Floating Header - Optimized */}
|
||||
<FloatingHeader
|
||||
metadata={metadata}
|
||||
logoLoadError={assetData.logoLoadError}
|
||||
handleBack={handleBack}
|
||||
handleToggleLibrary={handleToggleLibrary}
|
||||
inLibrary={inLibrary}
|
||||
safeAreaTop={safeAreaTop}
|
||||
setLogoLoadError={assetData.setLogoLoadError}
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
style={styles.scrollView}
|
||||
showsVerticalScrollIndicator={false}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ const StreamCard = memo(({ stream, onPress, index, isLoading, statusMessage, the
|
|||
alignItems: 'stretch' as const,
|
||||
backgroundColor: isTV ? '#1a1a1a' : theme.colors.card,
|
||||
borderRadius: isTV ? 24 : 12,
|
||||
marginHorizontal: isTV ? 0 : 8,
|
||||
marginHorizontal: isTV ? 12 : 8,
|
||||
marginVertical: isTV ? 16 : 8,
|
||||
minHeight: isTV ? 160 : 90,
|
||||
overflow: 'hidden' as const,
|
||||
|
|
@ -194,6 +194,7 @@ const StreamCard = memo(({ stream, onPress, index, isLoading, statusMessage, the
|
|||
// Force visibility on TV
|
||||
opacity: 1,
|
||||
zIndex: isTV ? 10 : 1,
|
||||
maxWidth: isTV ? width - (24 * 2) - (12 * 2) : undefined,
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -211,11 +212,11 @@ const StreamCard = memo(({ stream, onPress, index, isLoading, statusMessage, the
|
|||
hasTVPreferredFocus={index === 0 && isTV}
|
||||
tvParallaxProperties={isTV ? {
|
||||
enabled: true,
|
||||
shiftDistanceX: 10.0,
|
||||
shiftDistanceY: 10.0,
|
||||
tiltAngle: 0.25,
|
||||
magnification: 1.08,
|
||||
pressMagnification: 0.92,
|
||||
shiftDistanceX: 6.0,
|
||||
shiftDistanceY: 6.0,
|
||||
tiltAngle: 0.18,
|
||||
magnification: 1.03,
|
||||
pressMagnification: 0.97,
|
||||
pressDuration: 0.12,
|
||||
} : undefined}
|
||||
>
|
||||
|
|
@ -1865,9 +1866,9 @@ export const StreamsScreen = () => {
|
|||
removeClippedSubviews={false}
|
||||
getItemLayout={undefined}
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: Platform.isTV ? 0 : 16,
|
||||
paddingVertical: Platform.isTV ? 0 : 16,
|
||||
paddingBottom: Platform.isTV ? 120 : 16,
|
||||
paddingHorizontal: Platform.isTV ? 24 : 16,
|
||||
paddingVertical: 0,
|
||||
paddingBottom: 0,
|
||||
width: '100%',
|
||||
}}
|
||||
style={{
|
||||
|
|
@ -1948,7 +1949,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
paddingTop: Platform.OS === 'android' ? 10 : 15,
|
||||
},
|
||||
filterContainer: {
|
||||
paddingHorizontal: Platform.isTV ? 0 : 16,
|
||||
paddingHorizontal: Platform.isTV ? 24 : 16,
|
||||
paddingBottom: 12,
|
||||
},
|
||||
filterScroll: {
|
||||
|
|
@ -1956,11 +1957,11 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
},
|
||||
filterChip: {
|
||||
backgroundColor: 'transparent',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
borderRadius: 20,
|
||||
marginRight: 8,
|
||||
borderWidth: 1,
|
||||
paddingHorizontal: Platform.isTV ? 22 : 16,
|
||||
paddingVertical: Platform.isTV ? 12 : 8,
|
||||
borderRadius: Platform.isTV ? 28 : 20,
|
||||
marginRight: Platform.isTV ? 12 : 8,
|
||||
borderWidth: Platform.isTV ? 2 : 1,
|
||||
borderColor: colors.border,
|
||||
},
|
||||
filterChipSelected: {
|
||||
|
|
@ -1969,11 +1970,12 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
},
|
||||
filterChipText: {
|
||||
color: colors.mediumEmphasis,
|
||||
fontWeight: '500',
|
||||
fontWeight: '600',
|
||||
fontSize: Platform.isTV ? 18 : undefined,
|
||||
},
|
||||
filterChipTextSelected: {
|
||||
color: colors.white,
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
},
|
||||
streamsContent: {
|
||||
flex: 1,
|
||||
|
|
@ -2061,17 +2063,17 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
},
|
||||
chip: {
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 4,
|
||||
marginRight: 4,
|
||||
marginBottom: 4,
|
||||
paddingHorizontal: Platform.isTV ? 14 : 10,
|
||||
paddingVertical: Platform.isTV ? 6 : 4,
|
||||
borderRadius: Platform.isTV ? 8 : 4,
|
||||
marginRight: Platform.isTV ? 6 : 4,
|
||||
marginBottom: Platform.isTV ? 6 : 4,
|
||||
backgroundColor: colors.surfaceVariant,
|
||||
},
|
||||
chipText: {
|
||||
color: colors.highEmphasis,
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
fontSize: Platform.isTV ? 14 : 12,
|
||||
fontWeight: '700',
|
||||
},
|
||||
progressContainer: {
|
||||
height: 20,
|
||||
|
|
@ -2141,7 +2143,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
},
|
||||
streamsHeroContainer: {
|
||||
width: '100%',
|
||||
height: 220,
|
||||
height: Platform.isTV ? Math.round(height * 0.45) : 220,
|
||||
marginBottom: 0,
|
||||
position: 'relative',
|
||||
backgroundColor: colors.black,
|
||||
|
|
@ -2155,7 +2157,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
streamsHeroGradient: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-end',
|
||||
padding: 16,
|
||||
padding: Platform.isTV ? 24 : 16,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
streamsHeroContent: {
|
||||
|
|
@ -2166,27 +2168,27 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
},
|
||||
streamsHeroEpisodeNumber: {
|
||||
color: colors.primary,
|
||||
fontSize: 14,
|
||||
fontSize: Platform.isTV ? 50 : 24,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 2,
|
||||
marginBottom: Platform.isTV ? 8 : 2,
|
||||
textShadowColor: 'rgba(0,0,0,0.75)',
|
||||
textShadowOffset: { width: 0, height: 1 },
|
||||
textShadowRadius: 2,
|
||||
},
|
||||
streamsHeroTitle: {
|
||||
color: colors.highEmphasis,
|
||||
fontSize: 24,
|
||||
fontSize: Platform.isTV ? 60 : 24,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 4,
|
||||
marginBottom: Platform.isTV ? 12 : 4,
|
||||
textShadowColor: 'rgba(0,0,0,0.75)',
|
||||
textShadowOffset: { width: 0, height: 1 },
|
||||
textShadowRadius: 3,
|
||||
},
|
||||
streamsHeroOverview: {
|
||||
color: colors.mediumEmphasis,
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
marginBottom: 2,
|
||||
fontSize: Platform.isTV ? 30 : 14,
|
||||
lineHeight: Platform.isTV ? 28 : 20,
|
||||
marginBottom: Platform.isTV ? 10 : 2,
|
||||
textShadowColor: 'rgba(0,0,0,0.75)',
|
||||
textShadowOffset: { width: 0, height: 1 },
|
||||
textShadowRadius: 2,
|
||||
|
|
@ -2194,12 +2196,12 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
streamsHeroMeta: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
gap: Platform.isTV ? 20 : 12,
|
||||
marginTop: 0,
|
||||
},
|
||||
streamsHeroReleased: {
|
||||
color: colors.mediumEmphasis,
|
||||
fontSize: 14,
|
||||
fontSize: Platform.isTV ? 25 : 14,
|
||||
textShadowColor: 'rgba(0,0,0,0.75)',
|
||||
textShadowOffset: { width: 0, height: 1 },
|
||||
textShadowRadius: 2,
|
||||
|
|
@ -2208,18 +2210,18 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(0,0,0,0.7)',
|
||||
paddingHorizontal: 6,
|
||||
paddingVertical: 3,
|
||||
paddingHorizontal: Platform.isTV ? 8 : 6,
|
||||
paddingVertical: Platform.isTV ? 4 : 3,
|
||||
borderRadius: 4,
|
||||
marginTop: 0,
|
||||
},
|
||||
tmdbLogo: {
|
||||
width: 20,
|
||||
height: 14,
|
||||
width: Platform.isTV ? 28 : 20,
|
||||
height: Platform.isTV ? 18 : 14,
|
||||
},
|
||||
streamsHeroRatingText: {
|
||||
color: colors.accent,
|
||||
fontSize: 13,
|
||||
fontSize: Platform.isTV ? 18 : 13,
|
||||
fontWeight: '700',
|
||||
marginLeft: 4,
|
||||
},
|
||||
|
|
@ -2270,11 +2272,11 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
},
|
||||
movieTitleContainer: {
|
||||
width: '100%',
|
||||
height: 140,
|
||||
height: Platform.isTV ? 200 : 140,
|
||||
backgroundColor: colors.darkBackground,
|
||||
pointerEvents: 'box-none',
|
||||
justifyContent: 'center',
|
||||
paddingTop: Platform.OS === 'android' ? 65 : 35,
|
||||
paddingTop: Platform.isTV ? 40 : (Platform.OS === 'android' ? 65 : 35),
|
||||
},
|
||||
movieTitleContent: {
|
||||
width: '100%',
|
||||
|
|
@ -2285,11 +2287,11 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
movieLogo: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: width * 0.85,
|
||||
maxWidth: Platform.isTV ? width * 0.9 : width * 0.85,
|
||||
},
|
||||
movieTitle: {
|
||||
color: colors.highEmphasis,
|
||||
fontSize: 28,
|
||||
fontSize: Platform.isTV ? 36 : 28,
|
||||
fontWeight: '900',
|
||||
textAlign: 'center',
|
||||
letterSpacing: -0.5,
|
||||
|
|
@ -2378,7 +2380,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
fontWeight: '600',
|
||||
},
|
||||
activeScrapersContainer: {
|
||||
paddingHorizontal: Platform.isTV ? 0 : 16,
|
||||
paddingHorizontal: Platform.isTV ? 24 : 16,
|
||||
paddingVertical: 8,
|
||||
backgroundColor: 'transparent',
|
||||
marginHorizontal: Platform.isTV ? 0 : 16,
|
||||
|
|
@ -2386,27 +2388,27 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
},
|
||||
activeScrapersTitle: {
|
||||
color: colors.mediumEmphasis,
|
||||
fontSize: 12,
|
||||
fontWeight: '500',
|
||||
fontSize: Platform.isTV ? 14 : 12,
|
||||
fontWeight: '600',
|
||||
marginBottom: 6,
|
||||
opacity: 0.8,
|
||||
},
|
||||
activeScrapersRow: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 4,
|
||||
gap: Platform.isTV ? 6 : 4,
|
||||
},
|
||||
activeScraperChip: {
|
||||
backgroundColor: colors.elevation2,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
borderRadius: 6,
|
||||
paddingHorizontal: Platform.isTV ? 12 : 8,
|
||||
paddingVertical: Platform.isTV ? 6 : 3,
|
||||
borderRadius: Platform.isTV ? 10 : 6,
|
||||
borderWidth: 0,
|
||||
},
|
||||
activeScraperText: {
|
||||
color: colors.mediumEmphasis,
|
||||
fontSize: 11,
|
||||
fontWeight: '400',
|
||||
fontSize: Platform.isTV ? 13 : 11,
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue