diff --git a/api/packages/game_domain/lib/src/models/hint.dart b/api/packages/game_domain/lib/src/models/hint.dart index 5611034a2..61982d2af 100644 --- a/api/packages/game_domain/lib/src/models/hint.dart +++ b/api/packages/game_domain/lib/src/models/hint.dart @@ -9,7 +9,11 @@ part 'hint.g.dart'; @JsonSerializable(ignoreUnannotated: true) class Hint extends Equatable { /// {@macro hint} - const Hint({required this.question, required this.response}); + const Hint({ + required this.question, + required this.response, + required this.readableResponse, + }); /// {@macro hint} factory Hint.fromJson(Map json) => _$HintFromJson(json); @@ -22,11 +26,15 @@ class Hint extends Equatable { @JsonKey() final HintResponse response; + /// Readable `response`. + @JsonKey() + final String readableResponse; + /// Returns a json representation from this instance. Map toJson() => _$HintToJson(this); @override - List get props => [question, response]; + List get props => [question, response, readableResponse]; } /// Enum representing the possible responses to a hint question. diff --git a/api/packages/game_domain/lib/src/models/hint.g.dart b/api/packages/game_domain/lib/src/models/hint.g.dart index ec5180ffb..ed1eb6d88 100644 --- a/api/packages/game_domain/lib/src/models/hint.g.dart +++ b/api/packages/game_domain/lib/src/models/hint.g.dart @@ -9,11 +9,13 @@ part of 'hint.dart'; Hint _$HintFromJson(Map json) => Hint( question: json['question'] as String, response: $enumDecode(_$HintResponseEnumMap, json['response']), + readableResponse: json['readableResponse'] as String, ); Map _$HintToJson(Hint instance) => { 'question': instance.question, 'response': _$HintResponseEnumMap[instance.response]!, + 'readableResponse': instance.readableResponse, }; const _$HintResponseEnumMap = { diff --git a/api/packages/game_domain/test/src/models/hint_test.dart b/api/packages/game_domain/test/src/models/hint_test.dart index 015891f22..f1517101c 100644 --- a/api/packages/game_domain/test/src/models/hint_test.dart +++ b/api/packages/game_domain/test/src/models/hint_test.dart @@ -6,7 +6,11 @@ import 'package:test/test.dart'; void main() { group('Hint', () { test('creates correct json object from Hint object', () { - final hint = Hint(question: 'to be?', response: HintResponse.yes); + final hint = Hint( + question: 'to be?', + response: HintResponse.yes, + readableResponse: 'Yes, that is correct!', + ); final json = hint.toJson(); expect( @@ -14,6 +18,7 @@ void main() { equals({ 'question': 'to be?', 'response': 'yes', + 'readableResponse': 'Yes, that is correct!', }), ); }); @@ -22,6 +27,7 @@ void main() { final json = { 'question': 'or not to be?', 'response': 'notApplicable', + 'readableResponse': "I can't answer that.", }; final hint = Hint.fromJson(json); expect( @@ -30,6 +36,7 @@ void main() { Hint( question: 'or not to be?', response: HintResponse.notApplicable, + readableResponse: "I can't answer that.", ), ), ); @@ -39,10 +46,12 @@ void main() { final firstHint = Hint( question: 'to be?', response: HintResponse.no, + readableResponse: 'Nope!', ); final secondHint = Hint( question: 'to be?', response: HintResponse.no, + readableResponse: 'Nope!', ); expect(firstHint, equals(secondHint)); }); diff --git a/api/packages/hint_repository/lib/src/hint_repository.dart b/api/packages/hint_repository/lib/src/hint_repository.dart index fe26a6ff2..06f4886c0 100644 --- a/api/packages/hint_repository/lib/src/hint_repository.dart +++ b/api/packages/hint_repository/lib/src/hint_repository.dart @@ -4,6 +4,7 @@ import 'package:db_client/db_client.dart'; import 'package:dio/dio.dart'; import 'package:game_domain/game_domain.dart'; import 'package:hint_repository/hint_repository.dart'; +import 'package:hint_repository/src/hint_response_extension.dart'; /// {@template hint_repository} /// A repository to handle the hints. @@ -102,6 +103,7 @@ class HintRepository { final hint = Hint( question: question, response: hintResponse, + readableResponse: hintResponse.readable, ); return hint; } catch (e, stackTrace) { diff --git a/lib/hint/extensions/hint_response_extension.dart b/api/packages/hint_repository/lib/src/hint_response_extension.dart similarity index 80% rename from lib/hint/extensions/hint_response_extension.dart rename to api/packages/hint_repository/lib/src/hint_response_extension.dart index e952c44df..b333b8d51 100644 --- a/lib/hint/extensions/hint_response_extension.dart +++ b/api/packages/hint_repository/lib/src/hint_response_extension.dart @@ -1,9 +1,11 @@ import 'dart:math'; -import 'package:flutter/foundation.dart'; import 'package:game_domain/game_domain.dart'; +import 'package:meta/meta.dart'; +/// An extension on [HintResponse] to provide readable responses. extension HintResponseExtension on HintResponse { + /// Returns a readable response for the hint. String get readable { final random = Random(); @@ -19,6 +21,7 @@ extension HintResponseExtension on HintResponse { } } +/// Response alternatives to [HintResponse.yes]. @visibleForTesting const yesResponses = [ 'Yes, that is correct!', @@ -33,6 +36,7 @@ const yesResponses = [ 'Yes!', ]; +/// Response alternatives to [HintResponse.no]. @visibleForTesting const noResponses = [ 'No, unfortunately.', @@ -47,6 +51,7 @@ const noResponses = [ 'Sorry, but no!', ]; +/// Response alternatives to [HintResponse.notApplicable]. @visibleForTesting const notApplicableResponses = [ "I can't answer that.", diff --git a/api/packages/hint_repository/pubspec.yaml b/api/packages/hint_repository/pubspec.yaml index 6d94b321c..edc414ea3 100644 --- a/api/packages/hint_repository/pubspec.yaml +++ b/api/packages/hint_repository/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: game_domain: path: ../game_domain http: ^1.2.1 + meta: ^1.14.0 dev_dependencies: mocktail: ^1.0.3 diff --git a/api/packages/hint_repository/test/src/hint_repository_test.dart b/api/packages/hint_repository/test/src/hint_repository_test.dart index ebc3cb804..5e50c156d 100644 --- a/api/packages/hint_repository/test/src/hint_repository_test.dart +++ b/api/packages/hint_repository/test/src/hint_repository_test.dart @@ -118,13 +118,34 @@ void main() { final hint = await hintRepository.generateHint( wordAnswer: 'answer', question: 'question', - previousHints: [Hint(question: 'is it?', response: HintResponse.no)], + previousHints: [ + Hint( + question: 'is it?', + response: HintResponse.no, + readableResponse: 'Nope!', + ), + ], userToken: 'token', ); expect( hint, - equals(Hint(question: 'question', response: HintResponse.yes)), + isA() + .having( + (hint) => hint.question, + 'the question field', + 'question', + ) + .having( + (hint) => hint.response, + 'the response field', + HintResponse.yes, + ) + .having( + (hint) => hint.readableResponse, + 'the readableResponse field', + isA(), + ), ); }); @@ -155,12 +176,22 @@ void main() { expect( hint, - equals( - Hint( - question: 'question', - response: HintResponse.notApplicable, - ), - ), + isA() + .having( + (hint) => hint.question, + 'the question field', + 'question', + ) + .having( + (hint) => hint.response, + 'the response field', + HintResponse.notApplicable, + ) + .having( + (hint) => hint.readableResponse, + 'the readableResponse field', + isA(), + ), ); }, ); @@ -244,7 +275,11 @@ void main() { userId: 'userId', wordId: 'wordId', hints: [ - Hint(question: 'question', response: HintResponse.yes), + Hint( + question: 'question', + response: HintResponse.yes, + readableResponse: 'Yeah!', + ), ], ); @@ -258,6 +293,7 @@ void main() { { 'question': 'question', 'response': 'yes', + 'readableResponse': 'Yeah!', }, ], }, @@ -277,6 +313,7 @@ void main() { Hint( question: 'question', response: HintResponse.yes, + readableResponse: 'Yeah!', ), ], ), diff --git a/test/hint/extensions/hint_response_extension_test.dart b/api/packages/hint_repository/test/src/hint_response_extension_test.dart similarity index 88% rename from test/hint/extensions/hint_response_extension_test.dart rename to api/packages/hint_repository/test/src/hint_response_extension_test.dart index deacd4e72..3848b9ae7 100644 --- a/test/hint/extensions/hint_response_extension_test.dart +++ b/api/packages/hint_repository/test/src/hint_response_extension_test.dart @@ -1,6 +1,6 @@ -import 'package:flutter_test/flutter_test.dart'; import 'package:game_domain/game_domain.dart'; -import 'package:io_crossword/hint/hint.dart'; +import 'package:hint_repository/src/hint_response_extension.dart'; +import 'package:test/test.dart'; void main() { group('HintResponseExtension', () { diff --git a/api/test/routes/game/hint_test.dart b/api/test/routes/game/hint_test.dart index e0e85fcb9..1c0888e94 100644 --- a/api/test/routes/game/hint_test.dart +++ b/api/test/routes/game/hint_test.dart @@ -107,13 +107,23 @@ void main() { userToken: 'token', ), ).thenAnswer( - (_) async => Hint(question: 'question', response: HintResponse.no), + (_) async => Hint( + question: 'question', + response: HintResponse.no, + readableResponse: 'Nope!', + ), ); when( () => hintRepository.saveHints( userId: 'userId', wordId: 'wordId', - hints: [Hint(question: 'question', response: HintResponse.no)], + hints: [ + Hint( + question: 'question', + response: HintResponse.no, + readableResponse: 'Nope!', + ), + ], ), ).thenAnswer((_) async {}); @@ -126,6 +136,7 @@ void main() { 'hint': { 'question': 'question', 'response': 'no', + 'readableResponse': 'Nope!', }, 'maxHints': 10, }), @@ -134,7 +145,13 @@ void main() { () => hintRepository.saveHints( userId: 'userId', wordId: 'wordId', - hints: [Hint(question: 'question', response: HintResponse.no)], + hints: [ + Hint( + question: 'question', + response: HintResponse.no, + readableResponse: 'Nope!', + ), + ], ), ).called(1); }, @@ -201,7 +218,11 @@ void main() { ); }, ); - final hint = Hint(question: 'question', response: HintResponse.yes); + final hint = Hint( + question: 'question', + response: HintResponse.yes, + readableResponse: 'Yes, that is correct!', + ); when( () => hintRepository.getPreviousHints( userId: 'userId', @@ -298,9 +319,21 @@ void main() { 'returns Response with a list of hints', () async { final hintList = [ - Hint(question: 'question1', response: HintResponse.yes), - Hint(question: 'question2', response: HintResponse.notApplicable), - Hint(question: 'question3', response: HintResponse.no), + Hint( + question: 'question1', + response: HintResponse.yes, + readableResponse: 'yes', + ), + Hint( + question: 'question2', + response: HintResponse.notApplicable, + readableResponse: 'nah', + ), + Hint( + question: 'question3', + response: HintResponse.no, + readableResponse: 'nope', + ), ]; when(() => uri.queryParameters).thenReturn({'wordId': 'wordId'}); when(() => hintRepository.isHintsEnabled()) @@ -320,9 +353,21 @@ void main() { await response.json(), equals({ 'hints': [ - {'question': 'question1', 'response': 'yes'}, - {'question': 'question2', 'response': 'notApplicable'}, - {'question': 'question3', 'response': 'no'}, + { + 'question': 'question1', + 'response': 'yes', + 'readableResponse': 'yes', + }, + { + 'question': 'question2', + 'response': 'notApplicable', + 'readableResponse': 'nah', + }, + { + 'question': 'question3', + 'response': 'no', + 'readableResponse': 'nope', + }, ], 'maxHints': 10, }), diff --git a/lib/hint/extensions/extensions.dart b/lib/hint/extensions/extensions.dart deleted file mode 100644 index 0beafd96c..000000000 --- a/lib/hint/extensions/extensions.dart +++ /dev/null @@ -1 +0,0 @@ -export 'hint_response_extension.dart'; diff --git a/lib/hint/hint.dart b/lib/hint/hint.dart index 86095c9ad..b551c310f 100644 --- a/lib/hint/hint.dart +++ b/lib/hint/hint.dart @@ -1,3 +1,2 @@ export 'bloc/hint_bloc.dart'; -export 'extensions/extensions.dart'; export 'widgets/widgets.dart'; diff --git a/lib/hint/widgets/hints_section.dart b/lib/hint/widgets/hints_section.dart index 292acebb1..ab32bf964 100644 --- a/lib/hint/widgets/hints_section.dart +++ b/lib/hint/widgets/hints_section.dart @@ -96,7 +96,7 @@ class HintQuestionResponse extends StatelessWidget { textAlign: TextAlign.center, ), const SizedBox(height: 8), - HintText(text: hint.response.readable), + HintText(text: hint.readableResponse), const SizedBox(height: 8), ], ); diff --git a/packages/api_client/test/src/resources/hint_resource_test.dart b/packages/api_client/test/src/resources/hint_resource_test.dart index 041dd1ed5..1184bee18 100644 --- a/packages/api_client/test/src/resources/hint_resource_test.dart +++ b/packages/api_client/test/src/resources/hint_resource_test.dart @@ -36,6 +36,7 @@ void main() { final hint = Hint( question: 'question', response: HintResponse.no, + readableResponse: 'Nope!', ); when(() => response.statusCode).thenReturn(HttpStatus.ok); when(() => response.body).thenReturn( @@ -65,6 +66,7 @@ void main() { final hint = Hint( question: 'is it a question?', response: HintResponse.yes, + readableResponse: 'Yes, that is correct!', ); when(() => response.statusCode).thenReturn(HttpStatus.ok); when(() => response.body).thenReturn( @@ -137,6 +139,7 @@ void main() { final hint = Hint( question: 'question', response: HintResponse.no, + readableResponse: 'Nope!', ); final hintList = [hint, hint, hint]; final responseJson = { @@ -160,6 +163,7 @@ void main() { final hint = Hint( question: 'question', response: HintResponse.no, + readableResponse: 'Nope!', ); final hintList = [hint, hint, hint]; final hintJson = { diff --git a/test/hint/bloc/hint_bloc_test.dart b/test/hint/bloc/hint_bloc_test.dart index 05f528a03..79a09db57 100644 --- a/test/hint/bloc/hint_bloc_test.dart +++ b/test/hint/bloc/hint_bloc_test.dart @@ -76,14 +76,24 @@ void main() { when( () => hintResource.generateHint(wordId: 'id', question: 'blue?'), ).thenAnswer( - (_) async => - (Hint(question: 'blue?', response: HintResponse.no), 9), + (_) async => ( + Hint( + question: 'blue?', + response: HintResponse.no, + readableResponse: 'Nope!', + ), + 9 + ), ); }, seed: () => HintState( status: HintStatus.asking, hints: [ - Hint(question: 'is it orange?', response: HintResponse.no), + Hint( + question: 'is it orange?', + response: HintResponse.no, + readableResponse: 'No!', + ), ], ), build: () => HintBloc( @@ -97,14 +107,26 @@ void main() { HintState( status: HintStatus.thinking, hints: [ - Hint(question: 'is it orange?', response: HintResponse.no), + Hint( + question: 'is it orange?', + response: HintResponse.no, + readableResponse: 'No!', + ), ], ), HintState( status: HintStatus.answered, hints: [ - Hint(question: 'is it orange?', response: HintResponse.no), - Hint(question: 'blue?', response: HintResponse.no), + Hint( + question: 'is it orange?', + response: HintResponse.no, + readableResponse: 'No!', + ), + Hint( + question: 'blue?', + response: HintResponse.no, + readableResponse: 'Nope!', + ), ], maxHints: 9, ), @@ -116,7 +138,11 @@ void main() { seed: () => HintState( status: HintStatus.asking, hints: [ - Hint(question: 'is it orange?', response: HintResponse.no), + Hint( + question: 'is it orange?', + response: HintResponse.no, + readableResponse: 'No!', + ), ], maxHints: 1, ), @@ -150,8 +176,16 @@ void main() { when(() => hintResource.getHints(wordId: 'id')).thenAnswer( (_) async => ( [ - Hint(question: 'is it orange?', response: HintResponse.no), - Hint(question: 'is it blue?', response: HintResponse.yes), + Hint( + question: 'is it orange?', + response: HintResponse.no, + readableResponse: 'No!', + ), + Hint( + question: 'is it blue?', + response: HintResponse.yes, + readableResponse: 'Yes!', + ), ], 8 ), @@ -165,8 +199,16 @@ void main() { expect: () => const [ HintState( hints: [ - Hint(question: 'is it orange?', response: HintResponse.no), - Hint(question: 'is it blue?', response: HintResponse.yes), + Hint( + question: 'is it orange?', + response: HintResponse.no, + readableResponse: 'No!', + ), + Hint( + question: 'is it blue?', + response: HintResponse.yes, + readableResponse: 'Yes!', + ), ], maxHints: 8, ), @@ -182,8 +224,16 @@ void main() { }, seed: () => HintState( hints: [ - Hint(question: 'is it orange?', response: HintResponse.no), - Hint(question: 'is it blue?', response: HintResponse.yes), + Hint( + question: 'is it orange?', + response: HintResponse.no, + readableResponse: 'No!', + ), + Hint( + question: 'is it blue?', + response: HintResponse.yes, + readableResponse: 'Yes!', + ), ], ), build: () => HintBloc( diff --git a/test/hint/bloc/hint_state_test.dart b/test/hint/bloc/hint_state_test.dart index c8d006b09..0be29d29e 100644 --- a/test/hint/bloc/hint_state_test.dart +++ b/test/hint/bloc/hint_state_test.dart @@ -44,6 +44,7 @@ void main() { final hint = Hint( question: 'is it orange?', response: HintResponse.notApplicable, + readableResponse: 'N/A', ); expect( state.copyWith(hints: [hint, hint]), diff --git a/test/hint/widgets/gemini_hint_button_test.dart b/test/hint/widgets/gemini_hint_button_test.dart index 3cf304d1c..01ffb9431 100644 --- a/test/hint/widgets/gemini_hint_button_test.dart +++ b/test/hint/widgets/gemini_hint_button_test.dart @@ -64,7 +64,11 @@ void main() { testWidgets( 'is disabled when there are no hints left', (tester) async { - final hint = Hint(question: 'is it orange?', response: HintResponse.no); + final hint = Hint( + question: 'is it orange?', + response: HintResponse.no, + readableResponse: 'Nope!', + ); when(() => hintBloc.state).thenReturn( HintState(hints: [hint, hint, hint], maxHints: 3), ); diff --git a/test/hint/widgets/hints_section_test.dart b/test/hint/widgets/hints_section_test.dart index eec97e6ec..752cce5f4 100644 --- a/test/hint/widgets/hints_section_test.dart +++ b/test/hint/widgets/hints_section_test.dart @@ -51,7 +51,11 @@ void main() { testWidgets( 'renders "run out of hints" when there are no more hints available', (tester) async { - final hint = Hint(question: 'Q1', response: HintResponse.yes); + final hint = Hint( + question: 'Q1', + response: HintResponse.yes, + readableResponse: 'Yes', + ); when(() => hintBloc.state).thenReturn( HintState( status: HintStatus.asking, @@ -81,7 +85,11 @@ void main() { 'renders "1 of 2 hints remaining" when the hint mode is active ' 'and there are hints available', (tester) async { - final hint = Hint(question: 'Q1', response: HintResponse.yes); + final hint = Hint( + question: 'Q1', + response: HintResponse.yes, + readableResponse: 'Yes', + ); when(() => hintBloc.state).thenReturn( HintState( status: HintStatus.asking, @@ -122,10 +130,26 @@ void main() { 'renders as many $HintQuestionResponse widgets as hints are available', (tester) async { final hints = [ - Hint(question: 'Q1', response: HintResponse.yes), - Hint(question: 'Q2', response: HintResponse.no), - Hint(question: 'Q3', response: HintResponse.notApplicable), - Hint(question: 'Q4', response: HintResponse.no), + Hint( + question: 'Q1', + response: HintResponse.yes, + readableResponse: 'Yes', + ), + Hint( + question: 'Q2', + response: HintResponse.no, + readableResponse: 'No', + ), + Hint( + question: 'Q3', + response: HintResponse.notApplicable, + readableResponse: 'N/A', + ), + Hint( + question: 'Q4', + response: HintResponse.no, + readableResponse: 'No', + ), ]; when(() => hintBloc.state).thenReturn( HintState(hints: hints, isHintsEnabled: true),