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

feat: add privacy mode #28021

Merged
merged 31 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7611b29
Add sensitive text
jonybur Oct 22, 2024
63c9c3f
Add nowrap to token container
jonybur Oct 22, 2024
25ded19
Dont show hidden text if there's no text
jonybur Oct 22, 2024
e916835
Use setPreference
jonybur Oct 22, 2024
4e59b98
Move privacyMode setting
jonybur Oct 23, 2024
2dd26d1
Fix test
jonybur Oct 23, 2024
b5eda7b
Add stories
jonybur Oct 23, 2024
ddbaf76
Fix test
jonybur Oct 23, 2024
a508e38
Fix test
jonybur Oct 23, 2024
ac1fb14
Add e2e test
jonybur Oct 23, 2024
c783377
Await for 2 secodns
jonybur Oct 23, 2024
02b49f1
Add privacyMode to state
jonybur Oct 23, 2024
4f3f174
fix: updates according to feedback from pr
vinnyhoward Oct 23, 2024
23e0a29
fix: e2e test delay
vinnyhoward Oct 23, 2024
8fc378a
Merge branch 'develop' into jb-privacy-mode
vinnyhoward Oct 23, 2024
e8ec40d
fix: UI udpates according to feedback from design
vinnyhoward Oct 23, 2024
c41b152
fix: lint in sensitive text type
vinnyhoward Oct 23, 2024
22eacd4
fix: fixed wording in readme of sensitive text
vinnyhoward Oct 23, 2024
6e27a5c
fix: updated e2e test
vinnyhoward Oct 24, 2024
7431efc
fix: remove logs for e2e test
vinnyhoward Oct 24, 2024
5ac2d24
Merge branch 'develop' of github.com:MetaMask/metamask-extension into…
vinnyhoward Oct 24, 2024
731199a
fix: refactor on how privacy mode works with token list and added e2e…
vinnyhoward Oct 25, 2024
2b24b2a
Merge branch 'develop' into jb-privacy-mode
darkwing Oct 28, 2024
6a05779
test: update snaps
vinnyhoward Oct 28, 2024
b713d3b
Merge branch 'develop' into jb-privacy-mode
vinnyhoward Oct 28, 2024
53d60cf
Merge branch 'develop' into jb-privacy-mode
vinnyhoward Oct 28, 2024
9240d83
fix: remove logs
vinnyhoward Oct 28, 2024
72198f0
Merge branch 'jb-privacy-mode' of github.com:MetaMask/metamask-extens…
vinnyhoward Oct 28, 2024
475a2d8
Merge branch 'develop' of github.com:MetaMask/metamask-extension into…
vinnyhoward Oct 29, 2024
ac9c738
Remove unwanted markdown file
darkwing Oct 29, 2024
3d0eeda
Merge branch 'develop' into jb-privacy-mode
vinnyhoward Oct 30, 2024
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
1 change: 1 addition & 0 deletions app/scripts/constants/sentry-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export const SENTRY_BACKGROUND_STATE = {
showNativeTokenAsMainBalance: true,
petnamesEnabled: true,
showConfirmationAdvancedDetails: true,
privacyMode: false,
},
useExternalServices: false,
selectedAddress: false,
Expand Down
2 changes: 2 additions & 0 deletions app/scripts/controllers/preferences-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,7 @@ describe('preferences controller', () => {
expect(controller.state.preferences).toStrictEqual({
autoLockTimeLimit: undefined,
showExtensionInFullSizeView: false,
privacyMode: false,
showFiatInTestnets: false,
showTestNetworks: false,
smartTransactionsOptInStatus: null,
Expand Down Expand Up @@ -764,6 +765,7 @@ describe('preferences controller', () => {
useNativeCurrencyAsPrimaryCurrency: true,
hideZeroBalanceTokens: false,
petnamesEnabled: true,
privacyMode: false,
redesignedConfirmationsEnabled: true,
redesignedTransactionsEnabled: true,
shouldShowAggregatedBalancePopover: true,
Expand Down
2 changes: 2 additions & 0 deletions app/scripts/controllers/preferences-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export type Preferences = {
redesignedTransactionsEnabled: boolean;
featureNotificationsEnabled: boolean;
showMultiRpcModal: boolean;
privacyMode: boolean;
isRedesignedConfirmationsDeveloperEnabled: boolean;
showConfirmationAdvancedDetails: boolean;
tokenSortConfig: {
Expand Down Expand Up @@ -214,6 +215,7 @@ export const getDefaultPreferencesControllerState =
isRedesignedConfirmationsDeveloperEnabled: false,
showConfirmationAdvancedDetails: false,
showMultiRpcModal: false,
privacyMode: false,
shouldShowAggregatedBalancePopover: true, // by default user should see popover;
tokenSortConfig: {
key: 'tokenFiatAmount',
Expand Down
1 change: 1 addition & 0 deletions app/scripts/fixtures/with-preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const FIXTURES_PREFERENCES = {
showNftAutodetectModal: false,
isRedesignedConfirmationsDeveloperEnabled: false,
showConfirmationAdvancedDetails: false,
privacyMode: false,
},
featureFlags: {
sendHexData: true,
Expand Down
1 change: 1 addition & 0 deletions test/e2e/fixture-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ function onboardingFixture() {
hideZeroBalanceTokens: false,
showExtensionInFullSizeView: false,
showFiatInTestnets: false,
privacyMode: false,
showTestNetworks: false,
smartTransactionsOptInStatus: false,
showNativeTokenAsMainBalance: true,
Expand Down
1 change: 1 addition & 0 deletions test/e2e/tests/metrics/errors.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,7 @@ describe('Sentry errors', function () {
preferences: {
autoLockTimeLimit: true, // Initialized as undefined
showConfirmationAdvancedDetails: true,
privacyMode: false,
},
smartTransactionsState: {
fees: {
Expand Down
59 changes: 59 additions & 0 deletions test/e2e/tests/privacy-mode/privacy-mode.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const { strict: assert } = require('assert');
const {
withFixtures,
unlockWallet,
defaultGanacheOptions,
} = require('../../helpers');
const FixtureBuilder = require('../../fixture-builder');

describe('Privacy Mode', function () {
it('should activate privacy mode, then deactivate it', async function () {
await withFixtures(
{
dapp: true,
fixtures: new FixtureBuilder().withPreferencesController().build(),
ganacheOptions: defaultGanacheOptions,
title: this.test.fullTitle(),
},
async ({ driver }) => {
async function checkForHeaderValue(value) {
const balanceElement = await driver.findElement(
'[data-testid="eth-overview__primary-currency"] .currency-display-component__text',
);
const surveyText = await balanceElement.getText();
assert.equal(surveyText, value, `Balance should be "${value}"`);
}

async function checkForTokenValue(value) {
const balanceElement = await driver.findElement(
'[data-testid="multichain-token-list-item-secondary-value"]',
);
const surveyText = await balanceElement.getText();
assert.equal(surveyText, value, `Balance should be "${value}"`);
}

async function checkForPrivacy() {
await checkForHeaderValue('*****');
await checkForTokenValue('*****');
}

async function checkForNoPrivacy() {
await checkForHeaderValue('25');
await checkForTokenValue('25 ETH');
}

async function togglePrivacy() {
await driver.clickElement('[data-testid="sensitive-toggle"]');
await new Promise((resolve) => setTimeout(resolve, 2e3));
vinnyhoward marked this conversation as resolved.
Show resolved Hide resolved
}

await unlockWallet(driver);
await checkForNoPrivacy();
await togglePrivacy();
await checkForPrivacy();
await togglePrivacy();
await checkForNoPrivacy();
},
);
});
});
3 changes: 2 additions & 1 deletion test/integration/data/onboarding-completion-route.json
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@
"hideZeroBalanceTokens": false,
"petnamesEnabled": true,
"redesignedConfirmationsEnabled": true,
"featureNotificationsEnabled": false
"featureNotificationsEnabled": false,
"privacyMode": false
},
"preventPollingOnNetworkRestart": false,
"previousAppVersion": "",
Expand Down
5 changes: 4 additions & 1 deletion ui/components/app/assets/token-cell/token-cell.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { fireEvent } from '@testing-library/react';
import { useSelector } from 'react-redux';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import { useTokenFiatAmount } from '../../../../hooks/useTokenFiatAmount';
import { getTokenList } from '../../../../selectors';
import { getTokenList, getPreferences } from '../../../../selectors';
import {
getMultichainCurrentChainId,
getMultichainIsEvm,
Expand Down Expand Up @@ -98,6 +98,9 @@ describe('Token Cell', () => {
};
const useSelectorMock = useSelector;
(useSelectorMock as jest.Mock).mockImplementation((selector) => {
if (selector === getPreferences) {
return { privacyMode: false };
}
if (selector === getTokenList) {
return MOCK_GET_TOKEN_LIST;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getSelectedAccount,
getShouldHideZeroBalanceTokens,
getTokensMarketData,
getPreferences,
} from '../../../selectors';
import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance';
import { AggregatedPercentageOverview } from './aggregated-percentage-overview';
Expand All @@ -22,6 +23,7 @@ jest.mock('../../../ducks/locale/locale', () => ({
jest.mock('../../../selectors', () => ({
getCurrentCurrency: jest.fn(),
getSelectedAccount: jest.fn(),
getPreferences: jest.fn(),
getShouldHideZeroBalanceTokens: jest.fn(),
getTokensMarketData: jest.fn(),
}));
Expand All @@ -32,6 +34,7 @@ jest.mock('../../../hooks/useAccountTotalFiatBalance', () => ({

const mockGetIntlLocale = getIntlLocale as unknown as jest.Mock;
const mockGetCurrentCurrency = getCurrentCurrency as jest.Mock;
const mockGetPreferences = getPreferences as jest.Mock;
const mockGetSelectedAccount = getSelectedAccount as unknown as jest.Mock;
const mockGetShouldHideZeroBalanceTokens =
getShouldHideZeroBalanceTokens as jest.Mock;
Expand Down Expand Up @@ -159,6 +162,7 @@ describe('AggregatedPercentageOverview', () => {
beforeEach(() => {
mockGetIntlLocale.mockReturnValue('en-US');
mockGetCurrentCurrency.mockReturnValue('USD');
mockGetPreferences.mockReturnValue({ privacyMode: false });
mockGetSelectedAccount.mockReturnValue(selectedAccountMock);
mockGetShouldHideZeroBalanceTokens.mockReturnValue(false);
mockGetTokensMarketData.mockReturnValue(marketDataMock);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getSelectedAccount,
getShouldHideZeroBalanceTokens,
getTokensMarketData,
getPreferences,
} from '../../../selectors';

import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance';
Expand All @@ -19,7 +20,7 @@ import {
TextColor,
TextVariant,
} from '../../../helpers/constants/design-system';
import { Box, Text } from '../../component-library';
import { Box, SensitiveText } from '../../component-library';
import { getCalculatedTokenAmount1dAgo } from '../../../helpers/utils/util';

// core already has this exported type but its not yet available in this version
Expand All @@ -34,6 +35,7 @@ export const AggregatedPercentageOverview = () => {
useSelector(getTokensMarketData);
const locale = useSelector(getIntlLocale);
const fiatCurrency = useSelector(getCurrentCurrency);
const { privacyMode } = useSelector(getPreferences);
const selectedAccount = useSelector(getSelectedAccount);
const shouldHideZeroBalanceTokens = useSelector(
getShouldHideZeroBalanceTokens,
Expand Down Expand Up @@ -121,23 +123,25 @@ export const AggregatedPercentageOverview = () => {
}
return (
<Box display={Display.Flex}>
<Text
<SensitiveText
variant={TextVariant.bodyMdMedium}
color={color}
data-testid="aggregated-value-change"
style={{ whiteSpace: 'pre' }}
isHidden={privacyMode}
ellipsis
>
{formattedAmountChange}
</Text>
<Text
</SensitiveText>
<SensitiveText
variant={TextVariant.bodyMdMedium}
color={color}
data-testid="aggregated-percentage-change"
isHidden={privacyMode}
ellipsis
>
{formattedPercentChange}
</Text>
</SensitiveText>
</Box>
);
};
62 changes: 40 additions & 22 deletions ui/components/app/wallet-overview/coin-overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ import Spinner from '../../ui/spinner';
import { PercentageAndAmountChange } from '../../multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change';
import { getMultichainIsEvm } from '../../../selectors/multichain';
import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance';
import { setAggregatedBalancePopoverShown } from '../../../store/actions';
import {
setAggregatedBalancePopoverShown,
setPrivacyMode,
} from '../../../store/actions';
import { useTheme } from '../../../hooks/useTheme';
import { getSpecificSettingsRoute } from '../../../helpers/utils/settings-search';
import { useI18nContext } from '../../../hooks/useI18nContext';
Expand Down Expand Up @@ -128,7 +131,7 @@ export const CoinOverview = ({

const shouldShowPopover = useSelector(getShouldShowAggregatedBalancePopover);
const isTestnet = useSelector(getIsTestnet);
const { showFiatInTestnets } = useSelector(getPreferences);
const { showFiatInTestnets, privacyMode } = useSelector(getPreferences);

const selectedAccount = useSelector(getSelectedAccount);
const shouldHideZeroBalanceTokens = useSelector(
Expand Down Expand Up @@ -163,6 +166,10 @@ export const CoinOverview = ({
dispatch(setAggregatedBalancePopoverShown());
};

const handleSensitiveToggle = () => {
dispatch(setPrivacyMode(!privacyMode));
};

const [referenceElement, setReferenceElement] =
useState<HTMLSpanElement | null>(null);
const setBoxRef = (ref: HTMLSpanElement | null) => {
Expand Down Expand Up @@ -253,26 +260,37 @@ export const CoinOverview = ({
ref={setBoxRef}
>
{balanceToDisplay ? (
<UserPreferencedCurrencyDisplay
style={{ display: 'contents' }}
account={account}
className={classnames(
`${classPrefix}-overview__primary-balance`,
{
[`${classPrefix}-overview__cached-balance`]:
balanceIsCached,
},
)}
data-testid={`${classPrefix}-overview__primary-currency`}
value={balanceToDisplay}
type={PRIMARY}
ethNumberOfDecimals={4}
hideTitle
shouldCheckShowNativeToken
isAggregatedFiatOverviewBalance={
!showNativeTokenAsMainBalance && !isTestnet
}
/>
<>
<UserPreferencedCurrencyDisplay
style={{ display: 'contents' }}
account={account}
className={classnames(
`${classPrefix}-overview__primary-balance`,
{
[`${classPrefix}-overview__cached-balance`]:
balanceIsCached,
},
)}
data-testid={`${classPrefix}-overview__primary-currency`}
value={balanceToDisplay}
type={PRIMARY}
ethNumberOfDecimals={4}
hideTitle
shouldCheckShowNativeToken
isAggregatedFiatOverviewBalance={
!showNativeTokenAsMainBalance && !isTestnet
}
/>
<ButtonIcon
marginLeft={2}
size={ButtonIconSize.Lg}
onClick={handleSensitiveToggle}
iconName={privacyMode ? IconName.EyeSlash : IconName.Eye}
justifyContent={JustifyContent.center}
ariaLabel="Sensitive toggle"
data-testid="sensitive-toggle"
/>
</>
) : (
<Spinner className="loading-overlay__spinner" />
)}
Expand Down
6 changes: 4 additions & 2 deletions ui/components/app/wallet-overview/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
display: flex;
max-width: inherit;
justify-content: center;
flex-wrap: wrap;
align-items: center;
flex-wrap: nowrap;
}

&__primary-balance {
Expand Down Expand Up @@ -134,7 +135,8 @@
display: flex;
max-width: inherit;
justify-content: center;
flex-wrap: wrap;
align-items: center;
flex-wrap: nowrap;
}

&__primary-balance {
Expand Down
2 changes: 2 additions & 0 deletions ui/components/component-library/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ export { TagUrl } from './tag-url';
export type { TagUrlProps } from './tag-url';
export { Text, ValidTag, TextDirection, InvisibleCharacter } from './text';
export type { TextProps } from './text';
export { SensitiveText, SensitiveLengths } from './sensitive-text';
export type { SensitiveTextProps } from './sensitive-text';
export { Input, InputType } from './input';
export type { InputProps } from './input';
export { TextField, TextFieldType, TextFieldSize } from './text-field';
Expand Down
3 changes: 3 additions & 0 deletions ui/components/component-library/sensitive-text/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { SensitiveText } from './sensitive-text';
export { SensitiveLengths } from './sensitive-text.types';
export type { SensitiveTextProps } from './sensitive-text.types';
Loading