import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:mchess/chess_bloc/chess_bloc.dart'; import 'package:mchess/chess_bloc/promotion_bloc.dart'; import '../chess_bloc/chess_events.dart'; import '../utils/chess_utils.dart'; class ChessSquare extends StatelessWidget { final ChessCoordinate coordinate; final ChessPiece? containedPiece; static const double pieceWidth = 200; static const double pieceHeight = 200; final Color color; const ChessSquare._({ required this.coordinate, required this.containedPiece, required this.color, }); factory ChessSquare( ChessCoordinate coord, ChessPiece? piece, bool wasPartOfLastMove) { Color lightSquaresColor = wasPartOfLastMove ? Colors.green.shade200 : Colors.brown.shade50; Color darkSquaresColor = wasPartOfLastMove ? Colors.green.shade300 : Colors.brown.shade400; Color squareColor; if (coord.row % 2 == 0) { if (coord.column % 2 == 0) { squareColor = darkSquaresColor; } else { squareColor = lightSquaresColor; } } else { if (coord.column % 2 == 0) { squareColor = lightSquaresColor; } else { squareColor = darkSquaresColor; } } return ChessSquare._( coordinate: coord, containedPiece: piece, color: squareColor, ); } @override Widget build(BuildContext context) { double windowWidth = MediaQuery.of(context).size.width; double windowHeight = MediaQuery.of(context).size.height; double draggableFdbSize; if (windowWidth < windowHeight) { draggableFdbSize = 0.15 * windowWidth; } else { draggableFdbSize = 0.15 * windowHeight; } return DragTarget( onWillAccept: (move) { if (move?.fromSquare == coordinate) { return false; } return true; }, onAccept: (pieceDragged) { // Replace the dummy value with the actual target of the move. pieceDragged.toSquare = coordinate; if (isPromotionMove(pieceDragged)) { var move = ChessMove( from: pieceDragged.fromSquare, to: pieceDragged.toSquare); PromotionBloc.getInstance().add(PawnMovedToPromotionField( move: move, colorMoved: ChessBloc.myColor!)); } else if (coordinate != pieceDragged.fromSquare) { ChessBloc.getInstance().add(OwnPieceMoved( startSquare: pieceDragged.fromSquare, endSquare: pieceDragged.toSquare, piece: pieceDragged.movedPiece!)); } }, builder: (context, candidateData, rejectedData) { var maxDrags = kDebugMode ? 1 : ((ChessBloc.turnColor == ChessBloc.myColor) && (containedPiece?.color == ChessBloc.turnColor) ? 1 : 0); return Container( color: color, width: ChessSquare.pieceWidth, height: ChessSquare.pieceWidth, child: Draggable( /* We create the move with the startSquare == endSquare. The receiving widget will give the correct value to end square. */ data: PieceDragged(coordinate, coordinate, containedPiece), maxSimultaneousDrags: maxDrags, feedback: FractionalTranslation( translation: const Offset(-0.5, -0.75), child: SizedBox( height: draggableFdbSize, width: draggableFdbSize, child: containedPiece), ), childWhenDragging: Container(), dragAnchorStrategy: pointerDragAnchorStrategy, child: containedPiece ?? Container(), onDragCompleted: () {}, onDragStarted: () {}, ), ); }, ); } bool isPromotionMove(PieceDragged move) { bool isPromotion = false; if (move.movedPiece!.pieceClass != ChessPieceClass.pawn) { return isPromotion; } switch (ChessBloc.myColor) { case ChessColor.black: if (move.toSquare.row == 1) { isPromotion = true; } break; case ChessColor.white: if (move.toSquare.row == 8) { isPromotion = true; } break; case null: break; } return isPromotion; } }