import React, { useEffect } from 'react'; import { View, Text, StyleSheet, Modal, Pressable, TouchableOpacity, useColorScheme, Dimensions, Platform } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; import { Image as ExpoImage } from 'expo-image'; import { colors } from '../../styles/colors'; import Animated, { useAnimatedStyle, withTiming, useSharedValue, interpolate, Extrapolate, runOnJS, } from 'react-native-reanimated'; import { Gesture, GestureDetector, GestureHandlerRootView, } from 'react-native-gesture-handler'; import { StreamingContent } from '../../services/catalogService'; interface DropUpMenuProps { visible: boolean; onClose: () => void; item: StreamingContent; onOptionSelect: (option: string) => void; isSaved?: boolean; // allow parent to pass saved status directly isWatched?: boolean; // allow parent to pass watched status directly } export const DropUpMenu = ({ visible, onClose, item, onOptionSelect, isSaved: isSavedProp, isWatched: isWatchedProp }: DropUpMenuProps) => { const translateY = useSharedValue(300); const opacity = useSharedValue(0); const isDarkMode = useColorScheme() === 'dark'; const SNAP_THRESHOLD = 100; useEffect(() => { if (visible) { opacity.value = withTiming(1, { duration: 200 }); translateY.value = withTiming(0, { duration: 300 }); } else { opacity.value = withTiming(0, { duration: 200 }); translateY.value = withTiming(300, { duration: 300 }); } }, [visible]); const gesture = Gesture.Pan() .onStart(() => { // Store initial position if needed }) .onUpdate((event) => { if (event.translationY > 0) { // Only allow dragging downwards translateY.value = event.translationY; opacity.value = interpolate( event.translationY, [0, 300], [1, 0], Extrapolate.CLAMP ); } }) .onEnd((event) => { if (event.translationY > SNAP_THRESHOLD || event.velocityY > 500) { translateY.value = withTiming(300, { duration: 300 }); opacity.value = withTiming(0, { duration: 200 }); runOnJS(onClose)(); } else { translateY.value = withTiming(0, { duration: 300 }); opacity.value = withTiming(1, { duration: 200 }); } }); const overlayStyle = useAnimatedStyle(() => ({ opacity: opacity.value, })); const menuStyle = useAnimatedStyle(() => ({ transform: [{ translateY: translateY.value }], borderTopLeftRadius: 24, borderTopRightRadius: 24, })); // Robustly determine if the item is in the library (saved) const isSaved = typeof isSavedProp === 'boolean' ? isSavedProp : !!item.inLibrary; const isWatched = !!isWatchedProp; let menuOptions = [ { icon: 'bookmark', label: isSaved ? 'Remove from Library' : 'Add to Library', action: 'library' }, { icon: 'check-circle', label: isWatched ? 'Mark as Unwatched' : 'Mark as Watched', action: 'watched' }, /* { icon: 'playlist-add', label: 'Add to Playlist', action: 'playlist' }, */ { icon: 'share', label: 'Share', action: 'share' } ]; // If used in LibraryScreen, only show 'Remove from Library' if item is in library if (isSavedProp === true) { menuOptions = menuOptions.filter(opt => opt.action !== 'library' || isSaved); } const backgroundColor = isDarkMode ? '#1A1A1A' : '#FFFFFF'; return ( {item.name} {item.year && ( {item.year} )} {menuOptions.map((option, index) => ( { onOptionSelect(option.action); onClose(); }} > {option.label} ))} ); }; const styles = StyleSheet.create({ modalOverlay: { flex: 1, justifyContent: 'flex-end', backgroundColor: colors.transparentDark, }, modalOverlayPressable: { flex: 1, }, dragHandle: { width: 40, height: 4, backgroundColor: colors.transparentLight, borderRadius: 2, alignSelf: 'center', marginTop: 12, marginBottom: 10, }, menuContainer: { borderTopLeftRadius: 24, borderTopRightRadius: 24, paddingBottom: Platform.select({ ios: 40, android: 24 }), ...Platform.select({ ios: { shadowColor: colors.black, shadowOffset: { width: 0, height: -3 }, shadowOpacity: 0.1, shadowRadius: 5, }, android: { elevation: 5, }, }), }, menuHeader: { flexDirection: 'row', padding: 16, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: colors.border, }, menuPoster: { width: 60, height: 90, borderRadius: 12, }, menuTitleContainer: { flex: 1, marginLeft: 12, justifyContent: 'center', }, menuTitle: { fontSize: 16, fontWeight: '600', marginBottom: 4, }, menuYear: { fontSize: 14, }, menuOptions: { paddingTop: 8, }, menuOption: { flexDirection: 'row', alignItems: 'center', padding: 16, borderBottomWidth: StyleSheet.hairlineWidth, }, lastMenuOption: { borderBottomWidth: 0, }, menuOptionText: { fontSize: 16, marginLeft: 16, }, }); export default DropUpMenu;