Skip to content

Feature/buddy merge#66

Merged
ericgriffin merged 18 commits into
mainfrom
feature/buddy-merge
Mar 23, 2026
Merged

Feature/buddy merge#66
ericgriffin merged 18 commits into
mainfrom
feature/buddy-merge

Conversation

@ericgriffin

@ericgriffin ericgriffin commented Mar 22, 2026

Copy link
Copy Markdown
Member

Summary

  • Add buddy merge feature mirroring the sites merge pattern (PR Feature/sites merge #54), allowing users to merge duplicate buddy entries with full undo support
  • Multi-select mode on buddy list with merge (2+ selected) and bulk delete (1+ selected) actions
  • Merge edit page with per-field cycling to pick the best value from each duplicate (name, email, phone, certification, notes)
  • DiveBuddies junction relinking with role hierarchy collision resolution (instructor > diveMaster > diveGuide > buddy > student > solo)
  • Snapshot-based undo via SnackBar action within 5 seconds of merge
  • All 10 locales translated (en + ar, de, es, fr, he, hu, it, nl, pt)

Test Plan

  • 6 repository unit tests: basic merge, role collision, 3-way merge, zero-dive merge, undo restoration, bulk delete
  • 5 provider integration tests: merge with snapshot, merge with <2 IDs, undo restores state, bulk delete, empty bulk delete
  • Manual: long-press buddy in list to enter selection mode, select 2+ buddies, tap merge icon
  • Manual: verify per-field cycling works on the merge edit page (tap cycle button to switch values)
  • Manual: confirm merge, verify survivor has merged fields, duplicates deleted, dive associations relinked
  • Manual: tap Undo on SnackBar within 5 seconds, verify all buddies and dive associations restored
  • Manual: select 1+ buddies, tap delete, confirm, verify deleted
  • flutter test passes (1946 tests)
  • flutter analyze reports no issues

Copilot AI review requested due to automatic review settings March 22, 2026 16:30

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 “buddy merge” workflow (mirroring the existing site-merge pattern) so users can multi-select buddies, merge duplicates into a single survivor with per-field value cycling, relink DiveBuddies junction rows with role-collision resolution, and optionally undo shortly after via SnackBar.

Changes:

  • Implemented repository-level buddy merge/undo/bulk-delete behavior (with DiveBuddies relinking + role hierarchy).
  • Added UI selection mode on the buddy list (merge + bulk delete actions) and a merge-capable BuddyEditPage flow (via BuddyMergePage + routing).
  • Added tests for merge/undo/bulk delete and added localization strings across supported locales.

Reviewed changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/features/dive_import/data/services/uddf_entity_importer_test.mocks.dart Updates generated mock to include new repository APIs (merge/undo/bulk delete).
test/features/buddies/presentation/providers/buddy_merge_providers_test.dart Provider/integration-style tests for merge/undo/bulk delete flows.
test/features/buddies/data/repositories/buddy_merge_test.dart Unit tests for merge behavior, role collisions, undo, and bulk delete.
lib/l10n/arb/app_pt.arb Adds buddy selection/merge/bulk-delete localization strings (pt).
lib/l10n/arb/app_nl.arb Adds buddy selection/merge/bulk-delete localization strings (nl).
lib/l10n/arb/app_it.arb Adds buddy selection/merge/bulk-delete localization strings (it).
lib/l10n/arb/app_hu.arb Adds buddy selection/merge/bulk-delete localization strings (hu).
lib/l10n/arb/app_he.arb Adds buddy selection/merge/bulk-delete localization strings (he).
lib/l10n/arb/app_fr.arb Adds buddy selection/merge/bulk-delete localization strings (fr).
lib/l10n/arb/app_es.arb Adds buddy selection/merge/bulk-delete localization strings (es).
lib/l10n/arb/app_en.arb Adds source strings + placeholders for selection/merge/bulk delete + merge editor strings (en).
lib/l10n/arb/app_de.arb Adds buddy selection/merge/bulk-delete localization strings (de).
lib/l10n/arb/app_ar.arb Adds buddy selection/merge/bulk-delete localization strings (ar).
lib/l10n/arb/app_localizations_pt.dart Generated localization bindings for new buddy strings (pt).
lib/l10n/arb/app_localizations_nl.dart Generated localization bindings for new buddy strings (nl).
lib/l10n/arb/app_localizations_it.dart Generated localization bindings for new buddy strings (it).
lib/l10n/arb/app_localizations_hu.dart Generated localization bindings for new buddy strings (hu).
lib/l10n/arb/app_localizations_he.dart Generated localization bindings for new buddy strings (he).
lib/l10n/arb/app_localizations_fr.dart Generated localization bindings for new buddy strings (fr).
lib/l10n/arb/app_localizations_es.dart Generated localization bindings for new buddy strings (es).
lib/l10n/arb/app_localizations_en.dart Generated localization bindings for new buddy strings (en).
lib/l10n/arb/app_localizations_de.dart Generated localization bindings for new buddy strings (de).
lib/l10n/arb/app_localizations_ar.dart Generated localization bindings for new buddy strings (ar).
lib/l10n/arb/app_localizations.dart Updates base AppLocalizations API surface for new buddy strings.
lib/features/buddies/presentation/widgets/dense_buddy_list_tile.dart Adds selection-mode checkbox support for dense tiles.
lib/features/buddies/presentation/widgets/buddy_list_content.dart Implements multi-select mode, merge navigation + undo SnackBar, and bulk delete UI.
lib/features/buddies/presentation/providers/buddy_providers.dart Adds BuddyListNotifier APIs for merge/undo/bulk delete + provider invalidation.
lib/features/buddies/presentation/pages/buddy_merge_page.dart Wrapper page routing merge IDs into BuddyEditPage merge mode.
lib/features/buddies/presentation/pages/buddy_edit_page.dart Extends BuddyEditPage with merge mode, candidate cycling UI, and merge-save path.
lib/features/buddies/data/repositories/buddy_repository.dart Exposes merge/undo/bulk-delete methods and re-exports merge types.
lib/features/buddies/data/repositories/buddy_merge_repository.dart New repository implementing transactional merge + snapshot-based undo + bulk delete.
lib/core/router/app_router.dart Adds /buddies/merge route.
docs/superpowers/specs/2026-03-22-buddy-merge-design.md Design/spec documentation for buddy merge feature.
docs/superpowers/plans/2026-03-22-buddy-merge.md Implementation plan documentation for buddy merge feature.

Comment thread lib/features/buddies/presentation/pages/buddy_edit_page.dart Outdated
Comment thread lib/features/buddies/data/repositories/buddy_merge_repository.dart Outdated
Comment thread test/features/buddies/presentation/providers/buddy_merge_providers_test.dart Outdated
Comment thread docs/superpowers/specs/2026-03-22-buddy-merge-design.md Outdated
@codecov

codecov Bot commented Mar 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.77432% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...dies/data/repositories/buddy_merge_repository.dart 94.31% 12 Missing ⚠️
...es/presentation/widgets/dense_buddy_list_tile.dart 42.85% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@ericgriffin
ericgriffin force-pushed the feature/buddy-merge branch 2 times, most recently from 4cea049 to 226333f Compare March 22, 2026 21:32
ericgriffin and others added 17 commits March 22, 2026 19:01
Adds DiveBuddySnapshot, BuddyMergeSnapshot, BuddyMergeResult classes and
mergeBuddies() method to BuddyRepository, mirroring the sites merge pattern.
Handles junction relinking with role-hierarchy conflict resolution.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mergeBuddies

- Update survivorDiveMap after role upgrade so subsequent duplicates
  on the same dive compare against the correct rank
- Use whereType<String>() for diverId validation so global buddies
  (null diverId) can merge with diver-scoped buddies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uddies/merge route

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change _invalidateMergeProviders from void to Future<void> so
  callers can await it and exceptions aren't silently swallowed
- Consistently invalidate-then-refresh in both mergeBuddies and
  undoMerge (matching the deleteBuddy pattern)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… dead code

Remove inline mergeBuddies/undoMerge/bulkDeleteBuddies implementations
from BuddyRepository (1019 -> 657 lines). BuddyRepository now delegates
to BuddyMergeRepository and re-exports snapshot types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5 tests covering BuddyListNotifier.mergeBuddies(), undoMerge(),
and bulkDeleteBuddies() through the repository delegation layer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes setState() called during build when FutureBuilder completes
and _initializeFromMerge sets controller text values, triggering
_onFieldChanged listener during the build phase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…plementation

Standalone repository containing the extracted merge logic, snapshot
classes, role hierarchy, and junction relinking with collision
resolution. Regenerated mock stubs for BuddyRepository's new methods.
@ericgriffin
ericgriffin force-pushed the feature/buddy-merge branch from 226333f to cccec69 Compare March 22, 2026 23:02
Comment thread lib/features/buddies/presentation/pages/buddy_edit_page.dart
Comment thread lib/features/buddies/presentation/pages/buddy_edit_page.dart Outdated
Comment thread lib/features/buddies/data/repositories/buddy_merge_repository.dart
Comment thread lib/features/buddies/data/repositories/buddy_merge_repository.dart Outdated
…xtraction

Fix data integrity bugs in buddy merge undo: add createdAt to
DiveBuddySnapshot, preserve original buddy/DiveBuddies timestamps
instead of overwriting with current time, and prevent multi-snapshot
of the same row during 3+ buddy merges via modifiedRowIds guard.

Fix merge form rendering by lifting data loading to BuddyMergePage
and initializing synchronously in initState, eliminating the
addPostFrameCallback/missing-setState race condition.

Extract merge candidate logic into BuddyMergeFormController (1048 -> 815 lines).
Add 5-second timeout to test polling helper. Update spec for photo cycling scope.
ericgriffin added a commit that referenced this pull request Mar 22, 2026
SiteSpeciesSnapshot was missing createdAt, and undoMerge was
overwriting both site and species timestamps with the current time.
Add createdAt to SiteSpeciesSnapshot, capture raw DB timestamps for
deleted sites in MergeSnapshot, and restore originals on undo.

Mirrors the same fixes applied to buddy merge in PR #66.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread lib/features/buddies/presentation/pages/buddy_edit_page.dart
Comment thread lib/features/buddies/presentation/widgets/buddy_list_content.dart
@ericgriffin
ericgriffin merged commit 5926d0b into main Mar 23, 2026
14 checks passed
@ericgriffin
ericgriffin deleted the feature/buddy-merge branch March 23, 2026 00:01
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.

2 participants