Skip to content

Commit 87b4499

Browse files
refactor: modify trending browser navigators (#23598)
## **Description** Fixes issue where custom trending browser uses a different design compared to the original. This PR removes our custom browser wrapper in favour of the original browser + behaviour -- the mobile platform team will spearhead the IAB changes. For visibility: Navigation Structure Before: ``` (TAB) REMOVED Browser Tab -- removing this caused issues for areas using old browser navigation (TAB) Trending Tab (ExploreFlow) (STACK) Trending (STACK) Trending - TRENDING_FEED - EXPLORE_SEARCH - Custom Browser ``` Navigation Structure After: ``` (TAB) Browser Tab (BrowserFlow) -- Keeping original browser tab, but it is hidden - existing navigations will still work - BROWSER.VIEW - BROWSER.ASSET_LOADER - BROWSER.ASSET_VIEW (TAB) Trending Tab (ExploreFlow) - TRENDING_FEED - EXPLORE_SEARCH - Dedicated BrowserFlow screen -- Allows trending page to use existing browser (no custom browser), and retains trending navigation back behaviour (search queries and navigation stack is retained) ``` ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: refactor: modify trending/explore page navigation stacks ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** https://www.loom.com/share/bb1343b7a7ed4b1abb841f8c6d1284f3 ## **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** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Refactors Explore/Trending to use the main Browser flow (with a hidden Browser tab), adds `TRENDING_FEED`, and enhances TabBar to support custom selection/hidden states, updating routes and tests accordingly. > > - **Navigation / Explore-Trending**: > - Replace custom Trending browser with existing `BrowserFlow`; remove `BrowserWrapper` and related screens. > - Introduce `ExploreHome` stack with `Routes.TRENDING_FEED`, `Routes.EXPLORE_SEARCH`, `Routes.SITES_FULL_VIEW`, and nested `Routes.BROWSER.HOME`. > - Keep `Routes.BROWSER.HOME` as a hidden tab when trending is enabled; Trending tab considers both `TRENDING_VIEW` and `BROWSER.HOME` as selected. > - Update `BrowserTab` back behavior to return to `TRENDING_VIEW -> TRENDING_FEED` when not launched from Trending. > - Add `Routes.TRENDING_FEED`. > - **TabBar**: > - Add `options.isSelected(rootScreenName)` and `options.isHidden` to `ExtendedBottomTabDescriptor`. > - Change Trending tab press to `navigation.reset({ routes: [{ name: Routes.TRENDING_VIEW }] })`. > - **Sites/Explore interactions**: > - `SiteRowItemWrapper` and `SitesSearchFooter` now navigate to `Routes.BROWSER.HOME` with `screen: Routes.BROWSER.VIEW` and `{ fromTrending: true, newTabUrl, timestamp }`. > - **Tests / Snapshots**: > - Update unit tests and snapshots for new navigation targets and removal of deprecated screens (`TrendingBrowser`, `BrowserWrapper`). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit ec05612. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 6f907f4 commit 87b4499

File tree

14 files changed

+193
-260
lines changed

14 files changed

+193
-260
lines changed

app/component-library/components/Navigation/TabBar/TabBar.test.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,10 @@ describe('TabBar', () => {
222222
);
223223

224224
fireEvent.press(getByTestId(`tab-bar-item-${TabBarIconKey.Trending}`));
225-
expect(navigation.navigate).toHaveBeenCalledWith(Routes.TRENDING_VIEW);
225+
expect(navigation.reset).toHaveBeenCalledWith({
226+
index: 0,
227+
routes: [{ name: Routes.TRENDING_VIEW }],
228+
});
226229
});
227230

