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>
60 lines
1.6 KiB
Dart
60 lines
1.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../game/models/piece.dart';
|
|
import 'piece_painter.dart';
|
|
|
|
/// The 3-slot piece tray. Reports raw pan gestures up; the game screen owns
|
|
/// drag state so the lifted piece can float over the board.
|
|
class TrayWidget extends StatelessWidget {
|
|
const TrayWidget({
|
|
super.key,
|
|
required this.tray,
|
|
required this.draggingIndex,
|
|
required this.onDragStart,
|
|
required this.onDragUpdate,
|
|
required this.onDragEnd,
|
|
});
|
|
|
|
final List<Piece> tray;
|
|
final int? draggingIndex;
|
|
final void Function(int index, Offset globalPosition) onDragStart;
|
|
final void Function(Offset globalPosition) onDragUpdate;
|
|
final void Function() onDragEnd;
|
|
|
|
static const double slotCellSize = 16;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SizedBox(
|
|
height: 96,
|
|
child: Row(
|
|
children: [
|
|
for (var i = 0; i < 3; i++)
|
|
Expanded(
|
|
child: i < tray.length
|
|
? _slot(context, i, tray[i])
|
|
: const SizedBox.shrink(),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _slot(BuildContext context, int index, Piece piece) {
|
|
final hidden = index == draggingIndex;
|
|
return GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onPanStart: (d) => onDragStart(index, d.globalPosition),
|
|
onPanUpdate: (d) => onDragUpdate(d.globalPosition),
|
|
onPanEnd: (_) => onDragEnd(),
|
|
onPanCancel: onDragEnd,
|
|
child: Center(
|
|
child: Opacity(
|
|
opacity: hidden ? 0.0 : 1.0,
|
|
child: PieceWidget(piece: piece, cellSize: slotCellSize),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|