diff --git a/packages/mobile-aelf/js/assets/image/pngs/backupWalletLogo.png b/packages/mobile-aelf/js/assets/image/pngs/backupWalletLogo.png new file mode 100644 index 0000000000..de7905ddd2 Binary files /dev/null and b/packages/mobile-aelf/js/assets/image/pngs/backupWalletLogo.png differ diff --git a/packages/mobile-aelf/js/assets/image/pngs/backupWalletSuccess.png b/packages/mobile-aelf/js/assets/image/pngs/backupWalletSuccess.png new file mode 100644 index 0000000000..85afd20a44 Binary files /dev/null and b/packages/mobile-aelf/js/assets/image/pngs/backupWalletSuccess.png differ diff --git a/packages/mobile-aelf/js/assets/image/pngs/iCloud.png b/packages/mobile-aelf/js/assets/image/pngs/iCloud.png new file mode 100644 index 0000000000..b74588026a Binary files /dev/null and b/packages/mobile-aelf/js/assets/image/pngs/iCloud.png differ diff --git a/packages/mobile-aelf/js/assets/theme/index.ts b/packages/mobile-aelf/js/assets/theme/index.ts index 1d80176205..8c7ccc4822 100644 --- a/packages/mobile-aelf/js/assets/theme/index.ts +++ b/packages/mobile-aelf/js/assets/theme/index.ts @@ -280,6 +280,7 @@ export const darkColors = { bgTransparent: 'transparent', textBase1: '#ffffff', + textBase1Opacity07: '#FFFFFFB3', // #FFFFFF ยท 70%; textBase2: '#FFFFFFB2', textBase3: '#FFFFFF66', textDisabled1: '#626264', diff --git a/packages/mobile-aelf/js/assets/theme/theme.d.ts b/packages/mobile-aelf/js/assets/theme/theme.d.ts index 051021a357..a1bf9fc84a 100644 --- a/packages/mobile-aelf/js/assets/theme/theme.d.ts +++ b/packages/mobile-aelf/js/assets/theme/theme.d.ts @@ -31,6 +31,7 @@ declare module '@rneui/themed' { bgTransparent: string; textBase1: string; + textBase1Opacity07: string; textBase2: string; textBase3: string; textDisabled1: string; diff --git a/packages/mobile-aelf/js/pages/Home/HomeTab/index.tsx b/packages/mobile-aelf/js/pages/Home/HomeTab/index.tsx index ffa0059389..fdc8f312ae 100644 --- a/packages/mobile-aelf/js/pages/Home/HomeTab/index.tsx +++ b/packages/mobile-aelf/js/pages/Home/HomeTab/index.tsx @@ -2,10 +2,12 @@ import React, { useCallback, useEffect } from 'react'; import SafeAreaBox from 'components/SafeAreaBox'; import { useTheme } from '@rneui/themed'; import { TextM } from 'components/CommonText'; +import { ScrollView } from 'react-native'; import { useCurrentAccount, useWalletListState } from '@portkey-wallet/hooks/hooks-eoa/wallet'; import CommonButton from 'components/CommonButton'; import navigationService from 'utils/navigationService'; import { useCheckSecurityLock } from 'hooks/securityLock'; +import { useBackupWalletModal } from '../../Login/hooks/useBackupWalletModal'; const HomeTab: React.FC = ({ _ }) => { const { theme } = useTheme(); @@ -28,25 +30,52 @@ const HomeTab: React.FC = ({ _ }) => { } }, [checkSecurityLock]); + const { showBackupWalletModal } = useBackupWalletModal(); + return ( - Home Tab - {`Address: ${currentAccount?.address}`} - navigationService.push('Home')}> - Home - - navigationService.push('ImportWallet')} style={{ marginTop: 40 }}> - Import Wallet - - navigationService.push('ConfirmBackup')} style={{ marginTop: 40 }}> - Confirm Backup - - navigationService.push('ManualBackup')} style={{ marginTop: 40 }}> - Manual Backup - - - Check Pin - + + Home Tab + {`Address: ${currentAccount?.address}`} + navigationService.push('Home')}> + Home + + navigationService.push('ImportWallet')} style={{ marginTop: 40 }}> + Import Wallets + + navigationService.push('WalletImportTypeSelect')} + style={{ marginTop: 40 }}> + WalletImportTypeSelect + + navigationService.push('ConfirmBackup')} style={{ marginTop: 40 }}> + Confirm Backup + + navigationService.push('ManualBackupSuccess')} + style={{ marginTop: 40 }}> + Confirm Backup Success + + navigationService.push('ManualBackup')} style={{ marginTop: 40 }}> + Manual Backup + + navigationService.push('Referral')} style={{ marginTop: 40 }}> + Referral + + + Check Pin + + { + showBackupWalletModal(); + }} + style={{ marginTop: 40 }}> + Backup Modal + + ); }; diff --git a/packages/mobile-aelf/js/pages/Login/ConfirmBackup/index.tsx b/packages/mobile-aelf/js/pages/Login/ConfirmBackup/index.tsx index 45eb06052d..10474cf8cd 100644 --- a/packages/mobile-aelf/js/pages/Login/ConfirmBackup/index.tsx +++ b/packages/mobile-aelf/js/pages/Login/ConfirmBackup/index.tsx @@ -8,6 +8,7 @@ import { pTd } from 'utils/unit'; import fonts from 'assets/theme/fonts'; import Touchable from 'components/Touchable'; import Svg from 'components/Svg'; +import navigationService from 'utils/navigationService'; export default function ConfirmBackup() { const styles = getStyles(); @@ -37,7 +38,7 @@ export default function ConfirmBackup() { return shuffleArray(shuffledWords.concat(mnemonics[currentIndex])); }, [currentIndex]); - const selectRandomIndex = useCallback(() => { + const selectRandomIndex = useCallback((): number => { if (testedIndexes.current.length === mnemonics.length) { testedIndexes.current = checkedIndexes.current; } @@ -47,31 +48,33 @@ export default function ConfirmBackup() { } else { return randomIndex; } - }, [testedIndexes, checkedIndexes]); + }, [mnemonics.length]); - const onPressWord = useCallback((word: string) => { - const index = mnemonics.indexOf(word); - testedIndexes.current.push(currentIndex); - if (index === currentIndex) { - // selected the correct word - checkedIndexes.current.push(currentIndex); - console.log('checkedIndexes : ', checkedIndexes.current); - if (checkedIndexes.current.length === 2) { - // all words are selected, go to next page - // todo_wade: go to next page + const onPressWord = useCallback( + (word: string) => { + const index = mnemonics.indexOf(word); + testedIndexes.current.push(currentIndex); + if (index === currentIndex) { + // selected the correct word + checkedIndexes.current.push(currentIndex); + console.log('checkedIndexes : ', checkedIndexes.current); + if (checkedIndexes.current.length === 2) { + navigationService.push('ManualBackupSuccess'); + } else { + setCurrentIndex(selectRandomIndex()); + setShowError(false); + } } else { - setCurrentIndex(selectRandomIndex()); - setShowError(false); + // selected the incorrect word + setShowError(true); + setTimeout(() => { + setCurrentIndex(selectRandomIndex()); + setShowError(false); + }, 2000); } - } else { - // selected the incorrect word - setShowError(true); - setTimeout(() => { - setCurrentIndex(selectRandomIndex()); - setShowError(false); - }, 2000); - } - }, [testedIndexes, currentIndex, checkedIndexes, selectRandomIndex, showError]); + }, + [testedIndexes, currentIndex, checkedIndexes, selectRandomIndex, showError], + ); useEffect(() => { setCurrentIndex(selectRandomIndex()); @@ -84,16 +87,15 @@ export default function ConfirmBackup() { pageSafeBottomPadding={!isIOS} containerStyles={styles.containerStyles} scrollViewProps={{ disabled: true }}> - Confirm Backup - Complete this quicktestto confirm you've saved everything correctly. + Verify seed phrase + Verify your seed phrase by selecting the words in the correct order. {`# ${currentIndex + 1} word`} - {`Please select the #${ - currentIndex + 1 - } Word in your Secret Recovery Phrase.`} + {`Please select the #${currentIndex + 1} word in your seed phrase.`} {showWords.map((word, index) => { return ( 0 && styles.wordButtonMarginTop]} disabled={showError} onPress={() => onPressWord(word)}> diff --git a/packages/mobile-aelf/js/pages/Login/ImportWallet/index.tsx b/packages/mobile-aelf/js/pages/Login/ImportWallet/index.tsx index 45acc14416..e51b787973 100644 --- a/packages/mobile-aelf/js/pages/Login/ImportWallet/index.tsx +++ b/packages/mobile-aelf/js/pages/Login/ImportWallet/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { Text } from 'react-native'; import PageContainer from 'components/PageContainer'; import ImportWalletTabSwitch from './ImportWalletTabSwitch'; @@ -8,12 +8,24 @@ import { isIOS } from '@portkey-wallet/utils/mobile/device'; import { makeStyles } from '@rneui/themed'; import { pTd } from 'utils/unit'; import fonts from 'assets/theme/fonts'; +import useRouterParams from '@portkey-wallet/hooks/useRouterParams'; + +type RouterParams = { + importType: string; +}; export default function ImportWallet() { const styles = getStyles(); + const { importType } = useRouterParams(); const [isPrivateKeySelected, setPrivateKeySelected] = useState(false); + useEffect(() => { + if (importType === 'privateKey') { + setPrivateKeySelected(true); + } + }, [importType]); + const onSelectedTab = useCallback( (privateKeySelected: boolean) => { setPrivateKeySelected(privateKeySelected); @@ -29,7 +41,8 @@ export default function ImportWallet() { containerStyles={styles.containerStyles} scrollViewProps={{ disabled: true }}> - {isPrivateKeySelected ? 'Import your Private key' : 'Import your Recovery phrase'} + {/*{isPrivateKeySelected ? 'Import your Private key' : 'Import your Recovery phrase'}*/} + Import your wallet {isPrivateKeySelected ? : } diff --git a/packages/mobile-aelf/js/pages/Login/ManualBackup/Success/index.tsx b/packages/mobile-aelf/js/pages/Login/ManualBackup/Success/index.tsx new file mode 100644 index 0000000000..d5ac384b2d --- /dev/null +++ b/packages/mobile-aelf/js/pages/Login/ManualBackup/Success/index.tsx @@ -0,0 +1,88 @@ +import React from 'react'; +import { Text, View } from 'react-native'; +import PageContainer from 'components/PageContainer'; +import { isIOS } from '@portkey-wallet/utils/mobile/device'; +import { makeStyles } from '@rneui/themed'; +import { pTd } from 'utils/unit'; +import fonts from 'assets/theme/fonts'; +import CommonButton from 'components/CommonButton'; +import navigationService from 'utils/navigationService'; +import CommonAvatar from 'components/CommonAvatar'; +import backUpWalletSuccessLogo from 'assets/image/pngs/backupWalletSuccess.png'; + +export default function ManualBackupSuccess() { + const styles = getStyles(); + + return ( + + + + + + Manual backup completed + You have successfully backed up your wallet. + + { + navigationService.push('Tab'); + }}> + View wallet + + + ); +} + +const getStyles = makeStyles(theme => ({ + page: { + backgroundColor: theme.colors.bgBase1, + flexDirection: 'column', + justifyContent: 'space-between', + }, + container: { + flexDirection: 'column', + alignItems: 'center', + width: '100%', + position: 'relative', + }, + logoContainer: { + marginTop: pTd(100), + height: pTd(240), + width: '100%', + flexDirection: 'column', + alignItems: 'center', + marginBottom: pTd(16), + }, + logo: { + backgroundColor: 'transparent', + }, + title: { + fontSize: pTd(32), + lineHeight: pTd(32) * 1.2, + ...fonts.BGMediumFont, + textAlign: 'center', + }, + desc: { + color: theme.colors.textBase1, + marginTop: pTd(16), + fontSize: pTd(14), + lineHeight: pTd(14) * 1.4, + textAlign: 'center', + }, + continueButton: { + marginTop: pTd(24), + marginBottom: pTd(16), + }, +})); diff --git a/packages/mobile-aelf/js/pages/Login/ManualBackup/index.tsx b/packages/mobile-aelf/js/pages/Login/ManualBackup/index.tsx index bb17edf80c..1a794e4eef 100644 --- a/packages/mobile-aelf/js/pages/Login/ManualBackup/index.tsx +++ b/packages/mobile-aelf/js/pages/Login/ManualBackup/index.tsx @@ -10,6 +10,7 @@ import Svg from 'components/Svg'; import Touchable from 'components/Touchable'; import { screenWidth } from '@portkey-wallet/utils/mobile/device'; import CommonButton from 'components/CommonButton'; +import navigationService from 'utils/navigationService'; export default function ManualBackup() { const styles = getStyles(); @@ -39,7 +40,7 @@ export default function ManualBackup() { return ( - Paste from clipboard + Copy to clipboard ); }, [onCopy, styles]); @@ -48,7 +49,7 @@ export default function ManualBackup() { return ( - Copied + Seed phrase copied ); }, [styles, theme]); @@ -58,7 +59,7 @@ export default function ManualBackup() { - Next, you'll be asked to confirm the word at certain positions in your Secret Recovery Phrase. + Next, verify your seed phrase by selecting the words in the correct order. ); @@ -73,8 +74,8 @@ export default function ManualBackup() { scrollViewProps={{ disabled: true }}> Manual backup - This is the only way to recover your account. Save your Secret Recovery Phrase in a secure place that only you - control. + Keep a copy of your seed phrase at a safe place. DO NOT share it with anyone as this could result in wallet and + asset loss. {mnemonics.map((mnemonic, index) => ( @@ -93,8 +94,13 @@ export default function ManualBackup() { {copied ? copiedView : copyButton} {reminderUI} - - I've backed up. Continue! + { + navigationService.push('ConfirmBackup'); + }}> + Continue ); diff --git a/packages/mobile-aelf/js/pages/Login/WalletImportTypeSelect/index.tsx b/packages/mobile-aelf/js/pages/Login/WalletImportTypeSelect/index.tsx new file mode 100644 index 0000000000..89b6afb533 --- /dev/null +++ b/packages/mobile-aelf/js/pages/Login/WalletImportTypeSelect/index.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import { Text, View } from 'react-native'; +import PageContainer from 'components/PageContainer'; +import { isIOS } from '@portkey-wallet/utils/mobile/device'; +import { makeStyles } from '@rneui/themed'; +import { pTd } from 'utils/unit'; +import { useCardStyles, useWalletCommonStyles } from '../styles'; +import CommonAvatar from 'components/CommonAvatar'; +import { IconName } from 'components/Svg'; +import iCloudImage from 'assets/image/pngs/iCloud.png'; +import navigationService from 'utils/navigationService'; +import Touchable from 'components/Touchable'; + +const ListItem: { + isAndroid?: boolean; + isIOS?: boolean; + svgName?: IconName; + importType?: string; + localImage?: number; + title: string; + subTitle: string; +}[] = [ + { + isAndroid: true, + svgName: 'google-drive', + title: 'Google Drive', + subTitle: 'Import your seed phrase from Google Drive.', + }, + { + isIOS: true, + localImage: iCloudImage, + title: 'iCloud', + subTitle: 'Import your seed phrase from iCloud.', + }, + { + svgName: 'recovery phrase', + title: 'Seed phrase', + importType: 'seedPhrase', + subTitle: 'Enter your seed phrase manually', + }, + { + svgName: 'private key', + title: 'Private key', + importType: 'privateKey', + subTitle: 'Enter your private key manually', + }, +]; + +export default function WalletImportTypeSelect() { + const styles = getStyles(); + const commonStyles = useWalletCommonStyles(); + const cardStyles = useCardStyles(); + + return ( + + Import your wallet + Choose your preferred method + + {ListItem.map((item, index) => { + if (item.isIOS && !isIOS) { + return null; + } + if (item.isAndroid && isIOS) { + return null; + } + return ( + { + if (!item.importType) { + return; + } + navigationService.push('ImportWallet', { + importType: item.importType, + }); + }}> + + {/* TODO: iCloud, google drive loading */} + + + {item.title} + {item.subTitle} + + + + ); + })} + + ); +} + +const getStyles = makeStyles(() => ({ + icon: { + marginRight: pTd(12), + backgroundColor: 'transparent', + }, + marginBottom40: { + marginBottom: pTd(40), + }, + marginVertical16: { + marginVertical: pTd(8), + }, +})); diff --git a/packages/mobile-aelf/js/pages/Login/hooks/useBackupWalletModal.tsx b/packages/mobile-aelf/js/pages/Login/hooks/useBackupWalletModal.tsx new file mode 100644 index 0000000000..e47185caec --- /dev/null +++ b/packages/mobile-aelf/js/pages/Login/hooks/useBackupWalletModal.tsx @@ -0,0 +1,104 @@ +import { useCallback } from 'react'; +import ActionSheet from 'components/ActionSheet'; +import { Text, View } from 'react-native'; +import CommonAvatar from 'components/CommonAvatar'; +import backUpWalletLogo from 'assets/image/pngs/backupWalletLogo.png'; +import { pTd } from 'utils/unit'; +import navigationService from 'utils/navigationService'; +import React from 'react'; +import { makeStyles } from '@rneui/themed'; +import fonts from 'assets/theme/fonts'; +import { useCheckSecurityLock } from 'hooks/securityLock'; +import { isIOS } from '@portkey-wallet/utils/mobile/device'; + +export const useBackupWalletModal = () => { + const checkSecurityLock = useCheckSecurityLock(); + const styles = getStyles(); + const showBackupWalletModal = useCallback(() => { + ActionSheet.alert({ + isCloseShow: false, + title: ( + + + + + Backup your wallet + Back up your wallet to keep your seed phrase safe and secure your assets. + + ), + buttonGroupDirection: 'column', + buttons: [ + { + type: 'primary', + title: isIOS ? 'Back up on iCloud' : 'Back up on Google Drive', + onPress: async () => { + if (isIOS) { + // TODO: iCloud + } else { + // TODO: Google Drive + } + }, + }, + { + type: 'outline', + title: 'Back up manually', + onPress: async () => { + try { + await checkSecurityLock(() => { + navigationService.push('ManualBackup'); + console.log('check success'); + }); + } catch (error) { + console.log('checkPin error', error); + } + }, + }, + { + type: 'transparent', + title: "I'll do it later", + onPress: async () => { + // Do nothing will close this modal. + console.log('I will do it later'); + }, + }, + ], + }); + }, [checkSecurityLock, styles.container, styles.logo, styles.logoContainer, styles.subTitle, styles.title]); + return { + showBackupWalletModal, + }; +}; + +const getStyles = makeStyles(() => ({ + container: { + flexDirection: 'column', + alignItems: 'center', + width: '100%', + position: 'relative', + }, + logoContainer: { + height: pTd(240), + width: '100%', + flexDirection: 'column', + alignItems: 'center', + marginBottom: pTd(24), + }, + logo: { + backgroundColor: 'transparent', + }, + title: { + ...fonts.BGMediumFont, + fontSize: pTd(32), + lineHeight: pTd(32) * 1.2, + textAlign: 'center', + width: '100%', + }, + subTitle: { + fontSize: pTd(14), + width: '100%', + lineHeight: pTd(14) * 1.4, + textAlign: 'center', + marginTop: pTd(16), + marginBottom: pTd(48), + }, +})); diff --git a/packages/mobile-aelf/js/pages/Login/index.ts b/packages/mobile-aelf/js/pages/Login/index.ts index d5288d6b06..8701f93d28 100644 --- a/packages/mobile-aelf/js/pages/Login/index.ts +++ b/packages/mobile-aelf/js/pages/Login/index.ts @@ -8,6 +8,8 @@ import LoginQRCode from './LoginQRCode'; import ImportWallet from './ImportWallet'; import ConfirmBackup from './ConfirmBackup'; import ManualBackup from './ManualBackup'; +import ManualBackupSuccess from './ManualBackup/Success'; +import WalletImportTypeSelect from './WalletImportTypeSelect'; const stackNav = [ { name: 'LoginEmail', component: LoginEmail }, @@ -18,8 +20,10 @@ const stackNav = [ { name: 'SelectCountry', component: SelectCountry }, { name: 'PrepareWallet', component: PrepareWallet, options: { gestureEnabled: false } }, { name: 'ImportWallet', component: ImportWallet }, + { name: 'WalletImportTypeSelect', component: WalletImportTypeSelect }, { name: 'ConfirmBackup', component: ConfirmBackup }, { name: 'ManualBackup', component: ManualBackup }, + { name: 'ManualBackupSuccess', component: ManualBackupSuccess }, ] as const; export default stackNav; diff --git a/packages/mobile-aelf/js/pages/Login/styles.ts b/packages/mobile-aelf/js/pages/Login/styles.ts new file mode 100644 index 0000000000..52d9b28d81 --- /dev/null +++ b/packages/mobile-aelf/js/pages/Login/styles.ts @@ -0,0 +1,49 @@ +import { makeStyles } from '@rneui/themed'; +import { pTd } from 'utils/unit'; +import fonts from 'assets/theme/fonts'; + +export const useWalletCommonStyles = makeStyles(theme => ({ + containerStyles: { + backgroundColor: theme.colors.bgBase1, + }, + title: { + marginTop: pTd(24), + // marginBottom: pTd(24), + fontSize: pTd(32), + lineHeight: pTd(32) * 1.2, + ...fonts.BGMediumFont, + }, + desc: { + color: theme.colors.textBase2, + marginTop: pTd(16), + fontSize: pTd(14), + lineHeight: pTd(14) * 1.4, + }, +})); + +export const useCardStyles = makeStyles(theme => ({ + card: { + flexDirection: 'row', + // alignItems: 'center', + backgroundColor: theme.colors.bgBase2, + paddingVertical: pTd(20), + paddingHorizontal: pTd(16), + borderRadius: pTd(8), + }, + textContainer: { + flex: 1, + }, + title: { + ...fonts.SGMediumFont, + color: theme.colors.textBase1, + fontSize: pTd(16), + fontWeight: 'bold', + lineHeight: pTd(16) * 1.4, + }, + subtitle: { + color: theme.colors.textBase1Opacity07, + fontSize: pTd(14), + lineHeight: pTd(14) * 1.4, + marginTop: pTd(4), + }, +})); diff --git a/packages/mobile-aelf/js/pages/Referral/index.tsx b/packages/mobile-aelf/js/pages/Referral/index.tsx index 1359bf381b..698a404818 100644 --- a/packages/mobile-aelf/js/pages/Referral/index.tsx +++ b/packages/mobile-aelf/js/pages/Referral/index.tsx @@ -100,7 +100,7 @@ export default function Referral() { @@ -111,7 +111,7 @@ export default function Referral() { title={'Import an existing wallet'} type="outline" onPress={() => { - //TODO: eoa add import + navigationService.navigate('WalletImportTypeSelect'); }} />