import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; 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 { const LobbySelector({super.key}); @override State createState() => _LobbySelectorState(); } class _LobbySelectorState extends State { final buttonStyle = const ButtonStyle(); final phraseController = TextEditingController(); late Future joinGameFuture; @override Widget build(BuildContext context) { SharedPreferences.getInstance().then((prefs) { final playerID = prefs.getString("playerID"); final lobbyID = prefs.getString("lobbyID"); final passphrase = prefs.getString("passphrase"); log("lobbyID: $lobbyID and playerID: $playerID and passphrase: $passphrase"); }); return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () => buildJoinOrHostDialog(context), child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.lock), SizedBox( width: 10, ), Text('Private game') ], ), ), ], ), ), ); } Future buildJoinOrHostDialog(BuildContext context) { return showDialog( context: context, builder: (BuildContext context) { return Scaffold( body: AlertDialog( title: const Text('Host or join?'), actions: [ TextButton( child: const Text('Cancel'), onPressed: () => context.pop(), ), TextButton( child: const Text('Host'), onPressed: () { context.pop(); //close dialog before going to host context.goNamed('host'); }), TextButton( child: const Text('Join'), onPressed: () { context.pop(); //close dialog before going to next dialog buildEnterPassphraseDialog(context); }, ), ], ), ); }, ); } Future buildEnterPassphraseDialog(BuildContext context) { return showDialog( context: context, builder: (BuildContext context) { return ScaffoldMessenger( child: Builder(builder: (builderContext) { return Scaffold( backgroundColor: Colors.transparent, body: AlertDialog( title: const Text('Enter the passphrase here:'), content: TextField( controller: phraseController, decoration: InputDecoration( hintText: 'Enter passphrase here', suffixIcon: IconButton( onPressed: () { joinGameFuture = joinPrivateGame(builderContext); joinGameFuture.then((value) { if (value != null) { phraseController.clear(); builderContext.pop(); switchToGame(value); } }); }, icon: const Icon(Icons.check), )), ), actions: [ TextButton( child: const Text('Cancel'), onPressed: () { builderContext.pop(); }, ), ], ), ); }), ); }, ); } 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()) { context.goNamed('lobbySelector'); const snackBar = SnackBar( backgroundColor: Colors.amberAccent, content: Text("Game information is corrupted"), ); ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar(snackBar); return; } context.goNamed('game', extra: chessGameArgs); } Future joinPrivateGame(BuildContext context) async { http.Response response; // server expects us to send the passphrase var info = PlayerInfo( playerID: null, lobbyID: null, passphrase: phraseController.text); try { response = await http.post(Uri.parse(config.getJoinURL()), body: jsonEncode(info), headers: {"Accept": "application/json"}); } 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"), ); 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); return null; } if (response.statusCode == HttpStatus.ok) { var info = PlayerInfo.fromJson(jsonDecode(response.body)); log('Player info received from server: '); log('lobbyID: ${info.lobbyID}'); log('playerID: ${info.playerID}'); log('passphrase: ${info.passphrase}'); return info; } return null; } }