floating header logo fetch fix

This commit is contained in:
tapframe 2025-10-17 23:41:27 +05:30
parent 1535ef9aac
commit fd5861026d
3 changed files with 23 additions and 12 deletions

View file

@ -6,6 +6,7 @@ import {
TouchableOpacity, TouchableOpacity,
Platform, Platform,
Dimensions, Dimensions,
Image,
} from 'react-native'; } from 'react-native';
import { BlurView as ExpoBlurView } from 'expo-blur'; import { BlurView as ExpoBlurView } from 'expo-blur';
import { MaterialIcons, Feather } from '@expo/vector-icons'; import { MaterialIcons, Feather } from '@expo/vector-icons';
@ -24,7 +25,6 @@ if (Platform.OS === 'ios') {
liquidGlassAvailable = false; liquidGlassAvailable = false;
} }
} }
import FastImage from '@d11/react-native-fast-image';
import Animated, { import Animated, {
useAnimatedStyle, useAnimatedStyle,
interpolate, interpolate,
@ -49,6 +49,7 @@ interface FloatingHeaderProps {
headerElementsOpacity: SharedValue<number>; headerElementsOpacity: SharedValue<number>;
safeAreaTop: number; safeAreaTop: number;
setLogoLoadError: (error: boolean) => void; setLogoLoadError: (error: boolean) => void;
stableLogoUri?: string | null;
} }
const FloatingHeader: React.FC<FloatingHeaderProps> = ({ const FloatingHeader: React.FC<FloatingHeaderProps> = ({
@ -62,6 +63,7 @@ const FloatingHeader: React.FC<FloatingHeaderProps> = ({
headerElementsOpacity, headerElementsOpacity,
safeAreaTop, safeAreaTop,
setLogoLoadError, setLogoLoadError,
stableLogoUri,
}) => { }) => {
const { currentTheme } = useTheme(); const { currentTheme } = useTheme();
const [isHeaderInteractive, setIsHeaderInteractive] = React.useState(false); const [isHeaderInteractive, setIsHeaderInteractive] = React.useState(false);
@ -111,13 +113,13 @@ const FloatingHeader: React.FC<FloatingHeaderProps> = ({
</TouchableOpacity> </TouchableOpacity>
<View style={styles.headerTitleContainer}> <View style={styles.headerTitleContainer}>
{metadata.logo && !logoLoadError ? ( {(stableLogoUri || metadata.logo) && !logoLoadError ? (
<FastImage <Image
source={{ uri: metadata.logo }} source={{ uri: stableLogoUri || metadata.logo }}
style={styles.floatingHeaderLogo} style={styles.floatingHeaderLogo}
resizeMode={FastImage.resizeMode.contain} resizeMode="contain"
onError={() => { onError={() => {
logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`); logger.warn(`[FloatingHeader] Logo failed to load: ${stableLogoUri || metadata.logo}`);
setLogoLoadError(true); setLogoLoadError(true);
}} }}
/> />
@ -155,13 +157,13 @@ const FloatingHeader: React.FC<FloatingHeaderProps> = ({
</TouchableOpacity> </TouchableOpacity>
<View style={styles.headerTitleContainer}> <View style={styles.headerTitleContainer}>
{metadata.logo && !logoLoadError ? ( {(stableLogoUri || metadata.logo) && !logoLoadError ? (
<FastImage <Image
source={{ uri: metadata.logo }} source={{ uri: stableLogoUri || metadata.logo }}
style={styles.floatingHeaderLogo} style={styles.floatingHeaderLogo}
resizeMode={FastImage.resizeMode.contain} resizeMode="contain"
onError={() => { onError={() => {
logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`); logger.warn(`[FloatingHeader] Logo failed to load: ${stableLogoUri || metadata.logo}`);
setLogoLoadError(true); setLogoLoadError(true);
}} }}
/> />

View file

@ -83,6 +83,7 @@ interface HeroSectionProps {
traktSynced?: boolean; traktSynced?: boolean;
traktProgress?: number; traktProgress?: number;
} | null; } | null;
onStableLogoUriChange?: (logoUri: string | null) => void;
type: 'movie' | 'series'; type: 'movie' | 'series';
getEpisodeDetails: (episodeId: string) => { seasonNumber: string; episodeNumber: string; episodeName: string } | null; getEpisodeDetails: (episodeId: string) => { seasonNumber: string; episodeNumber: string; episodeName: string } | null;
handleShowStreams: () => void; handleShowStreams: () => void;
@ -777,6 +778,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
buttonsTranslateY, buttonsTranslateY,
watchProgressOpacity, watchProgressOpacity,
watchProgress, watchProgress,
onStableLogoUriChange,
type, type,
getEpisodeDetails, getEpisodeDetails,
handleShowStreams, handleShowStreams,
@ -966,12 +968,14 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
if (metadata?.logo && metadata.logo !== stableLogoUri) { if (metadata?.logo && metadata.logo !== stableLogoUri) {
setStableLogoUri(metadata.logo); setStableLogoUri(metadata.logo);
onStableLogoUriChange?.(metadata.logo);
setLogoHasLoadedSuccessfully(false); // Reset for new logo setLogoHasLoadedSuccessfully(false); // Reset for new logo
logoLoadOpacity.value = 0; // reset fade for new logo logoLoadOpacity.value = 0; // reset fade for new logo
setShouldShowTextFallback(false); setShouldShowTextFallback(false);
} else if (!metadata?.logo && stableLogoUri) { } else if (!metadata?.logo && stableLogoUri) {
// Clear logo if metadata no longer has one // Clear logo if metadata no longer has one
setStableLogoUri(null); setStableLogoUri(null);
onStableLogoUriChange?.(null);
setLogoHasLoadedSuccessfully(false); setLogoHasLoadedSuccessfully(false);
// Start a short grace period before showing text fallback // Start a short grace period before showing text fallback
setShouldShowTextFallback(false); setShouldShowTextFallback(false);

View file

@ -212,6 +212,9 @@ const MetadataScreen: React.FC = () => {
const assetData = useMetadataAssets(metadata, id, type, imdbId, settings, setMetadata); const assetData = useMetadataAssets(metadata, id, type, imdbId, settings, setMetadata);
const animations = useMetadataAnimations(safeAreaTop, watchProgressData.watchProgress); const animations = useMetadataAnimations(safeAreaTop, watchProgressData.watchProgress);
// Stable logo URI from HeroSection
const [stableLogoUri, setStableLogoUri] = React.useState<string | null>(null);
// Extract dominant color from hero image for dynamic background // Extract dominant color from hero image for dynamic background
const heroImageUri = useMemo(() => { const heroImageUri = useMemo(() => {
if (!settings.useDominantBackgroundColor) return null; if (!settings.useDominantBackgroundColor) return null;
@ -881,6 +884,7 @@ const MetadataScreen: React.FC = () => {
headerElementsOpacity={animations.headerElementsOpacity} headerElementsOpacity={animations.headerElementsOpacity}
safeAreaTop={safeAreaTop} safeAreaTop={safeAreaTop}
setLogoLoadError={assetData.setLogoLoadError} setLogoLoadError={assetData.setLogoLoadError}
stableLogoUri={stableLogoUri}
/> />
<Animated.ScrollView <Animated.ScrollView
@ -908,6 +912,7 @@ const MetadataScreen: React.FC = () => {
watchProgressOpacity={animations.watchProgressOpacity} watchProgressOpacity={animations.watchProgressOpacity}
watchProgressWidth={animations.watchProgressWidth} watchProgressWidth={animations.watchProgressWidth}
watchProgress={watchProgressData.watchProgress} watchProgress={watchProgressData.watchProgress}
onStableLogoUriChange={setStableLogoUri}
type={Object.keys(groupedEpisodes).length > 0 ? 'series' : type as 'movie' | 'series'} type={Object.keys(groupedEpisodes).length > 0 ? 'series' : type as 'movie' | 'series'}
getEpisodeDetails={watchProgressData.getEpisodeDetails} getEpisodeDetails={watchProgressData.getEpisodeDetails}
handleShowStreams={handleShowStreams} handleShowStreams={handleShowStreams}