import React, { useEffect, useRef } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Image, Animated, Modal, StatusBar, Dimensions, Platform, } from 'react-native'; import { MaterialCommunityIcons } from '@expo/vector-icons'; import { callStore } from '../../stores/call'; import { blurActiveElement } from '../../infrastructure/platform'; const { height: SCREEN_HEIGHT } = Dimensions.get('window'); const IncomingCallModal: React.FC = () => { const incomingCall = callStore((s) => s.incomingCall); const acceptCall = callStore((s) => s.acceptCall); const rejectCall = callStore((s) => s.rejectCall); const pulseAnim = useRef(new Animated.Value(1)).current; const rippleAnim = useRef(new Animated.Value(0)).current; useEffect(() => { if (incomingCall) { blurActiveElement(); const pulse = Animated.loop( Animated.sequence([ Animated.timing(pulseAnim, { toValue: 1.06, duration: 1000, useNativeDriver: true, }), Animated.timing(pulseAnim, { toValue: 1, duration: 1000, useNativeDriver: true, }), ]) ); const ripple = Animated.loop( Animated.sequence([ Animated.timing(rippleAnim, { toValue: 1, duration: 2000, useNativeDriver: true, }), Animated.timing(rippleAnim, { toValue: 0, duration: 0, useNativeDriver: true, }), ]) ); Animated.parallel([pulse, ripple]).start(); return () => { pulse.stop(); ripple.stop(); }; } }, [incomingCall, pulseAnim, rippleAnim]); const handleAccept = () => { acceptCall(); }; const handleReject = () => { rejectCall(); }; if (!incomingCall) return null; return ( {/* Avatar with ripple effect - positioned in upper area */} {/* Ripple rings */} {[0, 1, 2].map((i) => ( ))} {incomingCall.callerAvatar ? ( ) : ( {incomingCall.callerName?.charAt(0).toUpperCase() || '?'} )} {/* Caller info */} {incomingCall.callerName || '未知用户'} {incomingCall.callType === 'video' ? '视频通话' : '语音通话'} {/* Bottom controls */} {/* Decline */} 拒绝 {/* Accept */} 接听 ); }; const AVATAR_SIZE = 100; const ACTION_CIRCLE_SIZE = 60; const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: '#0D0D0D', }, avatarSection: { position: 'absolute', top: '18%', left: 0, right: 0, height: AVATAR_SIZE + 60, justifyContent: 'center', alignItems: 'center', }, rippleRing: { position: 'absolute', width: AVATAR_SIZE + 16, height: AVATAR_SIZE + 16, borderRadius: (AVATAR_SIZE + 16) / 2, borderWidth: 2, borderColor: '#4CD964', }, avatarContainer: { width: AVATAR_SIZE + 8, height: AVATAR_SIZE + 8, borderRadius: (AVATAR_SIZE + 8) / 2, backgroundColor: '#4CD964', justifyContent: 'center', alignItems: 'center', }, avatar: { width: AVATAR_SIZE, height: AVATAR_SIZE, borderRadius: AVATAR_SIZE / 2, backgroundColor: '#3A3A5C', }, avatarPlaceholder: { justifyContent: 'center', alignItems: 'center', }, avatarText: { fontSize: 36, color: '#fff', fontWeight: '600', }, infoSection: { position: 'absolute', top: '42%', left: 0, right: 0, alignItems: 'center', paddingHorizontal: 40, }, callerName: { fontSize: 24, fontWeight: '600', color: '#FFFFFF', marginBottom: 6, textAlign: 'center', maxWidth: 280, }, callType: { fontSize: 14, color: 'rgba(255, 255, 255, 0.5)', letterSpacing: 0.3, }, controls: { position: 'absolute', bottom: '12%', left: 0, right: 0, flexDirection: 'row', justifyContent: 'center', gap: 60, }, actionButton: { alignItems: 'center', width: 80, }, declineCircle: { width: ACTION_CIRCLE_SIZE, height: ACTION_CIRCLE_SIZE, borderRadius: ACTION_CIRCLE_SIZE / 2, backgroundColor: '#E54D42', justifyContent: 'center', alignItems: 'center', }, acceptCircle: { width: ACTION_CIRCLE_SIZE, height: ACTION_CIRCLE_SIZE, borderRadius: ACTION_CIRCLE_SIZE / 2, backgroundColor: '#4CD964', justifyContent: 'center', alignItems: 'center', }, actionLabel: { fontSize: 12, color: 'rgba(255, 255, 255, 0.6)', marginTop: 10, }, }); export default IncomingCallModal;