import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:huacu_mobile/models/auth_data.dart'; import 'package:huacu_mobile/models/available_game.dart'; import 'package:huacu_mobile/models/game.dart'; import 'package:huacu_mobile/ui/widgets/socket_connection_indicator.dart'; import 'package:socket_io_client/socket_io_client.dart' as io; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State createState() => _HomePageState(); } class _HomePageState extends State { final io.Socket socket = Get.find(); final AuthData authData = Get.find(); final availableGames = [].obs; @override void initState() { super.initState(); socket.on("hello", (idky) { socket.dispose(); Get.offAllNamed("/auth"); }); socket.on("update", (update) { bool ok = update[0]; if (ok) { var data = update[1]; availableGames.value = (data["availableGames"] as List? ?? []) .map((e) => AvailableGame( id: e["id"], opponentName: e["player"], tries: e["tries"], neededRole: e["neededRole"], )) .toList(growable: false); } else { Get.snackbar("Error", "Update failed with message: ${update[1]}"); } }); socket.on("updateNeeded", (data) { socket.emit("getUpdate"); }); socket.on("removeGameResponse", (data) => null); socket.on("createGameResponse", (data) => null); socket.on("joinGameResponse", (data) { bool ok = data[0]; if (ok) { socket.off("hello"); socket.off("update"); socket.off("updateNeeded"); socket.off("someoneJoinedGame"); Get.put(authData); Get.put(socket); Get.put(Game( data[1]["id"], data[1]["guesser"], data[1]["suggester"], data[1]["tries"], (data[2] as List).map((e) => e.toString()).toSet(), )); Get.offNamed("/game"); } else { Get.snackbar("Request response", data[1]); } }); socket.emit("getUpdate"); } @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; return Scaffold( appBar: AppBar( title: Obx(() => Text("Available ${availableGames.length} game(s)")), ), body: SizedBox( width: size.width, height: size.height, child: Column( children: [ Expanded( child: ObxValue( (data) => ListView.builder( itemCount: data.length, itemBuilder: (context, index) { final game = data[index]; final you = authData.login == game.opponentName; return Card( child: ListTile( title: Text( "Game of ${game.opponentName} ${you ? "(you)" : ""}" .trim(), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Tries: ${game.tries}"), Text("Needed role: ${game.neededRole}"), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ if (!you) InkResponse( onTap: () => _joinGame(game.id), child: const Icon(Icons.connect_without_contact), ), if (you) InkResponse( onTap: () => _deleteGame(game.id), child: const Icon(Icons.delete), ), ], ), ), ); }, ), availableGames, ), ), Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: ObxValue( (data) { return ElevatedButton( onPressed: data.firstWhereOrNull( (g) => g.opponentName == authData.login) == null ? _createGame : null, child: const Text("Create"), ); }, availableGames, ), ), ], ), ], ), ), ); } void _createGame() async { var tries = 20; var role = "guesser"; final data = await Get.dialog?>( StatefulBuilder(builder: (buildContext, setState) { return AlertDialog( title: const Text("New game configuration"), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Tries: $tries"), Slider( value: tries.toDouble(), label: tries.toString(), onChanged: (value) { setState(() { tries = value.round(); }); }, min: 10, max: 50, divisions: 40, ), const Text("Needed role:"), Row( children: [ Expanded( child: DropdownButton( value: role, items: const [ DropdownMenuItem( value: "guesser", child: Text("Guesser"), ), DropdownMenuItem( value: "suggester", child: Text("Suggester"), ), ], onChanged: (value) { setState(() { role = value ?? "guesser"; }); }, ), ), ], ), ], ), actions: [ TextButton( onPressed: () { Get.back(); }, child: const Text("Cancel"), ), TextButton( onPressed: () { Get.back(result: { "tries": tries, "role": role, }); }, child: const Text("Create"), ), ], ); })); if (data == null) return; tries = data["tries"]; role = data["role"]; socket.emit("createGame", [tries, role]); Get.snackbar("Game created", "Game created"); } void _joinGame(String gameId) { socket.emit("joinGame", gameId); } void _deleteGame(String gameId) { Get.defaultDialog( title: "Delete game", content: const Text("Are you sure you want to delete this game?"), textConfirm: "Delete", onConfirm: () { socket.emit("removeGame", gameId); Get.back(); }, textCancel: "Cancel", onCancel: () { Get.back(); }, ); } }