From 2a19605d76d7618309934fd3986537002fce7f3a Mon Sep 17 00:00:00 2001 From: First-Terraner Date: Wed, 27 Mar 2024 17:31:04 +0100 Subject: [PATCH 01/10] remove restore comments, disable autoCapitalize for seed confirmation --- src/components/TxtInput.tsx | 5 ++++- src/screens/Restore/ConfirmMnemonic.tsx | 14 +------------- src/screens/Restore/Recovering.tsx | 4 ---- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/components/TxtInput.tsx b/src/components/TxtInput.tsx index 5d18ba82..f13c0c62 100644 --- a/src/components/TxtInput.tsx +++ b/src/components/TxtInput.tsx @@ -17,6 +17,7 @@ interface ITxtInputProps { multiline?: boolean numberOfLines?: number style?: StyleProp + autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters' } export default function TxtInput({ @@ -31,7 +32,8 @@ export default function TxtInput({ value, multiline, numberOfLines, - style + style, + autoCapitalize }: ITxtInputProps) { const { color, highlight } = useThemeContext() const inputRef = createRef() @@ -58,6 +60,7 @@ export default function TxtInput({ value={value} multiline={multiline} numberOfLines={numberOfLines} + autoCapitalize={autoCapitalize} style={[globals(color).input, { marginBottom: vs(20) }, style]} /> ) diff --git a/src/screens/Restore/ConfirmMnemonic.tsx b/src/screens/Restore/ConfirmMnemonic.tsx index 9ff56bed..270c0c9a 100644 --- a/src/screens/Restore/ConfirmMnemonic.tsx +++ b/src/screens/Restore/ConfirmMnemonic.tsx @@ -17,19 +17,6 @@ import { useTranslation } from 'react-i18next' import { KeyboardAvoidingView, type TextInput, View } from 'react-native' import { ScaledSheet } from 'react-native-size-matters' -/* - -manual test cases: ---- -[OK] * Start new seed wallet: confirm mnemonic, set pin, add mint, mint, send, receive, melt, restore -[OK] * Start new quick wallet: skip pin, add mint, activate seed, mint, send, receive, restore -[OK] * Start new recovery wallet: paste seed, restore, set pin, send, receive, melt, mint, restore -[OK] * Start new quick wallet, skip pin, skip mint, restore, send, receive, melt, mint, restore -[ ] * ... -[ ] * ... - -*/ - export default function ConfirmMnemonicScreen({ navigation, route }: IConfirmMnemonicPageProps) { const { t } = useTranslation([NS.common]) @@ -103,6 +90,7 @@ export default function ConfirmMnemonicScreen({ navigation, route }: IConfirmMne placeholder={`Seed (${randomInt + 1}.)`} onChangeText={text => setInput(text)} onSubmitEditing={() => void handleConfirm()} + autoCapitalize='none' autoFocus ms={200} /> diff --git a/src/screens/Restore/Recovering.tsx b/src/screens/Restore/Recovering.tsx index a6bcac29..328897d5 100644 --- a/src/screens/Restore/Recovering.tsx +++ b/src/screens/Restore/Recovering.tsx @@ -13,10 +13,6 @@ import { useTranslation } from 'react-i18next' import { View } from 'react-native' import { s, ScaledSheet } from 'react-native-size-matters' -// TODO -// show internet connection status -// show different quotes messages during the process - export default function RecoveringScreen({ navigation, route }: IRecoveringPageProps) { const { mintUrl, mnemonic, comingFromOnboarding } = route.params From 4a8e2b829032e87fd2731199ab07f1bc028b7124 Mon Sep 17 00:00:00 2001 From: First-Terraner Date: Wed, 27 Mar 2024 17:38:01 +0100 Subject: [PATCH 02/10] empty useEffect deps array for restore hook --- src/components/hooks/Restore.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/hooks/Restore.tsx b/src/components/hooks/Restore.tsx index b2a02b78..176fdd6d 100644 --- a/src/components/hooks/Restore.tsx +++ b/src/components/hooks/Restore.tsx @@ -130,7 +130,8 @@ export function useRestore({ mintUrl, mnemonic, comingFromOnboarding }: IUseRest } } void restore() - }, [comingFromOnboarding, mintUrl, mnemonic, navigation, openPromptAutoClose, t]) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) return { ...restored } } From f4267fff01670a846f3a0b9ac886320046c7c454 Mon Sep 17 00:00:00 2001 From: First-Terraner Date: Wed, 27 Mar 2024 21:37:18 +0100 Subject: [PATCH 03/10] Add keysetId to Recovering screen --- src/components/hooks/Restore.tsx | 61 +++++++++++++++++++----------- src/model/nav.ts | 3 ++ src/screens/Dashboard.tsx | 8 ++++ src/screens/Restore/Recover.tsx | 5 ++- src/screens/Restore/Recovering.tsx | 45 ++++++++++++---------- 5 files changed, 79 insertions(+), 43 deletions(-) diff --git a/src/components/hooks/Restore.tsx b/src/components/hooks/Restore.tsx index 176fdd6d..4e0295f7 100644 --- a/src/components/hooks/Restore.tsx +++ b/src/components/hooks/Restore.tsx @@ -18,25 +18,26 @@ type StackNavigation = NavigationProp type TRestoreInterval = Promise<{ proofs: Proof[]; newKeys?: MintKeys; lastCount: number } | undefined> interface IUseRestoreProps { + from?: number + to?: number mintUrl: string + keysetId: string mnemonic: string comingFromOnboarding?: boolean } -const defaultRestoreState = { - proofs: [] as Proof[], - from: 0, - to: RESTORE_INTERVAL, - overshoot: 0, -} - -export function useRestore({ mintUrl, mnemonic, comingFromOnboarding }: IUseRestoreProps) { +export function useRestore({ from, to, mintUrl, keysetId, mnemonic, comingFromOnboarding }: IUseRestoreProps) { const navigation = useNavigation() const { t } = useTranslation([NS.common]) const { openPromptAutoClose } = usePromptContext() - const [restored, setRestored] = useState({ ...defaultRestoreState }) + const [restored, setRestored] = useState({ + proofs: [] as Proof[], + start: from ?? 0, + end: to ?? RESTORE_INTERVAL, + overshoot: 0, + }) useEffect(() => { const restore = async () => { @@ -45,7 +46,12 @@ export function useRestore({ mintUrl, mnemonic, comingFromOnboarding }: IUseRest const proofs = await restoreWallet(mintUrl, mnemonic) if (!proofs?.length) { openPromptAutoClose({ msg: t('noProofsRestored'), success: false }) - setRestored({ ...defaultRestoreState }) + setRestored({ + proofs: [] as Proof[], + start: from ?? 0, + end: to ?? RESTORE_INTERVAL, + overshoot: 0, + }) if (comingFromOnboarding) { return navigation.navigate('auth', { pinHash: '' }) } @@ -58,7 +64,12 @@ export function useRestore({ mintUrl, mnemonic, comingFromOnboarding }: IUseRest type: 4, value: '', }) - setRestored({ ...defaultRestoreState }) + setRestored({ + proofs: [] as Proof[], + start: from ?? 0, + end: to ?? RESTORE_INTERVAL, + overshoot: 0, + }) navigation.navigate('success', { mint: mintUrl, amount: bal, @@ -67,7 +78,12 @@ export function useRestore({ mintUrl, mnemonic, comingFromOnboarding }: IUseRest }) } catch (e) { l('[handleRecovery] error: ', e) - setRestored({ ...defaultRestoreState }) + setRestored({ + proofs: [] as Proof[], + start: from ?? 0, + end: to ?? RESTORE_INTERVAL, + overshoot: 0, + }) navigation.navigate('processingError', { errorMsg: isErr(e) ? e.message : t('restoreErr'), comingFromOnboarding, @@ -77,8 +93,7 @@ export function useRestore({ mintUrl, mnemonic, comingFromOnboarding }: IUseRest const restoreWallet = async (mintUrl: string, mnemonic: string) => { try { const { wallet, seed } = await getSeedWalletByMnemonic({ mintUrl, mnemonic }) - // TODO get previous keysets from mint and try to restore from them - const resp = await restoreInterval(wallet, 0, RESTORE_INTERVAL) + const resp = await restoreInterval(wallet, from ?? 0, to ?? RESTORE_INTERVAL) if (!resp) { l('[restoreWallet] restore interval did not return a proper object!') throw new Error('[restoreWallet] restore interval did not return a proper object!') @@ -102,29 +117,29 @@ export function useRestore({ mintUrl, mnemonic, comingFromOnboarding }: IUseRest } const restoreInterval = async ( wallet: CashuWallet, - from: number, - to: number, + start: number, + end: number, restoredProofs: Proof[] = [], overshoot: number = 0 ): TRestoreInterval => { try { - setRestored({ proofs: restoredProofs, from, to, overshoot }) - const { proofs, newKeys } = await wallet.restore(from, to) - from += RESTORE_INTERVAL - to += RESTORE_INTERVAL + setRestored({ proofs: restoredProofs, start, end, overshoot }) + const { proofs, newKeys } = await wallet.restore(start, end, keysetId) + start += RESTORE_INTERVAL + end += RESTORE_INTERVAL if (proofs.length) { l('[restoreInterval] restored proofs: ', { from, to, proofsLength: proofs.length }) restoredProofs.push(...proofs) overshoot = 0 - return restoreInterval(wallet, from, to, restoredProofs, overshoot) + return restoreInterval(wallet, start, end, restoredProofs, overshoot) } if (overshoot < RESTORE_OVERSHOOT) { l('[restoreInterval] no proofs to restore! overshooting now: ', { from, to, proofsLength: proofs.length, overshoot }) overshoot++ - return restoreInterval(wallet, from, to, restoredProofs, overshoot) + return restoreInterval(wallet, start, end, restoredProofs, overshoot) } l('[restoreInterval] no proofs to restore! overshooting limit reached: ', { from, to, restoredProofs: restoredProofs.length, overshoot }) - return { proofs: restoredProofs, newKeys, lastCount: to } + return { proofs: restoredProofs, newKeys, lastCount: end } } catch (e) { l('[restoreInterval] error', { e }) } diff --git a/src/model/nav.ts b/src/model/nav.ts index d513f067..638a0783 100644 --- a/src/model/nav.ts +++ b/src/model/nav.ts @@ -236,7 +236,10 @@ export type RootStackParamList = { comingFromOnboarding?: boolean } Recovering: { + from?: number + to?: number mintUrl: string + keysetId: string mnemonic: string comingFromOnboarding?: boolean } diff --git a/src/screens/Dashboard.tsx b/src/screens/Dashboard.tsx index 6f0e0626..9c4bf19f 100644 --- a/src/screens/Dashboard.tsx +++ b/src/screens/Dashboard.tsx @@ -308,6 +308,14 @@ export default function Dashboard({ navigation, route }: TDashboardPageProps) { color={hi[highlight]} onPress={() => { setModal(prev => ({ ...prev, sendOpts: true })) + // navigation.navigate('Recovering', { + // from: 500, + // to: 550, + // mintUrl: 'https://testnut.cashu.space', + // keysetId: 'asfdafh8u2h3', + // mnemonic: '', + // comingFromOnboarding: false, + // }) }} /> : diff --git a/src/screens/Restore/Recover.tsx b/src/screens/Restore/Recover.tsx index 5c56ce04..98f2af39 100644 --- a/src/screens/Restore/Recover.tsx +++ b/src/screens/Restore/Recover.tsx @@ -7,6 +7,7 @@ import TxtInput from '@comps/TxtInput' import { isIOS } from '@consts' import type { IRecoverPageProps } from '@model/nav' import { NS } from '@src/i18n' +import { getMintCurrentKeySetId } from '@src/wallet' import { createRef, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { KeyboardAvoidingView, type TextInput, View } from 'react-native' @@ -19,10 +20,12 @@ export default function RecoverScreen({ navigation, route }: IRecoverPageProps) const { loading } = useLoading() const inputRef = createRef() - const handleBtnPress = () => { + const handleBtnPress = async () => { if (loading || !input.length) { return } + const keysetId = await getMintCurrentKeySetId(route.params.mintUrl) navigation.navigate('Recovering', { mintUrl: route.params.mintUrl, + keysetId, mnemonic: input, comingFromOnboarding: route.params.comingFromOnboarding, }) diff --git a/src/screens/Restore/Recovering.tsx b/src/screens/Restore/Recovering.tsx index 328897d5..4987390a 100644 --- a/src/screens/Restore/Recovering.tsx +++ b/src/screens/Restore/Recovering.tsx @@ -15,11 +15,11 @@ import { s, ScaledSheet } from 'react-native-size-matters' export default function RecoveringScreen({ navigation, route }: IRecoveringPageProps) { - const { mintUrl, mnemonic, comingFromOnboarding } = route.params + const { from, to, mintUrl, keysetId, mnemonic, comingFromOnboarding } = route.params const { t } = useTranslation([NS.common]) // Seed recovery process in useRestore hook - const { proofs, from, to, overshoot } = useRestore({ mintUrl, mnemonic, comingFromOnboarding }) + const { proofs, start, end, overshoot } = useRestore({ from, to, mintUrl, keysetId, mnemonic, comingFromOnboarding }) const { color } = useThemeContext() @@ -37,6 +37,24 @@ export default function RecoveringScreen({ navigation, route }: IRecoveringPageP styles={[styles.descText]} txt={t('recoveringWallet')} /> + 0} + styles={[styles.hint, { color: overshoot > 0 ? mainColors.VALID : mainColors.WARN, marginBottom: s(40) }]} + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + txt={overshoot > 0 ? `${t('doneSafety')} ${overshoot}/${RESTORE_OVERSHOOT}` : t('dontClose')} + /> + + + + @@ -56,16 +74,10 @@ export default function RecoveringScreen({ navigation, route }: IRecoveringPageP /> acc + p.amount, 0))})`} + txt={`${proofs.length} ${t('proofs', { ns: NS.wallet })} (${formatSatStr(proofs.reduce((acc, p) => acc + p.amount, 0))})`} /> - 0} - styles={[styles.hint, { color: overshoot > 0 ? mainColors.VALID : mainColors.WARN, marginTop: s(40) }]} - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - txt={overshoot > 0 ? `${t('doneSafety')} ${overshoot}/${RESTORE_OVERSHOOT}` : t('dontClose')} - /> + ) } @@ -78,18 +90,13 @@ const styles = ScaledSheet.create({ paddingHorizontal: '20@s', }, descText: { - marginTop: '20@s', - marginBottom: '30@s', + marginVertical: '20@s', textAlign: 'center', fontSize: '20@s', }, - warn: { - marginTop: '10@s', - marginBottom: '40@s', - }, hint: { - fontSize: '12@s', - marginTop: '10@s', + fontSize: '14@s', + marginBottom: '10@s', }, progress: { width: '100%', From 4b6c1ee6141845fc4aa7897adff97f4a53bd3709 Mon Sep 17 00:00:00 2001 From: First-Terraner Date: Fri, 29 Mar 2024 18:54:44 +0100 Subject: [PATCH 04/10] disable auto-capitalize in mint url input and invoice/lnurl input --- src/screens/Dashboard.tsx | 26 ++++++++++++++++--------- src/screens/Mints/index.tsx | 1 + src/screens/Payment/Send/Inputfield.tsx | 10 ++-------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/screens/Dashboard.tsx b/src/screens/Dashboard.tsx index 9c4bf19f..bcb3aa0a 100644 --- a/src/screens/Dashboard.tsx +++ b/src/screens/Dashboard.tsx @@ -307,15 +307,15 @@ export default function Dashboard({ navigation, route }: TDashboardPageProps) { txt={t('send', { ns: NS.wallet })} color={hi[highlight]} onPress={() => { - setModal(prev => ({ ...prev, sendOpts: true })) - // navigation.navigate('Recovering', { - // from: 500, - // to: 550, - // mintUrl: 'https://testnut.cashu.space', - // keysetId: 'asfdafh8u2h3', - // mnemonic: '', - // comingFromOnboarding: false, - // }) + // setModal(prev => ({ ...prev, sendOpts: true })) + navigation.navigate('Recovering', { + from: 500, + to: 550, + mintUrl: 'https://testnut.cashu.space', + keysetId: 'asfdafh8u2h3', + mnemonic: '', + comingFromOnboarding: false, + }) }} /> : @@ -325,6 +325,14 @@ export default function Dashboard({ navigation, route }: TDashboardPageProps) { color={hi[highlight]} onPress={() => { navigation.navigate('mints') + // navigation.navigate('Recovering', { + // from: 500, + // to: 550, + // mintUrl: 'https://testnut.cashu.space', + // keysetId: 'asfdafh8u2h3', + // mnemonic: '', + // comingFromOnboarding: false, + // }) }} /> } diff --git a/src/screens/Mints/index.tsx b/src/screens/Mints/index.tsx index 04a5f9f2..257e23c4 100644 --- a/src/screens/Mints/index.tsx +++ b/src/screens/Mints/index.tsx @@ -229,6 +229,7 @@ export default function Mints({ navigation }: TMintsPageProps) { value={input} onChangeText={setInput} onSubmitEditing={() => void handleMintInput()} + autoCapitalize='none' style={[{ paddingRight: s(55) }]} /> {/* scan icon */} diff --git a/src/screens/Payment/Send/Inputfield.tsx b/src/screens/Payment/Send/Inputfield.tsx index 298adb0b..55013b60 100644 --- a/src/screens/Payment/Send/Inputfield.tsx +++ b/src/screens/Payment/Send/Inputfield.tsx @@ -172,17 +172,11 @@ export default function InputfieldScreen({ navigation, route }: TMeltInputfieldP keyboardType='email-address' placeholder={t('invoiceOrLnurl')} value={input} - onChangeText={text => { - setInput(text) - /* Handle when the continue button is pressed - if (isLnInvoice(text)) { - void handleInvoicePaste(text) - } - */ - }} + onChangeText={text => setInput(text)} onSubmitEditing={() => void handleBtnPress()} autoFocus ms={200} + autoCapitalize='none' style={{ paddingRight: s(90) }} /> {/* Paste / Clear Input */} From d1dc48df46b813538c5218585bbefd0c6918e049 Mon Sep 17 00:00:00 2001 From: First-Terraner Date: Fri, 29 Mar 2024 19:03:49 +0100 Subject: [PATCH 05/10] update padding and disable auto-capitalize in mnemonic input --- src/screens/Restore/Recover.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/screens/Restore/Recover.tsx b/src/screens/Restore/Recover.tsx index 98f2af39..c828d284 100644 --- a/src/screens/Restore/Recover.tsx +++ b/src/screens/Restore/Recover.tsx @@ -57,7 +57,8 @@ export default function RecoverScreen({ navigation, route }: IRecoverPageProps) onSubmitEditing={() => void handleBtnPress()} autoFocus ms={200} - style={[styles.multilineInput]} + style={styles.multilineInput} + autoCapitalize='none' /> Date: Sat, 30 Mar 2024 12:35:39 +0100 Subject: [PATCH 06/10] add restoreSuccess screen component --- src/screens/Restore/Success.tsx | 130 ++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/screens/Restore/Success.tsx diff --git a/src/screens/Restore/Success.tsx b/src/screens/Restore/Success.tsx new file mode 100644 index 00000000..692f5e0e --- /dev/null +++ b/src/screens/Restore/Success.tsx @@ -0,0 +1,130 @@ +import Button from '@comps/Button' +import Separator from '@comps/Separator' +import Txt from '@comps/Txt' +import type { IRestoreSuccessPageProps } from '@model/nav' +import { isIOS } from '@src/consts' +import { useThemeContext } from '@src/context/Theme' +import { formatMintUrl, formatSatStr } from '@src/util' +import { globals } from '@styles' +import { View } from 'react-native' +import { useSafeAreaInsets } from 'react-native-safe-area-context' +import { s, ScaledSheet } from 'react-native-size-matters' + +export default function RestoreSuccess({ navigation, route }: IRestoreSuccessPageProps) { + + const insets = useSafeAreaInsets() + const { mint, keysetID, amount, cycle, comingFromOnboarding } = route.params + const { color } = useThemeContext() + + return ( + + + + + + + + + + + + + + + + + + + + + + +