diff --git a/native/chat/settings/thread-settings-avatar.react.js b/native/chat/settings/thread-settings-avatar.react.js --- a/native/chat/settings/thread-settings-avatar.react.js +++ b/native/chat/settings/thread-settings-avatar.react.js @@ -37,6 +37,7 @@ diff --git a/native/components/edit-avatar.react.js b/native/components/edit-avatar.react.js --- a/native/components/edit-avatar.react.js +++ b/native/components/edit-avatar.react.js @@ -2,26 +2,63 @@ import { useActionSheet } from '@expo/react-native-action-sheet'; import * as React from 'react'; -import { View, TouchableOpacity, Platform } from 'react-native'; +import { + View, + TouchableOpacity, + ActivityIndicator, + Platform, +} from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { updateUserAvatarActionTypes } from 'lib/actions/user-actions.js'; +import { useENSAvatar } from 'lib/hooks/ens-cache.js'; +import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; +import { getEthAddressForUserInfo } from 'lib/utils/ens-helpers.js'; + import CommIcon from '../components/comm-icon.react.js'; import SWMansionIcon from '../components/swmansion-icon.react.js'; +import { useSelector } from '../redux/redux-utils.js'; import { useColors, useStyles } from '../themes/colors.js'; +import { useSaveUserAvatar } from '../utils/avatar-utils.js'; + +const userAvatarLoadingStatusSelector = createLoadingStatusSelector( + updateUserAvatarActionTypes, +); type Props = { +children: React.Node, + +childAvatarType: 'user' | 'thread', +onPressEmojiAvatarFlow: () => mixed, +disabled?: boolean, }; function EditAvatar(props: Props): React.Node { - const { onPressEmojiAvatarFlow, children, disabled } = props; + const { children, childAvatarType, onPressEmojiAvatarFlow, disabled } = props; const { showActionSheetWithOptions } = useActionSheet(); const colors = useColors(); const styles = useStyles(unboundStyles); + const currentUserInfo = useSelector(state => state.currentUserInfo); + + const ethAddress = React.useMemo( + () => getEthAddressForUserInfo(currentUserInfo), + [currentUserInfo], + ); + const ensAvatarURI = useENSAvatar(ethAddress); + + const saveUserAvatar = useSaveUserAvatar(); + const saveUserAvatarCallLoading = useSelector( + state => userAvatarLoadingStatusSelector(state) === 'loading', + ); + + const onPressUseENSAvatar = React.useCallback(() => { + const newAvatarRequest = { + type: 'ens', + }; + saveUserAvatar(newAvatarRequest); + }, [saveUserAvatar]); + const editAvatarOptions = React.useMemo(() => { const options = [ { @@ -38,6 +75,21 @@ }, ]; + if (ensAvatarURI && childAvatarType === 'user') { + options.push({ + id: 'ens', + text: 'Use ENS Avatar', + onPress: onPressUseENSAvatar, + icon: ( + + ), + }); + } + if (Platform.OS === 'ios') { options.push({ id: 'cancel', @@ -46,7 +98,13 @@ }); } return options; - }, [onPressEmojiAvatarFlow, styles.bottomSheetIcon]); + }, [ + childAvatarType, + ensAvatarURI, + onPressEmojiAvatarFlow, + onPressUseENSAvatar, + styles.bottomSheetIcon, + ]); const insets = useSafeAreaInsets(); @@ -89,7 +147,7 @@ }, [editAvatarOptions, insets.bottom, showActionSheetWithOptions]); const editBadge = React.useMemo(() => { - if (disabled) { + if (disabled || saveUserAvatarCallLoading) { return null; } @@ -106,13 +164,30 @@ }, [ colors.floatingButtonLabel, disabled, + saveUserAvatarCallLoading, styles.editAvatarIcon, styles.editAvatarIconContainer, ]); + const loadingContainer = React.useMemo(() => { + if (!saveUserAvatarCallLoading) { + return null; + } + + return ( + + + + ); + }, [saveUserAvatarCallLoading, styles.loadingContainer]); + return ( - + {children} + {loadingContainer} {editBadge} ); @@ -137,6 +212,15 @@ bottomSheetIcon: { color: '#000000', }, + loadingContainer: { + position: 'absolute', + backgroundColor: '#000000', + width: 112, + height: 112, + borderRadius: 56, + opacity: 0.6, + justifyContent: 'center', + }, }; export default EditAvatar; diff --git a/native/profile/profile-screen.react.js b/native/profile/profile-screen.react.js --- a/native/profile/profile-screen.react.js +++ b/native/profile/profile-screen.react.js @@ -131,7 +131,10 @@ - +