mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at no-pointer-events 213 lines 5.4 kB view raw
1import RNFetchBlob from 'rn-fetch-blob' 2import ImageResizer from '@bam.tech/react-native-image-resizer' 3import {Image as RNImage, Share as RNShare} from 'react-native' 4import {Image} from 'react-native-image-crop-picker' 5import * as RNFS from 'react-native-fs' 6import uuid from 'react-native-uuid' 7import * as Sharing from 'expo-sharing' 8import * as MediaLibrary from 'expo-media-library' 9import {Dimensions} from './types' 10import {isAndroid, isIOS} from 'platform/detection' 11 12export async function compressIfNeeded( 13 img: Image, 14 maxSize: number = 1000000, 15): Promise<Image> { 16 const origUri = `file://${img.path}` 17 if (img.size < maxSize) { 18 return img 19 } 20 const resizedImage = await doResize(origUri, { 21 width: img.width, 22 height: img.height, 23 mode: 'stretch', 24 maxSize, 25 }) 26 const finalImageMovedPath = await moveToPermanentPath(resizedImage.path) 27 const finalImg = { 28 ...resizedImage, 29 path: finalImageMovedPath, 30 } 31 return finalImg 32} 33 34export interface DownloadAndResizeOpts { 35 uri: string 36 width: number 37 height: number 38 mode: 'contain' | 'cover' | 'stretch' 39 maxSize: number 40 timeout: number 41} 42 43export async function downloadAndResize(opts: DownloadAndResizeOpts) { 44 let appendExt = 'jpeg' 45 try { 46 const urip = new URL(opts.uri) 47 const ext = urip.pathname.split('.').pop() 48 if (ext === 'png') { 49 appendExt = 'png' 50 } 51 } catch (e: any) { 52 console.error('Invalid URI', opts.uri, e) 53 return 54 } 55 56 let downloadRes 57 try { 58 const downloadResPromise = RNFetchBlob.config({ 59 fileCache: true, 60 appendExt, 61 }).fetch('GET', opts.uri) 62 const to1 = setTimeout(() => downloadResPromise.cancel(), opts.timeout) 63 downloadRes = await downloadResPromise 64 clearTimeout(to1) 65 66 let localUri = downloadRes.path() 67 if (!localUri.startsWith('file://')) { 68 localUri = `file://${localUri}` 69 } 70 71 return await doResize(localUri, opts) 72 } finally { 73 if (downloadRes) { 74 downloadRes.flush() 75 } 76 } 77} 78 79export async function shareImageModal({uri}: {uri: string}) { 80 if (!(await Sharing.isAvailableAsync())) { 81 // TODO might need to give an error to the user in this case -prf 82 return 83 } 84 const downloadResponse = await RNFetchBlob.config({ 85 fileCache: true, 86 }).fetch('GET', uri) 87 88 // NOTE 89 // assuming PNG 90 // we're currently relying on the fact our CDN only serves pngs 91 // -prf 92 93 let imagePath = downloadResponse.path() 94 imagePath = normalizePath(await moveToPermanentPath(imagePath, '.png'), true) 95 96 // NOTE 97 // for some reason expo-sharing refuses to work on iOS 98 // ...and visa versa 99 // -prf 100 if (isIOS) { 101 await RNShare.share({url: imagePath}) 102 } else { 103 await Sharing.shareAsync(imagePath, { 104 mimeType: 'image/png', 105 UTI: 'image/png', 106 }) 107 } 108 RNFS.unlink(imagePath) 109} 110 111export async function saveImageToMediaLibrary({uri}: {uri: string}) { 112 // download the file to cache 113 // NOTE 114 // assuming PNG 115 // we're currently relying on the fact our CDN only serves pngs 116 // -prf 117 const downloadResponse = await RNFetchBlob.config({ 118 fileCache: true, 119 }).fetch('GET', uri) 120 let imagePath = downloadResponse.path() 121 imagePath = normalizePath(await moveToPermanentPath(imagePath, '.png'), true) 122 123 // save 124 await MediaLibrary.createAssetAsync(imagePath) 125} 126 127export function getImageDim(path: string): Promise<Dimensions> { 128 return new Promise((resolve, reject) => { 129 RNImage.getSize( 130 path, 131 (width, height) => { 132 resolve({width, height}) 133 }, 134 reject, 135 ) 136 }) 137} 138 139// internal methods 140// = 141 142interface DoResizeOpts { 143 width: number 144 height: number 145 mode: 'contain' | 'cover' | 'stretch' 146 maxSize: number 147} 148 149async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> { 150 for (let i = 0; i < 9; i++) { 151 const quality = 100 - i * 10 152 const resizeRes = await ImageResizer.createResizedImage( 153 localUri, 154 opts.width, 155 opts.height, 156 'JPEG', 157 quality, 158 undefined, 159 undefined, 160 undefined, 161 {mode: opts.mode}, 162 ) 163 if (resizeRes.size < opts.maxSize) { 164 return { 165 path: normalizePath(resizeRes.path), 166 mime: 'image/jpeg', 167 size: resizeRes.size, 168 width: resizeRes.width, 169 height: resizeRes.height, 170 } 171 } 172 } 173 throw new Error( 174 `This image is too big! We couldn't compress it down to ${opts.maxSize} bytes`, 175 ) 176} 177 178async function moveToPermanentPath(path: string, ext = ''): Promise<string> { 179 /* 180 Since this package stores images in a temp directory, we need to move the file to a permanent location. 181 Relevant: IOS bug when trying to open a second time: 182 https://github.com/ivpusic/react-native-image-crop-picker/issues/1199 183 */ 184 const filename = uuid.v4() 185 186 const destinationPath = joinPath( 187 RNFS.TemporaryDirectoryPath, 188 `${filename}${ext}`, 189 ) 190 await RNFS.moveFile(path, destinationPath) 191 return normalizePath(destinationPath) 192} 193 194function joinPath(a: string, b: string) { 195 if (a.endsWith('/')) { 196 if (b.startsWith('/')) { 197 return a.slice(0, -1) + b 198 } 199 return a + b 200 } else if (b.startsWith('/')) { 201 return a + b 202 } 203 return a + '/' + b 204} 205 206function normalizePath(str: string, allPlatforms = false): string { 207 if (isAndroid || allPlatforms) { 208 if (!str.startsWith('file://')) { 209 return `file://${str}` 210 } 211 } 212 return str 213}