Skip to content

fix(settings): self-describing item count in SettingsScreen - #2825

Closed
PonceGL wants to merge 1 commit into
PixelPlayerHQ:masterfrom
PonceGL:chore/p1-settings-total-items
Closed

PonceGL wants to merge 1 commit into
PixelPlayerHQ:masterfrom
PonceGL:chore/p1-settings-total-items

Conversation

@PonceGL

@PonceGL PonceGL commented Sep 10, 2026

Copy link
Copy Markdown

What

totalItems = mainCategories.size + 3 counts three trailing items (Device
Capabilities, Accounts, About) rendered by hand right after the category
loop, with a comment naming them — two sources of truth for the same fact.
Whoever adds a fourth trailing item and forgets the literal breaks the last
item's rounded corner. One of the small independent fixes listed in #2813.

The original justification for this fix (as scoped) turned out to be
wrong, verified against the code
: adding a SettingsCategory does not
trigger the bug — mainCategories.size is already dynamic. The real
fragility is the literal + 3 itself, disconnected from the three
ExpressiveXxxItem calls it's supposed to count.

Change

A private TrailingSettingsItem enum (DEVICE_CAPABILITIES, ACCOUNTS,
ABOUT) rendered via forEach + an exhaustive when, the same pattern
already used for mainCategories. totalItems = mainCategories.size + trailingItems.size — a real collection's size, not a literal. Adding a
fourth item now needs a new enum entry, and the compiler refuses to build
until the when covers it — the bug class becomes impossible, not just
less likely.

A self-review pass (before this PR went up) found the first version of this
fix only half-solved the duplication: the loop's own exclusion filter
(it != ABOUT && it != DEVICE_CAPABILITIES) was a second, independent
list of the same two categories. Fixed by giving TrailingSettingsItem a
nullable category: SettingsCategory? (null for Accounts, which isn't a
category) and deriving the loop's filter from it — one enum now drives both
the count and the exclusion.

Zero behavior change: same onClick, same colors, same order, same
shapeFor()/itemIndex bookkeeping.

Testing

No automated test added — SettingsScreen needs the full Hilt graph
(NavController, PlayerViewModel with ~30 dependencies, SettingsViewModel
via hiltViewModel()) to instantiate at all, and there's no existing Compose
test for this screen to build on; standing that up just for a
compiler-enforced, non-behavior-changing refactor felt disproportionate.

Attempted on-device visual verification instead; blocked by a sandbox
limitation in my own environment (synthetic input events never reached the
emulator — confirmed via raw getevent capture, unrelated to the app).
Verified instead: assembleDebug succeeds, full JVM baseline unaffected (5
pre-existing failures, none new), and the diff traced by hand against the
original for behavioral equivalence.

totalItems = mainCategories.size + 3 counted three trailing items
(Device Capabilities, Accounts, About) rendered by hand right after the
loop, with a comment naming them — two sources of truth for the same
fact. Whoever adds a fourth trailing item and forgets the literal
breaks the last item's rounded corner.

The plan's original justification for this fix was wrong (verified
against code): adding a SettingsCategory does NOT trigger the bug,
mainCategories.size is already dynamic. The real fragility is the
literal +3 itself, disconnected from the three ExpressiveXxxItem calls
it's supposed to count.

Fix: a private TrailingSettingsItem enum (DEVICE_CAPABILITIES,
ACCOUNTS, ABOUT) rendered via forEach + an exhaustive when, same
pattern already used for mainCategories. totalItems =
mainCategories.size + trailingItems.size — a real collection's size,
not a literal. Adding a fourth item now needs a new enum entry, and
the compiler refuses to compile until the when covers it —
the bug class becomes impossible, not just less likely.

Self-review (code-review skill, medium effort) found the fix was only
half done: the loop's own exclusion filter
(it != ABOUT && it != DEVICE_CAPABILITIES) was a second, independent
list of the same two categories, never derived from the new enum.
Fixed by giving TrailingSettingsItem a nullable `category:
SettingsCategory?` (null for Accounts, which isn't a category) and
deriving the loop's filter from it — one enum now drives both the
count and the exclusion, so a category can't end up rendered twice or
dropped by only remembering to update one of the two lists. Also
renamed the enum's entries to UPPER_SNAKE_CASE to match the sibling
SettingsCategory enum's convention in this same file (was PascalCase).

Zero behavior change: same onClick, same colors, same order, same
shapeFor()/itemIndex bookkeeping.

Testing: no automated test added. SettingsScreen needs the full Hilt
graph (NavController, PlayerViewModel with ~30 dependencies,
SettingsViewModel via hiltViewModel()) to instantiate at all, and
there's no existing Compose test for this screen to build on —
standing that up just for a compiler-enforced, non-behavior-changing
refactor is disproportionate. Attempted visual verification on-device
instead; blocked by this session's sandbox not delivering synthetic
input events to the emulator (adb shell input — confirmed via raw
getevent capture, zero events for both taps and keys after ruling out
disk space as the cause) — documented, not silently skipped. Verified
instead: assembleDebug succeeds, full JVM baseline unaffected (5
pre-existing failures, none new), and the diff traced by hand against
the original for behavioral equivalence. graphify-out/ refreshed per
this repo's CLAUDE.md.
@PonceGL

PonceGL commented Sep 10, 2026

Copy link
Copy Markdown
Author

Closing for now — reorganizing how this work is staged. It'll go through our fork first and we'll propose it upstream again, possibly bundled differently, once the larger feature it's part of is further along. Not a rejection, just a process change on our side.

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.

1 participant