Make NativeInputState.tabId non-null#8556
Conversation
| private fun updateToggleVisibilityForState() { | ||
| if (isDuckAiPageContext()) return | ||
| applyToggleVisibility(nativeInputState.toggleVisible) | ||
| applyToggleVisibility(nativeInputState?.toggleVisible ?: false) |
There was a problem hiding this comment.
We are scattering the default fallbacks inline whenever we read a state variable. Would be harder to maintain if we add more call sites or if we do future modifications. I think a cleaner approach would be to have one default state. Something like val DEFAULT_STATE = NativeInputState(SEARCH_ONLY, BROWSER, TOP, tabId = “") (or similar) and use its values as fallbacks wherever needed.
Not blocking for this PR but would be good to have while it’s fresh.
| override fun getInputState(): NativeInputState = | ||
| activeTabId?.let { nativeInputStateProvider.stateForTab(it).value } ?: nativeInputState | ||
| activeTabId?.let { nativeInputStateProvider.stateForTab(it).value } | ||
| ?: error("getInputState called before widget was configured") |
There was a problem hiding this comment.
If we’re throwing in the case where the state is not configured, do we need to have any nullable state? it could be non nullable and that will save us a lot of :? checks. right?
YoussefKeyrouz
left a comment
There was a problem hiding this comment.
Tested, I didn’t see any regression. Left a few comments, none of them are blocking but good to have.
7d57719 to
a86e916
Compare
Drop the String? = null default on NativeInputState.tabId and on NativeInputState.zero(). Every NativeInputState in the per-tab store is now provably associated with a tabId at the type level. ViewModel state flow now combines activeTabId.filterNotNull() so the emitted NativeInputState carries the active tabId. The publish init block simplifies to a direct collect-and-publish — the separate combine that re-attached the tabId is gone. The widget's local cache becomes nullable (NativeInputState?). Read sites use null-safe access with the same defaults the previous field initializer carried. getInputState() throws if called pre-configure instead of returning a placeholder; the publish-on-configure invariant ensures plugins only reach this after configure. ViewModel tests call configure() in @before so the state flow has a tabId; the back-buttons test passes an explicit tabId. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ba04601 to
1803308
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 1803308. Configure here.
1803308 to
96d5ee1
Compare

Task/Issue URL: https://app.asana.com/1/137249556945/project/1214157224317277/task/1214802223978853?focus=true
Stacked on #8550. Until that merges, the diff here shows PR 2's commits too; review the top commit (
7d57719) for the PR 2.5 change in isolation.Description
Small follow-up to PR 2. Now that the widget publishes on configure, every
NativeInputStatein the per-tab store is provably associated with atabId, so we tighten the type.String? = nulldefault onNativeInputState.tabIdandNativeInputState.zero().stateflow combinesactiveTabId.filterNotNull()so the emitted state carries the active tabId. The publish init block simplifies to a direct collect-and-publish — the separate combine that re-attached the tabId is gone.NativeInputState?). Read sites use null-safe access with the same defaults the previous field initializer carried.getInputState()throws if called pre-configure instead of returning a stale placeholder; the publish-on-configure invariant ensures plugins only reach it after configure.@Beforecallsconfigure()so the state flow has a tabId; the back-buttons test passes an explicit tabId.Steps to test this PR
Native input widget regressions
UI changes
No UI changes — refactor only.
Note
Medium Risk
Tightens a core UI/state model contract and changes initialization/placeholder behavior; mis-ordered widget configuration could now throw or suppress UI updates until
tabIdis set.Overview
Makes
NativeInputState.tabIdmandatory by removing the nullable/default value and updatingzero(tabId)accordingly.Updates
NativeInputModeWidgetViewModelto only emitstateonceactiveTabIdis non-null (viaactiveTabId.filterNotNull()), embedding thetabIdin every emittedNativeInputStateand simplifying publishing to a direct collect-and-publish.Adjusts
NativeInputModeWidgetto treat its cachedNativeInputStateas nullable (null-safe reads with safe defaults) and makesgetInputState()fail fast if called beforeconfigure(). Tests are updated to pass explicittabId/callconfigure()up front.Reviewed by Cursor Bugbot for commit 96d5ee1. Bugbot is set up for automated code reviews on this repo. Configure here.