Files
BlockSeasons/lib/ui/widgets/hud_widget.dart
T
airkjw 3138fc4b08 Add playable core UI: board painter, drag-and-drop, HUD, result overlay
CustomPainter board with gems/ghost/clear-flash, finger-lifted drag
with snap preview, combo text effect, HUD chips, phase overlays with
rescue stubs, demo stage. E2E widget test drives a real drag gesture.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:19:34 +09:00

84 lines
2.5 KiB
Dart

import 'package:flutter/material.dart';
import '../../game/models/objective.dart';
import '../../state/game_session_notifier.dart';
class HudWidget extends StatelessWidget {
const HudWidget({super.key, required this.view});
final GameViewState view;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_movesChip(theme),
AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
transitionBuilder: (child, anim) =>
ScaleTransition(scale: anim, child: child),
child: Text(
'${view.score}',
key: ValueKey(view.score),
style: theme.textTheme.headlineMedium
?.copyWith(fontWeight: FontWeight.w800),
),
),
_comboChip(theme),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (final obj in view.objectives) ...[
_objectiveChip(theme, obj),
const SizedBox(width: 12),
],
],
),
],
);
}
Widget _movesChip(ThemeData theme) {
return Chip(
avatar: const Icon(Icons.swipe, size: 18),
label: Text('${view.movesLeft}'),
labelStyle: theme.textTheme.titleMedium,
);
}
Widget _comboChip(ThemeData theme) {
final visible = view.comboStreak >= 2;
return AnimatedOpacity(
duration: const Duration(milliseconds: 150),
opacity: visible ? 1 : 0,
child: Chip(
avatar: const Icon(Icons.local_fire_department,
size: 18, color: Colors.deepOrange),
label: Text('x${view.comboStreak}'),
labelStyle: theme.textTheme.titleMedium,
),
);
}
Widget _objectiveChip(ThemeData theme, Objective obj) {
final (icon, color) = switch (obj) {
ClearGemsObjective() => (Icons.diamond, const Color(0xFF7CF5FF)),
ReachScoreObjective() => (Icons.star, Colors.amber),
ClearLinesObjective() => (Icons.table_rows, Colors.lightGreen),
};
final done = obj.isComplete;
return Chip(
avatar: Icon(done ? Icons.check_circle : icon, size: 18, color: color),
label: Text('${obj.current.clamp(0, obj.target)}/${obj.target}'),
labelStyle: theme.textTheme.titleSmall,
);
}
}