Skip to content

Commit

Permalink
Downloading banner and photos and saving them locally
Browse files Browse the repository at this point in the history
  • Loading branch information
shubhamkmr04 committed Jan 17, 2024
1 parent 444fa03 commit 184b093
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 79 deletions.
10 changes: 8 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@ PODS:
- React
- RNCPicker (2.4.8):
- React-Core
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.12.1):
- React-Core
- RNKeychain (8.1.1):
Expand Down Expand Up @@ -589,6 +591,7 @@ DEPENDENCIES:
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- "RNCPicker (from `../node_modules/@react-native-picker/picker`)"
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNKeychain (from `../node_modules/react-native-keychain`)
- RNPermissions (from `../node_modules/react-native-permissions`)
Expand Down Expand Up @@ -734,6 +737,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-community/masked-view"
RNCPicker:
:path: "../node_modules/@react-native-picker/picker"
RNFS:
:path: "../node_modules/react-native-fs"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNKeychain:
Expand All @@ -756,7 +761,7 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"

SPEC CHECKSUMS:
boost: 57d2868c099736d80fcd648bf211b4431e51a558
boost: a7c83b31436843459a1961bfd74b96033dc77234
BVLinearGradient: 34a999fda29036898a09c6a6b728b0b4189e1a44
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
Expand All @@ -768,7 +773,7 @@ SPEC CHECKSUMS:
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
lottie-ios: 8f97d3271e155c2d688875c29cd3c74908aef5f8
lottie-react-native: 8f9d4be452e23f6e5ca0fdc11669dc99ab52be81
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
RCTRequired: df81ab637d35fac9e6eb94611cfd20f0feb05455
RCTTypeSafety: 4636e4a36c7c2df332bda6d59b19b41c443d4287
React: e0cc5197a804031a6c53fb38483c3485fcb9d6f3
Expand Down Expand Up @@ -821,6 +826,7 @@ SPEC CHECKSUMS:
RNCClipboard: 99fc8ad669a376b756fbc8098ae2fd05c0ed0668
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNCPicker: 0bf8ef8f7800524f32d2bb2a8bcadd53eda0ecd1
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: c0d04458598fcb26052494ae23dda8f8f5162b13
RNKeychain: ff836453cba46938e0e9e4c22e43d43fa2c90333
RNPermissions: 06845210af313594dc3fe5e8ae6afc820d791409
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"react-native-draglist": "3.5.1",
"react-native-elements": "3.4.3",
"react-native-encrypted-storage": "4.0.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "2.12.1",
"react-native-get-random-values": "1.9.0",
"react-native-hce": "0.1.2",
Expand Down
178 changes: 107 additions & 71 deletions views/NostrContacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { v4 as uuidv4 } from 'uuid';
import { CheckBox, Icon } from 'react-native-elements';
import EncryptedStorage from 'react-native-encrypted-storage';
import { relayInit, nip05, nip19 } from 'nostr-tools';
import RNFS from 'react-native-fs';

import Button from '../components/Button';
import Header from '../components/Header';
Expand Down Expand Up @@ -196,31 +197,84 @@ export default class NostrContacts extends React.Component<
});
}

