Retry image support (#108)
* add dependencies * adding profile image componeent * upgrading to img check componenet * creating storage functions * adding storage endpionts * adding rn-fast-image * creating cache image context * using fast imgae for profile images * updating upload function * adding images * fixing new share placement icon * fixing parellel quering * get contact image from saved cache * cache image function for adding contact half modal * gets contact from cache not cache obj due to non active updates * finalizing image uploads * fix load missunderstanding null image * fixed style inconsistancy
This commit is contained in:
@@ -64,6 +64,7 @@ import getDeepLinkUser from './app/components/admin/homeComponents/contacts/inte
|
||||
import {navigationRef} from './navigation/navigationService';
|
||||
import {GlobalConbinedTxContextProvider} from './context-store/combinedTransactionsContext';
|
||||
import BreezTest from './app/screens/breezTest';
|
||||
import {ImageCacheProvider} from './context-store/imageCache';
|
||||
|
||||
const Stack = createNativeStackNavigator();
|
||||
|
||||
@@ -84,10 +85,12 @@ function App(): JSX.Element {
|
||||
<PushNotificationManager>
|
||||
<LiquidEventProvider>
|
||||
<LightningEventProvider>
|
||||
{/* <Suspense
|
||||
<ImageCacheProvider>
|
||||
{/* <Suspense
|
||||
fallback={<FullLoadingScreen text={'Loading Page'} />}> */}
|
||||
<ResetStack />
|
||||
{/* </Suspense> */}
|
||||
<ResetStack />
|
||||
{/* </Suspense> */}
|
||||
</ImageCacheProvider>
|
||||
</LightningEventProvider>
|
||||
</LiquidEventProvider>
|
||||
</PushNotificationManager>
|
||||
|
||||
@@ -92,7 +92,7 @@ android {
|
||||
versionCode 26
|
||||
versionName "0.4.5"
|
||||
ndk {
|
||||
abiFilters 'arm64-v8a', 'x86_64', // Removing these two version since liquid_sdk is not supported 'x86', 'armeabi-v7a', // Exclude riscv64
|
||||
abiFilters 'arm64-v8a', 'x86_64' // Removing these two version since liquid_sdk is not supported 'x86', 'armeabi-v7a', // Exclude riscv64
|
||||
}
|
||||
// Add a build config field to read the Breez API key
|
||||
// from system
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -26,6 +26,8 @@ import {useKeysContext} from '../../../../../context-store/keys';
|
||||
import {keyboardNavigate} from '../../../../functions/customNavigation';
|
||||
import {useGlobalThemeContext} from '../../../../../context-store/theme';
|
||||
import sha256Hash from '../../../../functions/hash';
|
||||
import ContactProfileImage from './internalComponents/profileImage';
|
||||
import {getCachedProfileImage} from '../../../../functions/cachedImage';
|
||||
|
||||
export default function AddContactsHalfModal(props) {
|
||||
const {contactsPrivateKey} = useKeysContext();
|
||||
@@ -40,25 +42,44 @@ export default function AddContactsHalfModal(props) {
|
||||
|
||||
const debouncedSearch = useDebounce(async term => {
|
||||
const results = await searchUsers(term);
|
||||
const newUsers = results
|
||||
.map((savedContact, id) => {
|
||||
if (!savedContact) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
savedContact.uniqueName ===
|
||||
globalContactsInformation.myProfile.uniqueName
|
||||
)
|
||||
return false;
|
||||
if (!savedContact.receiveAddress) return false;
|
||||
return savedContact;
|
||||
})
|
||||
.filter(Boolean);
|
||||
const newUsers = (
|
||||
await Promise.all(
|
||||
results.map(async savedContact => {
|
||||
if (!savedContact) return false;
|
||||
if (
|
||||
savedContact.uniqueName ===
|
||||
globalContactsInformation.myProfile.uniqueName
|
||||
)
|
||||
return false;
|
||||
if (!savedContact?.uuid) return false;
|
||||
|
||||
let responseData;
|
||||
|
||||
if (
|
||||
savedContact.hasProfileImage ||
|
||||
typeof savedContact.hasProfileImage === 'boolean'
|
||||
) {
|
||||
responseData = await getCachedProfileImage(savedContact.uuid);
|
||||
console.log(responseData, 'response');
|
||||
}
|
||||
|
||||
if (!responseData) return savedContact;
|
||||
else
|
||||
return {
|
||||
...savedContact,
|
||||
...responseData,
|
||||
};
|
||||
}),
|
||||
)
|
||||
).filter(Boolean);
|
||||
console.log(newUsers, 'test');
|
||||
unstable_batchedUpdates(() => {
|
||||
setIsSearching(false);
|
||||
setUsers(newUsers);
|
||||
});
|
||||
}, 500);
|
||||
}, 800);
|
||||
|
||||
console.log(users);
|
||||
|
||||
const handleSearch = term => {
|
||||
setSearchInput(term);
|
||||
@@ -192,20 +213,37 @@ export default function AddContactsHalfModal(props) {
|
||||
/>
|
||||
</ScrollView>
|
||||
) : (
|
||||
<FlatList
|
||||
key={sha256Hash(users.join('') + `${isSearching}`)}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={users}
|
||||
renderItem={({item}) => (
|
||||
<ContactListItem
|
||||
savedContact={item}
|
||||
contactsPrivateKey={contactsPrivateKey}
|
||||
<>
|
||||
{users.length ? (
|
||||
<FlatList
|
||||
key={sha256Hash(users.join('') + `${isSearching}`)}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={users}
|
||||
renderItem={({item}) => (
|
||||
<ContactListItem
|
||||
savedContact={item}
|
||||
contactsPrivateKey={contactsPrivateKey}
|
||||
theme={theme}
|
||||
darkModeType={darkModeType}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={item => item?.uniqueName}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
keyboardDismissMode="none"
|
||||
/>
|
||||
) : (
|
||||
<ThemeText
|
||||
styles={{textAlign: 'center', marginTop: 20}}
|
||||
content={
|
||||
isSearching
|
||||
? ''
|
||||
: searchInput
|
||||
? 'No profiles match this search'
|
||||
: 'Start typing to search for a profile'
|
||||
}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={item => item?.uniqueName}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
keyboardDismissMode="none"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
@@ -215,6 +253,7 @@ export default function AddContactsHalfModal(props) {
|
||||
function ContactListItem(props) {
|
||||
const {textColor, backgroundOffset} = GetThemeColors();
|
||||
const navigate = useNavigation();
|
||||
|
||||
const newContact = {
|
||||
...props.savedContact,
|
||||
isFavorite: false,
|
||||
@@ -235,13 +274,14 @@ function ContactListItem(props) {
|
||||
style={[
|
||||
styles.contactListLetterImage,
|
||||
{
|
||||
borderColor: textColor,
|
||||
backgroundColor: backgroundOffset,
|
||||
},
|
||||
]}>
|
||||
<ThemeText
|
||||
styles={{includeFontPadding: false}}
|
||||
content={newContact.uniqueName[0].toUpperCase()}
|
||||
<ContactProfileImage
|
||||
updated={newContact.updated}
|
||||
uri={newContact.localUri}
|
||||
darkModeType={props.darkModeType}
|
||||
theme={props.theme}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
@@ -287,12 +327,12 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
|
||||
contactListLetterImage: {
|
||||
height: 30,
|
||||
width: 30,
|
||||
borderRadius: 15,
|
||||
height: 40,
|
||||
width: 40,
|
||||
borderRadius: 20,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderWidth: 1,
|
||||
overflow: 'hidden',
|
||||
marginRight: 10,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -27,25 +27,23 @@ import {useGlobalThemeContext} from '../../../../../context-store/theme';
|
||||
import {useAppStatus} from '../../../../../context-store/appStatus';
|
||||
import {useKeysContext} from '../../../../../context-store/keys';
|
||||
import useHandleBackPressNew from '../../../../hooks/useHandleBackPressNew';
|
||||
import {ANDROIDSAFEAREA, KEYBOARDTIMEOUT} from '../../../../constants/styles';
|
||||
import {keyboardNavigate} from '../../../../functions/customNavigation';
|
||||
import {crashlyticsLogReport} from '../../../../functions/crashlyticsLogs';
|
||||
import ContactProfileImage from './internalComponents/profileImage';
|
||||
import {useImageCache} from '../../../../../context-store/imageCache';
|
||||
|
||||
export default function ContactsPage({navigation}) {
|
||||
const {masterInfoObject} = useGlobalContextProvider();
|
||||
const {cache} = useImageCache();
|
||||
const {isConnectedToTheInternet} = useAppStatus();
|
||||
const {theme, darkModeType} = useGlobalThemeContext();
|
||||
const {
|
||||
decodedAddedContacts,
|
||||
globalContactsInformation,
|
||||
myProfileImage,
|
||||
contactsMessags,
|
||||
} = useGlobalContacts();
|
||||
const {decodedAddedContacts, globalContactsInformation, contactsMessags} =
|
||||
useGlobalContacts();
|
||||
const [inputText, setInputText] = useState('');
|
||||
const hideUnknownContacts = masterInfoObject.hideUnknownContacts;
|
||||
const tabsNavigate = navigation.navigate;
|
||||
const navigate = useNavigation();
|
||||
const {backgroundOffset} = GetThemeColors();
|
||||
const {backgroundOffset, backgroundColor} = GetThemeColors();
|
||||
const myProfile = globalContactsInformation.myProfile;
|
||||
const didEditProfile = globalContactsInformation.myProfile.didEditProfile;
|
||||
|
||||
@@ -65,7 +63,13 @@ export default function ContactsPage({navigation}) {
|
||||
return decodedAddedContacts
|
||||
.filter(contact => contact.isFavorite)
|
||||
.map((contact, id) => {
|
||||
return <PinnedContactElement key={contact.uuid} contact={contact} />;
|
||||
return (
|
||||
<PinnedContactElement
|
||||
cache={cache}
|
||||
key={contact.uuid}
|
||||
contact={contact}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}, [decodedAddedContacts, contactsMessags]);
|
||||
|
||||
@@ -87,7 +91,9 @@ export default function ContactsPage({navigation}) {
|
||||
return (earliset_B || 0) - (earliset_A || 0);
|
||||
})
|
||||
.map((contact, id) => {
|
||||
return <ContactElement key={contact.uuid} contact={contact} />;
|
||||
return (
|
||||
<ContactElement cache={cache} key={contact.uuid} contact={contact} />
|
||||
);
|
||||
});
|
||||
}, [decodedAddedContacts, inputText, hideUnknownContacts, contactsMessags]);
|
||||
|
||||
@@ -143,19 +149,11 @@ export default function ContactsPage({navigation}) {
|
||||
...styles.profileImageContainer,
|
||||
backgroundColor: backgroundOffset,
|
||||
}}>
|
||||
<Image
|
||||
source={
|
||||
myProfileImage
|
||||
? {uri: myProfileImage}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
}
|
||||
style={
|
||||
myProfileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '50%', height: '50%'}
|
||||
}
|
||||
<ContactProfileImage
|
||||
updated={cache[masterInfoObject?.uuid]?.updated}
|
||||
uri={cache[masterInfoObject?.uuid]?.localUri}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
@@ -166,11 +164,14 @@ export default function ContactsPage({navigation}) {
|
||||
).length !== 0 && myProfile.didEditProfile ? (
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={{paddingTop: 10, paddingBottom: 10}}
|
||||
contentContainerStyle={{
|
||||
paddingTop: pinnedContacts.length ? 0 : 10,
|
||||
paddingBottom: 10,
|
||||
}}
|
||||
style={{flex: 1, overflow: 'hidden'}}
|
||||
stickyHeaderIndices={[pinnedContacts.length ? 1 : 0]}>
|
||||
{pinnedContacts.length != 0 && (
|
||||
<View style={{height: 130}}>
|
||||
<View style={{height: 120}}>
|
||||
<ScrollView
|
||||
showsHorizontalScrollIndicator={false}
|
||||
horizontal
|
||||
@@ -183,6 +184,7 @@ export default function ContactsPage({navigation}) {
|
||||
placeholderText={'Search added contacts'}
|
||||
inputText={inputText}
|
||||
setInputText={setInputText}
|
||||
containerStyles={{width: '100%', backgroundColor}}
|
||||
/>
|
||||
{contactElements}
|
||||
</ScrollView>
|
||||
@@ -288,19 +290,19 @@ function PinnedContactElement(props) {
|
||||
position: 'relative',
|
||||
},
|
||||
]}>
|
||||
<Image
|
||||
source={
|
||||
contact.profileImage
|
||||
? {uri: contact.profileImage}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
<ContactProfileImage
|
||||
updated={
|
||||
contact.isLNURL
|
||||
? new Date().toISOString()
|
||||
: props.cache[contact.uuid]?.updated
|
||||
}
|
||||
style={
|
||||
contact.profileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '50%', height: '50%'}
|
||||
uri={
|
||||
contact.isLNURL
|
||||
? contact.profileImage
|
||||
: props.cache[contact.uuid]?.localUri
|
||||
}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -393,19 +395,19 @@ export function ContactElement(props) {
|
||||
position: 'relative',
|
||||
},
|
||||
]}>
|
||||
<Image
|
||||
source={
|
||||
contact.profileImage
|
||||
? {uri: contact.profileImage}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
<ContactProfileImage
|
||||
updated={
|
||||
contact.isLNURL
|
||||
? new Date().toISOString()
|
||||
: props.cache[contact.uuid]?.updated
|
||||
}
|
||||
style={
|
||||
contact.profileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '50%', height: '50%'}
|
||||
uri={
|
||||
contact.isLNURL
|
||||
? contact.profileImage
|
||||
: props.cache[contact.uuid]?.localUri
|
||||
}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
@@ -661,9 +663,8 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
|
||||
pinnedContact: {
|
||||
height: 'auto',
|
||||
|
||||
margin: 5,
|
||||
// height: 'auto',
|
||||
marginHorizontal: 5,
|
||||
alignItems: 'center',
|
||||
},
|
||||
pinnedContactsContainer: {
|
||||
|
||||
@@ -30,10 +30,6 @@ import {isValidUniqueName} from '../../../../../db';
|
||||
import CustomButton from '../../../../functions/CustomElements/button';
|
||||
import {useGlobalContacts} from '../../../../../context-store/globalContacts';
|
||||
import GetThemeColors from '../../../../hooks/themeColors';
|
||||
import {
|
||||
removeLocalStorageItem,
|
||||
setLocalStorageItem,
|
||||
} from '../../../../functions/localStorage';
|
||||
import {getImageFromLibrary} from '../../../../functions/imagePickerWrapper';
|
||||
import {useGlobalThemeContext} from '../../../../../context-store/theme';
|
||||
import {useKeysContext} from '../../../../../context-store/keys';
|
||||
@@ -43,6 +39,15 @@ import {INSET_WINDOW_WIDTH} from '../../../../constants/theme';
|
||||
import useHandleBackPressNew from '../../../../hooks/useHandleBackPressNew';
|
||||
import {keyboardGoBack} from '../../../../functions/customNavigation';
|
||||
import {useTranslation} from 'react-i18next';
|
||||
import * as ImageManipulator from 'expo-image-manipulator';
|
||||
import ContactProfileImage from './internalComponents/profileImage';
|
||||
import FullLoadingScreen from '../../../../functions/CustomElements/loadingScreen';
|
||||
import {
|
||||
deleteDatabaseImage,
|
||||
setDatabaseIMG,
|
||||
} from '../../../../../db/photoStorage';
|
||||
import {useImageCache} from '../../../../../context-store/imageCache';
|
||||
import {useContactImage} from '../../../../hooks/useContactImage';
|
||||
|
||||
export default function EditMyProfilePage(props) {
|
||||
const navigate = useNavigation();
|
||||
@@ -127,16 +132,16 @@ function InnerContent({
|
||||
}) {
|
||||
const {contactsPrivateKey, publicKey} = useKeysContext();
|
||||
const {theme, darkModeType} = useGlobalThemeContext();
|
||||
const {cache, refreshCache, removeProfileImageFromCache} = useImageCache();
|
||||
const {backgroundOffset, textInputColor, textInputBackground, textColor} =
|
||||
GetThemeColors();
|
||||
const {
|
||||
decodedAddedContacts,
|
||||
globalContactsInformation,
|
||||
toggleGlobalContactsInformation,
|
||||
setMyProfileImage,
|
||||
myProfileImage,
|
||||
} = useGlobalContacts();
|
||||
const {t} = useTranslation();
|
||||
const [isAddingImage, setIsAddingImage] = useState(false);
|
||||
|
||||
const nameRef = useRef(null);
|
||||
const uniquenameRef = useRef(null);
|
||||
@@ -162,6 +167,7 @@ function InnerContent({
|
||||
uniquename: '',
|
||||
receiveAddress: '',
|
||||
});
|
||||
const [hasImage, setHasImage] = useState(false);
|
||||
const [isKeyboardActive, setIsKeyboardActive] = useState(false);
|
||||
const paddingBottom = Platform.select({
|
||||
ios: insets.bottom,
|
||||
@@ -212,6 +218,9 @@ function InnerContent({
|
||||
selectedAddedContactUniqueName,
|
||||
]);
|
||||
|
||||
const myProfileImage = cache[myContact?.uuid];
|
||||
const selectedAddedContactImage = useContactImage(selectedAddedContact?.uuid);
|
||||
|
||||
return (
|
||||
<View style={styles.innerContainer}>
|
||||
<ScrollView
|
||||
@@ -223,20 +232,23 @@ function InnerContent({
|
||||
...CENTER,
|
||||
}}>
|
||||
<TouchableOpacity
|
||||
activeOpacity={
|
||||
(isEditingMyProfile || selectedAddedContact.isLNURL) &&
|
||||
!isAddingImage
|
||||
? 0.2
|
||||
: 1
|
||||
}
|
||||
onPress={() => {
|
||||
if (
|
||||
(!selectedAddedContact?.profileImage && !isEditingMyProfile) ||
|
||||
(!myProfileImage && isEditingMyProfile)
|
||||
) {
|
||||
if (!isEditingMyProfile && !selectedAddedContact.isLNURL) return;
|
||||
if (isAddingImage) return;
|
||||
if (!hasImage) {
|
||||
addProfilePicture();
|
||||
return;
|
||||
}
|
||||
navigate.navigate('AddOrDeleteContactImage', {
|
||||
addPhoto: addProfilePicture,
|
||||
deletePhoto: deleteProfilePicture,
|
||||
hasImage:
|
||||
(selectedAddedContact?.profileImage && !isEditingMyProfile) ||
|
||||
(myProfileImage && isEditingMyProfile),
|
||||
hasImage: hasImage,
|
||||
});
|
||||
}}>
|
||||
<View
|
||||
@@ -246,38 +258,38 @@ function InnerContent({
|
||||
backgroundColor: backgroundOffset,
|
||||
},
|
||||
]}>
|
||||
<Image
|
||||
source={
|
||||
(selectedAddedContact?.profileImage && !isEditingMyProfile) ||
|
||||
(myProfileImage && isEditingMyProfile)
|
||||
? {
|
||||
uri: isEditingMyProfile
|
||||
? myProfileImage
|
||||
: selectedAddedContact?.profileImage,
|
||||
}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
}
|
||||
style={
|
||||
(selectedAddedContact?.profileImage && !isEditingMyProfile) ||
|
||||
(myProfileImage && isEditingMyProfile)
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '50%', height: '50%'}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.selectFromPhotos}>
|
||||
<Image
|
||||
source={
|
||||
(selectedAddedContact?.profileImage && !isEditingMyProfile) ||
|
||||
(myProfileImage && isEditingMyProfile)
|
||||
? ICONS.xSmallIconBlack
|
||||
: ICONS.ImagesIconDark
|
||||
}
|
||||
style={{width: 20, height: 20}}
|
||||
/>
|
||||
{isAddingImage ? (
|
||||
<FullLoadingScreen showText={false} />
|
||||
) : (
|
||||
<ContactProfileImage
|
||||
updated={
|
||||
isEditingMyProfile
|
||||
? myProfileImage?.updated
|
||||
: selectedAddedContact.isLNURL
|
||||
? new Date().toISOString()
|
||||
: selectedAddedContactImage?.updated
|
||||
}
|
||||
uri={
|
||||
isEditingMyProfile
|
||||
? myProfileImage?.localUri
|
||||
: selectedAddedContact.isLNURL
|
||||
? selectedAddedContact.profileImage
|
||||
: selectedAddedContactImage?.localUri
|
||||
}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
setHasImage={setHasImage}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
{(isEditingMyProfile || selectedAddedContact.isLNURL) && (
|
||||
<View style={styles.selectFromPhotos}>
|
||||
<Image
|
||||
source={hasImage ? ICONS.xSmallIconBlack : ICONS.ImagesIconDark}
|
||||
style={{width: 20, height: 20}}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
@@ -661,7 +673,7 @@ function InnerContent({
|
||||
}
|
||||
|
||||
async function addProfilePicture() {
|
||||
const imagePickerResponse = await getImageFromLibrary();
|
||||
const imagePickerResponse = await getImageFromLibrary({quality: 1});
|
||||
const {didRun, error, imgURL} = imagePickerResponse;
|
||||
if (!didRun) return;
|
||||
if (error) {
|
||||
@@ -670,8 +682,19 @@ function InnerContent({
|
||||
}
|
||||
|
||||
if (isEditingMyProfile) {
|
||||
setMyProfileImage(imgURL.uri);
|
||||
setLocalStorageItem('myProfileImage', imgURL.uri);
|
||||
const response = await uploadProfileImage({imgURL: imgURL});
|
||||
if (!response) return;
|
||||
toggleGlobalContactsInformation(
|
||||
{
|
||||
myProfile: {
|
||||
...globalContactsInformation.myProfile,
|
||||
hasProfileImage: true,
|
||||
},
|
||||
|
||||
addedContacts: globalContactsInformation.addedContacts,
|
||||
},
|
||||
true,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -709,11 +732,63 @@ function InnerContent({
|
||||
true,
|
||||
);
|
||||
}
|
||||
async function uploadProfileImage({imgURL, removeImage}) {
|
||||
try {
|
||||
setIsAddingImage(true);
|
||||
if (!removeImage) {
|
||||
const resized = ImageManipulator.ImageManipulator.manipulate(
|
||||
imgURL.uri,
|
||||
).resize({width: 350});
|
||||
const image = await resized.renderAsync();
|
||||
const savedImage = await image.saveAsync({
|
||||
compress: 0.4,
|
||||
format: ImageManipulator.SaveFormat.WEBP,
|
||||
});
|
||||
|
||||
const response = await setDatabaseIMG(
|
||||
globalContactsInformation.myProfile.uuid,
|
||||
{uri: savedImage.uri},
|
||||
);
|
||||
|
||||
if (response) {
|
||||
await refreshCache(
|
||||
globalContactsInformation.myProfile.uuid,
|
||||
response,
|
||||
);
|
||||
return true;
|
||||
} else throw new Error('Unable to save image');
|
||||
} else {
|
||||
await deleteDatabaseImage(globalContactsInformation.myProfile.uuid);
|
||||
await removeProfileImageFromCache(
|
||||
globalContactsInformation.myProfile.uuid,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
navigate.navigate('ErrorScreen', {errorMessage: err.message});
|
||||
return false;
|
||||
} finally {
|
||||
setIsAddingImage(false);
|
||||
}
|
||||
}
|
||||
async function deleteProfilePicture() {
|
||||
try {
|
||||
if (isEditingMyProfile) {
|
||||
setMyProfileImage('');
|
||||
removeLocalStorageItem('myProfileImage');
|
||||
const response = await uploadProfileImage({removeImage: true});
|
||||
console.log(response);
|
||||
if (!response) return;
|
||||
toggleGlobalContactsInformation(
|
||||
{
|
||||
myProfile: {
|
||||
...globalContactsInformation.myProfile,
|
||||
hasProfileImage: false,
|
||||
},
|
||||
|
||||
addedContacts: globalContactsInformation.addedContacts,
|
||||
},
|
||||
true,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (fromInitialAdd) {
|
||||
|
||||
@@ -30,6 +30,8 @@ import {useGlobalThemeContext} from '../../../../../context-store/theme';
|
||||
import {useAppStatus} from '../../../../../context-store/appStatus';
|
||||
import {useKeysContext} from '../../../../../context-store/keys';
|
||||
import useHandleBackPressNew from '../../../../hooks/useHandleBackPressNew';
|
||||
import ContactProfileImage from './internalComponents/profileImage';
|
||||
import {useContactImage} from '../../../../hooks/useContactImage';
|
||||
|
||||
export default function ExpandedContactsPage(props) {
|
||||
const navigate = useNavigation();
|
||||
@@ -37,7 +39,6 @@ export default function ExpandedContactsPage(props) {
|
||||
const {isConnectedToTheInternet} = useAppStatus();
|
||||
const {theme, darkModeType} = useGlobalThemeContext();
|
||||
const {
|
||||
textColor,
|
||||
backgroundOffset,
|
||||
backgroundColor,
|
||||
textInputColor,
|
||||
@@ -51,7 +52,6 @@ export default function ExpandedContactsPage(props) {
|
||||
} = useGlobalContacts();
|
||||
const insets = useSafeAreaInsets();
|
||||
const currentTime = new Date();
|
||||
const isInitialRender = useRef(true);
|
||||
const selectedUUID = props?.route?.params?.uuid || props?.uuid;
|
||||
const myProfile = globalContactsInformation?.myProfile;
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function ExpandedContactsPage(props) {
|
||||
decodedAddedContacts.filter(contact => contact?.uuid === selectedUUID),
|
||||
[decodedAddedContacts, selectedUUID],
|
||||
);
|
||||
|
||||
const imageData = useContactImage(selectedContact.uuid);
|
||||
const contactTransactions = contactsMessags[selectedUUID]?.messages || []; //selectedContact?.transactions;
|
||||
useHandleBackPressNew();
|
||||
console.log(selectedContact);
|
||||
@@ -104,22 +104,6 @@ export default function ExpandedContactsPage(props) {
|
||||
lightsOutIcon={ICONS.arrow_small_left_white}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
{!selectedContact?.isLNURL && selectedContact?.uniqueName && (
|
||||
<TouchableOpacity
|
||||
style={{marginRight: 5}}
|
||||
onPress={() => {
|
||||
Share.share({
|
||||
title: 'Blitz Contact',
|
||||
message: `https://blitz-wallet.com/u/${selectedContact?.uniqueName}`,
|
||||
});
|
||||
}}>
|
||||
<ThemeImage
|
||||
darkModeIcon={ICONS.share}
|
||||
lightModeIcon={ICONS.share}
|
||||
lightsOutIcon={ICONS.shareWhite}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{selectedContact && (
|
||||
<TouchableOpacity
|
||||
style={{marginRight: 5}}
|
||||
@@ -211,29 +195,52 @@ export default function ExpandedContactsPage(props) {
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<View
|
||||
style={[
|
||||
styles.profileImage,
|
||||
{
|
||||
// borderColor: COLORS.darkModeText,
|
||||
backgroundColor: backgroundOffset,
|
||||
},
|
||||
]}>
|
||||
<Image
|
||||
source={
|
||||
selectedContact.profileImage
|
||||
? {uri: selectedContact.profileImage}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
}
|
||||
style={
|
||||
selectedContact.profileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '50%', height: '50%'}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
activeOpacity={
|
||||
!selectedContact?.isLNURL && selectedContact?.uniqueName ? 0.2 : 1
|
||||
}
|
||||
onPress={() => {
|
||||
if (selectedContact?.isLNURL || !selectedContact?.uniqueName)
|
||||
return;
|
||||
Share.share({
|
||||
title: 'Blitz Contact',
|
||||
message: `https://blitz-wallet.com/u/${selectedContact?.uniqueName}`,
|
||||
});
|
||||
}}
|
||||
style={{...CENTER}}>
|
||||
<View
|
||||
style={[
|
||||
styles.profileImage,
|
||||
{
|
||||
backgroundColor: backgroundOffset,
|
||||
},
|
||||
]}>
|
||||
<ContactProfileImage
|
||||
updated={
|
||||
selectedContact.isLNURL
|
||||
? new Date().toISOString()
|
||||
: imageData?.updated
|
||||
}
|
||||
uri={
|
||||
selectedContact.isLNURL
|
||||
? selectedContact.profileImage
|
||||
: imageData?.localUri
|
||||
}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
{!selectedContact?.isLNURL && selectedContact?.uniqueName && (
|
||||
<View style={styles.selectFromPhotos}>
|
||||
<ThemeImage
|
||||
styles={{width: 20, height: 20}}
|
||||
darkModeIcon={ICONS.shareBlack}
|
||||
lightModeIcon={ICONS.shareBlack}
|
||||
lightsOutIcon={ICONS.shareBlack}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<ThemeText
|
||||
styles={styles.profileName}
|
||||
content={selectedContact.name || selectedContact.uniqueName}
|
||||
@@ -408,4 +415,16 @@ const styles = StyleSheet.create({
|
||||
marginBottom: 'auto',
|
||||
marginTop: 'auto',
|
||||
},
|
||||
selectFromPhotos: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 20,
|
||||
backgroundColor: COLORS.darkModeText,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
position: 'absolute',
|
||||
right: 12.5,
|
||||
bottom: 12.5,
|
||||
zIndex: 2,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import {ICONS} from '../../../../../constants';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import customUUID from '../../../../../functions/customUUID';
|
||||
|
||||
export default function ContactProfileImage({
|
||||
priority = FastImage.priority.high,
|
||||
resizeMode = FastImage.resizeMode.cover,
|
||||
uri,
|
||||
darkModeType,
|
||||
theme,
|
||||
setHasImage,
|
||||
updated,
|
||||
}) {
|
||||
const [loadError, setLoadError] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const fallbackIcon = darkModeType && theme ? ICONS.userWhite : ICONS.userIcon;
|
||||
const customURI = `${uri}?v=${
|
||||
updated ? new Date(updated).getTime() : customUUID()
|
||||
}`;
|
||||
|
||||
return (
|
||||
<FastImage
|
||||
onLoad={() => {
|
||||
setIsLoading(false);
|
||||
if (setHasImage) {
|
||||
console.log('On load has image', !!customURI);
|
||||
setHasImage(!!uri);
|
||||
}
|
||||
}}
|
||||
onError={() => {
|
||||
setLoadError(true);
|
||||
if (setHasImage) {
|
||||
console.log('on error has image', !!customURI);
|
||||
setHasImage(false);
|
||||
}
|
||||
}}
|
||||
style={
|
||||
!loadError && uri && !isLoading
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '50%', height: '50%'}
|
||||
}
|
||||
source={
|
||||
!loadError && uri && !isLoading
|
||||
? {
|
||||
uri: customURI,
|
||||
priority: priority,
|
||||
}
|
||||
: fallbackIcon
|
||||
}
|
||||
resizeMode={resizeMode}
|
||||
/>
|
||||
);
|
||||
}
|
||||
+25
-61
@@ -7,10 +7,13 @@ import {useGlobalContacts} from '../../../../../../context-store/globalContacts'
|
||||
import GetThemeColors from '../../../../../hooks/themeColors';
|
||||
import {ThemeText} from '../../../../../functions/CustomElements';
|
||||
import {useGlobalThemeContext} from '../../../../../../context-store/theme';
|
||||
import ContactProfileImage from './profileImage';
|
||||
import {useImageCache} from '../../../../../../context-store/imageCache';
|
||||
|
||||
export default function ProfilePageTransactions({transaction, currentTime}) {
|
||||
const profileInfo = transaction;
|
||||
const transactionData = transaction.transaction;
|
||||
const {cache} = useImageCache();
|
||||
|
||||
const {theme, darkModeType} = useGlobalThemeContext();
|
||||
const {textColor, backgroundOffset} = GetThemeColors();
|
||||
@@ -47,6 +50,7 @@ export default function ProfilePageTransactions({transaction, currentTime}) {
|
||||
timeDifferenceHours={timeDifferenceHours}
|
||||
timeDifferenceDays={timeDifferenceDays}
|
||||
profileInfo={profileInfo}
|
||||
cache={cache}
|
||||
/>
|
||||
) : (
|
||||
<View style={{...styles.transactionContainer}}>
|
||||
@@ -55,21 +59,11 @@ export default function ProfilePageTransactions({transaction, currentTime}) {
|
||||
...styles.selectImage,
|
||||
backgroundColor: backgroundOffset,
|
||||
}}>
|
||||
<Image
|
||||
source={
|
||||
profileInfo.selectedProfileImage
|
||||
? {
|
||||
uri: profileInfo.selectedProfileImage,
|
||||
}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
}
|
||||
style={
|
||||
profileInfo.selectedProfileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '60%', height: '60%'}
|
||||
}
|
||||
<ContactProfileImage
|
||||
updated={cache[profileInfo.contactUUID]?.updated}
|
||||
uri={cache[profileInfo.contactUUID]?.localUri}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -130,10 +124,10 @@ function ConfirmedOrSentTransaction({
|
||||
timeDifferenceHours,
|
||||
timeDifferenceDays,
|
||||
profileInfo,
|
||||
cache,
|
||||
}) {
|
||||
const {masterInfoObject} = useGlobalContextProvider();
|
||||
const {theme, darkModeType} = useGlobalThemeContext();
|
||||
const {myProfileImage} = useGlobalContacts();
|
||||
const {textColor, backgroundOffset} = GetThemeColors();
|
||||
const didDeclinePayment = txParsed.isRedeemed != null && !txParsed.isRedeemed;
|
||||
|
||||
@@ -166,21 +160,11 @@ function ConfirmedOrSentTransaction({
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
}}>
|
||||
<Image
|
||||
source={
|
||||
myProfileImage
|
||||
? {
|
||||
uri: myProfileImage,
|
||||
}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
}
|
||||
style={
|
||||
myProfileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '60%', height: '60%'}
|
||||
}
|
||||
<ContactProfileImage
|
||||
updated={cache[masterInfoObject.uuid]?.updated}
|
||||
uri={cache[masterInfoObject.uuid]?.localUri}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
@@ -191,21 +175,11 @@ function ConfirmedOrSentTransaction({
|
||||
top: 0,
|
||||
right: 0,
|
||||
}}>
|
||||
<Image
|
||||
source={
|
||||
profileInfo.selectedProfileImage
|
||||
? {
|
||||
uri: profileInfo.selectedProfileImage,
|
||||
}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
}
|
||||
style={
|
||||
profileInfo.selectedProfileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '60%', height: '60%'}
|
||||
}
|
||||
<ContactProfileImage
|
||||
updated={cache[profileInfo.contactUUID]?.updated}
|
||||
uri={cache[profileInfo.contactUUID]?.localUri}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
@@ -221,21 +195,11 @@ function ConfirmedOrSentTransaction({
|
||||
|
||||
backgroundColor: backgroundOffset,
|
||||
}}>
|
||||
<Image
|
||||
source={
|
||||
profileInfo.selectedProfileImage
|
||||
? {
|
||||
uri: profileInfo.selectedProfileImage,
|
||||
}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
}
|
||||
style={
|
||||
profileInfo.selectedProfileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '60%', height: '60%'}
|
||||
}
|
||||
<ContactProfileImage
|
||||
updated={cache[profileInfo.contactUUID]?.updated}
|
||||
uri={cache[profileInfo.contactUUID]?.localUri}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from 'react-native';
|
||||
import {CENTER, COLORS, ICONS, SIZES} from '../../../../constants';
|
||||
import {useFocusEffect, useNavigation} from '@react-navigation/native';
|
||||
import {useCallback, useMemo, useState} from 'react';
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import {GlobalThemeView, ThemeText} from '../../../../functions/CustomElements';
|
||||
import {useGlobalContacts} from '../../../../../context-store/globalContacts';
|
||||
import GetThemeColors from '../../../../hooks/themeColors';
|
||||
@@ -21,21 +21,23 @@ import {useGlobalThemeContext} from '../../../../../context-store/theme';
|
||||
import {useAppStatus} from '../../../../../context-store/appStatus';
|
||||
import useHandleBackPressNew from '../../../../hooks/useHandleBackPressNew';
|
||||
import MaxHeap from '../../../../functions/minHeap';
|
||||
import ContactProfileImage from './internalComponents/profileImage';
|
||||
import {useImageCache} from '../../../../../context-store/imageCache';
|
||||
|
||||
export default function MyContactProfilePage({navigation}) {
|
||||
const {isConnectedToTheInternet} = useAppStatus();
|
||||
const {cache} = useImageCache();
|
||||
const {theme, darkModeType} = useGlobalThemeContext();
|
||||
const {
|
||||
globalContactsInformation,
|
||||
myProfileImage,
|
||||
decodedAddedContacts,
|
||||
contactsMessags,
|
||||
} = useGlobalContacts();
|
||||
const {globalContactsInformation, decodedAddedContacts, contactsMessags} =
|
||||
useGlobalContacts();
|
||||
const {backgroundOffset, textInputBackground, textInputColor} =
|
||||
GetThemeColors();
|
||||
const navigate = useNavigation();
|
||||
const currentTime = new Date();
|
||||
const [showList, setShowList] = useState(false);
|
||||
|
||||
const myContact = globalContactsInformation.myProfile;
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
setShowList(true);
|
||||
@@ -46,8 +48,6 @@ export default function MyContactProfilePage({navigation}) {
|
||||
}, []),
|
||||
);
|
||||
|
||||
const myContact = globalContactsInformation.myProfile;
|
||||
|
||||
const createdPayments = useMemo(() => {
|
||||
const messageHeap = new MaxHeap();
|
||||
const MAX_MESSAGES = 50;
|
||||
@@ -151,21 +151,11 @@ export default function MyContactProfilePage({navigation}) {
|
||||
backgroundColor: backgroundOffset,
|
||||
},
|
||||
]}>
|
||||
<Image
|
||||
source={
|
||||
myProfileImage
|
||||
? {
|
||||
uri: myProfileImage,
|
||||
}
|
||||
: darkModeType && theme
|
||||
? ICONS.userWhite
|
||||
: ICONS.userIcon
|
||||
}
|
||||
style={
|
||||
myProfileImage
|
||||
? {width: '100%', aspectRatio: 1}
|
||||
: {width: '50%', height: '50%'}
|
||||
}
|
||||
<ContactProfileImage
|
||||
updated={cache[myContact.uuid]?.updated}
|
||||
uri={cache[myContact.uuid]?.localUri}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.scanProfileImage}>
|
||||
@@ -243,6 +233,7 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 15,
|
||||
},
|
||||
|
||||
innerContainer: {
|
||||
|
||||
@@ -148,6 +148,7 @@ import navigationIcon from '../assets/icons/navigation.png';
|
||||
import navigationIconFill from '../assets/icons/navigation_fill.png';
|
||||
import navigationIconWhite from '../assets/icons/navigation_white.png';
|
||||
import navigationIconFillWhite from '../assets/icons/navigation_fill_white.png';
|
||||
import shareBlack from '../assets/icons/shareBlack.png';
|
||||
export default {
|
||||
Xcircle,
|
||||
XcircleLight,
|
||||
@@ -300,4 +301,5 @@ export default {
|
||||
navigationIconFill,
|
||||
navigationIconWhite,
|
||||
navigationIconFillWhite,
|
||||
shareBlack,
|
||||
};
|
||||
|
||||
@@ -37,7 +37,7 @@ const QUICK_PAY_STORAGE_KEY = 'FAST_PAY_SETTINGS';
|
||||
const LOGIN_SECUITY_MODE_KEY = 'LOGIN_SECURITY_MODE';
|
||||
const MIGRATE_ECASH_STORAGE_KEY = 'MIGRATE_ECASH';
|
||||
const POINT_OF_SALE_PAYOUT_DESCRIPTION = 'Blitz Tips Payout';
|
||||
|
||||
const BLITZ_PROFILE_IMG_STORAGE_REF = 'profile_pictures';
|
||||
const BLITZ_DEFAULT_PAYMENT_DESCRIPTION = 'Blitz Wallet';
|
||||
|
||||
const CHATGPT_INPUT_COST = 10 / 1000000;
|
||||
@@ -95,4 +95,5 @@ export {
|
||||
LIQUID_NON_BITCOIN_DRAIN_LIMIT,
|
||||
POINT_OF_SALE_PAYOUT_DESCRIPTION,
|
||||
BLITZ_GOAL_USER_COUNT,
|
||||
BLITZ_PROFILE_IMG_STORAGE_REF,
|
||||
};
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import {StyleSheet, View} from 'react-native';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import {useGlobalContacts} from '../../../context-store/globalContacts';
|
||||
|
||||
import {CENTER, COLORS, ICONS} from '../../constants';
|
||||
import GetThemeColors from '../../hooks/themeColors';
|
||||
|
||||
import {useGlobalContextProvider} from '../../../context-store/context';
|
||||
import {useImageCache} from '../../../context-store/imageCache';
|
||||
|
||||
export default function QrCodeWrapper({
|
||||
QRData = 'No data available',
|
||||
outerContainerStyle,
|
||||
@@ -13,8 +16,11 @@ export default function QrCodeWrapper({
|
||||
logoMargin = 5,
|
||||
logoBorderRadius = 50,
|
||||
}) {
|
||||
const {myProfileImage} = useGlobalContacts();
|
||||
const {cache} = useImageCache();
|
||||
const {masterInfoObject} = useGlobalContextProvider();
|
||||
const {backgroundOffset} = GetThemeColors();
|
||||
const image = cache[masterInfoObject.uuid]?.localUri;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
@@ -29,8 +35,8 @@ export default function QrCodeWrapper({
|
||||
value={QRData}
|
||||
color={COLORS.lightModeText}
|
||||
backgroundColor={COLORS.darkModeText}
|
||||
logo={myProfileImage || ICONS.logoWithPadding}
|
||||
logoSize={myProfileImage ? 70 : 50}
|
||||
logo={!!image ? image : ICONS.logoWithPadding}
|
||||
logoSize={!!image ? 70 : 50}
|
||||
logoMargin={logoMargin}
|
||||
logoBorderRadius={logoBorderRadius}
|
||||
logoBackgroundColor={COLORS.darkModeText}
|
||||
|
||||
@@ -37,6 +37,8 @@ export default function CustomSearchInput({
|
||||
<>
|
||||
<View style={{...styles.inputContainer, ...containerStyles}}>
|
||||
<TextInput
|
||||
autoComplete="off"
|
||||
autoCorrect={false}
|
||||
keyboardAppearance={theme ? 'dark' : 'light'}
|
||||
placeholder={placeholderText || ''}
|
||||
placeholderTextColor={
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import {BLITZ_PROFILE_IMG_STORAGE_REF} from '../constants';
|
||||
import {getStorage} from '@react-native-firebase/storage';
|
||||
|
||||
const FILE_DIR = FileSystem.cacheDirectory + 'profileImages/';
|
||||
const CACHE_KEY = uuid => `${BLITZ_PROFILE_IMG_STORAGE_REF}/${uuid}`;
|
||||
|
||||
export async function getCachedProfileImage(uuid) {
|
||||
try {
|
||||
const key = `${CACHE_KEY(uuid)}`;
|
||||
const ref = getStorage().ref(
|
||||
`${BLITZ_PROFILE_IMG_STORAGE_REF}/${uuid}.jpg`,
|
||||
);
|
||||
const metadata = await ref.getMetadata();
|
||||
const updated = metadata.updated;
|
||||
|
||||
// Check for cached image info
|
||||
const cacheEntry = await AsyncStorage.getItem(key);
|
||||
const parsed = cacheEntry ? JSON.parse(cacheEntry) : null;
|
||||
|
||||
if (parsed?.updated === updated) {
|
||||
const exists = await FileSystem.getInfoAsync(parsed.localUri);
|
||||
if (exists.exists)
|
||||
return {localUri: parsed.localUri, updated: parsed?.updated};
|
||||
}
|
||||
|
||||
const url = await ref.getDownloadURL();
|
||||
await FileSystem.makeDirectoryAsync(FILE_DIR, {intermediates: true});
|
||||
const localUri = `${FILE_DIR}${uuid}.jpg`;
|
||||
|
||||
await FileSystem.downloadAsync(url, localUri);
|
||||
const newEntry = {localUri, updated};
|
||||
await AsyncStorage.setItem(key, JSON.stringify(newEntry));
|
||||
|
||||
return {localUri, updated};
|
||||
} catch (e) {
|
||||
console.error('Error caching profile image', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import {useEffect, useState} from 'react';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import {BLITZ_PROFILE_IMG_STORAGE_REF} from '../constants';
|
||||
|
||||
export function useContactImage(uuid) {
|
||||
const [uri, setUri] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
const keys = await AsyncStorage.getAllKeys();
|
||||
const imgKeys = keys.filter(k =>
|
||||
k.startsWith(BLITZ_PROFILE_IMG_STORAGE_REF),
|
||||
);
|
||||
const stores = await AsyncStorage.multiGet(imgKeys);
|
||||
const initialCache = {};
|
||||
stores.forEach(([key, value]) => {
|
||||
if (value) {
|
||||
const uuid = key.replace(BLITZ_PROFILE_IMG_STORAGE_REF + '/', '');
|
||||
const parsed = JSON.parse(value);
|
||||
initialCache[uuid] = parsed;
|
||||
}
|
||||
});
|
||||
console.log(initialCache, uuid);
|
||||
if (initialCache[uuid]?.localUri) {
|
||||
setUri(initialCache[uuid]);
|
||||
}
|
||||
}
|
||||
load();
|
||||
}, [uuid]);
|
||||
|
||||
return uri;
|
||||
}
|
||||
@@ -202,6 +202,9 @@ export default function RestoreWallet({navigation: {reset}, route: {params}}) {
|
||||
]}>
|
||||
<ThemeText styles={styles.numberText} content={`${item1}.`} />
|
||||
<TextInput
|
||||
autoCorrect={false}
|
||||
autoComplete="off"
|
||||
autoCapitalize="none"
|
||||
keyboardAppearance={theme ? 'dark' : 'light'}
|
||||
ref={ref => (keyRefs.current[item1] = ref)}
|
||||
value={inputedKey[`key${item1}`]}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import {getStorage} from '@react-native-firebase/storage';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import {useGlobalContacts} from './globalContacts';
|
||||
import {useAppStatus} from './appStatus';
|
||||
|
||||
const BLITZ_PROFILE_IMG_STORAGE_REF = 'profile_pictures';
|
||||
const FILE_DIR = FileSystem.cacheDirectory + 'profile_images/';
|
||||
|
||||
const ImageCacheContext = createContext();
|
||||
|
||||
export function ImageCacheProvider({children}) {
|
||||
const [cache, setCache] = useState({});
|
||||
const {didGetToHomepage} = useAppStatus();
|
||||
const {decodedAddedContacts} = useGlobalContacts();
|
||||
const didRunContextCacheCheck = useRef(null);
|
||||
|
||||
console.log(cache, 'imgaes cache');
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const keys = await AsyncStorage.getAllKeys();
|
||||
const imgKeys = keys.filter(k =>
|
||||
k.startsWith(BLITZ_PROFILE_IMG_STORAGE_REF),
|
||||
);
|
||||
const stores = await AsyncStorage.multiGet(imgKeys);
|
||||
const initialCache = {};
|
||||
stores.forEach(([key, value]) => {
|
||||
if (value) {
|
||||
const uuid = key.replace(BLITZ_PROFILE_IMG_STORAGE_REF + '/', '');
|
||||
const parsed = JSON.parse(value);
|
||||
initialCache[uuid] = parsed;
|
||||
}
|
||||
});
|
||||
setCache(initialCache);
|
||||
} catch (e) {
|
||||
console.error('Error loading image cache from storage', e);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!didGetToHomepage) return;
|
||||
if (didRunContextCacheCheck.current) return;
|
||||
didRunContextCacheCheck.current = true;
|
||||
console.log(decodedAddedContacts, 'DECIN FUNC');
|
||||
async function refreshContactsImages() {
|
||||
for (let index = 0; index < decodedAddedContacts.length; index++) {
|
||||
const element = decodedAddedContacts[index];
|
||||
await refreshCache(element.uuid);
|
||||
}
|
||||
}
|
||||
refreshContactsImages();
|
||||
}, [decodedAddedContacts, didGetToHomepage]);
|
||||
|
||||
async function refreshCache(uuid, hasdownloadURL) {
|
||||
try {
|
||||
console.log('Refreshing image for', uuid);
|
||||
const key = `${BLITZ_PROFILE_IMG_STORAGE_REF}/${uuid}`;
|
||||
let url;
|
||||
let metadata;
|
||||
let updated;
|
||||
|
||||
if (!hasdownloadURL) {
|
||||
const reference = getStorage().ref(
|
||||
`${BLITZ_PROFILE_IMG_STORAGE_REF}/${uuid}.jpg`,
|
||||
);
|
||||
|
||||
metadata = await reference.getMetadata();
|
||||
updated = metadata.updated;
|
||||
|
||||
const cached = cache[uuid];
|
||||
if (cached && cached.updated === updated) {
|
||||
const fileInfo = await FileSystem.getInfoAsync(cached.localUri);
|
||||
if (fileInfo.exists) return;
|
||||
}
|
||||
|
||||
url = await reference.getDownloadURL();
|
||||
} else {
|
||||
url = hasdownloadURL;
|
||||
updated = new Date().toISOString();
|
||||
}
|
||||
|
||||
const localUri = `${FILE_DIR}${uuid}.jpg`;
|
||||
|
||||
await FileSystem.makeDirectoryAsync(FILE_DIR, {intermediates: true});
|
||||
await FileSystem.downloadAsync(url, localUri);
|
||||
|
||||
const newCacheEntry = {
|
||||
uri: localUri,
|
||||
localUri,
|
||||
updated,
|
||||
};
|
||||
|
||||
await AsyncStorage.setItem(key, JSON.stringify(newCacheEntry));
|
||||
setCache(prev => ({...prev, [uuid]: newCacheEntry}));
|
||||
|
||||
return newCacheEntry;
|
||||
} catch (err) {
|
||||
console.log('Error refreshing image cache', err);
|
||||
}
|
||||
}
|
||||
|
||||
async function removeProfileImageFromCache(uuid) {
|
||||
try {
|
||||
console.log('Deleting profile image', uuid);
|
||||
const key = `${BLITZ_PROFILE_IMG_STORAGE_REF}/${uuid}`;
|
||||
|
||||
const newCacheEntry = {
|
||||
uri: null,
|
||||
localUri: null,
|
||||
updated: new Date().getTime(),
|
||||
};
|
||||
await AsyncStorage.setItem(key, JSON.stringify(newCacheEntry));
|
||||
setCache(prev => ({...prev, [uuid]: newCacheEntry}));
|
||||
return newCacheEntry;
|
||||
} catch (err) {
|
||||
console.log('Error refreshing image cache', err);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ImageCacheContext.Provider
|
||||
value={{cache, refreshCache, removeProfileImageFromCache}}>
|
||||
{children}
|
||||
</ImageCacheContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useImageCache() {
|
||||
return useContext(ImageCacheContext);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import {getStorage} from '@react-native-firebase/storage';
|
||||
import {BLITZ_PROFILE_IMG_STORAGE_REF} from '../app/constants';
|
||||
|
||||
export async function setDatabaseIMG(publicKey, imgURL) {
|
||||
try {
|
||||
const reference = getStorage().ref(
|
||||
`${BLITZ_PROFILE_IMG_STORAGE_REF}/${publicKey}.jpg`,
|
||||
);
|
||||
|
||||
await reference.putFile(imgURL.uri);
|
||||
|
||||
const downloadURL = await reference.getDownloadURL();
|
||||
return downloadURL;
|
||||
} catch (err) {
|
||||
console.log('set database image error', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export async function deleteDatabaseImage(publicKey) {
|
||||
try {
|
||||
const reference = getStorage().ref(
|
||||
`${BLITZ_PROFILE_IMG_STORAGE_REF}/${publicKey}.jpg`,
|
||||
);
|
||||
await reference.delete();
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.log('delete profime imgage error', err);
|
||||
if (err.message.includes('No object exists at the desired reference')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1212,6 +1212,9 @@ PODS:
|
||||
- ExpoModulesCore
|
||||
- EXConstants (17.0.8):
|
||||
- ExpoModulesCore
|
||||
- EXImageLoader (5.0.0):
|
||||
- ExpoModulesCore
|
||||
- React-Core
|
||||
- EXNotifications (0.29.14):
|
||||
- ExpoModulesCore
|
||||
- Expo (52.0.42):
|
||||
@@ -1226,6 +1229,10 @@ PODS:
|
||||
- ExpoModulesCore
|
||||
- ExpoFont (13.0.4):
|
||||
- ExpoModulesCore
|
||||
- ExpoImageManipulator (13.0.6):
|
||||
- EXImageLoader
|
||||
- ExpoModulesCore
|
||||
- SDWebImageWebPCoder
|
||||
- ExpoKeepAwake (14.0.3):
|
||||
- ExpoModulesCore
|
||||
- ExpoLocalAuthentication (15.0.2):
|
||||
@@ -1284,6 +1291,9 @@ PODS:
|
||||
- Firebase/Messaging (11.10.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 11.10.0)
|
||||
- Firebase/Storage (11.10.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseStorage (~> 11.10.0)
|
||||
- FirebaseAppCheckInterop (11.11.0)
|
||||
- FirebaseAuth (11.10.0):
|
||||
- FirebaseAppCheckInterop (~> 11.0)
|
||||
@@ -1366,6 +1376,13 @@ PODS:
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesSwift (~> 2.1)
|
||||
- FirebaseSharedSwift (11.11.0)
|
||||
- FirebaseStorage (11.10.0):
|
||||
- FirebaseAppCheckInterop (~> 11.0)
|
||||
- FirebaseAuthInterop (~> 11.0)
|
||||
- FirebaseCore (~> 11.10.0)
|
||||
- FirebaseCoreExtension (~> 11.10.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GTMSessionFetcher/Core (< 5.0, >= 3.4)
|
||||
- fmt (11.0.2)
|
||||
- glog (0.3.5)
|
||||
- GoogleDataTransport (10.1.0):
|
||||
@@ -1493,6 +1510,18 @@ PODS:
|
||||
- hermes-engine/Pre-built (0.77.2)
|
||||
- KeychainAccess (4.2.2)
|
||||
- leveldb-library (1.22.6)
|
||||
- libwebp (1.5.0):
|
||||
- libwebp/demux (= 1.5.0)
|
||||
- libwebp/mux (= 1.5.0)
|
||||
- libwebp/sharpyuv (= 1.5.0)
|
||||
- libwebp/webp (= 1.5.0)
|
||||
- libwebp/demux (1.5.0):
|
||||
- libwebp/webp
|
||||
- libwebp/mux (1.5.0):
|
||||
- libwebp/demux
|
||||
- libwebp/sharpyuv (1.5.0)
|
||||
- libwebp/webp (1.5.0):
|
||||
- libwebp/sharpyuv
|
||||
- lottie-ios (4.5.0)
|
||||
- lottie-react-native (7.1.0):
|
||||
- DoubleConversion
|
||||
@@ -3219,6 +3248,10 @@ PODS:
|
||||
- Yoga
|
||||
- RNDeviceInfo (14.0.4):
|
||||
- React-Core
|
||||
- RNFastImage (8.6.3):
|
||||
- React-Core
|
||||
- SDWebImage (~> 5.11.1)
|
||||
- SDWebImageWebPCoder (~> 0.8.4)
|
||||
- RNFBApp (21.13.0):
|
||||
- Firebase/CoreOnly (= 11.10.0)
|
||||
- React-Core
|
||||
@@ -3244,6 +3277,10 @@ PODS:
|
||||
- FirebaseCoreExtension
|
||||
- React-Core
|
||||
- RNFBApp
|
||||
- RNFBStorage (21.13.0):
|
||||
- Firebase/Storage (= 11.10.0)
|
||||
- React-Core
|
||||
- RNFBApp
|
||||
- RNGestureHandler (2.25.0):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
@@ -3476,6 +3513,12 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- SDWebImage (5.11.1):
|
||||
- SDWebImage/Core (= 5.11.1)
|
||||
- SDWebImage/Core (5.11.1)
|
||||
- SDWebImageWebPCoder (0.8.5):
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.10)
|
||||
- SocketRocket (0.7.1)
|
||||
- UMAppLoader (5.0.1)
|
||||
- VisionCamera (4.6.4):
|
||||
@@ -3497,6 +3540,7 @@ DEPENDENCIES:
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- EXApplication (from `../node_modules/expo-application/ios`)
|
||||
- EXConstants (from `../node_modules/expo-constants/ios`)
|
||||
- EXImageLoader (from `../node_modules/expo-image-loader/ios`)
|
||||
- EXNotifications (from `../node_modules/expo-notifications/ios`)
|
||||
- Expo (from `../node_modules/expo`)
|
||||
- ExpoAsset (from `../node_modules/expo-asset/ios`)
|
||||
@@ -3504,6 +3548,7 @@ DEPENDENCIES:
|
||||
- ExpoCrypto (from `../node_modules/expo-crypto/ios`)
|
||||
- ExpoFileSystem (from `../node_modules/expo-file-system/ios`)
|
||||
- ExpoFont (from `../node_modules/expo-font/ios`)
|
||||
- ExpoImageManipulator (from `../node_modules/expo-image-manipulator/ios`)
|
||||
- ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`)
|
||||
- ExpoLocalAuthentication (from `../node_modules/expo-local-authentication/ios`)
|
||||
- ExpoModulesCore (from `../node_modules/expo-modules-core`)
|
||||
@@ -3590,12 +3635,14 @@ DEPENDENCIES:
|
||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
|
||||
- RNFastImage (from `../node_modules/react-native-fast-image`)
|
||||
- "RNFBApp (from `../node_modules/@react-native-firebase/app`)"
|
||||
- "RNFBAuth (from `../node_modules/@react-native-firebase/auth`)"
|
||||
- "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)"
|
||||
- "RNFBFirestore (from `../node_modules/@react-native-firebase/firestore`)"
|
||||
- "RNFBFunctions (from `../node_modules/@react-native-firebase/functions`)"
|
||||
- "RNFBMessaging (from `../node_modules/@react-native-firebase/messaging`)"
|
||||
- "RNFBStorage (from `../node_modules/@react-native-firebase/storage`)"
|
||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||
- RNQrGenerator (from `../node_modules/rn-qr-generator`)
|
||||
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
||||
@@ -3630,6 +3677,7 @@ SPEC REPOS:
|
||||
- FirebaseRemoteConfigInterop
|
||||
- FirebaseSessions
|
||||
- FirebaseSharedSwift
|
||||
- FirebaseStorage
|
||||
- GoogleDataTransport
|
||||
- GoogleUtilities
|
||||
- "gRPC-C++"
|
||||
@@ -3637,12 +3685,15 @@ SPEC REPOS:
|
||||
- GTMSessionFetcher
|
||||
- KeychainAccess
|
||||
- leveldb-library
|
||||
- libwebp
|
||||
- lottie-ios
|
||||
- nanopb
|
||||
- OpenSSL-Universal
|
||||
- PromisesObjC
|
||||
- PromisesSwift
|
||||
- RecaptchaInterop
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
- SocketRocket
|
||||
- ZXingObjC
|
||||
|
||||
@@ -3659,6 +3710,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/expo-application/ios"
|
||||
EXConstants:
|
||||
:path: "../node_modules/expo-constants/ios"
|
||||
EXImageLoader:
|
||||
:path: "../node_modules/expo-image-loader/ios"
|
||||
EXNotifications:
|
||||
:path: "../node_modules/expo-notifications/ios"
|
||||
Expo:
|
||||
@@ -3673,6 +3726,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/expo-file-system/ios"
|
||||
ExpoFont:
|
||||
:path: "../node_modules/expo-font/ios"
|
||||
ExpoImageManipulator:
|
||||
:path: "../node_modules/expo-image-manipulator/ios"
|
||||
ExpoKeepAwake:
|
||||
:path: "../node_modules/expo-keep-awake/ios"
|
||||
ExpoLocalAuthentication:
|
||||
@@ -3840,6 +3895,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/@react-native-async-storage/async-storage"
|
||||
RNDeviceInfo:
|
||||
:path: "../node_modules/react-native-device-info"
|
||||
RNFastImage:
|
||||
:path: "../node_modules/react-native-fast-image"
|
||||
RNFBApp:
|
||||
:path: "../node_modules/@react-native-firebase/app"
|
||||
RNFBAuth:
|
||||
@@ -3852,6 +3909,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/@react-native-firebase/functions"
|
||||
RNFBMessaging:
|
||||
:path: "../node_modules/@react-native-firebase/messaging"
|
||||
RNFBStorage:
|
||||
:path: "../node_modules/@react-native-firebase/storage"
|
||||
RNGestureHandler:
|
||||
:path: "../node_modules/react-native-gesture-handler"
|
||||
RNQrGenerator:
|
||||
@@ -3882,6 +3941,7 @@ SPEC CHECKSUMS:
|
||||
DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb
|
||||
EXApplication: 4c72f6017a14a65e338c5e74fca418f35141e819
|
||||
EXConstants: fcfc75800824ac2d5c592b5bc74130bad17b146b
|
||||
EXImageLoader: e5da974e25b13585c196b658a440720c075482d5
|
||||
EXNotifications: 9d3d17e52c95f377750d4a2ae553a716313dd4aa
|
||||
Expo: e8f11c8e0290deca7be9254569e23f884b95a777
|
||||
ExpoAsset: 48386d40d53a8c1738929b3ed509bcad595b5516
|
||||
@@ -3889,6 +3949,7 @@ SPEC CHECKSUMS:
|
||||
ExpoCrypto: e97e864c8d7b9ce4a000bca45dddb93544a1b2b4
|
||||
ExpoFileSystem: 42d363d3b96f9afab980dcef60d5657a4443c655
|
||||
ExpoFont: f354e926f8feae5e831ec8087f36652b44a0b188
|
||||
ExpoImageManipulator: 4aca9cc1d84e31f62a7e8075c19026d3ad62f852
|
||||
ExpoKeepAwake: b0171a73665bfcefcfcc311742a72a956e6aa680
|
||||
ExpoLocalAuthentication: eb2be9c7bcdc68e9434d4be4bb5aa5cf7943e816
|
||||
ExpoModulesCore: bcee92d3a2c68c408b2d8da43e3094109340dc17
|
||||
@@ -3916,6 +3977,7 @@ SPEC CHECKSUMS:
|
||||
FirebaseRemoteConfigInterop: 85bdce8babed7814816496bb6f082bc05b0a45e1
|
||||
FirebaseSessions: 9b3b30947b97a15370e0902ee7a90f50ef60ead6
|
||||
FirebaseSharedSwift: b1d32c3b29a911dc174bcf363f2f70bda9509d2f
|
||||
FirebaseStorage: e83d1b9c8a5318d46ccfb2955f0d98095e0bf598
|
||||
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
|
||||
glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
@@ -3926,6 +3988,7 @@ SPEC CHECKSUMS:
|
||||
hermes-engine: 8eb265241fa1d7095d3a40d51fd90f7dce68217c
|
||||
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
|
||||
leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19
|
||||
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
||||
lottie-ios: a881093fab623c467d3bce374367755c272bdd59
|
||||
lottie-react-native: 34cff61bca6246919b9ee8d443ce5b869a7f05ac
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
@@ -4002,17 +4065,21 @@ SPEC CHECKSUMS:
|
||||
RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba
|
||||
RNCAsyncStorage: 923af351d21a33b6c57ed32ac9c25317ddbb0dd4
|
||||
RNDeviceInfo: d863506092aef7e7af3a1c350c913d867d795047
|
||||
RNFastImage: 462a183c4b0b6b26fdfd639e1ed6ba37536c3b87
|
||||
RNFBApp: 40dddac677bdc020c7669ffc52ed849930b8c694
|
||||
RNFBAuth: 1af20a72de76b03656c15b792e93c503dd23e5fb
|
||||
RNFBCrashlytics: 468a67446894a5234a0fd47b99b3263298546729
|
||||
RNFBFirestore: 8ab4210b7ed0ce05b92c182071a5d191a7ae957b
|
||||
RNFBFunctions: 4675adfe6256ac50c9f6808263ad4935a1de5711
|
||||
RNFBMessaging: f0760e86d85a314e39281301b4ea3e337ef12d96
|
||||
RNFBStorage: 82226bb12b3d77cc37506d23b5457aeccc79619e
|
||||
RNGestureHandler: 96fc2de36a25cf6bece93e030c2ed9a5e95d33dd
|
||||
RNQrGenerator: afacf12b55dfba0e3aaca963eec23691e8426431
|
||||
RNReanimated: b9822df9ff2671c696b1612aa88f27fab168f1fe
|
||||
RNScreens: 04304337930029a5d0db297b22eb0f07adc31a2c
|
||||
RNSVG: ca46052a4a0216157b3155e571f82d3b2d875452
|
||||
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
|
||||
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
|
||||
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
|
||||
UMAppLoader: 7e7e0eaa7854ffd652c00a68c443afb28c3bedba
|
||||
VisionCamera: f56eaedde0d3fa095143b78374d29e89e71735f9
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"@react-native-firebase/firestore": "^21.13.0",
|
||||
"@react-native-firebase/functions": "^21.13.0",
|
||||
"@react-native-firebase/messaging": "^21.13.0",
|
||||
"@react-native-firebase/storage": "21.13.0",
|
||||
"@react-navigation/bottom-tabs": "^7.3.5",
|
||||
"@react-navigation/drawer": "^7.3.4",
|
||||
"@react-navigation/native": "^7.1.6",
|
||||
@@ -47,6 +48,7 @@
|
||||
"expo-clipboard": "~7.0.1",
|
||||
"expo-crypto": "~14.0.2",
|
||||
"expo-file-system": "~18.0.12",
|
||||
"expo-image-manipulator": "~13.0.6",
|
||||
"expo-local-authentication": "~15.0.2",
|
||||
"expo-network": "~7.0.5",
|
||||
"expo-notifications": "~0.29.14",
|
||||
@@ -68,6 +70,7 @@
|
||||
"react-native-country-picker-modal": "^2.0.0",
|
||||
"react-native-device-info": "^14.0.4",
|
||||
"react-native-email-link": "^1.16.1",
|
||||
"react-native-fast-image": "^8.6.3",
|
||||
"react-native-gesture-handler": "^2.25.0",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"react-native-image-picker": "^8.2.0",
|
||||
|
||||
@@ -3610,6 +3610,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native-firebase/storage@npm:21.13.0":
|
||||
version: 21.13.0
|
||||
resolution: "@react-native-firebase/storage@npm:21.13.0"
|
||||
peerDependencies:
|
||||
"@react-native-firebase/app": 21.13.0
|
||||
checksum: a54b8e267e7e95ba6b746d320dc29ea9175049470e13eaa2804807fce3810dac989e5123bb70889a2b0b765c6ed0046af6ff8b8db5da9628f539ea064499c917
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/assets-registry@npm:0.77.2":
|
||||
version: 0.77.2
|
||||
resolution: "@react-native/assets-registry@npm:0.77.2"
|
||||
@@ -4683,6 +4692,7 @@ __metadata:
|
||||
"@react-native-firebase/firestore": ^21.13.0
|
||||
"@react-native-firebase/functions": ^21.13.0
|
||||
"@react-native-firebase/messaging": ^21.13.0
|
||||
"@react-native-firebase/storage": 21.13.0
|
||||
"@react-native/babel-preset": 0.77.2
|
||||
"@react-native/eslint-config": 0.77.2
|
||||
"@react-native/metro-config": 0.77.2
|
||||
@@ -4709,6 +4719,7 @@ __metadata:
|
||||
expo-clipboard: ~7.0.1
|
||||
expo-crypto: ~14.0.2
|
||||
expo-file-system: ~18.0.12
|
||||
expo-image-manipulator: ~13.0.6
|
||||
expo-local-authentication: ~15.0.2
|
||||
expo-network: ~7.0.5
|
||||
expo-notifications: ~0.29.14
|
||||
@@ -4733,6 +4744,7 @@ __metadata:
|
||||
react-native-device-info: ^14.0.4
|
||||
react-native-dotenv: ^3.4.11
|
||||
react-native-email-link: ^1.16.1
|
||||
react-native-fast-image: ^8.6.3
|
||||
react-native-gesture-handler: ^2.25.0
|
||||
react-native-get-random-values: ^1.11.0
|
||||
react-native-image-picker: ^8.2.0
|
||||
@@ -7829,6 +7841,26 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"expo-image-loader@npm:~5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "expo-image-loader@npm:5.0.0"
|
||||
peerDependencies:
|
||||
expo: "*"
|
||||
checksum: 7741b4b926124a1f85e51b0b8c8c9adc37fccf0654eaa0e715cb55cffc716bdc149c0421120f9bec69a69643d3328ec8562899b4aa37a0fdcecfb6fe3cf6f985
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"expo-image-manipulator@npm:~13.0.6":
|
||||
version: 13.0.6
|
||||
resolution: "expo-image-manipulator@npm:13.0.6"
|
||||
dependencies:
|
||||
expo-image-loader: ~5.0.0
|
||||
peerDependencies:
|
||||
expo: "*"
|
||||
checksum: 5e2c9e0e7f1a57f5aa24429854956db97d38b83e90fba6d6f3c4801dec087222f4845332a3e974bdef93acf6b378a8dff45fd7ba9b47fcbc5291e368a1712742
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"expo-keep-awake@npm:~14.0.3":
|
||||
version: 14.0.3
|
||||
resolution: "expo-keep-awake@npm:14.0.3"
|
||||
@@ -12590,6 +12622,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-fast-image@npm:^8.6.3":
|
||||
version: 8.6.3
|
||||
resolution: "react-native-fast-image@npm:8.6.3"
|
||||
peerDependencies:
|
||||
react: ^17 || ^18
|
||||
react-native: ">=0.60.0"
|
||||
checksum: 29289cb6b2eae0983c8922b22e2d9de3be07322bb7991c5def19f95eadefaedb0e308ff0b38cc1d0444e8bd4fe94a7621a99a2d3d9298100bcb60b3144677234
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-gesture-handler@npm:^2.25.0":
|
||||
version: 2.25.0
|
||||
resolution: "react-native-gesture-handler@npm:2.25.0"
|
||||
|
||||
Reference in New Issue
Block a user