memoize things, clean code, and replace deprecated resizeMode with contentFit (#526)

zio/stable
Ansh 2023-04-24 16:45:02 -07:00 committed by GitHub
parent 1b356556c9
commit c5222db38b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 97 additions and 80 deletions

View File

@ -1,4 +1,4 @@
import React from 'react'
import React, {useMemo, useState, useEffect} from 'react'
import {observer} from 'mobx-react-lite'
import {
Animated,
@ -47,8 +47,8 @@ export const FeedItem = observer(function FeedItem({
item: NotificationsFeedItemModel
}) {
const pal = usePalette('default')
const [isAuthorsExpanded, setAuthorsExpanded] = React.useState<boolean>(false)
const itemHref = React.useMemo(() => {
const [isAuthorsExpanded, setAuthorsExpanded] = useState<boolean>(false)
const itemHref = useMemo(() => {
if (item.isLike || item.isRepost) {
const urip = new AtUri(item.subjectUri)
return `/profile/${urip.host}/post/${urip.rkey}`
@ -60,7 +60,7 @@ export const FeedItem = observer(function FeedItem({
}
return ''
}, [item])
const itemTitle = React.useMemo(() => {
const itemTitle = useMemo(() => {
if (item.isLike || item.isRepost) {
return 'Post'
} else if (item.isFollow) {
@ -74,6 +74,35 @@ export const FeedItem = observer(function FeedItem({
setAuthorsExpanded(!isAuthorsExpanded)
}
const authors: Author[] = useMemo(() => {
return [
{
href: `/profile/${item.author.handle}`,
handle: item.author.handle,
displayName: item.author.displayName,
avatar: item.author.avatar,
labels: item.author.labels,
},
...(item.additional?.map(
({author: {avatar, labels, handle, displayName}}) => {
return {
href: `/profile/${handle}`,
handle,
displayName,
avatar,
labels,
}
},
) || []),
]
}, [
item.additional,
item.author.avatar,
item.author.displayName,
item.author.handle,
item.author.labels,
])
if (item.additionalPost?.notFound) {
// don't render anything if the target post was deleted or unfindable
return <View />
@ -125,30 +154,9 @@ export const FeedItem = observer(function FeedItem({
icon = 'user-plus'
iconStyle = [s.blue3 as FontAwesomeIconStyle]
} else {
return <></>
return null
}
const authors: Author[] = [
{
href: `/profile/${item.author.handle}`,
handle: item.author.handle,
displayName: item.author.displayName,
avatar: item.author.avatar,
labels: item.author.labels,
},
...(item.additional?.map(
({author: {avatar, labels, handle, displayName}}) => {
return {
href: `/profile/${handle}`,
handle,
displayName,
avatar,
labels,
}
},
) || []),
]
return (
<Link
testID={`feedItem-by-${item.author.handle}`}
@ -301,13 +309,14 @@ function ExpandedAuthorsList({
const heightStyle = {
height: Animated.multiply(heightInterp, targetHeight),
}
React.useEffect(() => {
useEffect(() => {
Animated.timing(heightInterp, {
toValue: visible ? 1 : 0,
duration: 200,
useNativeDriver: false,
}).start()
}, [heightInterp, visible])
return (
<Animated.View
style={[

View File

@ -1,4 +1,4 @@
import React from 'react'
import React, {useMemo} from 'react'
import {StyleSheet, View} from 'react-native'
import Svg, {Circle, Path} from 'react-native-svg'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
@ -53,61 +53,69 @@ export function UserAvatar({
const {requestCameraAccessIfNeeded} = useCameraPermission()
const {requestPhotoAccessIfNeeded} = usePhotoLibraryPermission()
const dropdownItems = [
!isWeb && {
testID: 'changeAvatarCameraBtn',
label: 'Camera',
icon: 'camera' as IconProp,
onPress: async () => {
if (!(await requestCameraAccessIfNeeded())) {
return
}
onSelectNewAvatar?.(
await openCamera(store, {
width: 1000,
height: 1000,
cropperCircleOverlay: true,
}),
)
const dropdownItems = useMemo(
() => [
!isWeb && {
testID: 'changeAvatarCameraBtn',
label: 'Camera',
icon: 'camera' as IconProp,
onPress: async () => {
if (!(await requestCameraAccessIfNeeded())) {
return
}
onSelectNewAvatar?.(
await openCamera(store, {
width: 1000,
height: 1000,
cropperCircleOverlay: true,
}),
)
},
},
},
{
testID: 'changeAvatarLibraryBtn',
label: 'Library',
icon: 'image' as IconProp,
onPress: async () => {
if (!(await requestPhotoAccessIfNeeded())) {
return
}
const items = await openPicker(store, {
mediaType: 'photo',
multiple: false,
})
onSelectNewAvatar?.(
await openCropper(store, {
{
testID: 'changeAvatarLibraryBtn',
label: 'Library',
icon: 'image' as IconProp,
onPress: async () => {
if (!(await requestPhotoAccessIfNeeded())) {
return
}
const items = await openPicker(store, {
mediaType: 'photo',
path: items[0].path,
width: 1000,
height: 1000,
cropperCircleOverlay: true,
}),
)
},
},
{
testID: 'changeAvatarRemoveBtn',
label: 'Remove',
icon: ['far', 'trash-can'] as IconProp,
onPress: async () => {
onSelectNewAvatar?.(null)
},
},
]
multiple: false,
})
const warning = React.useMemo(() => {
onSelectNewAvatar?.(
await openCropper(store, {
mediaType: 'photo',
path: items[0].path,
width: 1000,
height: 1000,
cropperCircleOverlay: true,
}),
)
},
},
{
testID: 'changeAvatarRemoveBtn',
label: 'Remove',
icon: ['far', 'trash-can'] as IconProp,
onPress: async () => {
onSelectNewAvatar?.(null)
},
},
],
[
onSelectNewAvatar,
requestCameraAccessIfNeeded,
requestPhotoAccessIfNeeded,
store,
],
)
const warning = useMemo(() => {
if (!hasWarning) {
return <></>
return null
}
return (
<View style={[styles.warningIconContainer, pal.view]}>
@ -156,7 +164,7 @@ export function UserAvatar({
<HighPriorityImage
testID="userAvatarImage"
style={{width: size, height: size, borderRadius: Math.floor(size / 2)}}
resizeMode="stretch"
contentFit="cover"
source={{uri: avatar}}
/>
{warning}