Skip to content

Commit

Permalink
Merge branch 'main' into salim/add-new-default-networks
Browse files Browse the repository at this point in the history
  • Loading branch information
salimtb committed Oct 24, 2024
2 parents 4afec48 + def6f50 commit e1ab767
Show file tree
Hide file tree
Showing 193 changed files with 7,244 additions and 2,713 deletions.
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ app/component-library/ @MetaMask/design-system-engineers
patches/ @MetaMask/mobile-platform
app/core/Engine.ts @MetaMask/mobile-platform
app/core/Engine.test.js @MetaMask/mobile-platform
app/core/Analytics/ @MetaMask/mobile-platform
app/util/metrics/ @MetaMask/mobile-platform
app/components/hooks/useMetrics/ @MetaMask/mobile-platform

# Supply Chain Team
bitrise.yml @MetaMask/supply-chain @MetaMask/mobile-platform
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,6 @@ app/util/termsOfUse/termsOfUseContent.ts
docs/assets/termsOfUse.html

/app/images/branding

# build metadata
android/app/src/main/assets/modules.json
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.12.2
20.14.0
2 changes: 1 addition & 1 deletion .storybook/storybook.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const getStories = () => {
"./app/components/Views/confirmations/components/UI/InfoRow/InfoRow.stories.tsx": require("../app/components/Views/confirmations/components/UI/InfoRow/InfoRow.stories.tsx"),
"./app/components/Views/confirmations/components/UI/ExpandableSection/ExpandableSection.stories.tsx": require("../app/components/Views/confirmations/components/UI/ExpandableSection/ExpandableSection.stories.tsx"),
"./app/components/Views/confirmations/components/UI/Tooltip/Tooltip.stories.tsx": require("../app/components/Views/confirmations/components/UI/Tooltip/Tooltip.stories.tsx"),
"./app/components/Views/confirmations/components/UI/CopyButton/CopyButton.stories.tsx": require("../app/components/Views/confirmations/components/UI/CopyButton/CopyButton.stories.tsx"),
"./app/component-library/components/Texts/SensitiveText/SensitiveText.stories.tsx": require("../app/component-library/components/Texts/SensitiveText/SensitiveText.stories.tsx"),
};
};

Expand Down
9 changes: 2 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,12 @@ cd metamask-mobile

Before running the app, keep in mind that MetaMask uses FCM (Firebase Cloud Message) to empower communications. Based on this, as an external contributor you would preferably need to provide your own FREE Firebase project config file with a matching client for package name `io.metamask`, and update your `google-services.json` file in the `android/app` directory as well your `.env` files (`.ios.env`, `.js.env`, `.android.env`), adding `GOOGLE_SERVICES_B64` variable depending on the environment you are running the app (ios/android).

The value you should provide to `GOOGLE_SERVICES_B64` is the base64 encoded version of your Firebase project config file, which can be generated as follows:
ATTENTION: In case you don't provide your own Firebase project config file, you can make use of a mock file at `android/app/google-services-example.json`, following the steps below from the root of the project:

```bash
base64 -i ./android/app/google-services-example.json
echo "export GOOGLE_SERVICES_B64=\"$(base64 -w0 -i ./android/app/google-services-example.json)\"" | tee -a .js.env .ios.env .android.env
```

Copy the result to your clipboard and paste it in the `GOOGLE_SERVICES_B64` variable in the `.env` file you are running the app.

> [!CAUTION]
> In case you don't provide your own Firebase project config file, you will face the error `No matching client found for package name 'io.metamask'`.
You can make usage of a mock file at `android/app/google-services-example.json`, following the same steps above from the root of the project.

In case of any doubt, please follow the instructions in the link below to get your Firebase project config file.
Expand Down
32 changes: 26 additions & 6 deletions android/app/google-services-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
},
"client": [
{
"api_key": [
{
"current_key": ""
}
],
"api_key": [{ "current_key": "" }],
"client_info": {
"mobilesdk_app_id": "1:123456789000:android:f1bf012572b04063",
"client_id": "android:io.metamask",
Expand All @@ -21,7 +17,31 @@
"certificate_hash": []
}
}
},
{
"api_key": [{ "current_key": "" }],
"client_info": {
"mobilesdk_app_id": "1:123456789000:android:f1bf012572b04063",
"client_id": "android:io.metamask.qa",
"client_type": 1,
"android_client_info": {
"package_name": "io.metamask.qa",
"certificate_hash": []
}
}
},
{
"api_key": [{ "current_key": "" }],
"client_info": {
"mobilesdk_app_id": "1:123456789000:android:f1bf012572b04063",
"client_id": "android:io.metamask.flask",
"client_type": 1,
"android_client_info": {
"package_name": "io.metamask.flask",
"certificate_hash": []
}
}
}
],
"configuration_version": "1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* eslint-disable react/display-name */
/* eslint-disable react-native/no-inline-styles */
// External dependencies.
import React from 'react';
import { View, Text } from 'react-native';

