Settings will translate everything about them (label, choices, units) in one
category, the label's, so:
- "Achievement sound volume" moves from Achievements to Audio, where the other
volumes are.
- The choice strings of the ad hoc relay mode and chat positions are copied
from Dialog to Networking, the notification position's to System, and the
leaderboard tracker position's to Achievements.
- "seconds" is added to Controls and System, for the units of the touch
control auto-hide delay and the rewind snapshot interval.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ChoiceGroups no longer have hardcoded margins. A new ChoiceGroupList holds them,
with padding and spacing that give the same look as before. Settings tabs, developer
tools, the two-pane settings columns, the pause menu and the rest put their groups in
one, and a few screens adjust its padding and spacing to their layout.
Also add the two groups in the remote disc streaming settings that were created but
never added, and make the settings search look inside groups: it only checked a tab's
direct children, so with ChoiceGroups a filter hid everything.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Achievement badges and game icons don't change, so re-downloading them
daily was wasted. InsertIcon now takes a max age, and each entry saves
its expiry time. Leaderboard avatars get a day, everything else 30 days.
Bumps the cache version.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
rc_client frees a request's async handle right after calling back. The
error path didn't clear pendingAsyncCall_, so closing the screen after a
failed fetch aborted a freed handle. Switching between Top players and
Around me also overwrote the handle without aborting the old request,
which could then call back into a closed screen, or leak an entry list.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
rc_client_begin_fetch_leaderboard_entries[_around_user]()'s returned
async handle was discarded instead of stored in pendingAsyncCall_, so
the destructor's "abort the in-flight request" guard was always a
no-op. Closing (or switching modes on) a leaderboard screen before its
network fetch completes let the completion callback run later against
the already-destroyed screen (writing to its now-freed
pendingEntryList_/pendingAsyncCall_ members) - ordinary usage on a
slow connection, not just an edge case.