Simplify the avatar component (#1744)

* Copypaste UserAvatar to EditableUserAvatar

* Swap usages with onSelectNewAvatar to EditableUserAvatar

* Split prop types into UserAvatarProps and EditableUserAvatarProps

* Remove dead branches from EditableUserAvatar

* Remove dead branches from UserAvatar
zio/stable
dan 2023-10-25 04:57:34 +01:00 committed by GitHub
parent c6e28f88e5
commit 32fbb9dba7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 44 deletions

View File

@ -18,7 +18,7 @@ import {ListModel} from 'state/models/content/list'
import {s, colors, gradients} from 'lib/styles' import {s, colors, gradients} from 'lib/styles'
import {enforceLen} from 'lib/strings/helpers' import {enforceLen} from 'lib/strings/helpers'
import {compressIfNeeded} from 'lib/media/manip' import {compressIfNeeded} from 'lib/media/manip'
import {UserAvatar} from '../util/UserAvatar' import {EditableUserAvatar} from '../util/UserAvatar'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useTheme} from 'lib/ThemeContext' import {useTheme} from 'lib/ThemeContext'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
@ -148,7 +148,7 @@ export function Component({
)} )}
<Text style={[styles.label, pal.text]}>List Avatar</Text> <Text style={[styles.label, pal.text]}>List Avatar</Text>
<View style={[styles.avi, {borderColor: pal.colors.background}]}> <View style={[styles.avi, {borderColor: pal.colors.background}]}>
<UserAvatar <EditableUserAvatar
type="list" type="list"
size={80} size={80}
avatar={avatar} avatar={avatar}

View File

@ -20,7 +20,7 @@ import {enforceLen} from 'lib/strings/helpers'
import {MAX_DISPLAY_NAME, MAX_DESCRIPTION} from 'lib/constants' import {MAX_DISPLAY_NAME, MAX_DESCRIPTION} from 'lib/constants'
import {compressIfNeeded} from 'lib/media/manip' import {compressIfNeeded} from 'lib/media/manip'
import {UserBanner} from '../util/UserBanner' import {UserBanner} from '../util/UserBanner'
import {UserAvatar} from '../util/UserAvatar' import {EditableUserAvatar} from '../util/UserAvatar'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useTheme} from 'lib/ThemeContext' import {useTheme} from 'lib/ThemeContext'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
@ -153,7 +153,7 @@ export function Component({
onSelectNewBanner={onSelectNewBanner} onSelectNewBanner={onSelectNewBanner}
/> />
<View style={[styles.avi, {borderColor: pal.colors.background}]}> <View style={[styles.avi, {borderColor: pal.colors.background}]}>
<UserAvatar <EditableUserAvatar
size={80} size={80}
avatar={userAvatar} avatar={userAvatar}
onSelectNewAvatar={onSelectNewAvatar} onSelectNewAvatar={onSelectNewAvatar}

View File

@ -23,14 +23,18 @@ interface BaseUserAvatarProps {
type?: Type type?: Type
size: number size: number
avatar?: string | null avatar?: string | null
moderation?: ModerationUI
} }
interface UserAvatarProps extends BaseUserAvatarProps { interface UserAvatarProps extends BaseUserAvatarProps {
onSelectNewAvatar?: (img: RNImage | null) => void moderation?: ModerationUI
}
interface EditableUserAvatarProps extends BaseUserAvatarProps {
onSelectNewAvatar: (img: RNImage | null) => void
} }
interface PreviewableUserAvatarProps extends BaseUserAvatarProps { interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
moderation?: ModerationUI
did: string did: string
handle: string handle: string
} }
@ -106,8 +110,65 @@ export function UserAvatar({
size, size,
avatar, avatar,
moderation, moderation,
onSelectNewAvatar,
}: UserAvatarProps) { }: UserAvatarProps) {
const pal = usePalette('default')
const aviStyle = useMemo(() => {
if (type === 'algo' || type === 'list') {
return {
width: size,
height: size,
borderRadius: size > 32 ? 8 : 3,
}
}
return {
width: size,
height: size,
borderRadius: Math.floor(size / 2),
}
}, [type, size])
const alert = useMemo(() => {
if (!moderation?.alert) {
return null
}
return (
<View style={[styles.alertIconContainer, pal.view]}>
<FontAwesomeIcon
icon="exclamation-circle"
style={styles.alertIcon}
size={Math.floor(size / 3)}
/>
</View>
)
}, [moderation?.alert, size, pal])
return avatar &&
!((moderation?.blur && isAndroid) /* android crashes with blur */) ? (
<View style={{width: size, height: size}}>
<HighPriorityImage
testID="userAvatarImage"
style={aviStyle}
contentFit="cover"
source={{uri: avatar}}
blurRadius={moderation?.blur ? BLUR_AMOUNT : 0}
/>
{alert}
</View>
) : (
<View style={{width: size, height: size}}>
<DefaultAvatar type={type} size={size} />
{alert}
</View>
)
}
export function EditableUserAvatar({
type = 'user',
size,
avatar,
onSelectNewAvatar,
}: EditableUserAvatarProps) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const {requestCameraAccessIfNeeded} = useCameraPermission() const {requestCameraAccessIfNeeded} = useCameraPermission()
@ -146,7 +207,7 @@ export function UserAvatar({
return return
} }
onSelectNewAvatar?.( onSelectNewAvatar(
await openCamera(store, { await openCamera(store, {
width: 1000, width: 1000,
height: 1000, height: 1000,
@ -186,7 +247,7 @@ export function UserAvatar({
path: item.path, path: item.path,
}) })
onSelectNewAvatar?.(croppedImage) onSelectNewAvatar(croppedImage)
}, },
}, },
!!avatar && { !!avatar && {
@ -203,7 +264,7 @@ export function UserAvatar({
web: 'trash', web: 'trash',
}, },
onPress: async () => { onPress: async () => {
onSelectNewAvatar?.(null) onSelectNewAvatar(null)
}, },
}, },
].filter(Boolean) as DropdownItem[], ].filter(Boolean) as DropdownItem[],
@ -216,23 +277,7 @@ export function UserAvatar({
], ],
) )
const alert = useMemo(() => { return (
if (!moderation?.alert) {
return null
}
return (
<View style={[styles.alertIconContainer, pal.view]}>
<FontAwesomeIcon
icon="exclamation-circle"
style={styles.alertIcon}
size={Math.floor(size / 3)}
/>
</View>
)
}, [moderation?.alert, size, pal])
// onSelectNewAvatar is only passed as prop on the EditProfile component
return onSelectNewAvatar ? (
<NativeDropdown <NativeDropdown
testID="changeAvatarBtn" testID="changeAvatarBtn"
items={dropdownItems} items={dropdownItems}
@ -256,23 +301,6 @@ export function UserAvatar({
/> />
</View> </View>
</NativeDropdown> </NativeDropdown>
) : avatar &&
!((moderation?.blur && isAndroid) /* android crashes with blur */) ? (
<View style={{width: size, height: size}}>
<HighPriorityImage
testID="userAvatarImage"
style={aviStyle}
contentFit="cover"
source={{uri: avatar}}
blurRadius={moderation?.blur ? BLUR_AMOUNT : 0}
/>
{alert}
</View>
) : (
<View style={{width: size, height: size}}>
<DefaultAvatar type={type} size={size} />
{alert}
</View>
) )
} }