192 lines
5.7 KiB
TypeScript
192 lines
5.7 KiB
TypeScript
import React from 'react';
|
||
import { useTranslation } from 'react-i18next';
|
||
import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||
import Modal from 'react-native-modal';
|
||
import Cascader, { CascaderItem } from '../cascader';
|
||
|
||
interface LocationModalProps {
|
||
modalVisible: boolean;
|
||
setModalVisible: (visible: boolean) => void;
|
||
podiumPosition: { x: number, y: number, width: number, height: number };
|
||
handleChange: (selectedItems: CascaderItem[]) => void;
|
||
data: CascaderItem[];
|
||
}
|
||
|
||
const LocationModal = React.memo((props: LocationModalProps) => {
|
||
const { modalVisible, setModalVisible, podiumPosition, handleChange, data } = props;
|
||
const { t } = useTranslation();
|
||
|
||
return (
|
||
<Modal
|
||
isVisible={modalVisible}
|
||
onBackdropPress={() => setModalVisible(false)}
|
||
swipeDirection={['right']} // 改为数组形式
|
||
propagateSwipe={true}
|
||
animationIn="slideInRight"
|
||
animationOut="slideOutRight"
|
||
backdropOpacity={0.5}
|
||
onSwipeComplete={() => setModalVisible(false)}
|
||
onModalHide={() => {
|
||
// 确保动画完全结束后再更新状态
|
||
}}
|
||
useNativeDriver={true} // 启用原生驱动
|
||
hideModalContentWhileAnimating={true} // 动画时隐藏内容
|
||
style={{
|
||
margin: 0,
|
||
justifyContent: 'flex-start',
|
||
marginTop: podiumPosition.height + podiumPosition.y,
|
||
}}
|
||
>
|
||
<View style={styles.modalView}>
|
||
<View style={styles.modalHeader}>
|
||
<Text style={{ opacity: 0 }}>Settings</Text>
|
||
<Text style={styles.modalTitle}>{t('generalSetting.location', { ns: 'personal' })}</Text>
|
||
<TouchableOpacity onPress={() => setModalVisible(false)}>
|
||
<Text style={styles.closeButton}>×</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
<ScrollView style={styles.modalContent} showsVerticalScrollIndicator={false}>
|
||
<Cascader
|
||
data={data}
|
||
onChange={handleChange}
|
||
/>
|
||
</ScrollView>
|
||
<TouchableOpacity
|
||
style={styles.confirmButton}
|
||
onPress={() => {
|
||
setModalVisible(false)
|
||
}}
|
||
activeOpacity={0.8}
|
||
>
|
||
<Text className="text-[#fff] font-bold text-lg">
|
||
{t('generalSetting.confirm', { ns: 'personal' })}
|
||
</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</Modal>
|
||
);
|
||
}, areEqual);
|
||
|
||
function areEqual(prevProps: LocationModalProps, nextProps: LocationModalProps) {
|
||
// 只有当这些 props 变化时才重新渲染
|
||
return (
|
||
prevProps.modalVisible === nextProps.modalVisible &&
|
||
prevProps.podiumPosition.x === nextProps.podiumPosition.x &&
|
||
prevProps.podiumPosition.y === nextProps.podiumPosition.y &&
|
||
prevProps.podiumPosition.width === nextProps.podiumPosition.width &&
|
||
prevProps.podiumPosition.height === nextProps.podiumPosition.height
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
modalView: {
|
||
width: '100%',
|
||
height: '60%',
|
||
backgroundColor: 'white',
|
||
borderRadius: 24,
|
||
paddingVertical: 16,
|
||
},
|
||
modalHeader: {
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
marginBottom: 20,
|
||
borderBottomWidth: 1,
|
||
borderBottomColor: '#E5E5E5',
|
||
},
|
||
modalTitle: {
|
||
fontSize: 20,
|
||
fontWeight: 'bold',
|
||
color: '#4C320C',
|
||
},
|
||
closeButton: {
|
||
fontSize: 28,
|
||
color: '#4C320C',
|
||
padding: 10,
|
||
},
|
||
modalContent: {
|
||
flex: 1,
|
||
paddingHorizontal: 16,
|
||
},
|
||
modalText: {
|
||
fontSize: 16,
|
||
color: '#4C320C',
|
||
},
|
||
premium: {
|
||
backgroundColor: "#FAF9F6",
|
||
padding: 16,
|
||
borderRadius: 24,
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
},
|
||
content: {
|
||
flex: 1,
|
||
flexDirection: 'column',
|
||
gap: 4,
|
||
backgroundColor: '#FAF9F6',
|
||
borderRadius: 24,
|
||
paddingVertical: 8
|
||
},
|
||
item: {
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 8,
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
},
|
||
itemText: {
|
||
fontSize: 14,
|
||
fontWeight: '600',
|
||
color: '#4C320C',
|
||
},
|
||
upgradeButton: {
|
||
backgroundColor: '#E2793F',
|
||
borderRadius: 20,
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 8,
|
||
},
|
||
upgradeButtonText: {
|
||
color: '#fff',
|
||
fontSize: 14,
|
||
fontWeight: "600"
|
||
},
|
||
switchContainer: {
|
||
width: 50,
|
||
height: 30,
|
||
borderRadius: 15,
|
||
justifyContent: 'center',
|
||
paddingHorizontal: 2,
|
||
},
|
||
switchOn: {
|
||
backgroundColor: '#E2793F',
|
||
alignItems: 'flex-end',
|
||
},
|
||
switchOff: {
|
||
backgroundColor: '#E5E5E5',
|
||
alignItems: 'flex-start',
|
||
},
|
||
switchCircle: {
|
||
width: 26,
|
||
height: 26,
|
||
borderRadius: 13,
|
||
},
|
||
switchCircleOn: {
|
||
backgroundColor: 'white',
|
||
},
|
||
switchCircleOff: {
|
||
backgroundColor: '#A5A5A5',
|
||
},
|
||
confirmButton: {
|
||
backgroundColor: '#E2793F',
|
||
borderRadius: 20,
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 8,
|
||
marginHorizontal: 16,
|
||
display: 'flex',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
});
|
||
|
||
export default LocationModal; |