Skip to content

Commit

Permalink
refactor(1702-4): ipfs gateway settings and display nft media setting…
Browse files Browse the repository at this point in the history
…s components (#11381)

## **Description**

This PR is part of a series that breaks down the original [large PR
#11127](#11127) into
smaller, more manageable chunks.

The `IPFSGateway` functionality and `DisplayNFtMedia` functionality are
valuable beyond its original implementation. By converting it into a
reusable component, we can:
1. Improve code maintainability
2. Reduce duplication
3. Enhance consistency across the application and ease of use

### Changes
- Extracted `IPFSGateway` and `DisplayNFTMedia` logic from its original
location of `SecuritySettings` into separate component files
- Included new tests
- Updated the original screen to use the new components
- Removed related tests/constants within `SecuritySettings` and moved
them into the new component folder

### Impact
This refactored component will be used in:
- Its current original screen of `SecuritySettings`
- New screens coming from the enhanced onboarding settings
[#1702](MetaMask/mobile-planning#1702) that is
currently under progress

## **Related issues**

Feature:
[#1702](MetaMask/mobile-planning#1702)

## **Manual testing steps**

### Display NFT Media Settings

1. On wallet home screen click on the NFT tab and make sure your NFT
media (images/etc) are showing
2. Goto settings under Security and Privacy and goto Display NFT Media
and toggle off
3. Go back to the wallet home screen under the NFT tab and you should
see the NFT media not load.
4. Repeat steps 1-3 to see your NFT media render and not render

### IPFS Gateway Settings

1. Goto settings
2. Click on IPFS dropdown and choose your preferred IPFS
3. Toggle off your IPFS gateway and your dropdown should disappear

## **Screenshots/Recordings**

### Display NFT Media Settings

| Toggle Off  | Toggle On  |
|:---:|:---:|

|![display_nft_media_toggle_off](https://github.com/user-attachments/assets/4993cf46-815f-4c26-865d-2776e51c7a4e)|![display_nft_media_toggle_on](https://github.com/user-attachments/assets/bc55e832-0451-4257-ad11-356ee2b5102a)|

### IPFS Gateway Settings

| Selecting new IPFS gateways  | Toggle Off  |
|:---:|:---:|

|![ipfs_gateway](https://github.com/user-attachments/assets/e8351f43-ea2c-426d-b8ca-257321e83d27)|![toggle_off_ipfs_gateway](https://github.com/user-attachments/assets/6dff912a-745f-4870-9629-054c42fa0ff0)|

### **Before**

NA

### **After**

NA

## **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.
  • Loading branch information
vinnyhoward authored Oct 4, 2024
1 parent c531cf8 commit f721b8d
Show file tree
Hide file tree
Showing 16 changed files with 702 additions and 172 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DisplayNFTMediaSettings should render correctly 1`] = `
<View
style={
{
"marginTop": 16,
}
}
>
<View
style={
{
"alignItems": "center",
"flexDirection": "row",
}
}
>
<Text
accessibilityRole="text"
style={
{
"color": "#141618",
"flex": 1,
"fontFamily": "EuclidCircularB-Medium",
"fontSize": 16,
"fontWeight": "500",
"letterSpacing": 0,
"lineHeight": 24,
}
}
>
Display NFT Media
</Text>
<View
style={
{
"marginLeft": 16,
}
}
>
<RCTSwitch
accessibilityRole="switch"
onChange={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onTintColor="#0376c9"
style={
[
{
"height": 31,
"width": 51,
},
[
{
"alignSelf": "flex-start",
},
{
"backgroundColor": "#bbc0c566",
"borderRadius": 16,
},
],
]
}
testID="nft-display-media-mode-section"
thumbTintColor="#ffffff"
tintColor="#bbc0c566"
value={false}
/>
</View>
</View>
<Text
accessibilityRole="text"
style={
{
"color": "#6a737d",
"fontFamily": "EuclidCircularB-Regular",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
"marginTop": 8,
}
}
>
Displaying NFT media and data exposes your IP address to OpenSea or other third parties. NFT autodetection relies on this feature, and won't be available when turned off. If NFT media is fully located on IPFS, it can still be displayed even when this feature is turned off.
</Text>
</View>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const NFT_DISPLAY_MEDIA_MODE_SECTION = 'nft-display-media-mode-section';
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { StyleSheet } from 'react-native';

const styleSheet = () =>
StyleSheet.create({
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
},
title: {
flex: 1,
},
switchElement: {
marginLeft: 16,
},
switch: {
alignSelf: 'flex-start',
},
halfSetting: {
marginTop: 16,
},
desc: {
marginTop: 8,
},
});

export default styleSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import { fireEvent } from '@testing-library/react-native';
import Engine from '../../../../core/Engine';
import renderWithProvider from '../../../../util/test/renderWithProvider';
import { backgroundState } from '../../../../util/test/initial-root-state';
import DisplayNFTMediaSettings from '.';
import { NFT_DISPLAY_MEDIA_MODE_SECTION } from './index.constants';

let mockSetDisplayNftMedia: jest.Mock;
let mockSetUseNftDetection: jest.Mock;

beforeEach(() => {
mockSetDisplayNftMedia.mockClear();
mockSetUseNftDetection.mockClear();
});

const mockEngine = Engine;

jest.mock('../../../../core/Engine', () => {
mockSetDisplayNftMedia = jest.fn();
mockSetUseNftDetection = jest.fn();
return {
init: () => mockEngine.init({}),
context: {
PreferencesController: {
setDisplayNftMedia: mockSetDisplayNftMedia,
setUseNftDetection: mockSetUseNftDetection,
},
},
};
});

describe('DisplayNFTMediaSettings', () => {
beforeEach(() => {
jest.clearAllMocks();
});

const initialState = {
engine: {
backgroundState: {
...backgroundState,
PreferencesController: {
...backgroundState.PreferencesController,
displayNftMedia: false,
useNftDetection: false,
},
},
},
};

it('should render correctly', () => {
const tree = renderWithProvider(<DisplayNFTMediaSettings />, {
state: initialState,
});
expect(tree).toMatchSnapshot();
});

describe('Display NFT Media', () => {
it('should toggle display NFT media when switch is pressed', () => {
const { getByTestId } = renderWithProvider(<DisplayNFTMediaSettings />, {
state: initialState,
});
const toggleSwitch = getByTestId(NFT_DISPLAY_MEDIA_MODE_SECTION);

fireEvent(toggleSwitch, 'onValueChange', true);
expect(mockSetDisplayNftMedia).toHaveBeenCalledWith(true);
expect(mockSetUseNftDetection).not.toHaveBeenCalled();

fireEvent(toggleSwitch, 'onValueChange', false);
expect(mockSetDisplayNftMedia).toHaveBeenCalledWith(false);
expect(mockSetUseNftDetection).toHaveBeenCalledWith(false);
});
});
});
61 changes: 61 additions & 0 deletions app/components/Views/Settings/DisplayNFTMediaSettings/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import { View, Switch } from 'react-native';
import { useSelector } from 'react-redux';
import { useStyles } from '../../../../component-library/hooks';
import Engine from '../../../../core/Engine';
import { selectDisplayNftMedia } from '../../../../selectors/preferencesController';
import { useTheme } from '../../../../util/theme';
import { strings } from '../../../../../locales/i18n';
import Text, {
TextVariant,
TextColor,
} from '../../../../component-library/components/Texts/Text';
import styleSheet from './index.styles';
import { NFT_DISPLAY_MEDIA_MODE_SECTION } from './index.constants';

const DisplayNFTMediaSettings = () => {
const theme = useTheme();
const { colors } = theme;
const { styles } = useStyles(styleSheet, {});

const displayNftMedia = useSelector(selectDisplayNftMedia);

const toggleDisplayNftMedia = (value: boolean) => {
const { PreferencesController } = Engine.context;
PreferencesController?.setDisplayNftMedia(value);
if (!value) PreferencesController?.setUseNftDetection(value);
};

return (
<View style={styles.halfSetting}>
<View style={styles.titleContainer}>
<Text variant={TextVariant.BodyLGMedium} style={styles.title}>
{strings('app_settings.display_nft_media')}
</Text>
<View style={styles.switchElement}>
<Switch
testID={NFT_DISPLAY_MEDIA_MODE_SECTION}
value={displayNftMedia}
onValueChange={toggleDisplayNftMedia}
trackColor={{
true: colors.primary.default,
false: colors.border.muted,
}}
thumbColor={theme.brandColors.white}
style={styles.switch}
ios_backgroundColor={colors.border.muted}
/>
</View>
</View>
<Text
variant={TextVariant.BodyMD}
color={TextColor.Alternative}
style={styles.desc}
>
{strings('app_settings.display_nft_media_desc_new')}
</Text>
</View>
);
};

export default DisplayNFTMediaSettings;
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`IPFSGatewaySettings should render correctly 1`] = `
<View
style={
{
"marginTop": 32,
}
}
>
<View
style={
{
"alignItems": "center",
"flexDirection": "row",
}
}
>
<Text
accessibilityRole="text"
style={
{
"color": "#141618",
"flex": 1,
"fontFamily": "EuclidCircularB-Medium",
"fontSize": 16,
"fontWeight": "500",
"letterSpacing": 0,
"lineHeight": 24,
}
}
>
IPFS Gateway
</Text>
<View
style={
{
"marginLeft": 16,
}
}
>
<RCTSwitch
accessibilityRole="switch"
onChange={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onTintColor="#0376c9"
style={
[
{
"height": 31,
"width": 51,
},
[
{
"alignSelf": "flex-start",
},
{
"backgroundColor": "#bbc0c566",
"borderRadius": 16,
},
],
]
}
testID="IPFS_GATEWAY_SECTION"
thumbTintColor="#ffffff"
tintColor="#bbc0c566"
value={true}
/>
</View>
</View>
<Text
accessibilityRole="text"
style={
{
"color": "#6a737d",
"fontFamily": "EuclidCircularB-Regular",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
"marginTop": 8,
}
}
>
MetaMask uses third-party services to show images of your NFTs stored on IPFS, display information related to ENS addresses entered in your browser's address bar, and fetch icons for different tokens. Your IP address may be exposed to these services when you’re using them.
</Text>
<View
style={
{
"marginTop": 16,
}
}
>
<Text
accessibilityRole="text"
style={
{
"color": "#6a737d",
"fontFamily": "EuclidCircularB-Regular",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
"marginTop": 8,
}
}
>
Choose your preferred IPFS gateway.
</Text>
<View
style={
{
"borderColor": "#bbc0c5",
"borderRadius": 5,
"borderWidth": 2,
"marginTop": 16,
}
}
>
<View>
<ActivityIndicator
size="small"
/>
</View>
</View>
</View>
</View>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const IPFS_GATEWAY_SECTION = 'IPFS_GATEWAY_SECTION';
export const HASH_TO_TEST = 'Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a';
export const HASH_STRING = 'Hello from IPFS Gateway Checker';
export const IPFS_GATEWAY_SELECTED = 'ipfs-gateway-selected';
Loading

0 comments on commit f721b8d

Please sign in to comment.