import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart' as http; import 'package:mchess/api/game_info.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:universal_platform/universal_platform.dart'; class JoinGameHandleWidget extends StatefulWidget { final String passphrase; const JoinGameHandleWidget({required this.passphrase, super.key}); @override State createState() => _JoinGameHandleWidgetState(); } class _JoinGameHandleWidgetState extends State { late Future joinGameFuture; @override void initState() { super.initState(); joinGameFuture = joinPrivateGame(widget.passphrase); joinGameFuture.then((val) { if (val == null) return; ConnectionCubit.getInstance().connectIfNotConnected( val.playerID!.uuid, val.passphrase, ); }); } @override Widget build(BuildContext context) { FloatingActionButton? fltnBtn; if (UniversalPlatform.isLinux || UniversalPlatform.isMacOS || UniversalPlatform.isWindows) { fltnBtn = FloatingActionButton( child: const Icon(Icons.cancel), onPressed: () { context.pop(); }, ); } var loadingIndicator = const SizedBox( height: 100, width: 100, child: CircularProgressIndicator(), ); return Scaffold( floatingActionButton: fltnBtn, body: Center( child: FutureBuilder( future: joinGameFuture, builder: (context, snapshot) { if (snapshot.connectionState != ConnectionState.done) { return loadingIndicator; } else { return BlocBuilder( builder: (context, state) { if (state.iAmConnected) { return const ChessGame(); } else { return loadingIndicator; } }); } }), ), ); } Future joinPrivateGame(String phrase) async { http.Response response; var existingInfo = await GameInfo.get(phrase); log('playerID: ${existingInfo?.playerID} and passphrase: "${existingInfo?.passphrase}"'); GameInfo info; if (existingInfo?.passphrase == phrase) { // We have player info for this exact passphrase info = GameInfo(playerID: existingInfo?.playerID, passphrase: phrase); } else { info = GameInfo(playerID: null, passphrase: phrase); } try { response = await http.post(Uri.parse(config.getJoinGameURL()), 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"), ); Future.delayed(const Duration(seconds: 1), () { if (!mounted) return null; ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar(snackBar); context.goNamed('lobbySelector'); // We go back to the lobby selector }); return null; } if (response.statusCode == HttpStatus.notFound) { const snackBar = SnackBar( backgroundColor: Colors.amberAccent, content: Text("Passphrase could not be found."), ); if (!mounted) return null; ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar(snackBar); context.goNamed('lobbySelector'); return null; } if (response.statusCode == HttpStatus.ok) { var info = GameInfo.fromJson(jsonDecode(response.body)); info.store(); log('Player info received from server: '); log('playerID: ${info.playerID}'); log('passphrase: ${info.passphrase}'); return info; } return null; } }