Skip to content

Commit

Permalink
fix reply message in composer and messages (#1252)
Browse files Browse the repository at this point in the history
  • Loading branch information
thierryskoda authored Nov 25, 2024
1 parent b4ed98d commit f6120dc
Show file tree
Hide file tree
Showing 11 changed files with 390 additions and 74 deletions.
86 changes: 59 additions & 27 deletions components/Chat/Attachment/AttachmentMessagePreview.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { translate } from "@i18n";
import { Image } from "expo-image";
import { Image, ImageProps } from "expo-image";
import prettyBytes from "pretty-bytes";
import { memo } from "react";
import { ActivityIndicator } from "react-native";

import { getCurrentAccount } from "@data/store/accountsStore";
import { Center } from "@design-system/Center";
import { Icon } from "@design-system/Icon/Icon";
import { Text } from "@design-system/Text";
import { IVStackProps, VStack } from "@design-system/VStack";
Expand All @@ -14,41 +15,77 @@ import { useAppTheme } from "@theme/useAppTheme";
import { getLocalAttachmentForMessageId } from "@utils/attachment/getLocalAttachment";
import { handleDecryptedLocalAttachment } from "@utils/attachment/handleDecryptedLocalAttachment";
import {
MAX_SMALL_ATTACHMENT_SIZE,
MAX_AUTOMATIC_DOWNLOAD_ATTACHMENT_SIZE,
fetchAndDecodeRemoteAttachment,
} from "@utils/xmtpRN/attachments";
import {
DecodedMessage,
RemoteAttachmentCodec,
RemoteAttachmentContent,
} from "@xmtp/react-native-sdk";
import { RemoteAttachmentContent } from "@xmtp/react-native-sdk";

export function useRemoteAttachment(
messageId: string,
remoteMessageContent: RemoteAttachmentContent
) {
return useQuery({
queryKey: ["attachment", messageId],
queryFn: () => fetchAttachment(messageId, remoteMessageContent),
});
}

type Props = {
message: DecodedMessage<[RemoteAttachmentCodec]>;
type IRemoteImageProps = ImageProps & {
messageId: string;
remoteMessageContent: RemoteAttachmentContent;
fitAspectRatio?: boolean;
};

export function RemoteAttachmentMessagePreview({ message }: Props) {
const { theme } = useAppTheme();
export const RemoteImage = memo(function RemoteImage(props: IRemoteImageProps) {
const { messageId, remoteMessageContent, fitAspectRatio, ...imageProps } =
props;

const {
data: attachment,
isLoading: attachmentLoading,
error: attachmentError,
} = useRemoteAttachment(messageId, remoteMessageContent);

const content = message.content();
if (attachmentLoading) {
return (
<Center>
<ActivityIndicator />
</Center>
);
}

if (typeof content === "string") {
// TODO
return null;
if (attachmentError || !attachment) {
return (
<Center>
<Text>Error loading attachment</Text>
</Center>
);
}

const aspectRatio =
fitAspectRatio && attachment.imageSize
? attachment.imageSize.width / attachment.imageSize.height
: undefined;

const { style, ...rest } = imageProps;

return (
<RemoteAttachmentPreview
messageId={message.id}
remoteMessageContent={content}
<Image
source={{ uri: attachment.mediaURL }}
style={[{ aspectRatio }, style]}
{...rest}
/>
);
}
});

const RemoteAttachmentPreview = memo(function RemoteAttachmentPreview(props: {
type IRemoteAttachmentPreviewProps = {
messageId: string;
remoteMessageContent: RemoteAttachmentContent;
}) {
};

export const RemoteAttachmentPreview = memo(function RemoteAttachmentPreview(
props: IRemoteAttachmentPreviewProps
) {
const { messageId, remoteMessageContent } = props;

const { theme } = useAppTheme();
Expand All @@ -63,8 +100,6 @@ const RemoteAttachmentPreview = memo(function RemoteAttachmentPreview(props: {
queryFn: () => fetchAttachment(messageId, remoteMessageContent),
});

console.log("attachment:", attachment);

if (!attachment && attachmentLoading) {
return (
<AttachmentPreviewContainer>
Expand Down Expand Up @@ -155,8 +190,6 @@ const RemoteAttachmentPreview = memo(function RemoteAttachmentPreview(props: {
? attachment.imageSize.width / attachment.imageSize.height
: undefined;

console.log("aspectRatio:", aspectRatio);

return (
<AttachmentPreviewContainer
style={{
Expand Down Expand Up @@ -269,10 +302,9 @@ async function fetchAttachment(
return localAttachment;
}

// Only the ones smaller than
if (
content.contentLength &&
parseFloat(content.contentLength) <= MAX_SMALL_ATTACHMENT_SIZE
parseFloat(content.contentLength) <= MAX_AUTOMATIC_DOWNLOAD_ATTACHMENT_SIZE
) {
const decryptedLocalAttachment = await fetchAndDecodeRemoteAttachment({
account: getCurrentAccount()!,
Expand Down
3 changes: 1 addition & 2 deletions components/Chat/Message/Message.utils.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
currentAccount,
getCurrentAccount,
useCurrentAccount,
} from "@data/store/accountsStore";
Expand Down Expand Up @@ -76,7 +75,7 @@ export function isStaticAttachmentMessage(
// message: DecodedMessageWithCodecsType
message: any
): message is DecodedMessage<[StaticAttachmentCodec]> {
return getMessageContentType(message.contentTypeId) === "remoteAttachment";
return getMessageContentType(message.contentTypeId) === "attachment";
}
export function isTransactionReferenceMessage(
// message: DecodedMessageWithCodecsType
Expand Down
132 changes: 118 additions & 14 deletions components/Chat/Message/V3Message.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { RemoteAttachmentMessagePreview } from "@components/Chat/Attachment/AttachmentMessagePreview";
import {
RemoteAttachmentPreview,
RemoteImage,
} from "@components/Chat/Attachment/AttachmentMessagePreview";
import {
BubbleContainer,
BubbleContentContainer,
Expand Down Expand Up @@ -27,8 +30,8 @@ import { useQuery } from "@tanstack/react-query";
import { SICK_DAMPING, SICK_STIFFNESS } from "@theme/animations";
import { useAppTheme } from "@theme/useAppTheme";
import { getLocalizedTime, getRelativeDate } from "@utils/date";
import { debugBorder } from "@utils/debug-style";
import logger from "@utils/logger";
import { sentryTrackError } from "@utils/sentry";
import { getReadableProfile } from "@utils/str";
import { flattenStyles } from "@utils/styles";
import {
Expand All @@ -48,7 +51,6 @@ import {
withSpring,
} from "react-native-reanimated";
import { useShallow } from "zustand/react/shallow";
import { useMessageText } from "../../../features/conversation-list/hooks/useMessageText";
import {
getCurrentConversationMessages,
setCurrentConversationReplyToMessageId,
Expand Down Expand Up @@ -285,7 +287,6 @@ export const V3Message = memo(
function useConversationMessageForReplyMessage(
messageId: MessageId
): DecodedMessage<[ReplyCodec]> | undefined {
const topic = useConversationCurrentTopic();
const currentAccount = useCurrentAccount()!;
const messages = getCurrentConversationMessages();

Expand Down Expand Up @@ -313,13 +314,23 @@ const RemoteAttachmentMessage = memo(function RemoteAttachmentMessage({
}: {
message: DecodedMessage<[RemoteAttachmentCodec]>;
}) {
const content = message.content();

if (typeof content === "string") {
// TODO
return null;
}

return (
<VStack>
<MessageTime />
<RepliableMessageWrapper onReply={() => {}}>
<MessageContainer fromMe={true}>
<MessageContentContainer fromMe={true}>
<RemoteAttachmentMessagePreview message={message} />
<RemoteAttachmentPreview
messageId={message.id}
remoteMessageContent={content}
/>
</MessageContentContainer>
</MessageContainer>
</RepliableMessageWrapper>
Expand Down Expand Up @@ -406,9 +417,37 @@ const ReplyMessage = memo(function ReplyMessage() {
replyMessageContent.reference as MessageId
}
/>
<MessageText inverted={fromMe}>
{replyMessageContent.content.text}
</MessageText>

{!!replyMessageContent.content.remoteAttachment && (
<VStack
style={{
marginTop: theme.spacing.xxxs,
marginBottom: theme.spacing.xxxs,
}}
>
<RemoteImage
fitAspectRatio
messageId={replyMessageContent.reference}
remoteMessageContent={
replyMessageContent.content.remoteAttachment
}
style={{
width: "100%",
borderRadius:
theme.borderRadius.message.attachment -
theme.spacing.message.replyMessage
.horizontalPadding /
2,
}}
/>
</VStack>
)}

{!!replyMessageContent.content.text && (
<MessageText inverted={fromMe}>
{replyMessageContent.content.text}
</MessageText>
)}
</VStack>
</BubbleContentContainer>
</BubbleContainer>
Expand Down Expand Up @@ -485,8 +524,6 @@ const ReplyMessageReference = memo(function ReplyMessageReference(props: {
const replyMessageReference =
useConversationMessageForReplyMessage(referenceMessageId);

const replyMessageReferenceText = useMessageText(replyMessageReference);

const readableProfile = replyMessageReference
? getReadableProfile(currentAccount, replyMessageReference.senderAddress)
: null;
Expand All @@ -499,7 +536,9 @@ const ReplyMessageReference = memo(function ReplyMessageReference(props: {
backgroundColor: fromMe
? theme.colors.bubbles.nestedReplyFromMe
: theme.colors.bubbles.nestedReply,
borderRadius: theme.spacing.sm - theme.spacing.xs / 2, // - theme.spacing.xs / 2 so the border fits the border radius of BubbleContentContainer
borderRadius:
theme.borderRadius.message.bubble -
theme.spacing.message.replyMessage.horizontalPadding / 2, // / 2 so the border fits the border radius of BubbleContentContainer
paddingHorizontal: theme.spacing.xs,
paddingVertical: theme.spacing.xxs,
}}
Expand All @@ -523,13 +562,78 @@ const ReplyMessageReference = memo(function ReplyMessageReference(props: {
{readableProfile}
</Text>
</HStack>
<Text numberOfLines={1} inverted={fromMe}>
{replyMessageReferenceText}
</Text>
{!!replyMessageReference && (
<ReplyMessageReferenceMessageContent
replyMessage={replyMessageReference}
/>
)}
</VStack>
);
});

const ReplyMessageReferenceMessageContent = memo(
function ReplyMessageReferenceMessageContent(props: {
replyMessage: DecodedMessage<[ReplyCodec]>;
}) {
const { replyMessage } = props;

const { theme } = useAppTheme();

const fromMe = useMessageContextStoreContext((s) => s.fromMe);

const content = replyMessage.content();

if (typeof content === "string") {
return (
<Text numberOfLines={1} inverted={fromMe}>
{content}
</Text>
);
}

if (content.content.remoteAttachment) {
return (
<RemoteImage
messageId={replyMessage.id}
remoteMessageContent={content.content.remoteAttachment}
style={{
height: theme.avatarSize.md,
width: theme.avatarSize.md,
marginBottom: theme.spacing.xxxs, // Because with text our lineHeight is 20 so we don't need it but with attachment we need to put that missing 4px (16+4)
borderRadius:
theme.borderRadius.message.attachment -
theme.spacing.message.replyMessage.horizontalPadding / 2 -
theme.spacing.message.replyMessage.horizontalPadding / 2,
}}
/>
);
}

const replyMessageSafeText = getReplyMessageSafeText(replyMessage);
sentryTrackError(
`Reply message reference message content is not handled with default text ${replyMessageSafeText}`
);
return (
<Text numberOfLines={1} inverted={fromMe}>
{replyMessageSafeText}
</Text>
);
}
);

function getReplyMessageSafeText(replyMessage: DecodedMessage<[ReplyCodec]>) {
try {
const content = replyMessage.content();
if (typeof content === "string") {
return content;
}
return content.content.text;
} catch (error) {
sentryTrackError(error);
return replyMessage.fallback;
}
}

const SimpleMessage = memo(function SimpleMessage({
message,
}: {
Expand Down
10 changes: 9 additions & 1 deletion features/conversation-list/hooks/useMessageText.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { isReplyMessage } from "@components/Chat/Message/Message.utils";
import {
isReplyMessage,
isStaticAttachmentMessage,
} from "@components/Chat/Message/Message.utils";
import logger from "@utils/logger";
import { DecodedMessageWithCodecsType } from "@utils/xmtpRN/client";
import { getMessageContentType } from "@utils/xmtpRN/contentTypes";
Expand All @@ -15,12 +18,17 @@ export const useMessageText = (
if (isReplyMessage(message)) {
const messageTyped = message as DecodedMessage<[ReplyCodec]>;
const content = messageTyped.content();

if (typeof content === "string") {
return content;
}
return content.content.text;
}

if (isStaticAttachmentMessage(message)) {
return "Attachment";
}

const content = message?.content();
const contentType = getMessageContentType(message.contentTypeId);
if (contentType === "conversationUpdated") {
Expand Down
Loading

0 comments on commit f6120dc

Please sign in to comment.