3138fc4b08
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>
84 lines
2.5 KiB
Dart
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,
|
|
);
|
|
}
|
|
}
|