feat(collection): batch set/clear dance level in multi-select (#409)#422
Merged
Conversation
Adds a 'Set level' action to the Collection multi-select bar, letting a caller apply (or clear) a difficulty level across many selected dances at once, parallel to the existing batch tag add/remove flow. Core gains DanceRepository.setLevelForMany, a single-transaction batched write that reuses the existing upsert path, skips unknown ids and dances already at the target level (idempotent), and returns the changed count so an error leaves the collection untouched rather than half-updated. The app-side flow captures prior per-dance levels for a snackbar Undo, announces the result to assistive tech, and treats an empty selection or a no-op change accordingly. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
3 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new Collection multi-select action to batch set or clear a dance’s difficulty level, implemented with a single-transaction core repository method and a new app dialog + undo flow.
Changes:
- Core: add
DanceRepository.setLevelForMany(...)to update many dances’levelatomically and idempotently. - App: add a batch level picker dialog with an explicit “Unspecified (clear)” option.
- App: wire a new selection-mode action to apply the batch change with snackbar + Undo, plus widget tests.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/compendium_core/lib/src/storage/repositories/dance_repository.dart | Adds batched repository API for setting/clearing level in one transaction. |
| packages/compendium_core/test/storage/dance_batch_level_test.dart | Adds core tests for batch set/clear/idempotency/unknown IDs. |
| app/lib/src/widgets/batch_level_dialog.dart | New single-choice batch level dialog with explicit clear option. |
| app/lib/src/screens/dance_list_screen.dart | Adds selection-mode “Set level” action with apply + undo + AT announcement. |
| app/test/screens/batch_level_test.dart | Adds widget tests covering apply/clear/idempotency/undo/disabled state. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
#409) Require a non-null level unless clearLevel is true, so calling the batch setter with default args can no longer silently wipe every selected dance's level. Documents the mutually-exclusive set-vs-clear contract and adds a test asserting the guard fires. Addresses Copilot review feedback on #422. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
… call (#409) Asserts are stripped in release, so the debug-only guard alone left a latent footgun: a caller omitting level: (with clearLevel default false) would silently wipe every selected dance's level in production. Add a release-safe ArgumentError thrown before the assert so the contract holds in all build modes; clearLevel still wins when both are passed. Updates the core test to expect ArgumentError and verify the existing level survives. Addresses Copilot review feedback on #422. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.
What & why
Closes part of #409 ("Ability to add tags en-masse").
Scope note (important): The issue's title asks for bulk tagging, but batch Add tags / Remove tags already ship in multi-select (landed in #93, v0.1.0-beta.3) — as the issue owner's own triage comment confirms. The genuinely new ask is "add metadata/other info like level". This PR delivers that for level, reusing the existing batch-tag flow.
rating/tunes/customFieldsare deferred to a follow-up issue to keep this atomic.Changes
DanceRepository.setLevelForMany(ids, {level, clearLevel, now})— a single-transaction batched write that reuses the existing upsert path (keeping derived figure/FTS indexes consistent), skips unknown ids and dances already at the target level (idempotent), and returns the changed count. Running the whole batch in one transaction means an error leaves the collection untouched rather than half-updated. Stays Flutter-free.batch_level_dialog.dartsingle-choice picker (mirrorsbatch_tag_dialog.dart) with an explicit Unspecified (clear) option, using the repo'sRadioGrouppattern.dance_list_screen.dart:_batchSetLevel+_undoBatchLeveland abatch-set-levelaction in the selection app bar. Captures prior per-dance levels for a snackbar Undo, announces the result to assistive tech, and handles empty-selection / no-op cases.Semantics
Setting a level is a replace (not additive like tags), so the picker is single-choice and the action is explicit + Undo-restorable. Idempotent (dances already at the target are skipped -> "No changes" when nothing changes). Non-selected dances are never touched. Empty selection disables the button and is a guarded no-op.
Tests & gates
dance_batch_level_test.dart— sets level on N ids in one txn; unknown ids ignored; empty list no-op; idempotent skip;clearLevelunsets and wins over a passed value;updatedAtstamped only on changed dances.batch_level_test.dart— applies to all selected; un-selected untouched; idempotent; clear path; Undo restores prior per-dance levels; no-op message; button disabled on empty selection.Gates (exact):
fvm dart format .— cleanfvm flutter analyze— No issues found (0/0)fvm dart test— 1804 passed, 4 skippedfvm flutter test— 1651 passedCo-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com