Skip to content

Refine Duck.ai chat history screen and gate it via suspend flag#8531

Open
GerardPaligot wants to merge 7 commits into
developfrom
feature/gerard/chat-history-native-screen
Open

Refine Duck.ai chat history screen and gate it via suspend flag#8531
GerardPaligot wants to merge 7 commits into
developfrom
feature/gerard/chat-history-native-screen

Conversation

@GerardPaligot
Copy link
Copy Markdown
Contributor

@GerardPaligot GerardPaligot commented May 12, 2026

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

Description

Ships the native Duck.ai chat history screen, reachable from the browser menu on the New Tab Page and on website tabs (gated by the layered duckAiChatHistory feature flags). The screen lists past Duck.ai conversations partitioned into Pinned and Recent sections, sorted most-recent-first; tapping a row opens Duck.ai with that conversation already loaded via the ?chatID=<id> URL parameter.

Steps to test this PR

Note

Prerequisites:

  • Install Internal Debug.
  • Open Settings → Developer Settings → Feature Flags → duckAiChatHistory and confirm self, historyScreen are ON.
  • Native storage enabled for chat data: confirm useNativeStorageChatData is ON under duckChat in the feature flags.

Menu entry visibility

  • Open the app to the New Tab Page → tap the browser menu → confirm the "Chats" entry is visible.
  • Load any website (e.g. https://duckduckgo.com) → open the browser menu → confirm the "Chats" entry is visible.
  • Open Duck.ai → open the browser menu → confirm the "Chats" entry is visible.
  • Open custom tab → confirm the entry does NOT appear in those menu surfaces.

Empty state

  • Fire all existing Chats if there are chats in your app
  • Tap the "Chats" menu entry → confirm the empty state shows the Duck.ai hero illustration, a title, and a single "Open Duck.ai" CTA.
  • Tap the CTA → confirm Duck.ai opens.

Loaded list and row tap

  • Open Duck.ai and create at least 3 chats; pin one or two from Duck.ai side panel.
  • Open the chat history screen → confirm Pinned section appears above Recent.
  • Tap any chat row → confirm Duck.ai opens with that specific conversation.
  • Change pinned chats from Duck.ai and confirm the chat history screen reflects the changes on refresh.

UI changes

Screen_recording_20260512_152511.mp4

Note

Medium Risk
Adds a new Duck.ai chat history Activity/Fragment surface backed by reactive native storage flows and new navigation commands; while gated by feature flags, it touches browser menu/intent tab switching and DuckChat API/feature toggles.

Overview
Adds a new native Duck.ai chat history screen (ChatHistoryActivity/ChatHistoryFragment) that lists stored chats (Pinned/Recent) and opens Duck.ai with a selected conversation via a chatID URL parameter.

Wires a new browser menu entry (“Chats”) on NTP and regular tabs, controlled by a new BrowserViewState/BrowserMenuViewState flag and a new Command.LaunchDuckChatHistory, with fallback to the existing sidebar action when history isn’t available.

Extends DuckChat with suspend-gated isChatHistoryAvailable() and adds reactive chat retrieval (DuckAiChatStore.getChatsFlow() + Room DAO Flow), plus small Duck.ai intent handling tweaks to reuse an existing Duck.ai tab when resuming a session. Includes new resources, icons, manifest registration, and unit tests for gating/repository/viewmodel behavior.

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

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Comment thread app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt
Comment thread app/src/main/java/com/duckduckgo/app/browser/menu/BrowserMenuViewStateFactory.kt Outdated
In full-screen mode every OPEN_DUCK_CHAT intent previously spawned a
new browser tab regardless of whether a Duck.ai tab was already open,
which made entry points like chat-history row taps pile up duplicate
Duck.ai tabs. When the intent carries an active session flag we now
look for an existing Duck.ai tab via isDuckChatUrl, switch to it, and
submit the target URL; the pager-selection flow is awaited first so
currentTab resolves to the right fragment before navigation. No Duck.ai
tab or a cold session falls back to the original new-tab path.
The browser-menu entry and the screen toolbar previously read "Duck.ai
Chats"; the shorter "Chats" label aligns with the Figma design and
removes redundancy when the screen launches from inside the Duck.ai
context. A new browserMenuChats string in browser-ui's donottranslate
keeps the entry consistent across locales until translation lands, and
the empty-state title becomes "No Chats yet" to match. The per-row
3-dot popup also gains a Delete entry (still mocked to the "Coming
soon" snackbar) so Phase 3 can wire the real action against an
already-final popup shape.
Fixes the DenyListedApi lint failure flagged by the in-house lint rule
on Flow.first: the safer firstOrNull variant returns null if the flow
ever completes without emitting, where first would throw. The behaviour
is equivalent for selectedTabFlow (a hot StateFlow-derived stream that
never completes in practice), and the downstream call already null-checks
currentTab so a null tabId result is benign.
DuckChat no longer exposes openDuckChatHistory; the screen is launched
through a new DuckChatHistoryNoParams entry in :duckchat-api annotated
on ChatHistoryActivity with @ContributeToActivityStarter. This matches
the pattern already used by DuckChatSettingsNoParams and decouples the
caller from the concrete Activity class — :app can navigate to the
screen without a facade method on the Duck.ai interface, and the
impl no longer hard-references ChatHistoryActivity. BrowserTabViewModel
keeps the available-vs-sidebar decision (and its two tests) by emitting
a new LaunchDuckChatHistory command that BrowserTabFragment translates
into the GlobalActivityStarter call.
Co-locating historyScreen and deleteFromAutocomplete with the rest of
the aiChat flags lets RealDuckChat depend on a single feature interface
and drops the redundant DuckAiChatHistoryFeature.self() gate from
isChatHistoryAvailable(). DuckAiChatHistoryFeature stays for the
input-screen suggestion settings consumed via getSettings().
The chat-history visibility decision now flows entirely through
BrowserViewState, so the factory no longer needs to query DuckChat
directly. Removing the field shrinks its Dagger graph and keeps the
factory focused on translating view state into menu state.
@GerardPaligot GerardPaligot force-pushed the feature/gerard/chat-history-native-screen branch from f320a85 to fff886e Compare May 12, 2026 15:19
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

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 1 potential issue.

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 fff886e. Configure here.

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.

1 participant