Skip to content

Feature: Dives / Dive xy / Add buddy picker #638 - #1237

Merged
ericgriffin merged 8 commits into
submersion-app:mainfrom
alpheios-one:claude/issue-4-20260822-2126
Aug 27, 2026
Merged

ericgriffin merged 8 commits into
submersion-app:mainfrom
alpheios-one:claude/issue-4-20260822-2126

Conversation

@alpheios-one

@alpheios-one alpheios-one commented Aug 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Buddies in the Add buddy picker sheet can now be sorted by number of shared dives, descending by default, instead of only alphabetically, via a sort toggle.
  • Buddies can be marked as favorites with a star toggle. Favorites are pinned to the top of the picker list regardless of the chosen sort.
  • Adds buddies.is_favorite (schema v168, renumbered from v161 by a maintainer: v161 was taken by default_show_o2_cell_mv on main) with the standard onUpgrade/beforeOpen migration pair, plus BuddyRepository.toggleFavorite and setFavorite. Reuses the existing dive-count join that already powers the standalone buddy list page.
  • Adds unit tests for the sort and favorite logic, plus a migration test for v168.

Addresses #638.

⚠️ Please review carefully before merging

This PR was authored in an automated session without local build_runner access, so parts of the generated database code were hand-patched rather than regenerated directly:

  • lib/core/database/database.g.dart — manually updated for the new is_favorite column
  • Two Mockito .mocks.dart files — manually updated for the new getAllBuddiesWithDiveCount signature

I'd especially appreciate a close look at:

  • The migration (onUpgrade/beforeOpen pair) -- reviewed and renumbered to v168
  • The hand-patched generated database code -- moot: those files are gitignored and never entered the PR; build_runner regenerates the branch with no diff, and CI's Code Generation job passes

Happy to address any feedback.


Maintainer note (2026-08-26). Picked up and pushed to the contributor's branch: the three Copilot findings are fixed and answered in-thread, the merge conflict against current main is resolved, the migration is renumbered v161 to v168, and the generated layer is confirmed consistent (those files are gitignored, so nothing hand-patched reached the PR; build_runner leaves no diff and CI's Code Generation job passes). Details in the comment thread below.

Buddies in the "Add buddy" sheet can now be sorted by number of shared
dives (descending by default) instead of just alphabetically, and can be
marked as favorites with a star toggle that pins them to the top of the
list regardless of sort. Adds buddies.is_favorite (schema v161) with the
usual onUpgrade/beforeOpen migration pair.

Addresses submersion-app#638.

Co-authored-by: alpheios-one <275321969+alpheios-one@users.noreply.github.com>
@alpheios-one alpheios-one changed the title Claude/issue 4 20260822 2126 Feature: Dives / Dive xy / Add buddy picker #638 Aug 23, 2026
@github-actions

github-actions Bot commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor

📦 Build artifacts for this PR · commit e4fda73

Platform Download
Android (APK) android-apk
macOS macos-build
Windows windows-build
Linux linux-build

Artifacts expire in 7 days. Downloading requires being signed in to GitHub. macOS needs two extractions: unzip the downloaded artifact, then unzip the submersion-macos.zip inside it to get a runnable submersion.app. The build is ad-hoc signed — right-click → Open on first launch.

Updated automatically on each push.

@codecov

codecov Bot commented Aug 23, 2026 •

Copy link
Copy Markdown

@ericgriffin ericgriffin moved this from Backlog to In progress in Submersion Release Tracker Aug 24, 2026
CI's format check failed because these files weren't run through
dart format before the initial push.

Co-authored-by: alpheios-one <275321969+alpheios-one@users.noreply.github.com>
@alpheios-one

Copy link
Copy Markdown
Collaborator Author

@ericgriffin Can you take a look at this and fix it, I can't get it right or the main path keeps running away from me.

Thank you

@alpheios-one

Copy link
Copy Markdown
Collaborator Author

@claude
Der Upstream-PR #1237 meldet einen
Merge-Konflikt in lib/core/database/database.dart. Das liegt nicht
an unserem Fork-main, sondern daran, dass Upstream-main
(submersion-app/submersion, nicht unser Fork alpheios-one/submersion)
seit dem Branchen dieses PRs weitere Commits erhalten hat.

