@@ -163,16 +163,19 @@ fun GlobalSearchScreen(
163 val showResultsWhileSearching = state.searching && state.hasSearched && state.results.isNotEmpty()
163 val showResultsWhileSearching = state.searching && state.hasSearched && state.results.isNotEmpty()
164 // Crossfade between content states so transitions read as a smooth fade instead
164 // Crossfade between content states so transitions read as a smooth fade instead
165 // of an instant snap. Matches the session list's Crossfade pattern; reduced
165 // of an instant snap. Matches the session list's Crossfade pattern; reduced
166− // motion is honored by Crossfade's default spec.
166+ // motion is honored by Crossfade's default spec. The content lambda branches
167+ // on its target-state parameter (not the captured `state`) so the outgoing
168+ // layer keeps rendering the OLD state type while it fades out — reading `state`
169+ // directly would recompose both layers to the latest content and defeat the
170+ // crossfade into an instant snap.
167 val stateKey = globalSearchStateKey(state)
171 val stateKey = globalSearchStateKey(state)
168− @Suppress("UnusedCrossfadeTargetStateParameter")
169 Crossfade(
172 Crossfade(
170 targetState = stateKey,
173 targetState = stateKey,
171 animationSpec = tween(soy.iko.opencode.data.network.NetworkConfig.motionFadeDurationMs.toInt()),
174 animationSpec = tween(soy.iko.opencode.data.network.NetworkConfig.motionFadeDurationMs.toInt()),
172 label = "global_search_state",
175 label = "global_search_state",
174− when {
177+ when (key) {
175− state.searching && !showResultsWhileSearching -> Column(
178+ "searching" -> Column(
176 modifier = Modifier.align(Alignment.Center),
179 modifier = Modifier.align(Alignment.Center),
177 horizontalAlignment = Alignment.CenterHorizontally,
180 horizontalAlignment = Alignment.CenterHorizontally,
@@ -189,14 +192,14 @@ fun GlobalSearchScreen(
192− state.error != null -> EmptyState(
195+ "error" -> EmptyState(
193 icon = Icons.Filled.ErrorOutline,
196 icon = Icons.Filled.ErrorOutline,
194 title = state.error ?: "",
197 title = state.error ?: "",
195 modifier = Modifier.align(Alignment.Center),
198 modifier = Modifier.align(Alignment.Center),
196 actionLabel = stringResource(R.string.retry),
199 actionLabel = stringResource(R.string.retry),
197 onAction = vm::retry,
200 onAction = vm::retry,
199− state.hasSearched && state.results.isEmpty() -> EmptyState(
202+ "no_matches" -> EmptyState(
200 icon = Icons.Filled.SearchOff,
203 icon = Icons.Filled.SearchOff,
201 title = stringResource(R.string.search_no_matches),
204 title = stringResource(R.string.search_no_matches),
202 modifier = Modifier.align(Alignment.Center),
205 modifier = Modifier.align(Alignment.Center),
@@ -204,14 +207,14 @@ fun GlobalSearchScreen(
204 // Typed something but below the min length (no search run yet): nudge to keep
207 // Typed something but below the min length (no search run yet): nudge to keep
205 // typing rather than reverting to the untouched start state, which reads as if
208 // typing rather than reverting to the untouched start state, which reads as if
206 // the field were empty.
209 // the field were empty.
207− state.query.isNotBlank() && !state.hasSearched -> EmptyState(
210+ "keep_typing" -> EmptyState(
208 icon = Icons.Filled.Search,
211 icon = Icons.Filled.Search,
209 title = stringResource(R.string.search_keep_typing),
212 title = stringResource(R.string.search_keep_typing),
210 modifier = Modifier.align(Alignment.Center),
213 modifier = Modifier.align(Alignment.Center),
212 // Empty query + persisted history: surface suggestions so a returning user can
215 // Empty query + persisted history: surface suggestions so a returning user can
213 // re-run a prior search in one tap instead of retyping it.
216 // re-run a prior search in one tap instead of retyping it.
214− state.query.isBlank() && state.history.isNotEmpty() -> HistorySuggestions(
217+ "history" -> HistorySuggestions(
215 history = state.history,
218 history = state.history,
216 onPick = { query ->
219 onPick = { query ->
217 vm.setQuery(query)
220 vm.setQuery(query)
@@ -220,7 +223,7 @@ fun GlobalSearchScreen(
220 onClear = vm::clearHistory,
223 onClear = vm::clearHistory,
221 modifier = Modifier.fillMaxSize(),
224 modifier = Modifier.fillMaxSize(),
223− state.results.isEmpty() -> EmptyState(
226+ "start" -> EmptyState(
224 icon = Icons.Filled.Search,
227 icon = Icons.Filled.Search,
225 title = stringResource(R.string.search_all_start),
228 title = stringResource(R.string.search_all_start),
226 description = stringResource(R.string.search_all_start_hint),
229 description = stringResource(R.string.search_all_start_hint),