@droppii-org/chat-mobile 0.2.16 → 0.2.18
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/icon_excel.png +0 -0
- package/lib/module/assets/images/icon_img.png +0 -0
- package/lib/module/assets/images/icon_pdf.png +0 -0
- package/lib/module/assets/images/icon_txt.png +0 -0
- package/lib/module/assets/images/icon_word.png +0 -0
- package/lib/module/assets/images/index.js +5 -0
- package/lib/module/assets/images/index.js.map +1 -1
- package/lib/module/components/AttachmentPreview/FilePreview.js +107 -0
- package/lib/module/components/AttachmentPreview/FilePreview.js.map +1 -0
- package/lib/module/components/AttachmentPreview/MediaPreview.js +212 -0
- package/lib/module/components/AttachmentPreview/MediaPreview.js.map +1 -0
- package/lib/module/components/AttachmentPreview/index.js +49 -0
- package/lib/module/components/AttachmentPreview/index.js.map +1 -0
- package/lib/module/components/MergedImageGrid.js +28 -18
- package/lib/module/components/MergedImageGrid.js.map +1 -1
- package/lib/module/components/messages/fileMessage/index.js +122 -12
- package/lib/module/components/messages/fileMessage/index.js.map +1 -1
- package/lib/module/components/messages/mergedMessage/index.js +4 -7
- package/lib/module/components/messages/mergedMessage/index.js.map +1 -1
- package/lib/module/hooks/useFileAttachment.js +116 -0
- package/lib/module/hooks/useFileAttachment.js.map +1 -0
- package/lib/module/hooks/useFileDownload.js +175 -0
- package/lib/module/hooks/useFileDownload.js.map +1 -0
- package/lib/module/hooks/useImageAttachment.js +16 -8
- package/lib/module/hooks/useImageAttachment.js.map +1 -1
- package/lib/module/hooks/useVideoAttachment.js +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/screens/MediaView/VideoPlayer.js +1 -0
- package/lib/module/screens/MediaView/VideoPlayer.js.map +1 -1
- package/lib/module/screens/MediaView/index.js +7 -9
- package/lib/module/screens/MediaView/index.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatComposer.js +44 -36
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatListLegend.js +11 -2
- package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
- package/lib/module/screens/chat-detail/hooks/useAttachmentMapping.js +51 -0
- package/lib/module/screens/chat-detail/hooks/useAttachmentMapping.js.map +1 -0
- package/lib/module/screens/chat-detail/hooks/useAttachmentSendHandler.js +39 -13
- package/lib/module/screens/chat-detail/hooks/useAttachmentSendHandler.js.map +1 -1
- package/lib/module/services/attachmentHandlers/fileAttachmentHandler.js +6 -6
- package/lib/module/services/attachmentHandlers/fileAttachmentHandler.js.map +1 -1
- package/lib/module/services/attachmentHandlers/index.js +1 -1
- package/lib/module/services/attachmentHandlers/index.js.map +1 -1
- package/lib/module/services/attachmentHandlers/videoAttachmentHandler.js +1 -1
- package/lib/module/translation/resources/i18n.js +10 -0
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/utils/device.js +32 -0
- package/lib/module/utils/device.js.map +1 -1
- package/lib/module/utils/imageUtils.js +44 -28
- package/lib/module/utils/imageUtils.js.map +1 -1
- package/lib/module/utils/videoThumbnail.js +76 -3
- package/lib/module/utils/videoThumbnail.js.map +1 -1
- package/lib/typescript/src/assets/images/index.d.ts +5 -0
- package/lib/typescript/src/assets/images/index.d.ts.map +1 -1
- package/lib/typescript/src/components/AttachmentPreview/FilePreview.d.ts +6 -0
- package/lib/typescript/src/components/AttachmentPreview/FilePreview.d.ts.map +1 -0
- package/lib/typescript/src/components/AttachmentPreview/MediaPreview.d.ts +9 -0
- package/lib/typescript/src/components/AttachmentPreview/MediaPreview.d.ts.map +1 -0
- package/lib/typescript/src/components/AttachmentPreview/index.d.ts +9 -0
- package/lib/typescript/src/components/AttachmentPreview/index.d.ts.map +1 -0
- package/lib/typescript/src/components/MergedImageGrid.d.ts +2 -2
- package/lib/typescript/src/components/MergedImageGrid.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/fileMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/mergedMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useFileAttachment.d.ts +20 -0
- package/lib/typescript/src/hooks/useFileAttachment.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useFileDownload.d.ts +15 -0
- package/lib/typescript/src/hooks/useFileDownload.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useImageAttachment.d.ts +1 -2
- package/lib/typescript/src/hooks/useImageAttachment.d.ts.map +1 -1
- package/lib/typescript/src/screens/MediaView/VideoPlayer.d.ts.map +1 -1
- package/lib/typescript/src/screens/MediaView/index.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentMapping.d.ts +10 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentMapping.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentSendHandler.d.ts +4 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentSendHandler.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentHandlers/fileAttachmentHandler.d.ts +2 -2
- package/lib/typescript/src/services/attachmentHandlers/fileAttachmentHandler.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentHandlers/index.d.ts +1 -1
- package/lib/typescript/src/services/attachmentHandlers/index.d.ts.map +1 -1
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/lib/typescript/src/types/attachment.d.ts +22 -1
- package/lib/typescript/src/types/attachment.d.ts.map +1 -1
- package/lib/typescript/src/utils/device.d.ts +7 -0
- package/lib/typescript/src/utils/device.d.ts.map +1 -1
- package/lib/typescript/src/utils/imageUtils.d.ts +1 -0
- package/lib/typescript/src/utils/imageUtils.d.ts.map +1 -1
- package/lib/typescript/src/utils/videoThumbnail.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/assets/images/icon_excel.png +0 -0
- package/src/assets/images/icon_img.png +0 -0
- package/src/assets/images/icon_pdf.png +0 -0
- package/src/assets/images/icon_txt.png +0 -0
- package/src/assets/images/icon_word.png +0 -0
- package/src/assets/images/index.ts +5 -0
- package/src/components/AttachmentPreview/FilePreview.tsx +137 -0
- package/src/components/AttachmentPreview/MediaPreview.tsx +238 -0
- package/src/components/AttachmentPreview/index.tsx +68 -0
- package/src/components/MergedImageGrid.tsx +36 -23
- package/src/components/messages/fileMessage/index.tsx +156 -13
- package/src/components/messages/mergedMessage/index.tsx +5 -7
- package/src/hooks/useFileAttachment.ts +163 -0
- package/src/hooks/useFileDownload.ts +200 -0
- package/src/hooks/useImageAttachment.ts +23 -13
- package/src/hooks/useVideoAttachment.ts +1 -1
- package/src/screens/MediaView/VideoPlayer.tsx +1 -0
- package/src/screens/MediaView/index.tsx +7 -6
- package/src/screens/chat-detail/ChatComposer.tsx +61 -30
- package/src/screens/chat-detail/ChatListLegend.tsx +9 -2
- package/src/screens/chat-detail/hooks/useAttachmentMapping.ts +58 -0
- package/src/screens/chat-detail/hooks/useAttachmentSendHandler.ts +50 -11
- package/src/services/attachmentHandlers/fileAttachmentHandler.ts +8 -7
- package/src/services/attachmentHandlers/index.ts +4 -1
- package/src/services/attachmentHandlers/videoAttachmentHandler.ts +1 -1
- package/src/translation/resources/i18n.ts +10 -0
- package/src/types/attachment.ts +23 -1
- package/src/utils/device.ts +58 -0
- package/src/utils/imageUtils.ts +50 -28
- package/src/utils/videoThumbnail.ts +77 -3
- package/lib/module/components/AttachmentPreview.js +0 -250
- package/lib/module/components/AttachmentPreview.js.map +0 -1
- package/lib/typescript/src/components/AttachmentPreview.d.ts +0 -28
- package/lib/typescript/src/components/AttachmentPreview.d.ts.map +0 -1
- package/src/components/AttachmentPreview.tsx +0 -304
|
@@ -6,12 +6,13 @@ interface FileElem {
|
|
|
6
6
|
fileName: string;
|
|
7
7
|
fileSize: number;
|
|
8
8
|
fileType: string;
|
|
9
|
-
|
|
9
|
+
sourceUrl: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const MB = 1024 * 1024;
|
|
13
|
+
export const MAX_FILE_SIZE = 50 * MB;
|
|
14
14
|
|
|
15
|
+
export class FileAttachmentHandler implements IAttachmentHandler {
|
|
15
16
|
validate(
|
|
16
17
|
attachment: Attachment
|
|
17
18
|
): { valid: true } | { valid: false; reason: string } {
|
|
@@ -38,10 +39,10 @@ export class FileAttachmentHandler implements IAttachmentHandler {
|
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
if (sourceFile.size >
|
|
42
|
+
if (sourceFile.size > MAX_FILE_SIZE) {
|
|
42
43
|
return {
|
|
43
44
|
valid: false,
|
|
44
|
-
reason: `File size exceeds maximum (${
|
|
45
|
+
reason: `File size exceeds maximum (${MAX_FILE_SIZE / 1024 / 1024}MB)`,
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -60,7 +61,7 @@ export class FileAttachmentHandler implements IAttachmentHandler {
|
|
|
60
61
|
fileName: sourceFile.filename,
|
|
61
62
|
fileSize: sourceFile.size,
|
|
62
63
|
fileType: sourceFile.mimeType,
|
|
63
|
-
|
|
64
|
+
sourceUrl: uploadedUrl,
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
console.warn('[FileAttachmentHandler] Built payload', {
|
|
@@ -68,7 +69,7 @@ export class FileAttachmentHandler implements IAttachmentHandler {
|
|
|
68
69
|
fileName: fileElem.fileName,
|
|
69
70
|
fileSize: fileElem.fileSize,
|
|
70
71
|
fileType: fileElem.fileType,
|
|
71
|
-
|
|
72
|
+
sourceUrl: uploadedUrl.substring(0, 50) + '...',
|
|
72
73
|
});
|
|
73
74
|
|
|
74
75
|
return fileElem;
|
|
@@ -7,4 +7,7 @@ export function initializeAttachmentHandlers(): void {
|
|
|
7
7
|
|
|
8
8
|
export { ImageAttachmentHandler } from './imageAttachmentHandler';
|
|
9
9
|
export { default as VideoAttachmentHandler } from './videoAttachmentHandler';
|
|
10
|
-
export {
|
|
10
|
+
export {
|
|
11
|
+
default as FileAttachmentHandler,
|
|
12
|
+
MAX_FILE_SIZE,
|
|
13
|
+
} from './fileAttachmentHandler';
|
|
@@ -18,7 +18,7 @@ interface VideoPicInfo {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export class VideoAttachmentHandler implements IAttachmentHandler {
|
|
21
|
-
private static readonly MAX_VIDEO_SIZE =
|
|
21
|
+
private static readonly MAX_VIDEO_SIZE = 200 * 1024 * 1024; // 200MB
|
|
22
22
|
private static readonly SUPPORTED_TYPES = ['video/mp4', 'video/quicktime'];
|
|
23
23
|
|
|
24
24
|
validate(
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
const i18nKey: Record<string, string> = {
|
|
2
2
|
'thread_card_bot_crm_name': 'Droppii Hỗ Trợ',
|
|
3
3
|
'thread_card_fallback_name': 'Người dùng',
|
|
4
|
+
'chat:file_too_large': 'Tệp quá lớn. Tối đa 10MB',
|
|
5
|
+
'chat:file_max_count': 'Chỉ có thể đính kèm tối đa 3 tệp',
|
|
6
|
+
'chat:file_pick_failed': 'Không thể chọn tệp',
|
|
7
|
+
'chat:file_upload_failed': 'Lỗi tải tệp lên',
|
|
8
|
+
'chat:file_preview_unsupported': 'Không thể xem trước tệp này',
|
|
9
|
+
'chat:file_downloading': 'Đang tải {{received}}/{{total}} MB',
|
|
10
|
+
'chat:file_downloaded_success': 'Đã tải thành công {{fileName}}',
|
|
11
|
+
'chat:file_download_failed': 'Tải tệp thất bại',
|
|
12
|
+
'chat:file_open_failed': 'Không thể mở tệp này',
|
|
4
13
|
'chat:image_preview': 'Xem trước ảnh',
|
|
5
14
|
'chat:image_too_large': 'Ảnh quá lớn. Tối đa 5MB',
|
|
15
|
+
'chat:video_too_large': 'Video quá lớn. Tối đa 200MB',
|
|
6
16
|
'chat:image_sent': 'Đã gửi ảnh',
|
|
7
17
|
'chat:image_upload_failed': 'Lỗi tải ảnh',
|
|
8
18
|
'chat:failed_to_send_message': 'Không thể gửi tin nhắn. Thử lại?',
|
package/src/types/attachment.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type AttachmentType = 'image' | 'video' | 'file' | 'audio';
|
|
1
|
+
export type AttachmentType = 'image' | 'video' | 'file' | 'audio' | 'document';
|
|
2
2
|
|
|
3
3
|
export interface BaseAttachment {
|
|
4
4
|
id: string;
|
|
@@ -83,3 +83,25 @@ export interface AttachmentSendResult {
|
|
|
83
83
|
mergedMessageId?: string;
|
|
84
84
|
errors: Record<string, string>;
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
interface AttachmentMetadata {
|
|
88
|
+
id?: string;
|
|
89
|
+
path: string;
|
|
90
|
+
filename?: string;
|
|
91
|
+
size?: number;
|
|
92
|
+
duration?: number;
|
|
93
|
+
mimeType?: string;
|
|
94
|
+
width?: number;
|
|
95
|
+
height?: number;
|
|
96
|
+
uri?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface AttachmentItem {
|
|
100
|
+
metadata: AttachmentMetadata;
|
|
101
|
+
uploadProgress: number;
|
|
102
|
+
error: string | null;
|
|
103
|
+
isUploading: boolean;
|
|
104
|
+
uploadedUrl?: string;
|
|
105
|
+
thumbnailUrl?: string;
|
|
106
|
+
type: AttachmentType;
|
|
107
|
+
}
|
package/src/utils/device.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import ImagePicker from 'react-native-image-crop-picker';
|
|
2
|
+
import {
|
|
3
|
+
pick as pickDocument,
|
|
4
|
+
types as documentTypes,
|
|
5
|
+
isErrorWithCode,
|
|
6
|
+
errorCodes,
|
|
7
|
+
keepLocalCopy,
|
|
8
|
+
} from '@react-native-documents/picker';
|
|
9
|
+
|
|
10
|
+
export interface PickedFile {
|
|
11
|
+
uri: string;
|
|
12
|
+
name: string;
|
|
13
|
+
size: number;
|
|
14
|
+
mimeType: string;
|
|
15
|
+
}
|
|
2
16
|
|
|
3
17
|
const DeviceUtils = {
|
|
4
18
|
openImagePicker: async (multiple: boolean = false) => {
|
|
@@ -68,6 +82,50 @@ const DeviceUtils = {
|
|
|
68
82
|
throw error;
|
|
69
83
|
}
|
|
70
84
|
},
|
|
85
|
+
|
|
86
|
+
openFilePicker: async (
|
|
87
|
+
multiple: boolean = false
|
|
88
|
+
): Promise<PickedFile[] | null> => {
|
|
89
|
+
try {
|
|
90
|
+
const results = await pickDocument({
|
|
91
|
+
allowMultiSelection: multiple,
|
|
92
|
+
type: [documentTypes.allFiles],
|
|
93
|
+
mode: 'import',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Copy picked files to app's document directory so uploads can access them
|
|
97
|
+
const copies = await keepLocalCopy({
|
|
98
|
+
files: results.map((r) => ({
|
|
99
|
+
uri: r.uri,
|
|
100
|
+
fileName: r.name ?? 'file',
|
|
101
|
+
})) as [
|
|
102
|
+
{ uri: string; fileName: string },
|
|
103
|
+
...{ uri: string; fileName: string }[],
|
|
104
|
+
],
|
|
105
|
+
destination: 'documentDirectory',
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const files = results.map((r, i) => ({
|
|
109
|
+
uri: decodeURIComponent(
|
|
110
|
+
copies[i]?.status === 'success' ? copies[i].localUri : r.uri
|
|
111
|
+
),
|
|
112
|
+
name: r.name ?? 'file',
|
|
113
|
+
size: r.size ?? 0,
|
|
114
|
+
mimeType: r.type ?? 'application/octet-stream',
|
|
115
|
+
}));
|
|
116
|
+
|
|
117
|
+
return files;
|
|
118
|
+
} catch (error: any) {
|
|
119
|
+
if (
|
|
120
|
+
isErrorWithCode(error) &&
|
|
121
|
+
error.code === errorCodes.OPERATION_CANCELED
|
|
122
|
+
) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
console.error('[File Picker] Error:', error);
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
},
|
|
71
129
|
};
|
|
72
130
|
|
|
73
131
|
export default DeviceUtils;
|
package/src/utils/imageUtils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ImageFile } from '../types/imageUpload';
|
|
2
|
+
import Images from '../assets/images';
|
|
2
3
|
|
|
3
4
|
export const generateUUID = (): string => {
|
|
4
5
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
@@ -17,39 +18,60 @@ export const isVideoFromPicker = (pickedItem: any): boolean => {
|
|
|
17
18
|
return mime.startsWith('video/');
|
|
18
19
|
};
|
|
19
20
|
|
|
21
|
+
const mimeMap: Record<string, string> = {
|
|
22
|
+
jpg: 'image/jpeg',
|
|
23
|
+
jpeg: 'image/jpeg',
|
|
24
|
+
png: 'image/png',
|
|
25
|
+
webp: 'image/webp',
|
|
26
|
+
heic: 'image/heic',
|
|
27
|
+
heif: 'image/heif',
|
|
28
|
+
mp4: 'video/mp4',
|
|
29
|
+
mov: 'video/quicktime',
|
|
30
|
+
avi: 'video/x-msvideo',
|
|
31
|
+
mkv: 'video/x-matroska',
|
|
32
|
+
webm: 'video/webm',
|
|
33
|
+
m4v: 'video/mp4',
|
|
34
|
+
flv: 'video/x-flv',
|
|
35
|
+
wmv: 'video/x-ms-wmv',
|
|
36
|
+
mp3: 'audio/mpeg',
|
|
37
|
+
wav: 'audio/wav',
|
|
38
|
+
m4a: 'audio/mp4',
|
|
39
|
+
aac: 'audio/aac',
|
|
40
|
+
flac: 'audio/flac',
|
|
41
|
+
ogg: 'audio/ogg',
|
|
42
|
+
pdf: 'application/pdf',
|
|
43
|
+
doc: 'application/msword',
|
|
44
|
+
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
45
|
+
xls: 'application/vnd.ms-excel',
|
|
46
|
+
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
47
|
+
zip: 'application/zip',
|
|
48
|
+
};
|
|
49
|
+
|
|
20
50
|
export const getMimeType = (fileName: string): string => {
|
|
21
51
|
const ext = fileName.split('.').pop()?.toLowerCase();
|
|
22
|
-
const mimeMap: Record<string, string> = {
|
|
23
|
-
jpg: 'image/jpeg',
|
|
24
|
-
jpeg: 'image/jpeg',
|
|
25
|
-
png: 'image/png',
|
|
26
|
-
webp: 'image/webp',
|
|
27
|
-
heic: 'image/heic',
|
|
28
|
-
heif: 'image/heif',
|
|
29
|
-
mp4: 'video/mp4',
|
|
30
|
-
mov: 'video/quicktime',
|
|
31
|
-
avi: 'video/x-msvideo',
|
|
32
|
-
mkv: 'video/x-matroska',
|
|
33
|
-
webm: 'video/webm',
|
|
34
|
-
m4v: 'video/mp4',
|
|
35
|
-
flv: 'video/x-flv',
|
|
36
|
-
wmv: 'video/x-ms-wmv',
|
|
37
|
-
mp3: 'audio/mpeg',
|
|
38
|
-
wav: 'audio/wav',
|
|
39
|
-
m4a: 'audio/mp4',
|
|
40
|
-
aac: 'audio/aac',
|
|
41
|
-
flac: 'audio/flac',
|
|
42
|
-
ogg: 'audio/ogg',
|
|
43
|
-
pdf: 'application/pdf',
|
|
44
|
-
doc: 'application/msword',
|
|
45
|
-
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
46
|
-
xls: 'application/vnd.ms-excel',
|
|
47
|
-
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
48
|
-
zip: 'application/zip',
|
|
49
|
-
};
|
|
50
52
|
return mimeMap[ext || ''] || 'application/octet-stream';
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
export const getFileIcon = (mimeType?: string): number => {
|
|
56
|
+
if (mimeType?.startsWith('image/')) return Images.ICON_IMG;
|
|
57
|
+
|
|
58
|
+
switch (mimeType) {
|
|
59
|
+
case mimeMap.pdf:
|
|
60
|
+
return Images.ICON_PDF;
|
|
61
|
+
|
|
62
|
+
case mimeMap.doc:
|
|
63
|
+
case mimeMap.docx:
|
|
64
|
+
return Images.ICON_WORD;
|
|
65
|
+
|
|
66
|
+
case mimeMap.xls:
|
|
67
|
+
case mimeMap.xlsx:
|
|
68
|
+
return Images.ICON_EXCEL;
|
|
69
|
+
|
|
70
|
+
default:
|
|
71
|
+
return Images.ICON_TXT;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
53
75
|
export const formatFileSize = (bytes: number): string => {
|
|
54
76
|
if (bytes === 0) return '0 Bytes';
|
|
55
77
|
const k = 1024;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
1
2
|
import RNFS from 'react-native-fs';
|
|
2
3
|
import { createThumbnail } from 'react-native-create-thumbnail';
|
|
3
4
|
|
|
@@ -13,6 +14,64 @@ interface ThumbnailResult {
|
|
|
13
14
|
height: number;
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Routes the video source so react-native-create-thumbnail picks the correct
|
|
19
|
+
* native MediaMetadataRetriever.setDataSource overload.
|
|
20
|
+
*
|
|
21
|
+
* Root cause of the Android crash: CreateThumbnailModule.getBitmapAtTime branches
|
|
22
|
+
* on the URL scheme —
|
|
23
|
+
* - "file://..." -> setDataSource(String) ✅ works for local files
|
|
24
|
+
* - "content://" -> setDataSource(Context, Uri)
|
|
25
|
+
* - otherwise -> setDataSource(String, Map headers) ❌ this overload is for
|
|
26
|
+
* REMOTE URIs; a bare local path makes it throw an uncaught
|
|
27
|
+
* RuntimeException (status 0xFFFFFFEA / EINVAL) → app crash.
|
|
28
|
+
* The app strips "file://" before calling, so local videos fall into the broken
|
|
29
|
+
* branch. The fix is to KEEP the file:// scheme so the working overload is used.
|
|
30
|
+
*
|
|
31
|
+
* For Android photo-picker synthetic paths we additionally copy the file into the
|
|
32
|
+
* app cache first (a clean, app-private file the retriever can always open) and
|
|
33
|
+
* still hand it back with a file:// prefix. Returns the path to pass to
|
|
34
|
+
* createThumbnail plus a raw cleanup path for any temp copy.
|
|
35
|
+
*/
|
|
36
|
+
const ensureRetrievableVideoPath = async (
|
|
37
|
+
videoPath: string
|
|
38
|
+
): Promise<{ path: string; cleanupPath: string | null }> => {
|
|
39
|
+
// iOS (and any non-Android platform) is left completely untouched.
|
|
40
|
+
if (Platform.OS !== 'android') {
|
|
41
|
+
return { path: videoPath, cleanupPath: null };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// content:// is handled by a dedicated native branch — pass through unchanged.
|
|
45
|
+
if (videoPath.startsWith('content://')) {
|
|
46
|
+
return { path: videoPath, cleanupPath: null };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const rawPath = videoPath.startsWith('file://')
|
|
50
|
+
? videoPath.replace('file://', '')
|
|
51
|
+
: videoPath;
|
|
52
|
+
|
|
53
|
+
const isSynthetic =
|
|
54
|
+
rawPath.includes('/.transforms/') || rawPath.includes('/synthetic/');
|
|
55
|
+
|
|
56
|
+
if (isSynthetic) {
|
|
57
|
+
const ext = (rawPath.split('.').pop() || 'mp4').split('?')[0];
|
|
58
|
+
const dest = `${RNFS.CachesDirectoryPath}/video-thumb-src-${Date.now()}-${Math.floor(
|
|
59
|
+
Math.random() * 1e6
|
|
60
|
+
)}.${ext}`;
|
|
61
|
+
|
|
62
|
+
console.log(
|
|
63
|
+
'[VideoThumbnail] Copying picker video to cache before thumbnail',
|
|
64
|
+
{ from: rawPath, to: dest }
|
|
65
|
+
);
|
|
66
|
+
await RNFS.copyFile(rawPath, dest);
|
|
67
|
+
return { path: `file://${dest}`, cleanupPath: dest };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Any other local path: ensure the file:// scheme so the native module routes
|
|
71
|
+
// to setDataSource(String) instead of the broken (String, Map) overload.
|
|
72
|
+
return { path: `file://${rawPath}`, cleanupPath: null };
|
|
73
|
+
};
|
|
74
|
+
|
|
16
75
|
export const VideoThumbnailUtil = {
|
|
17
76
|
generateThumbnail: async (
|
|
18
77
|
videoPath: string,
|
|
@@ -20,10 +79,18 @@ export const VideoThumbnailUtil = {
|
|
|
20
79
|
): Promise<ThumbnailResult | null> => {
|
|
21
80
|
const { time = 800, quality = 80, cacheId } = options; // time in milliseconds
|
|
22
81
|
|
|
82
|
+
let tempSourcePath: string | null = null;
|
|
83
|
+
|
|
23
84
|
try {
|
|
85
|
+
// Normalize the source so the native MediaMetadataRetriever can open it.
|
|
86
|
+
// Android picker paths crash the app otherwise (see ensureRetrievableVideoPath).
|
|
87
|
+
const { path: retrievablePath, cleanupPath } =
|
|
88
|
+
await ensureRetrievableVideoPath(videoPath);
|
|
89
|
+
tempSourcePath = cleanupPath;
|
|
90
|
+
|
|
24
91
|
// Generate unique cache name per video to avoid conflicts with concurrent generations
|
|
25
92
|
// Uses provided cacheId or generates one from videoPath filename
|
|
26
|
-
const fileName =
|
|
93
|
+
const fileName = retrievablePath.split('/').pop() || String(Date.now());
|
|
27
94
|
const cacheName =
|
|
28
95
|
cacheId ||
|
|
29
96
|
`thumb-${fileName.replace(/[^a-zA-Z0-9-_]/g, '')}-${Math.abs(
|
|
@@ -31,14 +98,14 @@ export const VideoThumbnailUtil = {
|
|
|
31
98
|
)}`;
|
|
32
99
|
|
|
33
100
|
console.log('[VideoThumbnail] Generating thumbnail', {
|
|
34
|
-
videoPath,
|
|
101
|
+
videoPath: retrievablePath,
|
|
35
102
|
timeMs: time,
|
|
36
103
|
quality,
|
|
37
104
|
cacheName,
|
|
38
105
|
});
|
|
39
106
|
|
|
40
107
|
const result = await createThumbnail({
|
|
41
|
-
url:
|
|
108
|
+
url: retrievablePath,
|
|
42
109
|
timeStamp: time,
|
|
43
110
|
format: 'png',
|
|
44
111
|
dirSize: 100,
|
|
@@ -60,6 +127,13 @@ export const VideoThumbnailUtil = {
|
|
|
60
127
|
} catch (error) {
|
|
61
128
|
console.error('[VideoThumbnail] Failed to generate thumbnail', error);
|
|
62
129
|
return null;
|
|
130
|
+
} finally {
|
|
131
|
+
// Remove the temporary video copy made for synthetic/content sources.
|
|
132
|
+
if (tempSourcePath) {
|
|
133
|
+
RNFS.unlink(tempSourcePath).catch((err) =>
|
|
134
|
+
console.warn('[VideoThumbnail] Temp source cleanup failed:', err)
|
|
135
|
+
);
|
|
136
|
+
}
|
|
63
137
|
}
|
|
64
138
|
},
|
|
65
139
|
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { memo } from 'react';
|
|
4
|
-
import { ScrollView, StyleSheet } from 'react-native';
|
|
5
|
-
import { KContainer, KImage, KColors, KLabel } from '@droppii/libs';
|
|
6
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
7
|
-
const formatDuration = seconds => {
|
|
8
|
-
const mins = Math.floor(seconds / 60);
|
|
9
|
-
const secs = seconds % 60;
|
|
10
|
-
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
11
|
-
};
|
|
12
|
-
const getAttachmentIcon = type => {
|
|
13
|
-
switch (type) {
|
|
14
|
-
case 'image':
|
|
15
|
-
return 'image';
|
|
16
|
-
case 'video':
|
|
17
|
-
return 'play-circle';
|
|
18
|
-
case 'audio':
|
|
19
|
-
return 'music';
|
|
20
|
-
case 'document':
|
|
21
|
-
return 'file-document';
|
|
22
|
-
case 'file':
|
|
23
|
-
default:
|
|
24
|
-
return 'file';
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
export const AttachmentPreview = /*#__PURE__*/memo(({
|
|
28
|
-
visible,
|
|
29
|
-
attachments,
|
|
30
|
-
onRemove
|
|
31
|
-
}) => {
|
|
32
|
-
if (!visible || !attachments?.length) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
return /*#__PURE__*/_jsx(KContainer.View, {
|
|
36
|
-
paddingH: "0.75rem"
|
|
37
|
-
// paddingV="0.75rem"
|
|
38
|
-
,
|
|
39
|
-
brW: 1,
|
|
40
|
-
brC: KColors.palette.gray.w100,
|
|
41
|
-
background: KColors.white,
|
|
42
|
-
style: styles.container,
|
|
43
|
-
children: /*#__PURE__*/_jsx(KContainer.View, {
|
|
44
|
-
row: true,
|
|
45
|
-
alignItems: true,
|
|
46
|
-
minH: 70,
|
|
47
|
-
children: /*#__PURE__*/_jsx(KContainer.View, {
|
|
48
|
-
flex: true,
|
|
49
|
-
children: /*#__PURE__*/_jsx(ScrollView, {
|
|
50
|
-
horizontal: true,
|
|
51
|
-
showsHorizontalScrollIndicator: false,
|
|
52
|
-
scrollEventThrottle: 16,
|
|
53
|
-
contentContainerStyle: {
|
|
54
|
-
alignItems: 'center'
|
|
55
|
-
},
|
|
56
|
-
children: attachments.map((item, index) => {
|
|
57
|
-
const {
|
|
58
|
-
type,
|
|
59
|
-
metadata,
|
|
60
|
-
uploadProgress,
|
|
61
|
-
error,
|
|
62
|
-
isUploading,
|
|
63
|
-
thumbnailUrl
|
|
64
|
-
} = item;
|
|
65
|
-
const isImage = type === 'image';
|
|
66
|
-
const isVideo = type === 'video';
|
|
67
|
-
const hasPreview = isImage || isVideo;
|
|
68
|
-
return /*#__PURE__*/_jsxs(KContainer.View, {
|
|
69
|
-
children: [/*#__PURE__*/_jsxs(KContainer.View, {
|
|
70
|
-
style: styles.thumbnail,
|
|
71
|
-
center: true,
|
|
72
|
-
children: [isVideo && thumbnailUrl && /*#__PURE__*/_jsx(KImage.Base, {
|
|
73
|
-
uri: thumbnailUrl,
|
|
74
|
-
width: 48,
|
|
75
|
-
height: 48,
|
|
76
|
-
resizeMode: "cover"
|
|
77
|
-
}), isVideo && !thumbnailUrl && /*#__PURE__*/_jsx(KContainer.View, {
|
|
78
|
-
style: [styles.videoBg, styles.videoThumbnail]
|
|
79
|
-
}), isImage && /*#__PURE__*/_jsx(KImage.Base, {
|
|
80
|
-
uri: `file://${metadata.path}`,
|
|
81
|
-
width: 48,
|
|
82
|
-
height: 48
|
|
83
|
-
}), !hasPreview && /*#__PURE__*/_jsx(KContainer.View, {
|
|
84
|
-
style: styles.iconOverlay,
|
|
85
|
-
center: true,
|
|
86
|
-
background: KColors.palette.gray.w100,
|
|
87
|
-
children: /*#__PURE__*/_jsx(KImage.VectorIcons, {
|
|
88
|
-
name: getAttachmentIcon(type),
|
|
89
|
-
provider: "MaterialCommunityIcons",
|
|
90
|
-
size: 24,
|
|
91
|
-
color: KColors.palette.primary.w400
|
|
92
|
-
})
|
|
93
|
-
}), isVideo && metadata.duration && /*#__PURE__*/_jsx(KContainer.View, {
|
|
94
|
-
style: styles.durationBadge,
|
|
95
|
-
center: true,
|
|
96
|
-
children: /*#__PURE__*/_jsx(KLabel.Text, {
|
|
97
|
-
typo: "TextXsNormal",
|
|
98
|
-
color: KColors.white,
|
|
99
|
-
style: styles.durationText,
|
|
100
|
-
children: formatDuration(metadata.duration / 1000)
|
|
101
|
-
})
|
|
102
|
-
}), !hasPreview && /*#__PURE__*/_jsx(KContainer.View, {
|
|
103
|
-
style: styles.typeIcon,
|
|
104
|
-
center: true,
|
|
105
|
-
children: /*#__PURE__*/_jsx(KImage.VectorIcons, {
|
|
106
|
-
name: getAttachmentIcon(type),
|
|
107
|
-
provider: "MaterialCommunityIcons",
|
|
108
|
-
size: 14,
|
|
109
|
-
color: KColors.white
|
|
110
|
-
})
|
|
111
|
-
}), error && /*#__PURE__*/_jsx(KContainer.View, {
|
|
112
|
-
style: styles.errorOverlay,
|
|
113
|
-
center: true,
|
|
114
|
-
children: /*#__PURE__*/_jsx(KImage.VectorIcons, {
|
|
115
|
-
name: "close-circle",
|
|
116
|
-
provider: "MaterialCommunityIcons",
|
|
117
|
-
size: 28,
|
|
118
|
-
color: KColors.white
|
|
119
|
-
})
|
|
120
|
-
}), isUploading && /*#__PURE__*/_jsx(KContainer.View, {
|
|
121
|
-
style: styles.progressOverlay,
|
|
122
|
-
center: true,
|
|
123
|
-
children: /*#__PURE__*/_jsxs(KLabel.Text, {
|
|
124
|
-
typo: "TextSmNormal",
|
|
125
|
-
color: KColors.white,
|
|
126
|
-
children: [uploadProgress, "%"]
|
|
127
|
-
})
|
|
128
|
-
})]
|
|
129
|
-
}), /*#__PURE__*/_jsx(KContainer.Touchable, {
|
|
130
|
-
style: styles.removeButton,
|
|
131
|
-
center: true,
|
|
132
|
-
br: "round",
|
|
133
|
-
background: KColors.black,
|
|
134
|
-
onPress: () => onRemove(type, index),
|
|
135
|
-
disabled: isUploading,
|
|
136
|
-
hitSlop: {
|
|
137
|
-
top: 10,
|
|
138
|
-
bottom: 10,
|
|
139
|
-
left: 10,
|
|
140
|
-
right: 10
|
|
141
|
-
},
|
|
142
|
-
children: /*#__PURE__*/_jsx(KImage.VectorIcons, {
|
|
143
|
-
name: "close",
|
|
144
|
-
provider: "MaterialCommunityIcons",
|
|
145
|
-
size: 14,
|
|
146
|
-
color: KColors.white
|
|
147
|
-
})
|
|
148
|
-
})]
|
|
149
|
-
}, `${type}-${index}`);
|
|
150
|
-
})
|
|
151
|
-
})
|
|
152
|
-
})
|
|
153
|
-
})
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
AttachmentPreview.displayName = 'AttachmentPreview';
|
|
157
|
-
const styles = StyleSheet.create({
|
|
158
|
-
container: {
|
|
159
|
-
// minHeight: 80,
|
|
160
|
-
},
|
|
161
|
-
thumbnail: {
|
|
162
|
-
position: 'relative',
|
|
163
|
-
width: 48,
|
|
164
|
-
height: 48,
|
|
165
|
-
borderRadius: 4,
|
|
166
|
-
overflow: 'hidden',
|
|
167
|
-
marginRight: 8,
|
|
168
|
-
backgroundColor: KColors.palette.gray.w50
|
|
169
|
-
},
|
|
170
|
-
durationBadge: {
|
|
171
|
-
position: 'absolute',
|
|
172
|
-
bottom: 4,
|
|
173
|
-
right: 4,
|
|
174
|
-
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
175
|
-
borderRadius: 3,
|
|
176
|
-
paddingVertical: 2,
|
|
177
|
-
paddingHorizontal: 4
|
|
178
|
-
},
|
|
179
|
-
durationText: {
|
|
180
|
-
fontSize: 11,
|
|
181
|
-
fontWeight: '600'
|
|
182
|
-
},
|
|
183
|
-
iconOverlay: {
|
|
184
|
-
width: 48,
|
|
185
|
-
height: 48,
|
|
186
|
-
borderRadius: 4
|
|
187
|
-
},
|
|
188
|
-
videoIcon: {
|
|
189
|
-
position: 'absolute',
|
|
190
|
-
top: 2,
|
|
191
|
-
right: 2,
|
|
192
|
-
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
193
|
-
borderRadius: 8,
|
|
194
|
-
width: 20,
|
|
195
|
-
height: 20
|
|
196
|
-
},
|
|
197
|
-
typeIcon: {
|
|
198
|
-
position: 'absolute',
|
|
199
|
-
bottom: 2,
|
|
200
|
-
right: 2,
|
|
201
|
-
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
202
|
-
borderRadius: 6,
|
|
203
|
-
width: 16,
|
|
204
|
-
height: 16
|
|
205
|
-
},
|
|
206
|
-
videoBg: {
|
|
207
|
-
width: 48,
|
|
208
|
-
height: 48,
|
|
209
|
-
borderRadius: 4
|
|
210
|
-
},
|
|
211
|
-
videoThumbnail: {
|
|
212
|
-
backgroundColor: KColors.black
|
|
213
|
-
},
|
|
214
|
-
progressOverlay: {
|
|
215
|
-
position: 'absolute',
|
|
216
|
-
top: 0,
|
|
217
|
-
left: 0,
|
|
218
|
-
right: 0,
|
|
219
|
-
bottom: 0,
|
|
220
|
-
backgroundColor: 'rgba(0, 0, 0, 0.6)'
|
|
221
|
-
},
|
|
222
|
-
errorOverlay: {
|
|
223
|
-
position: 'absolute',
|
|
224
|
-
top: 0,
|
|
225
|
-
left: 0,
|
|
226
|
-
right: 0,
|
|
227
|
-
bottom: 0,
|
|
228
|
-
backgroundColor: 'rgba(255, 59, 48, 0.8)'
|
|
229
|
-
},
|
|
230
|
-
removeButton: {
|
|
231
|
-
position: 'absolute',
|
|
232
|
-
top: -8,
|
|
233
|
-
right: 2,
|
|
234
|
-
width: 22,
|
|
235
|
-
height: 22,
|
|
236
|
-
shadowColor: '#000',
|
|
237
|
-
shadowOffset: {
|
|
238
|
-
width: 0,
|
|
239
|
-
height: 1
|
|
240
|
-
},
|
|
241
|
-
shadowOpacity: 0.2,
|
|
242
|
-
shadowRadius: 2,
|
|
243
|
-
elevation: 3
|
|
244
|
-
},
|
|
245
|
-
sendButton: {
|
|
246
|
-
width: 48,
|
|
247
|
-
height: 48
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
//# sourceMappingURL=AttachmentPreview.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["memo","ScrollView","StyleSheet","KContainer","KImage","KColors","KLabel","jsx","_jsx","jsxs","_jsxs","formatDuration","seconds","mins","Math","floor","secs","toString","padStart","getAttachmentIcon","type","AttachmentPreview","visible","attachments","onRemove","length","View","paddingH","brW","brC","palette","gray","w100","background","white","style","styles","container","children","row","alignItems","minH","flex","horizontal","showsHorizontalScrollIndicator","scrollEventThrottle","contentContainerStyle","map","item","index","metadata","uploadProgress","error","isUploading","thumbnailUrl","isImage","isVideo","hasPreview","thumbnail","center","Base","uri","width","height","resizeMode","videoBg","videoThumbnail","path","iconOverlay","VectorIcons","name","provider","size","color","primary","w400","duration","durationBadge","Text","typo","durationText","typeIcon","errorOverlay","progressOverlay","Touchable","removeButton","br","black","onPress","disabled","hitSlop","top","bottom","left","right","displayName","create","position","borderRadius","overflow","marginRight","backgroundColor","w50","paddingVertical","paddingHorizontal","fontSize","fontWeight","videoIcon","shadowColor","shadowOffset","shadowOpacity","shadowRadius","elevation","sendButton"],"sourceRoot":"../../../src","sources":["components/AttachmentPreview.tsx"],"mappings":"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","ignoreList":[]}
|