11import React from 'react' ;
22
3- import { Alert , ImageBackground , StyleSheet , Text , View } from 'react-native' ;
3+ import { Alert , ImageBackground , Platform , StyleSheet , Text , View } from 'react-native' ;
44
55import { TouchableOpacity } from '@gorhom/bottom-sheet' ;
66import dayjs from 'dayjs' ;
77import { lookup } from 'mime-types' ;
88
9+ import type { AttachmentPickerContextValue } from '../../../contexts/attachmentPickerContext/AttachmentPickerContext' ;
910import { useTheme } from '../../../contexts/themeContext/ThemeContext' ;
1011import { Recorder } from '../../../icons' ;
12+ import { getLocalAssetUri } from '../../../native' ;
1113import type { Asset , File } from '../../../types/types' ;
1214import { vw } from '../../../utils/utils' ;
1315
14- type AttachmentPickerItemType = {
16+ type AttachmentPickerItemType = Pick <
17+ AttachmentPickerContextValue ,
18+ 'selectedFiles' | 'setSelectedFiles' | 'setSelectedImages' | 'selectedImages' | 'maxNumberOfFiles'
19+ > & {
1520 asset : Asset ;
1621 ImageOverlaySelectedComponent : React . ComponentType ;
17- maxNumberOfFiles : number ;
1822 numberOfUploads : number ;
1923 selected : boolean ;
20- setSelectedFiles : React . Dispatch < React . SetStateAction < File [ ] > > ;
21- setSelectedImages : React . Dispatch < React . SetStateAction < Asset [ ] > > ;
2224 numberOfAttachmentPickerImageColumns ?: number ;
2325} ;
2426
25- type AttachmentImageProps = Omit < AttachmentPickerItemType , 'setSelectedFiles' > ;
27+ type AttachmentImageProps = Omit < AttachmentPickerItemType , 'setSelectedFiles' | 'selectedFiles' > ;
2628
27- type AttachmentVideoProps = Omit < AttachmentPickerItemType , 'setSelectedImages' > ;
29+ type AttachmentVideoProps = Omit < AttachmentPickerItemType , 'setSelectedImages' | 'selectedImages' > ;
2830
2931const AttachmentVideo : React . FC < AttachmentVideoProps > = ( props ) => {
3032 const {
@@ -34,6 +36,7 @@ const AttachmentVideo: React.FC<AttachmentVideoProps> = (props) => {
3436 numberOfAttachmentPickerImageColumns,
3537 numberOfUploads,
3638 selected,
39+ selectedFiles,
3740 setSelectedFiles,
3841 } = props ;
3942
@@ -61,29 +64,43 @@ const AttachmentVideo: React.FC<AttachmentVideoProps> = (props) => {
6164
6265 const size = vw ( 100 ) / ( numberOfAttachmentPickerImageColumns || 3 ) - 2 ;
6366
67+ /* Patches video files with uri and mimetype */
68+ const patchVideoFile = async ( files : File [ ] ) => {
69+ // For the case of Expo CLI where you need to fetch the file uri from file id. Here it is only done for iOS since for android the file.uri is fine.
70+ const localAssetURI = Platform . OS === 'ios' && asset . id && ( await getLocalAssetUri ( asset . id ) ) ;
71+ const uri = localAssetURI || asset . uri || '' ;
72+ // We need a mime-type to upload a video file.
73+ const mimeType = lookup ( asset . filename ) || 'multipart/form-data' ;
74+ return [
75+ ...files ,
76+ {
77+ duration : durationLabel ,
78+ id : asset . id ,
79+ mimeType,
80+ name : asset . filename ,
81+ size : asset . fileSize ,
82+ uri,
83+ } ,
84+ ] ;
85+ } ;
86+
87+ const updateSelectedFiles = async ( ) => {
88+ if ( numberOfUploads >= maxNumberOfFiles ) {
89+ Alert . alert ( 'Maximum number of files reached' ) ;
90+ return ;
91+ }
92+ const files = await patchVideoFile ( selectedFiles ) ;
93+ setSelectedFiles ( files ) ;
94+ } ;
95+
6496 const onPressVideo = ( ) => {
6597 if ( selected ) {
66- setSelectedFiles ( ( files ) => files . filter ( ( file ) => file . uri !== asset . uri ) ) ;
98+ setSelectedFiles ( ( files ) =>
99+ // `id` is available for Expo MediaLibrary while Cameraroll doesn't share id therefore we use `uri`
100+ files . filter ( ( file ) => ( file . id ? file . id !== asset . id : file . uri !== asset . uri ) ) ,
101+ ) ;
67102 } else {
68- setSelectedFiles ( ( files ) => {
69- if ( numberOfUploads >= maxNumberOfFiles ) {
70- Alert . alert ( 'Maximum number of files reached' ) ;
71- return files ;
72- }
73- // We need a mime-type to upload a video file.
74- const mimeType = lookup ( asset . filename ) || 'multipart/form-data' ;
75- return [
76- ...files ,
77- {
78- duration : durationLabel ,
79- id : asset . id ,
80- mimeType,
81- name : asset . filename ,
82- size : asset . fileSize ,
83- uri : asset . uri ,
84- } ,
85- ] ;
86- } ) ;
103+ updateSelectedFiles ( ) ;
87104 }
88105 } ;
89106
@@ -126,6 +143,7 @@ const AttachmentImage: React.FC<AttachmentImageProps> = (props) => {
126143 numberOfAttachmentPickerImageColumns,
127144 numberOfUploads,
128145 selected,
146+ selectedImages,
129147 setSelectedImages,
130148 } = props ;
131149 const {
@@ -139,17 +157,37 @@ const AttachmentImage: React.FC<AttachmentImageProps> = (props) => {
139157
140158 const { uri } = asset ;
141159
160+ /* Patches image files with uri */
161+ const patchImageFile = async ( images : Asset [ ] ) => {
162+ // For the case of Expo CLI where you need to fetch the file uri from file id. Here it is only done for iOS since for android the file.uri is fine.
163+ const localAssetURI = Platform . OS === 'ios' && asset . id && ( await getLocalAssetUri ( asset . id ) ) ;
164+ const uri = localAssetURI || asset . uri || '' ;
165+ return [
166+ ...images ,
167+ {
168+ ...asset ,
169+ uri,
170+ } ,
171+ ] ;
172+ } ;
173+
174+ const updateSelectedImages = async ( ) => {
175+ if ( numberOfUploads >= maxNumberOfFiles ) {
176+ Alert . alert ( 'Maximum number of files reached' ) ;
177+ return ;
178+ }
179+ const images = await patchImageFile ( selectedImages ) ;
180+ setSelectedImages ( images ) ;
181+ } ;
182+
142183 const onPressImage = ( ) => {
143184 if ( selected ) {
144- setSelectedImages ( ( images ) => images . filter ( ( image ) => image . uri !== asset . uri ) ) ;
185+ // `id` is available for Expo MediaLibrary while Cameraroll doesn't share id therefore we use `uri`
186+ setSelectedImages ( ( images ) =>
187+ images . filter ( ( image ) => ( image . id ? image . id !== asset . id : image . uri !== asset . uri ) ) ,
188+ ) ;
145189 } else {
146- setSelectedImages ( ( images ) => {
147- if ( numberOfUploads >= maxNumberOfFiles ) {
148- Alert . alert ( 'Maximum number of files reached' ) ;
149- return images ;
150- }
151- return [ ...images , asset ] ;
152- } ) ;
190+ updateSelectedImages ( ) ;
153191 }
154192 } ;
155193
@@ -184,6 +222,8 @@ export const renderAttachmentPickerItem = ({ item }: { item: AttachmentPickerIte
184222 numberOfAttachmentPickerImageColumns,
185223 numberOfUploads,
186224 selected,
225+ selectedFiles,
226+ selectedImages,
187227 setSelectedFiles,
188228 setSelectedImages,
189229 } = item ;
@@ -205,6 +245,7 @@ export const renderAttachmentPickerItem = ({ item }: { item: AttachmentPickerIte
205245 numberOfAttachmentPickerImageColumns = { numberOfAttachmentPickerImageColumns }
206246 numberOfUploads = { numberOfUploads }
207247 selected = { selected }
248+ selectedFiles = { selectedFiles }
208249 setSelectedFiles = { setSelectedFiles }
209250 />
210251 ) ;
@@ -218,6 +259,7 @@ export const renderAttachmentPickerItem = ({ item }: { item: AttachmentPickerIte
218259 numberOfAttachmentPickerImageColumns = { numberOfAttachmentPickerImageColumns }
219260 numberOfUploads = { numberOfUploads }
220261 selected = { selected }
262+ selectedImages = { selectedImages }
221263 setSelectedImages = { setSelectedImages }
222264 />
223265 ) ;
0 commit comments