Skip to content

Commit 432fbf5

Browse files
authored
feat: improve hardware wallet connection ui (#27649)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** No manual testing steps ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk UI/i18n updates; primary risk is unintended UX regressions from replacing the loading button with an `ActivityIndicator` and removing the `tip_dnd_off` translation key. > > **Overview** > Updates the hardware wallet “connecting” bottom sheet to show connection tips above a themed `ActivityIndicator` spinner, removing the previous full-width loading `Button` footer. > > Refines the Ledger tip list by dropping the “Do Not Disturb off” tip, updates the connecting title/header copy in `en.json`, and extends tests to cover `getConnectionTipsForWalletType` behavior and the new spinner/tip rendering. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit a879a03. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 1fe77d2 commit 432fbf5

5 files changed

Lines changed: 77 additions & 54 deletions

File tree

app/core/HardwareWallet/components/HardwareWalletBottomSheet/contents/ConnectingContent.test.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,18 @@ describe('ConnectingContent', () => {
5757
expect(getByTestId(CONNECTING_CONTENT_TEST_ID)).toBeOnTheScreen();
5858
});
5959

60-
it('renders activity indicator', () => {
60+
it('renders spinner', () => {
6161
const { getByTestId } = renderComponent();
6262

6363
expect(getByTestId(CONNECTING_CONTENT_SPINNER_TEST_ID)).toBeOnTheScreen();
6464
});
6565

66-
it('renders tips', () => {
66+
it('renders connection tips', () => {
6767
const { getByText } = renderComponent();
6868

6969
expect(
7070
getByText('hardware_wallet.connecting.tips_header'),
7171
).toBeOnTheScreen();
72-
// All tips are rendered with { device: deviceName } interpolation params
7372
expect(
7473
getByText(/hardware_wallet\.connecting\.tip_unlock/),
7574
).toBeOnTheScreen();
@@ -79,8 +78,5 @@ describe('ConnectingContent', () => {
7978
expect(
8079
getByText(/hardware_wallet\.connecting\.tip_enable_bluetooth/),
8180
).toBeOnTheScreen();
82-
expect(
83-
getByText(/hardware_wallet\.connecting\.tip_dnd_off/),
84-
).toBeOnTheScreen();
8581
});
8682
});

app/core/HardwareWallet/components/HardwareWalletBottomSheet/contents/ConnectingContent.tsx

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import React from 'react';
2-
import { View, StyleSheet } from 'react-native';
2+
import { ActivityIndicator, StyleSheet, View } from 'react-native';
33

44
import Text, {
55
TextVariant,
66
TextColor,
77
} from '../../../../../component-library/components/Texts/Text';
8-
import Button, {
9-
ButtonVariants,
10-
ButtonSize,
11-
ButtonWidthTypes,
12-
} from '../../../../../component-library/components/Buttons/Button';
138

149
import { strings } from '../../../../../../locales/i18n';
1510
import { HardwareWalletType } from '@metamask/hw-wallet-sdk';
@@ -18,11 +13,15 @@ import {
1813
getConnectionTipsForWalletType,
1914
} from '../../../helpers';
2015
import { ContentLayout } from './ContentLayout';
16+
import { useTheme } from '../../../../../util/theme';
2117

2218
export const CONNECTING_CONTENT_TEST_ID = 'connecting-content';
2319
export const CONNECTING_CONTENT_SPINNER_TEST_ID = 'connecting-content-spinner';
2420

2521
const styles = StyleSheet.create({
22+
tipsHeader: {
23+
marginBottom: 8,
24+
},
2625
tipItem: {
2726
flexDirection: 'row',
2827
marginBottom: 8,
@@ -34,6 +33,10 @@ const styles = StyleSheet.create({
3433
tipText: {
3534
flex: 1,
3635
},
36+
spinnerContainer: {
37+
alignItems: 'center',
38+
paddingVertical: 16,
39+
},
3740
});
3841

3942
export interface ConnectingContentProps {
@@ -44,6 +47,7 @@ export interface ConnectingContentProps {
4447
export const ConnectingContent: React.FC<ConnectingContentProps> = ({
4548
deviceType,
4649
}) => {
50+
const { colors } = useTheme();
4751
const deviceName = getHardwareWalletTypeName(deviceType);
4852
const connectionTips = getConnectionTipsForWalletType(deviceType);
4953

@@ -54,46 +58,46 @@ export const ConnectingContent: React.FC<ConnectingContentProps> = ({
5458
device: deviceName,
5559
})}
5660
body={
57-
connectionTips.length > 0 ? (
58-
<View>
59-
<Text variant={TextVariant.BodyMD} color={TextColor.Default}>
60-
{strings('hardware_wallet.connecting.tips_header')}
61-
</Text>
61+
<View>
62+
{connectionTips.length > 0 && (
63+
<View>
64+
<Text
65+
variant={TextVariant.BodyMD}
66+
color={TextColor.Default}
67+
style={styles.tipsHeader}
68+
>
69+
{strings('hardware_wallet.connecting.tips_header')}
70+
</Text>
6271

63-
{connectionTips.map((tipKey) => (
64-
<View key={tipKey} style={styles.tipItem}>
65-
<Text
66-
variant={TextVariant.BodyMD}
67-
color={TextColor.Default}
68-
style={styles.tipBullet}
69-
>
70-
71-
</Text>
72-
<Text
73-
variant={TextVariant.BodyMD}
74-
color={TextColor.Default}
75-
style={styles.tipText}
76-
>
77-
{strings(tipKey, { device: deviceName })}
78-
</Text>
79-
</View>
80-
))}
72+
{connectionTips.map((tipKey) => (
73+
<View key={tipKey} style={styles.tipItem}>
74+
<Text
75+
variant={TextVariant.BodyMD}
76+
color={TextColor.Default}
77+
style={styles.tipBullet}
78+
>
79+
80+
</Text>
81+
<Text
82+
variant={TextVariant.BodyMD}
83+
color={TextColor.Default}
84+
style={styles.tipText}
85+
>
86+
{strings(tipKey, { device: deviceName })}
87+
</Text>
88+
</View>
89+
))}
90+
</View>
91+
)}
92+
93+
<View style={styles.spinnerContainer}>
94+
<ActivityIndicator
95+
testID={CONNECTING_CONTENT_SPINNER_TEST_ID}
96+
size="large"
97+
color={colors.primary.default}
98+
/>
8199
</View>
82-
) : undefined
83-
}
84-
footer={
85-
<Button
86-
variant={ButtonVariants.Primary}
87-
size={ButtonSize.Lg}
88-
width={ButtonWidthTypes.Full}
89-
label=""
90-
onPress={
91-
// eslint-disable-next-line no-empty-function
92-
() => {}
93-
}
94-
loading
95-
testID={CONNECTING_CONTENT_SPINNER_TEST_ID}
96-
/>
100+
</View>
97101
}
98102
/>
99103
);

app/core/HardwareWallet/helpers.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
getHardwareWalletTypeName,
33
getHardwareWalletTypeForAddress,
4+
getConnectionTipsForWalletType,
45
} from './helpers';
56
import { HardwareWalletType } from '@metamask/hw-wallet-sdk';
67

@@ -110,4 +111,28 @@ describe('HardwareWallet helpers', () => {
110111
expect(result).toBe(HardwareWalletType.Ledger);
111112
});
112113
});
114+
115+
describe('getConnectionTipsForWalletType', () => {
116+
it('returns Ledger-specific tips for Ledger wallet type', () => {
117+
const tips = getConnectionTipsForWalletType(HardwareWalletType.Ledger);
118+
119+
expect(tips).toEqual([
120+
'hardware_wallet.connecting.tip_unlock',
121+
'hardware_wallet.connecting.tip_open_app',
122+
'hardware_wallet.connecting.tip_enable_bluetooth',
123+
]);
124+
});
125+
126+
it('returns empty array for QR wallet type', () => {
127+
const tips = getConnectionTipsForWalletType(HardwareWalletType.Qr);
128+
129+
expect(tips).toEqual([]);
130+
});
131+
132+
it('returns empty array for null wallet type', () => {
133+
const tips = getConnectionTipsForWalletType(null);
134+
135+
expect(tips).toEqual([]);
136+
});
137+
});
113138
});

app/core/HardwareWallet/helpers.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ export function getConnectionTipsForWalletType(
4949
'hardware_wallet.connecting.tip_unlock',
5050
'hardware_wallet.connecting.tip_open_app',
5151
'hardware_wallet.connecting.tip_enable_bluetooth',
52-
'hardware_wallet.connecting.tip_dnd_off',
5352
];
5453
default:
5554
return [];

locales/languages/en.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8032,13 +8032,12 @@
80328032
"continue": "Continue"
80338033
},
80348034
"connecting": {
8035-
"title": "Connect your {{device}}",
8035+
"title": "Connecting your {{device}}...",
80368036
"searching": "Looking for {{device}}...",
8037-
"tips_header": "To continue, make sure:",
8037+
"tips_header": "Make sure:",
80388038
"tip_unlock": "Your {{device}} is unlocked",
80398039
"tip_open_app": "The Ethereum app is open",
80408040
"tip_enable_bluetooth": "Bluetooth is turned on",
8041-
"tip_dnd_off": "Do Not Disturb is turned off",
80428041
"tip_bluetooth_permission": "Location and Bluetooth permission is granted",
80438042
"tip_bluetooth_permission_v12": "Nearby devices permission is granted",
80448043
"tip_stay_close": "Your device stays close to your phone"

0 commit comments

Comments
 (0)