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

Refactor/native/split device and app onboarding modules #17605

Merged
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
1 change: 1 addition & 0 deletions suite-native/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"@suite-native/module-authorize-device": "workspace:*",
"@suite-native/module-connect-popup": "workspace:*",
"@suite-native/module-dev-utils": "workspace:*",
"@suite-native/module-device-onboarding": "workspace:*",
"@suite-native/module-device-settings": "workspace:*",
"@suite-native/module-home": "workspace:*",
"@suite-native/module-onboarding": "workspace:*",
Expand Down
5 changes: 5 additions & 0 deletions suite-native/app/src/navigation/RootStackNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { DeviceCompromisedModalScreen } from '@suite-native/module-authenticity-
import { AuthorizeDeviceStackNavigator } from '@suite-native/module-authorize-device';
import { ConnectPopupScreen } from '@suite-native/module-connect-popup';
import { DevUtilsStackNavigator } from '@suite-native/module-dev-utils';
import { DeviceOnboardingStackNavigator } from '@suite-native/module-device-onboarding';
import { DeviceSettingsStackNavigator } from '@suite-native/module-device-settings';
import { OnboardingStackNavigator } from '@suite-native/module-onboarding';
import { SendStackNavigator } from '@suite-native/module-send';
Expand Down Expand Up @@ -90,6 +91,10 @@ export const RootStackNavigator = () => {
/>
{/* Navigation flows that start by push from bottom animation on the first screen of its stack. */}
<RootStack.Group screenOptions={{ animation: 'slide_from_bottom' }}>
<RootStack.Screen
name={RootStackRoutes.DeviceOnboardingStack}
component={DeviceOnboardingStackNavigator}
/>
<RootStack.Screen
name={RootStackRoutes.AccountsImport}
component={AccountsImportStackNavigator}
Expand Down
1 change: 1 addition & 0 deletions suite-native/app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
{ "path": "../module-authorize-device" },
{ "path": "../module-connect-popup" },
{ "path": "../module-dev-utils" },
{ "path": "../module-device-onboarding" },
{ "path": "../module-device-settings" },
{ "path": "../module-home" },
{ "path": "../module-onboarding" },
Expand Down
24 changes: 15 additions & 9 deletions suite-native/device/src/hooks/useHandleDeviceConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {
AppTabsRoutes,
AuthorizeDeviceStackParamList,
AuthorizeDeviceStackRoutes,
DeviceOnboardingStackRoutes,
HomeStackRoutes,
OnboardingStackRoutes,
RootStackParamList,
RootStackRoutes,
StackToStackCompositeNavigationProps,
Expand Down Expand Up @@ -73,7 +73,7 @@ export const useHandleDeviceConnection = () => {
// We should not redirect him away so he can read the screen content and decide what to do.
// If the device is connected again, he still should stay on that screen.
const isSuspiciousDeviceScreenFocused = useNavigationRouteMatch(
OnboardingStackRoutes.SuspiciousDevice,
DeviceOnboardingStackRoutes.SuspiciousDevice,
);
const isConnectAndUnlockDeviceScreenFocused = useNavigationRouteMatch(
AuthorizeDeviceStackRoutes.ConnectAndUnlockDevice,
Expand All @@ -83,6 +83,7 @@ export const useHandleDeviceConnection = () => {
const isDeviceSettingsStackFocused = lastRoute === RootStackRoutes.DeviceSettingsStack;
const isSendStackFocused = lastRoute === RootStackRoutes.SendStack;
const isOnboardingStackFocused = lastRoute === RootStackRoutes.OnboardingStack;
const isDeviceOnboardingStackFocused = lastRoute === RootStackRoutes.DeviceOnboardingStack;
const shouldBlockSendReviewRedirect = isDeviceRemembered && isSendStackFocused;
const isDeviceCompromisedModalFocused =
lastRoute === RootStackRoutes.DeviceCompromisedModalScreen;
Expand All @@ -95,25 +96,29 @@ export const useHandleDeviceConnection = () => {
if (
isDeviceSetupSupported &&
isDeviceConnected &&
isOnboardingFinished &&
!isDeviceInitialized &&
!isPortfolioTrackerDevice &&
!isBiometricsOverlayVisible &&
!isOnboardingStackFocused &&
!isOnboardingDeviceDisconnectedAlertDisplayed
!isDeviceOnboardingStackFocused &&
!isOnboardingDeviceDisconnectedAlertDisplayed &&
!isFirmwareInstallationRunning
) {
navigation.navigate(RootStackRoutes.OnboardingStack, {
screen: OnboardingStackRoutes.UninitializedDeviceLanding,
navigation.navigate(RootStackRoutes.DeviceOnboardingStack, {
screen: DeviceOnboardingStackRoutes.UninitializedDeviceLanding,
});
}
}, [
dispatch,
isDeviceConnected,
isOnboardingStackFocused,
isOnboardingFinished,
isBiometricsOverlayVisible,
navigation,
isDeviceInitialized,
isPortfolioTrackerDevice,
isDeviceSetupSupported,
isDeviceOnboardingStackFocused,
isFirmwareInstallationRunning,
isOnboardingDeviceDisconnectedAlertDisplayed,
]);

Expand Down Expand Up @@ -168,7 +173,7 @@ export const useHandleDeviceConnection = () => {
// set connecting screen to be displayed again on the next device connection.
useEffect(() => {
if (
(isFirmwareInstallationRunning && !isOnboardingStackFocused) ||
isFirmwareInstallationRunning ||
!isOnboardingFinished ||
isConnectAndUnlockDeviceScreenFocused
)
Expand All @@ -186,7 +191,7 @@ export const useHandleDeviceConnection = () => {
return;
}

if (isOnboardingStackFocused) {
if (isDeviceOnboardingStackFocused) {
handleOnboardingDeviceDisconnection();

return;
Expand All @@ -210,6 +215,7 @@ export const useHandleDeviceConnection = () => {
isOnboardingStackFocused,
handleOnboardingDeviceDisconnection,
isConnectAndUnlockDeviceScreenFocused,
isDeviceOnboardingStackFocused,
]);

// When trezor gets locked, it is necessary to display a PIN matrix for T1 so that it can be unlocked
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,22 @@ export const useHandleOnboardingDeviceDisconnection = () => {
// We need to wait for the navigation to be completed before showing the alert.
setTimeout(() => {
showAlert({
title: translate('moduleOnboarding.deviceDisconnectedAlert.title'),
title: translate('moduleDeviceOnboarding.deviceDisconnectedAlert.title'),
description: translate(
'moduleOnboarding.deviceDisconnectedAlert.description',
'moduleDeviceOnboarding.deviceDisconnectedAlert.description',
),
primaryButtonTitle: translate(
'moduleOnboarding.deviceDisconnectedAlert.reconnectButton',
'moduleDeviceOnboarding.deviceDisconnectedAlert.reconnectButton',
),
pictogramVariant: 'critical',
primaryButtonVariant: 'redBold',
secondaryButtonTitle: translate('generic.buttons.cancel'),
secondaryButtonVariant: 'redElevation0',
onPressPrimaryButton: hideDeviceDisconnectedAlert,
onPressSecondaryButton: hideDeviceDisconnectedAlert,
onPressSecondaryButton: () => {
hideDeviceDisconnectedAlert();
navigation.goBack();
},
});
}, 300);
}
Expand Down
1 change: 1 addition & 0 deletions suite-native/device/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './hooks/useDetectDeviceError';
export * from './hooks/useReportDeviceConnectToAnalytics';
export * from './hooks/useReportDeviceCompromised';
export * from './hooks/useRetryFwAuthenticityChecks';
export * from './hooks/useHandleOnboardingDeviceDisconnection';
export * from './components/ConnectDeviceAnimation';
export * from './components/ConfirmOnTrezorImage';
export * from './components/ConnectorImage';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type FirmwareInstallationScreenContentProps = {
onFirmwareInstallationSuccess: () => void;
onFirmwareInstallationFailure?: () => void;
isCancellationAllowed?: boolean;
isRetryAllowed?: boolean;
};

// This component is shared between `module-onboarding` and `module-device-settings`.
Expand All @@ -53,6 +54,7 @@ export const FirmwareInstallationScreenContent = ({
onFirmwareInstallationSuccess,
onFirmwareInstallationFailure,
isCancellationAllowed = true,
isRetryAllowed = true,
}: FirmwareInstallationScreenContentProps) => {
const dispatch = useDispatch();
const { applyStyle } = useNativeStyles();
Expand Down Expand Up @@ -228,9 +230,11 @@ export const FirmwareInstallationScreenContent = ({
bottom: bottomButtonOffset,
})}
>
<Button onPress={handleRetry} colorScheme="redBold">
<Translation id="firmware.firmwareUpdateProgress.retryButton" />
</Button>
{isRetryAllowed && (
<Button onPress={handleRetry} colorScheme="redBold">
<Translation id="firmware.firmwareUpdateProgress.retryButton" />
</Button>
)}
<Button onPress={handleContactSupport} colorScheme="tertiaryElevation0">
<Translation id="firmware.firmwareUpdateProgress.contactSupportButton" />
</Button>
Expand Down
2 changes: 1 addition & 1 deletion suite-native/firmware/src/hooks/useFirmware.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { useFirmwareAnalytics } from './useFirmwareAnalytics';
// If progress doesn't change for 1 minute
const MAYBE_STUCKED_TIMEOUT = 1 * 60 * 1000; // 1 minute

export const useFirmware = (params: UseFirmwareInstallationParams) => {
export const useFirmware = (params?: UseFirmwareInstallationParams) => {
const dispatch = useDispatch();
const {
firmwareUpdate: firmwareUpdateCommon,
Expand Down
1 change: 1 addition & 0 deletions suite-native/firmware/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './components/FirmwareInstallationScreenContent';
export * from './components/ConfirmFirmwareUpdateScreenContent';
export * from './components/ConfirmFirmwareUpdateScreenFooter';
export * from './hooks/useIsFirmwareUpdateFeatureEnabled';
export * from './hooks/useFirmware';
3 changes: 2 additions & 1 deletion suite-native/intl/src/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,8 @@ export const en = {
notNow: 'Not now',
},
},

},
moduleDeviceOnboarding: {
uninitializedDeviceLandingScreen: {
noFirmware: {
title: 'Now it’s just you\nand your crypto',
Expand Down
33 changes: 33 additions & 0 deletions suite-native/module-device-onboarding/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@suite-native/module-device-onboarding",
"version": "1.0.0",
"private": true,
"license": "See LICENSE.md in repo root",
"sideEffects": false,
"main": "src/index",
"scripts": {
"depcheck": "yarn g:depcheck",
"lint:js": "yarn g:eslint '**/*.{ts,tsx,js}'",
"type-check": "yarn g:tsc --build"
},
"dependencies": {
"@react-navigation/core": "^6.4.10",
"@react-navigation/native": "6.1.18",
"@react-navigation/native-stack": "6.11.0",
"@reduxjs/toolkit": "2.6.0",
"@suite-native/atoms": "workspace:*",
"@suite-native/device": "workspace:*",
"@suite-native/icons": "workspace:*",
"@suite-native/intl": "workspace:*",
"@suite-native/navigation": "workspace:*",
"@trezor/device-utils": "workspace:*",
"@trezor/env-utils": "workspace:*",
"@trezor/styles": "workspace:*",
"jotai": "1.9.1",
"react": "18.2.0",
"react-native": "0.76.1",
"react-native-reanimated": "^3.16.7",
"react-native-svg": "^15.9.0",
"react-redux": "9.2.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,45 @@ import { useSetAtom } from 'jotai';
import { deviceActions, selectSelectedDevice } from '@suite-common/wallet-core';
import { useAlert } from '@suite-native/alerts';
import { wasDeviceDisconnectedByUserActionAtom } from '@suite-native/device';
import { useFirmware } from '@suite-native/firmware';
import { useTranslate } from '@suite-native/intl';
import { Screen, ScreenHeader, ScreenProps } from '@suite-native/navigation';

const OnboardingExitButtonScreenHeader = () => {
const DeviceOnboardingExitButtonScreenHeader = () => {
const navigation = useNavigation();
const { showAlert } = useAlert();
const { translate } = useTranslate();
const dispatch = useDispatch();
const selectedDevice = useSelector(selectSelectedDevice);
const setWasDeviceDisconnectedByUserAction = useSetAtom(wasDeviceDisconnectedByUserActionAtom);
const { setIsFirmwareInstallationRunning } = useFirmware();

const handleExitButtonPress = useCallback(() => {
showAlert({
title: translate('moduleOnboarding.cancelOnboardingAlert.title'),
description: translate('moduleOnboarding.cancelOnboardingAlert.description'),
title: translate('moduleDeviceOnboarding.cancelOnboardingAlert.title'),
description: translate('moduleDeviceOnboarding.cancelOnboardingAlert.description'),
primaryButtonTitle: translate('generic.buttons.cancel'),
primaryButtonVariant: 'redBold',
secondaryButtonTitle: translate(
'moduleOnboarding.cancelOnboardingAlert.continueButton',
'moduleDeviceOnboarding.cancelOnboardingAlert.continueButton',
),
secondaryButtonVariant: 'redElevation0',
onPressPrimaryButton: () => {
if (selectedDevice) {
setIsFirmwareInstallationRunning(false);
setWasDeviceDisconnectedByUserAction(true);
dispatch(deviceActions.deviceDisconnect(selectedDevice));
}
},
});
}, [dispatch, selectedDevice, setWasDeviceDisconnectedByUserAction, translate, showAlert]);
}, [
dispatch,
selectedDevice,
setWasDeviceDisconnectedByUserAction,
setIsFirmwareInstallationRunning,
translate,
showAlert,
]);

useEffect(() => {
// Override default navigation GO_BACK action to align it with the exit button behavior.
Expand All @@ -52,8 +62,8 @@ const OnboardingExitButtonScreenHeader = () => {
return <ScreenHeader closeActionType="close" closeAction={handleExitButtonPress} />;
};

export const OnboardingScreenWithExitButton = ({ children, ...screenProps }: ScreenProps) => (
<Screen header={<OnboardingExitButtonScreenHeader />} {...screenProps}>
export const DeviceOnboardingScreenWithExitButton = ({ children, ...screenProps }: ScreenProps) => (
<Screen header={<DeviceOnboardingExitButtonScreenHeader />} {...screenProps}>
{children}
</Screen>
);
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import {
import { Icon, IconName } from '@suite-native/icons';
import { Translation } from '@suite-native/intl';
import {
DeviceOnboardingStackParamList,
DeviceOnboardingStackRoutes,
DeviceSuspicionCause,
OnboardingStackParamList,
OnboardingStackRoutes,
StackNavigationProps,
} from '@suite-native/navigation';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';
Expand All @@ -40,8 +40,8 @@ type SecurityCheckStepCardProps = {
};

type NavigationProps = StackNavigationProps<
OnboardingStackParamList,
OnboardingStackRoutes.SecurityCheck
DeviceOnboardingStackParamList,
DeviceOnboardingStackRoutes.SecurityCheck
>;

const ANIMATION_DURATION = 300;
Expand Down Expand Up @@ -71,7 +71,7 @@ export const SecurityCheckStepCard = ({
const headerColor: Color = isChecked ? 'textPrimaryDefault' : 'textSubdued';

const navigateToSuspiciousDeviceScreen = () => {
navigation.navigate(OnboardingStackRoutes.SuspiciousDevice, {
navigation.navigate(DeviceOnboardingStackRoutes.SuspiciousDevice, {
suspicionCause,
});
};
Expand Down Expand Up @@ -128,7 +128,7 @@ export const SecurityCheckStepCard = ({
colorScheme="tertiaryElevation0"
onPress={navigateToSuspiciousDeviceScreen}
>
<Translation id="moduleOnboarding.securityCheckScreen.declineButton" />
<Translation id="moduleDeviceOnboarding.securityCheckScreen.declineButton" />
</Button>
</HStack>
</AnimatedVStack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const SecuritySealDescription = () => {
<>
<Text variant="highlight">
<Translation
id="moduleOnboarding.securityCheckScreen.step2.description"
id="moduleDeviceOnboarding.securityCheckScreen.step2.description"
values={{
link: linkChunk => (
<Link
Expand Down Expand Up @@ -61,14 +61,14 @@ export const SecuritySealDescription = () => {
<VStack spacing="sp16">
<Box>
<Text variant="highlight">
<Translation id="moduleOnboarding.securityCheckScreen.step2.modal.title" />
<Translation id="moduleDeviceOnboarding.securityCheckScreen.step2.modal.title" />
</Text>
<Text>
<Translation id="moduleOnboarding.securityCheckScreen.step2.modal.paragraph1" />
<Translation id="moduleDeviceOnboarding.securityCheckScreen.step2.modal.paragraph1" />
</Text>
</Box>
<Text>
<Translation id="moduleOnboarding.securityCheckScreen.step2.modal.paragraph2" />
<Translation id="moduleDeviceOnboarding.securityCheckScreen.step2.modal.paragraph2" />
</Text>
</VStack>
</VStack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const SecuritySealImages = () => {
textVariant="hint"
contentColor="textDefault"
title={
<Translation id="moduleOnboarding.securityCheckScreen.step2.modal.alertBox" />
<Translation id="moduleDeviceOnboarding.securityCheckScreen.step2.modal.alertBox" />
}
/>
</VStack>
Expand Down
1 change: 1 addition & 0 deletions suite-native/module-device-onboarding/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './navigation/DeviceOnboardingStackNavigator';
Loading
Loading