Marco
32caf86f7f
With this change, the lobby selector gets its dark background back. Also, now the passphrase can be submitted by pressing Enter and not only by clicking the 'check' icon.
220 lines
6.5 KiB
Dart
220 lines
6.5 KiB
Dart
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<LobbySelector> createState() => _LobbySelectorState();
|
|
}
|
|
|
|
class _LobbySelectorState extends State<LobbySelector> {
|
|
final buttonStyle = const ButtonStyle();
|
|
final phraseController = TextEditingController();
|
|
late Future<PlayerInfo?> 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<void> buildJoinOrHostDialog(BuildContext context) {
|
|
return showDialog<void>(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: Colors.transparent,
|
|
body: AlertDialog(
|
|
title: const Text('Host or join?'),
|
|
actions: <Widget>[
|
|
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<void> buildEnterPassphraseDialog(BuildContext context) {
|
|
return showDialog<void>(
|
|
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,
|
|
onSubmitted: (val) {
|
|
submitPassphrase(builderContext);
|
|
},
|
|
decoration: InputDecoration(
|
|
hintText: 'Enter passphrase here',
|
|
suffixIcon: IconButton(
|
|
onPressed: () {
|
|
submitPassphrase(builderContext);
|
|
},
|
|
icon: const Icon(Icons.check),
|
|
)),
|
|
),
|
|
actions: <Widget>[
|
|
TextButton(
|
|
child: const Text('Cancel'),
|
|
onPressed: () {
|
|
builderContext.pop();
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
void submitPassphrase(BuildContext ctx) {
|
|
joinGameFuture = joinPrivateGame(ctx);
|
|
joinGameFuture.then((value) {
|
|
if (value != null) {
|
|
phraseController.clear();
|
|
ctx.pop();
|
|
switchToGame(value);
|
|
}
|
|
});
|
|
}
|
|
|
|
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<PlayerInfo?> 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;
|
|
}
|
|
}
|