Introduce checkmate screen

Show checkmate screen, once the server sends the 'gameEnded' message.

Additionally, show an icon that lets users copy the passphrase to the
clipboard.
This commit is contained in:
Marco 2024-01-17 22:50:02 +01:00
parent 7d55a0e123
commit 13bcfb1131
6 changed files with 103 additions and 16 deletions

View File

@ -4,7 +4,8 @@ enum MessageType {
boardState,
move,
invalidMove,
colorDetermined;
colorDetermined,
gameEnded;
String toJson() => name;
static MessageType fromJson(String json) => values.byName(json);
@ -82,6 +83,16 @@ class ApiWebsocketMessage {
squareInCheck: json['squareInCheck'],
playerColor: null,
);
case MessageType.gameEnded:
ret = ApiWebsocketMessage(
type: type,
move: null,
turnColor: null,
reason: json['reason'],
position: null,
squareInCheck: null,
playerColor: null,
);
}
return ret;
}

View File

@ -1,5 +1,7 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mchess/api/move.dart';
import 'package:mchess/api/websocket_message.dart';
import 'package:mchess/chess_bloc/chess_bloc.dart';
@ -7,7 +9,9 @@ import 'package:mchess/chess_bloc/chess_events.dart';
import 'package:mchess/api/register.dart';
import 'package:mchess/chess_bloc/chess_position.dart';
import 'package:mchess/connection_cubit/connection_cubit.dart';
import 'package:mchess/utils/chess_router.dart';
import 'package:mchess/utils/chess_utils.dart';
import 'package:mchess/utils/config.dart' as config;
import 'package:web_socket_channel/web_socket_channel.dart';
class ServerConnection {
@ -38,9 +42,7 @@ class ServerConnection {
}
void connect(String playerID, lobbyID, String? passphrase) {
String url;
url = 'wss://chess.sw-gross.de:9999/api/ws';
channel = WebSocketChannel.connect(Uri.parse(url));
channel = WebSocketChannel.connect(Uri.parse(config.getWebsocketURL()));
send(
jsonEncode(
@ -82,6 +84,8 @@ class ServerConnection {
case MessageType.invalidMove:
handleInvalidMoveMessage(apiMessage);
case MessageType.gameEnded:
handleGameEndedMessage(apiMessage);
}
}
@ -125,4 +129,29 @@ class ServerConnection {
),
);
}
void handleGameEndedMessage(ApiWebsocketMessage apiMessage) {
showDialog(
context: navigatorKey.currentContext!,
builder: (context) {
String msg = '';
if (apiMessage.reason == 'whiteIsCheckmated') {
msg = 'Black won! White is checkmated';
} else if (apiMessage.reason == 'blackIsCheckmated') {
msg = 'White won! Black is checkmated';
}
return AlertDialog(
title: const Text('Game ended'),
content: Text(msg),
actions: <Widget>[
TextButton(
child: const Text('Home'),
onPressed: () {
navigatorKey.currentContext!.goNamed('lobbySelector');
},
),
]);
},
);
}
}

View File

@ -1,6 +1,7 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart';
@ -10,6 +11,7 @@ import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:mchess/pages/chess_game.dart';
import 'package:mchess/utils/config.dart' as config;
class HostGameWidget extends StatefulWidget {
const HostGameWidget({super.key});
@ -80,9 +82,21 @@ class _HostGameWidgetState extends State<HostGameWidget> {
color: Theme.of(context).colorScheme.primary),
),
const SizedBox(height: 25),
SelectableText(
passphrase,
style: const TextStyle(fontWeight: FontWeight.bold),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SelectableText(
passphrase,
style: const TextStyle(fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(Icons.copy),
onPressed: () async {
await Clipboard.setData(
ClipboardData(text: passphrase));
},
)
],
),
const SizedBox(height: 25),
const CircularProgressIndicator()
@ -97,14 +111,11 @@ class _HostGameWidgetState extends State<HostGameWidget> {
}
Future<PlayerInfo?> hostPrivateGame() async {
String addr;
Response response;
addr = 'https://chess.sw-gross.de:9999/api/hostPrivate';
try {
response = await http
.get(Uri.parse(addr), headers: {"Accept": "application/json"});
response = await http.get(Uri.parse(config.getHostURL()),
headers: {"Accept": "application/json"});
} catch (e) {
log(e.toString());

View File

@ -7,6 +7,7 @@ import 'package:http/http.dart' as http;
import 'package:mchess/api/register.dart';
import 'package:mchess/connection_cubit/connection_cubit.dart';
import 'package:mchess/pages/chess_game.dart';
import 'package:mchess/utils/config.dart' as config;
import 'package:shared_preferences/shared_preferences.dart';
class LobbySelector extends StatefulWidget {
@ -149,17 +150,14 @@ class _LobbySelectorState extends State<LobbySelector> {
}
Future<PlayerInfo?> joinPrivateGame() async {
String addr;
http.Response response;
// server expects us to send the passphrase
var info = PlayerInfo(
playerID: null, lobbyID: null, passphrase: phraseController.text);
addr = 'https://chess.sw-gross.de:9999/api/joinPrivate';
try {
response = await http.post(Uri.parse(addr),
response = await http.post(Uri.parse(config.getJoinURL()),
body: jsonEncode(info), headers: {"Accept": "application/json"});
} catch (e) {
log(e.toString());

View File

@ -1,8 +1,11 @@
import 'package:flutter/widgets.dart';
import 'package:go_router/go_router.dart';
import 'package:mchess/pages/chess_game.dart';
import 'package:mchess/pages/lobby_selector.dart';
import 'package:mchess/pages/host_game.dart';
final navigatorKey = GlobalKey<NavigatorState>();
class ChessAppRouter {
static final ChessAppRouter _instance = ChessAppRouter._internal();
@ -13,6 +16,7 @@ class ChessAppRouter {
}
final router = GoRouter(
navigatorKey: navigatorKey,
debugLogDiagnostics: true,
routes: [
GoRoute(

34
lib/utils/config.dart Normal file
View File

@ -0,0 +1,34 @@
const prodURL = 'chess.sw-gross.de:9999';
const debugURL = 'localhost:8080';
const dbgUrl = false;
String getHostURL() {
var prot = 'https';
var domain = prodURL;
if (dbgUrl) {
prot = 'http';
domain = debugURL;
}
return '$prot://$domain/api/hostPrivate';
}
String getJoinURL() {
var prot = 'https';
var domain = prodURL;
if (dbgUrl) {
prot = 'http';
domain = debugURL;
}
return '$prot://$domain/api/joinPrivate';
}
String getWebsocketURL() {
var prot = 'wss';
var domain = prodURL;
if (dbgUrl) {
prot = 'ws';
domain = debugURL;
}
return '$prot://$domain/api/ws';
}