Skip to content

Commit

Permalink
feat(suite-native): rework layout of the Device info screen
Browse files Browse the repository at this point in the history
  • Loading branch information
yanascz committed Oct 9, 2024
1 parent 7e33a06 commit 794445f
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 117 deletions.
1 change: 1 addition & 0 deletions packages/theme/src/borders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ export const nativeBorders = {
} as const;

export type NativeBorders = typeof nativeBorders;
export type NativeRadius = keyof typeof nativeBorders.radii;
13 changes: 5 additions & 8 deletions suite-native/atoms/src/AlertBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { ReactNode } from 'react';
import { ActivityIndicator } from 'react-native';

import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';
import { Color, nativeBorders } from '@trezor/theme';
import { Color, NativeRadius } from '@trezor/theme';
import { Icon, IconName } from '@suite-common/icons-deprecated';

import { Box } from './Box';
import { Text } from './Text';
import { nativeRadiusToNumber } from './utils';

export type AlertBoxVariant = 'info' | 'success' | 'warning' | 'loading' | 'error';

Expand Down Expand Up @@ -80,7 +81,7 @@ const variantToIconName = {
export type AlertBoxProps = {
variant: AlertBoxVariant;
title: ReactNode;
borderRadius?: number;
borderRadius?: NativeRadius | number;
};

const AlertSpinner = ({ color }: { color: Color }) => {
Expand All @@ -91,18 +92,14 @@ const AlertSpinner = ({ color }: { color: Color }) => {
return <ActivityIndicator size={16} color={colors[color]} />;
};

export const AlertBox = ({
title,
variant = 'info',
borderRadius = nativeBorders.radii.r16,
}: AlertBoxProps) => {
export const AlertBox = ({ title, variant = 'info', borderRadius = 'r16' }: AlertBoxProps) => {
const { applyStyle } = useNativeStyles();
const { contentColor, backgroundColor, borderColor } = variantToColorMap[variant];

return (
<Box
style={applyStyle(alertWrapperStyle, {
borderRadius,
borderRadius: nativeRadiusToNumber(borderRadius),
borderColor,
backgroundColor,
})}
Expand Down
1 change: 1 addition & 0 deletions suite-native/atoms/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ export * from './Skeleton/ListItemSkeleton';
export * from './BulletListItem';
export * from './SelectableItem';
export * from './constants';
export * from './utils';

export { useDebugView } from './DebugView';
7 changes: 7 additions & 0 deletions suite-native/atoms/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { nativeBorders, NativeRadius, NativeSpacing, nativeSpacings } from '@trezor/theme';

export const nativeSpacingToNumber = (value: NativeSpacing | number) =>
typeof value === 'number' ? value : nativeSpacings[value];

export const nativeRadiusToNumber = (value: NativeRadius | number) =>
typeof value === 'number' ? value : nativeBorders.radii[value];
2 changes: 2 additions & 0 deletions suite-native/device/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"@react-navigation/native": "6.1.18",
"@reduxjs/toolkit": "1.9.5",
"@sentry/react-native": "5.33.0",
"@suite-common/icons-deprecated": "workspace:*",
"@suite-common/redux-utils": "workspace:*",
"@suite-common/suite-utils": "workspace:*",
"@suite-common/wallet-core": "workspace:*",
"@suite-common/wallet-utils": "workspace:*",
"@suite-native/alerts": "workspace:*",
Expand Down
110 changes: 110 additions & 0 deletions suite-native/device/src/components/DeviceFirmwareCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { ReactNode } from 'react';
import { useSelector } from 'react-redux';

import { G } from '@mobily/ts-belt';

import { getFwUpdateVersion } from '@suite-common/suite-utils';
import { DeviceModelIcon } from '@suite-common/icons-deprecated';
import {
selectDevice,
selectDeviceModel,
selectDeviceReleaseInfo,
} from '@suite-common/wallet-core';
import { AlertBox, Box, Card, HStack, Text, VStack } from '@suite-native/atoms';
import { Translation } from '@suite-native/intl';
import { getFirmwareVersion, hasBitcoinOnlyFirmware } from '@trezor/device-utils';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';

const vStackStyle = prepareNativeStyle(() => ({
flexGrow: 1,
}));

type DeviceInfoProps = {
label: ReactNode;
value: ReactNode;
};

const FirmwareInfo = ({ label, value }: DeviceInfoProps) => {
const { applyStyle } = useNativeStyles();

return (
<VStack spacing="sp2" style={applyStyle(vStackStyle)}>
<Text variant="hint" color="textSubdued">
{label}
</Text>
<Text variant="callout">{value}</Text>
</VStack>
);
};

export const DeviceFirmwareCard = () => {
const { applyStyle } = useNativeStyles();

const device = useSelector(selectDevice);
const deviceModel = useSelector(selectDeviceModel);
const deviceReleaseInfo = useSelector(selectDeviceReleaseInfo);

if (!device || !deviceModel) {
return null;
}

const firmwareVersion = getFirmwareVersion(device);
const firmwareTypeTranslationId = hasBitcoinOnlyFirmware(device)
? 'deviceSettings.firmware.typeBitcoinOnly'
: 'deviceSettings.firmware.typeUniversal';

const firmwareUpdateProps = (() => {
if (G.isNotNullable(deviceReleaseInfo)) {
const isUpgradable = deviceReleaseInfo.isNewer ?? false;

if (isUpgradable) {
return {
title: (
<Translation
id="deviceSettings.firmware.newVersionAvailable"
values={{ version: getFwUpdateVersion(device) }}
/>
),
variant: 'info',
} as const;
}

return {
title: <Translation id="deviceSettings.firmware.upToDate" />,
variant: 'success',
} as const;
}

return undefined;
})();

return (
<Card noPadding>
<HStack margin="sp16" spacing="sp12">
<Box marginVertical="sp2">
<DeviceModelIcon deviceModel={deviceModel} size="mediumLarge" />
</Box>
<VStack spacing="sp12" style={applyStyle(vStackStyle)}>
<Text variant="highlight">
<Translation id="deviceSettings.firmware.title" />
</Text>
<HStack spacing="sp2">
<FirmwareInfo
label={<Translation id="deviceSettings.firmware.version" />}
value={firmwareVersion}
/>
<FirmwareInfo
label={<Translation id="deviceSettings.firmware.type" />}
value={<Translation id={firmwareTypeTranslationId} />}
/>
</HStack>
</VStack>
</HStack>
{firmwareUpdateProps && (
<Box margin="sp4">
<AlertBox {...firmwareUpdateProps} borderRadius="r12" />
</Box>
)}
</Card>
);
};
113 changes: 19 additions & 94 deletions suite-native/device/src/screens/DeviceInfoModalScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,28 @@
import { useSelector } from 'react-redux';
import { useEffect, useState } from 'react';

import { G } from '@mobily/ts-belt';
import { useNavigation } from '@react-navigation/native';

import { DeviceModelInternal } from '@trezor/connect';
import {
Image,
Box,
Card,
HStack,
VStack,
Button,
IconButton,
ScreenHeaderWrapper,
Text,
} from '@suite-native/atoms';
import { Image, VStack, Button, Text } from '@suite-native/atoms';
import {
AppTabsRoutes,
HomeStackRoutes,
RootStackParamList,
RootStackRoutes,
Screen,
ScreenSubHeader,
StackNavigationProps,
} from '@suite-native/navigation';
import {
selectDevice,
selectDeviceLabel,
selectDeviceModel,
selectDeviceReleaseInfo,
selectIsPortfolioTrackerDevice,
} from '@suite-common/wallet-core';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';
import { Translation, useTranslate } from '@suite-native/intl';
import { getFirmwareVersion } from '@trezor/device-utils';
import { useOpenLink } from '@suite-native/link';

import { DeviceFirmwareCard } from '../components/DeviceFirmwareCard';
import { HowToUpdateBottomSheet } from '../components/HowToUpdateBottomSheet';

const deviceImageMap: Record<DeviceModelInternal, string> = {
Expand All @@ -46,51 +33,21 @@ const deviceImageMap: Record<DeviceModelInternal, string> = {
[DeviceModelInternal.T3T1]: require('../assets/t3t1.png'),
};

const emptyBoxStyle = prepareNativeStyle(() => ({
width: 48,
}));

const contentStyle = prepareNativeStyle(() => ({
flexGrow: 1,
}));

type NavigationProp = StackNavigationProps<RootStackParamList, RootStackRoutes.DeviceInfo>;

export const DeviceInfoModalScreen = () => {
const navigation = useNavigation<NavigationProp>();
const { translate } = useTranslate();
const openLink = useOpenLink();

const deviceModel = useSelector(selectDeviceModel);
const deviceLabel = useSelector(selectDeviceLabel);
const device = useSelector(selectDevice);
const deviceModel = useSelector(selectDeviceModel);
const isPortfolioTrackerDevice = useSelector(selectIsPortfolioTrackerDevice);
const deviceReleaseInfo = useSelector(selectDeviceReleaseInfo);
const { applyStyle } = useNativeStyles();

const [isUpdateSheetOpen, setIsUpdateSheetOpen] = useState<boolean>(false);

const isUpgradable = deviceReleaseInfo?.isNewer ?? false;

const getCardAlertProps = () => {
if (G.isNotNullable(deviceReleaseInfo)) {
if (isUpgradable) {
return {
alertTitle: <Translation id="deviceInfo.outdatedFw" />,
alertVariant: 'warning',
} as const;
}

return {
alertTitle: <Translation id="deviceInfo.upToDateFw" />,
alertVariant: 'success',
} as const;
}

return { alertTitle: undefined, alertVariant: undefined } as const;
};
const cardAlertProps = getCardAlertProps();

useEffect(() => {
if (isPortfolioTrackerDevice) {
navigation.navigate(RootStackRoutes.AppTabs, {
Expand All @@ -102,61 +59,29 @@ export const DeviceInfoModalScreen = () => {
}
}, [isPortfolioTrackerDevice, navigation]);

if (!deviceModel) return null;

const currentFwVersion = getFirmwareVersion(device);

const handleGoBack = () => {
navigation.goBack();
};

const handleAccessoriesClick = () => {
openLink('https://trezor.io/accessories');
};
if (!device || !deviceModel) {
return null;
}

const handleUpdateClick = () => setIsUpdateSheetOpen(true);

return (
<Screen
screenHeader={
// TODO once https://github.com/trezor/trezor-suite/issues/9856 is done, this should be removed
<ScreenHeaderWrapper>
<IconButton
iconName="close"
colorScheme="tertiaryElevation0"
onPress={handleGoBack}
/>
<Text>Device info</Text>
<Box style={applyStyle(emptyBoxStyle)} />
</ScreenHeaderWrapper>
<ScreenSubHeader
customHorizontalPadding="sp16"
content={translate('deviceSettings.title')}
closeActionType="close"
/>
}
customHorizontalPadding="sp16"
>
<Box style={applyStyle(contentStyle)}>
<Card {...cardAlertProps}>
<HStack spacing="sp24">
<Image width={92} height={151} source={deviceImageMap[deviceModel]} />
<VStack spacing="sp4" justifyContent="center">
{deviceLabel && <Text variant="titleSmall">{deviceLabel}</Text>}
<Text variant="label" color="textSubdued">
{device?.name}
</Text>
<Text variant="hint">
{translate('deviceInfo.installedFw', {
version: currentFwVersion,
})}
</Text>
</VStack>
</HStack>
</Card>
</Box>
<VStack spacing="sp16">
<Button
colorScheme="tertiaryElevation0"
onPress={handleAccessoriesClick}
viewRight="arrowUpRight"
>
<Translation id="deviceInfo.goToAccessories" />
</Button>
<VStack marginVertical="sp32" spacing="sp24" alignItems="center">
<Image width={92} height={151} source={deviceImageMap[deviceModel]} />
<Text variant="titleMedium">{device.name}</Text>
</VStack>
<VStack spacing="sp24">
<DeviceFirmwareCard />
{isUpgradable && (
<Button colorScheme="primary" onPress={handleUpdateClick}>
<Translation id="deviceInfo.updateHowTo.title" />
Expand Down
6 changes: 6 additions & 0 deletions suite-native/device/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "libDev" },
"references": [
{
"path": "../../suite-common/icons-deprecated"
},
{
"path": "../../suite-common/redux-utils"
},
{
"path": "../../suite-common/suite-utils"
},
{
"path": "../../suite-common/wallet-core"
},
Expand Down
12 changes: 12 additions & 0 deletions suite-native/intl/src/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,18 @@ export const en = {
button: 'Learn more @ Trezor.io',
},
},
deviceSettings: {
title: 'Device info', // TODO: Change to "Device settings" once something may be changed
firmware: {
title: 'Firmware',
version: 'Version',
type: 'Type',
typeUniversal: 'Universal',
typeBitcoinOnly: 'Bitcoin-only',
upToDate: 'You’re all up to date',
newVersionAvailable: 'New version available ({version})',
},
},
qrCode: {
addressCopied: 'Address copied',
copyButton: 'Copy',
Expand Down
Loading

0 comments on commit 794445f

Please sign in to comment.