Skip to content

Commit

Permalink
feat: Added context menus for Conversation List V3 (#1255)
Browse files Browse the repository at this point in the history
Added context menu store
Added handling for context menus with pinned conversations
Fixed dark mode messages
Fixed timestamps
Fixed Unread
  • Loading branch information
alexrisch authored Nov 26, 2024
1 parent cac75a9 commit b46a58a
Show file tree
Hide file tree
Showing 25 changed files with 693 additions and 423 deletions.
19 changes: 10 additions & 9 deletions components/Conversation/V3Conversation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCurrentAccount } from "@data/store/accountsStore";
import { useConversationMessages } from "@queries/useConversationMessages";
import { ConversationTopic, ConversationVersion } from "@xmtp/react-native-sdk";
import { memo, useCallback, useEffect } from "react";
import { FlatListProps, Platform } from "react-native";
import { FlatListProps, ListRenderItem, Platform } from "react-native";
// import { DmChatPlaceholder } from "@components/Chat/ChatPlaceholder/ChatPlaceholder";
import { Screen } from "@components/Screen/ScreenComp/Screen";
import { Button } from "@design-system/Button/Button";
Expand Down Expand Up @@ -33,7 +33,6 @@ import {
initializeCurrentConversation,
useConversationCurrentTopic,
} from "../../features/conversation/conversation-service";
import { getDraftMessage } from "../../features/conversations/utils/textDrafts";
import { GroupConversationTitle } from "../../features/conversations/components/GroupConversationTitle";
import { DmConversationTitle } from "../../features/conversations/components/DmConversationTitle";
import { NewConversationTitle } from "../../features/conversations/components/NewConversationTitle";
Expand All @@ -52,7 +51,7 @@ export const V3Conversation = ({
textPrefill,
}: V3ConversationProps) => {
// TODO: Handle when topic is not defined
const messageToPrefill = textPrefill ?? getDraftMessage(topic) ?? "";
const messageToPrefill = textPrefill ?? "";
initializeCurrentConversation({
topic,
peerAddress,
Expand Down Expand Up @@ -166,7 +165,11 @@ const GroupContent = memo(function GroupContent() {
);
});

const MessagesList = memo(function MessagesList(
const renderItem: ListRenderItem<string> = ({ item, index }) => {
return <Message messageId={item} index={index} />;
};

export const MessagesList = memo(function MessagesList(
props: Omit<AnimatedProps<FlatListProps<string>>, "renderItem">
) {
const { theme } = useAppTheme();
Expand All @@ -177,9 +180,7 @@ const MessagesList = memo(function MessagesList(
// @ts-ignore It says error but it works
// layout={theme.animation.springLayoutTransition}
itemLayoutAnimation={theme.animation.reanimatedSpringLayoutTransition}
renderItem={({ item, index }) => (
<Message messageId={item} index={index} />
)}
renderItem={renderItem}
keyboardDismissMode="interactive"
automaticallyAdjustContentInsets={false}
contentInsetAdjustmentBehavior="never"
Expand Down Expand Up @@ -218,8 +219,8 @@ const Message = memo(function Message(props: {
>
<V3Message
messageId={messageId}
previousMessageId={messages.ids[index + 1]}
nextMessageId={messages.ids[index - 1]}
previousMessageId={messages?.ids[index + 1]}
nextMessageId={messages?.ids[index - 1]}
/>
</AnimatedVStack>
);
Expand Down
43 changes: 21 additions & 22 deletions components/ConversationContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import {
resetConversationListContextMenuStore,
useConversationListContextMenuConversationTopic,
useConversationListContextMenuIsVisible,
useConversationListContextMenuItems,
} from "@/features/conversation-list/ConversationListContextMenu.store";
import { ConversationReadOnly } from "@/screens/ConversationReadOnly";
import { AnimatedBlurView } from "@components/AnimatedBlurView";
import TableView, { TableViewItemType } from "@components/TableView/TableView";
import TableView from "@components/TableView/TableView";
import {
BACKDROP_DARK_BACKGROUND_COLOR,
BACKDROP_LIGHT_BACKGROUND_COLOR,
contextMenuStyleGuide,
} from "@design-system/ContextMenu/ContextMenu.constants";
import { Text } from "@design-system/Text";
import { backgroundColor } from "@styles/colors";
import { animation } from "@theme/animations";
import { useAppTheme } from "@theme/useAppTheme";
import { ConversationTopic } from "@xmtp/react-native-sdk";
import React, { FC, memo, useCallback, useEffect } from "react";
import {
Platform,
Expand All @@ -31,23 +38,14 @@ import Animated, {
withTiming,
} from "react-native-reanimated";

type ConversationContextMenuProps = {
isVisible: boolean;
onClose: (openConversationOnClose?: boolean) => void;
items: TableViewItemType[];
conversationTopic: string;
};

const ConversationContextMenuComponent: FC<ConversationContextMenuProps> = ({
isVisible,
onClose,
items,
conversationTopic,
}) => {
const ConversationContextMenuComponent: FC = () => {
const isVisible = useConversationListContextMenuIsVisible();
const conversationTopic = useConversationListContextMenuConversationTopic();
const contextMenuItems = useConversationListContextMenuItems();
const activeValue = useSharedValue(false);
const opacityValue = useSharedValue(0);
const intensityValue = useSharedValue(0);
const { height, width } = useWindowDimensions();
const { height } = useWindowDimensions();
const colorScheme = useColorScheme();
const styles = useStyles();

Expand Down Expand Up @@ -93,10 +91,10 @@ const ConversationContextMenuComponent: FC<ConversationContextMenuProps> = ({
height,
{ duration: animation.contextMenuHoldDuration },
() => {
runOnJS(onClose)();
runOnJS(resetConversationListContextMenuStore)();
}
);
}, [height, onClose, translateY]);
}, [height, translateY]);

const gesture = Gesture.Simultaneous(
Gesture.Pan()
Expand Down Expand Up @@ -139,15 +137,16 @@ const ConversationContextMenuComponent: FC<ConversationContextMenuProps> = ({
<View style={styles.previewContainer}>
<GestureDetector
gesture={Gesture.Tap().onEnd(() => {
runOnJS(onClose)(true);
runOnJS(resetConversationListContextMenuStore)();
})}
>
<Text>TODO: Add Conversation Read Only</Text>
{/* <ConversationReadOnly topic={conversationTopic} /> */}
<ConversationReadOnly
topic={conversationTopic as ConversationTopic}
/>
</GestureDetector>
</View>
<View style={styles.menuContainer}>
<TableView style={styles.table} items={items} />
<TableView style={styles.table} items={contextMenuItems} />
</View>
</Animated.View>
</View>
Expand Down
3 changes: 0 additions & 3 deletions components/ConversationListItem/ConversationListItemDumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export type ConversationListItemDumbProps = {
onWillLeftSwipe?: () => void;
onRightActionPress?: () => void;
onWillRightSwipe?: () => void;
contextMenuComponent: React.JSX.Element;
isUnread: boolean;
showError: boolean;
showImagePreview: boolean;
Expand Down Expand Up @@ -219,7 +218,6 @@ export const ConversationListItemDumb = memo(
title,
subtitle,
avatarComponent,
contextMenuComponent,
showError,
showImagePreview,
imagePreviewUrl,
Expand Down Expand Up @@ -393,7 +391,6 @@ export const ConversationListItemDumb = memo(
hitSlop={{ left: -6 }}
>
{rowItem}
{contextMenuComponent}
</Swipeable>
{/* Hide part of the border to mimic margin*/}
{displayRowSeparator && <View style={styles.rowSeparatorMargin} />}
Expand Down
86 changes: 81 additions & 5 deletions components/PinnedConversations/PinnedV3DMConversation.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { PinnedConversation } from "./PinnedConversation";
import { usePinnedConversationLongPress } from "../../features/conversation-list/usePinnedConversationLongPress";
import { useCallback, useMemo } from "react";
import { navigate } from "@utils/navigation";
import Avatar from "@components/Avatar";
Expand All @@ -8,24 +7,101 @@ import { DmWithCodecsType } from "@utils/xmtpRN/client";
import { usePreferredInboxName } from "@hooks/usePreferredInboxName";
import { usePreferredInboxAvatar } from "@hooks/usePreferredInboxAvatar";
import { useDmPeerInboxOnConversationList } from "@queries/useDmPeerInboxOnConversationList";
import { useCurrentAccount } from "@data/store/accountsStore";
import { useChatStore, useCurrentAccount } from "@data/store/accountsStore";
import { useSelect } from "@/data/store/storeHelpers";
import {
resetConversationListContextMenuStore,
setConversationListContextMenuConversationData,
} from "@/features/conversation-list/ConversationListContextMenu.store";
import { translate } from "@i18n";
import { useToggleReadStatus } from "@/features/conversation-list/hooks/useToggleReadStatus";
import { useConversationIsUnread } from "@/features/conversation-list/hooks/useMessageIsUnread";
import { useHandleDeleteDm } from "@/features/conversation-list/hooks/useHandleDeleteDm";

type PinnedV3DMConversationProps = {
conversation: DmWithCodecsType;
};

const closeContextMenu = () => {
resetConversationListContextMenuStore();
};

export const PinnedV3DMConversation = ({
conversation,
}: PinnedV3DMConversationProps) => {
const currentAccount = useCurrentAccount();
const currentAccount = useCurrentAccount()!;

const topic = conversation.topic;

const { data: peerInboxId } = useDmPeerInboxOnConversationList(
currentAccount!,
currentAccount,
conversation
);

const preferredName = usePreferredInboxName(peerInboxId);

const preferredAvatar = usePreferredInboxAvatar(peerInboxId);

const onLongPress = usePinnedConversationLongPress(conversation.topic);
const { setPinnedConversations } = useChatStore(
useSelect(["setPinnedConversations"])
);

const timestamp = conversation?.lastMessage?.sentNs ?? 0;

const isUnread = useConversationIsUnread({
topic,
lastMessage: conversation.lastMessage,
conversation: conversation,
timestamp,
});

const toggleReadStatus = useToggleReadStatus({
topic,
isUnread,
currentAccount,
});

const handleDelete = useHandleDeleteDm({
topic,
preferredName,
conversation,
});

const contextMenuItems = useMemo(
() => [
{
title: translate("unpin"),
action: () => {
setPinnedConversations([topic]);
closeContextMenu();
},
id: "pin",
},
{
title: isUnread
? translate("mark_as_read")
: translate("mark_as_unread"),
action: () => {
toggleReadStatus();
closeContextMenu();
},
id: "markAsUnread",
},
{
title: translate("delete"),
action: () => {
handleDelete();
closeContextMenu();
},
id: "delete",
},
],
[isUnread, setPinnedConversations, topic, toggleReadStatus, handleDelete]
);

const onLongPress = useCallback(() => {
setConversationListContextMenuConversationData(topic, contextMenuItems);
}, [contextMenuItems, topic]);

const onPress = useCallback(() => {
navigate("Conversation", { topic: conversation.topic });
Expand Down
Loading

0 comments on commit b46a58a

Please sign in to comment.