Refactor chess square and prepare display of square in check.
This commit is contained in:
parent
102c0de20d
commit
01dcc74cfc
@ -23,6 +23,7 @@ class ApiWebsocketMessage {
|
|||||||
final ApiColor? color;
|
final ApiColor? color;
|
||||||
final String? reason;
|
final String? reason;
|
||||||
final String? position;
|
final String? position;
|
||||||
|
final ApiCoordinate? squareInCheck;
|
||||||
|
|
||||||
ApiWebsocketMessage({
|
ApiWebsocketMessage({
|
||||||
required this.type,
|
required this.type,
|
||||||
@ -30,6 +31,7 @@ class ApiWebsocketMessage {
|
|||||||
required this.color,
|
required this.color,
|
||||||
required this.reason,
|
required this.reason,
|
||||||
required this.position,
|
required this.position,
|
||||||
|
required this.squareInCheck,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ApiWebsocketMessage.fromJson(Map<String, dynamic> json) {
|
factory ApiWebsocketMessage.fromJson(Map<String, dynamic> json) {
|
||||||
@ -43,6 +45,7 @@ class ApiWebsocketMessage {
|
|||||||
color: ApiColor.fromJson(json['color']),
|
color: ApiColor.fromJson(json['color']),
|
||||||
reason: null,
|
reason: null,
|
||||||
position: null,
|
position: null,
|
||||||
|
squareInCheck: null,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case MessageType.move:
|
case MessageType.move:
|
||||||
@ -52,6 +55,7 @@ class ApiWebsocketMessage {
|
|||||||
color: null,
|
color: null,
|
||||||
reason: null,
|
reason: null,
|
||||||
position: json['position'],
|
position: json['position'],
|
||||||
|
squareInCheck: json['squareInCheck']
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case MessageType.invalidMove:
|
case MessageType.invalidMove:
|
||||||
@ -61,6 +65,7 @@ class ApiWebsocketMessage {
|
|||||||
color: null,
|
color: null,
|
||||||
reason: json['reason'],
|
reason: json['reason'],
|
||||||
position: null,
|
position: null,
|
||||||
|
squareInCheck: json['squareInCheck'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -24,7 +24,7 @@ class ChessBoard extends StatelessWidget {
|
|||||||
bool squareWasPartOfLastMove = false;
|
bool squareWasPartOfLastMove = false;
|
||||||
if ((boardState.lastMove.to == ChessCoordinate(column, row) ||
|
if ((boardState.lastMove.to == ChessCoordinate(column, row) ||
|
||||||
boardState.lastMove.from == ChessCoordinate(column, row)) &&
|
boardState.lastMove.from == ChessCoordinate(column, row)) &&
|
||||||
boardState.positionAckd) {
|
boardState.positionAckdByServer) {
|
||||||
squareWasPartOfLastMove = true;
|
squareWasPartOfLastMove = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mchess/chess/chess_square_outer_dragtarget.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';
|
import '../utils/chess_utils.dart';
|
||||||
|
|
||||||
class ChessSquare extends StatelessWidget {
|
class ChessSquare extends StatelessWidget {
|
||||||
@ -53,94 +48,11 @@ class ChessSquare extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
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<PieceDragged>(
|
|
||||||
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(
|
return Container(
|
||||||
color: color,
|
color: color,
|
||||||
width: ChessSquare.pieceWidth,
|
child: ChessSquareOuterDragTarget(
|
||||||
height: ChessSquare.pieceWidth,
|
coordinate: coordinate,
|
||||||
child: Draggable<PieceDragged>(
|
containedPiece: containedPiece ?? const ChessPiece.none()),
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
55
lib/chess/chess_square_inner_draggable.dart
Normal file
55
lib/chess/chess_square_inner_draggable.dart
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mchess/chess/chess_square.dart';
|
||||||
|
import 'package:mchess/chess_bloc/chess_bloc.dart';
|
||||||
|
import 'package:mchess/utils/chess_utils.dart';
|
||||||
|
|
||||||
|
class ChessSquareInnerDraggable extends StatelessWidget {
|
||||||
|
const ChessSquareInnerDraggable({
|
||||||
|
super.key,
|
||||||
|
required this.coordinate,
|
||||||
|
required this.containedPiece,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ChessCoordinate coordinate;
|
||||||
|
final ChessPiece? containedPiece;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
double windowWidth = MediaQuery.of(context).size.width;
|
||||||
|
double windowHeight = MediaQuery.of(context).size.height;
|
||||||
|
double draggableFdbSize;
|
||||||
|
|
||||||
|
var canMove = (ChessBloc.turnColor == ChessBloc.myColor) &&
|
||||||
|
(containedPiece?.color == ChessBloc.turnColor);
|
||||||
|
var maxDrags = kDebugMode ? 1 : (canMove ? 1 : 0);
|
||||||
|
|
||||||
|
if (windowWidth < windowHeight) {
|
||||||
|
draggableFdbSize = 0.15 * windowWidth;
|
||||||
|
} else {
|
||||||
|
draggableFdbSize = 0.15 * windowHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SizedBox(
|
||||||
|
width: ChessSquare.pieceWidth,
|
||||||
|
height: ChessSquare.pieceWidth,
|
||||||
|
child: Draggable<PieceDragged>(
|
||||||
|
/* 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: () {},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
74
lib/chess/chess_square_outer_dragtarget.dart
Normal file
74
lib/chess/chess_square_outer_dragtarget.dart
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mchess/chess/chess_square_inner_draggable.dart';
|
||||||
|
import 'package:mchess/chess_bloc/chess_bloc.dart';
|
||||||
|
import 'package:mchess/chess_bloc/chess_events.dart';
|
||||||
|
import 'package:mchess/chess_bloc/promotion_bloc.dart';
|
||||||
|
import 'package:mchess/utils/chess_utils.dart';
|
||||||
|
|
||||||
|
class ChessSquareOuterDragTarget extends StatelessWidget {
|
||||||
|
final ChessCoordinate coordinate;
|
||||||
|
final ChessPiece containedPiece;
|
||||||
|
|
||||||
|
const ChessSquareOuterDragTarget(
|
||||||
|
{super.key,
|
||||||
|
required this.coordinate,
|
||||||
|
required this.containedPiece});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DragTarget<PieceDragged>(
|
||||||
|
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) {
|
||||||
|
return ChessSquareInnerDraggable(
|
||||||
|
coordinate: coordinate,
|
||||||
|
containedPiece: containedPiece,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:mchess/chess_bloc/chess_bloc.dart';
|
|
||||||
|
|
||||||
import '../utils/chess_utils.dart';
|
|
||||||
|
|
||||||
class TurnIndicator extends StatelessWidget {
|
|
||||||
const TurnIndicator({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocBuilder<ChessBloc, ChessBoardState>(
|
|
||||||
builder: (context, state) => Text(
|
|
||||||
state.newTurnColor == ChessColor.white ? "white" : "black",
|
|
||||||
style: const TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -44,6 +44,7 @@ class ChessBloc extends Bloc<ChessEvent, ChessBoardState> {
|
|||||||
ChessPositionManager.getInstance().currentPosition,
|
ChessPositionManager.getInstance().currentPosition,
|
||||||
ChessMove.none(),
|
ChessMove.none(),
|
||||||
false,
|
false,
|
||||||
|
ChessCoordinate.none(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -58,6 +59,7 @@ class ChessBloc extends Bloc<ChessEvent, ChessBoardState> {
|
|||||||
state.position,
|
state.position,
|
||||||
ChessMove.none(),
|
ChessMove.none(),
|
||||||
false,
|
false,
|
||||||
|
ChessCoordinate.none(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -79,6 +81,7 @@ class ChessBloc extends Bloc<ChessEvent, ChessBoardState> {
|
|||||||
event.position,
|
event.position,
|
||||||
ChessMove(from: event.startSquare, to: event.endSquare),
|
ChessMove(from: event.startSquare, to: event.endSquare),
|
||||||
true,
|
true,
|
||||||
|
event.squareInCheck,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -93,6 +96,7 @@ class ChessBloc extends Bloc<ChessEvent, ChessBoardState> {
|
|||||||
color: null,
|
color: null,
|
||||||
reason: null,
|
reason: null,
|
||||||
position: null,
|
position: null,
|
||||||
|
squareInCheck: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
ServerConnection.getInstance().send(jsonEncode(apiMessage));
|
ServerConnection.getInstance().send(jsonEncode(apiMessage));
|
||||||
@ -104,7 +108,8 @@ class ChessBloc extends Bloc<ChessEvent, ChessBoardState> {
|
|||||||
tempPosition[move.from] = const ChessPiece.none();
|
tempPosition[move.from] = const ChessPiece.none();
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
ChessBoardState(state.bottomColor, turnColor, tempPosition, move, false),
|
ChessBoardState(state.bottomColor, turnColor, tempPosition, move, false,
|
||||||
|
ChessCoordinate.none()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +125,7 @@ class ChessBloc extends Bloc<ChessEvent, ChessBoardState> {
|
|||||||
color: null,
|
color: null,
|
||||||
reason: null,
|
reason: null,
|
||||||
position: null,
|
position: null,
|
||||||
|
squareInCheck: null,
|
||||||
);
|
);
|
||||||
log(jsonEncode(message));
|
log(jsonEncode(message));
|
||||||
ServerConnection.getInstance().send(jsonEncode(message));
|
ServerConnection.getInstance().send(jsonEncode(message));
|
||||||
@ -128,8 +134,14 @@ class ChessBloc extends Bloc<ChessEvent, ChessBoardState> {
|
|||||||
void invalidMoveHandler(
|
void invalidMoveHandler(
|
||||||
InvalidMovePlayed event, Emitter<ChessBoardState> emit) {
|
InvalidMovePlayed event, Emitter<ChessBoardState> emit) {
|
||||||
emit(
|
emit(
|
||||||
ChessBoardState(state.bottomColor, turnColor,
|
ChessBoardState(
|
||||||
ChessPositionManager.getInstance().currentPosition, ChessMove.none(), false),
|
state.bottomColor,
|
||||||
|
turnColor,
|
||||||
|
ChessPositionManager.getInstance().currentPosition,
|
||||||
|
ChessMove.none(),
|
||||||
|
false,
|
||||||
|
event.squareInCheck,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,10 +151,17 @@ class ChessBoardState {
|
|||||||
final ChessColor newTurnColor;
|
final ChessColor newTurnColor;
|
||||||
final ChessPosition position;
|
final ChessPosition position;
|
||||||
final ChessMove lastMove;
|
final ChessMove lastMove;
|
||||||
final bool positionAckd;
|
final bool positionAckdByServer;
|
||||||
|
final ChessCoordinate squareInCheck;
|
||||||
|
|
||||||
ChessBoardState._(
|
ChessBoardState._(
|
||||||
this.bottomColor, this.newTurnColor, this.position, this.lastMove, this.positionAckd);
|
this.bottomColor,
|
||||||
|
this.newTurnColor,
|
||||||
|
this.position,
|
||||||
|
this.lastMove,
|
||||||
|
this.positionAckdByServer,
|
||||||
|
this.squareInCheck,
|
||||||
|
);
|
||||||
|
|
||||||
factory ChessBoardState(
|
factory ChessBoardState(
|
||||||
ChessColor bottomColor,
|
ChessColor bottomColor,
|
||||||
@ -150,8 +169,10 @@ class ChessBoardState {
|
|||||||
ChessPosition position,
|
ChessPosition position,
|
||||||
ChessMove lastMove,
|
ChessMove lastMove,
|
||||||
bool positionAckd,
|
bool positionAckd,
|
||||||
|
ChessCoordinate squareInCheck,
|
||||||
) {
|
) {
|
||||||
return ChessBoardState._(bottomColor, turnColor, position, lastMove, positionAckd);
|
return ChessBoardState._(bottomColor, turnColor, position, lastMove,
|
||||||
|
positionAckd, squareInCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory ChessBoardState.init() {
|
factory ChessBoardState.init() {
|
||||||
@ -166,6 +187,7 @@ class ChessBoardState {
|
|||||||
ChessPositionManager.getInstance().currentPosition,
|
ChessPositionManager.getInstance().currentPosition,
|
||||||
ChessMove.none(),
|
ChessMove.none(),
|
||||||
false,
|
false,
|
||||||
|
ChessCoordinate.none(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,14 @@ class ReceivedMove extends ChessEvent {
|
|||||||
final ChessCoordinate startSquare;
|
final ChessCoordinate startSquare;
|
||||||
final ChessCoordinate endSquare;
|
final ChessCoordinate endSquare;
|
||||||
final ChessPosition position;
|
final ChessPosition position;
|
||||||
|
final ChessCoordinate squareInCheck;
|
||||||
|
|
||||||
ReceivedMove({required this.startSquare, required this.endSquare, required this.position});
|
ReceivedMove({
|
||||||
|
required this.startSquare,
|
||||||
|
required this.endSquare,
|
||||||
|
required this.position,
|
||||||
|
required this.squareInCheck,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class OwnPieceMoved extends ChessEvent {
|
class OwnPieceMoved extends ChessEvent {
|
||||||
@ -41,6 +47,10 @@ class ColorDetermined extends ChessEvent {
|
|||||||
|
|
||||||
class InvalidMovePlayed extends ChessEvent {
|
class InvalidMovePlayed extends ChessEvent {
|
||||||
final ChessMove move;
|
final ChessMove move;
|
||||||
|
final ChessCoordinate squareInCheck;
|
||||||
|
|
||||||
InvalidMovePlayed({required this.move});
|
InvalidMovePlayed({
|
||||||
|
required this.move,
|
||||||
|
required this.squareInCheck,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:mchess/api/move.dart';
|
||||||
import 'package:mchess/api/websocket_message.dart';
|
import 'package:mchess/api/websocket_message.dart';
|
||||||
import 'package:mchess/chess_bloc/chess_bloc.dart';
|
import 'package:mchess/chess_bloc/chess_bloc.dart';
|
||||||
import 'package:mchess/chess_bloc/chess_events.dart';
|
import 'package:mchess/chess_bloc/chess_events.dart';
|
||||||
@ -88,11 +89,16 @@ class ServerConnection {
|
|||||||
var move = ChessMove.fromApiMove(apiMessage.move!);
|
var move = ChessMove.fromApiMove(apiMessage.move!);
|
||||||
|
|
||||||
if (apiMessage.position != null) {
|
if (apiMessage.position != null) {
|
||||||
ChessBloc.getInstance().add(ReceivedMove(
|
ChessBloc.getInstance().add(
|
||||||
|
ReceivedMove(
|
||||||
startSquare: move.from,
|
startSquare: move.from,
|
||||||
endSquare: move.to,
|
endSquare: move.to,
|
||||||
position: ChessPositionManager.getInstance()
|
position: ChessPositionManager.getInstance()
|
||||||
.fromPGNString(apiMessage.position!)));
|
.fromPGNString(apiMessage.position!),
|
||||||
|
squareInCheck:
|
||||||
|
ChessCoordinate.fromApiCoordinate(apiMessage.squareInCheck ?? const ApiCoordinate(col: 0, row: 0)),
|
||||||
|
),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
log('Error: no position received');
|
log('Error: no position received');
|
||||||
}
|
}
|
||||||
@ -100,7 +106,12 @@ class ServerConnection {
|
|||||||
|
|
||||||
void handleInvalidMoveMessage(ApiWebsocketMessage apiMessage) {
|
void handleInvalidMoveMessage(ApiWebsocketMessage apiMessage) {
|
||||||
log("invalid move message received, with move: ${apiMessage.move.toString()}");
|
log("invalid move message received, with move: ${apiMessage.move.toString()}");
|
||||||
ChessBloc.getInstance()
|
ChessBloc.getInstance().add(
|
||||||
.add(InvalidMovePlayed(move: ChessMove.fromApiMove(apiMessage.move!)));
|
InvalidMovePlayed(
|
||||||
|
move: ChessMove.fromApiMove(apiMessage.move!),
|
||||||
|
squareInCheck:
|
||||||
|
ChessCoordinate.fromApiCoordinate(apiMessage.squareInCheck!),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,33 @@ Map<ChessPieceAssetKey, String> chessPiecesShortName = {
|
|||||||
): '-',
|
): '-',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Map<ChessPieceAssetKey, String> pieceCharacter = {
|
||||||
|
ChessPieceAssetKey(pieceClass: ChessPieceClass.pawn, color: ChessColor.white):
|
||||||
|
"♙",
|
||||||
|
ChessPieceAssetKey(pieceClass: ChessPieceClass.rook, color: ChessColor.white):
|
||||||
|
"♖",
|
||||||
|
ChessPieceAssetKey(
|
||||||
|
pieceClass: ChessPieceClass.knight, color: ChessColor.white): "♘",
|
||||||
|
ChessPieceAssetKey(
|
||||||
|
pieceClass: ChessPieceClass.bishop, color: ChessColor.white): "♗",
|
||||||
|
ChessPieceAssetKey(pieceClass: ChessPieceClass.king, color: ChessColor.white):
|
||||||
|
"♔",
|
||||||
|
ChessPieceAssetKey(
|
||||||
|
pieceClass: ChessPieceClass.queen, color: ChessColor.white): "♕",
|
||||||
|
ChessPieceAssetKey(pieceClass: ChessPieceClass.pawn, color: ChessColor.black):
|
||||||
|
"♟︎",
|
||||||
|
ChessPieceAssetKey(pieceClass: ChessPieceClass.rook, color: ChessColor.black):
|
||||||
|
"♜",
|
||||||
|
ChessPieceAssetKey(
|
||||||
|
pieceClass: ChessPieceClass.knight, color: ChessColor.black): "♞",
|
||||||
|
ChessPieceAssetKey(
|
||||||
|
pieceClass: ChessPieceClass.bishop, color: ChessColor.black): "♝",
|
||||||
|
ChessPieceAssetKey(pieceClass: ChessPieceClass.king, color: ChessColor.black):
|
||||||
|
"♚",
|
||||||
|
ChessPieceAssetKey(
|
||||||
|
pieceClass: ChessPieceClass.queen, color: ChessColor.black): "♛",
|
||||||
|
};
|
||||||
|
|
||||||
Map<String, ChessPiece> pieceFromShortname = {
|
Map<String, ChessPiece> pieceFromShortname = {
|
||||||
'P': ChessPiece(ChessPieceClass.pawn, ChessColor.white),
|
'P': ChessPiece(ChessPieceClass.pawn, ChessColor.white),
|
||||||
'R': ChessPiece(ChessPieceClass.rook, ChessColor.white),
|
'R': ChessPiece(ChessPieceClass.rook, ChessColor.white),
|
||||||
@ -171,6 +198,10 @@ class ChessCoordinate {
|
|||||||
return ChessCoordinate(column, row);
|
return ChessCoordinate(column, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
factory ChessCoordinate.none() {
|
||||||
|
return ChessCoordinate(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return hash2(column, row);
|
return hash2(column, row);
|
||||||
|
53
lib/utils/widgets/move_history_widget.dart
Normal file
53
lib/utils/widgets/move_history_widget.dart
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:mchess/chess_bloc/chess_bloc.dart';
|
||||||
|
import 'package:mchess/chess_bloc/chess_position.dart';
|
||||||
|
import 'package:mchess/utils/chess_utils.dart';
|
||||||
|
|
||||||
|
class MoveHistory extends StatefulWidget {
|
||||||
|
const MoveHistory({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MoveHistory> createState() => _MoveHistoryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MoveHistoryState extends State<MoveHistory> {
|
||||||
|
late List<String> entries;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
entries = [];
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocListener<ChessBloc, ChessBoardState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
List<String> newEntries = [];
|
||||||
|
var positionManager = ChessPositionManager.getInstance();
|
||||||
|
var allMoves = positionManager.allMoves;
|
||||||
|
|
||||||
|
for (ChessMove move in allMoves) {
|
||||||
|
var movedPiece = positionManager.getPieceAt(move.to);
|
||||||
|
var char = pieceCharacter[ChessPieceAssetKey(
|
||||||
|
pieceClass: movedPiece!.pieceClass,
|
||||||
|
color: movedPiece.color.getOpposite())];
|
||||||
|
|
||||||
|
if (movedPiece.color == ChessColor.white) {
|
||||||
|
newEntries.add("$char ${move.to.toAlphabetical()}");
|
||||||
|
} else {
|
||||||
|
newEntries.last =
|
||||||
|
"${newEntries.last}\t\t$char${move.to.toAlphabetical()}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
entries = newEntries;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: ListView(children: [
|
||||||
|
for (var entry in entries) Text(entry),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
72
pubspec.lock
72
pubspec.lock
@ -53,10 +53,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.2"
|
version: "1.18.0"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -69,10 +69,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: cupertino_icons
|
name: cupertino_icons
|
||||||
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
|
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.6"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -98,18 +98,18 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_lints
|
name: flutter_lints
|
||||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.3"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_svg
|
name: flutter_svg
|
||||||
sha256: "6ff8c902c8056af9736de2689f63f81c42e2d642b9f4c79dbf8790ae48b63012"
|
sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.6"
|
version: "2.0.7"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -124,18 +124,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: bd7e671d26fd39c78cba82070fa34ef1f830b0e7ed1aeebccabc6561302a7ee5
|
sha256: "5668e6d3dbcb2d0dfa25f7567554b88c57e1e3f3c440b672b24d4a9477017d5b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.5.9"
|
version: "10.1.2"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
|
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -212,10 +212,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: petitparser
|
name: petitparser
|
||||||
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.4.0"
|
version: "6.0.1"
|
||||||
provider:
|
provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -245,22 +245,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.10.0"
|
||||||
|
sprintf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sprintf
|
||||||
|
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -281,10 +289,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.6.1"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -297,34 +305,34 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
|
sha256: e03928880bdbcbf496fb415573f5ab7b1ea99b9b04f669c01104d085893c3134
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.7"
|
version: "4.0.0"
|
||||||
vector_graphics:
|
vector_graphics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics
|
name: vector_graphics
|
||||||
sha256: b96f10cbdfcbd03a65758633a43e7d04574438f059b1043104b5d61b23d38a4f
|
sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_graphics_codec:
|
vector_graphics_codec:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_codec
|
name: vector_graphics_codec
|
||||||
sha256: "57a8e6e24662a3bdfe3b3d61257db91768700c0b8f844e235877b56480f31c69"
|
sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_graphics_compiler:
|
vector_graphics_compiler:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_compiler
|
name: vector_graphics_compiler
|
||||||
sha256: "7430f5d834d0db4560d7b19863362cd892f1e52b43838553a3c5cdfc9ab28e5b"
|
sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -353,10 +361,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xml
|
name: xml
|
||||||
sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
|
sha256: af5e77e9b83f2f4adc5d3f0a4ece1c7f45a2467b695c2540381bac793e34e556
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.0"
|
version: "6.4.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.0-185.0.dev <4.0.0"
|
dart: ">=3.1.0 <4.0.0"
|
||||||
flutter: ">=3.7.0-0"
|
flutter: ">=3.7.0"
|
||||||
|
10
pubspec.yaml
10
pubspec.yaml
@ -16,10 +16,10 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.0+1
|
version: 1.0.1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.19.0-392.0.dev <3.0.0'
|
sdk: ^3.1.0
|
||||||
|
|
||||||
# Dependencies specify other packages that your package needs in order to work.
|
# Dependencies specify other packages that your package needs in order to work.
|
||||||
# To automatically upgrade your package dependencies to the latest versions
|
# To automatically upgrade your package dependencies to the latest versions
|
||||||
@ -38,12 +38,12 @@ dependencies:
|
|||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
flutter_bloc: ^8.1.1
|
flutter_bloc: ^8.1.3
|
||||||
quiver: ^3.1.0
|
quiver: ^3.1.0
|
||||||
web_socket_channel: ^2.2.0
|
web_socket_channel: ^2.2.0
|
||||||
go_router: ^6.0.0
|
go_router: ^10.1.0
|
||||||
http: ^1.0.0
|
http: ^1.0.0
|
||||||
uuid: ^3.0.7
|
uuid: ^4.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -13,7 +13,7 @@ import 'package:uuid/uuid.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||||
// Build our app and trigger a frame.
|
// Build our app and trigger a frame.
|
||||||
await tester.pumpWidget(ChessGame(
|
await tester.pumpWidget(const ChessGame(
|
||||||
playerID: UuidValue("test"),
|
playerID: UuidValue("test"),
|
||||||
lobbyID: UuidValue("testLobbyId"),
|
lobbyID: UuidValue("testLobbyId"),
|
||||||
passphrase: 'test',
|
passphrase: 'test',
|
||||||
|
Loading…
Reference in New Issue
Block a user