import React, { useEffect, useState } from "react"; import { Keyboard } from "react-native"; import Animated, { Easing, useAnimatedStyle, useSharedValue, withTiming, } from "react-native-reanimated"; import { useQuery } from "@tanstack/react-query"; import { View, ZStack } from "tamagui"; import { getMediaPoster, searchTitle } from "@movie-web/tmdb"; import type { ItemData } from "~/components/item/item"; import Item from "~/components/item/item"; import ScreenLayout from "~/components/layout/ScreenLayout"; import { SearchBar } from "~/components/ui/Searchbar"; export default function SearchScreen() { const [query, setQuery] = useState(""); const translateY = useSharedValue(0); const fadeAnim = useSharedValue(1); const searchResultsOpacity = useSharedValue(0); const searchResultsScale = useSharedValue(0.95); const [searchResultsLoaded, setSearchResultsLoaded] = useState(false); const { data } = useQuery({ queryKey: ["searchResults", query], queryFn: () => fetchSearchResults(query), }); useEffect(() => { if (data && data.length > 0 && query) { searchResultsOpacity.value = withTiming(1, { duration: 500 }); searchResultsScale.value = withTiming(1, { duration: 500 }); setSearchResultsLoaded(true); } else if (!query) { searchResultsOpacity.value = withTiming(0, { duration: 500 }); searchResultsScale.value = withTiming(0.95, { duration: 500 }); setSearchResultsLoaded(false); } }, [data, query, searchResultsOpacity, searchResultsScale]); useEffect(() => { const keyboardWillShowListener = Keyboard.addListener( "keyboardWillShow", (e) => { translateY.value = withTiming( -(e.endCoordinates.height - 100), // determines the height of the Searchbar above keyboard, use Platform.select to adjust value if needed { duration: e.duration ?? 250, // duration always returns 0 on Android, adjust value if needed easing: Easing.out(Easing.ease), }, ); }, ); const keyboardWillHideListener = Keyboard.addListener( "keyboardWillHide", () => { translateY.value = withTiming(0, { duration: 250, easing: Easing.out(Easing.ease), }); }, ); return () => { keyboardWillShowListener.remove(); keyboardWillHideListener.remove(); }; }, [translateY]); const animatedStyle = useAnimatedStyle(() => { return { transform: [{ translateY: translateY.value }], opacity: fadeAnim.value, }; }); const searchResultsStyle = useAnimatedStyle(() => { return { opacity: searchResultsOpacity.value, transform: [{ scale: searchResultsScale.value }], }; }); const handleScrollBegin = () => { fadeAnim.value = withTiming(0, { duration: 100, }); }; const handleScrollEnd = () => { fadeAnim.value = withTiming(1, { duration: 100, }); }; return ( {data?.map((item, index) => ( ))} ); } async function fetchSearchResults(query: string): Promise { const results = await searchTitle(query); return results.map((result) => ({ id: result.id.toString(), title: result.media_type === "tv" ? result.name : result.title, posterUrl: getMediaPoster(result.poster_path), release_date: new Date( result.media_type === "tv" ? result.first_air_date : result.release_date, ), year: new Date( result.media_type === "tv" ? result.first_air_date : result.release_date, ).getFullYear(), type: result.media_type, })); }