diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index d40e105..d1402e5 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -235,7 +235,7 @@ class GameSession extends ChangeNotifier { /// This method updates the points of each player after a round. /// It first uses the _sumPoints() method to calculate the total points of each player. - /// Then, it checks if any player has reached 100 points. If so, it marks + /// Then, it checks if any player has reached 100 points. If so, saves their indices and marks /// that player as having reached 100 points in that corresponding [Round] object. /// If the game has the point limit activated, it first applies the /// _subtractPointsForReachingHundred() method to subtract 50 points @@ -243,10 +243,13 @@ class GameSession extends ChangeNotifier { /// It then checks if any player has exceeded 100 points. If so, it sets /// isGameFinished to true and calls the _setWinner() method to determine /// the winner. - Future updatePoints() async { + /// It returns a list of players indices who reached 100 points in the current + /// round for the [RoundView] to show a popup + List updatePoints() { + List bonusPlayers = []; _sumPoints(); if (isPointsLimitEnabled) { - _checkHundredPointsReached(); + bonusPlayers = _checkHundredPointsReached(); for (int i = 0; i < playerScores.length; i++) { if (playerScores[i] > pointLimit) { @@ -258,6 +261,7 @@ class GameSession extends ChangeNotifier { } } notifyListeners(); + return bonusPlayers; } @visibleForTesting @@ -278,15 +282,18 @@ class GameSession extends ChangeNotifier { /// Checks if a player has reached 100 points in the current round. /// If so, it updates the [scoreUpdate] List by subtracting 50 points from /// the corresponding round update. - void _checkHundredPointsReached() { + List _checkHundredPointsReached() { + List bonusPlayers = []; for (int i = 0; i < players.length; i++) { if (playerScores[i] == pointLimit) { + bonusPlayers.add(i); print('${players[i]} hat genau 100 Punkte erreicht und bekommt ' 'deswegen ${(pointLimit / 2).round()} Punkte abgezogen'); roundList[roundNumber - 1].scoreUpdates[i] -= (pointLimit / 2).round(); } } _sumPoints(); + return bonusPlayers; } /// Determines the winner of the game session. diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index b072d63..93215ed 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -73,6 +73,25 @@ "kamikaze": "Kamikaze", "done": "Fertig", "next_round": "Nächste Runde", + "bonus_points_title": "Bonus-Punkte!", + "bonus_points_message": "{playerCount, plural, =1{{names} hat exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommt deshalb {bonusPoints} Punkte abgezogen!} other{{names} haben exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommen deshalb jeweils {bonusPoints} Punkte abgezogen!}}", + "@bonus_points_message": { + "placeholders": { + "playerCount": { + "type": "int" + }, + "names": { + "type": "String" + }, + "pointLimit": { + "type": "int" + }, + "bonusPoints": { + "type": "int" + } + } + }, + "end_game": "Spiel beenden", "delete_game": "Spiel löschen", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index a649362..19695a5 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -73,6 +73,25 @@ "kamikaze": "Kamikaze", "done": "Done", "next_round": "Next Round", + "bonus_points_title": "Bonus-Points!", + "bonus_points_message": "{playerCount, plural, =1{{names} has reached exactly the point limit of {pointLimit} points and therefore gets {bonusPoints} points deducted!} other{{names} have reached exactly the point limit of {pointLimit} points and therefore get {bonusPoints} points deducted!}}", + "@bonus_points_message": { + "placeholders": { + "playerCount": { + "type": "int" + }, + "names": { + "type": "String" + }, + "pointLimit": { + "type": "int" + }, + "bonusPoints": { + "type": "int" + } + } + }, + "end_game": "End Game", "delete_game": "Delete Game", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 2059f1b..0a902f6 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -416,6 +416,19 @@ abstract class AppLocalizations { /// **'Nächste Runde'** String get next_round; + /// No description provided for @bonus_points_title. + /// + /// In de, this message translates to: + /// **'Bonus-Punkte!'** + String get bonus_points_title; + + /// No description provided for @bonus_points_message. + /// + /// In de, this message translates to: + /// **'{playerCount, plural, =1{{names} hat exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommt deshalb {bonusPoints} Punkte abgezogen!} other{{names} haben exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommen deshalb jeweils {bonusPoints} Punkte abgezogen!}}'** + String bonus_points_message( + int playerCount, String names, int pointLimit, int bonusPoints); + /// No description provided for @end_game. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 068711f..7a71d00 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -178,6 +178,23 @@ class AppLocalizationsDe extends AppLocalizations { @override String get next_round => 'Nächste Runde'; + @override + String get bonus_points_title => 'Bonus-Punkte!'; + + @override + String bonus_points_message( + int playerCount, String names, int pointLimit, int bonusPoints) { + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: + '$names haben exakt das Punktelimit von $pointLimit Punkten erreicht und bekommen deshalb jeweils $bonusPoints Punkte abgezogen!', + one: + '$names hat exakt das Punktelimit von $pointLimit Punkten erreicht und bekommt deshalb $bonusPoints Punkte abgezogen!', + ); + return '$_temp0'; + } + @override String get end_game => 'Spiel beenden'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 06b5c03..4d4d663 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -175,6 +175,23 @@ class AppLocalizationsEn extends AppLocalizations { @override String get next_round => 'Next Round'; + @override + String get bonus_points_title => 'Bonus-Points!'; + + @override + String bonus_points_message( + int playerCount, String names, int pointLimit, int bonusPoints) { + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: + '$names have reached exactly the point limit of $pointLimit points and therefore get $bonusPoints points deducted!', + one: + '$names has reached exactly the point limit of $pointLimit points and therefore gets $bonusPoints points deducted!', + ); + return '$_temp0'; + } + @override String get end_game => 'End Game'; diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 39e5cc8..a821fb5 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -287,9 +287,14 @@ class _RoundViewState extends State { children: [ CupertinoButton( onPressed: _areRoundInputsValid() - ? () { - _finishRound(); + ? () async { + List bonusPlayersIndices = _finishRound(); + if (bonusPlayersIndices.isNotEmpty) { + await _showBonusPopup( + context, bonusPlayersIndices); + } LocalStorageService.saveGameSessions(); + if (!context.mounted) return; Navigator.pop(context); } : null, @@ -298,12 +303,18 @@ class _RoundViewState extends State { if (!widget.gameSession.isGameFinished) CupertinoButton( onPressed: _areRoundInputsValid() - ? () { - _finishRound(); + ? () async { + List bonusPlayersIndices = + _finishRound(); + if (bonusPlayersIndices.isNotEmpty) { + await _showBonusPopup( + context, bonusPlayersIndices); + } LocalStorageService.saveGameSessions(); - if (widget.gameSession.isGameFinished) { + if (widget.gameSession.isGameFinished && + context.mounted) { Navigator.pop(context); - } else { + } else if (context.mounted) { Navigator.pop( context, widget.roundNumber + 1); } @@ -359,7 +370,7 @@ class _RoundViewState extends State { /// every player. If the round is the highest round played in this game, /// it expands the player score lists. At the end it updates the score /// array for the game. - void _finishRound() { + List _finishRound() { print('===================================='); print('Runde ${widget.roundNumber} beendet'); // The shown round is smaller than the newest round @@ -381,12 +392,63 @@ class _RoundViewState extends State { widget.gameSession.calculateScoredPoints( widget.roundNumber, roundScores, _caboPlayerIndex); } - widget.gameSession.updatePoints(); + List bonusPlayers = widget.gameSession.updatePoints(); if (widget.gameSession.isGameFinished == true) { print('Das Spiel ist beendet'); } else if (widget.roundNumber == widget.gameSession.roundNumber) { widget.gameSession.increaseRound(); } + return bonusPlayers; + } + + /// Shows a popup dialog with the bonus information. + Future _showBonusPopup( + BuildContext context, List bonusPlayers) async { + print('Bonus Popup wird angezeigt'); + int pointLimit = widget.gameSession.pointLimit; + int bonusPoints = (pointLimit / 2).round(); + + String resultText = + _getBonusPopupMessageString(pointLimit, bonusPoints, bonusPlayers); + + await showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).bonus_points_title), + content: Text(resultText), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + ); + } + + /// Generates the message string for the bonus popup. + /// It takes the [pointLimit], [bonusPoints] and the list of [bonusPlayers] + /// and returns a formatted string. + String _getBonusPopupMessageString( + int pointLimit, int bonusPoints, List bonusPlayers) { + List nameList = + bonusPlayers.map((i) => widget.gameSession.players[i]).toList(); + String resultText = ''; + if (nameList.length == 1) { + resultText = AppLocalizations.of(context).bonus_points_message( + nameList.length, nameList.first, pointLimit, bonusPoints); + } else { + resultText = nameList.length == 2 + ? '${nameList[0]} & ${nameList[1]}' + : '${nameList.sublist(0, nameList.length - 1).join(', ')} & ${nameList.last}'; + resultText = AppLocalizations.of(context).bonus_points_message( + nameList.length, + resultText, + pointLimit, + bonusPoints, + ); + } + return resultText; } @override diff --git a/pubspec.yaml b/pubspec.yaml index 7946bbb..9db5d4b 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.4.4+486 +version: 0.4.5+494 environment: sdk: ^3.5.4 diff --git a/test/data/game_session_test.dart b/test/data/game_session_test.dart index de4e284..4ca2158 100644 --- a/test/data/game_session_test.dart +++ b/test/data/game_session_test.dart @@ -114,15 +114,15 @@ void main() { expect(session.roundList[0].caboPlayerIndex, 0); }); - test('updatePoints - game not finished', () async { + test('updatePoints - game not finished', () { session.addRoundScoresToList(1, [10, 20, 30], [10, 20, 30], 0); - await session.updatePoints(); + session.updatePoints(); expect(session.isGameFinished, isFalse); }); - test('updatePoints - game finished', () async { + test('updatePoints - game finished', () { session.addRoundScoresToList(1, [101, 20, 30], [101, 20, 30], 0); - await session.updatePoints(); + session.updatePoints(); expect(session.isGameFinished, isTrue); }); @@ -154,9 +154,9 @@ void main() { expect(session.playerScores, equals([50, 0, 30])); }); - test('_setWinner via updatePoints', () async { + test('_setWinner via updatePoints', () { session.addRoundScoresToList(1, [101, 20, 30], [101, 0, 30], 1); - await session.updatePoints(); + session.updatePoints(); expect(session.winner, 'Bob'); // Bob has lowest score (20) }); });