diff --git a/e2e/backup.e2e.js b/e2e/backup.e2e.js index 00965d543..ffdd7a93a 100644 --- a/e2e/backup.e2e.js +++ b/e2e/backup.e2e.js @@ -57,7 +57,7 @@ d('Backup', () => { } // recieve bitcoin await element(by.id('Receive')).tap(); - await sleep(1000); // animation + await sleep(200); // animation // get address from qrcode await waitFor(element(by.id('QRCode'))).toBeVisible(); await sleep(100); // wait for qr code to render @@ -72,7 +72,7 @@ d('Backup', () => { .toBeVisible() .withTimeout(10000); await element(by.id('NewTxPrompt')).swipe('down'); // close Receive screen - await sleep(1000); // animation + await sleep(200); // animation // set tag to new tx const tag = 'testtag'; @@ -81,7 +81,7 @@ d('Backup', () => { await element(by.id('ActivityTag')).tap(); await element(by.id('TagInput')).replaceText(tag); await element(by.id('TagInput')).tapReturnKey(); - await sleep(1000); // animation + await sleep(200); // animation await element(by.id('NavigationClose')).tap(); // change currency to GBP @@ -92,46 +92,24 @@ d('Backup', () => { await element(by.text('GBP (£)')).tap(); await element(by.id('NavigationClose')).tap(); - // add price widget - await element(by.id('WalletsScrollView')).scroll(300, 'down', NaN, 0.85); - await element(by.id('WidgetsAdd')).tap(); - await element(by.id('WidgetsOnboarding-button')).tap(); - await element(by.id('PriceWidget')).tap(); - // for unknown reason await waitFor(element(by.id('HourglassSpinner'))).not.toBeVisible(); - // doesn't work here, so instead we just wait until we can tap WidgetSave - // 5 min timeout - for (let i = 0; i < 300; i++) { - await sleep(1000); - try { - await element(by.id('WidgetSave')).tap(); - break; - } catch (e) {} + // remove 2 default widgets, leave PriceWidget + await element(by.id('WalletsScrollView')).scroll(100, 'down', NaN, 0.85); + await element(by.id('WidgetsEdit')).tap(); + for (const w of ['HeadlinesWidget', 'BlocksWidget']) { + await element(by.id('WidgetActionDelete').withAncestor(by.id(w))).tap(); + await element(by.text('Yes, Delete')).tap(); + await expect(element(by.id(w))).not.toBeVisible(); } + await element(by.id('WidgetsEdit')).tap(); + await expect(element(by.id('PriceWidget'))).toBeVisible(); - await sleep(1000); // animation await element(by.id('TransferButton')).swipe('up'); - // add headlines widget - await element(by.id('WidgetsAdd')).tap(); - await element(by.id('HeadlinesWidget')).tap(); - // for unknown reason await waitFor(element(by.id('HourglassSpinner'))).not.toBeVisible(); - // doesn't work here, so instead we just wait until we can tap WidgetSave - // 5 min timeout - for (let i = 0; i < 300; i++) { - await sleep(1000); - try { - await element(by.id('WidgetSave')).tap(); - break; - } catch (e) {} - } - - await sleep(1000); // animation - // get seed await element(by.id('Settings')).tap(); await element(by.id('BackupSettings')).tap(); await element(by.id('BackupWallet')).tap(); - await sleep(1000); // animation + await sleep(200); // animation await element(by.id('TapToReveal')).tap(); // get the seed from SeedContaider @@ -140,7 +118,7 @@ d('Backup', () => { ).getAttributes(); await element(by.id('SeedContaider')).swipe('down'); - await sleep(1000); // animation + await sleep(200); // animation await element(by.id('NavigationClose')).tap(); await sleep(5000); // make sure everything is saved to cloud storage TODO: improve this @@ -169,7 +147,7 @@ d('Backup', () => { // wait for SuggestionsLabel to appear and be accessible for (let i = 0; i < 60; i++) { - await sleep(1000); + await sleep(200); try { await element(by.id('SuggestionsLabel')).tap(); break; @@ -191,10 +169,9 @@ d('Backup', () => { // check widgets await element(by.id('WalletsScrollView')).scroll(300, 'down', NaN, 0.85); - await expect(element(by.id('PriceWidget'))).toBeVisible(); - - // FIXME: HeadlinesWidget is not visible here - // await expect(element(by.id('HeadlinesWidget'))).toBeVisible(); + await expect(element(by.id('PriceWidget'))).toExist(); + await expect(element(by.id('HeadlinesWidget'))).not.toExist(); + await expect(element(by.id('BlocksWidget'))).not.toExist(); markComplete('backup-1'); }); diff --git a/e2e/widgets.e2e.js b/e2e/widgets.e2e.js index 2c7f7aae1..8f1b4bfff 100644 --- a/e2e/widgets.e2e.js +++ b/e2e/widgets.e2e.js @@ -26,6 +26,14 @@ d('Widgets', () => { return; } + // delete all default widgets + await element(by.id('WidgetsEdit')).tap(); + for (const w of ['PriceWidget', 'HeadlinesWidget', 'BlocksWidget']) { + await element(by.id('WidgetActionDelete').withAncestor(by.id(w))).tap(); + await element(by.text('Yes, Delete')).tap(); + await expect(element(by.id(w))).not.toBeVisible(); + } + // add price widget await element(by.id('WalletsScrollView')).scroll(300, 'down', NaN, 0.85); await element(by.id('WidgetsAdd')).tap(); @@ -59,12 +67,6 @@ d('Widgets', () => { await expect(element(by.id('PriceWidgetRow-BTC/EUR'))).not.toBeVisible(); await expect(element(by.id('PriceWidgetSource'))).not.toBeVisible(); - // delete price widget - await element(by.id('WidgetsEdit')).tap(); - await element(by.id('WidgetActionDelete')).tap(); - await element(by.text('Yes, Delete')).tap(); - await expect(element(by.id('PriceWidget'))).not.toBeVisible(); - markComplete('widgets-1'); }); }); diff --git a/src/screens/Wallets/MainOnboarding.tsx b/src/screens/Wallets/MainOnboarding.tsx new file mode 100644 index 000000000..7085aaf53 --- /dev/null +++ b/src/screens/Wallets/MainOnboarding.tsx @@ -0,0 +1,84 @@ +import React, { ReactElement, memo } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { StyleProp, ViewStyle } from 'react-native'; + +import WalletOnboarding from '../../components/WalletOnboarding'; +import { useAppDispatch } from '../../hooks/redux'; +import { useSlashfeed } from '../../hooks/widgets'; +import { updateSettings } from '../../store/slices/settings'; +import { setFeedWidget } from '../../store/slices/widgets'; +import { Display } from '../../styles/text'; +import { SUPPORTED_FEED_TYPES } from '../../utils/widgets'; +import { + BlocksFeedURL, + NewsFeedURL, + PriceFeedURL, +} from '../Widgets/WidgetsSuggestions'; + +const MainOnboarding = ({ + style, +}: { + style: StyleProp; +}): ReactElement => { + const dispatch = useAppDispatch(); + const { t } = useTranslation('onboarding'); + const { config: priceConfig } = useSlashfeed({ url: PriceFeedURL }); + const { config: newsConfig } = useSlashfeed({ url: NewsFeedURL }); + const { config: blocksConfig } = useSlashfeed({ url: BlocksFeedURL }); + + const onHideOnboarding = (): void => { + // add default widgets + if (priceConfig) { + dispatch( + setFeedWidget({ + url: PriceFeedURL, + type: SUPPORTED_FEED_TYPES.PRICE_FEED, + fields: priceConfig.fields.filter((f) => f.name === 'BTC/USD'), + extras: { period: '1D', showSource: false }, + }), + ); + } + + if (newsConfig) { + dispatch( + setFeedWidget({ + url: NewsFeedURL, + type: SUPPORTED_FEED_TYPES.HEADLINES_FEED, + fields: newsConfig.fields, + }), + ); + } + + if (blocksConfig) { + const fields = blocksConfig.fields.filter((f) => { + return ['Block', 'Time', 'Date'].includes(f.name); + }); + + dispatch( + setFeedWidget({ + url: BlocksFeedURL, + type: SUPPORTED_FEED_TYPES.BLOCKS_FEED, + fields, + }), + ); + } + + dispatch(updateSettings({ hideOnboardingMessage: true })); + }; + + return ( + }} + /> + } + /> + ); +}; + +export default memo(MainOnboarding); diff --git a/src/screens/Wallets/index.tsx b/src/screens/Wallets/index.tsx index ceb2496d0..b9dc8a3c9 100644 --- a/src/screens/Wallets/index.tsx +++ b/src/screens/Wallets/index.tsx @@ -3,27 +3,22 @@ import { StyleSheet, View } from 'react-native'; import { useFocusEffect } from '@react-navigation/native'; import { RefreshControl, ScrollView } from 'react-native-gesture-handler'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { Trans, useTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; -import { Display } from '../../styles/text'; import { useBalance } from '../../hooks/wallet'; import useColors from '../../hooks/colors'; -import { useSlashfeed } from '../../hooks/widgets'; import { useAppDispatch, useAppSelector } from '../../hooks/redux'; import { updateSettings } from '../../store/slices/settings'; import { widgetsSelector } from '../../store/reselect/widgets'; import { refreshWallet } from '../../utils/wallet'; -import { SUPPORTED_FEED_TYPES } from '../../utils/widgets'; import ActivityListShort from '../../screens/Activity/ActivityListShort'; import DetectSwipe from '../../components/DetectSwipe'; import BalanceHeader from '../../components/BalanceHeader'; import Suggestions from '../../components/Suggestions'; import Widgets from '../../components/Widgets'; import SafeAreaInset from '../../components/SafeAreaInset'; -import WalletOnboarding from '../../components/WalletOnboarding'; import Balances from '../../components/Balances'; import Header from './Header'; -import { PriceFeedURL } from '../Widgets/WidgetsSuggestions'; import type { WalletScreenProps } from '../../navigation/types'; import { enableSwipeToHideBalanceSelector, @@ -34,7 +29,7 @@ import { import { showToast } from '../../utils/notifications'; import { ignoresHideBalanceToastSelector } from '../../store/reselect/user'; import { ignoreHideBalanceToast } from '../../store/slices/user'; -import { setFeedWidget } from '../../store/slices/widgets'; +import MainOnboarding from './MainOnboarding'; const HEADER_HEIGHT = 46; @@ -59,7 +54,6 @@ const Wallets = ({ navigation, onFocus }: Props): ReactElement => { const widgets = useAppSelector(widgetsSelector); const insets = useSafeAreaInsets(); const { t } = useTranslation('wallet'); - const { config } = useSlashfeed({ url: PriceFeedURL }); // tell WalletNavigator that this screen is focused useFocusEffect( @@ -97,22 +91,6 @@ const Wallets = ({ navigation, onFocus }: Props): ReactElement => { setRefreshing(false); }; - const onHideOnboarding = (): void => { - // add default widgets - if (config) { - dispatch( - setFeedWidget({ - url: PriceFeedURL, - type: SUPPORTED_FEED_TYPES.PRICE_FEED, - fields: config.fields.filter((f) => f.name === 'BTC/USD'), - extras: { period: '1D', showSource: false }, - }), - ); - } - - dispatch(updateSettings({ hideOnboardingMessage: true })); - }; - const hideOnboarding = hideOnboardingSetting || totalBalance > 0 || @@ -162,17 +140,7 @@ const Wallets = ({ navigation, onFocus }: Props): ReactElement => { ) : ( - }} - /> - } - onHide={onHideOnboarding} - /> + )} diff --git a/src/screens/Widgets/WidgetsSuggestions.tsx b/src/screens/Widgets/WidgetsSuggestions.tsx index 2ade9ec22..0be367e8c 100644 --- a/src/screens/Widgets/WidgetsSuggestions.tsx +++ b/src/screens/Widgets/WidgetsSuggestions.tsx @@ -16,9 +16,9 @@ import type { RootStackScreenProps } from '../../navigation/types'; export const PriceFeedURL = 'slashfeed:9ckhj7ea31ugskdewy9eiod5trhtbgcu9juza8aypjyugsp5f4oo/Bitcoin Price'; -const NewsFeedURL = +export const NewsFeedURL = 'slashfeed:tdm8gwcuh6nfw4w8remadpzid9cff4tpoyazeokzbrfnjrxyf9ho/Bitcoin Headlines'; -const BlocksFeedURL = +export const BlocksFeedURL = 'slashfeed:xzdjbqu5ym3hk4xp993hg4ahzs1g4o85dhw9nnp4qcbd57pxndoo/Bitcoin Blocks'; const BitcoinFactsURL = 'slashfeed:jm1n46tbdbnz4soq8hqppbpwt3pqp3cp9qobdjgyk8mjmnmdj14o/Bitcoin Facts';