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 @@ -12,10 +12,6 @@ changeThreadSettingsActionTypes, } from 'lib/actions/thread-actions.js'; import { uploadMultimedia } from 'lib/actions/upload-actions.js'; -import { - updateUserAvatar, - updateUserAvatarActionTypes, -} from 'lib/actions/user-actions.js'; import { extensionFromFilename, filenameFromPathOrURI, @@ -191,67 +187,6 @@ ); } -const updateUserAvatarLoadingStatusSelector = createLoadingStatusSelector( - updateUserAvatarActionTypes, -); -function useSelectFromGalleryAndUpdateUserAvatar(): [ - () => Promise, - boolean, -] { - const dispatchActionPromise = useDispatchActionPromise(); - const updateUserAvatarCall = useServerCall(updateUserAvatar); - - const [processingOrUploadInProgress, setProcessingOrUploadInProgress] = - React.useState(false); - - const updateUserAvatarLoadingStatus: LoadingStatus = useSelector( - updateUserAvatarLoadingStatusSelector, - ); - - const inProgress = React.useMemo( - () => - processingOrUploadInProgress || - updateUserAvatarLoadingStatus === 'loading', - [processingOrUploadInProgress, updateUserAvatarLoadingStatus], - ); - - const uploadSelectedMedia = useUploadSelectedMedia( - setProcessingOrUploadInProgress, - ); - - const selectFromGalleryAndUpdateUserAvatar = React.useCallback(async () => { - const selection: ?MediaLibrarySelection = await selectFromGallery(); - - const uploadedMediaID = await uploadSelectedMedia(selection); - - if (!uploadedMediaID) { - return; - } - - const imageAvatarUpdateRequest: ImageAvatarDBContent = { - type: 'image', - uploadID: uploadedMediaID, - }; - - dispatchActionPromise( - updateUserAvatarActionTypes, - (async () => { - setProcessingOrUploadInProgress(false); - try { - return await updateUserAvatarCall(imageAvatarUpdateRequest); - } catch { - Alert.alert('Avatar update failed', 'Unable to update avatar.'); - } - })(), - ); - }, [dispatchActionPromise, updateUserAvatarCall, uploadSelectedMedia]); - - return React.useMemo( - () => [selectFromGalleryAndUpdateUserAvatar, inProgress], - [selectFromGalleryAndUpdateUserAvatar, inProgress], - ); -} - const threadAvatarLoadingStatusSelector = createLoadingStatusSelector( changeThreadSettingsActionTypes, `${changeThreadSettingsActionTypes.started}:avatar`, @@ -478,10 +413,11 @@ }; export { + selectFromGallery, + useUploadSelectedMedia, useUploadProcessedMedia, useProcessSelectedMedia, useShowAvatarActionSheet, - useSelectFromGalleryAndUpdateUserAvatar, useSelectFromGalleryAndUpdateThreadAvatar, useRemoveThreadAvatar, }; diff --git a/native/avatars/edit-user-avatar-provider.react.js b/native/avatars/edit-user-avatar-provider.react.js --- a/native/avatars/edit-user-avatar-provider.react.js +++ b/native/avatars/edit-user-avatar-provider.react.js @@ -9,19 +9,23 @@ } from 'lib/actions/user-actions.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import type { + ImageAvatarDBContent, ENSAvatarDBContent, UpdateUserAvatarRemoveRequest, } from 'lib/types/avatar-types.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; +import type { MediaLibrarySelection } from 'lib/types/media-types.js'; import { useDispatchActionPromise, useServerCall, } from 'lib/utils/action-utils.js'; +import { selectFromGallery, useUploadSelectedMedia } from './avatar-hooks.js'; import { useSelector } from '../redux/redux-utils.js'; export type EditUserAvatarContextType = { +userAvatarSaveInProgress: boolean, + +selectFromGalleryAndUpdateUserAvatar: () => Promise, +setENSUserAvatar: () => void, +removeUserAvatar: () => void, }; @@ -42,14 +46,52 @@ const dispatchActionPromise = useDispatchActionPromise(); const updateUserAvatarCall = useServerCall(updateUserAvatar); + const [userAvatarMediaUploadInProgress, setUserAvatarMediaUploadInProgress] = + React.useState(false); + const updateUserAvatarLoadingStatus: LoadingStatus = useSelector( updateUserAvatarLoadingStatusSelector, ); const userAvatarSaveInProgress = React.useMemo( - () => updateUserAvatarLoadingStatus === 'loading', - [updateUserAvatarLoadingStatus], + () => + userAvatarMediaUploadInProgress || + updateUserAvatarLoadingStatus === 'loading', + [userAvatarMediaUploadInProgress, updateUserAvatarLoadingStatus], + ); + + const uploadUserAvatarSelectedMedia = useUploadSelectedMedia( + setUserAvatarMediaUploadInProgress, ); + const selectFromGalleryAndUpdateUserAvatar = React.useCallback(async () => { + const selection: ?MediaLibrarySelection = await selectFromGallery(); + const uploadedMediaID = await uploadUserAvatarSelectedMedia(selection); + + if (!uploadedMediaID) { + return; + } + + const imageAvatarUpdateRequest: ImageAvatarDBContent = { + type: 'image', + uploadID: uploadedMediaID, + }; + + dispatchActionPromise( + updateUserAvatarActionTypes, + (async () => { + setUserAvatarMediaUploadInProgress(false); + try { + return await updateUserAvatarCall(imageAvatarUpdateRequest); + } catch { + Alert.alert('Avatar update failed', 'Unable to update avatar.'); + } + })(), + ); + }, [ + dispatchActionPromise, + updateUserAvatarCall, + uploadUserAvatarSelectedMedia, + ]); const setENSUserAvatar = React.useCallback(() => { const ensAvatarRequest: ENSAvatarDBContent = { @@ -88,10 +130,16 @@ const context = React.useMemo( () => ({ userAvatarSaveInProgress, + selectFromGalleryAndUpdateUserAvatar, setENSUserAvatar, removeUserAvatar, }), - [removeUserAvatar, setENSUserAvatar, userAvatarSaveInProgress], + [ + removeUserAvatar, + selectFromGalleryAndUpdateUserAvatar, + setENSUserAvatar, + userAvatarSaveInProgress, + ], ); return ( 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 @@ -7,10 +7,7 @@ import { useENSAvatar } from 'lib/hooks/ens-cache.js'; import { getETHAddressForUserInfo } from 'lib/shared/account-utils.js'; -import { - useSelectFromGalleryAndUpdateUserAvatar, - useShowAvatarActionSheet, -} from './avatar-hooks.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'; @@ -28,8 +25,12 @@ const editUserAvatarContext = React.useContext(EditUserAvatarContext); invariant(editUserAvatarContext, 'editUserAvatarContext should be set'); - const { userAvatarSaveInProgress, setENSUserAvatar, removeUserAvatar } = - editUserAvatarContext; + const { + userAvatarSaveInProgress, + selectFromGalleryAndUpdateUserAvatar, + setENSUserAvatar, + removeUserAvatar, + } = editUserAvatarContext; const currentUserInfo = useSelector(state => state.currentUserInfo); const ethAddress = React.useMemo( @@ -38,12 +39,6 @@ ); const ensAvatarURI = useENSAvatar(ethAddress); - const [selectFromGalleryAndUpdateUserAvatar, isGalleryAvatarUpdateLoading] = - useSelectFromGalleryAndUpdateUserAvatar(); - - const isAvatarUpdateInProgress = - isGalleryAvatarUpdateLoading || userAvatarSaveInProgress; - const actionSheetConfig = React.useMemo(() => { const configOptions = [ { id: 'emoji', onPress: onPressEmojiAvatarFlow }, @@ -68,7 +63,7 @@ const showAvatarActionSheet = useShowAvatarActionSheet(actionSheetConfig); let spinner; - if (isAvatarUpdateInProgress) { + if (userAvatarSaveInProgress) { spinner = (