Skip to content

Commit

Permalink
fix: Update handling for conversation list group avatars and names
Browse files Browse the repository at this point in the history
Added avatars and names in specific group conversation item
  • Loading branch information
Alex Risch authored and Alex Risch committed Jun 24, 2024
1 parent b282f06 commit 845ca42
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 104 deletions.
49 changes: 3 additions & 46 deletions components/ConversationFlashList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import {
useSettingsStore,
} from "../data/store/accountsStore";
import { useSelect } from "../data/store/storeHelpers";
import { getGroupNameQueryData } from "../queries/useGroupNameQuery";
import { getGroupPhotoQueryData } from "../queries/useGroupPhotoQuery";
import { NavigationParamList } from "../screens/Navigation/Navigation";
import { useIsSplitScreen } from "../screens/Navigation/navHelpers";
import { backgroundColor } from "../utils/colors";
Expand All @@ -21,6 +19,7 @@ import {
} from "../utils/conversation";
import { getPreferredAvatar } from "../utils/profile";
import { conversationName } from "../utils/str";
import { GroupConversationItem } from "./ConversationList/GroupConversationItem";
import ConversationListItem from "./ConversationListItem";

type Props = {
Expand Down Expand Up @@ -107,53 +106,11 @@ export default function ConversationFlashList({
? profiles[conversation.peerAddress]?.socials
: undefined;
if (conversation.isGroup) {
const groupName = getGroupNameQueryData(
userAddress,
conversation.topic
);
const groupImage = getGroupPhotoQueryData(
userAddress,
conversation.topic
);
return (
<ConversationListItem
onLongPress={() => {
setPinnedConversations([conversation]);
}}
<GroupConversationItem
conversation={conversation}
navigation={navigation}
route={route}
conversationPeerAddress={conversation.peerAddress}
conversationPeerAvatar={groupImage}
colorScheme={colorScheme}
conversationTopic={conversation.topic}
conversationTime={
lastMessagePreview?.message?.sent || conversation.createdAt
}
conversationName={
groupName ? groupName : conversationName(conversation)
}
showUnread={(() => {
if (!initialLoadDoneOnce) return false;
if (!lastMessagePreview) return false;
// Manually marked as unread
if (topicsData[conversation.topic]?.status === "unread")
return true;
// If not manually markes as unread, we only show badge if last message
// not from me
if (lastMessagePreview.message.senderAddress === userAddress)
return false;
const readUntil = topicsData[conversation.topic]?.readUntil || 0;
return readUntil < lastMessagePreview.message.sent;
})()}
lastMessagePreview={
lastMessagePreview ? lastMessagePreview.contentPreview : ""
}
lastMessageStatus={lastMessagePreview?.message?.status}
lastMessageFromMe={
!!lastMessagePreview &&
lastMessagePreview.message?.senderAddress === userAddress
}
conversationOpened={conversation.topic === openedConversationTopic}
/>
);
}
Expand Down
89 changes: 89 additions & 0 deletions components/ConversationList/GroupConversationItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { NativeStackScreenProps } from "@react-navigation/native-stack";
import { FC, useCallback } from "react";
import { useColorScheme } from "react-native";

import {
useChatStore,
useCurrentAccount,
} from "../../data/store/accountsStore";
import { useSelect } from "../../data/store/storeHelpers";
import { useGroupName } from "../../hooks/useGroupName";
import { useGroupPhoto } from "../../hooks/useGroupPhoto";
import { NavigationParamList } from "../../screens/Navigation/Navigation";
import { ConversationWithLastMessagePreview } from "../../utils/conversation";
import { conversationName } from "../../utils/str";
import ConversationListItem from "../ConversationListItem";

interface GroupConversationItemProps
extends NativeStackScreenProps<
NavigationParamList,
"Chats" | "ShareFrame" | "ChatsRequests"
> {
conversation: ConversationWithLastMessagePreview;
}

export const GroupConversationItem: FC<GroupConversationItemProps> = ({
navigation,
route,
conversation,
}) => {
const topic = conversation.topic;
const lastMessagePreview = conversation.lastMessagePreview;
const { groupName } = useGroupName(topic);
const { groupPhoto } = useGroupPhoto(topic);
const colorScheme = useColorScheme();
const userAddress = useCurrentAccount() as string;
const { initialLoadDoneOnce, openedConversationTopic, topicsData } =
useChatStore(
useSelect([
"lastUpdateAt",
"initialLoadDoneOnce",
"openedConversationTopic",
"topicsData",
])
);
const setPinnedConversations = useChatStore(
(state) => state.setPinnedConversations
);

const onLongPress = useCallback(() => {
setPinnedConversations([conversation]);
}, [setPinnedConversations, conversation]);

return (
<ConversationListItem
onLongPress={onLongPress}
navigation={navigation}
route={route}
conversationPeerAddress={conversation.peerAddress}
conversationPeerAvatar={groupPhoto}
colorScheme={colorScheme}
conversationTopic={conversation.topic}
conversationTime={
lastMessagePreview?.message?.sent || conversation.createdAt
}
conversationName={groupName ? groupName : conversationName(conversation)}
showUnread={(() => {
if (!initialLoadDoneOnce) return false;
if (!lastMessagePreview) return false;
// Manually marked as unread
if (topicsData[conversation.topic]?.status === "unread") return true;
// If not manually markes as unread, we only show badge if last message
// not from me
if (lastMessagePreview.message.senderAddress === userAddress)
return false;
const readUntil = topicsData[conversation.topic]?.readUntil || 0;
return readUntil < lastMessagePreview.message.sent;
})()}
lastMessagePreview={
lastMessagePreview ? lastMessagePreview.contentPreview : ""
}
lastMessageStatus={lastMessagePreview?.message?.status}
lastMessageFromMe={
!!lastMessagePreview &&
lastMessagePreview.message?.senderAddress === userAddress
}
conversationOpened={conversation.topic === openedConversationTopic}
/>
);
};
78 changes: 78 additions & 0 deletions components/PinnedConversations/PinnedConversation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { FC, useCallback } from "react";
import {
StyleSheet,
Text,
TouchableOpacity,
useColorScheme,
} from "react-native";

import { useChatStore, useProfilesStore } from "../../data/store/accountsStore";
import { XmtpConversation } from "../../data/store/chatStore";
import { useGroupName } from "../../hooks/useGroupName";
import { useGroupPhoto } from "../../hooks/useGroupPhoto";
import { backgroundColor, textSecondaryColor } from "../../utils/colors";
import { navigate } from "../../utils/navigation";
import { getPreferredAvatar } from "../../utils/profile";
import Avatar from "../Avatar";
interface Props {
conversation: XmtpConversation;
}

export const PinnedConversation: FC<Props> = ({ conversation }) => {
const profiles = useProfilesStore((s) => s.profiles);
const { topic, isGroup } = conversation;
const { groupName } = useGroupName(topic);
const { groupPhoto } = useGroupPhoto(topic);
const title = isGroup ? groupName : conversation.conversationTitle;
const socials = profiles[conversation.peerAddress as string]?.socials;
const avatar = isGroup ? groupPhoto : getPreferredAvatar(socials);
const setPinnedConversations = useChatStore((s) => s.setPinnedConversations);
const styles = useStyles();

const onPress = useCallback(() => {
navigate("Conversation", {
topic: conversation.topic,
});
}, [conversation.topic]);

const onLongPress = useCallback(() => {
setPinnedConversations([conversation]);
}, [conversation, setPinnedConversations]);

return (
<TouchableOpacity
style={styles.container}
onPress={onPress}
onLongPress={onLongPress}
>
<Avatar
key={conversation.topic}
uri={avatar}
size={80}
style={styles.avatar}
/>
<Text style={styles.text}>{title}</Text>
</TouchableOpacity>
);
};

const useStyles = () => {
const colorScheme = useColorScheme();
return StyleSheet.create({
safe: {
flex: 1,
backgroundColor: backgroundColor(colorScheme),
},
container: {
margin: 8,
padding: 4,
},
avatar: { margin: 8 },
text: {
color: textSecondaryColor(colorScheme),
textAlign: "center",
flexWrap: "wrap",
maxWidth: 100,
},
});
};
71 changes: 13 additions & 58 deletions components/PinnedConversations/PinnedConversations.tsx
Original file line number Diff line number Diff line change
@@ -1,70 +1,25 @@
import { Text, View, useColorScheme } from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler";
import { StyleSheet, View } from "react-native";

import { useChatStore, useProfilesStore } from "../../data/store/accountsStore";
import { XmtpConversation } from "../../data/store/chatStore";
import { textSecondaryColor } from "../../utils/colors";
import { navigate } from "../../utils/navigation";
import { getPreferredAvatar } from "../../utils/profile";
import Avatar from "../Avatar";
import { PinnedConversation } from "./PinnedConversation";

type Props = {
convos?: XmtpConversation[];
};

export default function PinnedConversations({ convos }: Props) {
const colorScheme = useColorScheme();
const profiles = useProfilesStore((s) => s.profiles);
const setPinnedConversations = useChatStore((s) => s.setPinnedConversations);
const pinnedConvos = !convos
? []
: convos?.map((convo) => {
const title = convo.isGroup ? convo.groupName : convo.conversationTitle;
const socials = profiles[convo.peerAddress as string]?.socials;
const avatar = getPreferredAvatar(socials);

return (
<TouchableOpacity
style={{
margin: 8,
padding: 4,
}}
onPress={() => {
navigate("Conversation", {
topic: convo.topic,
});
}}
onLongPress={() => {
setPinnedConversations([convo]);
}}
>
<Avatar
key={convo.topic}
uri={avatar}
size={80}
style={{ margin: 8 }}
/>
<Text
style={{
color: textSecondaryColor(colorScheme),
textAlign: "center",
flexWrap: "wrap",
maxWidth: 100,
}}
>
{title}
</Text>
</TouchableOpacity>
);
return <PinnedConversation conversation={convo} />;
});
return (
<View
style={{
flexDirection: "row",
justifyContent: "center",
flexWrap: "wrap",
}}
>
{pinnedConvos}
</View>
);
return <View style={styles.container}>{pinnedConvos}</View>;
}

const styles = StyleSheet.create({
container: {
flexDirection: "row",
justifyContent: "center",
flexWrap: "wrap",
},
});

0 comments on commit 845ca42

Please sign in to comment.