From 6e5d84364dddfd7106e77f9bf575cfb11e9a8a97 Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 8 Jun 2023 17:10:48 +0200 Subject: [PATCH] Various changes. --- lib/api/websocket_message.dart | 41 +++++++++ lib/chess_bloc/chess_bloc.dart | 18 +++- lib/connection/ws_connection.dart | 23 +++-- lib/pages/chess_game.dart | 2 +- lib/pages/lobby_selector.dart | 12 +-- lib/pages/prepare_chess_game.dart | 90 +++++++++++++++----- lib/utils/chess_utils.dart | 14 +++- lib/utils/widgets/server_log_widget.dart | 16 ++-- pubspec.lock | 102 ++++++++++++++--------- 9 files changed, 237 insertions(+), 81 deletions(-) create mode 100644 lib/api/websocket_message.dart diff --git a/lib/api/websocket_message.dart b/lib/api/websocket_message.dart new file mode 100644 index 0000000..d4eebbc --- /dev/null +++ b/lib/api/websocket_message.dart @@ -0,0 +1,41 @@ +import 'package:mchess/api/move.dart'; + +enum MessageType { + moveMessage, + colorDetermined; + + String toJson() => name; + static MessageType fromJson(String json) => values.byName(json); +} + +enum ApiColor { + black, + white; + + String toJson() => name; + static ApiColor fromJson(String json) => values.byName(json); +} + +class ApiWebsocketMessage { + final MessageType type; + final ApiMove? move; + final ApiColor? color; + + ApiWebsocketMessage( + {required this.type, required this.move, required this.color}); + + factory ApiWebsocketMessage.fromJson(Map json) { + final type = MessageType.fromJson(json['messageType']); + ApiWebsocketMessage ret; + switch (type) { + case MessageType.colorDetermined: + ret = ApiWebsocketMessage( + type: type, move: null, color: ApiColor.fromJson(json['color'])); + break; + case MessageType.moveMessage: + ret = ApiWebsocketMessage( + type: type, move: ApiMove.fromJson(json['move']), color: null); + } + return ret; + } +} diff --git a/lib/chess_bloc/chess_bloc.dart b/lib/chess_bloc/chess_bloc.dart index 7426ef6..f4f8fab 100644 --- a/lib/chess_bloc/chess_bloc.dart +++ b/lib/chess_bloc/chess_bloc.dart @@ -51,8 +51,6 @@ class ChessBloc extends Bloc { ? ChessColor.black : ChessColor.white; - log('emitting new state with position $newPosition'); - emit( ChessBoardState( state.bottomColor, @@ -60,6 +58,7 @@ class ChessBloc extends Bloc { newPosition, ), ); + log('emitting new state with position $newPosition'); } void ownMoveHandler(OwnPieceMoved event, Emitter emit) { @@ -72,6 +71,21 @@ class ChessBloc extends Bloc { var move = ApiMove(startSquare: start, endSquare: end); ServerConnection.getInstance().send(jsonEncode(move)); + + turnColor = state.newTurnColor == ChessColor.white + ? ChessColor.black + : ChessColor.white; + + var newPosition = ChessPosition.getInstance().currentPosition; + + emit( + ChessBoardState( + state.bottomColor, + turnColor, + newPosition, + ), + ); + log('emitting new state with position $newPosition'); } } diff --git a/lib/connection/ws_connection.dart b/lib/connection/ws_connection.dart index 131733f..1e7f9a8 100644 --- a/lib/connection/ws_connection.dart +++ b/lib/connection/ws_connection.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'dart:developer'; import 'package:flutter/foundation.dart'; -import 'package:mchess/api/move.dart'; +import 'package:mchess/api/websocket_message.dart'; import 'package:mchess/chess_bloc/chess_bloc.dart'; import 'package:mchess/chess_bloc/chess_events.dart'; import 'package:mchess/chess_bloc/chess_position.dart'; @@ -41,8 +41,8 @@ class ServerConnection { channel = WebSocketChannel.connect(Uri.parse('ws://localhost:8080/api/ws')); } else { - channel = - WebSocketChannel.connect(Uri.parse('wss://chess.sw-gross.de:8080')); + channel = WebSocketChannel.connect( + Uri.parse('wss://chess.sw-gross.de:9999/api/ws')); } send(jsonEncode(WebsocketMessageIdentifyPlayer( playerID: (playerID), lobbyID: (lobbyID)))); @@ -59,12 +59,21 @@ class ServerConnection { void handleIncomingData(dynamic data) { log("Data received:"); log(data); - var apiMove = ApiMove.fromJson(jsonDecode(data)); + var apiMessage = ApiWebsocketMessage.fromJson(jsonDecode(data)); -//Todo: Implement status messages -// e.g. to tell the client that both players connected, who is playing which color and so on + switch (apiMessage.type) { + case MessageType.colorDetermined: + ChessBloc.getInstance().add(ColorDetermined( + myColor: ChessColor.fromApiColor(apiMessage.color!))); + break; - var move = ChessMove.fromApiMove(apiMove); + case MessageType.moveMessage: + handleIncomingMoveMessage(apiMessage); + } + } + + void handleIncomingMoveMessage(ApiWebsocketMessage apiMessage) { + var move = ChessMove.fromApiMove(apiMessage.move!); if (move == ChessPosition.getInstance().lastMove) { //This is our own move that got resent by the server. Do not process. } else { diff --git a/lib/pages/chess_game.dart b/lib/pages/chess_game.dart index a10d185..a442dd7 100644 --- a/lib/pages/chess_game.dart +++ b/lib/pages/chess_game.dart @@ -35,7 +35,7 @@ class _ChessGameState extends State { body: Center( child: FittedBox( fit: BoxFit.contain, - child: Row( + child: Column( children: [ if (kDebugMode) StreamBuilder( diff --git a/lib/pages/lobby_selector.dart b/lib/pages/lobby_selector.dart index 88f9aa4..58bd720 100644 --- a/lib/pages/lobby_selector.dart +++ b/lib/pages/lobby_selector.dart @@ -7,11 +7,13 @@ class LobbySelector extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - body: TextButton( - onPressed: () { - context.goNamed('prepareChessGame'); - }, - child: const Text('Random lobby'), + body: Center( + child: TextButton( + onPressed: () { + context.goNamed('prepareChessGame'); + }, + child: const Text('Random lobby'), + ), ), ); } diff --git a/lib/pages/prepare_chess_game.dart b/lib/pages/prepare_chess_game.dart index 48f4843..cd40448 100644 --- a/lib/pages/prepare_chess_game.dart +++ b/lib/pages/prepare_chess_game.dart @@ -1,43 +1,93 @@ import 'dart:developer'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:http/http.dart'; import 'package:mchess/api/register.dart'; import 'package:mchess/pages/chess_game.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; -class PrepareChessGameWidget extends StatelessWidget { +class PrepareChessGameWidget extends StatefulWidget { const PrepareChessGameWidget({super.key}); + @override + State createState() => _PrepareChessGameWidgetState(); +} + +class _PrepareChessGameWidgetState extends State { + late Future randomGameResponse; + + @override + void initState() { + randomGameResponse = registerForRandomGame(); + super.initState(); + } + @override Widget build(BuildContext context) { - return FutureBuilder( - future: registerForRandomGame(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - log('future done ${snapshot.data?.playerID}'); - return ChessGame( - playerID: snapshot.data!.playerID, - lobbyID: snapshot.data!.lobbyID, + return Scaffold( + body: FutureBuilder( + future: randomGameResponse, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + log('Response from registering to random game ${snapshot.data}'); + + if (snapshot.data != null) { + return ChessGame( + playerID: snapshot.data!.playerID, + lobbyID: snapshot.data!.lobbyID, + ); + } + } + return const Center( + child: SizedBox( + height: 100, + width: 100, + child: CircularProgressIndicator(), + ), ); - } - return const CircularProgressIndicator(); - }, + }, + ), ); } - Future registerForRandomGame() async { - final response = await http.get( - Uri.parse('http://localhost:8080/api/random'), - headers: {"Accept": "application/json"}); + Future registerForRandomGame() async { + String addr; + if (kDebugMode) { + addr = 'http://localhost:8080/api/random'; + } else { + addr = 'https://chess.sw-gross.de:9999/api/random'; + } + + Response response; + + try { + response = await http + .get(Uri.parse(addr), headers: {"Accept": "application/json"}); + } catch (e) { + const snackBar = SnackBar( + backgroundColor: Colors.amberAccent, + content: + Text("mChess server is not responding. Try again or give up")); + + if (!context.mounted) return null; + + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + + Future.delayed(const Duration(seconds: 2), () { + context.goNamed('lobbySelector'); + }); + + return null; + } if (response.statusCode == 200) { log(response.body); return ResponseFromRegisteringGame.fromJson(jsonDecode(response.body)); - } else { - // If the server did not return a 200 OK response, - // then throw an exception. - throw Exception('Failed to register for random game'); } + return null; } } diff --git a/lib/utils/chess_utils.dart b/lib/utils/chess_utils.dart index e2f21e3..8bcb4e8 100644 --- a/lib/utils/chess_utils.dart +++ b/lib/utils/chess_utils.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:mchess/api/move.dart'; +import 'package:mchess/api/websocket_message.dart'; import 'package:quiver/core.dart'; enum ChessPieceName { @@ -19,7 +20,18 @@ enum ChessPieceName { blackKing, } -enum ChessColor { black, white } +enum ChessColor { + black, + white; + + static ChessColor fromApiColor(ApiColor color) { + if (color == ApiColor.black) { + return black; + } else { + return white; + } + } +} Map chessPiecesAssets = { ChessPieceName.whitePawn: 'assets/pieces/white/pawn.svg', diff --git a/lib/utils/widgets/server_log_widget.dart b/lib/utils/widgets/server_log_widget.dart index c97e926..84e3c21 100644 --- a/lib/utils/widgets/server_log_widget.dart +++ b/lib/utils/widgets/server_log_widget.dart @@ -18,12 +18,16 @@ class ServerLogWidgetState extends State { @override Widget build(BuildContext context) { log.add(widget.addString); - - return Column( - children: [ - for (int i = 0; i < log.length; i++) - Text(style: TextStyle(color: widget.textColor, fontSize: 20), log[i]) - ], + return SizedBox( + height: 200, + width: 200, + child: ListView( + children: [ + for (int i = 0; i < log.length; i++) + Text( + style: TextStyle(color: widget.textColor, fontSize: 20), log[i]) + ], + ), ); } } diff --git a/pubspec.lock b/pubspec.lock index e341f79..9c0d7d9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: @@ -13,10 +21,10 @@ packages: dependency: transitive description: name: bloc - sha256: bd4f8027bfa60d96c8046dec5ce74c463b2c918dce1b0d36593575995344534a + sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49" url: "https://pub.dev" source: hosted - version: "8.1.0" + version: "8.1.2" boolean_selector: dependency: transitive description: @@ -53,10 +61,10 @@ packages: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -82,10 +90,10 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: "890c51c8007f0182360e523518a0c732efb89876cb4669307af7efada5b55557" + sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae url: "https://pub.dev" source: hosted - version: "8.1.1" + version: "8.1.3" flutter_lints: dependency: "direct dev" description: @@ -98,10 +106,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" + sha256: "6ff8c902c8056af9736de2689f63f81c42e2d642b9f4c79dbf8790ae48b63012" url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "2.0.6" flutter_test: dependency: "direct dev" description: flutter @@ -116,10 +124,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "788a89932142b0059c319e3153e73308e0fc8bbab78e9a66b0128423090c4e01" + sha256: bd7e671d26fd39c78cba82070fa34ef1f830b0e7ed1aeebccabc6561302a7ee5 url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.5.9" http: dependency: "direct main" description: @@ -148,26 +156,26 @@ packages: dependency: transitive description: name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.1" logging: dependency: transitive description: name: logging - sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" matcher: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: @@ -200,14 +208,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" - path_drawing: - dependency: transitive - description: - name: path_drawing - sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 - url: "https://pub.dev" - source: hosted - version: "1.0.1" path_parsing: dependency: transitive description: @@ -220,26 +220,26 @@ packages: dependency: transitive description: name: petitparser - sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.4.0" provider: dependency: transitive description: name: provider - sha256: e1e7413d70444ea3096815a60fe5da1b11bda8a9dc4769252cc82c53536f8bcc + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f url: "https://pub.dev" source: hosted - version: "6.0.4" + version: "6.0.5" quiver: dependency: "direct main" description: name: quiver - sha256: "93982981971e812c94d4a6fa3a57b89f9ec12b38b6380cd3c1370c3b01e4580e" + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.1" sky_engine: dependency: transitive description: flutter @@ -289,18 +289,18 @@ packages: dependency: transitive description: name: test_api - sha256: daadc9baabec998b062c9091525aa95786508b1c48e9c30f1f891b8bf6ff2e64 + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.2" + version: "0.6.0" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" uuid: dependency: "direct main" description: @@ -309,6 +309,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: b96f10cbdfcbd03a65758633a43e7d04574438f059b1043104b5d61b23d38a4f + url: "https://pub.dev" + source: hosted + version: "1.1.6" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "57a8e6e24662a3bdfe3b3d61257db91768700c0b8f844e235877b56480f31c69" + url: "https://pub.dev" + source: hosted + version: "1.1.6" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "7430f5d834d0db4560d7b19863362cd892f1e52b43838553a3c5cdfc9ab28e5b" + url: "https://pub.dev" + source: hosted + version: "1.1.6" vector_math: dependency: transitive description: @@ -321,18 +345,18 @@ packages: dependency: "direct main" description: name: web_socket_channel - sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.0" xml: dependency: transitive description: name: xml - sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.3.0" sdks: dart: ">=3.0.0 <4.0.0" - flutter: ">=3.3.0" + flutter: ">=3.7.0-0"