From 4322e758111674e29216c90127de12af735667f0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 21 Apr 2026 20:17:54 +0200 Subject: [PATCH] Implemented basic game choosing functionality --- .../create_match/choose_game_view.dart | 38 ++++---- .../create_match/create_match_view.dart | 89 ++++++------------- 2 files changed, 50 insertions(+), 77 deletions(-) diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart index d4d7f4d..51512f9 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:tallee/core/common.dart'; import 'package:tallee/core/custom_theme.dart'; -import 'package:tallee/core/enums.dart'; +import 'package:tallee/data/models/game.dart'; import 'package:tallee/l10n/generated/app_localizations.dart'; import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart'; import 'package:tallee/presentation/widgets/tiles/title_description_list_tile.dart'; @@ -13,14 +13,14 @@ class ChooseGameView extends StatefulWidget { const ChooseGameView({ super.key, required this.games, - required this.initialGameIndex, + required this.initialGameId, }); /// A list of tuples containing the game name, description and ruleset - final List<(String, String, Ruleset)> games; + final List games; - /// The index of the initially selected game - final int initialGameIndex; + /// The id of the initially selected game + final String initialGameId; @override State createState() => _ChooseGameViewState(); @@ -31,11 +31,11 @@ class _ChooseGameViewState extends State { final TextEditingController searchBarController = TextEditingController(); /// Currently selected game index - late int selectedGameIndex; + late String selectedGameId; @override void initState() { - selectedGameIndex = widget.initialGameIndex; + selectedGameId = widget.initialGameId; super.initState(); } @@ -49,7 +49,13 @@ class _ChooseGameViewState extends State { leading: IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: () { - Navigator.of(context).pop(selectedGameIndex); + Navigator.of(context).pop( + selectedGameId == '' + ? null + : widget.games.firstWhere( + (game) => game.id == selectedGameId, + ), + ); }, ), title: Text(loc.choose_game), @@ -62,7 +68,7 @@ class _ChooseGameViewState extends State { if (didPop) { return; } - Navigator.of(context).pop(selectedGameIndex); + Navigator.of(context).pop(widget.initialGameId); }, child: Column( children: [ @@ -79,19 +85,19 @@ class _ChooseGameViewState extends State { itemCount: widget.games.length, itemBuilder: (BuildContext context, int index) { return TitleDescriptionListTile( - title: widget.games[index].$1, - description: widget.games[index].$2, + title: widget.games[index].name, + description: widget.games[index].description, badgeText: translateRulesetToString( - widget.games[index].$3, + widget.games[index].ruleset, context, ), - isHighlighted: selectedGameIndex == index, + isHighlighted: selectedGameId == widget.games[index].id, onPressed: () async { setState(() { - if (selectedGameIndex == index) { - selectedGameIndex = -1; + if (selectedGameId != widget.games[index].id) { + selectedGameId = widget.games[index].id; } else { - selectedGameIndex = index; + selectedGameId = ''; } }); }, diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart index 83e5d0c..1a04c78 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -20,7 +20,9 @@ import 'package:tallee/presentation/widgets/tiles/choose_tile.dart'; class CreateMatchView extends StatefulWidget { /// A view that allows creating a new match - /// [onWinnerChanged]: Optional callback invoked when the winner is changed + /// - [onWinnerChanged]: Optional callback invoked when the winner is changed + /// - [matchToEdit]: An optional match to prefill the fields for editing. + /// - [onMatchUpdated]: Optional callback invoked when the match is updated (only in const CreateMatchView({ super.key, this.onWinnerChanged, @@ -28,13 +30,11 @@ class CreateMatchView extends StatefulWidget { this.onMatchUpdated, }); - /// Optional callback invoked when the winner is changed final VoidCallback? onWinnerChanged; - /// Optional callback invoked when the match is updated final void Function(Match)? onMatchUpdated; - /// An optional match to prefill the fields + /// An optional match to prefill the fields for editing. final Match? matchToEdit; @override @@ -50,20 +50,12 @@ class _CreateMatchViewState extends State { /// Hint text for the match name input field String? hintText; - /// List of all groups from the database List groupsList = []; - - /// List of all players from the database List playerList = []; + List gamesList = []; - /// The currently selected group Group? selectedGroup; - - /// The index of the currently selected game in [games] to mark it in - /// the [ChooseGameView] - int selectedGameIndex = -1; - - /// The currently selected players + Game? selectedGame; List selectedPlayers = []; /// GlobalKey for ScaffoldMessenger to show snackbars @@ -81,12 +73,14 @@ class _CreateMatchViewState extends State { Future.wait([ db.groupDao.getAllGroups(), db.playerDao.getAllPlayers(), + db.gameDao.getAllGames(), ]).then((result) async { groupsList = result[0] as List; playerList = result[1] as List; + gamesList = (result[2] as List); // If a match is provided, prefill the fields - if (widget.matchToEdit != null) { + if (isEditMode()) { prefillMatchDetails(); } }); @@ -105,20 +99,11 @@ class _CreateMatchViewState extends State { hintText ??= loc.match_name; } - List<(String, String, Ruleset)> games = [ - ('Example Game 1', 'This is a description', Ruleset.lowestScore), - ('Example Game 2', '', Ruleset.singleWinner), - ]; - @override Widget build(BuildContext context) { final loc = AppLocalizations.of(context); - final buttonText = widget.matchToEdit != null - ? loc.save_changes - : loc.create_match; - final viewTitle = widget.matchToEdit != null - ? loc.edit_match - : loc.create_new_match; + final buttonText = isEditMode() ? loc.save_changes : loc.create_match; + final viewTitle = isEditMode() ? loc.edit_match : loc.create_new_match; return ScaffoldMessenger( key: _scaffoldMessengerKey, @@ -140,21 +125,21 @@ class _CreateMatchViewState extends State { ), ChooseTile( title: loc.game, - trailingText: selectedGameIndex == -1 - ? loc.none - : games[selectedGameIndex].$1, + trailingText: selectedGame == null + ? loc.none_group + : selectedGame!.name, onPressed: () async { - selectedGameIndex = await Navigator.of(context).push( + selectedGame = await Navigator.of(context).push( adaptivePageRoute( builder: (context) => ChooseGameView( - games: games, - initialGameIndex: selectedGameIndex, + games: gamesList, + initialGameId: selectedGame?.id ?? '', ), ), ); setState(() { - if (selectedGameIndex != -1) { - hintText = games[selectedGameIndex].$1; + if (selectedGame != null) { + hintText = selectedGame!.name; } else { hintText = loc.match_name; } @@ -225,6 +210,10 @@ class _CreateMatchViewState extends State { ); } + bool isEditMode() { + return widget.matchToEdit != null; + } + /// Determines whether the "Create Match" button should be enabled. /// /// Returns `true` if: @@ -232,7 +221,7 @@ class _CreateMatchViewState extends State { /// - Either a group is selected OR at least 2 players are selected bool _enableCreateGameButton() { return (selectedGroup != null || - (selectedPlayers.length > 1) && selectedGameIndex != -1); + (selectedPlayers.length > 1) && selectedGame != null); } // If a match was provided to the view, it updates the match in the database @@ -240,7 +229,7 @@ class _CreateMatchViewState extends State { // If no match was provided, it creates a new match in the database and // navigates to the MatchResultView for the newly created match. void buttonNavigation(BuildContext context) async { - if (widget.matchToEdit != null) { + if (isEditMode()) { await updateMatch(); if (context.mounted) { Navigator.pop(context); @@ -266,9 +255,6 @@ class _CreateMatchViewState extends State { /// Updates attributes of the existing match in the database based on the /// changes made in the edit view. Future updateMatch() async { - //TODO: Remove when Games implemented - final tempGame = await getTemporaryGame(); - final updatedMatch = Match( id: widget.matchToEdit!.id, name: _matchNameController.text.isEmpty @@ -276,7 +262,7 @@ class _CreateMatchViewState extends State { : _matchNameController.text.trim(), group: selectedGroup, players: selectedPlayers, - game: tempGame, + game: widget.matchToEdit!.game, createdAt: widget.matchToEdit!.createdAt, endedAt: widget.matchToEdit!.endedAt, notes: widget.matchToEdit!.notes, @@ -322,8 +308,6 @@ class _CreateMatchViewState extends State { // Creates a new match and adds it to the database. // Returns the created match. Future createMatch() async { - final tempGame = await getTemporaryGame(); - Match match = Match( name: _matchNameController.text.isEmpty ? (hintText ?? '') @@ -331,35 +315,18 @@ class _CreateMatchViewState extends State { createdAt: DateTime.now(), group: selectedGroup, players: selectedPlayers, - game: tempGame, + game: selectedGame!, ); await db.matchDao.addMatch(match: match); return match; } - // TODO: Remove when games fully implemented - Future getTemporaryGame() async { - Game? game; - - final selectedGame = games[selectedGameIndex]; - game = Game( - name: selectedGame.$1, - description: selectedGame.$2, - ruleset: selectedGame.$3, - color: GameColor.blue, - icon: '', - ); - - await db.gameDao.addGame(game: game); - return game; - } - // If a match was provided to the view, this method prefills the input fields void prefillMatchDetails() { final match = widget.matchToEdit!; _matchNameController.text = match.name; selectedPlayers = match.players; - selectedGameIndex = 0; + selectedGame = match.game; if (match.group != null) { selectedGroup = match.group;