diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 24c55da..ea18be7 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -42,9 +42,27 @@ class GameManager extends ChangeNotifier { removeGameSessionByIndex(index); } + /// Retrieves a game session by its ID. + /// Takes a String [id] as input. It finds the game session with the matching id bool gameExistsInGameList(String id) { return gameList.any((session) => session.id.toString() == id); } + + /// Ends a game session if its in unlimited mode. + /// Takes a String [id] as input. It finds the index of the game + /// session with the matching ID marks it as finished, + void endGame(String id) { + final int index = + gameList.indexWhere((session) => session.id.toString() == id); + + // Game session not found or not in unlimited mode + if (index == -1 || gameList[index].isPointsLimitEnabled == false) return; + + gameList[index].roundNumber--; + gameList[index].isGameFinished = true; + notifyListeners(); + LocalStorageService.saveGameSessions(); + } } final gameManager = GameManager(); diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 7fa3710..d300ab0 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -65,12 +65,14 @@ "next_round": "Nächste Runde", "statistics": "Statistiken", + "end_game": "Spiel beenden", "delete_game": "Spiel löschen", "new_game_same_settings": "Neues Spiel mit gleichen Einstellungen", "export_game": "Spiel exportieren", "id_error_title": "ID Fehler", "id_error_message": "Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.", - + "end_game_title": "Spiel beenden?", + "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.", "game_process": "Spielverlauf", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f8dbb2f..8b328ba 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -65,6 +65,7 @@ "next_round": "Next Round", "statistics": "Statistics", + "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", "export_game": "Export Game", @@ -82,6 +83,8 @@ "export_data": "Export Data", "id_error_title": "ID Error", "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", + "end_game_title": "End the game?", + "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", "import_success_title": "Import successful", "import_success_message":"The game data has been successfully imported.", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index eb858f5..02e1d3c 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -368,6 +368,12 @@ abstract class AppLocalizations { /// **'Statistiken'** String get statistics; + /// No description provided for @end_game. + /// + /// In de, this message translates to: + /// **'Spiel beenden'** + String get end_game; + /// No description provided for @delete_game. /// /// In de, this message translates to: @@ -398,6 +404,18 @@ abstract class AppLocalizations { /// **'Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.'** String get id_error_message; + /// No description provided for @end_game_title. + /// + /// In de, this message translates to: + /// **'Spiel beenden?'** + String get end_game_title; + + /// No description provided for @end_game_message. + /// + /// In de, this message translates to: + /// **'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.'** + String get end_game_message; + /// No description provided for @game_process. /// /// In de, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index f72adbb..1b91ed4 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -152,6 +152,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get statistics => 'Statistiken'; + @override + String get end_game => 'Spiel beenden'; + @override String get delete_game => 'Spiel löschen'; @@ -168,6 +171,13 @@ class AppLocalizationsDe extends AppLocalizations { String get id_error_message => 'Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.'; + @override + String get end_game_title => 'Spiel beenden?'; + + @override + String get end_game_message => + 'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.'; + @override String get game_process => 'Spielverlauf'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 657f2ce..c98dddd 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -149,6 +149,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get statistics => 'Statistics'; + @override + String get end_game => 'End Game'; + @override String get delete_game => 'Delete Game'; @@ -165,6 +168,13 @@ class AppLocalizationsEn extends AppLocalizations { String get id_error_message => 'The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.'; + @override + String get end_game_title => 'End the game?'; + + @override + String get end_game_message => + 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; + @override String get game_process => 'Spielverlauf'; diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 1b5e546..dc0e078 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -129,21 +129,40 @@ class _ActiveGameViewState extends State { Column( children: [ CupertinoListTile( - backgroundColorActivated: - CustomTheme.backgroundColor, title: Text( AppLocalizations.of(context).statistics, ), + backgroundColorActivated: + CustomTheme.backgroundColor, onTap: () => Navigator.push( context, CupertinoPageRoute( builder: (_) => GraphView( gameSession: gameSession, )))), + if (!gameSession.isPointsLimitEnabled) + CupertinoListTile( + title: Text( + AppLocalizations.of(context).end_game, + style: gameSession.roundNumber > 1 && + !gameSession.isGameFinished + ? const TextStyle(color: Colors.white) + : const TextStyle(color: Colors.white30), + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () => { + gameSession.roundNumber > 1 && + !gameSession.isGameFinished + ? _showEndGameDialog() + : null + }), CupertinoListTile( title: Text( AppLocalizations.of(context).delete_game, ), + backgroundColorActivated: + CustomTheme.backgroundColor, onTap: () { _showDeleteGameDialog().then((value) { if (value) { @@ -157,6 +176,8 @@ class _ActiveGameViewState extends State { AppLocalizations.of(context) .new_game_same_settings, ), + backgroundColorActivated: + CustomTheme.backgroundColor, onTap: () { Navigator.pushReplacement( context, @@ -176,6 +197,8 @@ class _ActiveGameViewState extends State { style: const TextStyle( color: Colors.white30, )), + backgroundColorActivated: + CustomTheme.backgroundColor, ), ], ) @@ -186,6 +209,41 @@ class _ActiveGameViewState extends State { }); } + /// Shows a dialog to confirm ending the game. + /// If the user confirms, it calls the `endGame` method on the game manager + void _showEndGameDialog() { + showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).end_game_title), + content: Text(AppLocalizations.of(context).end_game_message), + actions: [ + CupertinoDialogAction( + child: Text( + AppLocalizations.of(context).end_game, + style: const TextStyle( + fontWeight: FontWeight.bold, color: Colors.red), + ), + onPressed: () { + setState(() { + gameSession.isGameFinished = true; + gameSession.roundNumber--; + gameManager.endGame(gameSession.id); + }); + Navigator.pop(context); + }, + ), + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).cancel), + onPressed: () => Navigator.pop(context), + ), + ], + ); + }, + ); + } + /// Returns a list of player indices sorted by their scores in /// ascending order. List _getSortedPlayerIndices() { diff --git a/pubspec.yaml b/pubspec.yaml index 56b89bc..e3b4a67 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.6+318 +version: 0.3.6+322 environment: sdk: ^3.5.4