Skip to content

Commit

Permalink
Merge branch 'develop' into tesnet-remove-patch
Browse files Browse the repository at this point in the history
  • Loading branch information
stackchain committed Oct 14, 2021
2 parents 51e2b45 + c606239 commit e3b8d6e
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 134 deletions.
196 changes: 88 additions & 108 deletions src/components/Receive/AddressModal.js
@@ -1,161 +1,117 @@
// @flow

import Clipboard from '@react-native-community/clipboard'
import React from 'react'
import {type IntlShape, defineMessages, useIntl} from 'react-intl'
import {Image, StyleSheet, TouchableOpacity, View} from 'react-native'
import {defineMessages, useIntl} from 'react-intl'
import {StyleSheet, View} from 'react-native'
import QRCode from 'react-native-qrcode-svg'
import {useSelector} from 'react-redux'

import copiedIcon from '../../assets/img/icon/copied.png'
import copyIcon from '../../assets/img/icon/copy-ext.png'
import {formatPath} from '../../crypto/commonUtils'
import {type KeyHashesCardano, AddressDTOCardano} from '../../crypto/shelley/Address.dto'
import {AddressDTOCardano} from '../../crypto/shelley/Address.dto'
import {externalAddressIndexSelector, walletMetaSelector} from '../../selectors'
import type {WalletMeta} from '../../state'
import {Button, Modal, Text} from '../UiKit'
import {type WalletMeta} from '../../state'
import {Button, CopyButton, Modal, Spacer, Text} from '../UiKit'

type Props = {|
address: string,
index?: number,
intl: IntlShape,
onRequestClose: () => any,
visible: boolean,
onAddressVerify: () => void,
walletMeta: WalletMeta,
index: number,
|}

type State = {
isCopied: boolean,
keyHashes: KeyHashesCardano | null,
}

