diff --git a/board_games_companion/lib/models/playthroughs/playthrough_details.dart b/board_games_companion/lib/models/playthroughs/playthrough_details.dart index 2108adee..6f865aa9 100644 --- a/board_games_companion/lib/models/playthroughs/playthrough_details.dart +++ b/board_games_companion/lib/models/playthroughs/playthrough_details.dart @@ -53,7 +53,11 @@ class PlaythroughDetails with _$PlaythroughDetails { List get tiedPlayerScores => playerScores.where((playerScore) => playerScore.id != null && playerScore.isTied).toList(); - GameClassification get playerScoreBasedGameClassification { + GameClassification? get playerScoreBasedGameClassification { + if (!playerScores.any((playerScore) => playerScore.score.hasScore)) { + return null; + } + if (playerScores.any((playerScore) => playerScore.score.noScoreGameResult != null)) { return GameClassification.NoScore; } diff --git a/board_games_companion/lib/pages/edit_playthrough/edit_playthrough_view_model.dart b/board_games_companion/lib/pages/edit_playthrough/edit_playthrough_view_model.dart index 4505f452..7ddf15af 100644 --- a/board_games_companion/lib/pages/edit_playthrough/edit_playthrough_view_model.dart +++ b/board_games_companion/lib/pages/edit_playthrough/edit_playthrough_view_model.dart @@ -106,8 +106,8 @@ abstract class _EditPlaythoughViewModel with Store { } @computed - CooperativeGameResult? get cooperativeGameResult => - playerScores.first.score.noScoreGameResult?.cooperativeGameResult; + CooperativeGameResult? get cooperativeGameResult => _playthroughDetailsWorkingCopy + ?.playerScores.first.score.noScoreGameResult?.cooperativeGameResult; bool get isDirty => _playthroughDetailsWorkingCopy != playthroughDetails; @@ -363,7 +363,11 @@ abstract class _EditPlaythoughViewModel with Store { } void _updateEditPlaythroughPageVisualState() { - switch (_playthroughDetailsWorkingCopy!.playerScoreBasedGameClassification) { + final gameClassificaition = + _playthroughDetailsWorkingCopy!.playerScoreBasedGameClassification ?? + _gamePlaythroughsDetailsStore.gameClassification; + + switch (gameClassificaition) { case GameClassification.Score: editPlaythroughPageVisualState = EditPlaythroughPageVisualStates.editScoreGame( gameFamily: _gamePlaythroughsDetailsStore.gameGameFamily, diff --git a/board_games_companion/test/view_models/edit_playthrough_view_model_test.dart b/board_games_companion/test/view_models/edit_playthrough_view_model_test.dart index 7177f05b..a7b9d58f 100644 --- a/board_games_companion/test/view_models/edit_playthrough_view_model_test.dart +++ b/board_games_companion/test/view_models/edit_playthrough_view_model_test.dart @@ -1,11 +1,13 @@ import 'package:board_games_companion/common/enums/game_classification.dart'; import 'package:board_games_companion/common/enums/game_family.dart'; +import 'package:board_games_companion/models/hive/no_score_game_result.dart'; import 'package:board_games_companion/models/hive/player.dart'; import 'package:board_games_companion/models/hive/playthrough.dart'; import 'package:board_games_companion/models/hive/score.dart'; import 'package:board_games_companion/models/hive/score_game_results.dart'; import 'package:board_games_companion/models/player_score.dart'; import 'package:board_games_companion/models/playthroughs/playthrough_details.dart'; +import 'package:board_games_companion/pages/edit_playthrough/edit_playthrough_page_visual_states.dart'; import 'package:board_games_companion/pages/edit_playthrough/edit_playthrough_view_model.dart'; import 'package:clock/clock.dart'; import 'package:collection/collection.dart'; @@ -53,7 +55,6 @@ void main() { editPlaythrouhgViewModel = EditPlaythoughViewModel( mockGamePlaythroughsDetailsStore, ); - editPlaythrouhgViewModel.setPlaythroughId(mockPlaythroughId); }); tearDown(() { @@ -64,6 +65,7 @@ void main() { 'GIVEN edit playthrough view model ' 'WHEN setting a playthrough with an id ' 'THEN then the playthrough details should reflect that ', () { + editPlaythrouhgViewModel.setPlaythroughId(mockPlaythroughId); expect(editPlaythrouhgViewModel.playthroughDetails, mockPlaythroughDetails); }); @@ -75,6 +77,7 @@ void main() { .firstWhereOrNull((element) => element.id == mockEmptyPlayerScoreId); const newScore = 10.0; + editPlaythrouhgViewModel.setPlaythroughId(mockPlaythroughId); editPlaythrouhgViewModel.updatePlayerScore(playerScoreToUpdate!.id!, newScore); final updatedPlayerScore = editPlaythrouhgViewModel.playerScores @@ -122,6 +125,7 @@ void main() { .firstWhereOrNull((playerScore) => playerScore.player!.id == firstPlayerId); const newScore = 20.0; + editPlaythrouhgViewModel.setPlaythroughId(mockPlaythroughId); editPlaythrouhgViewModel.updatePlayerScore(playerScoreToUpdate!.id!, newScore); for (final playerScore in editPlaythrouhgViewModel.playerScores) { @@ -129,4 +133,129 @@ void main() { expect(playerScore.score.scoreGameResult!.tiebreakerType, isNull); } }); + + test( + 'GIVEN a non score game ' + 'WHEN a player scored a cooperative game ' + 'THEN cooperative game result should reflect that score ', () { + const firstPlayerId = '1'; + const cooperativeResult = CooperativeGameResult.win; + when(() => mockGamePlaythroughsDetailsStore.playthroughsDetails).thenReturn( + ObservableList.of( + [ + mockPlaythroughDetails.copyWith( + playerScores: [ + emptyPlayerScore.copyWith( + player: const Player(id: firstPlayerId), + score: emptyScore.copyWith( + noScoreGameResult: const NoScoreGameResult( + cooperativeGameResult: cooperativeResult, + ), + ), + ), + ], + ) + ], + ), + ); + + editPlaythrouhgViewModel.setPlaythroughId(mockPlaythroughId); + + expect(editPlaythrouhgViewModel.cooperativeGameResult, cooperativeResult); + }); + + test( + 'GIVEN a non score game ' + 'WHEN a non of the players scored ' + 'THEN cooperative game result should be null ', () { + const firstPlayerId = '1'; + when(() => mockGamePlaythroughsDetailsStore.playthroughsDetails).thenReturn( + ObservableList.of( + [ + mockPlaythroughDetails.copyWith( + playerScores: [ + emptyPlayerScore.copyWith( + player: const Player(id: firstPlayerId), + score: emptyScore, + ), + ], + ) + ], + ), + ); + + editPlaythrouhgViewModel.setPlaythroughId(mockPlaythroughId); + + expect(editPlaythrouhgViewModel.cooperativeGameResult, null); + }); + + group('GIVEN edit playthrough page visual state', () { + test( + 'WHEN players have no scores yet ' + 'THEN visual state should be based on the game setting classification ', () { + const gameFamily = GameFamily.Cooperative; + when(() => mockGamePlaythroughsDetailsStore.gameClassification) + .thenReturn(GameClassification.NoScore); + when(() => mockGamePlaythroughsDetailsStore.gameGameFamily).thenReturn(gameFamily); + when(() => mockGamePlaythroughsDetailsStore.playthroughsDetails).thenReturn( + ObservableList.of( + [ + mockPlaythroughDetails.copyWith( + playerScores: [ + emptyPlayerScore.copyWith( + player: const Player(id: '1'), + score: emptyScore, + ), + emptyPlayerScore.copyWith( + player: const Player(id: '2'), + score: emptyScore, + ), + ], + ) + ], + ), + ); + + editPlaythrouhgViewModel.setPlaythroughId(mockPlaythroughId); + + expect(editPlaythrouhgViewModel.editPlaythroughPageVisualState, + const EditPlaythroughPageVisualStates.editNoScoreGame(gameFamily: gameFamily)); + }); + + // MK We need this behaviour in order to support / migrate results that were logged for a game + // which classification was changed after logging games + test( + 'WHEN players have a score ' + 'THEN visual state should be based on their score classificiation ', () { + const gameFamily = GameFamily.Cooperative; + when(() => mockGamePlaythroughsDetailsStore.gameClassification) + .thenReturn(GameClassification.NoScore); + when(() => mockGamePlaythroughsDetailsStore.gameGameFamily).thenReturn(gameFamily); + when(() => mockGamePlaythroughsDetailsStore.playthroughsDetails).thenReturn( + ObservableList.of( + [ + mockPlaythroughDetails.copyWith( + playerScores: [ + emptyPlayerScore.copyWith( + player: const Player(id: '1'), + score: emptyScore.copyWith( + scoreGameResult: const ScoreGameResult(points: 10), + ), + ), + emptyPlayerScore.copyWith( + player: const Player(id: '2'), + score: emptyScore, + ), + ], + ) + ], + ), + ); + + editPlaythrouhgViewModel.setPlaythroughId(mockPlaythroughId); + + expect(editPlaythrouhgViewModel.editPlaythroughPageVisualState, + const EditPlaythroughPageVisualStates.editScoreGame(gameFamily: gameFamily)); + }); + }); }