From 1a9ff1b67029f826a834a7b22e2258338a9fd719 Mon Sep 17 00:00:00 2001 From: Evan Kaloudis Date: Tue, 2 Apr 2024 19:54:58 -0400 Subject: [PATCH 1/2] PhotoUtils --- components/WalletHeader.tsx | 12 +---- models/Contact.ts | 8 ++-- utils/PhotoUtils.ts | 58 +++++++++++++++++++++++++ views/Settings/AddContact.tsx | 29 +++++-------- views/Settings/NodeConfiguration.tsx | 12 +---- views/Settings/Nodes.tsx | 17 +++----- views/Settings/SetNodePicture.tsx | 65 +++++++++------------------- views/Settings/Settings.tsx | 14 +----- 8 files changed, 103 insertions(+), 112 deletions(-) create mode 100644 utils/PhotoUtils.ts diff --git a/components/WalletHeader.tsx b/components/WalletHeader.tsx index 2359a95aa..05105b5de 100644 --- a/components/WalletHeader.tsx +++ b/components/WalletHeader.tsx @@ -12,7 +12,6 @@ import { } from 'react-native'; import { inject, observer } from 'mobx-react'; import Clipboard from '@react-native-clipboard/clipboard'; -import RNFS from 'react-native-fs'; import ChannelsStore from '../stores/ChannelsStore'; import LightningAddressStore from '../stores/LightningAddressStore'; @@ -28,6 +27,7 @@ import NodeIdenticon from '../components/NodeIdenticon'; import handleAnything, { isClipboardValue } from '../utils/handleAnything'; import BackendUtils from '../utils/BackendUtils'; +import { getPhoto } from '../utils/PhotoUtils'; import { localeString } from '../utils/LocaleUtils'; import { protectedNavigation } from '../utils/NavigationUtils'; import PrivacyUtils from '../utils/PrivacyUtils'; @@ -205,14 +205,6 @@ export default class WalletHeader extends React.Component< } } - getPhoto(photo: string | null): string { - if (typeof photo === 'string' && photo.includes('rnfs://')) { - const fileName = photo.replace('rnfs://', ''); - return `file://${RNFS.DocumentDirectoryPath}/${fileName}`; - } - return photo || ''; - } - render() { const { clipboard } = this.state; const { @@ -254,7 +246,7 @@ export default class WalletHeader extends React.Component< {selectedNode && selectedNode.photo ? ( diff --git a/models/Contact.ts b/models/Contact.ts index e86332ddb..c65c7cbac 100644 --- a/models/Contact.ts +++ b/models/Contact.ts @@ -2,6 +2,8 @@ import { computed } from 'mobx'; import BaseModel from './BaseModel'; import RNFS from 'react-native-fs'; +import { getPhoto } from '../utils/PhotoUtils'; + export default class Contact extends BaseModel { id: string; // deprecated public contactId: string; @@ -86,11 +88,7 @@ export default class Contact extends BaseModel { } @computed public get getPhoto(): string { - if (this.photo?.includes('rnfs://')) { - const fileName = this.photo.replace('rnfs://', ''); - return `file://${RNFS.DocumentDirectoryPath}/${fileName}`; - } - return this.photo || ''; + return getPhoto(this.photo || ''); } @computed public get getBanner(): string { diff --git a/utils/PhotoUtils.ts b/utils/PhotoUtils.ts new file mode 100644 index 000000000..17c6391d1 --- /dev/null +++ b/utils/PhotoUtils.ts @@ -0,0 +1,58 @@ +import { Image } from 'react-native'; +import RNFS from 'react-native-fs'; + +const zeusillustration1a = require('..//assets/images/zeus-illustration-1a.jpg'); +const zeusillustration1b = require('..//assets/images/zeus-illustration-1b.jpg'); +const zeusillustration2a = require('..//assets/images/zeus-illustration-2a.jpg'); +const zeusillustration2b = require('..//assets/images/zeus-illustration-2b.jpg'); +const zeusillustration3a = require('..//assets/images/zeus-illustration-3a.jpg'); +const zeusillustration3b = require('..//assets/images/zeus-illustration-3b.jpg'); +const zeusillustration4a = require('..//assets/images/zeus-illustration-4a.jpg'); +const zeusillustration4b = require('..//assets/images/zeus-illustration-4b.jpg'); +const zeusillustration5a = require('..//assets/images/zeus-illustration-5a.jpg'); +const zeusillustration5b = require('..//assets/images/zeus-illustration-5b.jpg'); +const zeusillustration6a = require('..//assets/images/zeus-illustration-6a.jpg'); +const zeusillustration6b = require('..//assets/images/zeus-illustration-6b.jpg'); +const zeusillustration7a = require('..//assets/images/zeus-illustration-7a.jpg'); +const zeusillustration7b = require('..//assets/images/zeus-illustration-7b.jpg'); + +const Alby = require('..//assets/images/Alby.jpg'); +const BTCpay = require('..//assets/images/BTCpay.jpg'); +const CLN = require('..//assets/images/CLN.jpg'); +const LND = require('..//assets/images/LND.jpg'); + +const getPhoto = (photo: string | null): string => { + if (typeof photo === 'string' && photo.includes('rnfs://')) { + const fileName = photo.replace('rnfs://', ''); + return `file://${RNFS.DocumentDirectoryPath}/${fileName}`; + } + if (typeof photo === 'string' && photo.includes('preset://')) { + const fileName = photo.replace('preset://', ''); + let file; + if (fileName === 'zeusillustration1a') file = zeusillustration1a; + if (fileName === 'zeusillustration2a') file = zeusillustration2a; + if (fileName === 'zeusillustration3a') file = zeusillustration3a; + if (fileName === 'zeusillustration4a') file = zeusillustration4a; + if (fileName === 'zeusillustration5a') file = zeusillustration5a; + if (fileName === 'zeusillustration6a') file = zeusillustration6a; + if (fileName === 'zeusillustration7a') file = zeusillustration7a; + + if (fileName === 'zeusillustration1b') file = zeusillustration1b; + if (fileName === 'zeusillustration2b') file = zeusillustration2b; + if (fileName === 'zeusillustration3b') file = zeusillustration3b; + if (fileName === 'zeusillustration4b') file = zeusillustration4b; + if (fileName === 'zeusillustration5b') file = zeusillustration5b; + if (fileName === 'zeusillustration6b') file = zeusillustration6b; + if (fileName === 'zeusillustration7b') file = zeusillustration7b; + + if (fileName === 'alby') file = Alby; + if (fileName === 'btcpay') file = BTCpay; + if (fileName === 'cln') file = CLN; + if (fileName === 'lnd') file = LND; + + return Image.resolveAssetSource(file).uri || ''; + } + return photo || ''; +}; + +export { getPhoto }; diff --git a/views/Settings/AddContact.tsx b/views/Settings/AddContact.tsx index 040b23140..aaf228ad3 100644 --- a/views/Settings/AddContact.tsx +++ b/views/Settings/AddContact.tsx @@ -17,21 +17,22 @@ 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'; -import KeySecurity from '../../assets/images/SVG/Key Security.svg'; -import VerifiedAccount from '../../assets/images/SVG/Verified Account.svg'; -import AddIcon from '../../assets/images/SVG/Add.svg'; -import Scan from '../../assets/images/SVG/Scan.svg'; -import { themeColor } from '../../utils/ThemeUtils'; -import AddressUtils from '../../utils/AddressUtils'; - import Button from '../../components/Button'; import { localeString } from '../../utils/LocaleUtils'; import Screen from '../../components/Screen'; import Header from '../../components/Header'; import { Row } from '../../components/layout/Row'; +import AddressUtils from '../../utils/AddressUtils'; +import { getPhoto } from '../../utils/PhotoUtils'; +import { themeColor } from '../../utils/ThemeUtils'; + +import LightningBolt from '../../assets/images/SVG/Lightning Bolt.svg'; +import BitcoinIcon from '../../assets/images/SVG/BitcoinIcon.svg'; +import KeySecurity from '../../assets/images/SVG/Key Security.svg'; +import VerifiedAccount from '../../assets/images/SVG/Verified Account.svg'; +import AddIcon from '../../assets/images/SVG/Add.svg'; +import Scan from '../../assets/images/SVG/Scan.svg'; import Star from '../../assets/images/SVG/Star.svg'; interface AddContactProps { @@ -371,14 +372,6 @@ export default class AddContact extends React.Component< } } - getPhoto(photo): string { - if (photo?.includes('rnfs://')) { - const fileName = photo.replace('rnfs://', ''); - return `file://${RNFS.DocumentDirectoryPath}/${fileName}`; - } - return photo || ''; - } - render() { const { navigation } = this.props; const { @@ -505,7 +498,7 @@ export default class AddContact extends React.Component< {photo ? ( diff --git a/views/Settings/NodeConfiguration.tsx b/views/Settings/NodeConfiguration.tsx index 8b5acf2ac..aabc9da92 100644 --- a/views/Settings/NodeConfiguration.tsx +++ b/views/Settings/NodeConfiguration.tsx @@ -12,7 +12,6 @@ import Clipboard from '@react-native-clipboard/clipboard'; import { inject, observer } from 'mobx-react'; import EncryptedStorage from 'react-native-encrypted-storage'; import cloneDeep from 'lodash/cloneDeep'; -import RNFS from 'react-native-fs'; import { hash, STORAGE_KEY } from '../../backends/LNC/credentialStore'; @@ -47,6 +46,7 @@ import SettingsStore, { import Scan from '../../assets/images/SVG/Scan.svg'; import AddIcon from '../../assets/images/SVG/Add.svg'; +import { getPhoto } from '../../utils/PhotoUtils'; import { createLndWallet } from '../../utils/LndMobileUtils'; interface NodeConfigurationProps { @@ -583,14 +583,6 @@ export default class NodeConfiguration extends React.Component< } }; - getPhoto(photo: string | null): string { - if (typeof photo === 'string' && photo.includes('rnfs://')) { - const fileName = photo.replace('rnfs://', ''); - return `file://${RNFS.DocumentDirectoryPath}/${fileName}`; - } - return photo || ''; - } - render() { const { navigation, SettingsStore } = this.props; const node = navigation.getParam('node', null); @@ -986,7 +978,7 @@ export default class NodeConfiguration extends React.Component< {node?.photo || photo ? ( { /> ); - getPhoto(photo: string | null): string { - if (typeof photo === 'string' && photo.includes('rnfs://')) { - const fileName = photo.replace('rnfs://', ''); - return `file://${RNFS.DocumentDirectoryPath}/${fileName}`; - } - return photo || ''; - } - render() { const { navigation, @@ -262,7 +255,7 @@ export default class Nodes extends React.Component { {item.photo ? ( { let presetImageUri = Image.resolveAssetSource(item).uri; + presetImageUri = presetImageUri + .replace('.png', '') + .replace('.jpg', '') + .replace(/-/g, '') + .replace(/\//g, '_') + .toLowerCase(); + + const splitDash = presetImageUri.split('_').reverse()[0]; + const split = splitDash.split('?')[0]; + + const photo = `preset://${split}`; + this.setState({ - presetImageUri + photo }); }; onChoosePicturePress = async () => { - const { presetImageUri } = this.state; const { navigation } = this.props; - if (presetImageUri) { - const timestamp = new Date().getTime(); - const fileName = `photo_${timestamp}.jpg`; - const filePath = RNFS.DocumentDirectoryPath + '/' + fileName; - - try { - const downloadResult = await RNFS.downloadFile({ - fromUrl: presetImageUri, - toFile: filePath - }).promise; - if (downloadResult.statusCode === 200) { - console.log('File downloaded to ', filePath); - this.setState({ - photo: 'rnfs://' + fileName - }); - } else { - console.error( - 'Download failed:', - downloadResult.statusCode - ); - } - } catch (error) { - console.error('Error downloading image:', error); - } - } navigation.navigate('NodeConfiguration', { photo: this.state.photo, saved: false @@ -180,7 +157,7 @@ export default class SetNodePicture extends React.Component< render() { const { navigation } = this.props; - const { photo, presetImageUri } = this.state; + const { photo } = this.state; const AddPhotos = () => ( - {photo || presetImageUri ? ( + {photo ? ( diff --git a/views/Settings/Settings.tsx b/views/Settings/Settings.tsx index d0d9da5b9..7a3671363 100644 --- a/views/Settings/Settings.tsx +++ b/views/Settings/Settings.tsx @@ -10,7 +10,6 @@ import { } from 'react-native'; import { Icon } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; -import RNFS from 'react-native-fs'; import AddIcon from '../../assets/images/SVG/Add.svg'; import BlockIcon from '../../assets/images/SVG/Block.svg'; @@ -41,6 +40,7 @@ import NodeIdenticon, { NodeTitle } from '../../components/NodeIdenticon'; import Screen from '../../components/Screen'; import BackendUtils from '../../utils/BackendUtils'; +import { getPhoto } from '../../utils/PhotoUtils'; import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; import UrlUtils from '../../utils/UrlUtils'; @@ -92,14 +92,6 @@ export default class Settings extends React.Component< this.props.navigation.removeListener('didFocus'); } - getPhoto(photo: string | null): string { - if (typeof photo === 'string' && photo.includes('rnfs://')) { - const fileName = photo.replace('rnfs://', ''); - return `file://${RNFS.DocumentDirectoryPath}/${fileName}`; - } - return photo || ''; - } - render() { const { navigation, @@ -190,9 +182,7 @@ export default class Settings extends React.Component< {selectedNode.photo ? ( From 550d3e8f9b8700b41768f0102039596d1434a8b9 Mon Sep 17 00:00:00 2001 From: Evan Kaloudis Date: Tue, 2 Apr 2024 21:28:57 -0400 Subject: [PATCH 2/2] PhotoUtils tests --- utils/PhotoUtils.test.ts | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 utils/PhotoUtils.test.ts diff --git a/utils/PhotoUtils.test.ts b/utils/PhotoUtils.test.ts new file mode 100644 index 000000000..117a668c9 --- /dev/null +++ b/utils/PhotoUtils.test.ts @@ -0,0 +1,42 @@ +import { getPhoto } from './PhotoUtils'; +jest.mock('react-native-fs', () => ({ + DocumentDirectoryPath: 'docpath' +})); +jest.mock('react-native', () => ({ + Image: { + resolveAssetSource: (file: any) => ({ + uri: file.testUri + }) + } +})); + +describe('PhotoUtils', () => { + describe('getPhoto', () => { + it('groks out rnfs:// values', () => { + expect(getPhoto('rnfs://zeus1.jpg')).toEqual( + 'file://docpath/zeus1.jpg' + ); + expect(getPhoto('rnfs://zeus2.jpg')).toEqual( + 'file://docpath/zeus2.jpg' + ); + expect(getPhoto('rnfs://zeus3.jpg')).toEqual( + 'file://docpath/zeus3.jpg' + ); + }); + + it('groks out preset:// values', () => { + expect(getPhoto('preset://lnd')).toEqual( + '../../../assets/images/LND.jpg' + ); + expect(getPhoto('preset://zeusillustration1a')).toEqual( + '../../../assets/images/zeus-illustration-1a.jpg' + ); + }); + + it('returns value as is if no match', () => { + expect(getPhoto('file://zeus1.jpg')).toEqual('file://zeus1.jpg'); + expect(getPhoto('file://zeus2.jpg')).toEqual('file://zeus2.jpg'); + expect(getPhoto('file://zeus3.jpg')).toEqual('file://zeus3.jpg'); + }); + }); +});