fix: journey map season-complete styling, scroll callback guard, palette constant

- Guard addPostFrameCallback with !_autoScrolled so it only fires once per
  widget lifetime instead of on every LayoutBuilder rebuild.
- Derive seasonComplete flag; pass it into _node so the last stage uses
  gold "done" styling (not "current/next") when the season is fully 3-starred.
- Extract const Color(0xFF232B4A) to GamePalette.lockedNode.
- Remove warnIfMissed: false from tap call in season_map_screen_test; ensureVisible
  already guarantees hit-testing succeeds (confirmed: test still passes cleanly).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 23:30:22 +09:00
parent 78eb5c0639
commit 2b44dcd812
3 changed files with 13 additions and 10 deletions
+11 -6
View File
@@ -65,6 +65,8 @@ class _JourneyMapState extends ConsumerState<_JourneyMap> {
final ids = [for (final stage in pack.stages) stage.id];
final unlocked = repo.highestUnlockedIndex(pack.seasonId, ids);
final totalStars = repo.totalStars(pack.seasonId);
final seasonComplete = totalStars == pack.stages.length * 3 &&
pack.stages.isNotEmpty;
final locale = Localizations.localeOf(context).languageCode;
final colors = ThemeColors(pack.theme);
@@ -78,9 +80,11 @@ class _JourneyMapState extends ConsumerState<_JourneyMap> {
builder: (context, constraints) {
final layout = MapLayout(width: constraints.maxWidth);
final count = pack.stages.length;
WidgetsBinding.instance.addPostFrameCallback((_) =>
_autoScrollTo(
layout, unlocked, count, constraints.maxHeight));
if (!_autoScrolled) {
WidgetsBinding.instance.addPostFrameCallback((_) =>
_autoScrollTo(
layout, unlocked, count, constraints.maxHeight));
}
return SingleChildScrollView(
controller: _scroll,
reverse: true,
@@ -104,6 +108,7 @@ class _JourneyMapState extends ConsumerState<_JourneyMap> {
unlocked,
repo.progressFor(pack.seasonId, ids[i])?.stars ?? 0,
colors,
seasonComplete,
),
],
),
@@ -166,9 +171,9 @@ class _JourneyMapState extends ConsumerState<_JourneyMap> {
}
Widget _node(BuildContext context, MapLayout layout, int i, int count,
int unlocked, int stars, ThemeColors colors) {
int unlocked, int stars, ThemeColors colors, bool seasonComplete) {
final center = layout.nodeCenter(i, count);
final isCurrent = i == unlocked;
final isCurrent = i == unlocked && !seasonComplete;
final isUnlocked = i <= unlocked;
final size = isCurrent ? 64.0 : 52.0;
@@ -213,7 +218,7 @@ class _JourneyMapState extends ConsumerState<_JourneyMap> {
],
)
: null,
color: isUnlocked ? null : const Color(0xFF232B4A),
color: isUnlocked ? null : GamePalette.lockedNode,
boxShadow: isCurrent
? [
BoxShadow(
+1
View File
@@ -22,6 +22,7 @@ class GamePalette {
static Color tile(int colorId) => tileColors[colorId % tileColors.length];
static const lockedNode = Color(0xFF232B4A);
static const gem = Color(0xFF7CF5FF);
static const ghostLegal = Color(0x66FFFFFF);
static const ghostIllegal = Color(0x55FF5252);