228231
it('does not navigate to trending when trending feature flag is disabled', () => {

app/component-library/components/Navigation/TabBar/TabBar.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ const TabBar = ({ state, descriptors, navigation }: TabBarProps) => {
4747
const callback = options.callback;
4848
const rootScreenName = options.rootScreenName;
4949
const key = `tab-bar-item-${tabBarIconKey}`; // this key is also used to identify elements for e2e testing
50-
const isSelected = state.index === index;
50+
const isSelected = options?.isSelected
51+
? options.isSelected(state.routeNames[state.index])
52+
: state.index === index;
5153
const icon = ICON_BY_TAB_BAR_ICON_KEY[tabBarIconKey];
5254
const labelKey = LABEL_BY_TAB_BAR_ICON_KEY[tabBarIconKey];
5355
const labelText = labelKey ? strings(labelKey) : '';
@@ -93,7 +95,10 @@ const TabBar = ({ state, descriptors, navigation }: TabBarProps) => {
9395
break;
9496
case Routes.TRENDING_VIEW:
9597
if (isAssetsTrendingTokensEnabled) {
96-
navigation.navigate(Routes.TRENDING_VIEW);
98+
navigation.reset({
99+
index: 0,
100+
routes: [{ name: Routes.TRENDING_VIEW }],
101+
});
97102
}
98103
break;
99104
}
@@ -102,6 +107,10 @@ const TabBar = ({ state, descriptors, navigation }: TabBarProps) => {
102107
const isWalletAction =
103108
rootScreenName === Routes.MODAL.TRADE_WALLET_ACTIONS;
104109

110+
if (options?.isHidden) {
111+
return null;
112+
}
113+
105114
return (
106115
<View key={key} style={tw.style('flex-1 w-full')}>
107116
<TabBarItem

app/component-library/components/Navigation/TabBar/TabBar.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ export interface ExtendedBottomTabDescriptor extends BottomTabDescriptor {
3737
tabBarIconKey: TabBarIconKey;
3838
callback: () => void;
3939
rootScreenName: string;
40+
isSelected?: (rootScreenName: string) => boolean;
41+
isHidden?: boolean;
4042
};
4143
}
4244

app/components/Nav/Main/MainNavigator.js

Lines changed: 90 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ import { Confirm as RedesignedConfirm } from '../../Views/confirmations/componen
5151
import ContactForm from '../../Views/Settings/Contacts/ContactForm';
5252
import ActivityView from '../../Views/ActivityView';
5353
import RewardsNavigator from '../../UI/Rewards/RewardsNavigator';
54-
import TrendingView from '../../Views/TrendingView/TrendingView';
54+
import { ExploreFeed } from '../../Views/TrendingView/TrendingView';
55+
import ExploreSearchScreen from '../../Views/TrendingView/ExploreSearchScreen/ExploreSearchScreen';
5556
import SwapsAmountView from '../../UI/Swaps';
5657
import SwapsQuotesView from '../../UI/Swaps/QuotesView';
5758
import CollectiblesDetails from '../../UI/CollectibleModal';
@@ -133,7 +134,6 @@ import {
133134
} from '../../Views/AddAsset/AddAsset.constants';
134135
import { strings } from '../../../../locales/i18n';
135136
import SitesFullView from '../../Views/SitesFullView/SitesFullView';
136-
import BrowserWrapper from '../../Views/TrendingView/components/BrowserWrapper/BrowserWrapper';
137137
import BridgeView from '../../UI/Bridge/Views/BridgeView';
138138

139139
const Stack = createStackNavigator();
@@ -278,25 +278,6 @@ const RewardsHome = () => (
278278
</Stack.Navigator>
279279
);
280280

281-
// Persist the last trending screen across unmounts
282-
export const lastTrendingScreenRef = { current: 'TrendingFeed' };
283-
284-
// Callback to update the last trending screen (outside component to persist)
285-
export const updateLastTrendingScreen = (screenName) => {
286-
// eslint-disable-next-line react-compiler/react-compiler
287-
lastTrendingScreenRef.current = screenName;
288-
};
289-
290-
const TrendingHome = () => (
291-
<Stack.Navigator mode="modal" screenOptions={clearStackNavigatorOptions}>
292-
<Stack.Screen
293-
name={Routes.TRENDING_VIEW}
294-
component={TrendingView}
295-
options={{ headerShown: false }}
296-
/>
297-
</Stack.Navigator>
298-
);
299-
300281
/* eslint-disable react/prop-types */
301282
const BrowserFlow = (props) => (
302283
<Stack.Navigator
@@ -324,6 +305,63 @@ const BrowserFlow = (props) => (
324305
</Stack.Navigator>
325306
);
326307

308+
const ExploreHome = () => (
309+
<Stack.Navigator initialRouteName={Routes.TRENDING_FEED} mode="modal">
310+
<Stack.Screen
311+
name={Routes.TRENDING_FEED}
312+
component={ExploreFeed}
313+
options={{ headerShown: false }}
314+
/>
315+
<Stack.Screen
316+
name={Routes.EXPLORE_SEARCH}
317+
component={ExploreSearchScreen}
318+
options={{
319+
headerShown: false,
320+
animationEnabled: true,
321+
cardStyleInterpolator: ({ current, layouts }) => ({
322+
cardStyle: {
323+
transform: [
324+
{
325+
translateX: current.progress.interpolate({
326+
inputRange: [0, 1],
327+
outputRange: [layouts.screen.width, 0],
328+
}),
329+
},
330+
],
331+
},
332+
}),
333+
}}
334+
/>
335+
<Stack.Screen
336+
name={Routes.SITES_FULL_VIEW}
337+
component={SitesFullView}
338+
options={{
339+
headerShown: false,
340+
animationEnabled: true,
341+
cardStyleInterpolator: ({ current, layouts }) => ({
342+
cardStyle: {
343+
transform: [
344+
{
345+
translateX: current.progress.interpolate({
346+
inputRange: [0, 1],
347+
outputRange: [layouts.screen.width, 0],
348+
}),
349+
},
350+
],
351+
},
352+
}),
353+
}}
354+
/>
355+
356+
{/* Trending Browser Stack (uses existing browser flow) */}
357+
<Stack.Screen
358+
name={Routes.BROWSER.HOME}
359+
component={BrowserFlow}
360+
options={{ headerShown: false }}
361+
/>
362+
</Stack.Navigator>
363+
);
364+
327365
///: BEGIN:ONLY_INCLUDE_IF(external-snaps)
328366
const SnapsSettingsStack = () => (
329367
<Stack.Navigator>
@@ -642,10 +680,12 @@ const HomeTabs = () => {
642680
}
643681

644682
// Hide tab bar when browser is in fullscreen mode
645-
if (
646-
isBrowserFullscreen &&
647-
currentRoute.name?.startsWith(Routes.BROWSER.HOME)
648-
) {
683+
const currentStackRouteName =
684+
currentRoute?.state?.routes?.[currentRoute?.state?.index]?.name;
685+
const isInBrowser =
686+
currentRoute.name?.startsWith(Routes.BROWSER.HOME) ||
687+
currentStackRouteName?.startsWith(Routes.BROWSER.HOME);
688+
if (isBrowserFullscreen && isInBrowser) {
649689
return null;
650690
}
651691

@@ -669,21 +709,33 @@ const HomeTabs = () => {
669709
component={WalletTabModalFlow}
670710
/>
671711
{isAssetsTrendingTokensEnabled ? (
672-
<Tab.Screen
673-
name={Routes.TRENDING_VIEW}
674-
options={options.trending}
675-
component={TrendingHome}
676-
layout={({ children }) => UnmountOnBlurComponent(children)}
677-
/>
712+
<>
713+
<Tab.Screen
714+
name={Routes.TRENDING_VIEW}
715+
options={{
716+
...options.trending,
717+
isSelected: (rootScreenName) =>
718+
[Routes.TRENDING_VIEW, Routes.BROWSER.HOME].includes(
719+
rootScreenName,
720+
),
721+
}}
722+
component={ExploreHome}
723+
layout={({ children }) => UnmountOnBlurComponent(children)}
724+
/>
725+
<Tab.Screen
726+
name={Routes.BROWSER.HOME}
727+
options={{
728+
...options.browser,
729+
isHidden: true,
730+
}}
731+
component={BrowserFlow}
732+
layout={({ children }) => <UnmountOnBlur>{children}</UnmountOnBlur>}
733+
/>
734+
</>
678735
) : (
679736
<Tab.Screen
680737
name={Routes.BROWSER.HOME}
681-
options={{
682-
...options.browser,
683-
tabBarButton: isAssetsTrendingTokensEnabled
684-
? () => null
685-
: undefined,
686-
}}
738+
options={options.browser}
687739
component={BrowserFlow}
688740
layout={({ children }) => <UnmountOnBlur>{children}</UnmountOnBlur>}
689741
/>
@@ -950,26 +1002,6 @@ const MainNavigator = () => {
9501002
}}
9511003
/>
9521004
<Stack.Screen name="Home" component={HomeTabs} />
953-
<Stack.Screen
954-
name="TrendingBrowser"
955-
component={BrowserWrapper}
956-
options={{
957-
headerShown: false,
958-
animationEnabled: true,
959-
cardStyleInterpolator: ({ current, layouts }) => ({
960-
cardStyle: {
961-
transform: [
962-
{
963-
translateX: current.progress.interpolate({
964-
inputRange: [0, 1],
965-
outputRange: [layouts.screen.width, 0],
966-
}),
967-
},
968-
],
969-
},
970-
}),
971-
}}
972-
/>
9731005
<Stack.Screen
9741006
name={Routes.WALLET.TOKENS_FULL_VIEW}
9751007
component={TokensFullView}
@@ -1033,25 +1065,7 @@ const MainNavigator = () => {
10331065
}),
10341066
}}
10351067
/>
1036-
<Stack.Screen
1037-
name={Routes.SITES_FULL_VIEW}
1038-
component={SitesFullView}
1039-
options={{
1040-
animationEnabled: true,
1041-
cardStyleInterpolator: ({ current, layouts }) => ({
1042-
cardStyle: {
1043-
transform: [
1044-
{
1045-
translateX: current.progress.interpolate({
1046-
inputRange: [0, 1],
1047-
outputRange: [layouts.screen.width, 0],
1048-
}),
1049-
},
1050-
],
1051-
},
1052-
}),
1053-
}}
1054-
/>
1068+
10551069
<Stack.Screen name="Webview" component={Webview} />
10561070
<Stack.Screen name="SendView" component={SendView} />
10571071
<Stack.Screen

app/components/Nav/Main/__snapshots__/MainNavigator.test.tsx.snap

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,6 @@ exports[`MainNavigator matches rendered snapshot 1`] = `
3838
component={[Function]}
3939
name="Home"
4040
/>
41-
<Screen
42-
component={[Function]}
43-
name="TrendingBrowser"
44-
options={
45-
{
46-
"animationEnabled": true,
47-
"cardStyleInterpolator": [Function],
48-
"headerShown": false,
49-
}
50-
}
51-
/>
5241
<Screen
5342
component={[Function]}
5443
name="TokensFullView"
@@ -97,16 +86,6 @@ exports[`MainNavigator matches rendered snapshot 1`] = `
9786
}
9887
}
9988
/>
100-
<Screen
101-
component={[Function]}
102-
name="SitesFullView"
103-
options={
104-
{
105-
"animationEnabled": true,
106-
"cardStyleInterpolator": [Function],
107-
}
108-
}
109-
/>
11089
<Screen
11190
component={[Function]}
11291
name="Webview"

0 commit comments

Comments
 (0)