add state context, pressables

This commit is contained in:
Hailey
2024-02-13 11:44:53 -08:00
parent f553377e94
commit 805fffe5d8
+75 -19
View File
@@ -2,7 +2,9 @@ import React from 'react'
import { import {
ColorValue, ColorValue,
FlatList, FlatList,
FlatListProps,
ListRenderItemInfo, ListRenderItemInfo,
Pressable,
StyleSheet, StyleSheet,
View, View,
} from 'react-native' } from 'react-native'
@@ -34,10 +36,17 @@ type AvatarPlaceholder = 'thinking' | 'heart' | 'laughing'
interface Avatar { interface Avatar {
imageUri?: string imageUri?: string
backgroundColor?: ColorValue backgroundColor?: Color
placeholder?: AvatarPlaceholder placeholder?: Emoji
} }
const AvatarContext = React.createContext<Avatar>({} as Avatar)
const SetAvatarContext = React.createContext<
React.Dispatch<React.SetStateAction<Avatar>>
>({} as React.Dispatch<React.SetStateAction<Avatar>>)
const useAvatar = () => React.useContext(AvatarContext)
const useSetAvatar = () => React.useContext(SetAvatarContext)
export function StepProfile() { export function StepProfile() {
const {_} = useLingui() const {_} = useLingui()
const t = useTheme() const t = useTheme()
@@ -56,6 +65,8 @@ export function StepProfile() {
}, [track, dispatch]) }, [track, dispatch])
return ( return (
<SetAvatarContext.Provider value={setAvatar}>
<AvatarContext.Provider value={avatar}>
<View style={[a.align_start]}> <View style={[a.align_start]}>
<IconCircle icon={StreamingLive} style={[a.mb_2xl]} /> <IconCircle icon={StreamingLive} style={[a.mb_2xl]} />
@@ -67,8 +78,8 @@ export function StepProfile() {
</Description> </Description>
<View style={[a.pt_5xl, a.gap_3xl]}> <View style={[a.pt_5xl, a.gap_3xl]}>
<Items type="colors" />
<Items type="emojis" /> <Items type="emojis" />
<Items type="colors" />
</View> </View>
<OnboardingControls.Portal> <OnboardingControls.Portal>
@@ -86,16 +97,14 @@ export function StepProfile() {
</Button> </Button>
</OnboardingControls.Portal> </OnboardingControls.Portal>
</View> </View>
</AvatarContext.Provider>
</SetAvatarContext.Provider>
) )
} }
function AvatarCircle({ function AvatarCircle() {
avatar, const avatar = useAvatar()
setAvatar,
}: {
avatar: Avatar
setAvatar: React.Dispatch<React.SetStateAction<Avatar>>
}) {
if (avatar.imageUri) { if (avatar.imageUri) {
return ( return (
<View style={[styles.imageContainer]}> <View style={[styles.imageContainer]}>
@@ -127,15 +136,30 @@ const emojiItems: Record<Emoji, string> = {
} }
function ColorItem({color}: {color: Color}) { function ColorItem({color}: {color: Color}) {
const avatar = useAvatar()
const setAvatar = useSetAvatar()
const onPress = React.useCallback(() => {
setAvatar(prev => ({
...prev,
backgroundColor: color,
}))
}, [color, setAvatar])
if (color === 'image') return null if (color === 'image') return null
return ( return (
<View <Pressable
accessibilityRole="button"
style={[ style={[
styles.imageContainer, styles.imageContainer,
styles.paletteContainer, styles.paletteContainer,
{backgroundColor: color}, {
backgroundColor: color,
borderWidth: avatar.backgroundColor === color ? 3 : 1,
},
]} ]}
onPress={onPress}
/> />
) )
} }
@@ -144,10 +168,31 @@ function colorRenderItem({item}: ListRenderItemInfo<Color>) {
} }
function EmojiItem({emoji}: {emoji: Emoji}) { function EmojiItem({emoji}: {emoji: Emoji}) {
const avatar = useAvatar()
const setAvatar = useSetAvatar()
const onPress = React.useCallback(() => {
setAvatar(prev => ({
...prev,
placeholder: emoji,
}))
}, [emoji, setAvatar])
return ( return (
<View style={[styles.imageContainer, styles.paletteContainer]}> <Pressable
<Text>{emojiItems[emoji]}</Text> accessibilityRole="button"
</View> style={[
styles.imageContainer,
styles.paletteContainer,
{
alignItems: 'center',
justifyContent: 'center',
borderWidth: avatar.placeholder === emoji ? 3 : 1,
},
]}
onPress={onPress}>
<Text style={[a.text_5xl]}>{emojiItems[emoji]}</Text>
</Pressable>
) )
} }
function emojiRenderItem({item}: ListRenderItemInfo<Emoji>) { function emojiRenderItem({item}: ListRenderItemInfo<Emoji>) {
@@ -157,23 +202,25 @@ function emojiRenderItem({item}: ListRenderItemInfo<Emoji>) {
function Items({type}: {type: 'emojis' | 'colors'}) { function Items({type}: {type: 'emojis' | 'colors'}) {
if (type === 'colors') { if (type === 'colors') {
return ( return (
<View style={styles.flatListOuter}>
<FlatList<Color> <FlatList<Color>
style={{height: 100}} style={{height: 100}}
data={colors} data={colors}
renderItem={colorRenderItem} renderItem={colorRenderItem}
horizontal {...commonFlatListProps}
contentContainerStyle={styles.flatListContainer}
/> />
</View>
) )
} }
return ( return (
<View style={styles.flatListOuter}>
<FlatList<Emoji> <FlatList<Emoji>
data={emojis} data={emojis}
renderItem={emojiRenderItem} renderItem={emojiRenderItem}
horizontal {...commonFlatListProps}
contentContainerStyle={styles.flatListContainer}
/> />
</View>
) )
} }
@@ -189,8 +236,17 @@ const styles = StyleSheet.create({
width: 90, width: 90,
marginHorizontal: 5, marginHorizontal: 5,
}, },
flatListOuter: {
height: 100,
},
flatListContainer: { flatListContainer: {
paddingLeft: 40, paddingLeft: 40,
paddingRight: 40, paddingRight: 40,
}, },
}) })
const commonFlatListProps: Partial<FlatListProps<any>> = {
horizontal: true,
contentContainerStyle: styles.flatListContainer,
showsHorizontalScrollIndicator: false,
}