Skip to content

Fire Mode: Empty state pages#8748

Merged
0nko merged 7 commits into
developfrom
feature/ondrej/fire-mode-empty-pages
Jun 16, 2026
Merged

Fire Mode: Empty state pages#8748
0nko merged 7 commits into
developfrom
feature/ondrej/fire-mode-empty-pages

Conversation

@0nko

@0nko 0nko commented Jun 2, 2026

Copy link
Copy Markdown
Member

Task/Issue URL: https://app.asana.com/1/137249556945/project/1207418217763355/task/1215327489156969?focus=true

Figma: Tab switcher
Figma: Browser

Description

This PR adds Fire mode empty state for Fire tabs in the browser and the Tab switcher.

Steps to test this PR

  • Enable the Fire tabs FF in the dev settings (and restart the app)
  • Go to the Tab switcher
  • Switch to Fire mode
  • Verify the new empty state screen is displayed (compare with Figma design)
  • Tap on the New Fire tab button
  • Verify a new Fire tab is opened
  • Verify the new empty tab screen is displayed instead of Dax (compare with Figma design)
  • Go back to the Tab switcher
  • Close all Fire tabs using the X button
  • After the last Fire tab is closed, verify that the app automatically changes modes to Regular
Tab switch Browser
image image

Note

Medium Risk
Changes tab close and mode-switch behavior for Fire mode and tab auto-creation edge cases, but scope is limited to Fire mode with new unit tests covering the main paths.

Overview
Adds Fire mode empty states on the tab switcher and Fire new-tab page, replacing the normal Dax/NTP chrome when Fire mode is active.

In the tab switcher, when Fire mode has zero tabs, a dedicated empty state (feature bullets, explainer, New Fire Tab) is shown instead of the tab grid; New Fire Tab opens a tab via the existing new-tab flow. Mode-switch fade skips animating a hidden recycler so toggling modes from the empty state still recreates cleanly.

On the Fire new tab page, Fire mode shows a simpler empty state and hides logo, messages, favourites, and related NTP sections.

Closing the last or all Fire tabs now emits SwitchToRegularMode (activity recreates in Regular mode) instead of the close-all undo snackbar path used for regular tabs.

DefaultTabManager stops auto-adding a default tab when the Fire tab list is empty but global browser mode is already Regular, avoiding a stray tab during mode transitions. Tab switcher loading uses a TabItems loaded vs not-initialized distinction so the Fire empty state only appears after tabs have loaded, not during initial load.

New layouts, strings, and design-system icons support the UI.

Reviewed by Cursor Bugbot for commit e04a96c. Bugbot is set up for automated code reviews on this repo. Configure here.

0nko commented Jun 2, 2026

Copy link
Copy Markdown
Member Author

Comment thread app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt
@0nko 0nko force-pushed the feature/ondrej/fire-mode-empty-pages branch from 870da07 to 226d9ae Compare June 5, 2026 20:13
@0nko 0nko force-pushed the feature/ondrej/fire-mode-new-tabs branch from 96a48e5 to 04a7fae Compare June 5, 2026 20:13
Comment thread app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt Outdated
@0nko 0nko force-pushed the feature/ondrej/fire-mode-empty-pages branch from 226d9ae to 45c0a40 Compare June 9, 2026 13:58
@0nko 0nko force-pushed the feature/ondrej/fire-mode-new-tabs branch from 04a7fae to 0bf23a7 Compare June 9, 2026 13:58
@0nko 0nko force-pushed the feature/ondrej/fire-mode-empty-pages branch from 45c0a40 to 8682bf8 Compare June 11, 2026 09:29
@0nko 0nko changed the base branch from feature/ondrej/fire-mode-new-tabs to graphite-base/8748 June 11, 2026 09:29
@0nko 0nko force-pushed the feature/ondrej/fire-mode-empty-pages branch from 8682bf8 to d07ed9e Compare June 12, 2026 19:14
@0nko 0nko force-pushed the graphite-base/8748 branch from 0bf23a7 to 428c983 Compare June 12, 2026 19:14
@0nko 0nko changed the base branch from graphite-base/8748 to feature/ondrej/fire-mode-new-tabs June 12, 2026 19:15
@0nko 0nko force-pushed the feature/ondrej/fire-mode-empty-pages branch from d07ed9e to be483ff Compare June 12, 2026 19:45
@0nko 0nko force-pushed the feature/ondrej/fire-mode-new-tabs branch from 12f2280 to 407bc24 Compare June 12, 2026 19:45

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit be483ff. Configure here.

