Commit 0f9c816
Migrate StartChat plugin to NativeInputStateProvider (#8570)
Task/Issue URL:
https://app.asana.com/1/137249556945/project/1174433894299346/task/1214802413219916?focus=true
Stacked on #8556 — base is `feature/david/native_input_tabid_non_null`
until that merges.
### Description
First plugin migration onto the per-tab push model. `StartChatViewModel`
drops `DuckChatInputModeState` and observes the tab's `NativeInputState`
via `NativeInputStateProvider`.
- `NativeInputState` gets a stored `toggleSelection: ToggleSelection`
field (defaults to today's context-derived value via
`NativeInputState.defaultToggleFor`). `toggleSelection` is distinct from
`inputContext`: the context says where the widget lives, the selection
says which tab the user tapped — they can diverge inside a browser
omnibar.
- `NativeInputHost` exposes `val tabId: String`. The widget implements
it from `activeTabId`; reads pre-configure throw, mirroring
`getInputState()`.
- Widget's `configureMainButtonsVisibility` calls
`viewModel.setToggleSelection(...)` on every `onTabSelected` /
`onTabReselected`, before the existing `updatePluginContainerVisibility`
call. `WidgetConfig` carries a nullable `toggleSelection` override;
`configure()` resets it (null = follow context default).
- `StartChatViewModel` injects `NativeInputStateProvider` and exposes
`bindTabId(tabId)`; the combined `isVisible` flow `flatMapLatest`s on
`stateForTab(tabId)` and gates on `toggleSelection == SEARCH`.
- `StartChatView` stashes the host's tabId before attach and forwards it
to the VM from `onAttachedToWindow`; the plugin's `createView` calls
`bindTabId(host.tabId)` alongside the existing `onIconClicked` wiring.
`DuckChatInputModeState` stays in place — still consumed by ambient UI
(NTP background logo). Removal happens once nothing reads it.
`updatePluginContainerVisibility` carries a TODO: it becomes redundant
once every plugin reads `toggleSelection` from
`NativeInputStateProvider` and decides its own visibility.
### Steps to test this PR
_StartChat icon visibility_
- [ ] Enable Duck.ai feature + user setting on; disable input-screen
setting (search omnibar mode). On a website, focus the omnibar —
StartChat icon visible.
- [ ] Same setup, tap the Duck.ai tab in the toggle — icon hides.
- [ ] Tap back to the Search tab — icon reappears.
- [ ] Disable Duck.ai user setting — icon hides regardless of tab.
- [ ] Enable input-screen setting (SEARCH_AND_DUCK_AI mode) — icon
hides.
_Toggle / tab switching across tabs_
- [ ] Open a website on tab A, tap the Duck.ai toggle. Switch to a fresh
tab B in the browser. The widget should reflect tab B's selection
independently from tab A.
### UI changes
No visual change to existing UI; refactor of how the StartChat icon's
visibility is wired.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Moderate risk: refactors how native-input state is derived and
propagated across tabs, which can affect toggle selection, plugin
visibility, and SEARCH_ONLY vs SEARCH_AND_DUCK_AI UI rendering during
tab switches.
>
> **Overview**
> **Native input state is reworked to be active-tab driven.**
`NativeInputState` drops `tabId`, adds a stored `toggleSelection`
(defaulted via `defaultToggleFor`), and `NativeInputStateProvider` now
exposes a `state: Flow<NativeInputState>` that follows the selected
browser tab.
>
> **State propagation and UI syncing are updated.**
`RealNativeInputStateStore` now derives `state` from
`TabRepository.flowSelectedTab` (with a lazy injection to avoid a Dagger
cycle), while `NativeInputModeWidgetViewModel` publishes widget-owned
fields via `publisher.update` and tracks per-tab `toggleSelection`,
resetting it on `configure()`. `NativeInputModeWidget` always observes
`viewModel.state` (avoiding placeholder `zero()` emissions), keeps
`TabLayout` selection synchronized to `toggleSelection`, and only writes
selection back to state when the toggle row is user-visible.
>
> **Plugins are migrated off host state reads.**
`NativeInputHost.getInputState()` is removed; `ModelPickerView` and
`StartChatViewModel` now observe `NativeInputStateProvider.state` to
drive surface/visibility logic, with new tests covering active-tab
emissions and StartChat visibility gating.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
50d8c0d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: David Gonzalez <malmstein@Davids-MacBook-Pro.local>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 5f8b947 commit 0f9c816
12 files changed
Lines changed: 397 additions & 59 deletions
File tree
- duckchat
- duckchat-api/src/main/java/com/duckduckgo/duckchat/api/nativeinput
- duckchat-impl/src
- main/java/com/duckduckgo/duckchat/impl
- nativeinput
- ui
- nativeinput/views
- test/kotlin/com/duckduckgo/duckchat/impl
- nativeinput
- ui
- nativeinput/views
Lines changed: 4 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
| 23 | + | |
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
41 | | - | |
| 40 | + | |
| 41 | + | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
47 | 46 | | |
48 | 47 | | |
49 | 48 | | |
50 | 49 | | |
51 | 50 | | |
52 | | - | |
| 51 | + | |
53 | 52 | | |
54 | 53 | | |
55 | 54 | | |
56 | | - | |
57 | 55 | | |
58 | 56 | | |
59 | 57 | | |
Lines changed: 8 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
23 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
24 | 30 | | |
25 | 31 | | |
26 | 32 | | |
27 | 33 | | |
28 | 34 | | |
| 35 | + | |
29 | 36 | | |
30 | 37 | | |
duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/nativeinput/NativeInputPlugin.kt
Lines changed: 2 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
25 | 24 | | |
26 | 25 | | |
27 | 26 | | |
| |||
31 | 30 | | |
32 | 31 | | |
33 | 32 | | |
34 | | - | |
35 | | - | |
| 33 | + | |
| 34 | + | |
36 | 35 | | |
37 | 36 | | |
38 | 37 | | |
| |||
43 | 42 | | |
44 | 43 | | |
45 | 44 | | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | 45 | | |
50 | 46 | | |
51 | 47 | | |
| |||
Lines changed: 25 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| 25 | + | |
24 | 26 | | |
| 27 | + | |
| 28 | + | |
25 | 29 | | |
26 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
27 | 35 | | |
28 | 36 | | |
29 | 37 | | |
30 | 38 | | |
| 39 | + | |
31 | 40 | | |
32 | 41 | | |
33 | 42 | | |
34 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
35 | 50 | | |
36 | 51 | | |
37 | 52 | | |
38 | 53 | | |
39 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
40 | 63 | | |
41 | 64 | | |
42 | 65 | | |
| |||
59 | 82 | | |
60 | 83 | | |
61 | 84 | | |
62 | | - | |
| 85 | + | |
63 | 86 | | |
Lines changed: 29 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
160 | 160 | | |
161 | 161 | | |
162 | 162 | | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
163 | 167 | | |
164 | 168 | | |
165 | 169 | | |
| |||
172 | 176 | | |
173 | 177 | | |
174 | 178 | | |
175 | | - | |
| 179 | + | |
176 | 180 | | |
177 | 181 | | |
178 | 182 | | |
179 | 183 | | |
180 | | - | |
| 184 | + | |
181 | 185 | | |
182 | 186 | | |
183 | 187 | | |
| |||
186 | 190 | | |
187 | 191 | | |
188 | 192 | | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
189 | 201 | | |
190 | | - | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
191 | 213 | | |
192 | 214 | | |
193 | 215 | | |
| |||
220 | 242 | | |
221 | 243 | | |
222 | 244 | | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
223 | 249 | | |
224 | 250 | | |
225 | 251 | | |
| |||
Lines changed: 20 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
44 | 45 | | |
45 | 46 | | |
46 | 47 | | |
| |||
78 | 79 | | |
79 | 80 | | |
80 | 81 | | |
| 82 | + | |
| 83 | + | |
81 | 84 | | |
82 | 85 | | |
83 | 86 | | |
84 | 87 | | |
85 | 88 | | |
| 89 | + | |
86 | 90 | | |
87 | 91 | | |
88 | 92 | | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
89 | 97 | | |
90 | 98 | | |
91 | 99 | | |
| |||
131 | 139 | | |
132 | 140 | | |
133 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
134 | 151 | | |
135 | 152 | | |
136 | 153 | | |
| |||
165 | 182 | | |
166 | 183 | | |
167 | 184 | | |
168 | | - | |
| 185 | + | |
169 | 186 | | |
170 | 187 | | |
171 | 188 | | |
| |||
230 | 247 | | |
231 | 248 | | |
232 | 249 | | |
| 250 | + | |
| 251 | + | |
233 | 252 | | |
234 | 253 | | |
235 | 254 | | |
| |||
0 commit comments