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

fix: add favicon fetching hook #6951

Merged
merged 50 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
4888117
add favicon fetching hook
NicolasMassart Aug 2, 2023
81f5fbe
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Aug 2, 2023
b149005
making the code more readable
NicolasMassart Aug 2, 2023
ad27476
clean code and add cache
NicolasMassart Aug 3, 2023
0989616
Merge branch 'fix/1161_favicon_download' of github.com:MetaMask/metam…
NicolasMassart Aug 3, 2023
6062535
fix extension return
NicolasMassart Aug 3, 2023
f8e8aa0
move favicon html parsing to utils
NicolasMassart Aug 3, 2023
f1ed0d7
remove comments
NicolasMassart Aug 3, 2023
b7d0324
fix unit tests
NicolasMassart Aug 3, 2023
4b25546
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Aug 4, 2023
2de9ec7
update xmldom
NicolasMassart Aug 4, 2023
6f2b13b
update unit test and fix useEffect deps
NicolasMassart Aug 4, 2023
dadddb8
caching favicon url
NicolasMassart Aug 4, 2023
c7a341d
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Aug 28, 2023
646b4d7
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Sep 12, 2023
f6c4e22
adding hook to class controlers
NicolasMassart Sep 14, 2023
a7040c9
update tests
NicolasMassart Sep 18, 2023
56674dd
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Sep 18, 2023
72ffeef
add error handling
NicolasMassart Sep 18, 2023
3bcc367
update snapshots
NicolasMassart Sep 18, 2023
d67435b
Merge branch 'fix/1161_favicon_download' of github.com:MetaMask/metam…
NicolasMassart Sep 18, 2023
a2c05d7
fix the test
NicolasMassart Sep 18, 2023
06f350b
add reducer test
NicolasMassart Sep 18, 2023
8953e5c
update unit test
NicolasMassart Sep 18, 2023
566dd54
convert the tests back to JS to match reducer
NicolasMassart Sep 18, 2023
204f399
fix bookmark
NicolasMassart Sep 18, 2023
9cc9412
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Sep 18, 2023
7b9ec6c
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Sep 19, 2023
9b1efc1
add and fix TSDOC comment and code
NicolasMassart Sep 19, 2023
65c1058
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Sep 20, 2023
8a0019f
Remove useless try catch
NicolasMassart Sep 25, 2023
947dfd7
Merge branch 'fix/1161_favicon_download' of github.com:MetaMask/metam…
NicolasMassart Sep 25, 2023
3045705
add SVG support
NicolasMassart Sep 25, 2023
a9e255f
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Sep 25, 2023
d8c1677
update packages
NicolasMassart Sep 25, 2023
23274dc
update for fallback favicon
NicolasMassart Sep 25, 2023
318cc7e
revert format on a file that should have been ignored
NicolasMassart Sep 26, 2023
b9741fd
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Sep 26, 2023
5b4a349
Merge branch 'main' into fix/1161_favicon_download
cortisiko Oct 3, 2023
dea827e
update favicon for walletconnect deep linking
NicolasMassart Oct 10, 2023
db02899
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Oct 10, 2023
b1f6482
update unit test
NicolasMassart Oct 10, 2023
05ba2c7
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Oct 10, 2023
3f21e17
Merge branch 'main' into fix/1161_favicon_download
NicolasMassart Oct 11, 2023
830b147
fix svg image size when image on the website is an svg
tommasini Oct 20, 2023
717148e
added uniswap.org to the dapp url list, fixed the icon crash
tommasini Oct 23, 2023
784aece
merge main and solve conflicts
tommasini Oct 23, 2023
628f7fb
run `yarn deduplicate`
legobeat Oct 23, 2023
4d743c1
update uniswap.org url to app.uniswap.org on dapp list urls
tommasini Oct 24, 2023
fa7a1f3
Merge branch 'main' into fix/1161_favicon_download
tommasini Oct 25, 2023
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
7 changes: 7 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ node_modules
CHANGELOG.md
# Ignore auto generated file used for react-native-storybook-loader
/storybook/storyLoader.js
wdio
wdio.conf.js
scripts
.detoxrc.js
.prettierignore
locales
.storybook
15 changes: 15 additions & 0 deletions app/actions/browser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,18 @@ export function updateTab(id, data) {
data,
};
}

