You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
3.4 KiB
91 lines
3.4 KiB
import { Ionicons } from '@expo/vector-icons';
|
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
import { colors } from '../../../src/theme';
|
|
import { useImagePick, useOnboarding } from '../../../src/hooks';
|
|
import { ScreenShell } from '../ui/ScreenShell';
|
|
import { Avatar } from '../ui/Avatar';
|
|
import { PrimaryButton } from '../ui/PrimaryButton';
|
|
import { AVATAR_PRESETS } from '../assets';
|
|
|
|
export function P21Avatar() {
|
|
const { data, setData, navigate, back } = useOnboarding();
|
|
const { pick, picking, error } = useImagePick();
|
|
|
|
// 头像只有一个真相 `data.avatar`:命中预设素材就是预设名,否则是拍照/相册的本地 URI
|
|
const presetName = AVATAR_PRESETS.find((name) => name === data.avatar) ?? null;
|
|
const avatarUri = data.avatar !== null && presetName === null ? data.avatar : null;
|
|
|
|
const pickFrom = async (source: 'camera' | 'library') => {
|
|
const result = await pick(source);
|
|
// 取消或未授权时保持原头像不动,不写入空值
|
|
if (result.status === 'picked') setData({ avatar: result.uri });
|
|
};
|
|
|
|
return (
|
|
<ScreenShell title="头像设置" showBack onBack={back}>
|
|
<View style={styles.previewWrap}>
|
|
<Avatar
|
|
name={presetName ?? 'defaultAvatar'}
|
|
uri={avatarUri}
|
|
size={110}
|
|
selected={data.avatar !== null}
|
|
/>
|
|
</View>
|
|
|
|
<View style={styles.actions}>
|
|
{/* picking 期间禁用:否则系统权限弹窗还没出现就能连点出第二个 */}
|
|
<Pressable
|
|
style={[styles.actionBtn, picking && styles.actionBtnDim]}
|
|
disabled={picking}
|
|
onPress={() => void pickFrom('camera')}
|
|
>
|
|
<Ionicons name="camera" size={22} color={colors.primary} />
|
|
<Text style={styles.actionText}>拍照上传</Text>
|
|
</Pressable>
|
|
<Pressable
|
|
style={[styles.actionBtn, picking && styles.actionBtnDim]}
|
|
disabled={picking}
|
|
onPress={() => void pickFrom('library')}
|
|
>
|
|
<Ionicons name="images" size={22} color={colors.primary} />
|
|
<Text style={styles.actionText}>从相册选择</Text>
|
|
</Pressable>
|
|
</View>
|
|
|
|
{error ? <Text style={styles.error}>{error}</Text> : null}
|
|
|
|
<Text style={styles.subTitle}>系统默认头像</Text>
|
|
<View style={styles.presets}>
|
|
{AVATAR_PRESETS.map((name) => (
|
|
<Avatar
|
|
key={name}
|
|
name={name}
|
|
size={56}
|
|
selected={data.avatar === name}
|
|
onPress={() => setData({ avatar: name })}
|
|
/>
|
|
))}
|
|
</View>
|
|
|
|
<View style={styles.footer}>
|
|
<PrimaryButton
|
|
label="下一步"
|
|
active={data.avatar !== null && !picking}
|
|
onPress={() => navigate('P22')}
|
|
/>
|
|
</View>
|
|
</ScreenShell>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
previewWrap: { alignItems: 'center', marginVertical: 24 },
|
|
actions: { flexDirection: 'row', justifyContent: 'center', gap: 28, marginBottom: 28 },
|
|
actionBtn: { alignItems: 'center', gap: 6 },
|
|
actionBtnDim: { opacity: 0.5 },
|
|
actionText: { fontSize: 12, color: colors.textSecondary },
|
|
error: { fontSize: 12, color: colors.dangerText, textAlign: 'center', marginBottom: 18 },
|
|
subTitle: { fontSize: 14, fontWeight: '700', color: colors.textPrimary, marginBottom: 14 },
|
|
presets: { flexDirection: 'row', justifyContent: 'space-between', gap: 10 },
|
|
footer: { marginTop: 32 },
|
|
});
|
|
|