Skip to content

fix(search): drop idle placeholder on Explore → Search with prefilled query#4290

Merged
realmeylisdev merged 2 commits into
mainfrom
fix/3802-search-intermediate-state
May 21, 2026
Merged

fix(search): drop idle placeholder on Explore → Search with prefilled query#4290
realmeylisdev merged 2 commits into
mainfrom
fix/3802-search-intermediate-state

Conversation

@realmeylisdev
Copy link
Copy Markdown
Contributor

@realmeylisdev realmeylisdev commented May 12, 2026

Summary

Tapping into Explore's search bar and typing 2+ characters auto-pushes /search-results/:query after a 300ms debounce. The destination then flashed "Enter a search query / Discover something interesting" for another ~300–600ms before BLoCs were dispatched and section skeletons appeared. On slow networks the window stretched, reading as a flash, error, or hang. This PR makes the destination drop the idle placeholder when a route arg query is pending, and dispatch *QueryChanged events synchronously on AppBar mount so the BLoCs advance from initial this same frame.

Closes #3802. Companion to parent epic #3801.

Root cause

SearchResultsView keyed the idle short-circuit on VideoSearchBloc.state.status == initial alone. That signal correctly identifies "no query entered" (the load-bearing PR #3199 fix for #3023's infinite skeleton) but does NOT distinguish it from "query just arrived as a route arg, AppBar dispatch is still pending its 300ms UI debounce."

Changes

All 5 entry points to SearchResultsPage go through SearchResultsPage(initialQuery: query) (Explore auto-push, @mention link tap, universal link, deep link, GoRoute), so this fix applies uniformly.

Commit history

  1. 1f99c2b6 — initial fix.
  2. 2407333d — self-review follow-up: tighten the view's idle gate from isEmpty to trim().length < minSearchQueryLength so reachable edge cases (whitespace-only or 1-char deep links like /search-results/a and /search-results/%20%20) don't render infinite skeletons (a fix: skeleton loader shown indefinitely for empty search query #3023-class regression in the corner). Two extra regression tests pin the corrected behavior.

Scope clarification

Per the issue body: "Do not collapse this issue into keyboard/focus behavior. They are related, but not identical." This PR is scoped to the intermediate-state symptom only. The focus and keyboard work belongs to:

The parent epic #3801 calls for these three children to land as one cohesive transition PR (Gate 2). I scoped this PR to #3802 alone; bundling is the epic driver's call.

Test plan

  • flutter test test/screens/search_results/85 passing
  • flutter test test/blocs/{video,user,hashtag,list}_search test/blocs/search_results_filter119 passing
  • flutter test test/screens/explore_screen_pure_test.dart → 12 passing
  • flutter analyze lib test integration_test → no issues
  • dart format → clean

New test coverage:

  • search_results_view_test.dart — new with non-empty initialQuery group asserts SearchSectionInitialState does NOT render when initialQuery is non-empty + status is initial, and that the all-filter section list renders instead. Plus two regression tests pinning the whitespace-only and sub-min-length cases to the idle placeholder (cures the fix: skeleton loader shown indefinitely for empty search query #3023-class edge case).
  • search_results_app_bar_test.dart — adds missing _MockListSearchBloc mock (the existing setUp had a gap), plus three new tests: synchronous dispatch on non-empty initialQuery, NO dispatch on empty initialQuery, and no double-dispatch after the 300ms debounce window elapses.
  • Existing idle-state tests preserved verbatim — PR fix(search): replace empty-query skeleton with initial-state placeholder #3199's load-bearing behavior is unchanged for the empty-query path.

Manual device testing guide

What changed (one-paragraph context for QA)

When you typed 2+ characters in Explore's search bar and the app auto-pushed to /search-results/:query, you saw a brief "Enter a search query / Discover something interesting" placeholder for ~300–600ms before search results loaded — especially noticeable on slow networks. After this fix, the destination shows section skeletons immediately and lands on real results once they arrive. The empty-query case (opening the search screen directly) still shows the "Enter a search query" placeholder as before.

Build

Pick one:

  • Preview web build (fastest, no local setup): open the Mobile PR Preview link from this PR's checks. The bot posts a https://<hash>.openvine-app.pages.dev URL on every push.
  • Local install on the device:
    git fetch origin
    git checkout fix/3802-search-intermediate-state
    cd mobile
    flutter pub get
    flutter run --release   # release matters — debug mode is slower and masks the symptom
  • TestFlight / internal build if one is cut later — pull the build tagged with this PR's SHA.

Notes:

  • The bug is more visible in release than debug (debug is slow anyway, so any flash is harder to attribute).
  • The bug is most visible on slow networks. Throttle to "Slow 3G" via iOS Settings → Developer → Network Link Conditioner (or Android Developer Options → Networking → Network type → "GPRS"), or use a proxy throttle.

Golden path — primary repro from issue #3802

  1. Launch the app. Sign in if needed.
  2. Tap the Explore bottom-nav tab.
  3. Tap the search bar at the top of Explore.
  4. Type hello (or any 2+ character query). Stop typing and wait.
  5. After ~300ms the app navigates to the search results screen.

What to look for (frame-by-frame):

Frame Before this fix (broken) After this fix (correct)
Navigation completes Screen renders with a centered search icon + "Enter a search query" + "Discover something interesting" Screen renders with shimmer skeletons for People / Lists / Tags / Videos sections
~300–600ms later Skeletons appear (the placeholder fades) (same skeletons continue, no flash transition)
Results arrive Real results render Real results render
  • Pass criteria: at no point during the transition does the "Enter a search query" copy appear.
  • Fail signal: if you see "Enter a search query" or "Discover something interesting" even briefly, the fix didn't apply.

Tip: if you can't catch it visually, screen-record at 60 fps and step through frames.

Slow-network case — the issue's "feels like a hang" complaint

Same steps as Golden path, but throttle to Slow 3G first.

  • Pass: skeletons hold for as long as the network needs, then results land. No misleading "Enter a query" text. No fallback to an error state until/unless results genuinely fail.
  • Fail: the "Enter a search query" copy appears, OR the screen looks empty/blank for any period.

Direct entry to /search-results (regression check for #3023 — DO NOT skip)

This is the load-bearing case from PR #3199. This must still work the OLD way.

Two ways to trigger:

A. Universal/deep link with empty query — open the app from a divine.video/search-results/ link (no query) if you can construct one, OR

B. In the running app: Explore → tap search bar → land on /search-results/ with no query in the field.

Edge cases — sub-min-length & whitespace-only query (the F1 finding addressed in commit 2)

Reachable via deep / universal links — try if you can construct them, otherwise skip:

  1. Open divine.video/search-results/a (single character) — or build a URL pointing at /search-results/a and open it from another app.
  2. Open divine.video/search-results/%20%20%20 (whitespace-only, URL-encoded).
  • Pass for both: idle placeholder "Enter a search query" renders. (BLoCs gate on length >= 2 so sub-min queries never reach the network; the view correctly treats them as idle.)
  • Fail: shimmer skeletons render indefinitely.

Other entry paths — same expected behavior

These all converge through SearchResultsPage(initialQuery: ...) so they should all behave consistently:

  1. Tap an @username mention in a comment (links via linkified_text) — should land on search with the username pre-filled, no misleading placeholder.
  2. Open the app from a universal link https://divine.video/search-results/<query> — same.
  3. Open from a push-notification deep link with a search term — same.
  • Pass: skeletons + results. No "Enter a search query" flash.

Focus / keyboard — explicitly NOT in scope here

This fix does NOT change focus or keyboard behavior. Those are tracked separately in:

For #3802 QA: don't flag keyboard or focus issues against this PR. The destination field will not auto-focus when navigated with a pre-filled query — that's the existing behavior and intentionally untouched.

Filters & deep search — confirm nothing else regressed

  1. Land on /search-results/hello (golden path).
  2. Tap the filter pill (top-right). Switch between All / People / Videos / Tags / Lists.
  • Pass: each filter renders its skeletons → results. No "Enter a search query" appears on any filter tab even before results arrive.
  • Fail: any filter renders the empty-query placeholder.

Empty results — make sure we don't show idle instead of empty

  1. Search a query with truly no results (e.g. random keyboard mash like xqzqzqzq).
  2. Wait for results to settle (~1–5 seconds).
  • Pass: each section shows its appropriate empty-state ("No results found for X" / "Try a different search term"). Not "Enter a search query."
  • Fail: the idle placeholder shows after BLoCs have completed.

Error/timeout (people search) — confirm degraded-empty UI

Same as above on a flaky network. If NIP-50 user search times out:

Sign-off checklist

[ ] Golden path: type `hello` in Explore, no "Enter a search query" flash
[ ] Slow-3G repro: same, with throttle on
[ ] Direct-entry (empty query): "Enter a search query" placeholder DOES render
[ ] Sub-min-length deep link `/search-results/a`: idle placeholder renders
[ ] Whitespace-only deep link `/search-results/%20%20`: idle placeholder renders
[ ] @mention tap → search: skeletons not placeholder
[ ] Universal link with query: skeletons not placeholder
[ ] Filter switch: each filter shows skeletons until results, never placeholder
[ ] Empty result (mash query): empty-state not placeholder
[ ] People-timeout: retry UI not placeholder
[ ] Devices: iOS + Android, recent + min-supported OS

If any row fails, file a comment on this PR with the device, OS, network condition, and a screen recording.

Notes for reviewers

  • The doc comment over the isIdle conditional in search_results_view.dart is intentional — tests-guard-intentional-workarounds precedent. Don't simplify it back to isInitialStatus alone or fix: skeleton loader shown indefinitely for empty search query #3023 reopens.
  • The idle gate uses initialQuery.trim().length < minSearchQueryLength rather than isEmpty so it mirrors the BLoC handlers' own gate exactly. The looser isEmpty form regressed reachable edge cases in commit 1; commit 2 tightened it.
  • Parent epic epic(search): stabilize search UX, routing, focus, result quality, and technical debt #3801 Gate 1 (auto-push vs explicit submit) is owned by Product / Design and unresolved. This fix is safe under either outcome: if Gate 1 keeps auto-push, the misleading state is fixed; if Gate 1 removes auto-push from Explore, the universal-link / deep-link / @mention-link entry paths still benefit from this fix.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Member

@NotThatKindOfDrLiz NotThatKindOfDrLiz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior fix looks right and the added tests cover the edge cases well, but this should be tightened before merge to avoid carrying new maintenance debt into main.

Comment thread mobile/lib/screens/search_results/widgets/search_results_app_bar.dart Outdated
Comment thread mobile/lib/screens/search_results/widgets/search_results_app_bar.dart Outdated
Comment thread mobile/lib/screens/search_results/view/search_results_view.dart Outdated
@realmeylisdev realmeylisdev force-pushed the fix/3802-search-intermediate-state branch from 2407333 to 6baff0a Compare May 13, 2026 00:46
realmeylisdev added a commit that referenced this pull request May 13, 2026
Address review feedback on PR #4290:
- Extract the 4-way *QueryChanged fanout in SearchResultsAppBar into a
  private `_dispatchQuery` helper, reused by both the synchronous
  initState path and the debounced _onSearchChanged callback. Removes
  the pre-existing duplication this PR was about to cement.
- Rewrite the synchronous-dispatch comment to drop two inaccurate
  claims: BLoCs do not leave `initial` this frame (each applies its
  own internal debounce), and same-query dedup is not generally true
  (UserSearchBloc explicitly has no such guard).
- Trim the long narrative comment in SearchResultsView's idle gate to
  short intent only; issue-history references belong in the PR body,
  not in code.

No behavior change. All 85 search_results widget tests still pass.
@github-actions

This comment has been minimized.

@realmeylisdev realmeylisdev force-pushed the fix/3802-search-intermediate-state branch from 6baff0a to d0ab03b Compare May 13, 2026 09:46
realmeylisdev added a commit that referenced this pull request May 13, 2026
Address review feedback on PR #4290:
- Extract the 4-way *QueryChanged fanout in SearchResultsAppBar into a
  private `_dispatchQuery` helper, reused by both the synchronous
  initState path and the debounced _onSearchChanged callback. Removes
  the pre-existing duplication this PR was about to cement.
- Rewrite the synchronous-dispatch comment to drop two inaccurate
  claims: BLoCs do not leave `initial` this frame (each applies its
  own internal debounce), and same-query dedup is not generally true
  (UserSearchBloc explicitly has no such guard).
- Trim the long narrative comment in SearchResultsView's idle gate to
  short intent only; issue-history references belong in the PR body,
  not in code.

No behavior change. All 85 search_results widget tests still pass.
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Member

@rabble rabble left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran the focused local check with coverage mode:

  • flutter test --coverage test/screens/search_results/view/search_results_page_test.dart test/screens/search_results/view/search_results_view_test.dart test/screens/search_results/widgets/search_results_app_bar_test.dart

It passes locally. I’m still requesting changes because the fix couples idle rendering to the immutable route initialQuery, which leaves a real post-navigation state uncovered.

Blocking issue: SearchResultsView decides idle state from initialQuery instead of the current query/BLoC input state:

  • mobile/lib/screens/search_results/view/search_results_view.dart:25 checks whether VideoSearchBloc is still initial
  • mobile/lib/screens/search_results/view/search_results_view.dart:33 then combines that with initialQuery.trim().length < minSearchQueryLength

That handles the initial Explore -> Search case, but after landing on /search-results/hello, if the user clears the field or edits it down to one character, the search BLoCs can go back to initial while initialQuery remains hello. isIdle stays false, so the view falls through to the section skeletons instead of showing the idle placeholder. The current tests cover initial route values, not changing the query after navigation.

Please drive isIdle from the current query/search input state, or otherwise keep SearchResultsView synchronized with the app bar’s current text, and add a regression test for clearing/reducing a prefilled query below minSearchQueryLength after the page has mounted.

realmeylisdev added a commit that referenced this pull request May 17, 2026
… query

Tapping into Explore and typing 2+ characters auto-pushes
/search-results/:query, but the destination flashed "Enter a search
query / Discover something interesting" for ~300-600ms before
section skeletons appeared. On slow networks this read as a hang.

Hoist the search field's TextEditingController into a stateful
_SearchResultsBody so both the app bar (writer) and the view
(reader) operate on the same live text. The view drives its idle
gate from the live controller value rather than the route arg, so
the gate also returns to the placeholder when the user clears or
shortens the field below minSearchQueryLength after landing on a
prefilled route (rabble's PR #4290 review feedback) — the BLoCs
reset to `initial` in that case, and the old gate keyed on the
immutable initialQuery would have re-introduced the #3023
"infinite skeleton" symptom in the post-mount edit path.

The app bar still dispatches *QueryChanged synchronously on
mount for non-empty prefilled queries to skip the UI debounce
(#3802 root cause). The same-query dedup guard inside each
BLoC handler coalesces any late-arriving listener event; the
listener is attached after the synchronous dispatch so the
parent's pre-seeded controller text doesn't bounce through and
double-fire.

Closes #3802. Companion to parent epic #3801.

Test plan:
- search_results_view_test: new "field-edit transitions after
  mounting with a prefilled query" group adds three regression
  tests for rabble's case — a static empty-text+initial-state
  assertion, a static sub-min-length+initial-state assertion, and
  a live whenListen transition that flips from sections to idle
  when the user clears the field and the BLoC resets. Existing
  idle-state and filter-routing tests preserved; "with non-empty
  initialQuery" group renamed to "with non-empty search field
  text" and rewired to seed the controller directly.
- search_results_app_bar_test: helper now constructs an external
  TextEditingController and passes it in (mirroring the page).
  Keeps main's three focus-contract tests and adds three
  dispatch tests (sync dispatch on non-empty initialQuery, no
  dispatch on empty initialQuery, no double-dispatch after the
  debounce window).
@realmeylisdev realmeylisdev force-pushed the fix/3802-search-intermediate-state branch from d0ab03b to b3f304f Compare May 17, 2026 10:18
@realmeylisdev
Copy link
Copy Markdown
Contributor Author

@rabble — addressed in b3f304f (force-pushed after a rebase onto fresh origin/main).

Please drive isIdle from the current query/search input state, or otherwise keep SearchResultsView synchronized with the app bar's current text, and add a regression test for clearing/reducing a prefilled query below minSearchQueryLength after the page has mounted.

Hoisted the TextEditingController out of SearchResultsAppBar into a stateful _SearchResultsBody inside SearchResultsPage. Both children now operate on the same instance — the app bar writes to it (and attaches its listener), and SearchResultsView reads it via ValueListenableBuilder<TextEditingValue>. The view's isIdle gate is now:

final isIdle =
    isInitialStatus && text.trim().length < minSearchQueryLength;

…where text is the live controller.text rather than the immutable route arg. So after landing on /search-results/hello, clearing or shortening the field below minSearchQueryLength returns the BLoCs to initial AND the gate evaluates to true against the live text, flipping the view back to the placeholder.

Regression tests live in search_results_view_test.dart under the new group field-edit transitions after mounting with a prefilled query:

  • shows idle placeholder when the cleared field meets a reset BLoC — static controller.text == '' && status == initial assertion.
  • shows idle placeholder when a sub-min-length field meets a reset BLoC — static controller.text == 'h' && status == initial assertion.
  • flips from sections to idle when text is cleared and the BLoC resets — live whenListen transition: starts at (controller='hello', status=success), runs controller.clear() + emits const VideoSearchState(), asserts SearchSectionInitialState then renders. This pins the exact race you described.

Side effects of the hoist:

  • The companion focus-contract work from fix(search): define explore search focus contract #4413 lands cleanly — requestFocusOnMount plumbing on SearchResultsPage / _SearchResultsBody / SearchResultsAppBar is unchanged in surface.
  • SearchResultsView lost its initialQuery constructor param entirely; it now requires controller.
  • App bar tests pass an external controller through the helper; main's three focus-contract tests + my three sync-dispatch tests both kept.

Local: flutter analyze lib test integration_test clean; flutter test test/screens/search_results/ 91/91 green; flutter test test/blocs/{video,user,hashtag,list}_search test/blocs/search_results_filter 119/119 green. Waiting for CI before re-requesting review.

@github-actions

This comment has been minimized.

@realmeylisdev realmeylisdev requested a review from rabble May 17, 2026 10:25
Copy link
Copy Markdown
Member

@rabble rabble left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

Important: mobile/lib/screens/search_results/widgets/search_results_app_bar.dart:87 adds a new 300ms UI timer before dispatching user edits, but all four destination search BLoCs already debounce *QueryChanged by searchDebounceDuration / debounceRestartable (mobile/lib/constants/search_constants.dart:8, plus the on<*QueryChanged> handlers). That doubles the delay for normal typing and clearing inside the search results screen. In particular, clearing or reducing a prefilled query below minSearchQueryLength can leave stale sections/results visible for roughly 600ms before the BLoCs reset to initial. The previous app bar dispatched controller changes immediately and let the BLoCs own debounce; this PR should keep that model and only avoid firing the pre-seeded controller text twice.

Minor: mobile/lib/screens/search_results/widgets/search_results_app_bar.dart:57 still has an inaccurate comment. Dispatching in initState does not make the BLoCs “leave initial this frame” because the BLoC transformers still debounce the event, and the same-query dedup note is not true for all four blocs (UserSearchBloc explicitly has no same-query skip).

Verification: reviewed current PR head b3f304fc4; ran flutter test test/screens/search_results/view/search_results_view_test.dart test/screens/search_results/widgets/search_results_app_bar_test.dart from mobile/ and all 23 tests passed.

… query

Tapping into Explore and typing 2+ characters auto-pushes
/search-results/:query, but the destination flashed "Enter a search
query / Discover something interesting" for ~300-600ms before
section skeletons appeared. On slow networks this read as a hang.

Hoist the search field's TextEditingController into a stateful
_SearchResultsBody so both the app bar (writer) and the view
(reader) operate on the same live text. The view drives its idle
gate from the live controller value rather than the route arg, so
the gate also returns to the placeholder when the user clears or
shortens the field below minSearchQueryLength after landing on a
prefilled route (rabble's PR #4290 review feedback) — the BLoCs
reset to `initial` in that case, and the old gate keyed on the
immutable initialQuery would have re-introduced the #3023
"infinite skeleton" symptom in the post-mount edit path.

The app bar still dispatches *QueryChanged synchronously on
mount for non-empty prefilled queries to skip the UI debounce
(#3802 root cause). The same-query dedup guard inside each
BLoC handler coalesces any late-arriving listener event; the
listener is attached after the synchronous dispatch so the
parent's pre-seeded controller text doesn't bounce through and
double-fire.

Closes #3802. Companion to parent epic #3801.

Test plan:
- search_results_view_test: new "field-edit transitions after
  mounting with a prefilled query" group adds three regression
  tests for rabble's case — a static empty-text+initial-state
  assertion, a static sub-min-length+initial-state assertion, and
  a live whenListen transition that flips from sections to idle
  when the user clears the field and the BLoC resets. Existing
  idle-state and filter-routing tests preserved; "with non-empty
  initialQuery" group renamed to "with non-empty search field
  text" and rewired to seed the controller directly.
- search_results_app_bar_test: helper now constructs an external
  TextEditingController and passes it in (mirroring the page).
  Keeps main's three focus-contract tests and adds three
  dispatch tests (sync dispatch on non-empty initialQuery, no
  dispatch on empty initialQuery, no double-dispatch after the
  debounce window).
The PR head added a 300ms UI debounce on top of each search BLoC's
existing `debounceRestartable` (also 300ms), doubling user-perceived
latency on typing and clearing — most visibly leaving stale sections
visible for ~600ms after clearing a prefilled query. Restore the
pre-PR immediate-dispatch model so the BLoCs own the only debounce.

Also rewrites the load-bearing initState comment, which incorrectly
claimed the BLoCs "leave initial this frame" (debounceRestartable
queues the event behind a 300ms timer) and cited a same-query dedup
guard that UserSearchBloc explicitly does not have. Adds a
_lastDispatchedQuery guard so the TextField's EditableText-driven
selection updates don't fire duplicate *QueryChanged events.

Addresses review #4306847831.
@realmeylisdev realmeylisdev force-pushed the fix/3802-search-intermediate-state branch from b3f304f to 41dbd28 Compare May 18, 2026 02:45
@realmeylisdev
Copy link
Copy Markdown
Contributor Author

@rabble — addressed both findings from your review (#4290 (review)) in 41dbd28.

Important: mobile/lib/screens/search_results/widgets/search_results_app_bar.dart:87 adds a new 300ms UI timer before dispatching user edits, but all four destination search BLoCs already debounce *QueryChanged by searchDebounceDuration / debounceRestartable … In particular, clearing or reducing a prefilled query below minSearchQueryLength can leave stale sections/results visible for roughly 600ms before the BLoCs reset to initial.

Dropped the Timer? _debounce field entirely. _onSearchChanged now dispatches immediately, restoring the pre-PR model where each BLoC's own debounceRestartable(300ms) is the only debounce in the pipeline. Added a _lastDispatchedQuery text-equality guard so that selection-only updates the TextField's EditableText emits on attach/focus don't fire duplicate *QueryChanged events. New regression tests pin the immediate-dispatch behavior for both typing and clearing a prefilled query.

Minor: mobile/lib/screens/search_results/widgets/search_results_app_bar.dart:57 still has an inaccurate comment. Dispatching in initState does not make the BLoCs "leave initial this frame" because the BLoC transformers still debounce the event, and the same-query dedup note is not true for all four blocs (UserSearchBloc explicitly has no same-query skip).

Rewrote the comment. The new version explains that the synchronous dispatch is needed because the listener is attached after the parent seeds the controller (so the listener never sees the initial value), and that it starts each BLoC's 300ms debounceRestartable clock at mount time rather than 300ms later. It explicitly disclaims the "leave initial this frame" framing and points at SearchResultsView's controller.text-driven idle gate as the actual suppressor of the misleading placeholder symptom. Same-query dedup claim removed.

Verification (from mobile/):

  • flutter test test/screens/search_results/ → 93 passing (was 85 + new regression tests).
  • flutter analyze lib test integration_test → no issues.

@github-actions
Copy link
Copy Markdown

Mobile PR Preview

Preview refreshed for 41dbd28

Last refresh: 41dbd28 at 2026-05-18 02:49:33 UTC (preview run)

Property Value
Preview URL https://c2a86270.openvine-app.pages.dev
Pages project openvine-app
Preview branch pr-4290
PR branch fix/3802-search-intermediate-state
Commit 41dbd28

Copy link
Copy Markdown
Member

@NotThatKindOfDrLiz NotThatKindOfDrLiz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed current head 41dbd28. The live-controller idle gate fix and removal of the extra UI debounce address the earlier blocking issues, and the added regression coverage covers the post-mount clear/sub-min-length paths. Focused local verification and current PR checks are green.

@realmeylisdev
Copy link
Copy Markdown
Contributor Author

@rabble this is ready for another look

Copy link
Copy Markdown
Member

@rabble rabble left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed current head 41dbd28. The live-controller idle gate addresses the post-mount clear/sub-min-length path, the extra UI debounce is gone, prior threads are resolved/outdated, CI is green, and local Resolving dependencies...
Downloading packages...
_fe_analyzer_shared 91.0.0 (100.0.0 available)
_flutterfire_internals 1.3.66 (1.3.71 available)
alchemist 0.12.1 (0.14.0 available)
analyzer 8.4.0 (13.0.0 available)
analyzer_buffer 0.1.11 (0.3.2 available)
analyzer_plugin 0.13.10 (0.14.9 available)
! app_device_integrity 1.1.0 from path overrides/app_device_integrity-1.1.0 (overridden)
app_links 6.4.1 (7.0.0 available)
archive 4.0.7 (4.0.9 available)
async 2.13.0 (2.13.1 available)
audio_session 0.2.2 (0.2.3 available)
bip340 0.3.0 (0.3.1 available)
bloc 9.2.0 (9.2.1 available)
build 4.0.3 (4.0.6 available)
build_config 1.2.0 (1.3.0 available)
build_runner 2.10.5 (2.15.0 available)
built_value 8.12.1 (8.12.6 available)
cli_launcher 0.3.2+1 (0.3.3+1 available)
cli_util 0.4.2 (0.5.1 available)
code_assets 1.0.0 (1.1.0 available)
code_builder 4.11.0 (4.11.1 available)
connectivity_plus 7.0.0 (7.1.1 available)
connectivity_plus_platform_interface 2.0.1 (2.1.0 available)
cookie_jar 4.0.8 (4.0.9 available)
cross_file 0.3.5+1 (0.3.5+2 available)
! cryptography_flutter 2.3.2 from path overrides/cryptography_flutter-2.3.2 (overridden)
cupertino_icons 1.0.8 (1.0.9 available)
custom_lint_core 0.8.1 (0.8.2 available)
custom_lint_visitor 1.0.0+8.4.0 (1.0.0+9.0.0 available)
dart_style 3.1.3 (3.1.9 available)
dev_build 1.1.3+1 (1.1.7+1 available)
! device_info_plus 10.1.2 (overridden) (13.1.0 available)
device_info_plus_platform_interface 7.0.3 (8.1.0 available)
dio 5.9.0 (5.9.2 available)
dio_cookie_manager 3.3.0 (3.4.0 available)
dio_web_adapter 2.1.1 (2.1.2 available)
drift 2.31.0 (2.33.0 available)
drift_dev 2.31.0 (2.33.0 available)
drift_flutter 0.2.8 (0.3.0 available)
ffi 2.1.5 (2.2.0 available)
file_picker 10.3.8 (11.0.2 available)
file_selector_android 0.5.2+4 (0.5.2+6 available)
firebase_analytics 12.1.2 (12.4.1 available)
firebase_analytics_platform_interface 5.0.6 (6.0.1 available)
firebase_analytics_web 0.6.1+2 (0.6.1+7 available)
firebase_core 4.4.0 (4.9.0 available)
firebase_core_platform_interface 6.0.2 (7.0.1 available)
firebase_core_web 3.4.0 (3.7.0 available)
firebase_crashlytics 5.0.7 (5.2.2 available)
firebase_crashlytics_platform_interface 3.8.17 (3.8.22 available)
firebase_messaging 16.1.1 (16.2.2 available)
firebase_messaging_platform_interface 4.7.6 (4.7.11 available)
firebase_messaging_web 4.1.2 (4.1.7 available)
firebase_performance 0.11.1+4 (0.11.4+1 available)
firebase_performance_platform_interface 0.1.6+4 (0.2.0+1 available)
firebase_performance_web 0.1.8+2 (0.1.8+7 available)
flutter_local_notifications 19.5.0 (21.0.0 available)
flutter_local_notifications_linux 6.0.0 (8.0.0 available)
flutter_local_notifications_platform_interface 9.1.0 (11.0.0 available)
flutter_local_notifications_windows 1.0.3 (3.0.0 available)
flutter_plugin_android_lifecycle 2.0.33 (2.0.34 available)
flutter_riverpod 3.0.3 (3.3.1 available)
flutter_secure_storage 9.2.4 (10.2.0 available)
flutter_secure_storage_linux 1.2.3 (3.0.0 available)
flutter_secure_storage_macos 3.1.3 (4.0.0 available)
flutter_secure_storage_platform_interface 1.1.2 (2.0.1 available)
flutter_secure_storage_web 1.2.1 (2.1.1 available)
flutter_secure_storage_windows 3.1.2 (4.2.1 available)
flutter_svg 2.2.3 (2.3.0 available)
flutter_web_auth_2 4.1.0 (5.0.2 available)
flutter_web_auth_2_platform_interface 4.1.0 (5.0.0 available)
freezed 3.2.3 (3.2.5 available)
go_router 16.3.0 (17.2.3 available)
golden_toolkit 0.15.0 (discontinued)
google_fonts 6.3.3 (8.1.0 available)
gtk 2.1.0 (2.2.0 available)
hive_ce 2.16.0 (2.19.3 available)
hive_ce_flutter 2.3.3 (2.3.4 available)
hive_ce_generator 1.10.0 (1.11.2 available)
hooks 1.0.3 (2.0.0 available)
image 4.7.2 (4.8.0 available)
image_picker 1.2.1 (1.2.2 available)
image_picker_android 0.8.13+10 (0.8.13+17 available)
image_picker_ios 0.8.13+3 (0.8.13+6 available)
isolate_channel 0.2.2+1 (0.6.1 available)
jni 0.15.2 (1.0.0 available)
js 0.6.7 (0.7.2 available)
json_annotation 4.9.0 (4.12.0 available)
json_serializable 6.11.2 (6.14.0 available)
lints 6.0.0 (6.1.0 available)
matcher 0.12.19 (0.12.20 available)
melos 7.3.0 (7.7.0 available)
! meta 1.17.0 (overridden) (1.18.2 available)
mockito 5.6.4 (5.7.0 available)
mocktail 1.0.4 (1.0.5 available)
mustache_template 2.0.2 (2.0.4 available)
native_toolchain_c 0.17.6 (0.19.0 available)
package_info_plus 9.0.0 (10.1.0 available)
package_info_plus_platform_interface 3.2.1 (4.1.0 available)
path_provider_android 2.2.22 (2.3.1 available)
path_provider_foundation 2.5.1 (2.6.0 available)
patrol 4.2.0 (4.5.0 available)
patrol_finders 3.1.0 (3.4.0 available)
patrol_log 0.7.1 (0.9.0 available)
petitparser 7.0.1 (7.0.2 available)
pointycastle 3.9.1 (4.0.0 available)
posix 6.0.3 (6.5.0 available)
postgres 3.5.9 (3.5.11 available)
pro_video_editor 1.16.2 (1.16.3 available)
process_run 1.2.4 (1.3.3+1 available)
qr 3.0.2 (4.0.0 available)
riverpod 3.0.3 (3.2.1 available)
riverpod_analyzer_utils 1.0.0-dev.7 (1.0.0-dev.10 available)
riverpod_annotation 3.0.3 (4.0.2 available)
riverpod_generator 3.0.3 (4.0.3 available)
! rxdart 0.28.0 (overridden)
share_plus 12.0.1 (13.1.0 available)
share_plus_platform_interface 6.1.0 (7.1.0 available)
shared_preferences 2.5.4 (2.5.5 available)
shared_preferences_android 2.4.18 (2.4.23 available)
shared_preferences_platform_interface 2.4.1 (2.4.2 available)
shelf_web_socket 2.0.1 (3.0.0 available)
skeletonizer 2.1.2 (2.1.3 available)
source_gen 4.1.1 (4.2.3 available)
source_helper 1.3.8 (1.3.12 available)
source_span 1.10.1 (1.10.2 available)
sqflite 2.4.2 (2.4.2+1 available)
sqflite_android 2.4.2+2 (2.4.2+3 available)
sqflite_common 2.5.6 (2.5.8 available)
sqflite_common_ffi 2.3.6 (2.4.0+3 available)
sqflite_common_ffi_web 0.4.5+4 (1.1.1 available)
sqlite3 2.9.4 (3.3.1 available)
sqlite3_flutter_libs 0.5.41 (0.6.0+eol available)
sqlparser 0.43.1 (0.44.4 available)
synchronized 3.4.0 (3.4.0+1 available)
test 1.30.0 (1.31.1 available)
test_api 0.7.10 (0.7.12 available)
test_core 0.6.16 (0.6.18 available)
timezone 0.10.1 (0.11.0 available)
unique_names_generator 3.0.0 (3.1.2 available)
url_launcher_android 6.3.28 (6.3.30 available)
url_launcher_ios 6.3.6 (6.4.1 available)
url_launcher_web 2.4.1 (2.4.3 available)
uuid 4.5.2 (4.5.3 available)
vector_graphics 1.1.19 (1.2.2 available)
vector_graphics_compiler 1.1.19 (1.2.3 available)
vector_math 2.2.0 (2.3.0 available)
video_player 2.10.1 (2.11.1 available)
video_player_android 2.9.1 (2.9.5 available)
video_player_avfoundation 2.8.8 (2.9.7 available)
video_player_platform_interface 6.6.0 (6.7.0 available)
vm_service 15.0.2 (15.2.0 available)
volume_controller 3.4.4 (3.5.0 available)
wakelock_plus 1.5.2 (1.6.1 available)
wakelock_plus_platform_interface 1.5.0 (1.5.1 available)
watcher 1.2.0 (1.2.1 available)
web_socket 0.1.6 (1.0.1 available)
webview_flutter_android 4.10.13 (4.12.0 available)
webview_flutter_platform_interface 2.14.0 (2.15.1 available)
webview_flutter_wkwebview 3.24.1 (3.25.1 available)
win32 5.15.0 (6.2.0 available)
win32_registry 1.1.5 (3.0.3 available)
xml 6.6.1 (7.0.1 available)
yaml_edit 2.2.3 (2.2.4 available)
Got dependencies!
1 package is discontinued.
160 packages have newer versions incompatible with dependency constraints.
Try flutter pub outdated for more information.
00:00 +0: loading /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_view_test.dart
00:00 +0: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_view_test.dart: SearchResultsView renders all sections when filter is all
00:04 +1: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:05 +2: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:05 +3: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:06 +4: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:06 +5: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:06 +6: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:07 +7: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:07 +8: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:07 +9: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:07 +10: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:07 +11: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:08 +12: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:08 +13: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:08 +14: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:08 +15: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:09 +16: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/view/search_results_page_test.dart: SearchResultsPage shows the empty-query idle placeholder in default mode
00:09 +17: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/section_header_test.dart: SectionHeader renders title text
00:09 +18: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/section_header_test.dart: SectionHeader renders title text
00:09 +19: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/section_header_test.dart: SectionHeader renders title text
00:10 +20: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_error_state_test.dart: SearchSectionErrorState renders warning icon
00:11 +21: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_error_state_test.dart: SearchSectionErrorState renders warning icon
00:11 +22: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_error_state_test.dart: SearchSectionErrorState renders warning icon
00:11 +23: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_error_state_test.dart: SearchSectionErrorState renders warning icon
00:12 +24: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_error_state_test.dart: SearchSectionErrorState renders warning icon
00:12 +25: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_error_state_test.dart: SearchSectionErrorState renders warning icon
00:12 +26: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_error_state_test.dart: SearchSectionErrorState renders warning icon
00:13 +27: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_filter_sheet_test.dart: SearchFilterSheet shows all filter options
00:14 +28: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_filter_sheet_test.dart: SearchFilterSheet shows all filter options
00:14 +29: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_filter_sheet_test.dart: SearchFilterSheet shows all filter options
00:14 +30: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_filter_sheet_test.dart: SearchFilterSheet shows all filter options
00:17 +31: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/videos_section_test.dart: VideosSection showAll: false (All tab preview) hides entirely when success with empty results
00:18 +32: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/videos_section_test.dart: VideosSection showAll: false (All tab preview) hides entirely when success with empty results
00:19 +33: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/videos_section_test.dart: VideosSection showAll: false (All tab preview) hides entirely when success with empty results
00:19 +34: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:19 +35: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:20 +36: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:21 +37: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:21 +38: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:22 +39: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:23 +40: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:23 +41: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:23 +42: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:23 +43: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_results_app_bar_test.dart: SearchResultsAppBar renders SearchFilterPill
00:24 +44: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/lists_section_test.dart: ListsSection showAll: false (All tab preview) hides entirely when success with empty results
00:24 +45: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/lists_section_test.dart: ListsSection showAll: false (All tab preview) hides entirely when success with empty results
00:24 +46: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/lists_section_test.dart: ListsSection showAll: false (All tab preview) hides entirely when success with empty results
00:25 +47: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/lists_section_test.dart: ListsSection showAll: false (All tab preview) hides entirely when success with empty results
00:25 +48: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:25 +49: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:26 +50: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:26 +51: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:26 +52: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:27 +53: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:27 +54: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:27 +55: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:27 +56: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:27 +57: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:28 +58: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_section_empty_state_test.dart: SearchSectionEmptyState renders search icon
00:28 +59: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_filter_pill_test.dart: SearchFilterPill renders "All" label when filter is all
00:28 +60: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_filter_pill_test.dart: SearchFilterPill renders "All" label when filter is all
00:28 +61: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_filter_pill_test.dart: SearchFilterPill renders "All" label when filter is all
00:28 +62: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/search_filter_pill_test.dart: SearchFilterPill renders "All" label when filter is all
00:31 +63: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection showAll: false (All tab preview) hides entirely when success with empty results
00:32 +64: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection showAll: false (All tab preview) hides entirely when success with empty results
00:32 +65: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection showAll: false (All tab preview) hides entirely when success with empty results
00:32 +66: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection showAll: false (All tab preview) hides entirely when success with empty results
00:33 +67: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection showAll: false (All tab preview) hides entirely when success with empty results
00:34 +68: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection showAll: false (All tab preview) hides entirely when success with empty results
00:34 +69: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection showAll: false (All tab preview) hides entirely when success with empty results
00:35 +70: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) hides entirely when success with empty results
00:35 +71: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) hides entirely when success with empty results
00:36 +72: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) hides entirely when success with empty results
00:36 +73: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) hides entirely when success with empty results
00:36 +74: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) hides entirely when success with empty results
00:37 +75: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) hides entirely when success with empty results
00:37 +76: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection showAll: true (dedicated tab) renders SearchSectionErrorState on failure
00:37 +77: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) renders header and content when success with results
00:37 +78: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) renders header and content when success with results
00:37 +79: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) renders header and content when success with results
00:37 +80: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) renders header and content when success with results
00:37 +81: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection degraded-empty (#3791) hides section entirely in All tab preview when truly empty
00:37 +82: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) renders SearchSectionErrorState on failure
00:37 +83: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: false (All tab preview) renders SearchSectionErrorState on failure
00:38 +84: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection loading more indicator shows loading indicator when showAll and isLoadingMore
00:38 +85: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: true (dedicated tab) renders SearchSectionEmptyState when success with empty results
00:38 +86: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: true (dedicated tab) renders SearchSectionEmptyState when success with empty results
00:38 +87: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/people_section_test.dart: PeopleSection loading more indicator does not show loading indicator when not showAll
00:38 +88: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection showAll: true (dedicated tab) renders SearchSectionErrorState on failure
00:38 +89: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection retry dispatches HashtagSearchQueryChanged with current query
00:38 +90: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection loading more indicator shows loading indicator when showAll and isLoadingMore
00:38 +91: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection loading more indicator hides loading indicator when showAll and not isLoadingMore
00:38 +92: /Users/rabble/code/divine/divine-mobile/.claude/worktrees/search-video-sort/mobile/test/screens/search_results/widgets/tags_section_test.dart: TagsSection loading more indicator does not show loading indicator when not showAll
00:39 +93: All tests passed! passes.

@realmeylisdev realmeylisdev merged commit 3afb6b9 into main May 21, 2026
10 checks passed
@realmeylisdev realmeylisdev deleted the fix/3802-search-intermediate-state branch May 21, 2026 05:46
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.

search: avoid misleading intermediate state during Explore → Search transition

3 participants