// eslint-disable-next-line react-prefer-function-component/react-prefer-function-component
export class AddressModal extends React.Component<Props, State> {
state = {isCopied: false, keyHashes: null}

/* eslint-disable-next-line react/sort-comp */
_hideModalTimeoutId = null

/* eslint-disable-next-line camelcase */
async UNSAFE_componentWillMount(): Promise<void> {
const {address} = this.props
const addressInfo = new AddressDTOCardano(address)

this.setState({
keyHashes: await addressInfo.getKeyHashes(),
})
}

componentWillUnmount() {
if (this._hideModalTimeoutId) clearTimeout(this._hideModalTimeoutId)
}
export const AddressModal = ({address, visible, onRequestClose, walletMeta, index, onAddressVerify}: Props) => {
const strings = useStrings()
const keyHashes = useKeyHashes(address)

_copyAddress = () => {
if (this.props.address == null) return
Clipboard.setString(this.props.address)
this.setState({isCopied: true})

// To avoid reading the clipboard, we simply reset state once the modal
// is closed
this._hideModalTimeoutId = setTimeout(() => {
this.props.onRequestClose()
this.setState({isCopied: false})
}, 1000)
}

render() {
const {isCopied, keyHashes} = this.state
const {address, index, intl, onRequestClose, visible, onAddressVerify, walletMeta} = this.props

return (
<Modal visible={visible} onRequestClose={onRequestClose} showCloseIcon>
<Text style={styles.title}>{intl.formatMessage(messages.title).toLocaleUpperCase()}</Text>

<View style={{alignItems: 'center'}}>
<QRCode value={address} size={140} backgroundColor="white" color="black" />
</View>

<View style={styles.info}>
<Text style={styles.subtitle}>{intl.formatMessage(messages.walletAddress)}</Text>
return (
<Modal visible={visible} onRequestClose={onRequestClose} showCloseIcon>
<Text style={styles.title}>{strings.title.toLocaleUpperCase()}</Text>

<View style={styles.dataContainer}>
<Text secondary monospace numberOfLines={1} ellipsizeMode="middle">
{address}
</Text>
<Spacer width={8} />

<TouchableOpacity
accessibilityLabel={intl.formatMessage(messages.copyLabel)}
accessibilityRole="button"
onPress={this._copyAddress}
>
<Image source={isCopied ? copiedIcon : copyIcon} />
</TouchableOpacity>
</View>
<View style={{alignItems: 'center'}}>
<QRCode value={address} size={140} backgroundColor="white" color="black" />
</View>

<Text style={styles.subtitle}>{intl.formatMessage(messages.BIP32path)}</Text>
<Spacer width={4} />

<Text secondary monospace>
{index != null && <>{formatPath(0, 'External', index, walletMeta.walletImplementationId)}</>}
<Info>
<Text style={styles.subtitle}>{strings.walletAddress}</Text>
<Row>
<Text style={{flex: 1}} secondary monospace numberOfLines={1} ellipsizeMode="middle">
{address}
</Text>

<Text style={styles.subtitle}>{intl.formatMessage(messages.staking)}</Text>

<Text secondary monospace>
{keyHashes?.staking}
</Text>

<Text style={styles.subtitle}>{intl.formatMessage(messages.spending)}</Text>

<Text secondary monospace>
{keyHashes?.spending}
</Text>
</View>

{walletMeta.isHW && (
<Button onPress={onAddressVerify} title={intl.formatMessage(messages.verifyLabel)} style={styles.button} />
)}
</Modal>
)
}
<Spacer width={16} />
<CopyButton
value={address}
onCopy={() => {
setTimeout(onRequestClose, 1000)
}}
/>
</Row>

<Spacer width={8} />

<Text style={styles.subtitle}>{strings.BIP32path}</Text>
<Text secondary monospace>
{index != null && formatPath(0, 'External', index, walletMeta.walletImplementationId)}
</Text>

<Spacer width={8} />

<Text style={styles.subtitle}>{strings.staking}</Text>
<Text secondary monospace>
{keyHashes?.staking}
</Text>

<Spacer width={8} />

<Text style={styles.subtitle}>{strings.spending}</Text>
<Text secondary monospace>
{keyHashes?.spending}
</Text>
</Info>

<Spacer height={16} />

{walletMeta.isHW && <Button onPress={onAddressVerify} title={strings.verifyLabel} />}
</Modal>
)
}

type ExternalProps = {|
address: ?string,
address: string,
onRequestClose: () => any,
visible: boolean,
onAddressVerify: () => void,
|}

export default (props: ExternalProps) => {
const intl = useIntl()
const index = useSelector(externalAddressIndexSelector)[props.address]
const walletMeta = useSelector(walletMetaSelector)

// $FlowFixMe
return <AddressModal intl={intl} index={index} walletMeta={walletMeta} {...props} />
return <AddressModal index={index} walletMeta={walletMeta} {...props} />
}

const Info = (props) => <View {...props} style={styles.info} />
const Row = (props) => <View {...props} style={styles.row} />

const styles = StyleSheet.create({
info: {
alignItems: 'flex-start',
},
title: {
textAlign: 'center',
fontWeight: 'bold',
paddingBottom: 18,
},
subtitle: {
textAlign: 'center',
paddingTop: 14,
paddingBottom: 4,
},
button: {
paddingTop: 10,
},
dataContainer: {
row: {
flexDirection: 'row',
paddingRight: 70,
},
})

Expand Down Expand Up @@ -189,3 +145,27 @@ const messages = defineMessages({
defaultMessage: '!!!Verify Address on Ledger',
},
})
const useStrings = () => {
const intl = useIntl()

return {
walletAddress: intl.formatMessage(messages.walletAddress),
BIP32path: intl.formatMessage(messages.BIP32path),
copyLabel: intl.formatMessage(messages.copyLabel),
spending: intl.formatMessage(messages.spending),
staking: intl.formatMessage(messages.staking),
title: intl.formatMessage(messages.title),
verifyLabel: intl.formatMessage(messages.verifyLabel),
}
}

const useKeyHashes = (address) => {
const [keyHashes, setKeyHashes] = React.useState(null)

React.useEffect(() => {
const addressInfo = new AddressDTOCardano(address)
addressInfo.getKeyHashes().then(setKeyHashes)
}, [address])

return keyHashes
}
71 changes: 47 additions & 24 deletions src/components/Receive/AddressModal.stories.js
Expand Up @@ -10,27 +10,50 @@ import {AddressModal} from './AddressModal'
const address =
'addr1qxxvt9rzpdxxysmqp50d7f5a3gdescgrejsu7zsdxqjy8yun4cngaq46gr8c9qyz4td9ddajzqhjnrqvfh0gspzv9xnsmq6nqx'

storiesOf('AddressModal', module).add('default', ({intl}) => (
<WithModalProps>
{({visible, onRequestClose}) => (
<AddressModal
intl={intl}
index={1}
walletMeta={{
id: 'wallet-id',
name: 'AsdasdA',
networkId: 1,
provider: '',
walletImplementationId: 'haskell-shelley',
checksum: {TextPart: 'adsdasddasd', ImagePart: 'asdasdasd'},
isEasyConfirmationEnabled: false,
isHW: false,
}}
onAddressVerify={action('onAddressVerify')}
address={address}
visible={visible}
onRequestClose={onRequestClose}
/>
)}
</WithModalProps>
))
storiesOf('AddressModal', module)
.add('default', () => (
<WithModalProps>
{({visible, onRequestClose}) => (
<AddressModal
index={1}
walletMeta={{
id: 'wallet-id',
name: 'AsdasdA',
networkId: 1,
provider: '',
walletImplementationId: 'haskell-shelley',
checksum: {TextPart: 'adsdasddasd', ImagePart: 'asdasdasd'},
isEasyConfirmationEnabled: false,
isHW: false,
}}
onAddressVerify={action('onAddressVerify')}
address={address}
visible={visible}
onRequestClose={onRequestClose}
/>
)}
</WithModalProps>
))
.add('isHW', () => (
<WithModalProps>
{({visible, onRequestClose}) => (
<AddressModal
index={1}
walletMeta={{
id: 'wallet-id',
name: 'AsdasdA',
networkId: 1,
provider: '',
walletImplementationId: 'haskell-shelley',
checksum: {TextPart: 'adsdasddasd', ImagePart: 'asdasdasd'},
isEasyConfirmationEnabled: false,
isHW: true,
}}
onAddressVerify={action('onAddressVerify')}
address={address}
visible={visible}
onRequestClose={onRequestClose}
/>
)}
</WithModalProps>
))
11 changes: 9 additions & 2 deletions src/components/UiKit/CopyButton.js
Expand Up @@ -9,13 +9,20 @@ import {useCopy} from '../../utils/useCopy'

export type CopyButtonProps = {|
value: string,
onCopy?: () => void,
|}

export const CopyButton = ({value}: CopyButtonProps) => {
export const CopyButton = ({value, onCopy}: CopyButtonProps) => {
const [isCopying, copy] = useCopy()

return (
<TouchableOpacity onPress={() => copy(value)} disabled={isCopying}>
<TouchableOpacity
onPress={() => {
copy(value)
onCopy?.()
}}
disabled={isCopying}
>
<Image source={isCopying ? copiedIcon : copyIcon} />
</TouchableOpacity>
)
Expand Down

0 comments on commit e3b8d6e

Please sign in to comment.