memoize things, clean code, and replace deprecated resizeMode with contentFit (#526)
parent
1b356556c9
commit
c5222db38b
|
@ -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={[
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue