@droppii-org/chat-mobile 0.2.23 → 0.2.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/module/assets/images/btn_resend.png +0 -0
- package/lib/module/assets/images/index.js +2 -1
- package/lib/module/assets/images/index.js.map +1 -1
- package/lib/module/components/AttachmentPreview/FilePreview.js +1 -1
- package/lib/module/components/AttachmentPreview/FilePreview.js.map +1 -1
- package/lib/module/components/messages/MessageStatusIndicator.js +70 -0
- package/lib/module/components/messages/MessageStatusIndicator.js.map +1 -0
- package/lib/module/components/messages/fileMessage/index.js.map +1 -1
- package/lib/module/components/messages/imageMessage/index.js +59 -50
- package/lib/module/components/messages/imageMessage/index.js.map +1 -1
- package/lib/module/components/messages/linkMessage/index.js +14 -6
- package/lib/module/components/messages/linkMessage/index.js.map +1 -1
- package/lib/module/components/messages/mergedMessage/index.js.map +1 -1
- package/lib/module/components/messages/textMessage/index.js +14 -6
- package/lib/module/components/messages/textMessage/index.js.map +1 -1
- package/lib/module/components/messages/videoMessage/index.js.map +1 -1
- package/lib/module/config/uploadLimits.js +13 -0
- package/lib/module/config/uploadLimits.js.map +1 -0
- package/lib/module/core/useChatListener.js +35 -4
- package/lib/module/core/useChatListener.js.map +1 -1
- package/lib/module/core/useUserListener.js +17 -7
- package/lib/module/core/useUserListener.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +62 -15
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useChatCompose.js +153 -0
- package/lib/module/hooks/useChatCompose.js.map +1 -0
- package/lib/module/hooks/useChatMessages.js +39 -8
- package/lib/module/hooks/useChatMessages.js.map +1 -1
- package/lib/module/hooks/useFileAttachment.js +1 -1
- package/lib/module/hooks/useFileAttachment.js.map +1 -1
- package/lib/module/hooks/useFileDownload.js +1 -1
- package/lib/module/hooks/useFileDownload.js.map +1 -1
- package/lib/module/hooks/useImageAttachment.js +81 -152
- package/lib/module/hooks/useImageAttachment.js.map +1 -1
- package/lib/module/hooks/useSendAttachment.js +2 -2
- package/lib/module/hooks/useSendAttachment.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatComposer.js +50 -185
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetail.js +29 -137
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatListLegend.js +20 -15
- package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
- package/lib/module/screens/chat-detail/index.js +0 -1
- package/lib/module/screens/chat-detail/index.js.map +1 -1
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +18 -13
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
- package/lib/module/services/attachmentHandlers/fileAttachmentHandler.js +2 -2
- package/lib/module/services/attachmentHandlers/fileAttachmentHandler.js.map +1 -1
- package/lib/module/services/attachmentHandlers/imageAttachmentHandler.js +3 -3
- package/lib/module/services/attachmentHandlers/imageAttachmentHandler.js.map +1 -1
- package/lib/module/services/attachmentHandlers/videoAttachmentHandler.js +2 -1
- package/lib/module/services/attachmentHandlers/videoAttachmentHandler.js.map +1 -1
- package/lib/module/services/attachmentOrchestrator.js +40 -17
- package/lib/module/services/attachmentOrchestrator.js.map +1 -1
- package/lib/module/services/message.js +13 -5
- package/lib/module/services/message.js.map +1 -1
- package/lib/module/translation/resources/i18n.js +4 -3
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/types/chat.js.map +1 -1
- package/lib/module/types/global.d.js +2 -0
- package/lib/module/types/global.d.js.map +1 -0
- package/lib/module/types/index.d.js +3 -0
- package/lib/module/types/index.d.js.map +1 -0
- package/lib/module/utils/UIUtils.js +37 -0
- package/lib/module/utils/UIUtils.js.map +1 -0
- package/lib/module/utils/imageUtils.js +3 -3
- package/lib/module/utils/imageUtils.js.map +1 -1
- package/lib/module/utils/pLimit.js +19 -0
- package/lib/module/utils/pLimit.js.map +1 -0
- package/lib/module/utils/videoThumbnail.js +8 -3
- package/lib/module/utils/videoThumbnail.js.map +1 -1
- package/lib/module/utils/videoThumbnailUpload.js +76 -0
- package/lib/module/utils/videoThumbnailUpload.js.map +1 -0
- package/lib/typescript/src/assets/images/index.d.ts +1 -0
- package/lib/typescript/src/assets/images/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/MessageStatusIndicator.d.ts +9 -0
- package/lib/typescript/src/components/messages/MessageStatusIndicator.d.ts.map +1 -0
- package/lib/typescript/src/components/messages/fileMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/imageMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/linkMessage/index.d.ts +3 -8
- package/lib/typescript/src/components/messages/linkMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/mergedMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/textMessage/index.d.ts +2 -8
- package/lib/typescript/src/components/messages/textMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/videoMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/config/uploadLimits.d.ts +7 -0
- package/lib/typescript/src/config/uploadLimits.d.ts.map +1 -0
- package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
- package/lib/typescript/src/core/useUserListener.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts +2 -0
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useChatCompose.d.ts +27 -0
- package/lib/typescript/src/hooks/useChatCompose.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useChatMessages.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useImageAttachment.d.ts +2 -2
- package/lib/typescript/src/hooks/useImageAttachment.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useSendAttachment.d.ts +1 -1
- package/lib/typescript/src/hooks/useSendAttachment.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts +5 -2
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/index.d.ts +0 -2
- package/lib/typescript/src/screens/chat-detail/index.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts +3 -5
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/types.d.ts +1 -35
- package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentHandlers/fileAttachmentHandler.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentHandlers/imageAttachmentHandler.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentHandlers/videoAttachmentHandler.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentOrchestrator.d.ts +1 -1
- package/lib/typescript/src/services/attachmentOrchestrator.d.ts.map +1 -1
- package/lib/typescript/src/services/message.d.ts +7 -0
- package/lib/typescript/src/services/message.d.ts.map +1 -1
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/lib/typescript/src/types/chat.d.ts +11 -0
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/utils/UIUtils.d.ts +4 -0
- package/lib/typescript/src/utils/UIUtils.d.ts.map +1 -0
- package/lib/typescript/src/utils/imageUtils.d.ts.map +1 -1
- package/lib/typescript/src/utils/pLimit.d.ts +6 -0
- package/lib/typescript/src/utils/pLimit.d.ts.map +1 -0
- package/lib/typescript/src/utils/videoThumbnail.d.ts.map +1 -1
- package/lib/typescript/src/utils/videoThumbnailUpload.d.ts +11 -0
- package/lib/typescript/src/utils/videoThumbnailUpload.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/assets/images/btn_resend.png +0 -0
- package/src/assets/images/index.ts +1 -0
- package/src/components/AttachmentPreview/FilePreview.tsx +1 -1
- package/src/components/messages/MessageStatusIndicator.tsx +82 -0
- package/src/components/messages/fileMessage/index.tsx +0 -1
- package/src/components/messages/imageMessage/index.tsx +71 -57
- package/src/components/messages/linkMessage/index.tsx +13 -19
- package/src/components/messages/mergedMessage/index.tsx +0 -1
- package/src/components/messages/textMessage/index.tsx +13 -18
- package/src/components/messages/videoMessage/index.tsx +0 -1
- package/src/config/uploadLimits.ts +11 -0
- package/src/core/useChatListener.ts +38 -4
- package/src/core/useUserListener.ts +17 -7
- package/src/hooks/message/useSendMessage.ts +103 -24
- package/src/hooks/useChatCompose.ts +195 -0
- package/src/hooks/useChatMessages.ts +54 -10
- package/src/hooks/useFileAttachment.ts +1 -1
- package/src/hooks/useFileDownload.ts +1 -1
- package/src/hooks/useImageAttachment.ts +120 -199
- package/src/hooks/useSendAttachment.ts +3 -6
- package/src/index.tsx +3 -5
- package/src/screens/chat-detail/ChatComposer.tsx +88 -240
- package/src/screens/chat-detail/ChatDetail.tsx +36 -195
- package/src/screens/chat-detail/ChatListLegend.tsx +16 -13
- package/src/screens/chat-detail/index.ts +1 -5
- package/src/screens/chat-detail/legend/LegendChatMessage.tsx +19 -12
- package/src/screens/chat-detail/types.ts +1 -38
- package/src/services/attachmentHandlers/fileAttachmentHandler.ts +3 -2
- package/src/services/attachmentHandlers/imageAttachmentHandler.ts +6 -3
- package/src/services/attachmentHandlers/videoAttachmentHandler.ts +2 -1
- package/src/services/attachmentOrchestrator.ts +49 -27
- package/src/services/message.ts +21 -4
- package/src/translation/resources/i18n.ts +6 -3
- package/src/types/chat.ts +6 -0
- package/src/types/global.d.ts +299 -0
- package/src/types/index.d.ts +1 -0
- package/src/utils/UIUtils.ts +31 -0
- package/src/utils/imageUtils.ts +3 -4
- package/src/utils/pLimit.ts +20 -0
- package/src/utils/videoThumbnail.ts +10 -3
- package/src/utils/videoThumbnailUpload.ts +103 -0
- package/lib/module/hooks/useVideoAttachment.js +0 -251
- package/lib/module/hooks/useVideoAttachment.js.map +0 -1
- package/lib/module/screens/chat-detail/hooks/useAttachmentSendHandler.js +0 -288
- package/lib/module/screens/chat-detail/hooks/useAttachmentSendHandler.js.map +0 -1
- package/lib/module/utils/giftedChatMessage.js +0 -90
- package/lib/module/utils/giftedChatMessage.js.map +0 -1
- package/lib/module/utils/ui.js +0 -17
- package/lib/module/utils/ui.js.map +0 -1
- package/lib/typescript/src/hooks/useVideoAttachment.d.ts +0 -29
- package/lib/typescript/src/hooks/useVideoAttachment.d.ts.map +0 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentSendHandler.d.ts +0 -26
- package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentSendHandler.d.ts.map +0 -1
- package/lib/typescript/src/utils/giftedChatMessage.d.ts +0 -10
- package/lib/typescript/src/utils/giftedChatMessage.d.ts.map +0 -1
- package/lib/typescript/src/utils/ui.d.ts +0 -13
- package/lib/typescript/src/utils/ui.d.ts.map +0 -1
- package/src/hooks/useVideoAttachment.ts +0 -334
- package/src/screens/chat-detail/hooks/useAttachmentSendHandler.ts +0 -386
- package/src/utils/giftedChatMessage.ts +0 -137
- package/src/utils/ui.ts +0 -19
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import RNFS from 'react-native-fs';
|
|
3
|
-
import { isVideoFromPicker } from '../../../utils/imageUtils';
|
|
4
|
-
import VideoThumbnailUtil from '../../../utils/videoThumbnail';
|
|
5
|
-
import { ImageUploadAPI } from '../../../services/imageUpload';
|
|
6
|
-
import UIUtils from '../../../utils/ui';
|
|
7
|
-
import type { DMessageItem } from '../../../types/chat';
|
|
8
|
-
import type { FileWithUploadStatus } from '../../../hooks/useFileAttachment';
|
|
9
|
-
|
|
10
|
-
interface AttachmentItem {
|
|
11
|
-
image: any;
|
|
12
|
-
uploadedUrl?: string;
|
|
13
|
-
uploadProgress?: number;
|
|
14
|
-
error?: any;
|
|
15
|
-
isUploading?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface UseAttachmentSendHandlerProps {
|
|
19
|
-
selectedImages: AttachmentItem[];
|
|
20
|
-
selectedFiles: FileWithUploadStatus[];
|
|
21
|
-
sendAttachments: (
|
|
22
|
-
items: any[],
|
|
23
|
-
_: any,
|
|
24
|
-
onMessageSent?: (message: DMessageItem) => void
|
|
25
|
-
) => Promise<boolean>;
|
|
26
|
-
clearAllImages: () => void;
|
|
27
|
-
clearAllFiles?: () => void;
|
|
28
|
-
onSend?: () => void;
|
|
29
|
-
onMessageSent?: (message: DMessageItem) => void;
|
|
30
|
-
textMessage?: string;
|
|
31
|
-
urlMetadata?: any;
|
|
32
|
-
onSendText?: (text: string, urlMetadata?: any) => void;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const useAttachmentSendHandler = ({
|
|
36
|
-
selectedImages,
|
|
37
|
-
selectedFiles,
|
|
38
|
-
sendAttachments,
|
|
39
|
-
clearAllImages,
|
|
40
|
-
clearAllFiles,
|
|
41
|
-
onSend,
|
|
42
|
-
onMessageSent,
|
|
43
|
-
textMessage,
|
|
44
|
-
urlMetadata,
|
|
45
|
-
onSendText,
|
|
46
|
-
}: UseAttachmentSendHandlerProps) => {
|
|
47
|
-
const handleSend = useCallback(async () => {
|
|
48
|
-
console.log('[ChatComposer] handleSend called', {
|
|
49
|
-
selectedImagesCount: selectedImages.length,
|
|
50
|
-
selectedImagesData: selectedImages.map((img: any) => ({
|
|
51
|
-
filename: img.image.filename,
|
|
52
|
-
isUploading: img.isUploading,
|
|
53
|
-
uploadedUrl: img.uploadedUrl ? 'SET' : 'MISSING',
|
|
54
|
-
uploadProgress: img.uploadProgress,
|
|
55
|
-
})),
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// Separate images and videos from selectedImages
|
|
59
|
-
const actualImages = selectedImages.filter(
|
|
60
|
-
(img: any) => !isVideoFromPicker(img.image)
|
|
61
|
-
);
|
|
62
|
-
const videosFromGallery = selectedImages.filter((img: any) =>
|
|
63
|
-
isVideoFromPicker(img.image)
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
console.log('🎬 [ChatComposer] Separation result:', {
|
|
67
|
-
actualImagesCount: actualImages.length,
|
|
68
|
-
videosFromGalleryCount: videosFromGallery.length,
|
|
69
|
-
videosFromGalleryList: videosFromGallery.map((v: any) => ({
|
|
70
|
-
filename: v.image.filename,
|
|
71
|
-
uploadedUrl: v.uploadedUrl,
|
|
72
|
-
})),
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const uploadedImages = actualImages.filter((img: any) => img.uploadedUrl);
|
|
76
|
-
const uploadedVideosFromGallery = videosFromGallery.filter(
|
|
77
|
-
(vid: any) => vid.uploadedUrl
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
// Auto-generate thumbnails for gallery videos
|
|
81
|
-
// Use unique ID per video to avoid race conditions and path mismatches
|
|
82
|
-
const galleryVideoThumbnails: Record<
|
|
83
|
-
string,
|
|
84
|
-
{ url: string; size: number }
|
|
85
|
-
> = {};
|
|
86
|
-
const failedVideos: string[] = []; // Track failed videos
|
|
87
|
-
|
|
88
|
-
if (uploadedVideosFromGallery.length > 0) {
|
|
89
|
-
console.log(
|
|
90
|
-
'[ChatComposer] Auto-generating thumbnails for gallery videos...'
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
for (let idx = 0; idx < uploadedVideosFromGallery.length; idx++) {
|
|
94
|
-
const vidItem = uploadedVideosFromGallery[idx]!;
|
|
95
|
-
const videoId = vidItem.uploadedUrl || `video-${idx}`; // Use unique ID instead of path
|
|
96
|
-
let cachedVideoPath: string | null = null;
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const originalVideoPath = vidItem.image.path;
|
|
100
|
-
let videoDuration = (vidItem.image as any).duration || 0;
|
|
101
|
-
const videoMime = (vidItem.image as any).mime;
|
|
102
|
-
const filename = vidItem.image.filename || 'video.mp4';
|
|
103
|
-
|
|
104
|
-
console.log('[ChatComposer] Generating thumbnail for video:', {
|
|
105
|
-
index: idx,
|
|
106
|
-
filename,
|
|
107
|
-
originalVideoPath,
|
|
108
|
-
videoDuration,
|
|
109
|
-
videoMime,
|
|
110
|
-
uploadedUrl: vidItem.uploadedUrl,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// ✅ FIX: Validate duration is reasonable
|
|
114
|
-
if (videoDuration <= 0 || videoDuration > 3600000) {
|
|
115
|
-
// Duration should be between 0 and 1 hour (3600000ms)
|
|
116
|
-
console.warn(
|
|
117
|
-
'[ChatComposer] Invalid duration, using default:',
|
|
118
|
-
videoDuration
|
|
119
|
-
);
|
|
120
|
-
videoDuration = 5000; // Default 5 seconds
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Copy video to persistent location
|
|
124
|
-
const ext = filename.split('.').pop() || 'mp4';
|
|
125
|
-
// ✅ FIX: Use unique ID to avoid race condition
|
|
126
|
-
const cachedFileName = `thumb-cache-${idx}-${Date.now()}-${Math.random()
|
|
127
|
-
.toString(36)
|
|
128
|
-
.slice(2)}.${ext}`;
|
|
129
|
-
cachedVideoPath = `${RNFS.DocumentDirectoryPath}/${cachedFileName}`;
|
|
130
|
-
|
|
131
|
-
console.log('[ChatComposer] Copying video to cache:', {
|
|
132
|
-
from: originalVideoPath,
|
|
133
|
-
to: cachedVideoPath,
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
await RNFS.copyFile(originalVideoPath, cachedVideoPath);
|
|
137
|
-
console.log('[ChatComposer] Video cached successfully');
|
|
138
|
-
|
|
139
|
-
// ✅ FIX: Choose frame at 30-40% for better representation
|
|
140
|
-
// (not exactly middle, to avoid black frames/transitions)
|
|
141
|
-
const timeMs = Math.min(
|
|
142
|
-
Math.max(1000, Math.floor(videoDuration * 0.35)),
|
|
143
|
-
videoDuration - 1000
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
console.log('[ChatComposer] Thumbnail settings for video:', {
|
|
147
|
-
index: idx,
|
|
148
|
-
videoDuration,
|
|
149
|
-
timeMs,
|
|
150
|
-
quality: 80,
|
|
151
|
-
videoPath: cachedVideoPath,
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// Generate thumbnail from cached copy
|
|
155
|
-
const thumbnail = await VideoThumbnailUtil.generateThumbnail(
|
|
156
|
-
cachedVideoPath,
|
|
157
|
-
{
|
|
158
|
-
time: timeMs,
|
|
159
|
-
quality: 80,
|
|
160
|
-
cacheId: `thumb-${idx}-${Date.now()}`,
|
|
161
|
-
}
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
if (!thumbnail) {
|
|
165
|
-
throw new Error('Failed to generate thumbnail');
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
console.log('[ChatComposer] Thumbnail generated for video:', {
|
|
169
|
-
index: idx,
|
|
170
|
-
path: thumbnail.path,
|
|
171
|
-
width: thumbnail.width,
|
|
172
|
-
height: thumbnail.height,
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// Upload thumbnail
|
|
176
|
-
const baseName =
|
|
177
|
-
vidItem.image.filename?.split('.')[0] || `video-${idx}`;
|
|
178
|
-
const uploadedThumbnail = await ImageUploadAPI.uploadImageFile(
|
|
179
|
-
{
|
|
180
|
-
path: thumbnail.path,
|
|
181
|
-
filename: `thumb-${baseName}.jpg`,
|
|
182
|
-
size: 0,
|
|
183
|
-
width: thumbnail.width || 320,
|
|
184
|
-
height: thumbnail.height || 180,
|
|
185
|
-
mime: 'image/jpeg',
|
|
186
|
-
},
|
|
187
|
-
(progress) => {
|
|
188
|
-
console.log('[ChatComposer] Thumbnail upload progress:', {
|
|
189
|
-
videoIndex: idx,
|
|
190
|
-
percentage: progress,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
if (!uploadedThumbnail?.url) {
|
|
196
|
-
throw new Error('No thumbnail URL returned');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ✅ FIX: Store with unique ID instead of path
|
|
200
|
-
galleryVideoThumbnails[videoId] = {
|
|
201
|
-
url: uploadedThumbnail.url,
|
|
202
|
-
size: uploadedThumbnail.size || 0,
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
console.log('[ChatComposer] Thumbnail ready for video:', {
|
|
206
|
-
videoIndex: idx,
|
|
207
|
-
videoId,
|
|
208
|
-
url: uploadedThumbnail.url,
|
|
209
|
-
size: uploadedThumbnail.size,
|
|
210
|
-
});
|
|
211
|
-
console.log(
|
|
212
|
-
`✅ [ChatComposer] Video #${idx} THUMBNAIL URL: ${uploadedThumbnail.url}`
|
|
213
|
-
);
|
|
214
|
-
} catch (error) {
|
|
215
|
-
// ✅ FIX: Skip failed video instead of aborting all
|
|
216
|
-
const errorMsg =
|
|
217
|
-
error instanceof Error ? error.message : String(error);
|
|
218
|
-
console.error(
|
|
219
|
-
'[ChatComposer] Thumbnail generation error for video:',
|
|
220
|
-
idx,
|
|
221
|
-
errorMsg
|
|
222
|
-
);
|
|
223
|
-
failedVideos.push(vidItem.image.filename);
|
|
224
|
-
|
|
225
|
-
// Mark this video as failed (no thumbnail)
|
|
226
|
-
galleryVideoThumbnails[videoId] = { url: '', size: 0 };
|
|
227
|
-
} finally {
|
|
228
|
-
// Cleanup cached video file
|
|
229
|
-
if (cachedVideoPath) {
|
|
230
|
-
try {
|
|
231
|
-
await RNFS.unlink(cachedVideoPath);
|
|
232
|
-
console.log('[ChatComposer] Cleaned up cached video:', {
|
|
233
|
-
videoIndex: idx,
|
|
234
|
-
path: cachedVideoPath,
|
|
235
|
-
});
|
|
236
|
-
} catch (err) {
|
|
237
|
-
console.warn('[ChatComposer] Failed to clean cached video:', err);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Show error about failed videos if any
|
|
244
|
-
if (failedVideos.length > 0) {
|
|
245
|
-
UIUtils.toast.open({
|
|
246
|
-
title: 'Thumbnail Generation Failed',
|
|
247
|
-
message: `Failed for: ${failedVideos.join(', ')}. Videos will be sent without thumbnails.`,
|
|
248
|
-
theme: 'warning',
|
|
249
|
-
});
|
|
250
|
-
console.warn(
|
|
251
|
-
'[ChatComposer] Failed to generate thumbnails for:',
|
|
252
|
-
failedVideos
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const allUploadedVideos = [...uploadedVideosFromGallery];
|
|
258
|
-
|
|
259
|
-
console.log('[ChatComposer] handleSend summary:', {
|
|
260
|
-
actualImages: actualImages.length,
|
|
261
|
-
uploadedImages: uploadedImages.length,
|
|
262
|
-
videosFromGallery: videosFromGallery.length,
|
|
263
|
-
uploadedVideosFromGallery: uploadedVideosFromGallery.length,
|
|
264
|
-
allUploadedVideos: allUploadedVideos.length,
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
// Log thumbnail URLs
|
|
268
|
-
if (uploadedVideosFromGallery.length > 0) {
|
|
269
|
-
uploadedVideosFromGallery.forEach((vid: any, vidIdx: number) => {
|
|
270
|
-
// ✅ Use same key as storage: uploadedUrl or video-${idx}
|
|
271
|
-
const videoId = vid.uploadedUrl || `video-${vidIdx}`;
|
|
272
|
-
const thumbnail = galleryVideoThumbnails[videoId];
|
|
273
|
-
console.log(`✅ [ChatComposer] Gallery Video Thumbnail:`, {
|
|
274
|
-
filename: vid.image.filename,
|
|
275
|
-
videoId,
|
|
276
|
-
thumbnailUrl: thumbnail?.url || 'NOT FOUND',
|
|
277
|
-
videoUrl: vid.uploadedUrl,
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Send images and videos if any
|
|
283
|
-
if (uploadedImages.length > 0 || allUploadedVideos.length > 0) {
|
|
284
|
-
const attachmentItems = [
|
|
285
|
-
...uploadedImages.map((img: any) => ({
|
|
286
|
-
...img,
|
|
287
|
-
type: 'image' as const,
|
|
288
|
-
})),
|
|
289
|
-
// Videos from gallery picker with auto-generated thumbnails
|
|
290
|
-
...uploadedVideosFromGallery.map((vid: any, vidIdx: number) => {
|
|
291
|
-
// ✅ Use same key as storage: uploadedUrl or video-${idx}
|
|
292
|
-
const videoId = vid.uploadedUrl || `video-${vidIdx}`;
|
|
293
|
-
const thumbnail = galleryVideoThumbnails[videoId];
|
|
294
|
-
return {
|
|
295
|
-
type: 'video' as const,
|
|
296
|
-
video: vid.image,
|
|
297
|
-
uploadProgress: vid.uploadProgress,
|
|
298
|
-
error: vid.error,
|
|
299
|
-
isUploading: vid.isUploading,
|
|
300
|
-
uploadedUrl: vid.uploadedUrl,
|
|
301
|
-
thumbnailUrl: thumbnail?.url,
|
|
302
|
-
thumbnailSize: thumbnail?.size,
|
|
303
|
-
};
|
|
304
|
-
}),
|
|
305
|
-
];
|
|
306
|
-
|
|
307
|
-
console.log('[ChatComposer] Sending attachments...', {
|
|
308
|
-
imagesCount: uploadedImages.length,
|
|
309
|
-
videosCount: uploadedVideosFromGallery.length,
|
|
310
|
-
hasTextMessage: !!textMessage,
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
const success = await sendAttachments(
|
|
314
|
-
attachmentItems,
|
|
315
|
-
undefined,
|
|
316
|
-
onMessageSent
|
|
317
|
-
);
|
|
318
|
-
|
|
319
|
-
console.log('[ChatComposer] Attachments send result:', { success });
|
|
320
|
-
|
|
321
|
-
if (success) {
|
|
322
|
-
clearAllImages();
|
|
323
|
-
console.log('[ChatComposer] Images cleared after successful send');
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Send each file as its own individual message
|
|
328
|
-
const uploadedFiles = selectedFiles.filter(
|
|
329
|
-
(f) => f.uploadedUrl && !f.error
|
|
330
|
-
);
|
|
331
|
-
if (uploadedFiles.length > 0) {
|
|
332
|
-
console.log('[ChatComposer] Sending files individually:', {
|
|
333
|
-
count: uploadedFiles.length,
|
|
334
|
-
});
|
|
335
|
-
for (const file of uploadedFiles) {
|
|
336
|
-
await sendAttachments(
|
|
337
|
-
[
|
|
338
|
-
{
|
|
339
|
-
type: 'file' as const,
|
|
340
|
-
file: { path: file.uri, filename: file.name, size: file.size },
|
|
341
|
-
uploadProgress: 100,
|
|
342
|
-
error: null,
|
|
343
|
-
isUploading: false,
|
|
344
|
-
uploadedUrl: file.uploadedUrl,
|
|
345
|
-
},
|
|
346
|
-
],
|
|
347
|
-
undefined,
|
|
348
|
-
onMessageSent
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
clearAllFiles?.();
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Send text last
|
|
355
|
-
if (textMessage && onSendText) {
|
|
356
|
-
console.log('[ChatComposer] Sending text message after attachments', {
|
|
357
|
-
hasPreview: !!urlMetadata,
|
|
358
|
-
previewUrl: urlMetadata?.url,
|
|
359
|
-
});
|
|
360
|
-
onSendText(textMessage, urlMetadata);
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const hasAnySent =
|
|
365
|
-
uploadedImages.length > 0 ||
|
|
366
|
-
allUploadedVideos.length > 0 ||
|
|
367
|
-
uploadedFiles.length > 0;
|
|
368
|
-
if (!hasAnySent) {
|
|
369
|
-
onSend?.();
|
|
370
|
-
}
|
|
371
|
-
return;
|
|
372
|
-
}, [
|
|
373
|
-
selectedImages,
|
|
374
|
-
selectedFiles,
|
|
375
|
-
sendAttachments,
|
|
376
|
-
clearAllImages,
|
|
377
|
-
clearAllFiles,
|
|
378
|
-
onSend,
|
|
379
|
-
onMessageSent,
|
|
380
|
-
textMessage,
|
|
381
|
-
urlMetadata,
|
|
382
|
-
onSendText,
|
|
383
|
-
]);
|
|
384
|
-
|
|
385
|
-
return { handleSend };
|
|
386
|
-
};
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { MessageStatus, MessageType } from '@droppii/openim-rn-client-sdk';
|
|
2
|
-
import type { IMessage } from 'react-native-gifted-chat';
|
|
3
|
-
import type { DChatMessageType } from '../types/message';
|
|
4
|
-
import type { DMessageItem } from '../types/chat';
|
|
5
|
-
import { resolveChatMessageType } from './resolveMessageType';
|
|
6
|
-
|
|
7
|
-
export type DGiftedChatMessage = IMessage & {
|
|
8
|
-
openIMMessage: DMessageItem;
|
|
9
|
-
messageType: DChatMessageType;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const SYSTEM_MESSAGE_TYPES = new Set<MessageType>([
|
|
13
|
-
MessageType.FriendAdded,
|
|
14
|
-
MessageType.OANotification,
|
|
15
|
-
MessageType.GroupCreated,
|
|
16
|
-
MessageType.GroupInfoUpdated,
|
|
17
|
-
MessageType.MemberQuit,
|
|
18
|
-
MessageType.GroupOwnerTransferred,
|
|
19
|
-
MessageType.MemberKicked,
|
|
20
|
-
MessageType.MemberInvited,
|
|
21
|
-
MessageType.MemberEnter,
|
|
22
|
-
MessageType.GroupDismissed,
|
|
23
|
-
MessageType.GroupMemberMuted,
|
|
24
|
-
MessageType.GroupMemberCancelMuted,
|
|
25
|
-
MessageType.GroupMuted,
|
|
26
|
-
MessageType.GroupCancelMuted,
|
|
27
|
-
MessageType.GroupAnnouncementUpdated,
|
|
28
|
-
MessageType.GroupNameUpdated,
|
|
29
|
-
MessageType.RevokeMessage,
|
|
30
|
-
]);
|
|
31
|
-
|
|
32
|
-
const getMessageText = (message: DMessageItem): string => {
|
|
33
|
-
switch (message.contentType) {
|
|
34
|
-
case MessageType.TextMessage:
|
|
35
|
-
return message.textElem?.content ?? message.content;
|
|
36
|
-
case MessageType.AtTextMessage:
|
|
37
|
-
return message.atTextElem?.text ?? message.content;
|
|
38
|
-
case MessageType.QuoteMessage:
|
|
39
|
-
return message.quoteElem?.text ?? message.content;
|
|
40
|
-
case MessageType.PictureMessage:
|
|
41
|
-
return '';
|
|
42
|
-
case MessageType.VoiceMessage:
|
|
43
|
-
return message.soundElem?.sourceUrl ? '' : '[Tin nhắn thoại]';
|
|
44
|
-
case MessageType.VideoMessage:
|
|
45
|
-
return message.videoElem?.videoUrl ? '' : '[Video]';
|
|
46
|
-
case MessageType.FileMessage:
|
|
47
|
-
return message.fileElem?.fileName ?? message.content;
|
|
48
|
-
case MessageType.CardMessage:
|
|
49
|
-
return message.cardElem?.nickname ?? message.content;
|
|
50
|
-
case MessageType.LocationMessage:
|
|
51
|
-
return message.locationElem?.description ?? message.content;
|
|
52
|
-
case MessageType.CustomMessage:
|
|
53
|
-
return message.customElem?.description ?? message.content;
|
|
54
|
-
case MessageType.FaceMessage:
|
|
55
|
-
return '[Sticker]';
|
|
56
|
-
default:
|
|
57
|
-
if (message.notificationElem?.detail) {
|
|
58
|
-
return message.notificationElem.detail;
|
|
59
|
-
}
|
|
60
|
-
return message.content || '';
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const mapMessageStatus = (
|
|
65
|
-
message: DMessageItem
|
|
66
|
-
): Pick<IMessage, 'pending' | 'sent' | 'received'> => {
|
|
67
|
-
switch (message.status) {
|
|
68
|
-
case MessageStatus.Sending:
|
|
69
|
-
return { pending: true };
|
|
70
|
-
case MessageStatus.Succeed:
|
|
71
|
-
return { sent: true, received: message.isRead };
|
|
72
|
-
case MessageStatus.Failed:
|
|
73
|
-
return { pending: true };
|
|
74
|
-
default:
|
|
75
|
-
return {};
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export const mapOpenIMMessageToGiftedChat = (
|
|
80
|
-
message: DMessageItem
|
|
81
|
-
): DGiftedChatMessage => {
|
|
82
|
-
const gifted: DGiftedChatMessage = {
|
|
83
|
-
_id: message.clientMsgID || message.serverMsgID,
|
|
84
|
-
text: getMessageText(message),
|
|
85
|
-
createdAt: new Date(message.sendTime || message.createTime),
|
|
86
|
-
user: {
|
|
87
|
-
_id: String(message.sendID),
|
|
88
|
-
name: message.senderNickname,
|
|
89
|
-
avatar: message.senderFaceUrl || undefined,
|
|
90
|
-
},
|
|
91
|
-
openIMMessage: message,
|
|
92
|
-
messageType: resolveChatMessageType(message),
|
|
93
|
-
...mapMessageStatus(message),
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
if (SYSTEM_MESSAGE_TYPES.has(message.contentType)) {
|
|
97
|
-
gifted.system = true;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (message.contentType === MessageType.PictureMessage) {
|
|
101
|
-
const imageUrl =
|
|
102
|
-
message.pictureElem?.snapshotPicture?.url ||
|
|
103
|
-
message.pictureElem?.bigPicture?.url ||
|
|
104
|
-
message.pictureElem?.sourcePicture?.url;
|
|
105
|
-
|
|
106
|
-
if (imageUrl) {
|
|
107
|
-
gifted.image = imageUrl;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
message.contentType === MessageType.VideoMessage &&
|
|
113
|
-
message.videoElem?.videoUrl
|
|
114
|
-
) {
|
|
115
|
-
gifted.video = message.videoElem.videoUrl;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (
|
|
119
|
-
message.contentType === MessageType.VoiceMessage &&
|
|
120
|
-
message.soundElem?.sourceUrl
|
|
121
|
-
) {
|
|
122
|
-
gifted.audio = message.soundElem.sourceUrl;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return gifted;
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
export const mapOpenIMMessagesToGiftedChat = (
|
|
129
|
-
messages: DMessageItem[]
|
|
130
|
-
): DGiftedChatMessage[] => {
|
|
131
|
-
return messages
|
|
132
|
-
.map(mapOpenIMMessageToGiftedChat)
|
|
133
|
-
.sort(
|
|
134
|
-
(a, b) =>
|
|
135
|
-
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
|
|
136
|
-
);
|
|
137
|
-
};
|
package/src/utils/ui.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Alert } from 'react-native';
|
|
2
|
-
|
|
3
|
-
interface ToastConfig {
|
|
4
|
-
title?: string;
|
|
5
|
-
message?: string;
|
|
6
|
-
theme?: 'success' | 'danger' | 'warning' | 'info';
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const UIUtils = {
|
|
10
|
-
toast: {
|
|
11
|
-
open: (config: ToastConfig) => {
|
|
12
|
-
const { title = 'Message', message = '' } = config;
|
|
13
|
-
Alert.alert(title, message);
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export default UIUtils;
|
|
19
|
-
export { UIUtils };
|