Duck.ai voice mode entry point in input screen#7979
Conversation
...ckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/inputscreen/ui/InputScreenFragment.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Duplicated voice click routing logic in two handlers
- Extracted the duplicated voice-entry routing block into a shared
handleVoiceClick()method and reused it in both voice click handlers.
- Extracted the duplicated voice-entry routing block into a shared
Or push these changes by commenting:
@cursor push 6790996ab1
Preview (6790996ab1)
diff --git a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/inputscreen/ui/InputScreenFragment.kt b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/inputscreen/ui/InputScreenFragment.kt
--- a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/inputscreen/ui/InputScreenFragment.kt
+++ b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/inputscreen/ui/InputScreenFragment.kt
@@ -499,12 +499,7 @@
viewModel.onBrowserMenuTapped()
}
onVoiceClick = {
- val isChatTab = inputModeWidget.isChatTabSelected()
- if (isChatTab && duckChatFeature.duckAiVoiceEntryPoint().isEnabled()) {
- viewModel.onVoiceEntryTapped()
- } else {
- voiceSearchLauncher.launch(requireActivity(), VoiceSearchMode.fromValue(inputModeWidget.getSelectedTabPosition()))
- }
+ handleVoiceClick()
}
onClearTextTapped = {
viewModel.onClearTextTapped()
@@ -583,15 +578,19 @@
pixel.fire(DuckChatPixelName.DUCK_CHAT_EXPERIMENTAL_OMNIBAR_FLOATING_RETURN_PRESSED)
}
inputScreenButtons.onVoiceClick = {
- val isChatTab = inputModeWidget.isChatTabSelected()
- if (isChatTab && duckChatFeature.duckAiVoiceEntryPoint().isEnabled()) {
- viewModel.onVoiceEntryTapped()
- } else {
- voiceSearchLauncher.launch(requireActivity(), VoiceSearchMode.fromValue(inputModeWidget.getSelectedTabPosition()))
- }
+ handleVoiceClick()
}
}
+ private fun handleVoiceClick() {
+ val isChatTab = inputModeWidget.isChatTabSelected()
+ if (isChatTab && duckChatFeature.duckAiVoiceEntryPoint().isEnabled()) {
+ viewModel.onVoiceEntryTapped()
+ } else {
+ voiceSearchLauncher.launch(requireActivity(), VoiceSearchMode.fromValue(inputModeWidget.getSelectedTabPosition()))
+ }
+ }
+
private fun configureLogoAnimation() =
with(binding.ddgLogo) {
setMinAndMaxFrame(0, LOGO_MAX_FRAME)| viewModel.onVoiceEntryTapped() | ||
| } else { | ||
| voiceSearchLauncher.launch(requireActivity(), VoiceSearchMode.fromValue(inputModeWidget.getSelectedTabPosition())) | ||
| } |
There was a problem hiding this comment.
Duplicated voice click routing logic in two handlers
Low Severity
The new voice-entry-point routing logic (check isChatTabSelected(), check feature flag, branch to onVoiceEntryTapped() vs voiceSearchLauncher.launch(...)) is copy-pasted identically in both inputModeWidget.onVoiceClick and inputScreenButtons.onVoiceClick. If the routing logic ever changes (e.g., new conditions or actions), only one handler might get updated, causing inconsistent behavior depending on which voice button the user taps. Extracting this into a shared private method would eliminate the risk.
Please tell me if this was useful or not with a 👍 or 👎.
Additional Locations (1)
Adds a new `duckAiVoiceEntryPoint` feature flag (default: internal) that, when enabled, replaces the system voice recognition button on the duck.ai tab with a direct link to duck.ai/?mode=voice-mode. The search tab keeps its existing voice-to-text behaviour unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use isChatTabSelected() directly instead of falling back on visibilityState.searchMode, which can be stale after a tab switch. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
90da8e0 to
9a97b63
Compare
| override fun openVoiceDuckChat() { | ||
| logcat { "Duck.ai: openVoiceDuckChat" } | ||
| val parameters = mapOf(MODE_QUERY_NAME to VOICE_MODE_QUERY_VALUE) | ||
| openDuckChat(parameters, forceNewSession = true) |
joshliebe
left a comment
There was a problem hiding this comment.
Works well, nice one 🙂
Only missing tests on RealDuckChat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>




Task/Issue URL: https://app.asana.com/1/137249556945/project/1211654189969294/task/1213651299034811
Description
Adds a mic button on the duck.ai tab of the input screen that opens duck.ai directly in voice mode (
duck.ai/?mode=voice-mode), giving users 1-click access to voice chat.duckAiVoiceEntryPointsub-feature flag (DefaultFeatureValue.INTERNAL— off in production, on in internal builds)openVoiceDuckChat()on theDuckChatAPI → implemented inRealDuckChatby appendingmode=voice-modeand forcing a new sessionInputScreenViewModel: extended the voice button visibilitycombineblock to be tab-aware; duck.ai tab + flag on → button followsvoiceInputAllowed(text presence) rather thanVoiceSearchAvailabilityInputScreenFragment: both voice click handlers route toviewModel.onVoiceEntryTapped()on the duck.ai tab when flag is onm_aichat_voice_entry_tappedfired on tapInputScreenViewModelTestSteps to test this PR
Enable flag
duckAiVoiceEntryPointunder duck.ai feature flagsDuck.ai tab — empty field
?mode=voice-modein the URL, fresh sessionDuck.ai tab — with text
Search tab (unchanged)
Flag off
duckAiVoiceEntryPoint→ duck.ai tab mic button behaves as before (follows voice search availability, launches system voice recognition)UI changes
Note
Medium Risk
Changes input-screen voice button behavior behind a new feature flag and adds a new DuckChat navigation path that forces a fresh session; risk is moderate due to UI/flow branching and URL/session handling.
Overview
Adds a new, flag-gated Duck.ai voice entry point on the input screen: when on the Duck.ai tab and
duckAiVoiceEntryPointis enabled, the mic button opens Duck.ai withmode=voice-mode(forcing a new session) instead of launching system voice search.Introduces
DuckChat.openVoiceDuckChat()(implemented inRealDuckChatviamode=voice-modequery param), updates voice button visibility logic inInputScreenViewModelto be tab-aware, and wires both voice click handlers inInputScreenFragmentto the new behavior. Adds new pixels (m_aichat_voice_entry_tapped_*) plus a sharedfireCountAndDailyhelper, and expands unit test coverage for the new routing/visibility/session semantics.Written by Cursor Bugbot for commit 0ed7e9a. This will update automatically on new commits. Configure here.