Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ui): android hardware back press for bottom-sheets #2419

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 56 additions & 3 deletions src/hooks/bottomSheet.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { useEffect, useMemo, useRef } from 'react';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { BackHandler, NativeEventSubscription } from 'react-native';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import {
useSafeAreaFrame,
useSafeAreaInsets,
} from 'react-native-safe-area-context';

import { useAppDispatch, useAppSelector } from './redux';
import { closeSheet } from '../store/slices/ui';
import { viewControllerIsOpenSelector } from '../store/reselect/ui';
import { objectKeys } from '../utils/objectKeys';
import { TViewController } from '../store/types/ui';
import { closeAllSheets, closeSheet } from '../store/slices/ui';
import {
viewControllerIsOpenSelector,
viewControllersSelector,
} from '../store/reselect/ui';

export const useSnapPoints = (
size: 'small' | 'medium' | 'large' | 'calendar',
Expand Down Expand Up @@ -44,6 +49,10 @@ export const useSnapPoints = (
return snapPoints;
};

/**
* Hook to handle hardware back press (Android) when bottom sheet is open
* for simple one-sheet screens
*/
export const useBottomSheetBackPress = (
viewController: TViewController,
): void => {
Expand Down Expand Up @@ -75,3 +84,47 @@ export const useBottomSheetBackPress = (
};
}, [isBottomSheetOpen, viewController, dispatch]);
};

/**
* Hook to handle hardware back press (Android) when bottom sheet is open
* for screens that are part of a navigator nested in a bottom sheet
*/
export const useBottomSheetScreenBackPress = (): void => {
const dispatch = useAppDispatch();
const navigation = useNavigation();
const viewControllers = useAppSelector(viewControllersSelector);

const isBottomSheetOpen = useMemo(() => {
const viewControllerKeys = objectKeys(viewControllers);
return viewControllerKeys.some((view) => viewControllers[view].isOpen);
}, [viewControllers]);

const backHandlerSubscriptionRef = useRef<NativeEventSubscription | null>(
null,
);

useFocusEffect(
useCallback(() => {
if (!isBottomSheetOpen) {
return;
}

backHandlerSubscriptionRef.current = BackHandler.addEventListener(
'hardwareBackPress',
() => {
if (navigation.canGoBack()) {
navigation.goBack();
} else {
dispatch(closeAllSheets());
}
return true;
},
);

return (): void => {
backHandlerSubscriptionRef.current?.remove();
backHandlerSubscriptionRef.current = null;
};
}, [dispatch, isBottomSheetOpen, navigation]),
);
};
7 changes: 6 additions & 1 deletion src/navigation/bottom-sheet/LNURLWithdrawNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { NavigationContainer } from '../../styles/components';
import BottomSheetWrapper from '../../components/BottomSheetWrapper';
import Amount from '../../screens/Wallets/LNURLWithdraw/Amount';
import Confirm from '../../screens/Wallets/LNURLWithdraw/Confirm';
import { useSnapPoints } from '../../hooks/bottomSheet';
import {
useBottomSheetBackPress,
useSnapPoints,
} from '../../hooks/bottomSheet';
import { useAppSelector } from '../../hooks/redux';
import { viewControllerSelector } from '../../store/reselect/ui';
import { __E2E__ } from '../../constants/env';
Expand All @@ -37,6 +40,8 @@ const LNURLWithdrawNavigation = (): ReactElement => {
return viewControllerSelector(state, 'lnurlWithdraw');
});

useBottomSheetBackPress('lnurlWithdraw');

