import React, { useState, useRef, useCallback } from 'react'; import { Dimensions, ImageSourcePropType, TouchableOpacity, View } from 'react-native'; import Animated, { FadeIn, useAnimatedStyle, useSharedValue, withTiming, Easing as ReanimatedEasing, } from 'react-native-reanimated'; import { useTheme } from '~/utils/ThemeContext'; import { CardInfoPanel } from './FigureCardInfo'; import { FigureInfoModal } from './FigureInfoModal'; // Typ für den aktiven Tab im Modal type ActiveTabType = 'character' | 'item1' | 'item2' | 'item3' | null; interface VerticalFigureCardProps { image: ImageSourcePropType; title: string; creator: string; likes: number; expanded?: boolean; onToggleExpand?: () => void; characterInfo?: { character?: { image_prompt?: string; description?: string; lore?: string; }; items?: Array<{ name?: string; image_prompt?: string; description?: string; lore?: string; }>; }; } const { width, height } = Dimensions.get('window'); // Maximale Höhe für Desktop-Geräte (600px oder 80% der Bildschirmhöhe, je nachdem was kleiner ist) const MAX_CARD_HEIGHT = Math.min(600, height * 0.8); // Berechne die Breite basierend auf der maximalen Höhe und dem 2:3-Verhältnis // Wenn die Höhe 3 Einheiten ist, dann ist die Breite 2 Einheiten const CARD_WIDTH_BASED_ON_MAX_HEIGHT = (MAX_CARD_HEIGHT / 3) * 2; // Verwende die kleinere der beiden Breiten, um sicherzustellen, dass das Bild auf dem Bildschirm passt const CARD_WIDTH = Math.min(width, CARD_WIDTH_BASED_ON_MAX_HEIGHT); // Berechne die Höhe basierend auf dem 2:3-Format und der gewählten Breite const CARD_HEIGHT = (CARD_WIDTH / 2) * 3; export const VerticalFigureCard: React.FC = ({ image, title, creator, likes: initialLikes, expanded = false, onToggleExpand = () => {}, characterInfo, }) => { const { theme, debugBorders, isDark } = useTheme(); // Debug description props console.log('VerticalFigureCard props:', { title, characterInfo }); // State for tracking user interactions const [liked, setLiked] = useState(false); const [likes, setLikes] = useState(initialLikes); const [imageLoaded, setImageLoaded] = useState(false); const [showInfoModal, setShowInfoModal] = useState(false); const [activeTab, setActiveTab] = useState(null); // Animation values const imageOpacity = useSharedValue(0); const imageMarginLeft = useSharedValue(0); const imageMarginRight = useSharedValue(0); // Handle like action const handleLike = () => { if (liked) { setLikes(likes - 1); } else { setLikes(likes + 1); } setLiked(!liked); }; // Handle other actions const handleShare = () => { console.log('Share', title); }; // Toggle info modal mit Animationen const toggleInfoModal = () => { if (showInfoModal) { setShowInfoModal(false); setActiveTab(null); // Zurücksetzen der Margins mit Animation imageMarginLeft.value = withTiming(0, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); imageMarginRight.value = withTiming(0, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); } else { setShowInfoModal(true); setActiveTab('character'); // Standard-Tab beim Öffnen // Initiale Animation für Character-Tab imageMarginLeft.value = withTiming(-200, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); imageMarginRight.value = withTiming(0, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); } }; // Handler für Tab-Wechsel im Modal mit Animationen const handleTabChange = (tab: ActiveTabType) => { setActiveTab(tab); // Animiere die Margins basierend auf dem aktiven Tab if (tab === 'character') { // Animiere nach links für Character-Tab imageMarginLeft.value = withTiming(-200, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); imageMarginRight.value = withTiming(0, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); } else if (tab?.startsWith('item')) { // Animiere nach rechts für Item-Tabs imageMarginLeft.value = withTiming(0, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); imageMarginRight.value = withTiming(-120, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); } else { // Zurücksetzen, wenn kein Tab aktiv ist imageMarginLeft.value = withTiming(0, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); imageMarginRight.value = withTiming(0, { duration: 400, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }); } }; // Debug border styles const debugCardStyle = debugBorders ? { borderWidth: 2, borderColor: '#FF00FF' } : {}; const debugContainerStyle = debugBorders ? { borderWidth: 1, borderColor: '#00FFFF' } : {}; const debugImageStyle = debugBorders ? { borderWidth: 1, borderColor: '#FF0000' } : {}; const debugInfoStyle = debugBorders ? { borderWidth: 1, borderColor: '#00FF00' } : {}; const debugImageContentStyle = debugBorders ? { borderWidth: 2, borderColor: '#FFFF00', borderStyle: 'dashed' } : {}; // Handle image load completion const onImageLoaded = useCallback(() => { // Markiere das Bild als geladen setImageLoaded(true); // Animate opacity to 1 when image is fully loaded // Längere Dauer für ein langsameres Einblenden mit Ease-In-Effekt imageOpacity.value = withTiming(1, { duration: 1200, easing: ReanimatedEasing.in(ReanimatedEasing.ease), // Ease-In-Kurve für sanften Start }); }, []); // Create animated style for the image and container const imageAnimatedStyle = useAnimatedStyle(() => { return { opacity: imageOpacity.value, }; }); // Animated style für die Margins des Containers const containerAnimatedStyle = useAnimatedStyle(() => { return { marginLeft: imageMarginLeft.value, marginRight: imageMarginRight.value, }; }); // Verwende die gleiche Höhe wie das Bild für die gesamte Karte const cardHeight = CARD_HEIGHT; return ( {/* Card with image */} {/* Image container */} {/* Black loader card with low opacity */} {/* The actual image - only show when loaded */} {imageLoaded && ( )} {/* Invisible image for loading - not displayed */} {/* Figure card info panel under the image */} {/* Using the new FigureInfoModal component */} ); }; // Holen Sie sich die Bildschirmbreite für die Bildgröße const { width: SCREEN_WIDTH } = Dimensions.get('window');