/**
* Stores the favicon url using the origin as key
* @param {Object} favicon - favicon to store
* @param {string} favicon.origin - the origin of the favicon as key
* @param {string} favicon.url - the favicon image url
* @returns {{favicon, type: string}}
*/
export function storeFavicon({ origin, url }) {
return {
type: 'STORE_FAVICON_URL',
origin,
url,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@ import { AvatarSize } from '../../Avatar.types';
import { IconSizeByAvatarSize } from './AvatarFavicon.types';

export const TEST_REMOTE_IMAGE_URL = 'https://uniswap.org/favicon.ico';
export const TEST_REMOTE_SVG_IMAGE_URL =
'https://metamask.github.io/test-dapp/metamask-fox.svg';

export const TEST_REMOTE_IMAGE_SOURCE: ImageSourcePropType = {
uri: TEST_REMOTE_IMAGE_URL,
};

export const TEST_REMOTE_SVG_IMAGE_SOURCE: ImageSourcePropType = {
uri: TEST_REMOTE_SVG_IMAGE_URL,
};

/* eslint-disable-next-line */
export const TEST_LOCAL_IMAGE_SOURCE: ImageSourcePropType = require('../../../../../../images/fox.png');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
TEST_REMOTE_IMAGE_SOURCE,
FAVICON_AVATAR_IMAGE_ID,
TEST_LOCAL_IMAGE_SOURCE,
TEST_REMOTE_SVG_IMAGE_SOURCE,
} from './AvatarFavicon.constants';

describe('AvatarFavicon', () => {
Expand Down Expand Up @@ -50,6 +51,16 @@ describe('AvatarFavicon', () => {
expect(imageComponent.exists()).toBe(true);
});

it('should render SVG', () => {
const wrapper = shallow(
<AvatarFavicon
size={AvatarSize.Xl}
imageSource={TEST_REMOTE_SVG_IMAGE_SOURCE}
/>,
);
expect(wrapper).toMatchSnapshot();
});

it('should render fallback', () => {
const wrapper = shallow(
<AvatarFavicon
Expand All @@ -67,4 +78,23 @@ describe('AvatarFavicon', () => {
);
expect(currentImageComponent.exists()).toBe(false);
});

it('should render fallback when svg has error', () => {
const wrapper = shallow(
<AvatarFavicon
size={AvatarSize.Xl}
imageSource={TEST_REMOTE_SVG_IMAGE_SOURCE}
/>,
);
const prevImageComponent = wrapper.findWhere(
(node) => node.prop('testID') === FAVICON_AVATAR_IMAGE_ID,
);
// Simulate onError on Image component
prevImageComponent.props().onError(new Error('ERROR!'));
const currentImageComponent = wrapper.findWhere(
(node) => node.prop('testID') === FAVICON_AVATAR_IMAGE_ID,
);
expect(currentImageComponent.exists()).toBe(false);
expect(wrapper).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* eslint-disable react/prop-types */

// Third party dependencies.
import React, { useCallback, useState } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import { Image, ImageErrorEventData, NativeSyntheticEvent } from 'react-native';
import { SvgUri } from 'react-native-svg';

// External dependencies.
import AvatarBase from '../../foundation/AvatarBase';
Expand All @@ -17,13 +18,15 @@ import {
FAVICON_AVATAR_IMAGE_ID,
} from './AvatarFavicon.constants';
import stylesheet from './AvatarFavicon.styles';
import { isNumber } from 'lodash';
import { isFaviconSVG } from '../../../../../../util/favicon';

const AvatarFavicon = ({
imageSource,
size = AvatarSize.Md,
style,
}: AvatarFaviconProps) => {
const [error, setError] = useState(undefined);
const [error, setError] = useState<any>(undefined);
const { styles } = useStyles(stylesheet, { style, error });

const onError = useCallback(
Expand All @@ -32,10 +35,32 @@ const AvatarFavicon = ({
[setError],
);

const renderError = () => (
const onSvgError = useCallback((e: any) => setError(e), [setError]);

// TODO add the fallback with uppercase letter initial
// requires that the domain is passed in as a prop from the parent
const renderFallbackFavicon = () => (
<Icon size={ICON_SIZE_BY_AVATAR_SIZE[size]} name={IconName.Global} />
);

const svgSource = useMemo(() => {
if (imageSource && !isNumber(imageSource) && 'uri' in imageSource) {
return isFaviconSVG(imageSource);
}
}, [imageSource]);

const renderSvg = () =>
svgSource ? (
<SvgUri
testID={FAVICON_AVATAR_IMAGE_ID}
width="100%"
height="100%"
uri={svgSource}
style={styles.image}
onError={onSvgError}
/>
) : null;

const renderImage = () => (
<Image
testID={FAVICON_AVATAR_IMAGE_ID}
Expand All @@ -46,9 +71,11 @@ const AvatarFavicon = ({
/>
);

const renderFavicon = () => (svgSource ? renderSvg() : renderImage());

return (
<AvatarBase size={size} style={styles.base}>
{error ? renderError() : renderImage()}
{error ? renderFallbackFavicon() : renderFavicon()}
</AvatarBase>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,47 @@ exports[`AvatarFavicon should match the snapshot 1`] = `
/>
</AvatarBase>
`;

exports[`AvatarFavicon should render SVG 1`] = `
<AvatarBase
size="48"
style={
Object {
"borderRadius": 0,
}
}
>
<SvgUri
height="100%"
onError={[Function]}
style={
Object {
"flex": 1,
"height": undefined,
"width": undefined,
}
}
testID="favicon-avatar-image"
uri="https://metamask.github.io/test-dapp/metamask-fox.svg"
width="100%"
/>
</AvatarBase>
`;

exports[`AvatarFavicon should render fallback when svg has error 1`] = `
<AvatarBase
size="48"
style={
Object {
"alignItems": "center",
"backgroundColor": "#F2F4F6",
"justifyContent": "center",
}
}
>
<Icon
name="Global"
size="32"
/>
</AvatarBase>
`;
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
import AppConstants from '../../../core/AppConstants';

export const { ORIGIN_DEEPLINK, ORIGIN_QR_CODE } = AppConstants.DEEPLINKS;

export const FAV_ICON_URL = (hostUrl: string) =>
`https://api.faviconkit.com/${hostUrl}/64`;
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,20 @@ import { selectProviderConfig } from '../../../selectors/networkController';
import { selectAccounts } from '../../../selectors/accountTrackerController';
import { selectIdentities } from '../../../selectors/preferencesController';
import { renderAccountName, renderShortAddress } from '../../../util/address';
import {
getHost,
getUrlObj,
prefixUrlWithProtocol,
} from '../../../util/browser';
import { getUrlObj, prefixUrlWithProtocol } from '../../../util/browser';
import {
getNetworkImageSource,
getNetworkNameFromProviderConfig,
} from '../../../util/networks';
import { WALLET_CONNECT_ORIGIN } from '../../../util/walletconnect';
import useAddressBalance from '../../hooks/useAddressBalance/useAddressBalance';
import {
FAV_ICON_URL,
ORIGIN_DEEPLINK,
ORIGIN_QR_CODE,
} from './ApproveTransactionHeader.constants';
import stylesheet from './ApproveTransactionHeader.styles';
import { ApproveTransactionHeaderI } from './ApproveTransactionHeader.types';
import useFavicon from '../../hooks/useFavicon/useFavicon';

const ApproveTransactionHeader = ({
from,
Expand Down Expand Up @@ -110,21 +106,23 @@ const ApproveTransactionHeader = ({
url,
]);

const favIconUrl = useMemo(() => {
let newUrl = origin;
const faviconUpdatedOrigin = useMemo(() => {
let newOrigin = origin;
if (isOriginWalletConnect) {
newUrl = origin.split(WALLET_CONNECT_ORIGIN)[1];
newOrigin = origin.split(WALLET_CONNECT_ORIGIN)[1];
} else if (isOriginMMSDKRemoteConn) {
newUrl = origin.split(AppConstants.MM_SDK.SDK_REMOTE_ORIGIN)[1];
newOrigin = origin.split(AppConstants.MM_SDK.SDK_REMOTE_ORIGIN)[1];
}
return FAV_ICON_URL(getHost(newUrl));
return newOrigin;
}, [origin, isOriginWalletConnect, isOriginMMSDKRemoteConn]);

const faviconSource = useFavicon(faviconUpdatedOrigin);

return (
<View style={styles.transactionHeader}>
{origin ? (
<TagUrl
imageSource={{ uri: favIconUrl }}
imageSource={faviconSource}
label={domainTitle}
style={styles.tagUrl}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,7 @@ exports[`ApproveTransactionHeader should render correctly 1`] = `
<Image
onError={[Function]}
resizeMode="contain"
source={
Object {
"uri": "https://api.faviconkit.com/metamask.github.io/64",
}
}
source={Object {}}
style={
Object {
"flex": 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ exports[`ExpandedMessage should render correctly 1`] = `
}
}
>
<WebsiteIcon
<Component
style={
Object {
"borderRadius": 20,
Expand Down
2 changes: 1 addition & 1 deletion app/components/UI/SignatureRequest/Root/Root.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const messageParamsMock = {
meta: {
url: 'https://metamask.github.io/test-dapp/',
title: 'E2E Test Dapp',
icon: 'https://api.faviconkit.com/metamask.github.io/50',
icon: 'https://metamask.github.io/test-dapp/metamask-fox.svg',
analytics: {
request_source: 'In-App-Browser',
request_platform: 'Test-Platform',
Expand Down
Loading