Conversation
10 tasks
A two-sided card in the Collection tab, built from what the save already holds. Front: trainer name and number, lifetime tokens, Pokédex count over the 649 the app can hatch, shinies, graduations, duplicates, first catch, and the rarity split. Back: a team of six. The team asks nothing of the user until they want it: it fills itself with the rarest and shiniest graduates, and the first edit freezes what is on screen and takes it from there. "Automatic team" is a toggle, not a reset, so the picked line-up is kept aside and comes back. The raised Pokémon can join and keeps its slot through graduation, released individuals leave it, and a hand-edited save is reconciled on load. The card frames the pinned representative species, falling back to the raised Pokémon, so a fresh egg does not take it over. Released individuals count in no figure except the Pokédex, which folds owned species whatever became of them. Export copies the image to the clipboard or saves a PNG, with a toggle to hide the token count. The floating pet's menu copies it too and says so with a callout. Nothing leaves the Mac.
XCTest's setUp and tearDown are nonisolated, so a @mainactor test case cannot touch a mutable stored property from them. Swift 6.2 lets it through, the CI toolchain (Swift 6.0 on macos-15) rejects it.
The card was branched before Unown forms landed, so its sprites fell back to the default A and its names dropped the letter. The pinned form reaches the frame through the representative subject, and team slots and the picker rows read the form off the entry like the catch log does.
DyRize
force-pushed
the
feat/trainer-card
branch
from
September 21, 2026 15:40
493bd83 to
7250f43
Compare
10 tasks
This branch has not been deployed
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.
Summary
Adds a trainer card to the Collection tab, built entirely from what the save already holds — no new tracking, no cost figures, nothing leaving the Mac.
Part of #260 (point 3).
Front: trainer name (optional, empty by default), a 5-digit number drawn once on first open, lifetime tokens, Pokédex count over the 649 species the app can hatch, shinies, graduations, duplicates, first catch, and the rarity split. Back: a team of six.
The team asks nothing of the user until they want it. With no picks it fills itself — shinies first, then the rarest, then the newest. The first edit freezes what is on screen and edits from there, so nobody starts from an empty card. "Automatic team" is a toggle rather than a reset: the picked line-up is kept aside and comes back when it is turned off, because losing six deliberate picks to one stray click is not a fair trade.
Lifecycle cases are handled: the Pokémon being raised can join and keeps its slot through graduation (the team key is its profile id, which its graduated entry keeps), released individuals leave the team, and unknown, duplicate or out-of-range ids in a hand-edited save are reconciled on load and on import.
The card frames the pinned representative species and falls back to the Pokémon being raised, so a fresh egg does not take the card over. Released individuals count in no figure except the Pokédex line, which folds owned species whatever became of the individual — that rule is the dex's, not the card's.
Privacy: no cost in dollars, no account names, no emails, an empty trainer name by default and a toggle to hide the token count. Export copies a PNG to the clipboard or saves it through
NSSavePanel; the floating pet's right-click menu copies it too and confirms with a callout.Species beyond the animated range (Sylveon at #700, reachable from Eevee) stay out of the Pokédex count so it can never read
650 / 649.State added to
CompanionState:teamEntryIDs,teamIsAutomatic,trainerID,trainerName, all classified as progress for save transfer and lenient-decoded like the rest.If #265 (box) lands, the team could pick from the box as well — happy to follow up.
Type of change
UI changes
person.text.rectangle) and opens the card screen inside the popover: the two card sides, a name field, a "Show tokens" checkbox, Copy image, Save… and an "Automatic team" checkbox. Catch log rows gain a TEAM badge and a right-click entry to add or remove. The floating pet's menu gains "Copy trainer card".Screenshots (English, rendered from this branch):
The card itself is always rendered light so the exported image looks the same in light and dark mode. A shiny companion gets a holo frame on both sides.
Checklist
swift buildandswift testpass locallyscripts/test-gate.sh: 1105 tests, 11 skipped, 0 failures, logic-core line coverage 92.93%. 27 tests cover the card: automatic order, the first edit, add/replace/move/limit, the automatic toggle keeping the picks, graduation and release, load reconciliation, trainer id and name, stats and rows, released individuals counting nowhere but the Pokédex, save transfer, rendering in all seven languages, and the holo frame on both sides. New branches were checked withllvm-cov --show-regionsrather than the coverage number, and the team logic was verified by injecting defects one at a time to confirm the tests fail.