Skip to content

feat(collection): tap a tag chip to filter the Collection to that tag (#414)#424

Merged
ibanner56 merged 2 commits into
mainfrom
isaacbanner-tap-tag-to-filter-414
Jul 21, 2026
Merged

feat(collection): tap a tag chip to filter the Collection to that tag (#414)#424
ibanner56 merged 2 commits into
mainfrom
isaacbanner-tap-tag-to-filter-414

Conversation

@ibanner56

Copy link
Copy Markdown
Owner

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

  • New CollectionFilterController / CollectionFilterScope (app/lib/src/data/collection_filter_scope.dart), provided in main.dart's MaterialApp.builder chain — above the root Navigator — mirroring the existing CollectionRefreshScope, so pushed detail routes can reach it.
  • AppShell subscribes and, on a request, switches to the Collection tab (index 0) and pops to the list root.
  • DanceListScreen applies the filter through the existing FacetSelections.tagIds / TagFilter facet — no core changes, no second filtering system.
  • Tag chips become tappable ActionChips: on the detail screen (guarded to non-preview) and on list rows (opt-in via onTagTap, 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 . — clean
  • fvm flutter analyze (app) — No issues found; fvm dart analyze (core) — No issues found
  • Core fvm dart test1798 passed (~4 skipped)
  • App fvm flutter test1651 passed

Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com

Copilot AI review requested due to automatic review settings July 21, 2026 00:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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/CollectionFilterScope to 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.

Comment thread app/lib/src/screens/dance_list_screen.dart
ibanner56 and others added 2 commits July 20, 2026 18:17
…#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
ibanner56 force-pushed the isaacbanner-tap-tag-to-filter-414 branch from 4ea7011 to 2357d13 Compare July 21, 2026 01:19
@ibanner56
ibanner56 merged commit fa2fe37 into main Jul 21, 2026
7 checks passed
@ibanner56
ibanner56 deleted the isaacbanner-tap-tag-to-filter-414 branch July 21, 2026 01:31
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.

[Feature]: Click on user added tags to take to the Collection view filtered to that tag

2 participants