transformContactData = (contact: any) => {
return {
photo: contact?.picture,
name: contact?.display_name || contact?.name,
description: contact?.about,
lnAddress: contact?.lud16
? [contact?.lud16]
: contact?.lud06
? [contact?.lud06]
: contact?.lud16 && contact?.lud06
? [contact?.lud06, contact?.lud16]
: [],
onchainAddress: [''],
pubkey: [''],
nip05: contact?.nip05 ? [contact?.nip05] : [],
nostrNpub: contact?.npub
? [contact?.npub]
: contact?.pubkey
? [nip19.npubEncode(contact.pubkey)]
: [],
contactId: uuidv4(),
isFavourite: false,
banner: contact?.banner,
isSelected: false
};
transformContactData = async (contact: any) => {
try {
const name = contact?.display_name || contact?.name || '';
const transformedContact = {
photo: '',
name,
description: contact?.about || '',
lnAddress: contact?.lud16
? [contact?.lud16]
: contact?.lud06
? [contact?.lud06]
: contact?.lud16 && contact?.lud06
? [contact?.lud06, contact?.lud16]
: [],
onchainAddress: [''],
pubkey: [''],
nip05: contact?.nip05 ? [contact?.nip05] : [],
nostrNpub: contact?.npub
? [contact?.npub]
: contact?.pubkey
? [nip19.npubEncode(contact.pubkey)]
: [],
contactId: uuidv4(),
isFavourite: false,
banner: '',
isSelected: false
};

if (contact?.banner) {
console.log('Downloading banner...');
const bannerFileName =
'nostrContactBanner_' + transformedContact.name + '.png';
const bannerFilePath =
RNFS.DocumentDirectoryPath + '/' + bannerFileName;

try {
// Download the banner and save it locally
await RNFS.downloadFile({
fromUrl: contact?.banner,
toFile: bannerFilePath
}).promise;

console.log('Banner download successful!');
transformedContact.banner = 'file://' + bannerFilePath;
} catch (bannerError) {
console.error('Error downloading banner:', bannerError);
}
}

console.log('Transformed contact:', transformedContact);

if (contact?.picture) {
console.log('Downloading image...');
const fileName =
'nostrContactPhoto_' +
transformedContact.contactId +
'.png';
const filePath = RNFS.DocumentDirectoryPath + '/' + fileName;

try {
// Download the image and save it locally
await RNFS.downloadFile({
fromUrl: contact?.picture,
toFile: filePath
}).promise;

console.log('Download successful!');
transformedContact.photo = 'file://' + filePath;
} catch (photoError) {
console.error('Error downloading photo:', photoError);
}
}

return transformedContact;
} catch (error) {
console.error('Error transforming contact:', error);
return null;
}
};

toggleContactSelection = (contact: any) => {
Expand Down Expand Up @@ -267,7 +321,7 @@ export default class NostrContacts extends React.Component<
return `${str.substring(0, 6)}...${str.substring(str.length - 6)}`;
};

if (!item.name && !item.display_name) {
if (!item?.name && !item?.display_name) {
return null;
}

Expand All @@ -286,14 +340,12 @@ export default class NostrContacts extends React.Component<

return (
<TouchableOpacity
onPress={() => {
onPress={async () => {
if (isSelectionMode) {
this.toggleContactSelection(
this.transformContactData(item)
);
this.toggleContactSelection(item);
} else {
navigation.navigate('ContactDetails', {
nostrContact: this.transformContactData(item),
nostrContact: await this.transformContactData(item),
isNostrContact: true
});
}
Expand All @@ -314,9 +366,7 @@ export default class NostrContacts extends React.Component<
<CheckBox
checked={isSelected}
onPress={() => {
this.toggleContactSelection(
this.transformContactData(item)
);
this.toggleContactSelection(item);
}}
/>
</Animated.View>
Expand Down Expand Up @@ -349,7 +399,7 @@ export default class NostrContacts extends React.Component<
color: themeColor('text')
}}
>
{item.display_name || item.name}
{item?.display_name || item?.name}
</Text>
{item.lud06 && (
<Text
Expand Down Expand Up @@ -377,47 +427,33 @@ export default class NostrContacts extends React.Component<
);
};

importSelectedContacts = async () => {
importContacts = async () => {
try {
const { selectedContacts } = this.state;

// Retrieve existing contacts from Encrypted storage
const contactsString = await EncryptedStorage.getItem(
'zeus-contacts'
);
const existingContacts: any = contactsString
? JSON.parse(contactsString)
: [];
let contactsToImport = [];

// Merge existing contacts with the selected contacts
const updatedContacts = [
...existingContacts,
...selectedContacts
].sort((a, b) => a.name.localeCompare(b.name));
// Check if selectedContacts is not empty, use it; otherwise, use contactsData
if (this.state.selectedContacts.length > 0) {
contactsToImport = this.state.selectedContacts;
} else {
contactsToImport = this.state.contactsData;
}

// Save the updated contacts to encrypted storage
await EncryptedStorage.setItem(
'zeus-contacts',
JSON.stringify(updatedContacts)
// Remove null values and contacts without name or display_name
contactsToImport = contactsToImport.filter(
(contact) =>
contact !== null &&
(contact?.name || contact?.display_name) &&
contact?.picture &&
(contact?.lud06 || contact.lud16)
);

console.log('Contacts imported successfully!');
} catch (error) {
console.log('Error importing contacts:', error);
Alert.alert(
localeString('general.error'),
localeString('views.NostrContacts.importContactsError')
// Transform Nostr contacts data to match the format in AddContact
const transformedContactsPromises = contactsToImport.map(
(contact) => this.transformContactData(contact)
);
}
};

importAllContacts = async () => {
try {
const contactsToImport = this.state.contactsData;

// Transform Nostr contacts data to match the format in AddContact
const transformedContacts = contactsToImport.map((contact) =>
this.transformContactData(contact)
const transformedContacts = await Promise.all(
transformedContactsPromises
);

// Retrieve existing contacts from Encrypted storage
Expand Down Expand Up @@ -623,7 +659,7 @@ export default class NostrContacts extends React.Component<
'views.NostrContacts.importAllContacts'
)}
onPress={() => {
this.importAllContacts();
this.importContacts();
navigation.navigate('Contacts');
}}
containerStyle={{
Expand All @@ -643,7 +679,7 @@ export default class NostrContacts extends React.Component<
: ''
}`}
onPress={() => {
this.importSelectedContacts();
this.importContacts();
navigation.navigate('Contacts');
}}
containerStyle={{ paddingBottom: 12, paddingTop: 8 }}
Expand Down
29 changes: 25 additions & 4 deletions views/Settings/AddContact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { v4 as uuidv4 } from 'uuid';
import EncryptedStorage from 'react-native-encrypted-storage';
import { Icon, Divider } from 'react-native-elements';
import { launchImageLibrary } from 'react-native-image-picker';
import RNFS from 'react-native-fs';

import LightningBolt from '../../assets/images/SVG/Lightning Bolt.svg';
import BitcoinIcon from '../../assets/images/SVG/BitcoinIcon.svg';
Expand Down Expand Up @@ -260,13 +261,33 @@ export default class AddContact extends React.Component<
maxHeight: 500,
includeBase64: true
},
(response: any) => {
async (response: any) => {
if (!response.didCancel) {
const asset = response?.assets[0];
if (asset.base64) {
this.setState({
photo: `data:image/png;base64,${asset.base64}`
});
// Generate a unique name for the image
const timestamp = new Date().getTime(); // Timestamp
const fileName = `photo_${timestamp}.png`;

const filePath =
RNFS.DocumentDirectoryPath + '/' + fileName;

try {
// Write the base64 data to the file
await RNFS.writeFile(
filePath,
asset.base64,
'base64'
);
console.log('File saved to ', filePath);

// Set the local file path in the state
this.setState({
photo: 'file://' + filePath
});
} catch (error) {
console.error('Error saving file: ', error);
}
}
}
}
Expand Down
12 changes: 10 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3198,7 +3198,7 @@ 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:
base-64@0.1.0, 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==
Expand Down Expand Up @@ -8098,6 +8098,14 @@ react-native-encrypted-storage@4.0.3:
resolved "https://registry.yarnpkg.com/react-native-encrypted-storage/-/react-native-encrypted-storage-4.0.3.tgz#2a4d65459870511e8f4ccd22f02433dab7fa5e91"
integrity sha512-0pJA4Aj2S1PIJEbU7pN/Qvf7JIJx3hFywx+i+bLHtgK0/6Zryf1V2xVsWcrD50dfiu3jY1eN2gesQ5osGxE7jA==

react-native-fs@^2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/react-native-fs/-/react-native-fs-2.20.0.tgz#05a9362b473bfc0910772c0acbb73a78dbc810f6"
integrity sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==
dependencies:
base-64 "^0.1.0"
utf8 "^3.0.0"

react-native-gesture-handler@2.12.1:
version "2.12.1"
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.12.1.tgz#f11a99fb95169810c6886fad5efa01a17fd81660"
Expand Down Expand Up @@ -9545,7 +9553,7 @@ use-sync-external-store@^1.0.0:
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==

utf8@3.0.0:
utf8@3.0.0, utf8@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==
Expand Down

0 comments on commit 184b093

Please sign in to comment.