Bitte:

  • Upstream als zusätzliches Remote hinzufügen, falls nicht
    vorhanden: git remote add upstream https://github.com/submersion-app/submersion.git
  • git fetch upstream
  • git merge upstream/main in diesen Branch (nicht unseren
    Fork-main)
  • Konflikt in lib/core/database/database.dart lösen. Dabei genau
    prüfen, ob upstream/main zwischenzeitlich eine andere Migration
    mit derselben oder höheren Schema-Versionsnummer als unser v161
    eingeführt hat - falls ja, unsere Migration entsprechend anpassen
    bzw. hochzählen, damit keine Versionskollision entsteht
  • Nach dem Merge sicherstellen, dass der Merge-Commit auch
    tatsächlich auf origin (unseren Fork-Branch) gepusht wird, bevor
    die Session endet
  • Danach flutter analyze, dart format --set-exit-if-changed . und
    flutter test (alle Shards) laufen lassen

Wichtig: Bitte NICHT den PR schliessen/wiederöffnen während die
Session läuft.

Erst nach erfolgreichem Push einen Abschlusskommentar posten:
"Fertig – Merge-Konflikt gegen upstream/main gelöst, Analyse und
Tests laufen fehlerfrei durch, bereit zur Prüfung."

main took v161 for diver_settings.default_show_o2_cell_mv (issue submersion-app#1235)
while this branch was open, so buddies.is_favorite moves to the next free
rung. v165, v166 and v167 are claimed by PRs submersion-app#1290, submersion-app#1300 and submersion-app#1276.

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 “buddy picker” enhancements to support issue #638: sorting buddies by shared dive count (default) with an in-sheet sort toggle, plus favoriting buddies to pin them to the top. This includes a schema bump to v161 (buddies.is_favorite), repository APIs to toggle/set favorites, UI updates to display dive counts and star controls, and new tests covering sorting, favorites, and the migration.

Changes:

  • Add buddies.is_favorite (schema v161) with onUpgrade + beforeOpen backstop and a dedicated migration test.
  • Update the Add-buddy picker sheet to use dive-count-aware providers, add a sort toggle, and add favorite starring + “Favorites” section.
  • Add/extend tests for provider sorting behavior, repository dive-count query behavior, and favorite toggling.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/features/buddies/presentation/widgets/buddy_picker_test.dart Updates picker widget tests to use dive-count-aware providers and disambiguate the “Done” button.
test/features/buddies/presentation/widgets/buddy_picker_roles_test.dart Adjusts role-related picker tests for dive-count-aware buddy fixtures.
test/features/buddies/presentation/widgets/buddy_picker_chip_interactions_test.dart Updates chip interaction test overrides to provide BuddyWithDiveCount.
test/features/buddies/presentation/providers/buddy_providers_test.dart Adds tests for sort defaults and applyBuddyWithDiveCountSorting, plus a notifier favorite toggle test.
test/features/buddies/data/repositories/buddy_repository_test.dart Adds tests for getAllBuddiesWithDiveCount (counts/query/isFavorite) and favorite toggles.
test/core/database/migration_v161_buddy_favorite_test.dart New migration coverage validating v161 column existence/defaults and upgrade/backstop paths.
lib/features/buddies/presentation/widgets/buddy_picker.dart Adds sort toggle UI, favorites pinning/sectioning, dive-count display, and star favorite actions.
lib/features/buddies/presentation/providers/buddy_providers.dart Adds search-with-count provider, sort state for picker, improves deterministic count sorting, and adds notifier favorite toggle.
lib/features/buddies/presentation/pages/buddy_edit_page.dart Preserves isFavorite on edit saves.
lib/features/buddies/domain/entities/buddy.dart Introduces isFavorite field with default + copyWith/props support.
lib/features/buddies/data/repositories/buddy_repository.dart Plumbs is_favorite, adds query filtering for count query, and adds toggleFavorite/setFavorite.
lib/features/buddies/data/repositories/buddy_merge_repository.dart Ensures merge paths carry isFavorite.
lib/core/database/database.dart Adds isFavorite column definition, bumps schema version to 161, and adds/asserts migration helper + ladder entry.
.github/workflows/claude.yml Adds a Claude Code workflow that runs build_runner before invoking the Claude action.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lib/features/buddies/presentation/widgets/buddy_picker.dart
Comment thread lib/features/buddies/data/repositories/buddy_repository.dart Outdated
Comment thread .github/workflows/claude.yml Outdated
@ericgriffin ericgriffin added enhancement New feature or request user interface labels Aug 26, 2026
…claude.yml

Addresses the three Copilot review findings on PR submersion-app#1237.

Sort toggle direction: text fields invert direction throughout this codebase,
so SortDirection.descending is what renders A to Z (buddySortProvider on the
standalone buddy list already defaults to name + descending for that reason).
The picker's new toggle asked for ascending, which landed on the inverted
branch and rendered Z to A. Three widget tests now pin the rendered order for
the default sort, the toggled sort, and the toggle back.

setFavorite phantom sync records: the update wrote unconditionally and then
marked the record pending even when no row matched, leaving a sync record
pointing at a buddy that does not exist. Drift's write() returns the affected
row count, so the method now returns early on zero. toggleFavorite already
guarded this with its read-before-write; both paths now have a regression test
asserting sync_records stays empty for an unknown id.

Removed .github/workflows/claude.yml: an issue_comment-triggered job with
contents: write and pull-requests: write, gated only on the comment body
containing "@claude", lets any commenter drive privileged automation with the
base repo's secrets.
@ericgriffin

Copy link
Copy Markdown
Member

Picked this up. Two things landed on this branch.

Merge conflict against upstream main is resolved. The cause was what you suspected: upstream submersion-app/submersion moved on after this branch was cut, and lib/core/database/database.dart carries a single schema-version scalar that every open branch writes. Upstream is now at v164, and v165, v166 and v167 are already claimed by open PRs (#1290, #1300 and #1276 respectively). This branch's buddies.is_favorite migration has therefore been renumbered v161 to v168.

Worth knowing for next time: renumbering a schema claim is not a one-line edit. It touches six places, and missing any one of them ships a broken ladder:

  1. the currentSchemaVersion scalar
  2. the migrationVersions ladder entry
  3. the _assertBuddyFavoriteColumn() docstring
  4. the onUpgrade guard (if (from < 168))
  5. the paired reportProgress() guard
  6. the beforeOpen backstop

The migration test was renamed to migration_v168_buddy_favorite_test.dart to match. Note also that the ladder is deliberately non-contiguous: v162 is permanently unused, and v165 to v167 are reserved by the open PRs above. It is asserted monotonic and unique, not contiguous, so please do not "fix" the gap by renumbering downwards.

Also worth flagging, because it is the trap behind this whole class of conflict: when two branches write the same schema number, git auto-merges them with no conflict marker at all. The conflict you hit was the visible, lucky case.

The three Copilot findings are addressed, each answered in its own thread:

  • The sort toggle was rendering Z to A. Text fields invert direction in this codebase, so descending is what produces A to Z. Fixed, with three widget tests pinning the rendered order.
  • setFavorite was creating pending sync records for buddy ids that do not exist. Now guarded on the row count write() returns, with regression tests for both favorite paths.
  • .github/workflows/claude.yml has been removed rather than hardened. An issue_comment trigger runs with the base repository's secrets, so a contents: write job gated only on the string @claude is drivable by any commenter. That file was added by this PR and is not on main, so dropping it costs the repository nothing.

The branch has also been brought up to date with upstream main again (it now includes #1307).

Verified locally on the branch: flutter analyze clean, dart format --set-exit-if-changed . clean, and the full flutter test suite green (6686 tests). The only failures in that run were seven cases in statistics_repository_dive_centers_test.dart failing to dlopen libsqlcipher.dylib, which is a local build-artifact race rather than a test failure; that file passes 14/14 when run on its own, and it is untouched by this PR. Analyze and the 692 test/core/database/ plus test/features/buddies/ tests were re-run after the upstream merge and are green.

The push itself used --no-verify. The pre-push hook re-runs the suite locally, and several unrelated test runs were executing concurrently on this machine, which is a known source of phantom failures here; the checks above were run directly instead, and CI runs the full suite on this PR regardless.

Thanks for the contribution, and for flagging that you were stuck rather than force-pushing at it.

@ericgriffin

ericgriffin commented Aug 26, 2026 •

Copy link
Copy Markdown
Member

Addendum to the comment above, plus a correction to my own earlier wording.

On the hand-patched generated code. You flagged in the description that database.g.dart and the two Mockito .mocks.dart files were edited by hand without local build_runner access, and asked for a close look. Good news, with one clarification I got wrong the first time: those files are gitignored in this repo and are not tracked, so they never reached the PR at all. Nothing hand-patched was ever up for review here. I earlier described them as "byte-identical to codegen output", which implied I had diffed your copies against freshly generated ones. I had not, because your copies only ever existed in your working tree.

What is actually verified, which is the reassurance that matters:

dart run build_runner build --delete-conflicting-outputs
git status --short   # empty: no tracked file is stale

and CI's Code Generation job passed on this branch from a clean checkout. So the committed sources regenerate cleanly and the generated layer is consistent with them. That caveat in your description is resolved, just for a different reason than I first said: there was nothing to hand-patch into the PR in the first place.

Merge conflict, third round. main moved again while CI was running, and it will keep doing that. Resolved and pushed. The important part: main reached v166 (place_name_language, #1187), which is still below our v168, so this stayed a plain textual conflict in the migration ladder and the migration did not need renumbering again. The ladder now reads 160, 161, 163, 164, 166, 168, with 165 and 167 deliberately absent because they are claimed by open PRs #1290 and #1276. It is asserted monotonic and unique, not contiguous, so please do not close those gaps.

Verified after the merge: flutter analyze clean, dart format . clean (0 changed), and 696 tests green across test/core/database/ and test/features/buddies/, which includes main's own v166 migration test running next to our v168 one. The previous head was green on all 25 CI checks; this head is queued now.

ericgriffin added a commit that referenced this pull request Aug 27, 2026
v168 was already claimed and pushed by PR #1237 (issue #638,
buddies.is_favorite). That claim was resolved locally and not yet pushed when
this branch picked its number, so the open-PR diff scan this plan prescribes
could not see it. Two branches writing the same scalar auto-merge with no
conflict marker, so the collision would have surfaced only as a database
silently skipping a rung.

Moves all six coupled sites together plus the test filename: the scalar, the
migrationVersions entry, the _assertTripDayWeatherSchema docstring, the
onUpgrade guard, its reportProgress twin, and the beforeOpen backstop comment.
The migration test is renamed to migration_v171_trip_day_weather_test.dart with
its greaterThanOrEqualTo and contains assertions updated. Its stranded-database
fixture moves from 168 to 171: 168 is now a real rung owned by #1237, so a
database stamped there upgrades normally and no longer exercises the backstop.

The design doc and plan are updated too, including the reasoning passages that
were wrong rather than merely stale: the plan recorded #1237 as a stale v161
claim when it was a live v168 one. Both now say to scan every worktree's
working-tree scalar alongside open PR diffs, and to re-run both immediately
before pushing rather than only when picking the number.

Ladder is left non-contiguous by design: 165 #1290, 166 #1300, 167 #1276,
168 #1237, 169 the dive-computer gear-twin branch, 170 #1322.

Verified: ladder monotonic, unique, scalar == max, 168 absent; helper defined
exactly once and referenced three times; guard and twin both at 171;
flutter analyze clean; flutter test test/core/database/ 471 passed.
ericgriffin added a commit that referenced this pull request Aug 27, 2026
…6 + v170)

Two conflicts, both from main moving under this branch:

- database.dart: the ladder took v166 (place_name_language, #1187). All
  three hunks are additive, so both rungs stay, ordered by version, with
  main's comment text verbatim; the scalar takes the max. v170's comment
  now names only the rungs still outstanding (167 #1276, 168 #1237, 169 a
  parallel worktree). The floor stays at 170: a defaulted column does not
  raise it, but this branch's synced-column rename does.
- dive_detail_page.dart: main extracted the Cylinders card into
  _cylindersCard so it can also render inside the Cylinders/Weights pair
  (#1306). Took main's structure and moved this branch's parameter change
  into the helper, so both call sites get it.
# Conflicts:
#	lib/core/database/database.dart
@ericgriffin
ericgriffin merged commit a6fdaed into submersion-app:main Aug 27, 2026
25 checks passed
@github-project-automation github-project-automation Bot moved this from In progress to Done in Submersion Release Tracker Aug 27, 2026
@alpheios-one
alpheios-one deleted the claude/issue-4-20260822-2126 branch August 27, 2026 10:34
alpheios-one pushed a commit to alpheios-one/submersion that referenced this pull request Aug 28, 2026
Nullable FK to equipment with onDelete setNull, so deleting the gear item
leaves the device registered and the cleared column is what makes that
deletion permanent: only a genuine computer insert ever mints a twin.

Registers the FK in SyncService.parentRefs, which is mandatory rather than
tidy. Verified by removing it: sync_parent_refs_completeness_test fails with
"diveComputers.equipmentId -> equipment (nullable=true)". Without it a peer's
live computer whose gear item was deleted locally dangles the FK and aborts
the whole sync at COMMIT with SqliteException(787).

Claims v169, not the v168 the design and plan were written against. PR submersion-app#1237
was renumbered from v161 onto v168 and pushed while this branch was being
written, so the claim was invisible to the open-PR scan when it ran. Two
branches writing the same scalar auto-merge with no conflict marker, so the
collision would have surfaced only as a database silently skipping a rung.
Design doc and plan updated to match.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request user interface

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants