import ShowCard from "@/components/ui/ShowCard"; import { Colors } from "@/constants/colors"; import { useShows } from "@/hooks/useShows"; import { useStreamingServices } from "@/hooks/useStreamingServices"; import Feather from "@expo/vector-icons/Feather"; import * as Haptics from "expo-haptics"; import { router, Stack } from "expo-router"; import React from "react"; import { ActivityIndicator, Image, Platform, RefreshControl, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from "react-native"; export default function HomeScreen() { const { data: shows = [], error, isLoading: loading, refetch: refetchShows, } = useShows(); const { data: streamingServices = {}, refetch: refetchServices } = useStreamingServices(); const [activeFilter, setActiveFilter] = React.useState("all"); const [refreshing, setRefreshing] = React.useState(false); const haptikFeedback = () => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); }; const handleFilter = (type: string) => { haptikFeedback(); setActiveFilter(type === activeFilter ? "all" : type); }; const onRefresh = React.useCallback(async () => { haptikFeedback(); setRefreshing(true); try { await Promise.all([ typeof refetchShows === "function" ? refetchShows() : Promise.resolve(), typeof refetchServices === "function" ? refetchServices() : Promise.resolve(), ]); } finally { setRefreshing(false); } }, [refetchShows, refetchServices]); const filteredShows = React.useMemo(() => { if (activeFilter === "all") return shows; if (activeFilter === "live") return shows.filter((show) => show.running); return shows.filter((show) => show.streamingService .split(",") .map((s) => s.trim()) .includes(activeFilter), ); }, [shows, activeFilter]); const uniqueStreamingServices = React.useMemo(() => { const uniqueServices = new Set(); shows.forEach((show) => { show.streamingService .split(", ") .map((s) => s.trim()) .forEach((service) => uniqueServices.add(service)); }); return Array.from(uniqueServices); }, [shows]); if (loading) { return ( ); } if (error) { return ( ⚠️ Fehler beim Laden {error?.message || "Ein unerwarteter Fehler ist aufgetreten."} { if (typeof refetchShows === "function") refetchShows(); if (typeof refetchServices === "function") refetchServices(); }} style={s.retryButton} > Erneut versuchen ); } return ( ( router.push("/legal")} hitSlop={8}> ), }} /> } > {/* Filter chips */} handleFilter("all")} activeOpacity={0.7} > Alle handleFilter("live")} activeOpacity={0.7} > Live {uniqueStreamingServices.map((serviceName) => { const serviceUri = streamingServices[ `assets.images.streamingServices.${serviceName.toLowerCase()}` ]; const isActive = activeFilter === serviceName; return ( handleFilter(serviceName)} activeOpacity={0.7} > {serviceUri ? ( ) : ( {serviceName} )} ); })} {/* Show cards */} {filteredShows.map((show) => ( router.push({ pathname: "/showDetails", params: { id: String(show.id), title: show.title, bannerUri: show.bannerUri, description: show.description, concept: show.concept, genres: show.genres, streamingService: show.streamingService, logoUri: show.logoUrl, running: String(show.running), }, }) } imageUri={show.bannerUri} streamingServicesUris={show.streamingService .split(", ") .map( (sv) => streamingServices[ `assets.images.streamingServices.${sv.toLowerCase()}` ], )} genres={show.genres} {...(show.running ? { liveBadgeText: "LIVE", } : {})} /> ))} ); } const s = StyleSheet.create({ container: { flex: 1, backgroundColor: Colors.background, }, centered: { flex: 1, backgroundColor: Colors.background, justifyContent: "center", alignItems: "center", padding: 20, }, errorCard: { alignItems: "center", gap: 10, backgroundColor: "rgba(255,255,255,0.06)", paddingVertical: 28, paddingHorizontal: 24, borderRadius: 16, width: "90%", }, errorTitle: { fontSize: 17, fontWeight: "600", color: "white", textAlign: "center", }, errorMessage: { fontSize: 14, color: "rgba(255,255,255,0.55)", textAlign: "center", lineHeight: 20, }, retryButton: { marginTop: 8, backgroundColor: "rgba(255,255,255,0.12)", paddingVertical: 10, paddingHorizontal: 20, borderRadius: 10, }, retryText: { color: "white", fontWeight: "600", fontSize: 15, }, /* Filter row */ filterRow: { paddingHorizontal: 16, paddingTop: 8, paddingBottom: 4, gap: 8, alignItems: "center", }, filterPill: { flexDirection: "row", alignItems: "center", gap: 5, paddingHorizontal: 16, paddingVertical: 8, borderRadius: 20, backgroundColor: "rgba(255,255,255,0.08)", }, filterPillActive: { backgroundColor: "rgba(255,255,255,0.22)", }, filterPillText: { color: "rgba(255,255,255,0.7)", fontSize: 14, fontWeight: "600", }, filterPillTextActive: { color: "white", }, liveDot: { width: 7, height: 7, borderRadius: 4, backgroundColor: "#ff3b30", }, serviceChip: { width: 44, height: 44, borderRadius: 22, backgroundColor: "rgba(255,255,255,0.08)", alignItems: "center", justifyContent: "center", overflow: "hidden", }, serviceChipActive: { borderWidth: 2, borderColor: Colors.primary, }, serviceIcon: { width: 40, height: 40, borderRadius: 20, resizeMode: "contain", }, /* Card list */ cardList: { paddingHorizontal: 16, paddingBottom: 30, }, });