Skip to content

Commit

Permalink
[lib] Move selectFromGalleryAndUpdateUserAvatar from provider to `a…
Browse files Browse the repository at this point in the history
…vatar-hooks`

Summary:
This diff involved moving `selectFromGalleryAndUpdateUserAvatar` from `Edit*AvatarProvider` to `avatar-hooks.react.js`... which makes a lot more sense.

1. As discussed D8316, this allows us to better decouple the avatar providers and hooks. The providers are an entity(user/thread)-specific, but platform-agnostic interface b/w client and `keyserver`, whereas avatar hooks are platform-specific implementations. The coupling between the providers and hooks made things difficult to work w/ when dealing with implementing image avatars on `web`.
2. Previously we had hooks which were "functions" of provider state which itself was a "function" of hooks. This diff starts to enforce the idea that hooks are "downstream" of providers which makes things easier to reason about.
3. `selectFromGallery` functionality is specific to `native` where we launch the image gallery programmatically and process the media selection. On `web`, we "virtually" click on an `<input>` to launch file selection, and then handle selected media from `onChange` callback... so things aren't as "sequential."
4. We're one step closer to merging `WebEditUserAvatarProvider` and `NativeEditUserAvatarProvider`.

---

Depends on D8316

Test Plan: Still able to select and set image avatar from `native`.

Reviewers: ashoat, ginsu, rohan

Reviewed By: ginsu

Subscribers: tomek

Differential Revision: https://phab.comm.dev/D8318
  • Loading branch information