if (!wParams) {
return <></>;
}
Expand Down
7 changes: 6 additions & 1 deletion src/navigation/bottom-sheet/PubkyAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import SafeAreaInset from '../../components/SafeAreaInset';
import Button from '../../components/buttons/Button';
import BottomSheetNavigationHeader from '../../components/BottomSheetNavigationHeader';
import { useAppSelector } from '../../hooks/redux';
import { useSnapPoints } from '../../hooks/bottomSheet';
import {
useBottomSheetBackPress,
useSnapPoints,
} from '../../hooks/bottomSheet';
import { viewControllerSelector } from '../../store/reselect/ui.ts';
import { auth, parseAuthUrl } from '@synonymdev/react-native-pubky';
import { getPubkySecretKey } from '../../utils/pubky';
Expand Down Expand Up @@ -89,6 +92,8 @@ const PubkyAuth = (): ReactElement => {
const [authorizing, setAuthorizing] = React.useState(false);
const [authSuccess, setAuthSuccess] = React.useState(false);

useBottomSheetBackPress('pubkyAuth');

useEffect(() => {
const fetchParsed = async (): Promise<void> => {
const res = await parseAuthUrl(url);
Expand Down
3 changes: 0 additions & 3 deletions src/screens/Settings/Backup/ConfirmPassphrase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import SafeAreaInset from '../../../components/SafeAreaInset';
import GradientView from '../../../components/GradientView';
import Button from '../../../components/buttons/Button';
import { capitalize } from '../../../utils/helpers';
import { useBottomSheetBackPress } from '../../../hooks/bottomSheet';
import type { BackupScreenProps } from '../../../navigation/types';

const ConfirmPassphrase = ({
Expand All @@ -20,8 +19,6 @@ const ConfirmPassphrase = ({
const { bip39Passphrase: origPass } = route.params;
const [bip39Passphrase, setPassphrase] = useState<string>('');

useBottomSheetBackPress('backupNavigation');

return (
<GradientView style={styles.gradient}>
<BottomSheetNavigationHeader title={t('pass_confirm')} />
Expand Down
3 changes: 0 additions & 3 deletions src/screens/Settings/Backup/ShowPassphrase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import BottomSheetNavigationHeader from '../../../components/BottomSheetNavigati
import SafeAreaInset from '../../../components/SafeAreaInset';
import GradientView from '../../../components/GradientView';
import Button from '../../../components/buttons/Button';
import { useBottomSheetBackPress } from '../../../hooks/bottomSheet';
import type { BackupScreenProps } from '../../../navigation/types';

const ShowPassphrase = ({
Expand All @@ -19,8 +18,6 @@ const ShowPassphrase = ({
const { t } = useTranslation('security');
const { bip39Passphrase, seed } = route.params;

useBottomSheetBackPress('backupNavigation');

return (
<GradientView style={styles.gradient}>
<BottomSheetNavigationHeader title={t('pass_your')} />
Expand Down
3 changes: 3 additions & 0 deletions src/screens/Settings/PIN/AskForBiometrics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import GradientView from '../../../components/GradientView';
import Button from '../../../components/buttons/Button';
import { IsSensorAvailableResult } from '../../../components/Biometrics';
import { useAppDispatch } from '../../../hooks/redux';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import rnBiometrics from '../../../utils/biometrics';
import { showToast } from '../../../utils/notifications';
import { updateSettings } from '../../../store/slices/settings';
Expand All @@ -39,6 +40,8 @@ const AskForBiometrics = ({
const [biometryData, setBiometricData] = useState<IsSensorAvailableResult>();
const [shouldEnableBiometrics, setShouldEnableBiometrics] = useState(false);

useBottomSheetScreenBackPress();

useEffect(() => {
(async (): Promise<void> => {
const data = await rnBiometrics.isSensorAvailable();
Expand Down
5 changes: 1 addition & 4 deletions src/screens/Settings/PIN/ChoosePIN.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ import BottomSheetNavigationHeader from '../../../components/BottomSheetNavigati
import GradientView from '../../../components/GradientView';
import NumberPad from '../../../components/NumberPad';
import useColors from '../../../hooks/colors';
import { useAppDispatch } from '../../../hooks/redux';
import { vibrate } from '../../../utils/helpers';
import { useBottomSheetBackPress } from '../../../hooks/bottomSheet';
import { addPin } from '../../../utils/settings';
import { hideTodo } from '../../../store/slices/todos';
import { pinTodo } from '../../../store/shapes/todos';
import type { PinScreenProps } from '../../../navigation/types';
import { useAppDispatch } from '../../../hooks/redux';

const ChoosePIN = ({
navigation,
Expand Down Expand Up @@ -49,8 +48,6 @@ const ChoosePIN = ({
// reset pin on back
useFocusEffect(useCallback(() => setPin(''), []));

useBottomSheetBackPress('PINNavigation');

useEffect(() => {
const timer = setTimeout(async () => {
if (pin.length !== 4) {
Expand Down
3 changes: 3 additions & 0 deletions src/screens/Settings/PIN/Result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SafeAreaInset from '../../../components/SafeAreaInset';
import GradientView from '../../../components/GradientView';
import Button from '../../../components/buttons/Button';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import { closeSheet } from '../../../store/slices/ui';
import { updateSettings } from '../../../store/slices/settings';
import { pinForPaymentsSelector } from '../../../store/reselect/settings';
Expand All @@ -22,6 +23,8 @@ const Result = ({ route }: PinScreenProps<'Result'>): ReactElement => {
const dispatch = useAppDispatch();
const pinForPayments = useAppSelector(pinForPaymentsSelector);

useBottomSheetScreenBackPress();

const biometricsName = useMemo(
() =>
type === 'TouchID'
Expand Down
5 changes: 4 additions & 1 deletion src/screens/Wallets/LNURLPay/Amount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ import {
} from '../../../store/reselect/settings';
import { useAppSelector } from '../../../hooks/redux';
import { useBalance, useSwitchUnit } from '../../../hooks/wallet';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import { getNumberPadText } from '../../../utils/numberpad';
import { convertToSats } from '../../../utils/conversion';
import type { SendScreenProps } from '../../../navigation/types';
import { showToast } from '../../../utils/notifications';
import type { SendScreenProps } from '../../../navigation/types';

const LNURLAmount = ({
navigation,
Expand All @@ -52,6 +53,8 @@ const LNURLAmount = ({
const [text, setText] = useState('');
const [error, setError] = useState(false);

useBottomSheetScreenBackPress();

const amount = useMemo((): number => {
return convertToSats(text, conversionUnit);
}, [text, conversionUnit]);
Expand Down
9 changes: 6 additions & 3 deletions src/screens/Wallets/LNURLPay/Confirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { useTranslation } from 'react-i18next';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
import { FadeIn, FadeOut } from 'react-native-reanimated';

import { BodySSB, Caption13Up } from '../../../styles/text';
import { Checkmark, LightningHollow } from '../../../styles/icons';
import { AnimatedView, BottomSheetTextInput } from '../../../styles/components';
import AmountToggle from '../../../components/AmountToggle';
import Biometrics from '../../../components/Biometrics';
import BottomSheetNavigationHeader from '../../../components/BottomSheetNavigationHeader';
Expand All @@ -19,6 +22,7 @@ import SwipeToConfirm from '../../../components/SwipeToConfirm';
import useColors from '../../../hooks/colors';
import useKeyboard, { Keyboard } from '../../../hooks/keyboard';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import type { SendScreenProps } from '../../../navigation/types';
import {
pinForPaymentsSelector,
Expand All @@ -28,9 +32,6 @@ import {
import { addPendingPayment } from '../../../store/slices/lightning';
import { updateMetaTxComment } from '../../../store/slices/metadata';
import { EActivityType } from '../../../store/types/activity';
import { AnimatedView, BottomSheetTextInput } from '../../../styles/components';
import { Checkmark, LightningHollow } from '../../../styles/icons';
import { BodySSB, Caption13Up } from '../../../styles/text';
import { FeeText } from '../../../utils/fees';
import {
decodeLightningInvoice,
Expand Down Expand Up @@ -78,6 +79,8 @@ const LNURLConfirm = ({
const [showBiotmetrics, setShowBiometrics] = useState(false);
const [comment, setComment] = useState('');

useBottomSheetScreenBackPress();

const onError = useCallback(
(errorMessage: string) => {
navigation.navigate('Error', { errorMessage });
Expand Down
3 changes: 3 additions & 0 deletions src/screens/Wallets/Receive/ReceiveAmount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import UnitButton from '../UnitButton';
import { useSwitchUnit } from '../../../hooks/wallet';
import { useTransfer } from '../../../hooks/transfer';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import { updateInvoice } from '../../../store/slices/receive';
import { receiveSelector } from '../../../store/reselect/receive';
import { estimateOrderFee } from '../../../utils/blocktank';
Expand Down Expand Up @@ -48,6 +49,8 @@ const ReceiveAmount = ({

const { defaultLspBalance: lspBalance, maxClientBalance } = useTransfer(0);

useBottomSheetScreenBackPress();

useFocusEffect(
useCallback(() => {
refreshBlocktankInfo().then();
Expand Down
5 changes: 4 additions & 1 deletion src/screens/Wallets/Send/Amount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import {
} from '../../../store/reselect/settings';
import { useAppSelector } from '../../../hooks/redux';
import { useBalance, useSwitchUnit } from '../../../hooks/wallet';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import { sendTransactionSelector } from '../../../store/reselect/ui';
import {
setupFeeForOnChainTransaction,
setupOnChainTransaction,
Expand All @@ -55,7 +57,6 @@ import { showToast } from '../../../utils/notifications';
import { convertToSats } from '../../../utils/conversion';
import { TRANSACTION_DEFAULTS } from '../../../utils/wallet/constants';
import type { SendScreenProps } from '../../../navigation/types';
import { sendTransactionSelector } from '../../../store/reselect/ui';

const Amount = ({ navigation }: SendScreenProps<'Amount'>): ReactElement => {
const route = useRoute();
Expand All @@ -78,6 +79,8 @@ const Amount = ({ navigation }: SendScreenProps<'Amount'>): ReactElement => {
const { paymentMethod } = useAppSelector(sendTransactionSelector);
const usesLightning = paymentMethod === 'lightning';

useBottomSheetScreenBackPress();

const outputAmount = useMemo(() => {
const amount = getTransactionOutputValue({ outputs: transaction.outputs });
return amount;
Expand Down
3 changes: 3 additions & 0 deletions src/screens/Wallets/Send/Quickpay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import SyncSpinner from '../../../components/SyncSpinner';
import HourglassSpinner from '../../../components/HourglassSpinner';
import LightningSyncing from '../../../components/LightningSyncing';
import { useAppDispatch } from '../../../hooks/redux';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import { addPendingPayment } from '../../../store/slices/lightning';
import { EActivityType } from '../../../store/types/activity';
import type { SendScreenProps } from '../../../navigation/types';
Expand All @@ -30,6 +31,8 @@ const Quickpay = ({
const { invoice, amount } = route.params;
const dispatch = useAppDispatch();

useBottomSheetScreenBackPress();

useFocusEffect(
useCallback(() => {
const pay = async (): Promise<void> => {
Expand Down
8 changes: 4 additions & 4 deletions src/screens/Wallets/Send/Recipient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ClipboardTextIcon,
ScanIcon,
} from '../../../styles/icons';
import GradientView from '../../../components/GradientView';
import BottomSheetNavigationHeader from '../../../components/BottomSheetNavigationHeader';
import SafeAreaInset from '../../../components/SafeAreaInset';
import ContactImage from '../../../components/ContactImage';
Expand All @@ -20,11 +21,10 @@ import { showToast } from '../../../utils/notifications';
import useColors from '../../../hooks/colors';
import { useAppSelector } from '../../../hooks/redux';
import { useScreenSize } from '../../../hooks/screen';
import { useBottomSheetBackPress } from '../../../hooks/bottomSheet';
import type { SendScreenProps } from '../../../navigation/types';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import { lastPaidSelector } from '../../../store/reselect/slashtags';
import { selectedNetworkSelector } from '../../../store/reselect/wallet';
import GradientView from '../../../components/GradientView';
import type { SendScreenProps } from '../../../navigation/types';

const imageSrc = require('../../../assets/illustrations/coin-stack-logo.png');

Expand Down Expand Up @@ -64,7 +64,7 @@ const Recipient = ({
const selectedNetwork = useAppSelector(selectedNetworkSelector);
const lastPaidContacts = useAppSelector(lastPaidSelector);

useBottomSheetBackPress('sendNavigation');
useBottomSheetScreenBackPress();

const onOpenContacts = (): void => {
navigation.navigate('Contacts');
Expand Down
3 changes: 3 additions & 0 deletions src/screens/Wallets/Send/ReviewAndSend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
import useColors from '../../../hooks/colors';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
import { useLightningBalance } from '../../../hooks/lightning';
import { useBottomSheetScreenBackPress } from '../../../hooks/bottomSheet';
import { EFeeId } from '../../../store/types/fees';
import {
decodeLightningInvoice,
Expand Down Expand Up @@ -139,6 +140,8 @@ const ReviewAndSend = ({
const [rawTx, setRawTx] = useState<{ hex: string; id: string }>();
const [decodedInvoice, setDecodedInvoice] = useState<TInvoice>();

useBottomSheetScreenBackPress();

useEffect(() => {
const decodeAndSetLightningInvoice = async (): Promise<void> => {
if (!usesLightning || !transaction.lightningInvoice) {
Expand Down
Loading
Loading