mirror of
https://github.com/KoalaSat/nostros.git
synced 2024-09-29 06:30:47 +00:00
Upload images (#215)
This commit is contained in:
commit
945446b5f0
25
frontend/Constants/Services/index.ts
Normal file
25
frontend/Constants/Services/index.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { nostrBuildUpload } from '../../Functions/ServicesFunctions/NostrBuildUpload'
|
||||
import { voidCatUpload } from '../../Functions/ServicesFunctions/VoidCatUpload'
|
||||
|
||||
export const imageHostingServices: Record<
|
||||
string,
|
||||
{
|
||||
uri: string
|
||||
uploadUrl: string
|
||||
donation: string
|
||||
sendFunction: (fileUri: string, fileType: string, filename: string) => Promise<string | null>
|
||||
}
|
||||
> = {
|
||||
voidCat: {
|
||||
uri: 'https://void.cat',
|
||||
uploadUrl: 'https://void.cat/upload',
|
||||
donation: 'https://void.cat/donate',
|
||||
sendFunction: voidCatUpload,
|
||||
},
|
||||
nostrBuild: {
|
||||
uri: 'https://nostr.build',
|
||||
uploadUrl: 'https://nostr.build/upload.php',
|
||||
donation: 'https://nostr.build',
|
||||
sendFunction: nostrBuildUpload,
|
||||
},
|
||||
}
|
@ -4,6 +4,8 @@ import { initDatabase } from '../Functions/DatabaseFunctions'
|
||||
import SInfo from 'react-native-sensitive-info'
|
||||
import { Linking, StyleSheet } from 'react-native'
|
||||
import { Text } from 'react-native-paper'
|
||||
import { Config } from '../Pages/ConfigPage'
|
||||
import { imageHostingServices } from '../Constants/Services'
|
||||
|
||||
export interface AppContextProps {
|
||||
init: () => void
|
||||
@ -16,6 +18,8 @@ export interface AppContextProps {
|
||||
showSensitive: boolean
|
||||
setShowSensitive: (showPublicImages: boolean) => void
|
||||
satoshi: 'kebab' | 'sats'
|
||||
imageHostingService: string
|
||||
setImageHostingService: (imageHostingService: string) => void
|
||||
setSatoshi: (showPublicImages: 'kebab' | 'sats') => void
|
||||
getSatoshiSymbol: (fontSize?: number) => JSX.Element
|
||||
}
|
||||
@ -36,6 +40,8 @@ export const initialAppContext: AppContextProps = {
|
||||
setShowSensitive: () => {},
|
||||
satoshi: 'kebab',
|
||||
setSatoshi: () => {},
|
||||
imageHostingService: Object.keys(imageHostingServices)[0],
|
||||
setImageHostingService: () => {},
|
||||
getSatoshiSymbol: () => <></>,
|
||||
}
|
||||
|
||||
@ -44,6 +50,9 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
|
||||
initialAppContext.showPublicImages,
|
||||
)
|
||||
const [showSensitive, setShowSensitive] = React.useState<boolean>(initialAppContext.showSensitive)
|
||||
const [imageHostingService, setImageHostingService] = React.useState<string>(
|
||||
initialAppContext.imageHostingService,
|
||||
)
|
||||
const [notificationSeenAt, setNotificationSeenAt] = React.useState<number>(0)
|
||||
const [satoshi, setSatoshi] = React.useState<'kebab' | 'sats'>(initialAppContext.satoshi)
|
||||
const [database, setDatabase] = useState<QuickSQLiteConnection | null>(null)
|
||||
@ -64,10 +73,14 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
|
||||
setShowSensitive(config.show_sensitive ?? initialAppContext.showSensitive)
|
||||
setSatoshi(config.satoshi)
|
||||
setNotificationSeenAt(config.last_notification_seen_at ?? 0)
|
||||
setImageHostingService(
|
||||
config.image_hosting_service ?? initialAppContext.imageHostingService,
|
||||
)
|
||||
} else {
|
||||
const config: Config = {
|
||||
show_public_images: initialAppContext.showPublicImages,
|
||||
show_sensitive: initialAppContext.showSensitive,
|
||||
image_hosting_service: initialAppContext.imageHostingService,
|
||||
satoshi: initialAppContext.satoshi,
|
||||
last_notification_seen_at: 0,
|
||||
last_pets_at: 0,
|
||||
@ -93,6 +106,8 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
|
||||
return (
|
||||
<AppContext.Provider
|
||||
value={{
|
||||
imageHostingService,
|
||||
setImageHostingService,
|
||||
init,
|
||||
loadingDb,
|
||||
database,
|
||||
|
@ -0,0 +1,33 @@
|
||||
import { imageHostingServices } from '../../../Constants/Services'
|
||||
import axios from 'axios'
|
||||
|
||||
export const nostrBuildUpload: (
|
||||
fileUri: string,
|
||||
fileType: string,
|
||||
fileName: string,
|
||||
) => Promise<string | null> = async (fileUri, fileType, fileName) => {
|
||||
return await new Promise<string | null>((resolve, reject) => {
|
||||
const formdata = new FormData()
|
||||
formdata.append('fileToUpload', {
|
||||
uri: fileUri,
|
||||
name: fileName,
|
||||
type: fileType,
|
||||
})
|
||||
formdata.append('submit', 'Upload Image')
|
||||
const headers = {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
}
|
||||
axios
|
||||
.post(imageHostingServices.nostrBuild.uploadUrl, formdata, {
|
||||
headers,
|
||||
})
|
||||
.then((response) => {
|
||||
const regExp = /(https:\/\/nostr.build\/i\/nostr.build.*)<\/b>/
|
||||
const imageUrl: string = response.data.match(regExp)[0].slice(0, -4)
|
||||
resolve(imageUrl)
|
||||
})
|
||||
.catch(() => {
|
||||
reject(new Error('Error uploading image'))
|
||||
})
|
||||
})
|
||||
}
|
39
frontend/Functions/ServicesFunctions/VoidCatUpload/index.ts
Normal file
39
frontend/Functions/ServicesFunctions/VoidCatUpload/index.ts
Normal file
@ -0,0 +1,39 @@
|
||||
// Thanks to v0l/snort for the nice code!
|
||||
// https://github.com/v0l/snort/blob/39fbe3b10f94b7542df01fb085e4f164aab15fca/src/Feed/VoidUpload.ts
|
||||
|
||||
import { imageHostingServices } from '../../../Constants/Services'
|
||||
import ReactNativeBlobUtil from 'react-native-blob-util'
|
||||
|
||||
export const voidCatUpload: (
|
||||
fileUri: string,
|
||||
fileType: string,
|
||||
fileName: string,
|
||||
) => Promise<string | null> = async (fileUri, fileType, fileName) => {
|
||||
const digest = await ReactNativeBlobUtil.fs.hash(fileUri, 'sha256')
|
||||
return await new Promise<string | null>((resolve, reject) => {
|
||||
ReactNativeBlobUtil.fetch(
|
||||
'POST',
|
||||
imageHostingServices.voidCat.uploadUrl,
|
||||
{
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'V-Content-Type': fileType,
|
||||
'V-Filename': fileName,
|
||||
'V-Full-Digest': digest,
|
||||
'V-Description': 'Uploaded from Nostros https://github.com/KoalaSat/nostros',
|
||||
'V-Strip-Metadata': 'true',
|
||||
},
|
||||
ReactNativeBlobUtil.wrap(fileUri),
|
||||
)
|
||||
.then((repsp) => JSON.parse(repsp.data))
|
||||
.then((data) => {
|
||||
if (data.ok) {
|
||||
resolve(`${imageHostingServices.voidCat.uri}/d/${data.file.id}.png`)
|
||||
} else {
|
||||
reject(new Error('Error uploading image'))
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
reject(new Error('Error uploading image'))
|
||||
})
|
||||
})
|
||||
}
|
@ -46,7 +46,9 @@
|
||||
"isContact": "Following",
|
||||
"isNotContact": "Not following",
|
||||
"contentWarning": "Sensitive content",
|
||||
"send": "Send"
|
||||
"send": "Send",
|
||||
"imageUploaded": "Your file has been uploaded.\nConsider donating to the service: {{uri}}",
|
||||
"imageUploadErro": "There was an error while trying to upload your file"
|
||||
},
|
||||
"menuItems": {
|
||||
"relays": "Relays",
|
||||
@ -61,7 +63,8 @@
|
||||
"configPage": {
|
||||
"showPublicImages": "Show images on public feed",
|
||||
"showSensitive": "Show sensitive notes",
|
||||
"satoshi": "Satoshi symbol"
|
||||
"satoshi": "Satoshi symbol",
|
||||
"imageHostingService": "Image hosting service"
|
||||
},
|
||||
"noteCard": {
|
||||
"answering": "Answer to {{pubkey}}",
|
||||
|
@ -61,7 +61,8 @@
|
||||
"configPage": {
|
||||
"showPublicImages": "Mostrar imágenes en feed global",
|
||||
"showSensitive": "Mostrar notas sensibles",
|
||||
"satoshi": "Símbolo de satoshi"
|
||||
"satoshi": "Símbolo de satoshi",
|
||||
"imageHostingService": "Servicio de subida de imágenes"
|
||||
},
|
||||
"noteCard": {
|
||||
"answering": "Responder a {{pubkey}}",
|
||||
|
@ -61,7 +61,8 @@
|
||||
"configPage": {
|
||||
"showPublicImages": "Afficher les images dans le flux global",
|
||||
"showSensitive": "Montrer les notes sensibles",
|
||||
"satoshi": "Symbole de satoshi"
|
||||
"satoshi": "Symbole de satoshi",
|
||||
"imageHostingService": "Image hosting service"
|
||||
},
|
||||
"noteCard": {
|
||||
"answering": "Répondre à {{pubkey}}",
|
||||
|
@ -56,7 +56,8 @@
|
||||
"followers": "{{followers}} followers",
|
||||
"configuration": "Настройки",
|
||||
"about": "Подроблее",
|
||||
"logout": "Выйти"
|
||||
"logout": "Выйти",
|
||||
"imageHostingService": "Хостинг изображений"
|
||||
},
|
||||
"configPage": {
|
||||
"showPublicImages": "Show images on public feed",
|
||||
|
@ -5,7 +5,16 @@ import { Divider, List, Switch, useTheme } from 'react-native-paper'
|
||||
import SInfo from 'react-native-sensitive-info'
|
||||
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import { Config } from '../../Functions/DatabaseFunctions/Config'
|
||||
import { imageHostingServices } from '../../Constants/Services'
|
||||
|
||||
export interface Config {
|
||||
satoshi: 'kebab' | 'sats'
|
||||
show_public_images: boolean
|
||||
show_sensitive: boolean
|
||||
last_notification_seen_at: number
|
||||
last_pets_at: number
|
||||
image_hosting_service: string
|
||||
}
|
||||
|
||||
export const ConfigPage: React.FC = () => {
|
||||
const theme = useTheme()
|
||||
@ -18,12 +27,15 @@ export const ConfigPage: React.FC = () => {
|
||||
setShowSensitive,
|
||||
satoshi,
|
||||
setSatoshi,
|
||||
imageHostingService,
|
||||
setImageHostingService,
|
||||
} = React.useContext(AppContext)
|
||||
const bottomSheetRef = React.useRef<RBSheet>(null)
|
||||
const bottomSheetSatoshiRef = React.useRef<RBSheet>(null)
|
||||
const bottomSheetImageHostingRef = React.useRef<RBSheet>(null)
|
||||
|
||||
React.useEffect(() => {}, [showPublicImages, showSensitive, satoshi])
|
||||
|
||||
const createOptions = React.useMemo(() => {
|
||||
const satoshiOptions = React.useMemo(() => {
|
||||
return [
|
||||
{
|
||||
key: 1,
|
||||
@ -35,7 +47,7 @@ export const ConfigPage: React.FC = () => {
|
||||
config.satoshi = 'kebab'
|
||||
SInfo.setItem('config', JSON.stringify(config), {})
|
||||
})
|
||||
bottomSheetRef.current?.close()
|
||||
bottomSheetSatoshiRef.current?.close()
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -48,12 +60,30 @@ export const ConfigPage: React.FC = () => {
|
||||
config.satoshi = 'sats'
|
||||
SInfo.setItem('config', JSON.stringify(config), {})
|
||||
})
|
||||
bottomSheetRef.current?.close()
|
||||
bottomSheetSatoshiRef.current?.close()
|
||||
},
|
||||
},
|
||||
]
|
||||
}, [])
|
||||
|
||||
const imageHostingOptions = React.useMemo(() => {
|
||||
return Object.keys(imageHostingServices).map((service, index) => {
|
||||
return {
|
||||
key: index,
|
||||
title: <Text>{imageHostingServices[service].uri}</Text>,
|
||||
onPress: () => {
|
||||
setImageHostingService(service)
|
||||
SInfo.getItem('config', {}).then((result) => {
|
||||
const config: Config = JSON.parse(result)
|
||||
config.image_hosting_service = service
|
||||
SInfo.setItem('config', JSON.stringify(config), {})
|
||||
})
|
||||
bottomSheetImageHostingRef.current?.close()
|
||||
},
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
const bottomSheetStyles = React.useMemo(() => {
|
||||
return {
|
||||
container: {
|
||||
@ -105,12 +135,30 @@ export const ConfigPage: React.FC = () => {
|
||||
/>
|
||||
<List.Item
|
||||
title={t('configPage.satoshi')}
|
||||
onPress={() => bottomSheetRef.current?.open()}
|
||||
onPress={() => bottomSheetSatoshiRef.current?.open()}
|
||||
right={() => getSatoshiSymbol(25)}
|
||||
/>
|
||||
<RBSheet ref={bottomSheetRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
||||
<List.Item
|
||||
title={t('configPage.imageHostingService')}
|
||||
onPress={() => bottomSheetImageHostingRef.current?.open()}
|
||||
right={() => <Text>{imageHostingServices[imageHostingService].uri}</Text>}
|
||||
/>
|
||||
<RBSheet ref={bottomSheetSatoshiRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
||||
<FlatList
|
||||
data={createOptions}
|
||||
data={satoshiOptions}
|
||||
renderItem={({ item }) => {
|
||||
return <List.Item key={item.key} title={item.title} onPress={item.onPress} />
|
||||
}}
|
||||
ItemSeparatorComponent={Divider}
|
||||
/>
|
||||
</RBSheet>
|
||||
<RBSheet
|
||||
ref={bottomSheetImageHostingRef}
|
||||
closeOnDragDown={true}
|
||||
customStyles={bottomSheetStyles}
|
||||
>
|
||||
<FlatList
|
||||
data={imageHostingOptions}
|
||||
renderItem={({ item }) => {
|
||||
return <List.Item key={item.key} title={item.title} onPress={item.onPress} />
|
||||
}}
|
||||
|
@ -6,6 +6,7 @@ import { UserContext } from '../../Contexts/UserContext'
|
||||
import { getUsers, User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getUnixTime from 'date-fns/getUnixTime'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import Logo from '../../Components/Logo'
|
||||
import { Button, Text, useTheme } from 'react-native-paper'
|
||||
@ -23,14 +24,17 @@ export const ProfileLoadPage: React.FC = () => {
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
debounce(() => {
|
||||
loadMeta()
|
||||
loadPets()
|
||||
}, 500)
|
||||
|
||||
return () => relayPool?.unsubscribe(['profile-load-notes', 'profile-load-meta-pets'])
|
||||
}, []),
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
loadMeta()
|
||||
loadPets()
|
||||
reloadUser()
|
||||
if (name) {
|
||||
|
@ -9,23 +9,35 @@ import { Note } from '../../Functions/DatabaseFunctions/Notes'
|
||||
import { getETags, getTaggedPubKeys } from '../../Functions/RelayFunctions/Events'
|
||||
import { getUsers, User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import { formatPubKey } from '../../Functions/RelayFunctions/Users'
|
||||
import { Button, Switch, Text, TextInput, TouchableRipple } from 'react-native-paper'
|
||||
import { launchImageLibrary } from 'react-native-image-picker'
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Snackbar,
|
||||
Switch,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableRipple,
|
||||
} from 'react-native-paper'
|
||||
import { UserContext } from '../../Contexts/UserContext'
|
||||
import { goBack } from '../../lib/Navigation'
|
||||
import { Kind } from 'nostr-tools'
|
||||
import ProfileData from '../../Components/ProfileData'
|
||||
import NoteCard from '../../Components/NoteCard'
|
||||
import { imageHostingServices } from '../../Constants/Services'
|
||||
|
||||
interface SendPageProps {
|
||||
route: { params: { note: Note; type?: 'reply' | 'repost' } | undefined }
|
||||
}
|
||||
|
||||
export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
||||
const { database } = useContext(AppContext)
|
||||
const { database, imageHostingService } = useContext(AppContext)
|
||||
const { publicKey } = useContext(UserContext)
|
||||
const { relayPool, lastConfirmationtId } = useContext(RelayPoolContext)
|
||||
const { t } = useTranslation('common')
|
||||
// state
|
||||
const [showNotification, setShowNotification] = useState<undefined | string>()
|
||||
const [uploadingFile, setUploadingFile] = useState<boolean>(false)
|
||||
const [content, setContent] = useState<string>('')
|
||||
const [contentWarning, setContentWarning] = useState<boolean>(false)
|
||||
const [userSuggestions, setUserSuggestions] = useState<User[]>([])
|
||||
@ -64,6 +76,32 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
||||
return `@${user.name ?? formatPubKey(user.id)}`
|
||||
}
|
||||
|
||||
const onUploadImage: () => void = async () => {
|
||||
launchImageLibrary({ selectionLimit: 1, quality: 0, mediaType: 'photo' }, async (result) => {
|
||||
const assets = result?.assets
|
||||
if (assets && assets.length > 0) {
|
||||
const file = assets[0]
|
||||
if (file.uri && file.type && file.fileName) {
|
||||
imageHostingServices[imageHostingService]
|
||||
.sendFunction(file.uri, file.type, file.fileName)
|
||||
.then((imageUri) => {
|
||||
setShowNotification('imageUploaded')
|
||||
setUploadingFile(false)
|
||||
setContent((prev) => `${prev}\n\n${imageUri}`)
|
||||
})
|
||||
.catch(() => {
|
||||
setShowNotification('imageUploadErro')
|
||||
setUploadingFile(false)
|
||||
})
|
||||
} else {
|
||||
setUploadingFile(false)
|
||||
}
|
||||
} else {
|
||||
setUploadingFile(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const onPressSend: () => void = () => {
|
||||
if (database && publicKey) {
|
||||
setIsSending(true)
|
||||
@ -178,15 +216,22 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
||||
// FIXME: can't find this color
|
||||
<View style={{ backgroundColor: '#001C37' }}>
|
||||
<View style={styles.contentWarning}>
|
||||
<Text>{t('sendPage.contentWarning')}</Text>
|
||||
<Text style={styles.contentWarningText}>{t('sendPage.contentWarning')}</Text>
|
||||
<Switch value={contentWarning} onValueChange={setContentWarning} />
|
||||
<IconButton
|
||||
icon='image-outline'
|
||||
size={25}
|
||||
style={styles.imageButton}
|
||||
onPress={onUploadImage}
|
||||
disabled={uploadingFile}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.send}>
|
||||
<Button
|
||||
mode='contained'
|
||||
onPress={onPressSend}
|
||||
disabled={route.params?.type !== 'repost' && (!content || content === '')}
|
||||
loading={isSending}
|
||||
loading={isSending || uploadingFile}
|
||||
>
|
||||
{t('sendPage.send')}
|
||||
</Button>
|
||||
@ -194,17 +239,41 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
{showNotification && (
|
||||
<Snackbar
|
||||
style={styles.snackbar}
|
||||
visible={showNotification !== undefined}
|
||||
duration={Snackbar.DURATION_SHORT}
|
||||
onIconPress={() => setShowNotification(undefined)}
|
||||
onDismiss={() => setShowNotification(undefined)}
|
||||
>
|
||||
{t(`sendPage.${showNotification}`, {
|
||||
uri: imageHostingServices[imageHostingService].donation,
|
||||
})}
|
||||
</Snackbar>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
contentWarningText: {
|
||||
marginTop: 3,
|
||||
},
|
||||
snackbar: {
|
||||
margin: 16,
|
||||
bottom: 100,
|
||||
},
|
||||
textInputContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
textInput: {
|
||||
paddingBottom: 0,
|
||||
},
|
||||
imageButton: {
|
||||
marginBottom: -13,
|
||||
marginTop: -8,
|
||||
},
|
||||
noteCard: {
|
||||
flexDirection: 'column-reverse',
|
||||
paddingLeft: 16,
|
||||
|
@ -19,6 +19,7 @@
|
||||
"@react-navigation/stack": "^6.3.11",
|
||||
"@scure/base": "^1.1.1",
|
||||
"assert": "^2.0.0",
|
||||
"axios": "^1.2.6",
|
||||
"bip-schnorr": "^0.6.6",
|
||||
"buffer": "^6.0.3",
|
||||
"cipher-base": "https://github.com/KoalaSat/cipher-base",
|
||||
@ -37,7 +38,9 @@
|
||||
"react-native": "0.70.6",
|
||||
"react-native-action-button": "^2.8.5",
|
||||
"react-native-bidirectional-infinite-scroll": "^0.3.3",
|
||||
"react-native-blob-util": "^0.17.1",
|
||||
"react-native-gesture-handler": "^2.8.0",
|
||||
"react-native-image-picker": "^5.0.1",
|
||||
"react-native-multithreading": "^1.1.1",
|
||||
"react-native-pager-view": "^6.1.2",
|
||||
"react-native-paper": "^5.1.3",
|
||||
|
29
yarn.lock
29
yarn.lock
@ -2464,6 +2464,15 @@ axios@^1.2.2:
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
axios@^1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.6.tgz#eacb6d065baa11bad5959e7ffa0cb6745c65f392"
|
||||
integrity sha512-rC/7F08XxZwjMV4iuWv+JpD3E0Ksqg9nac4IIg6RwNuF0JTeWoCo/mBNG54+tNhhI11G3/VDRbdDQTs9hGp4pQ==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.0"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
babel-core@^7.0.0-bridge.0:
|
||||
version "7.0.0-bridge.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece"
|
||||
@ -2596,6 +2605,11 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
base-64@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb"
|
||||
integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==
|
||||
|
||||
base-x@^3.0.2:
|
||||
version "3.0.9"
|
||||
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
|
||||
@ -4487,7 +4501,7 @@ glob-parent@^6.0.2:
|
||||
dependencies:
|
||||
is-glob "^4.0.3"
|
||||
|
||||
glob@^7.1.3, glob@^7.1.4:
|
||||
glob@^7.1.3, glob@^7.1.4, glob@^7.2.3:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
@ -7152,6 +7166,14 @@ react-native-bidirectional-infinite-scroll@^0.3.3:
|
||||
resolved "https://registry.yarnpkg.com/react-native-bidirectional-infinite-scroll/-/react-native-bidirectional-infinite-scroll-0.3.3.tgz#31e83e30514be2eaaa889b97d01149c8a08576ec"
|
||||
integrity sha512-zxYJDjrxTkGqg83WH3fSdufg79XZ7xDDn9HdHlKo9avAcz92Rf28/ivDeUM2aOUmmboqJK8BqtVByT6cF/taYg==
|
||||
|
||||
react-native-blob-util@^0.17.1:
|
||||
version "0.17.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-blob-util/-/react-native-blob-util-0.17.1.tgz#d9d6caaa79cd44622ff68c566ab9b448c97003b6"
|
||||
integrity sha512-sel2PvprG3Y5XK89mIuezB/ROTDkr9cz9nJXxfXil12GGZpGRsOsB+e919ZEGWV/BfPFx5AVjOE67XOJ7FNLMQ==
|
||||
dependencies:
|
||||
base-64 "0.1.0"
|
||||
glob "^7.2.3"
|
||||
|
||||
react-native-codegen@^0.70.6:
|
||||
version "0.70.6"
|
||||
resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.70.6.tgz#2ce17d1faad02ad4562345f8ee7cbe6397eda5cb"
|
||||
@ -7178,6 +7200,11 @@ react-native-gradle-plugin@^0.70.3:
|
||||
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz#cbcf0619cbfbddaa9128701aa2d7b4145f9c4fc8"
|
||||
integrity sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==
|
||||
|
||||
react-native-image-picker@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-picker/-/react-native-image-picker-5.0.1.tgz#c9e99217396bc82a977785e39e14afb4819e8448"
|
||||
integrity sha512-+poQTHOnEGrbxJnut591XA9006svFOyfPg/i5bv+fLuwoSHh5HW0E/PVhvT8lbX0Z5C108vh3DAsnrfFFnPBGw==
|
||||
|
||||
react-native-multithreading@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-multithreading/-/react-native-multithreading-1.1.1.tgz#e1522ecd56115993d444a69c21bca49ca123bf4e"
|
||||
|
Loading…
Reference in New Issue
Block a user