// Internal dependencies.
import PickerBase from './PickerBase';
import { IconSize } from '../../Icons/Icon';

const PickerBaseMeta = {
title: 'Component Library / Pickers',
component: PickerBase,
argTypes: {
children: {
control: { type: 'text' },
defaultValue: 'Select an option',
},
iconSize: {
options: Object.values(IconSize),
control: { type: 'select' },
defaultValue: IconSize.Md,
},
},
};

export default PickerBaseMeta;

export const Default = {
render: ({
children,
iconSize,
}: {
children: string;
iconSize: IconSize;
}) => (
<View style={{ alignItems: 'flex-start' }}>
<PickerBase onPress={() => null} iconSize={iconSize}>
<Text>{children}</Text>
</PickerBase>
</View>
),
};

export const WithCustomStyles = {
render: () => (
<View style={{ alignItems: 'flex-start' }}>
<PickerBase
onPress={() => null}
style={{ width: 200 }}
dropdownIconStyle={{ marginLeft: 20 }}
>
<Text>Custom Styled Picker</Text>
</PickerBase>
</View>
),
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ const styleSheet = (params: {
}) => {
const { vars, theme } = params;
const { colors } = theme;
const { style } = vars;
const { style, dropdownIconStyle } = vars;

return StyleSheet.create({
base: Object.assign(
{
Expand All @@ -35,9 +36,12 @@ const styleSheet = (params: {
} as ViewStyle,
style,
) as ViewStyle,
dropdownIcon: {
marginLeft: 16,
},
dropdownIcon: Object.assign(
{
marginLeft: 16,
} as ViewStyle,
dropdownIconStyle,
),
});
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,78 @@
// Third party dependencies.
import React from 'react';
import { View } from 'react-native';
import { render } from '@testing-library/react-native';
import { Text } from 'react-native';
import { render, fireEvent } from '@testing-library/react-native';

// Internal dependencies.
import PickerBase from './PickerBase';
import { IconName, IconSize } from '../../Icons/Icon';

describe('PickerBase', () => {
it('should render correctly', () => {
const { toJSON } = render(
<PickerBase onPress={jest.fn}>
<View />
<PickerBase onPress={jest.fn()}>
<Text>Test Content</Text>
</PickerBase>,
);
expect(toJSON()).toMatchSnapshot();
});

it('should call onPress when pressed', () => {
const onPressMock = jest.fn();
const { getByText } = render(
<PickerBase onPress={onPressMock}>
<Text>Test Content</Text>
</PickerBase>,
);

fireEvent.press(getByText('Test Content'));
expect(onPressMock).toHaveBeenCalledTimes(1);
});

it('should render children correctly', () => {
const { getByText } = render(
<PickerBase onPress={jest.fn()}>
<Text>Child Component</Text>
</PickerBase>,
);

expect(getByText('Child Component')).toBeTruthy();
});

it('should render dropdown icon', () => {
const { UNSAFE_getByProps } = render(
<PickerBase onPress={jest.fn()}>
<Text>Test Content</Text>
</PickerBase>,
);

const icon = UNSAFE_getByProps({ name: IconName.ArrowDown });
expect(icon).toBeTruthy();
});

it('should apply custom icon size', () => {
const { UNSAFE_getByProps } = render(
<PickerBase onPress={jest.fn()} iconSize={IconSize.Lg}>
<Text>Test Content</Text>
</PickerBase>,
);

const icon = UNSAFE_getByProps({
name: IconName.ArrowDown,
size: IconSize.Lg,
});
expect(icon).toBeTruthy();
});

it('should apply custom dropdown icon style', () => {
const customStyle = { marginLeft: 20 };
const { UNSAFE_getByProps } = render(
<PickerBase onPress={jest.fn()} dropdownIconStyle={customStyle}>
<Text>Test Content</Text>
</PickerBase>,
);

const icon = UNSAFE_getByProps({ name: IconName.ArrowDown });
expect(icon.props.style).toEqual(expect.objectContaining(customStyle));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@ import styleSheet from './PickerBase.styles';
const PickerBase: React.ForwardRefRenderFunction<
TouchableOpacity,
PickerBaseProps
> = ({ style, children, ...props }, ref) => {
const { styles, theme } = useStyles(styleSheet, { style });
> = (
{ iconSize = IconSize.Md, style, dropdownIconStyle, children, ...props },
ref,
) => {
const { styles, theme } = useStyles(styleSheet, { style, dropdownIconStyle });
const { colors } = theme;

return (
<TouchableOpacity style={styles.base} {...props} ref={ref}>
{children}
<Icon
size={IconSize.Md}
size={iconSize}
color={colors.icon.default}
name={IconName.ArrowDown}
style={styles.dropdownIcon}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Third party dependencies.
import { TouchableOpacityProps } from 'react-native';
import { TouchableOpacityProps, ViewStyle } from 'react-native';
import { IconSize } from '../../Icons/Icon';

/**
* PickerBase component props.
Expand All @@ -13,9 +14,20 @@ export interface PickerBaseProps extends TouchableOpacityProps {
* Content to wrap in PickerBase.
*/
children: React.ReactNode;
/**
* Icon size.
*/
iconSize?: IconSize;
/**
* Dropdown icon styles.
*/
dropdownIconStyle?: ViewStyle;
}

/**
* Style sheet input parameters.
*/
export type PickerBaseStyleSheetVars = Pick<PickerBaseProps, 'style'>;
export type PickerBaseStyleSheetVars = Pick<
PickerBaseProps,
'style' | 'dropdownIconStyle'
>;
56 changes: 50 additions & 6 deletions app/component-library/components/Pickers/PickerBase/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# PickerBase

PickerBase is a **wrapper** component used for providing a dropdown icon next to wrapped content.
PickerBase is a **wrapper** component used for providing a dropdown icon next to wrapped content. It's designed to be a flexible base for various picker-style components.

## Props

This component extends `TouchableOpacityProps` from React Native's [TouchableOpacityProps](https://reactnative.dev/docs/touchableOpacity) opacity.
This component extends `TouchableOpacityProps` from React Native's [TouchableOpacity](https://reactnative.dev/docs/touchableopacity).

### `onPress`

Expand All @@ -22,11 +22,55 @@ Content to wrap in PickerBase.
| :-------------------------------------------------- | :------------------------------------------------------ |
| ReactNode | Yes |

### `iconSize`

Size of the dropdown icon.

| <span style="color:gray;font-size:14px">TYPE</span> | <span style="color:gray;font-size:14px">REQUIRED</span> | <span style="color:gray;font-size:14px">DEFAULT</span> |
| :-------------------------------------------------- | :------------------------------------------------------ | :----------------------------------------------------- |
| IconSize | No | IconSize.Md |

### `dropdownIconStyle`

Custom styles for the dropdown icon.

| <span style="color:gray;font-size:14px">TYPE</span> | <span style="color:gray;font-size:14px">REQUIRED</span> |
| :-------------------------------------------------- | :------------------------------------------------------ |
| ViewStyle | No |

### `style`

Custom styles for the main container.

| <span style="color:gray;font-size:14px">TYPE</span> | <span style="color:gray;font-size:14px">REQUIRED</span> |
| :-------------------------------------------------- | :------------------------------------------------------ |
| ViewStyle | No |

## Usage

```javascript
// Replace import with relative path.
import React from 'react';
import { Text } from 'react-native';
import PickerBase from 'app/component-library/components/Pickers/PickerBase';
import { IconSize } from 'app/component-library/components/Icons/Icon';

const ExampleComponent = () => (
<PickerBase
onPress={() => console.log('Picker pressed')}
iconSize={IconSize.Lg}
dropdownIconStyle={{ marginLeft: 20 }}
style={{ backgroundColor: 'lightgray' }}
>
<Text>Select an option</Text>
</PickerBase>
);

<PickerBase onPress={ONPRESS_CALLBACK}>
<SampleContent />
</PickerBase>;
export default ExampleComponent;
```

## Notes

- The component uses a `TouchableOpacity` as its base, providing press feedback.
- It automatically includes a dropdown icon (ArrowDown) to the right of the content.
- The component is designed to be flexible and can be customized using the `style` and `dropdownIconStyle` props.
- The dropdown icon color is determined by the theme's `colors.icon.default`.
Loading

0 comments on commit e1ab767

Please sign in to comment.