diff --git a/native/account/registration/avatar-selection.react.js b/native/account/registration/avatar-selection.react.js index fc108ab8f..ac356abe9 100644 --- a/native/account/registration/avatar-selection.react.js +++ b/native/account/registration/avatar-selection.react.js @@ -1,69 +1,106 @@ // @flow import * as React from 'react'; -import { Text } from 'react-native'; +import { Text, View } from 'react-native'; import type { SIWEResult } from 'lib/types/siwe-types.js'; import RegistrationButtonContainer from './registration-button-container.react.js'; import RegistrationButton from './registration-button.react.js'; import RegistrationContainer from './registration-container.react.js'; import RegistrationContentContainer from './registration-content-container.react.js'; import type { RegistrationNavigationProp } from './registration-navigator.react.js'; import type { CoolOrNerdMode } from './registration-types.js'; +import EditUserAvatar from '../../avatars/edit-user-avatar.react.js'; import type { NavigationRoute } from '../../navigation/route-names.js'; import { useStyles } from '../../themes/colors.js'; type EthereumAccountSelections = { +accountType: 'ethereum', ...SIWEResult, }; type UsernameAccountSelections = { +accountType: 'username', +username: string, +password: string, }; export type AvatarSelectionParams = { +userSelections: { +coolOrNerdMode: CoolOrNerdMode, +keyserverUsername: string, +accountSelections: EthereumAccountSelections | UsernameAccountSelections, }, }; type Props = { +navigation: RegistrationNavigationProp<'AvatarSelection'>, +route: NavigationRoute<'AvatarSelection'>, }; -// eslint-disable-next-line no-unused-vars function AvatarSelection(props: Props): React.Node { + const { userSelections } = props.route.params; + const { accountSelections } = userSelections; + const username = + accountSelections.accountType === 'username' + ? accountSelections.username + : accountSelections.address; + + const [avatarData] = React.useState(); + const onProceed = React.useCallback(() => {}, []); + const clientAvatar = avatarData?.clientAvatar; + const userInfoOverride = React.useMemo( + () => ({ + username, + avatar: clientAvatar, + }), + [username, clientAvatar], + ); + const styles = useStyles(unboundStyles); return ( - + Pick an avatar + + + + + ); } const unboundStyles = { + scrollViewContentContainer: { + paddingHorizontal: 0, + }, header: { fontSize: 24, color: 'panelForegroundLabel', paddingBottom: 16, + paddingHorizontal: 16, + }, + stagedAvatarSection: { + marginTop: 16, + backgroundColor: 'panelForeground', + paddingVertical: 24, + alignItems: 'center', + }, + editUserAvatar: { + alignItems: 'center', + justifyContent: 'center', }, }; export default AvatarSelection; diff --git a/native/avatars/edit-user-avatar.react.js b/native/avatars/edit-user-avatar.react.js index d8277e038..bdc61aab0 100644 --- a/native/avatars/edit-user-avatar.react.js +++ b/native/avatars/edit-user-avatar.react.js @@ -1,121 +1,132 @@ // @flow import { useNavigation } from '@react-navigation/native'; import invariant from 'invariant'; import * as React from 'react'; import { ActivityIndicator, TouchableOpacity, View } from 'react-native'; import { useENSAvatar } from 'lib/hooks/ens-cache.js'; import { getETHAddressForUserInfo } from 'lib/shared/account-utils.js'; +import type { GenericUserInfoWithAvatar } from 'lib/types/avatar-types.js'; import { useShowAvatarActionSheet } from './avatar-hooks.js'; import EditAvatarBadge from './edit-avatar-badge.react.js'; import { EditUserAvatarContext } from './edit-user-avatar-provider.react.js'; import UserAvatar from './user-avatar.react.js'; import { EmojiUserAvatarCreationRouteName, UserAvatarCameraModalRouteName, } from '../navigation/route-names.js'; import { useSelector } from '../redux/redux-utils.js'; import { useStyles } from '../themes/colors.js'; -type Props = { - +userID: ?string, - +disabled?: boolean, -}; +type Props = + | { +userID: ?string, +disabled?: boolean } + | { +userInfo: ?GenericUserInfoWithAvatar, +disabled?: boolean }; function EditUserAvatar(props: Props): React.Node { - const styles = useStyles(unboundStyles); - const { userID, disabled } = props; - const editUserAvatarContext = React.useContext(EditUserAvatarContext); invariant(editUserAvatarContext, 'editUserAvatarContext should be set'); const { userAvatarSaveInProgress, selectFromGalleryAndUpdateUserAvatar, setUserAvatar, } = editUserAvatarContext; const currentUserInfo = useSelector(state => state.currentUserInfo); + const userInfoProp = props.userInfo; + const userInfo: ?GenericUserInfoWithAvatar = userInfoProp ?? currentUserInfo; + const ethAddress = React.useMemo( - () => getETHAddressForUserInfo(currentUserInfo), - [currentUserInfo], + () => getETHAddressForUserInfo(userInfo), + [userInfo], ); const ensAvatarURI = useENSAvatar(ethAddress); const { navigate } = useNavigation(); const navigateToUserEmojiAvatarCreation = React.useCallback(() => { navigate(EmojiUserAvatarCreationRouteName); }, [navigate]); const navigateToCamera = React.useCallback(() => { navigate(UserAvatarCameraModalRouteName); }, [navigate]); const setENSUserAvatar = React.useCallback(() => { setUserAvatar({ type: 'ens' }); }, [setUserAvatar]); const removeUserAvatar = React.useCallback(() => { setUserAvatar({ type: 'remove' }); }, [setUserAvatar]); + const hasCurrentAvatar = !!userInfo?.avatar; const actionSheetConfig = React.useMemo(() => { const configOptions = [ { id: 'emoji', onPress: navigateToUserEmojiAvatarCreation }, { id: 'image', onPress: selectFromGalleryAndUpdateUserAvatar }, { id: 'camera', onPress: navigateToCamera }, ]; if (ensAvatarURI) { configOptions.push({ id: 'ens', onPress: setENSUserAvatar }); } - if (currentUserInfo?.avatar) { + if (hasCurrentAvatar) { configOptions.push({ id: 'remove', onPress: removeUserAvatar }); } return configOptions; }, [ - currentUserInfo?.avatar, + hasCurrentAvatar, ensAvatarURI, navigateToCamera, navigateToUserEmojiAvatarCreation, removeUserAvatar, setENSUserAvatar, selectFromGalleryAndUpdateUserAvatar, ]); const showAvatarActionSheet = useShowAvatarActionSheet(actionSheetConfig); + const styles = useStyles(unboundStyles); + let spinner; if (userAvatarSaveInProgress) { spinner = ( ); } + const { userID } = props; + const userAvatar = userID ? ( + + ) : ( + + ); + + const { disabled } = props; return ( - + {userAvatar} {spinner} {!disabled ? : null} ); } const unboundStyles = { spinnerContainer: { position: 'absolute', alignItems: 'center', justifyContent: 'center', top: 0, bottom: 0, left: 0, right: 0, }, }; export default EditUserAvatar; diff --git a/native/avatars/user-avatar.react.js b/native/avatars/user-avatar.react.js index 4a3012388..9cbda8f52 100644 --- a/native/avatars/user-avatar.react.js +++ b/native/avatars/user-avatar.react.js @@ -1,35 +1,35 @@ // @flow import * as React from 'react'; import { getAvatarForUser, useENSResolvedAvatar, } from 'lib/shared/avatar-utils.js'; +import type { GenericUserInfoWithAvatar } from 'lib/types/avatar-types.js'; import Avatar from './avatar.react.js'; import { useSelector } from '../redux/redux-utils.js'; -type Props = { - +userID: ?string, - +size: 'micro' | 'small' | 'large' | 'profile', -}; - +type Size = 'micro' | 'small' | 'large' | 'profile'; +type Props = + | { +userID: ?string, +size: Size } + | { +userInfo: ?GenericUserInfoWithAvatar, +size: Size }; function UserAvatar(props: Props): React.Node { - const { userID, size } = props; + const { userID, userInfo: userInfoProp, size } = props; const currentUserInfo = useSelector(state => state.currentUserInfo); const userInfo = useSelector(state => - userID ? state.userStore.userInfos[userID] : null, + userID ? state.userStore.userInfos[userID] : userInfoProp, ); const avatarUserInfo = userID === currentUserInfo?.id ? currentUserInfo : userInfo; const avatarInfo = getAvatarForUser(avatarUserInfo); const resolvedUserAvatar = useENSResolvedAvatar(avatarInfo, userInfo); return ; } export default UserAvatar;