atulsmadhugiri committed Jun 27, 2023
1 parent 6746bd0 commit b309c50
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 33 deletions.
24 changes: 2 additions & 22 deletions lib/components/base-edit-user-avatar-provider.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ import type {
UpdateUserAvatarRequest,
} from '../types/avatar-types.js';
import type { LoadingStatus } from '../types/loading-types.js';
import type {
MediaLibrarySelection,
NativeMediaSelection,
} from '../types/media-types.js';
import type { NativeMediaSelection } from '../types/media-types.js';
import {
useDispatchActionPromise,
useServerCall,
Expand All @@ -35,7 +32,6 @@ const registrationModeOff = { registrationMode: 'off' };

export type EditUserAvatarContextType = {
+userAvatarSaveInProgress: boolean,
+selectFromGalleryAndUpdateUserAvatar: () => Promise<void>,
+updateImageUserAvatar: (selection: NativeMediaSelection) => Promise<void>,
+setUserAvatar: (avatarRequest: UpdateUserAvatarRequest) => Promise<void>,
+setRegistrationMode: (registrationMode: RegistrationMode) => void,
Expand All @@ -51,19 +47,13 @@ const updateUserAvatarLoadingStatusSelector = createLoadingStatusSelector(

type Props = {
+displayFailureAlert?: () => mixed,
+selectFromGallery: () => Promise<?MediaLibrarySelection>,
+useUploadSelectedMedia: (
setProcessingOrUploadInProgress?: (inProgress: boolean) => mixed,
) => (selection: NativeMediaSelection) => Promise<?ImageAvatarDBContent>,
+children: React.Node,
};
function BaseEditUserAvatarProvider(props: Props): React.Node {
const {
displayFailureAlert,
selectFromGallery,
useUploadSelectedMedia,
children,
} = props;
const { displayFailureAlert, useUploadSelectedMedia, children } = props;

const registrationModeRef =
React.useRef<RegistrationMode>(registrationModeOff);
Expand Down Expand Up @@ -121,14 +111,6 @@ function BaseEditUserAvatarProvider(props: Props): React.Node {
],
);

const selectFromGalleryAndUpdateUserAvatar = React.useCallback(async () => {
const selection = await selectFromGallery();
if (!selection) {
return;
}
await updateImageUserAvatar(selection);
}, [selectFromGallery, updateImageUserAvatar]);

const setUserAvatar = React.useCallback(
async (request: UpdateUserAvatarRequest) => {
const regMode = registrationModeRef.current;
Expand Down Expand Up @@ -165,15 +147,13 @@ function BaseEditUserAvatarProvider(props: Props): React.Node {
const context = React.useMemo(
() => ({
userAvatarSaveInProgress,
selectFromGalleryAndUpdateUserAvatar,
updateImageUserAvatar,
setUserAvatar,
setRegistrationMode,
getRegistrationModeEnabled,
}),
[
userAvatarSaveInProgress,
selectFromGalleryAndUpdateUserAvatar,
updateImageUserAvatar,
setUserAvatar,
setRegistrationMode,
Expand Down
20 changes: 20 additions & 0 deletions native/avatars/avatar-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import { useActionSheet } from '@expo/react-native-action-sheet';
import * as ImagePicker from 'expo-image-picker';
import invariant from 'invariant';
import * as React from 'react';
import { Platform } from 'react-native';
import Alert from 'react-native/Libraries/Alert/Alert.js';
import filesystem from 'react-native-fs';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import { uploadMultimedia } from 'lib/actions/upload-actions.js';
import { EditUserAvatarContext } from 'lib/components/base-edit-user-avatar-provider.react.js';
import {
extensionFromFilename,
filenameFromPathOrURI,
Expand Down Expand Up @@ -181,6 +183,23 @@ function useUploadSelectedMedia(
);
}

function useSelectFromGalleryAndUpdateUserAvatar(): () => Promise<void> {
const editUserAvatarContext = React.useContext(EditUserAvatarContext);
invariant(editUserAvatarContext, 'updateImageUserAvatar must be defined');
const { updateImageUserAvatar } = editUserAvatarContext;

const selectFromGalleryAndUpdateUserAvatar =
React.useCallback(async (): Promise<void> => {
const selection = await selectFromGallery();
if (!selection) {
return;
}
await updateImageUserAvatar(selection);
}, [updateImageUserAvatar]);

return selectFromGalleryAndUpdateUserAvatar;
}

type ShowAvatarActionSheetOptions = {
+id: 'emoji' | 'image' | 'camera' | 'ens' | 'cancel' | 'remove',
+onPress?: () => mixed,
Expand Down Expand Up @@ -310,4 +329,5 @@ export {
useUploadProcessedMedia,
useProcessSelectedMedia,
useShowAvatarActionSheet,
useSelectFromGalleryAndUpdateUserAvatar,
};
9 changes: 7 additions & 2 deletions native/avatars/edit-user-avatar.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ 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 {
useSelectFromGalleryAndUpdateUserAvatar,
useShowAvatarActionSheet,
} from './avatar-hooks.js';
import EditAvatarBadge from './edit-avatar-badge.react.js';
import UserAvatar from './user-avatar.react.js';
import {
Expand All @@ -34,11 +37,13 @@ function EditUserAvatar(props: Props): React.Node {
invariant(editUserAvatarContext, 'editUserAvatarContext should be set');
const {
userAvatarSaveInProgress,
selectFromGalleryAndUpdateUserAvatar,
setUserAvatar,
getRegistrationModeEnabled,
} = editUserAvatarContext;

const selectFromGalleryAndUpdateUserAvatar =
useSelectFromGalleryAndUpdateUserAvatar();

const currentUserInfo = useSelector(state => state.currentUserInfo);
const userInfoProp = props.userInfo;
const userInfo: ?GenericUserInfoWithAvatar = userInfoProp ?? currentUserInfo;
Expand Down
3 changes: 1 addition & 2 deletions native/avatars/native-edit-user-avatar-provider.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Alert } from 'react-native';

import { BaseEditUserAvatarProvider } from 'lib/components/base-edit-user-avatar-provider.react.js';

import { selectFromGallery, useUploadSelectedMedia } from './avatar-hooks.js';
import { useUploadSelectedMedia } from './avatar-hooks.js';

const displayAvatarUpdateFailureAlert = () =>
Alert.alert(
Expand All @@ -23,7 +23,6 @@ function NativeEditUserAvatarProvider(props: Props): React.Node {
return (
<BaseEditUserAvatarProvider
displayFailureAlert={displayAvatarUpdateFailureAlert}
selectFromGallery={selectFromGallery}
useUploadSelectedMedia={useUploadSelectedMedia}
>
{children}
Expand Down
8 changes: 1 addition & 7 deletions web/avatars/web-edit-user-avatar-provider.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import * as React from 'react';

import { BaseEditUserAvatarProvider } from 'lib/components/base-edit-user-avatar-provider.react.js';

// TODO: Implement `selectFromGallery(...)` for `web`.
const selectFromGallery = async () => null;

// TODO: Implement `useUploadSelectedMedia(...)` for `web`.
const useUploadSelectedMedia = () => async () => null;

Expand All @@ -16,10 +13,7 @@ type Props = {
function WebEditUserAvatarProvider(props: Props): React.Node {
const { children } = props;
return (
<BaseEditUserAvatarProvider
selectFromGallery={selectFromGallery}
useUploadSelectedMedia={useUploadSelectedMedia}
>
<BaseEditUserAvatarProvider useUploadSelectedMedia={useUploadSelectedMedia}>
{children}
</BaseEditUserAvatarProvider>
);
Expand Down

0 comments on commit b309c50

Please sign in to comment.