diff --git a/native/avatars/edit-thread-avatar.react.js b/native/avatars/edit-thread-avatar.react.js
index a8c3a8dbb..d374ab2e2 100644
--- a/native/avatars/edit-thread-avatar.react.js
+++ b/native/avatars/edit-thread-avatar.react.js
@@ -1,125 +1,121 @@
// @flow
import { useNavigation } from '@react-navigation/native';
import invariant from 'invariant';
import * as React from 'react';
import { ActivityIndicator, TouchableOpacity, View } from 'react-native';
import { EditThreadAvatarContext } from 'lib/components/base-edit-thread-avatar-provider.react.js';
-import type { MinimallyEncodedThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js';
-import type {
- RawThreadInfo,
- LegacyThreadInfo,
-} from 'lib/types/thread-types.js';
+import type { RawThreadInfo, ThreadInfo } from 'lib/types/thread-types.js';
import {
useNativeSetThreadAvatar,
useSelectFromGalleryAndUpdateThreadAvatar,
useShowAvatarActionSheet,
} from './avatar-hooks.js';
import EditAvatarBadge from './edit-avatar-badge.react.js';
import ThreadAvatar from './thread-avatar.react.js';
import {
EmojiThreadAvatarCreationRouteName,
ThreadAvatarCameraModalRouteName,
} from '../navigation/route-names.js';
import { useStyles } from '../themes/colors.js';
type Props = {
- +threadInfo: RawThreadInfo | LegacyThreadInfo | MinimallyEncodedThreadInfo,
+ +threadInfo: RawThreadInfo | ThreadInfo,
+disabled?: boolean,
};
function EditThreadAvatar(props: Props): React.Node {
const styles = useStyles(unboundStyles);
const { threadInfo, disabled } = props;
const editThreadAvatarContext = React.useContext(EditThreadAvatarContext);
invariant(editThreadAvatarContext, 'editThreadAvatarContext should be set');
const { threadAvatarSaveInProgress } = editThreadAvatarContext;
const nativeSetThreadAvatar = useNativeSetThreadAvatar();
const selectFromGalleryAndUpdateThreadAvatar =
useSelectFromGalleryAndUpdateThreadAvatar();
const { navigate } = useNavigation();
const navigateToThreadEmojiAvatarCreation = React.useCallback(() => {
navigate<'EmojiThreadAvatarCreation'>({
name: EmojiThreadAvatarCreationRouteName,
params: {
threadInfo,
},
});
}, [navigate, threadInfo]);
const selectFromGallery = React.useCallback(
() => selectFromGalleryAndUpdateThreadAvatar(threadInfo.id),
[selectFromGalleryAndUpdateThreadAvatar, threadInfo.id],
);
const navigateToCamera = React.useCallback(() => {
navigate<'ThreadAvatarCameraModal'>({
name: ThreadAvatarCameraModalRouteName,
params: { threadID: threadInfo.id },
});
}, [navigate, threadInfo.id]);
const removeAvatar = React.useCallback(
() => nativeSetThreadAvatar(threadInfo.id, { type: 'remove' }),
[nativeSetThreadAvatar, threadInfo.id],
);
const actionSheetConfig = React.useMemo(() => {
const configOptions = [
{ id: 'emoji', onPress: navigateToThreadEmojiAvatarCreation },
{ id: 'image', onPress: selectFromGallery },
{ id: 'camera', onPress: navigateToCamera },
];
if (threadInfo.avatar) {
configOptions.push({ id: 'remove', onPress: removeAvatar });
}
return configOptions;
}, [
navigateToCamera,
navigateToThreadEmojiAvatarCreation,
removeAvatar,
selectFromGallery,
threadInfo.avatar,
]);
const showAvatarActionSheet = useShowAvatarActionSheet(actionSheetConfig);
let spinner;
if (threadAvatarSaveInProgress) {
spinner = (
);
}
return (
{spinner}
{!disabled ? : null}
);
}
const unboundStyles = {
spinnerContainer: {
position: 'absolute',
alignItems: 'center',
justifyContent: 'center',
top: 0,
bottom: 0,
left: 0,
right: 0,
},
};
export default EditThreadAvatar;
diff --git a/native/avatars/thread-avatar.react.js b/native/avatars/thread-avatar.react.js
index eca9e6613..bf1e1a710 100644
--- a/native/avatars/thread-avatar.react.js
+++ b/native/avatars/thread-avatar.react.js
@@ -1,62 +1,58 @@
// @flow
import * as React from 'react';
import {
useAvatarForThread,
useENSResolvedAvatar,
} from 'lib/shared/avatar-utils.js';
import { getSingleOtherUser } from 'lib/shared/thread-utils.js';
import type { AvatarSize } from 'lib/types/avatar-types.js';
-import type {
- MinimallyEncodedResolvedThreadInfo,
- MinimallyEncodedThreadInfo,
-} from 'lib/types/minimally-encoded-thread-permissions-types.js';
+import type { MinimallyEncodedResolvedThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js';
import { threadTypes } from 'lib/types/thread-types-enum.js';
import type {
- LegacyThreadInfo,
ResolvedThreadInfo,
RawThreadInfo,
+ ThreadInfo,
} from 'lib/types/thread-types.js';
import Avatar from './avatar.react.js';
import { useSelector } from '../redux/redux-utils.js';
type Props = {
+threadInfo:
| RawThreadInfo
- | LegacyThreadInfo
+ | ThreadInfo
| ResolvedThreadInfo
- | MinimallyEncodedThreadInfo
| MinimallyEncodedResolvedThreadInfo,
+size: AvatarSize,
};
function ThreadAvatar(props: Props): React.Node {
const { threadInfo, size } = props;
const avatarInfo = useAvatarForThread(threadInfo);
const viewerID = useSelector(
state => state.currentUserInfo && state.currentUserInfo.id,
);
let displayUserIDForThread;
if (threadInfo.type === threadTypes.PRIVATE) {
displayUserIDForThread = viewerID;
} else if (threadInfo.type === threadTypes.PERSONAL) {
displayUserIDForThread = getSingleOtherUser(threadInfo, viewerID);
}
const displayUser = useSelector(state =>
displayUserIDForThread
? state.userStore.userInfos[displayUserIDForThread]
: null,
);
const resolvedThreadAvatar = useENSResolvedAvatar(avatarInfo, displayUser);
return ;
}
export default ThreadAvatar;
diff --git a/native/chat/chat-context-provider.react.js b/native/chat/chat-context-provider.react.js
index 331022230..e7ebef09a 100644
--- a/native/chat/chat-context-provider.react.js
+++ b/native/chat/chat-context-provider.react.js
@@ -1,174 +1,173 @@
// @flow
import * as React from 'react';
-import type { MinimallyEncodedThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js';
-import type { LegacyThreadInfo } from 'lib/types/thread-types.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
import { ChatContext } from './chat-context.js';
import type { SidebarAnimationType } from './chat-context.js';
import ChatItemHeightMeasurer from './chat-item-height-measurer.react.js';
import type { NativeChatMessageItem } from './message-data.react.js';
import type { ChatMessageItemWithHeight } from '../types/chat-types.js';
type Props = {
+children: React.Node,
};
export type MeasurementTask = {
+messages: $ReadOnlyArray,
- +threadInfo: LegacyThreadInfo | MinimallyEncodedThreadInfo,
+ +threadInfo: ThreadInfo,
+onMessagesMeasured: (
messagesWithHeight: $ReadOnlyArray,
measuredHeights: $ReadOnlyMap,
) => mixed,
+measurerID: number,
+initialMeasuredHeights: ?$ReadOnlyMap,
};
function ChatContextProvider(props: Props): React.Node {
const [measurements, setMeasurements] = React.useState<
$ReadOnlyArray,
>([]);
const nextMeasurerID = React.useRef(0);
const measuredHeights = React.useRef<
Map>,
>(new Map());
const measureMessages = React.useCallback(
(
messages: ?$ReadOnlyArray,
- threadInfo: ?LegacyThreadInfo | ?MinimallyEncodedThreadInfo,
+ threadInfo: ?ThreadInfo,
onMessagesMeasured: ($ReadOnlyArray) => mixed,
measurerID: number,
) => {
if (!threadInfo) {
// When threadInfo is not present, we can't measure the messages: we can
// determine the height, but we can't merge the result as it requires
// threadInfo to be present.
return;
}
if (!messages) {
return;
}
const measureCallback = (
messagesWithHeight: $ReadOnlyArray,
newMeasuredHeights: $ReadOnlyMap,
) => {
measuredHeights.current.set(measurerID, newMeasuredHeights);
onMessagesMeasured(messagesWithHeight);
};
let initialMeasuredHeights = null;
const isMeasurementPresent = measuredHeights.current.has(measurerID);
if (!isMeasurementPresent) {
const sourceMeasurerID = measurements.find(
measurement => measurement.threadInfo.id === threadInfo.id,
)?.measurerID;
initialMeasuredHeights = sourceMeasurerID
? measuredHeights.current.get(sourceMeasurerID)
: null;
}
const newMeasurement = {
messages,
threadInfo,
onMessagesMeasured: measureCallback,
measurerID,
initialMeasuredHeights,
};
setMeasurements(prevMeasurements => {
const withoutCurrentMeasurement = prevMeasurements.filter(
measurement => measurement.measurerID !== measurerID,
);
return [...withoutCurrentMeasurement, newMeasurement];
});
},
[measurements],
);
const registerMeasurer = React.useCallback(() => {
const measurerID = nextMeasurerID.current++;
return {
measure: (
messages: ?$ReadOnlyArray,
- threadInfo: ?LegacyThreadInfo | ?MinimallyEncodedThreadInfo,
+ threadInfo: ?ThreadInfo,
onMessagesMeasured: (
$ReadOnlyArray,
) => mixed,
) =>
measureMessages(messages, threadInfo, onMessagesMeasured, measurerID),
unregister: () => {
setMeasurements(prevMeasurements =>
prevMeasurements.filter(
measurement => measurement.measurerID !== measurerID,
),
);
measuredHeights.current.delete(measurerID);
},
};
}, [measureMessages]);
const [
currentTransitionSidebarSourceID,
setCurrentTransitionSidebarSourceID,
] = React.useState(null);
const chatInputBarHeights = React.useRef