diff --git a/native/avatars/avatar-hooks.js b/native/avatars/avatar-hooks.js --- a/native/avatars/avatar-hooks.js +++ b/native/avatars/avatar-hooks.js @@ -302,7 +302,7 @@ } type ShowAvatarActionSheetOptions = { - +id: 'emoji' | 'image' | 'ens' | 'cancel' | 'remove', + +id: 'emoji' | 'image' | 'camera' | 'ens' | 'cancel' | 'remove', +onPress?: () => mixed, }; function useShowAvatarActionSheet( @@ -320,6 +320,8 @@ return 'Use Emoji'; } else if (option.id === 'image') { return 'Select image'; + } else if (option.id === 'camera') { + return 'Camera'; } else if (option.id === 'ens') { return 'Use ENS Avatar'; } else if (option.id === 'remove') { @@ -354,6 +356,14 @@ style={styles.bottomSheetIcon} /> ); + } else if (option.id === 'camera') { + return ( + + ); } else if (option.id === 'ens') { return ( Promise, + +selectFromCameraAndUpdateUserAvatar: ( + selection: PhotoCapture, + ) => Promise, +setENSUserAvatar: () => void, +removeUserAvatar: () => void, }; @@ -93,6 +99,28 @@ uploadUserAvatarSelectedMedia, ]); + const selectFromCameraAndUpdateUserAvatar = React.useCallback( + async (selection: PhotoCapture) => { + const imageAvatarUpdateRequest = await uploadUserAvatarSelectedMedia( + selection, + ); + + if (!imageAvatarUpdateRequest) { + return; + } + + dispatchActionPromise( + updateUserAvatarActionTypes, + updateImageUserAvatarPromise(imageAvatarUpdateRequest), + ); + }, + [ + dispatchActionPromise, + updateImageUserAvatarPromise, + uploadUserAvatarSelectedMedia, + ], + ); + const setENSUserAvatar = React.useCallback(() => { const ensAvatarRequest: ENSAvatarDBContent = { type: 'ens', @@ -133,11 +161,13 @@ () => ({ userAvatarSaveInProgress, selectFromGalleryAndUpdateUserAvatar, + selectFromCameraAndUpdateUserAvatar, setENSUserAvatar, removeUserAvatar, }), [ removeUserAvatar, + selectFromCameraAndUpdateUserAvatar, selectFromGalleryAndUpdateUserAvatar, setENSUserAvatar, userAvatarSaveInProgress, diff --git a/native/avatars/edit-user-avatar.react.js b/native/avatars/edit-user-avatar.react.js --- a/native/avatars/edit-user-avatar.react.js +++ b/native/avatars/edit-user-avatar.react.js @@ -41,14 +41,20 @@ const ensAvatarURI = useENSAvatar(ethAddress); const { navigate } = useNavigation(); + const navigateToUserEmojiAvatarCreation = React.useCallback(() => { navigate(EmojiUserAvatarCreationRouteName); }, [navigate]); + const navigateToCamera = React.useCallback(() => { + navigate('UserAvatarCameraModal'); + }, [navigate]); + const actionSheetConfig = React.useMemo(() => { const configOptions = [ { id: 'emoji', onPress: navigateToUserEmojiAvatarCreation }, { id: 'image', onPress: selectFromGalleryAndUpdateUserAvatar }, + { id: 'camera', onPress: navigateToCamera }, ]; if (ensAvatarURI) { @@ -60,6 +66,7 @@ return configOptions; }, [ ensAvatarURI, + navigateToCamera, navigateToUserEmojiAvatarCreation, removeUserAvatar, setENSUserAvatar, diff --git a/native/media/user-avatar-camera-modal.react.js b/native/media/user-avatar-camera-modal.react.js new file mode 100644 --- /dev/null +++ b/native/media/user-avatar-camera-modal.react.js @@ -0,0 +1,35 @@ +// @flow + +import invariant from 'invariant'; +import * as React from 'react'; + +import type { PhotoCapture } from 'lib/types/media-types.js'; + +import { EditUserAvatarContext } from '../avatars/edit-user-avatar-provider.react.js'; +import CameraModal from '../media/camera-modal.react.js'; +import type { AppNavigationProp } from '../navigation/app-navigator.react.js'; +import type { NavigationRoute } from '../navigation/route-names.js'; + +type Props = { + +navigation: AppNavigationProp<'UserAvatarCameraModal'>, + +route: NavigationRoute<'UserAvatarCameraModal'>, +}; + +function UserAvatarCameraModal(props: Props): React.Node { + const { navigation } = props; + + const editUserAvatarContext = React.useContext(EditUserAvatarContext); + invariant(editUserAvatarContext, 'editUserAvatarContext should be set'); + const { selectFromCameraAndUpdateUserAvatar } = editUserAvatarContext; + + const sendPhoto = React.useCallback( + (capture: PhotoCapture) => { + selectFromCameraAndUpdateUserAvatar(capture); + }, + [selectFromCameraAndUpdateUserAvatar], + ); + + return ; +} + +export default UserAvatarCameraModal; diff --git a/native/navigation/app-navigator.react.js b/native/navigation/app-navigator.react.js --- a/native/navigation/app-navigator.react.js +++ b/native/navigation/app-navigator.react.js @@ -14,6 +14,7 @@ } from './overlay-navigator.react.js'; import type { RootNavigationProp } from './root-navigator.react.js'; import { + UserAvatarCameraModalRouteName, ImageModalRouteName, MultimediaMessageTooltipModalRouteName, ActionResultModalRouteName, @@ -34,6 +35,7 @@ import KeyboardStateContainer from '../keyboard/keyboard-state-container.react.js'; import ChatCameraModal from '../media/chat-camera-modal.react.js'; import ImageModal from '../media/image-modal.react.js'; +import UserAvatarCameraModal from '../media/user-avatar-camera-modal.react.js'; import VideoPlaybackModal from '../media/video-playback-modal.react.js'; import RelationshipListItemTooltipModal from '../profile/relationship-list-item-tooltip-modal.react.js'; import PushHandler from '../push/push-handler.react.js'; @@ -135,6 +137,10 @@ name={ChatCameraModalRouteName} component={ChatCameraModal} /> +