Refactor MetadataScreen to integrate haptic feedback for user interactions; update play button and library toggle functionality to enhance user experience. Replace BlurView with ExpoBlurView and CommunityBlurView for improved visual effects across platforms.

This commit is contained in:
tapframe 2025-05-02 16:34:49 +05:30
parent f9514a51a6
commit 94c49a2767

View file

@ -20,7 +20,9 @@ import { useRoute, useNavigation, useFocusEffect } from '@react-navigation/nativ
import { MaterialIcons } from '@expo/vector-icons'; import { MaterialIcons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import { Image } from 'expo-image'; import { Image } from 'expo-image';
import { BlurView } from 'expo-blur'; import { BlurView as ExpoBlurView } from 'expo-blur';
import { BlurView as CommunityBlurView } from '@react-native-community/blur';
import * as Haptics from 'expo-haptics';
import { colors } from '../styles/colors'; import { colors } from '../styles/colors';
import { useMetadata } from '../hooks/useMetadata'; import { useMetadata } from '../hooks/useMetadata';
import { CastSection as OriginalCastSection } from '../components/metadata/CastSection'; import { CastSection as OriginalCastSection } from '../components/metadata/CastSection';
@ -103,54 +105,62 @@ const ActionButtons = React.memo(({
navigation: NavigationProp<RootStackParamList>; navigation: NavigationProp<RootStackParamList>;
playButtonText: string; playButtonText: string;
animatedStyle: any; animatedStyle: any;
}) => ( }) => {
<Animated.View style={[styles.actionButtons, animatedStyle]}> // Add wrapper for play button with haptic feedback
<TouchableOpacity const handlePlay = () => {
style={[styles.actionButton, styles.playButton]} Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
onPress={handleShowStreams} handleShowStreams();
> };
<MaterialIcons
name={playButtonText === 'Resume' ? "play-circle-outline" : "play-arrow"}
size={24}
color="#000"
/>
<Text style={styles.playButtonText}>
{playButtonText}
</Text>
</TouchableOpacity>
<TouchableOpacity return (
style={[styles.actionButton, styles.infoButton]} <Animated.View style={[styles.actionButtons, animatedStyle]}>
onPress={toggleLibrary}
>
<MaterialIcons
name={inLibrary ? 'bookmark' : 'bookmark-border'}
size={24}
color="#fff"
/>
<Text style={styles.infoButtonText}>
{inLibrary ? 'Saved' : 'Save'}
</Text>
</TouchableOpacity>
{type === 'series' && (
<TouchableOpacity <TouchableOpacity
style={[styles.iconButton]} style={[styles.actionButton, styles.playButton]}
onPress={async () => { onPress={handlePlay}
const tmdb = TMDBService.getInstance();
const tmdbId = await tmdb.extractTMDBIdFromStremioId(id);
if (tmdbId) {
navigation.navigate('ShowRatings', { showId: tmdbId });
} else {
logger.error('Could not find TMDB ID for show');
}
}}
> >
<MaterialIcons name="assessment" size={24} color="#fff" /> <MaterialIcons
name={playButtonText === 'Resume' ? "play-circle-outline" : "play-arrow"}
size={24}
color="#000"
/>
<Text style={styles.playButtonText}>
{playButtonText}
</Text>
</TouchableOpacity> </TouchableOpacity>
)}
</Animated.View> <TouchableOpacity
)); style={[styles.actionButton, styles.infoButton]}
onPress={toggleLibrary}
>
<MaterialIcons
name={inLibrary ? 'bookmark' : 'bookmark-border'}
size={24}
color="#fff"
/>
<Text style={styles.infoButtonText}>
{inLibrary ? 'Saved' : 'Save'}
</Text>
</TouchableOpacity>
{type === 'series' && (
<TouchableOpacity
style={[styles.iconButton]}
onPress={async () => {
const tmdb = TMDBService.getInstance();
const tmdbId = await tmdb.extractTMDBIdFromStremioId(id);
if (tmdbId) {
navigation.navigate('ShowRatings', { showId: tmdbId });
} else {
logger.error('Could not find TMDB ID for show');
}
}}
>
<MaterialIcons name="assessment" size={24} color="#fff" />
</TouchableOpacity>
)}
</Animated.View>
);
});
// Memoized WatchProgress Component // Memoized WatchProgress Component
const WatchProgressDisplay = React.memo(({ const WatchProgressDisplay = React.memo(({
@ -254,6 +264,21 @@ const MetadataScreen = () => {
episodeId?: string; episodeId?: string;
} | null>(null); } | null>(null);
// Add wrapper for toggleLibrary that includes haptic feedback
const handleToggleLibrary = useCallback(() => {
// Trigger appropriate haptic feedback based on action
if (inLibrary) {
// Removed from library - light impact
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
} else {
// Added to library - success feedback
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
}
// Call the original toggleLibrary function
toggleLibrary();
}, [inLibrary, toggleLibrary]);
// Add new animated value for watch progress // Add new animated value for watch progress
const watchProgressOpacity = useSharedValue(0); const watchProgressOpacity = useSharedValue(0);
const watchProgressScaleY = useSharedValue(0); const watchProgressScaleY = useSharedValue(0);
@ -1023,46 +1048,91 @@ const MetadataScreen = () => {
<Animated.View style={containerAnimatedStyle}> <Animated.View style={containerAnimatedStyle}>
{/* Floating Header */} {/* Floating Header */}
<Animated.View style={[styles.floatingHeader, headerAnimatedStyle]}> <Animated.View style={[styles.floatingHeader, headerAnimatedStyle]}>
<BlurView {Platform.OS === 'ios' ? (
intensity={Platform.OS === 'ios' ? 50 : 80} <ExpoBlurView
tint="dark" intensity={50}
style={[styles.blurContainer, { paddingTop: Math.max(safeAreaTop * 0.8, safeAreaTop - 6) }]} tint="dark"
> style={[styles.blurContainer, { paddingTop: Math.max(safeAreaTop * 0.8, safeAreaTop - 6) }]}
<Animated.View style={[styles.floatingHeaderContent, headerElementsStyle]}> >
<TouchableOpacity <Animated.View style={[styles.floatingHeaderContent, headerElementsStyle]}>
style={styles.backButton} <TouchableOpacity
onPress={handleBack} style={styles.backButton}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} onPress={handleBack}
> hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
<MaterialIcons name="arrow-back" size={24} color={colors.highEmphasis} /> >
</TouchableOpacity> <MaterialIcons name="arrow-back" size={24} color={colors.highEmphasis} />
</TouchableOpacity>
<View style={styles.headerTitleContainer}>
{metadata.logo ? ( <View style={styles.headerTitleContainer}>
<Image {metadata.logo ? (
source={{ uri: metadata.logo }} <Image
style={styles.floatingHeaderLogo} source={{ uri: metadata.logo }}
contentFit="contain" style={styles.floatingHeaderLogo}
transition={150} contentFit="contain"
transition={150}
/>
) : (
<Text style={styles.floatingHeaderTitle} numberOfLines={1}>{metadata.name}</Text>
)}
</View>
<TouchableOpacity
style={styles.headerActionButton}
onPress={handleToggleLibrary}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<MaterialIcons
name={inLibrary ? 'bookmark' : 'bookmark-border'}
size={22}
color={colors.highEmphasis}
/> />
) : ( </TouchableOpacity>
<Text style={styles.floatingHeaderTitle} numberOfLines={1}>{metadata.name}</Text> </Animated.View>
)} </ExpoBlurView>
</View> ) : (
<View style={[styles.blurContainer, { paddingTop: Math.max(safeAreaTop * 0.8, safeAreaTop - 6) }]}>
<TouchableOpacity <CommunityBlurView
style={styles.headerActionButton} style={styles.absoluteFill}
onPress={toggleLibrary} blurType="dark"
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} blurAmount={15}
> reducedTransparencyFallbackColor="rgba(20, 20, 20, 0.9)"
<MaterialIcons />
name={inLibrary ? 'bookmark' : 'bookmark-border'} <Animated.View style={[styles.floatingHeaderContent, headerElementsStyle]}>
size={22} <TouchableOpacity
color={colors.highEmphasis} style={styles.backButton}
/> onPress={handleBack}
</TouchableOpacity> hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
</Animated.View> >
</BlurView> <MaterialIcons name="arrow-back" size={24} color={colors.highEmphasis} />
</TouchableOpacity>
<View style={styles.headerTitleContainer}>
{metadata.logo ? (
<Image
source={{ uri: metadata.logo }}
style={styles.floatingHeaderLogo}
contentFit="contain"
transition={150}
/>
) : (
<Text style={styles.floatingHeaderTitle} numberOfLines={1}>{metadata.name}</Text>
)}
</View>
<TouchableOpacity
style={styles.headerActionButton}
onPress={handleToggleLibrary}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<MaterialIcons
name={inLibrary ? 'bookmark' : 'bookmark-border'}
size={22}
color={colors.highEmphasis}
/>
</TouchableOpacity>
</Animated.View>
</View>
)}
{Platform.OS === 'ios' && <View style={styles.headerBottomBorder} />} {Platform.OS === 'ios' && <View style={styles.headerBottomBorder} />}
</Animated.View> </Animated.View>
@ -1129,7 +1199,7 @@ const MetadataScreen = () => {
{/* Action Buttons */} {/* Action Buttons */}
<ActionButtons <ActionButtons
handleShowStreams={handleShowStreams} handleShowStreams={handleShowStreams}
toggleLibrary={toggleLibrary} toggleLibrary={handleToggleLibrary}
inLibrary={inLibrary} inLibrary={inLibrary}
type={type as 'movie' | 'series'} type={type as 'movie' | 'series'}
id={id} id={id}