2023-12-23 15:44:23 +00:00
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:developer';
|
2024-02-05 09:35:28 +00:00
|
|
|
import 'dart:io';
|
2023-12-23 15:44:23 +00:00
|
|
|
|
2022-12-25 15:16:23 +00:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:go_router/go_router.dart';
|
2023-12-23 15:44:23 +00:00
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import 'package:mchess/api/register.dart';
|
2024-05-15 17:42:18 +00:00
|
|
|
import 'package:mchess/connection/ws_connection.dart';
|
2023-12-23 15:44:23 +00:00
|
|
|
import 'package:mchess/connection_cubit/connection_cubit.dart';
|
|
|
|
import 'package:mchess/pages/chess_game.dart';
|
2024-01-17 21:50:02 +00:00
|
|
|
import 'package:mchess/utils/config.dart' as config;
|
2022-12-25 15:16:23 +00:00
|
|
|
|
2023-12-23 15:44:23 +00:00
|
|
|
class LobbySelector extends StatefulWidget {
|
2022-12-25 15:16:23 +00:00
|
|
|
const LobbySelector({super.key});
|
|
|
|
|
2023-12-23 15:44:23 +00:00
|
|
|
@override
|
|
|
|
State<LobbySelector> createState() => _LobbySelectorState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _LobbySelectorState extends State<LobbySelector> {
|
2023-06-29 23:49:18 +00:00
|
|
|
final buttonStyle = const ButtonStyle();
|
2023-12-27 14:46:15 +00:00
|
|
|
final phraseController = TextEditingController();
|
2023-12-23 15:44:23 +00:00
|
|
|
late Future<PlayerInfo?> joinGameFuture;
|
2023-06-29 23:49:18 +00:00
|
|
|
|
2022-12-25 15:16:23 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2022-12-25 19:18:50 +00:00
|
|
|
return Scaffold(
|
2023-06-08 15:10:48 +00:00
|
|
|
body: Center(
|
2023-06-29 23:49:18 +00:00
|
|
|
child: Column(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
ElevatedButton(
|
2023-12-27 14:46:15 +00:00
|
|
|
onPressed: () => buildJoinOrHostDialog(context),
|
2023-06-29 23:49:18 +00:00
|
|
|
child: const Row(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
Icon(Icons.lock),
|
|
|
|
SizedBox(
|
|
|
|
width: 10,
|
|
|
|
),
|
2023-08-14 15:04:25 +00:00
|
|
|
Text('Private game')
|
2023-06-29 23:49:18 +00:00
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
2023-06-08 15:10:48 +00:00
|
|
|
),
|
2022-12-25 19:18:50 +00:00
|
|
|
),
|
2022-12-25 15:16:23 +00:00
|
|
|
);
|
|
|
|
}
|
2023-06-29 23:49:18 +00:00
|
|
|
|
2023-12-23 15:44:23 +00:00
|
|
|
Future<void> buildJoinOrHostDialog(BuildContext context) {
|
2024-05-15 17:42:18 +00:00
|
|
|
//TODO: find a better place to disconnect old websocket connection
|
|
|
|
ServerConnection.getInstance().disconnectExistingConnection();
|
|
|
|
|
2023-12-23 15:44:23 +00:00
|
|
|
return showDialog<void>(
|
|
|
|
context: context,
|
2024-02-05 09:39:01 +00:00
|
|
|
builder: (BuildContext context) {
|
2023-12-23 15:44:23 +00:00
|
|
|
return Scaffold(
|
2024-05-11 17:58:29 +00:00
|
|
|
backgroundColor: Colors.transparent,
|
2023-12-23 15:44:23 +00:00
|
|
|
body: AlertDialog(
|
|
|
|
title: const Text('Host or join?'),
|
|
|
|
actions: <Widget>[
|
|
|
|
TextButton(
|
|
|
|
child: const Text('Cancel'),
|
2024-02-05 09:39:01 +00:00
|
|
|
onPressed: () => context.pop(),
|
2023-12-23 15:44:23 +00:00
|
|
|
),
|
|
|
|
TextButton(
|
2023-12-27 14:46:15 +00:00
|
|
|
child: const Text('Host'),
|
|
|
|
onPressed: () {
|
2024-02-05 09:39:01 +00:00
|
|
|
context.pop(); //close dialog before going to host
|
|
|
|
context.goNamed('host');
|
2023-12-27 14:46:15 +00:00
|
|
|
}),
|
2023-12-23 15:44:23 +00:00
|
|
|
TextButton(
|
|
|
|
child: const Text('Join'),
|
|
|
|
onPressed: () {
|
2024-02-05 09:39:01 +00:00
|
|
|
context.pop(); //close dialog before going to next dialog
|
|
|
|
buildEnterPassphraseDialog(context);
|
2023-12-23 15:44:23 +00:00
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> buildEnterPassphraseDialog(BuildContext context) {
|
2023-06-29 23:49:18 +00:00
|
|
|
return showDialog<void>(
|
|
|
|
context: context,
|
|
|
|
builder: (BuildContext context) {
|
2024-02-05 09:35:28 +00:00
|
|
|
return ScaffoldMessenger(
|
|
|
|
child: Builder(builder: (builderContext) {
|
|
|
|
return Scaffold(
|
|
|
|
backgroundColor: Colors.transparent,
|
|
|
|
body: AlertDialog(
|
|
|
|
title: const Text('Enter the passphrase here:'),
|
|
|
|
content: TextField(
|
|
|
|
controller: phraseController,
|
2024-05-11 17:58:29 +00:00
|
|
|
onSubmitted: (val) {
|
|
|
|
submitPassphrase(builderContext);
|
|
|
|
},
|
2024-02-05 09:35:28 +00:00
|
|
|
decoration: InputDecoration(
|
|
|
|
hintText: 'Enter passphrase here',
|
|
|
|
suffixIcon: IconButton(
|
|
|
|
onPressed: () {
|
2024-05-11 17:58:29 +00:00
|
|
|
submitPassphrase(builderContext);
|
2024-02-05 09:35:28 +00:00
|
|
|
},
|
|
|
|
icon: const Icon(Icons.check),
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
actions: <Widget>[
|
|
|
|
TextButton(
|
|
|
|
child: const Text('Cancel'),
|
|
|
|
onPressed: () {
|
|
|
|
builderContext.pop();
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}),
|
2023-06-29 23:49:18 +00:00
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2023-12-23 15:44:23 +00:00
|
|
|
|
2024-05-11 17:58:29 +00:00
|
|
|
void submitPassphrase(BuildContext ctx) {
|
|
|
|
joinGameFuture = joinPrivateGame(ctx);
|
|
|
|
joinGameFuture.then((value) {
|
|
|
|
if (value != null) {
|
|
|
|
phraseController.clear();
|
|
|
|
ctx.pop();
|
|
|
|
switchToGame(value);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-12-23 15:44:23 +00:00
|
|
|
void switchToGame(PlayerInfo info) {
|
|
|
|
var chessGameArgs = ChessGameArguments(
|
|
|
|
lobbyID: info.lobbyID!,
|
|
|
|
playerID: info.playerID!,
|
|
|
|
passphrase: info.passphrase);
|
|
|
|
|
|
|
|
ConnectionCubit.getInstance().connect(
|
|
|
|
info.playerID!.uuid,
|
|
|
|
info.lobbyID!.uuid,
|
|
|
|
info.passphrase,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!chessGameArgs.isValid()) {
|
2023-12-25 16:50:58 +00:00
|
|
|
context.goNamed('lobbySelector');
|
2023-12-23 15:44:23 +00:00
|
|
|
const snackBar = SnackBar(
|
|
|
|
backgroundColor: Colors.amberAccent,
|
|
|
|
content: Text("Game information is corrupted"),
|
|
|
|
);
|
|
|
|
ScaffoldMessenger.of(context).clearSnackBars();
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
2024-02-05 09:35:28 +00:00
|
|
|
|
|
|
|
return;
|
2023-12-23 15:44:23 +00:00
|
|
|
}
|
|
|
|
|
2023-12-27 14:46:15 +00:00
|
|
|
context.goNamed('game', extra: chessGameArgs);
|
2023-12-23 15:44:23 +00:00
|
|
|
}
|
|
|
|
|
2024-02-05 09:35:28 +00:00
|
|
|
Future<PlayerInfo?> joinPrivateGame(BuildContext context) async {
|
2023-12-23 15:44:23 +00:00
|
|
|
http.Response response;
|
|
|
|
|
2024-05-15 17:42:18 +00:00
|
|
|
var existingInfo = await PlayerInfo.get();
|
|
|
|
|
|
|
|
log("lobbyID: ${existingInfo?.lobbyID} and playerID: ${existingInfo?.playerID} and passphrase: ${existingInfo?.passphrase}");
|
|
|
|
|
|
|
|
PlayerInfo info;
|
|
|
|
if (existingInfo?.passphrase == phraseController.text) {
|
|
|
|
// We have player info for this exact passphrase
|
|
|
|
info = PlayerInfo(
|
|
|
|
playerID: existingInfo?.playerID,
|
|
|
|
lobbyID: existingInfo?.lobbyID,
|
|
|
|
passphrase: phraseController.text);
|
|
|
|
} else {
|
|
|
|
info = PlayerInfo(
|
|
|
|
playerID: null, lobbyID: null, passphrase: phraseController.text);
|
|
|
|
}
|
|
|
|
|
|
|
|
var decodedInfo = jsonEncode(info);
|
|
|
|
log("decodedInfo: $decodedInfo");
|
2023-12-23 15:44:23 +00:00
|
|
|
|
|
|
|
try {
|
2024-01-17 21:50:02 +00:00
|
|
|
response = await http.post(Uri.parse(config.getJoinURL()),
|
2024-05-15 17:42:18 +00:00
|
|
|
body: decodedInfo, headers: {"Accept": "application/json"});
|
2023-12-23 15:44:23 +00:00
|
|
|
} catch (e) {
|
|
|
|
log(e.toString());
|
|
|
|
|
|
|
|
if (!context.mounted) return null;
|
|
|
|
|
|
|
|
const snackBar = SnackBar(
|
|
|
|
backgroundColor: Colors.amberAccent,
|
|
|
|
content: Text("mChess server is not responding. Try again or give up"),
|
|
|
|
);
|
2024-02-05 09:35:28 +00:00
|
|
|
ScaffoldMessenger.of(context).clearSnackBars();
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (response.statusCode == HttpStatus.notFound) {
|
|
|
|
const snackBar = SnackBar(
|
|
|
|
backgroundColor: Colors.amberAccent,
|
|
|
|
content: Text("Passphrase could not be found."),
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!context.mounted) return null;
|
|
|
|
|
|
|
|
ScaffoldMessenger.of(context).clearSnackBars();
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
2023-12-23 15:44:23 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2024-02-05 09:35:28 +00:00
|
|
|
if (response.statusCode == HttpStatus.ok) {
|
2023-12-23 15:44:23 +00:00
|
|
|
var info = PlayerInfo.fromJson(jsonDecode(response.body));
|
2024-05-15 17:42:18 +00:00
|
|
|
info.store();
|
2023-12-23 15:44:23 +00:00
|
|
|
log('Player info received from server: ');
|
|
|
|
log('lobbyID: ${info.lobbyID}');
|
|
|
|
log('playerID: ${info.playerID}');
|
|
|
|
log('passphrase: ${info.passphrase}');
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
2022-12-25 15:16:23 +00:00
|
|
|
}
|