feat(message): support group avatar in navigation and chat screen
Pass group avatar through notification extras, navigation hrefs, and route parameters. Update ChatScreen to resolve group information (ID, name, and avatar) by prioritizing route parameters (e.g., from push notifications) and falling back to conversation data from the MessageManager. - Update `NotificationBootstrap` to include `groupAvatar` in query params - Update `hrefChat` to support `groupAvatar` - Refactor `useChatScreen` to use `effectiveGroupId`, `effectiveGroupName`, and `effectiveGroupAvatar` - Ensure `MessageManager` fetches conversation details if missing when activating a conversation - Update `MessageListScreen` to pass `groupAvatar` during navigation
This commit is contained in:
@@ -96,6 +96,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
isGroupChat?: string | string[];
|
||||
groupId?: string | string[];
|
||||
groupName?: string | string[];
|
||||
groupAvatar?: string | string[];
|
||||
}>();
|
||||
// 路由参数(动态段 + query);群 ID 勿用 Number(),避免超过 2^53-1 时精度丢失
|
||||
// 嵌入式模式下优先使用 props,否则从路由参数获取
|
||||
@@ -107,6 +108,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
isGroupChat: props.embeddedIsGroupChat ?? false,
|
||||
groupId: props.embeddedGroupId ?? null,
|
||||
groupName: props.embeddedGroupName ?? null,
|
||||
groupAvatar: null as string | null,
|
||||
};
|
||||
}
|
||||
const isGroupFlag = firstRouteParam(rawParams.isGroupChat);
|
||||
@@ -116,6 +118,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
isGroupChat: isGroupFlag === '1' || isGroupFlag === 'true',
|
||||
groupId: firstRouteParam(rawParams.groupId),
|
||||
groupName: firstRouteParam(rawParams.groupName),
|
||||
groupAvatar: firstRouteParam(rawParams.groupAvatar),
|
||||
};
|
||||
}, [
|
||||
props?.embeddedConversationId,
|
||||
@@ -127,9 +130,10 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
rawParams.isGroupChat,
|
||||
rawParams.groupId,
|
||||
rawParams.groupName,
|
||||
rawParams.groupAvatar,
|
||||
]);
|
||||
|
||||
const { conversationId: routeConversationId, userId: routeUserId, isGroupChat, groupId: routeGroupId, groupName: routeGroupName } = routeParams;
|
||||
const { conversationId: routeConversationId, userId: routeUserId, isGroupChat, groupId: routeGroupId, groupName: routeGroupName, groupAvatar: routeGroupAvatar } = routeParams;
|
||||
|
||||
// 当前会话ID(可能在新建私聊会话后动态更新)
|
||||
const [conversationId, setConversationId] = useState<string | null>(routeConversationId);
|
||||
@@ -147,13 +151,18 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
conversation,
|
||||
} = useChat(conversationId);
|
||||
|
||||
// 统一入口:优先路由参数,其次从 conversation 对象提取(JPUSH 进入时 conversation 异步加载)
|
||||
const effectiveGroupId = routeGroupId || (isGroupChat && conversation?.group?.id) || null;
|
||||
const effectiveGroupName = routeGroupName || (isGroupChat && conversation?.group?.name) || null;
|
||||
const effectiveGroupAvatar = routeGroupAvatar || (isGroupChat && conversation?.group?.avatar) || null;
|
||||
|
||||
// 本地状态
|
||||
const [currentUserId, setCurrentUserId] = useState<string>('');
|
||||
|
||||
// 【新架构】使用 MessageManager 获取群聊输入状态和禁言状态
|
||||
const { typingUsers: groupTypingUsers } = useGroupTyping(routeGroupId ? String(routeGroupId) : null);
|
||||
const { typingUsers: groupTypingUsers } = useGroupTyping(effectiveGroupId ? String(effectiveGroupId) : null);
|
||||
const { isMuted: isMutedFromManager, setMuted: setMutedStatus } = useGroupMuted(
|
||||
routeGroupId ? String(routeGroupId) : null,
|
||||
effectiveGroupId ? String(effectiveGroupId) : null,
|
||||
currentUserId
|
||||
);
|
||||
|
||||
@@ -202,8 +211,18 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
const [selectedMessageId, setSelectedMessageId] = useState<string | null>(null);
|
||||
|
||||
// 群聊相关状态
|
||||
const [groupInfo, setGroupInfo] = useState<{ name?: string; member_count?: number } | null>(null);
|
||||
const [groupInfo, setGroupInfo] = useState<{ name?: string; member_count?: number; avatar?: string | null } | null>(null);
|
||||
const [groupMembers, setGroupMembers] = useState<GroupMemberResponse[]>([]);
|
||||
|
||||
// 群名/头像:优先使用路由参数(JPUSH extras),其次从 conversation 对象获取
|
||||
useEffect(() => {
|
||||
if (!isGroupChat) return;
|
||||
const name = effectiveGroupName;
|
||||
const avatar = effectiveGroupAvatar;
|
||||
if (name || avatar) {
|
||||
setGroupInfo(prev => prev ? prev : { name: name || undefined, avatar: avatar || null });
|
||||
}
|
||||
}, [isGroupChat, effectiveGroupName, effectiveGroupAvatar]);
|
||||
const [currentUserRole, setCurrentUserRole] = useState<UserRole>('member');
|
||||
const [mentionQuery, setMentionQuery] = useState<string>('');
|
||||
const [selectedMentions, setSelectedMentions] = useState<string[]>([]);
|
||||
@@ -453,14 +472,14 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
|
||||
// 群聊模式:获取群组信息和成员列表
|
||||
useEffect(() => {
|
||||
if (!isGroupChat || !routeGroupId) return;
|
||||
if (!isGroupChat || !effectiveGroupId) return;
|
||||
|
||||
const fetchGroupInfo = async () => {
|
||||
try {
|
||||
const group = await groupManager.getGroup(routeGroupId);
|
||||
const group = await groupManager.getGroup(effectiveGroupId);
|
||||
setGroupInfo(group);
|
||||
|
||||
const membersResponse = await groupManager.getMembers(routeGroupId, 1, MEMBERS_PAGE_SIZE);
|
||||
const membersResponse = await groupManager.getMembers(effectiveGroupId, 1, MEMBERS_PAGE_SIZE);
|
||||
const members = membersResponse.list || [];
|
||||
setGroupMembers(members);
|
||||
|
||||
@@ -470,7 +489,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const myInfo = await groupService.getMyMemberInfo(routeGroupId);
|
||||
const myInfo = await groupService.getMyMemberInfo(effectiveGroupId);
|
||||
setIsMuted(myInfo.is_muted);
|
||||
setMutedStatus(myInfo.is_muted);
|
||||
setMuteAll(myInfo.mute_all);
|
||||
@@ -508,7 +527,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
if (currentUserId) {
|
||||
fetchGroupInfo();
|
||||
}
|
||||
}, [isGroupChat, routeGroupId, currentUserId, setMutedStatus]);
|
||||
}, [isGroupChat, effectiveGroupId, currentUserId, setMutedStatus]);
|
||||
|
||||
// 私聊模式:创建或获取会话
|
||||
useEffect(() => {
|
||||
@@ -1066,7 +1085,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isGroupChat && routeGroupId) {
|
||||
if (isGroupChat && effectiveGroupId) {
|
||||
await messageService.sendMessageByAction('group', conversationId, segments);
|
||||
|
||||
setInputText('');
|
||||
@@ -1097,7 +1116,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
pendingAttachments,
|
||||
conversationId,
|
||||
isGroupChat,
|
||||
routeGroupId,
|
||||
effectiveGroupId,
|
||||
sendMessageViaManager,
|
||||
isMuted,
|
||||
muteAll,
|
||||
@@ -1264,7 +1283,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
try {
|
||||
const segments = buildImageSegments(stickerUrl, stickerUrl, undefined, undefined, replyingTo);
|
||||
|
||||
if (isGroupChat && routeGroupId) {
|
||||
if (isGroupChat && effectiveGroupId) {
|
||||
await messageService.sendMessageByAction('group', conversationId, segments);
|
||||
setReplyingTo(null);
|
||||
} else {
|
||||
@@ -1282,7 +1301,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
} finally {
|
||||
setSendingImage(false);
|
||||
}
|
||||
}, [conversationId, isGroupChat, routeGroupId, sendMessageViaManager, isMuted, muteAll, buildImageSegments, replyingTo, canSendPrivateImage, scrollToLatest]);
|
||||
}, [conversationId, isGroupChat, effectiveGroupId, sendMessageViaManager, isMuted, muteAll, buildImageSegments, replyingTo, canSendPrivateImage, scrollToLatest]);
|
||||
|
||||
// 切换表情面板
|
||||
const toggleEmojiPanel = useCallback(() => {
|
||||
@@ -1310,7 +1329,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
// 撤回消息 - 现在通过 MessageManager 处理
|
||||
const handleRecall = useCallback(async (messageId: string) => {
|
||||
try {
|
||||
if (isGroupChat && routeGroupId) {
|
||||
if (isGroupChat && effectiveGroupId) {
|
||||
await messageService.recallMessage(messageId);
|
||||
} else {
|
||||
await messageService.recallMessage(messageId);
|
||||
@@ -1320,7 +1339,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
console.error('撤回消息失败:', error);
|
||||
Alert.alert('撤回失败', '无法撤回消息');
|
||||
}
|
||||
}, [isGroupChat, routeGroupId, conversationId]);
|
||||
}, [isGroupChat, effectiveGroupId, conversationId]);
|
||||
|
||||
// 长按消息显示操作菜单
|
||||
const handleLongPressMessage = useCallback((message: GroupMessage, position?: MenuPosition) => {
|
||||
@@ -1455,17 +1474,17 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
|
||||
// 导航到群组信息或用户资料
|
||||
const navigateToInfo = useCallback(() => {
|
||||
if (isGroupChat && routeGroupId) {
|
||||
router.push(hrefs.hrefGroupInfo(routeGroupId, conversationId || undefined));
|
||||
if (isGroupChat && effectiveGroupId) {
|
||||
router.push(hrefs.hrefGroupInfo(effectiveGroupId, conversationId || undefined));
|
||||
} else if (otherUser?.id) {
|
||||
router.push(hrefs.hrefUserProfile(String(otherUser.id)));
|
||||
}
|
||||
}, [isGroupChat, routeGroupId, otherUser, conversationId]);
|
||||
}, [isGroupChat, effectiveGroupId, otherUser, conversationId]);
|
||||
|
||||
// 导航到聊天管理页面
|
||||
const navigateToChatSettings = useCallback(() => {
|
||||
if (isGroupChat && routeGroupId) {
|
||||
router.push(hrefs.hrefGroupInfo(routeGroupId, conversationId || undefined));
|
||||
if (isGroupChat && effectiveGroupId) {
|
||||
router.push(hrefs.hrefGroupInfo(effectiveGroupId, conversationId || undefined));
|
||||
} else if (otherUser?.id && conversationId) {
|
||||
router.push(
|
||||
hrefs.hrefPrivateChatInfo({
|
||||
@@ -1476,7 +1495,7 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [isGroupChat, routeGroupId, otherUser, conversationId]);
|
||||
}, [isGroupChat, effectiveGroupId, otherUser, conversationId]);
|
||||
|
||||
return {
|
||||
// 状态
|
||||
@@ -1512,8 +1531,8 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
muteAll,
|
||||
followRestrictionHint,
|
||||
canSendPrivateImage,
|
||||
routeGroupId,
|
||||
routeGroupName,
|
||||
effectiveGroupId,
|
||||
effectiveGroupName,
|
||||
otherUserLastReadSeq,
|
||||
messageMap,
|
||||
loadingMore,
|
||||
|
||||
Reference in New Issue
Block a user