import { Ionicons } from '@expo/vector-icons'; import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect'; import * as Haptics from 'expo-haptics'; import React, { useEffect, useRef, useState } from 'react'; import { ActivityIndicator, Animated, Dimensions, Modal, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; const { height: screenHeight } = Dimensions.get('window'); interface MedicalDisclaimerSheetProps { visible: boolean; onClose: () => void; onConfirm: () => void; loading?: boolean; } /** * 医疗免责声明弹窗组件 * 用于在用户添加药品前显示医疗免责声明 */ export function MedicalDisclaimerSheet({ visible, onClose, onConfirm, loading = false, }: MedicalDisclaimerSheetProps) { const insets = useSafeAreaInsets(); const translateY = useRef(new Animated.Value(screenHeight)).current; const backdropOpacity = useRef(new Animated.Value(0)).current; const [modalVisible, setModalVisible] = useState(visible); useEffect(() => { if (visible) { setModalVisible(true); } }, [visible]); useEffect(() => { if (!modalVisible) { return; } if (visible) { translateY.setValue(screenHeight); backdropOpacity.setValue(0); Animated.parallel([ Animated.timing(backdropOpacity, { toValue: 1, duration: 200, useNativeDriver: true, }), Animated.spring(translateY, { toValue: 0, useNativeDriver: true, bounciness: 6, speed: 12, }), ]).start(); return; } Animated.parallel([ Animated.timing(backdropOpacity, { toValue: 0, duration: 150, useNativeDriver: true, }), Animated.timing(translateY, { toValue: screenHeight, duration: 240, useNativeDriver: true, }), ]).start(() => { translateY.setValue(screenHeight); backdropOpacity.setValue(0); setModalVisible(false); }); }, [visible, modalVisible, backdropOpacity, translateY]); const handleCancel = () => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); onClose(); }; const handleConfirm = () => { if (loading) return; Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); onConfirm(); }; if (!modalVisible) { return null; } return ( {/* 图标和标题 - 左对齐单行 */} 重要提示 {/* 免责声明内容 */} 本应用提供的任何禁食、饮食、健康或医学相关内容仅用于一般性信息参考,不构成医疗建议。 应用不提供诊断、治疗或医疗服务。 如您有任何医疗状况、正在服药、怀孕或哺乳,或计划开始禁食,请先咨询医生或持牌医疗专业人员。 如果在禁食或使用本应用过程中出现不适症状,请立即停止并寻求专业医疗帮助。 {/* 确认按钮 - 支持 Liquid Glass */} {isLiquidGlassAvailable() ? ( {loading ? ( ) : ( <> 已读并前往 )} ) : ( {loading ? ( ) : ( <> 已读并前往 )} )} ); } const styles = StyleSheet.create({ overlay: { flex: 1, justifyContent: 'flex-end', backgroundColor: 'transparent', }, backdrop: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(15, 23, 42, 0.45)', }, sheet: { backgroundColor: '#fff', borderTopLeftRadius: 28, borderTopRightRadius: 28, paddingHorizontal: 24, paddingTop: 16, shadowColor: '#000', shadowOpacity: 0.12, shadowRadius: 16, shadowOffset: { width: 0, height: -4 }, elevation: 16, gap: 20, }, handle: { width: 50, height: 4, borderRadius: 2, backgroundColor: '#E5E7EB', alignSelf: 'center', marginBottom: 8, }, header: { flexDirection: 'row', alignItems: 'center', gap: 12, }, iconContainer: { width: 40, height: 40, borderRadius: 20, backgroundColor: '#EFF6FF', alignItems: 'center', justifyContent: 'center', }, title: { fontSize: 20, fontWeight: '700', color: '#111827', }, contentContainer: { gap: 16, paddingVertical: 8, }, disclaimerItem: { flexDirection: 'row', gap: 12, alignItems: 'flex-start', }, bulletPoint: { width: 6, height: 6, borderRadius: 3, backgroundColor: '#3B82F6', marginTop: 8, }, disclaimerText: { flex: 1, fontSize: 15, lineHeight: 22, color: '#374151', }, actions: { marginTop: 8, }, confirmButton: { height: 56, borderRadius: 18, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 8, overflow: 'hidden', // 保证玻璃边界圆角效果 }, fallbackButton: { backgroundColor: '#3B82F6', shadowColor: 'rgba(59, 130, 246, 0.45)', shadowOffset: { width: 0, height: 10 }, shadowOpacity: 1, shadowRadius: 20, elevation: 6, }, confirmText: { fontSize: 16, fontWeight: '700', color: '#fff', }, });