Comment thread app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt
Base automatically changed from feature/ondrej/fire-mode-new-tabs to develop June 13, 2026 07:17
@0nko 0nko force-pushed the feature/ondrej/fire-mode-empty-pages branch 2 times, most recently from 0d9f439 to ca1e3b1 Compare June 15, 2026 10:11
@LukasPaczos LukasPaczos self-assigned this Jun 15, 2026
0nko and others added 3 commits June 15, 2026 22:14
In the Fire tabs empty state the recycler is hidden and empty, so the
mode-switch fade-out animates nothing and only adds a pointless delay
before recreate. Switch mode and recreate immediately when the recycler
isn't visible; the recreated activity still fades the new mode's tabs in.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The single-tab close path already drops the user back to Regular mode
when the last Fire tab is closed, but the bulk "Close all tabs" path
(onCloseTabsConfirmed) still emitted CloseAndShowUndoMessage in Fire
mode, leaving the user in Fire mode with no tabs. Mirror the single-tab
behaviour: when all tabs are being closed in Fire mode, mark them
deletable and emit SwitchToRegularMode (no undo), keeping the switcher
open. Non-Fire close-all is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-empty-pages branch from ca1e3b1 to 93afbfe Compare June 15, 2026 20:15

@LukasPaczos LukasPaczos left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i repeatably click the mode switcher, it eventually freezes. Not sure if this is a regression from this PR, or whether it's a preexisting issue. If the latter, are we tracking it already? If not, could you create a follow up?

Screen_recording_20260616_101116.mp4


if (viewState.showFireTabEmptyState) {
binding.fireTabEmptyState.root.show()
binding.indonesiaNewTabSectionView.gone()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is hidden but there's no other code path that would show this view again. Can that cause any issues?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good catch but it doesn't cause a problem today because showFireTabEmptyState is derived from isFireMode, which is fixed when the ViewModel is constructed and never changes, and the NTP view is fully recreated on mode switch. But I've made the hide reversible by showing both views in the non-fire path.

tabRepository.markDeletable(tabIds)
command.value = Command.CloseAndShowUndoMessage(tabIds)

if (fireModeAvailable && currentMode.value == BrowserMode.FIRE) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're already in currentMode.value == BrowserMode.FIRE, checking fireModeAvailable seems unnecessary, or even dangerous. If the user is in fire mode, but in parallel the fireModeAvailable changes to false, they might get stuck.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fire mode availability is checked and cached on app startup so it can never change mid-run and the default mode on startup is always regular mode. I guess the fireModeAvailable is redundant here so I can remove it if you want but I don't think it changes anything.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see 👍 This just looked like a code smell to me - since it's behind the interface, the view model shouldn't need to know that it's evaluated only once. Either way, I'll let you make the call on next steps.

viewModelScope.launch {
if (tabs.size == 1) {
val isLastTab = tabs.size == 1
if (isLastTab && fireModeAvailable && currentMode.value == BrowserMode.FIRE) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above ref. fire mode availability.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my answer above.

@0nko

0nko commented Jun 16, 2026

Copy link
Copy Markdown
Member Author

Thanks @LukasPaczos!

If i repeatably click the mode switcher, it eventually freezes. Not sure if this is a regression from this PR, or whether it's a preexisting issue. If the latter, are we tracking it already? If not, could you create a follow up?

The only thing I've experienced before was an occasional lag when changing the modes. I've never seen a complete freeze like you did here. This is not related to this PR so I'll follow up with it in another task.

@0nko 0nko merged commit 9c1017e into develop Jun 16, 2026
16 checks passed
@0nko 0nko deleted the feature/ondrej/fire-mode-empty-pages branch June 16, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants