feat(collection): tap a tag chip to filter the Collection to that tag (#414)#424
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a cross-screen “tap a tag → jump to Collection filtered by that tag” interaction by introducing an app-level filter coordinator and wiring tag chips in both dance detail and collection rows to publish filter requests that the shell/list react to.
Changes:
- Introduces
CollectionFilterController/CollectionFilterScopeto broadcast “filter Collection by tag” requests across routes. - Makes tag chips tappable (
ActionChip) on dance detail and (optionally) on list rows, applying the existing tag facet filter. - Adds widget tests covering narrow/wide navigation, clearability, in-place row filtering, and special-character tag names.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| app/test/tag_filter_navigation_test.dart | New widget tests for tag-tap navigation/filtering flows across layouts. |
| app/lib/src/widgets/dance_list_tile.dart | Adds onTagTap and renders tag chips as ActionChip when interactive. |
| app/lib/src/search/dance_detail_data.dart | Adds (id, name) tag pairs to detail data for id-based filtering. |
| app/lib/src/search/collection_data.dart | Adds (id, name) tag pairs to list entries for id-based filtering. |
| app/lib/src/screens/dance_list_screen.dart | Subscribes to filter requests and applies a single-tag facet filter by replacing the current query. |
| app/lib/src/screens/dance_detail_screen.dart | Makes detail tag chips publish filter requests via the new scope (non-preview only). |
| app/lib/src/screens/app_shell.dart | Listens for filter requests to switch to Collection and pop pushed routes so the filtered list is visible. |
| app/lib/src/models/dance_list_entry.dart | Adds (id, name) tag pairs for list-row chip rendering/filtering. |
| app/lib/src/data/collection_filter_scope.dart | New app-level coordinator (controller + inherited scope) for tag filter requests. |
| app/lib/main.dart | Provides CollectionFilterScope above the root navigator via MaterialApp.builder. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…#414) Tapping a tag chip where a user reads a dance's tags (dance detail/summary and Collection list rows) now switches to the Collection list and applies a clean single-tag filter, so callers can quickly find all dances sharing it. - Add CollectionFilterController/CollectionFilterScope (provided above the root Navigator in main.dart, mirroring CollectionRefreshScope) so pushed detail routes can request a filter. - AppShell subscribes and switches to the Collection tab + pops to the list. - DanceListScreen applies REPLACE semantics: clear prior FTS/facets/advanced, then set the tapped tag id on the existing tag facet and re-search. The active filter remains visible (Filters badge + tag facet chip) and clearable. - Make detail-screen and list-row tag chips tappable ActionChips (detail guarded to non-preview; list rows opt in via onTagTap so the Programs dance picker is unaffected). Carry tag ids alongside names in the data classes so filtering matches by id, not display text. Reuses the existing id-based TagFilter facet; no core changes. Tag ids come from the local DB and flow into the parameterized TagFilter; tag names are display-only, so special characters are safe. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…xits online mode _applyExternalTagFilter turns off online mode but an already-awaiting _runOnlineSearch() future could still complete and repopulate _onlineResults/_onlineError. Bump _onlineSeq so the existing seq guard ignores those late responses. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
ibanner56
force-pushed
the
isaacbanner-tap-tag-to-filter-414
branch
from
July 21, 2026 01:19
4ea7011 to
2357d13
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #414.
What
Tapping a tag chip where a user reads a dance's tags — the dance detail/summary screen and Collection list rows — now switches to the Collection list and filters it to that tag, so a caller can quickly find every dance sharing it.
Approach
CollectionFilterController/CollectionFilterScope(app/lib/src/data/collection_filter_scope.dart), provided inmain.dart'sMaterialApp.builderchain — above the root Navigator — mirroring the existingCollectionRefreshScope, so pushed detail routes can reach it.AppShellsubscribes and, on a request, switches to the Collection tab (index 0) and pops to the list root.DanceListScreenapplies the filter through the existingFacetSelections.tagIds/TagFilterfacet — no core changes, no second filtering system.ActionChips: on the detail screen (guarded to non-preview) and on list rows (opt-in viaonTagTap, so the Programs dance picker is unaffected).Replace vs. add — decision: REPLACE
A tap clears prior FTS/facets/advanced filters and applies a clean single-tag filter. Arriving from a detail screen with unknown prior filter state, a predictable "show everything with this tag" result — that the user can then clear — matches the issue intent better than silently AND-ing onto hidden filters. The active filter stays visible (Filters "(N active)" badge + selected tag facet chip) and clearable (Clear filters / untoggle).
Security (OWASP)
No new untrusted-input surface. Tag ids originate from the local DB and flow into the existing parameterized
TagFilter(matched by id, never by text). Tag names are display-only (Text), so a tag name with SQL/regex/emoji/RTL characters is safe — covered by a dedicated test.Tests
New
app/test/tag_filter_navigation_test.dart(6 tests): narrow pushed-detail nav, wide embedded-pane, clearable filter, list-row in-place filter, a tag with zero other dances, and a special-character tag name.Gates
fvm dart format .— cleanfvm flutter analyze(app) — No issues found;fvm dart analyze(core) — No issues foundfvm dart test— 1798 passed (~4 skipped)fvm flutter test— 1651 passedCo-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com