feat(push): integrate Honor and Xiaomi push plugins with related updates
This commit is contained in:
@@ -20,7 +20,9 @@ import {
|
||||
import { useLocalSearchParams, router } from 'expo-router';
|
||||
import { formatChatTime } from '@/utils/formatTime';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
import { GroupMemberResponse, MessageSegment, TextSegmentData, ImageSegmentData, AtSegmentData, ReplySegmentData, MessageStatus } from '../../../../types/dto';
|
||||
import * as DocumentPicker from 'expo-document-picker';
|
||||
import { Linking } from 'react-native';
|
||||
import { GroupMemberResponse, MessageSegment, TextSegmentData, ImageSegmentData, FileSegmentData, AtSegmentData, ReplySegmentData, MessageStatus } from '../../../../types/dto';
|
||||
import { messageService } from '@/services/message';
|
||||
import { uploadService } from '@/services/upload';
|
||||
import { ApiError } from '@/services/core';
|
||||
@@ -1049,6 +1051,38 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
return segments;
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* 构建文件消息的 segments 数组
|
||||
*/
|
||||
const buildFileSegments = useCallback((
|
||||
fileUrl: string,
|
||||
name: string,
|
||||
size?: number,
|
||||
mimeType?: string,
|
||||
replyToMessage?: GroupMessage | null,
|
||||
): MessageSegment[] => {
|
||||
const segments: MessageSegment[] = [];
|
||||
|
||||
if (replyToMessage) {
|
||||
segments.push({
|
||||
type: 'reply',
|
||||
data: { id: replyToMessage.id, seq: replyToMessage.seq } as ReplySegmentData
|
||||
});
|
||||
}
|
||||
|
||||
segments.push({
|
||||
type: 'file',
|
||||
data: {
|
||||
url: fileUrl,
|
||||
name,
|
||||
size,
|
||||
mime_type: mimeType,
|
||||
} as FileSegmentData
|
||||
});
|
||||
|
||||
return segments;
|
||||
}, []);
|
||||
|
||||
// 【新架构】发送消息(支持纯文字、纯多图、图文同条)
|
||||
const handleSend = useCallback(async () => {
|
||||
const trimmedText = inputText.trim();
|
||||
@@ -1253,6 +1287,89 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
setActivePanel('none');
|
||||
}, [pendingAttachments.length]);
|
||||
|
||||
// 选择并发送文件(单选,立即上传后发送)
|
||||
const handlePickFile = useCallback(async () => {
|
||||
if (!conversationId) {
|
||||
setActivePanel('none');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isGroupChat && isMuted) {
|
||||
Alert.alert('无法发送', muteAll ? '当前群组已开启全员禁言' : '你已被管理员禁言');
|
||||
setActivePanel('none');
|
||||
return;
|
||||
}
|
||||
|
||||
setActivePanel('none');
|
||||
|
||||
try {
|
||||
const result = await DocumentPicker.getDocumentAsync({
|
||||
multiple: false,
|
||||
copyToCacheDirectory: true,
|
||||
});
|
||||
if (result.canceled || !result.assets || result.assets.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const asset = result.assets[0];
|
||||
setUploadingAttachments(true);
|
||||
|
||||
const uploaded = await uploadService.uploadFile(
|
||||
{
|
||||
uri: asset.uri,
|
||||
name: asset.name,
|
||||
type: asset.mimeType || undefined,
|
||||
},
|
||||
'chat'
|
||||
);
|
||||
|
||||
if (!uploaded?.url) {
|
||||
Alert.alert('上传失败', getSendErrorMessage(null, '文件上传失败,请重试'));
|
||||
return;
|
||||
}
|
||||
|
||||
const segments = buildFileSegments(
|
||||
uploaded.url,
|
||||
uploaded.name || asset.name,
|
||||
uploaded.size ?? asset.size,
|
||||
uploaded.mime_type ?? asset.mimeType,
|
||||
replyingTo,
|
||||
);
|
||||
|
||||
setSending(true);
|
||||
try {
|
||||
if (isGroupChat && effectiveGroupId) {
|
||||
await messageService.sendMessageByAction('group', conversationId, segments);
|
||||
} else {
|
||||
await sendMessageViaManager(segments);
|
||||
}
|
||||
setReplyingTo(null);
|
||||
setTimeout(() => scrollToLatest(false, false, 'send-file'), 100);
|
||||
} catch (error) {
|
||||
console.error('发送文件消息失败:', error);
|
||||
Alert.alert('发送失败', getSendErrorMessage(error, '消息发送失败,请重试'));
|
||||
} finally {
|
||||
setSending(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('选择文件失败:', error);
|
||||
Alert.alert('错误', getSendErrorMessage(error, '选择文件失败'));
|
||||
} finally {
|
||||
setUploadingAttachments(false);
|
||||
}
|
||||
}, [
|
||||
conversationId,
|
||||
isGroupChat,
|
||||
isMuted,
|
||||
muteAll,
|
||||
effectiveGroupId,
|
||||
replyingTo,
|
||||
buildFileSegments,
|
||||
sendMessageViaManager,
|
||||
scrollToLatest,
|
||||
getSendErrorMessage,
|
||||
]);
|
||||
|
||||
// 处理更多功能
|
||||
const handleMoreAction = useCallback((actionId: string) => {
|
||||
switch (actionId) {
|
||||
@@ -1281,17 +1398,12 @@ export const useChatScreen = (props?: ChatScreenProps) => {
|
||||
handleTakePhoto();
|
||||
break;
|
||||
case 'file':
|
||||
Alert.alert('提示', '文件功能即将上线');
|
||||
setActivePanel('none');
|
||||
break;
|
||||
case 'location':
|
||||
Alert.alert('提示', '位置功能即将上线');
|
||||
setActivePanel('none');
|
||||
handlePickFile();
|
||||
break;
|
||||
default:
|
||||
setActivePanel('none');
|
||||
}
|
||||
}, [handlePickImage, handleTakePhoto, isGroupChat, otherUser, conversationId]);
|
||||
}, [handlePickImage, handleTakePhoto, handlePickFile, isGroupChat, otherUser, conversationId]);
|
||||
|
||||
// 插入表情
|
||||
const handleInsertEmoji = useCallback((emoji: string) => {
|
||||
|
||||
Reference in New Issue
Block a user