Initial commit: expo-popcore-app
This commit is contained in:
258
components/drawer/EditProfileDrawer.tsx
Normal file
258
components/drawer/EditProfileDrawer.tsx
Normal file
@@ -0,0 +1,258 @@
|
||||
import { useState, useEffect, useRef, useMemo, useCallback } from 'react'
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
Pressable,
|
||||
TextInput,
|
||||
Dimensions,
|
||||
Platform,
|
||||
Keyboard,
|
||||
ScrollView,
|
||||
} from 'react-native'
|
||||
import { Image } from 'expo-image'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import BottomSheet, { BottomSheetView, BottomSheetBackdrop, BottomSheetScrollView } from '@gorhom/bottom-sheet'
|
||||
import { CloseIcon, AvatarUploadIcon } from '@/components/icon'
|
||||
import { LinearGradient } from 'expo-linear-gradient'
|
||||
|
||||
|
||||
interface EditProfileDrawerProps {
|
||||
visible: boolean
|
||||
onClose: () => void
|
||||
initialName?: string
|
||||
initialAvatar?: any
|
||||
onSave?: (name: string) => void
|
||||
}
|
||||
|
||||
export default function EditProfileDrawer({
|
||||
visible,
|
||||
onClose,
|
||||
initialName = '乔乔乔',
|
||||
initialAvatar,
|
||||
onSave,
|
||||
}: EditProfileDrawerProps) {
|
||||
const { t } = useTranslation()
|
||||
const bottomSheetRef = useRef<BottomSheet>(null)
|
||||
const [name, setName] = useState(initialName)
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
const snapPoints = useMemo(() => [280], [])
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
bottomSheetRef.current?.expand()
|
||||
} else {
|
||||
bottomSheetRef.current?.close()
|
||||
}
|
||||
}, [visible])
|
||||
|
||||
// 当抽屉打开时,重置名字为初始值
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setName(initialName)
|
||||
}
|
||||
}, [visible, initialName])
|
||||
|
||||
const handleSheetChanges = useCallback((index: number) => {
|
||||
if (index === -1) {
|
||||
onClose()
|
||||
}
|
||||
}, [onClose])
|
||||
|
||||
const renderBackdrop = useCallback(
|
||||
(props: any) => (
|
||||
<BottomSheetBackdrop
|
||||
{...props}
|
||||
disappearsOnIndex={-1}
|
||||
appearsOnIndex={0}
|
||||
opacity={0.5}
|
||||
/>
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
const handleSave = () => {
|
||||
Keyboard.dismiss()
|
||||
onSave?.(name)
|
||||
onClose()
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
Keyboard.dismiss()
|
||||
onClose()
|
||||
}
|
||||
|
||||
return (
|
||||
<BottomSheet
|
||||
ref={bottomSheetRef}
|
||||
index={visible ? 0 : -1}
|
||||
snapPoints={snapPoints}
|
||||
onChange={handleSheetChanges}
|
||||
enablePanDownToClose
|
||||
backgroundStyle={styles.bottomSheetBackground}
|
||||
handleIndicatorStyle={styles.handleIndicator}
|
||||
backdropComponent={renderBackdrop}
|
||||
keyboardBehavior="interactive"
|
||||
keyboardBlurBehavior="restore"
|
||||
>
|
||||
<BottomSheetScrollView
|
||||
style={styles.scrollView}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
{/* 顶部关闭按钮 */}
|
||||
<Pressable
|
||||
style={styles.closeButton}
|
||||
onPress={handleClose}
|
||||
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
||||
>
|
||||
<CloseIcon />
|
||||
</Pressable>
|
||||
{/* 头像区域 */}
|
||||
<View style={styles.avatarContainer}>
|
||||
<View style={styles.avatarWrapper}>
|
||||
<Image
|
||||
source={initialAvatar || require('@/assets/images/icon.png')}
|
||||
style={styles.avatar}
|
||||
contentFit="cover"
|
||||
/>
|
||||
<Pressable style={styles.cameraButton}>
|
||||
<View style={styles.cameraIconContainer}>
|
||||
<AvatarUploadIcon />
|
||||
</View>
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 输入框 */}
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
value={name}
|
||||
onChangeText={setName}
|
||||
placeholder={t('editProfile.namePlaceholder')}
|
||||
placeholderTextColor="#666666"
|
||||
returnKeyType="done"
|
||||
onSubmitEditing={handleSave}
|
||||
blurOnSubmit={true}
|
||||
/>
|
||||
|
||||
{/* 保存按钮 */}
|
||||
<Pressable
|
||||
style={styles.saveButtonContainer}
|
||||
onPress={handleSave}
|
||||
android_ripple={{ color: 'rgba(255, 255, 255, 0.1)' }}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={['#9966FF', '#FF6699', '#FF9966']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={styles.saveButton}
|
||||
>
|
||||
<Text style={styles.saveButtonText}>{t('editProfile.save')}</Text>
|
||||
</LinearGradient>
|
||||
</Pressable>
|
||||
</View>
|
||||
</BottomSheetScrollView>
|
||||
</BottomSheet>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
bottomSheetBackground: {
|
||||
backgroundColor: '#1C1E22',
|
||||
},
|
||||
handleIndicator: {
|
||||
backgroundColor: '#666666',
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#1C1E22',
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
paddingTop: 32,
|
||||
paddingBottom: Platform.OS === 'ios' ? 25 : 17,
|
||||
paddingHorizontal: 0,
|
||||
flexGrow: 1,
|
||||
},
|
||||
closeButton: {
|
||||
position: 'absolute',
|
||||
top: Platform.OS === 'ios' ? 16 : 16,
|
||||
right: 16,
|
||||
width: 24,
|
||||
height: 24,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
zIndex: 10,
|
||||
},
|
||||
avatarContainer: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
avatarWrapper: {
|
||||
position: 'relative',
|
||||
width: 88,
|
||||
height: 88,
|
||||
},
|
||||
avatar: {
|
||||
width: 88,
|
||||
height: 88,
|
||||
borderRadius: 50,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
cameraButton: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
width: 26,
|
||||
height: 26,
|
||||
borderRadius: 16,
|
||||
backgroundColor: '#16181B',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderWidth: 2,
|
||||
borderColor: '#FFFFFF',
|
||||
},
|
||||
cameraIconContainer: {
|
||||
width: 13,
|
||||
height: 13,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
input: {
|
||||
backgroundColor: '#262A31',
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 16,
|
||||
marginVertical: 24,
|
||||
paddingVertical: 14,
|
||||
color: '#F5F5F5',
|
||||
fontWeight: '500',
|
||||
fontSize: 14,
|
||||
height: 48,
|
||||
},
|
||||
saveButtonContainer: {
|
||||
width: '100%',
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
height: 48,
|
||||
},
|
||||
saveButton: {
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 12,
|
||||
height: 48,
|
||||
},
|
||||
saveButtonText: {
|
||||
color: '#F5F5F5',
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user