From f5bd3cc565e26e4f23e15684c59760a8d2070ab7 Mon Sep 17 00:00:00 2001 From: Ayad Laaouissi Jones <42848220+AyadLaouissi@users.noreply.github.com> Date: Thu, 2 May 2024 13:26:18 +0200 Subject: [PATCH] feat: adds solved characters to CrosswordInput (#422) --- .../game_domain/lib/src/models/word.dart | 15 +++++++ .../test/src/models/word_test.dart | 35 ++++++++++++++++ lib/crossword2/view/crossword2_view.dart | 1 + lib/crossword2/widgets/crossword_input.dart | 3 ++ .../view/word_solving_view.dart | 1 + .../crossword2/view/crossword2_view_test.dart | 1 + .../widgets/crossword_input_test.dart | 35 +++++++++++++++- .../view/word_selection_view_test.dart | 3 ++ .../view/word_solving_view_test.dart | 42 +++++++++++++++++++ 9 files changed, 135 insertions(+), 1 deletion(-) diff --git a/api/packages/game_domain/lib/src/models/word.dart b/api/packages/game_domain/lib/src/models/word.dart index 8cdb3c5ed..6b41a3b23 100644 --- a/api/packages/game_domain/lib/src/models/word.dart +++ b/api/packages/game_domain/lib/src/models/word.dart @@ -68,6 +68,21 @@ class Word extends Equatable { @JsonKey() final Mascots? mascot; + /// Returns the solved characters with the index position and character + /// solved. + Map get solvedCharacters { + final map = {}; + + for (var i = 0; i < answer.length; i++) { + final character = answer[i]; + if (character != ' ') { + map[i] = character; + } + } + + return map; + } + /// Returns a json representation from this instance. Map toJson() => _$WordToJson(this); diff --git a/api/packages/game_domain/test/src/models/word_test.dart b/api/packages/game_domain/test/src/models/word_test.dart index 610fb6626..110439e89 100644 --- a/api/packages/game_domain/test/src/models/word_test.dart +++ b/api/packages/game_domain/test/src/models/word_test.dart @@ -161,5 +161,40 @@ void main() { expect(word.isSolved, isFalse); }); }); + + group('solvedCharacters', () { + test(' is empty when there are no characters solved', () { + final word = Word( + id: '1', + position: Point(1, 2), + axis: Axis.horizontal, + answer: ' ', + clue: 'clue', + ); + + expect(word.solvedCharacters, isEmpty); + }); + + test(' returns the solved characters', () { + final word = Word( + id: '1', + position: Point(1, 2), + axis: Axis.horizontal, + answer: ' ap y', + clue: 'clue', + ); + + expect( + word.solvedCharacters, + equals( + { + 1: 'a', + 2: 'p', + 4: 'y', + }, + ), + ); + }); + }); }); } diff --git a/lib/crossword2/view/crossword2_view.dart b/lib/crossword2/view/crossword2_view.dart index 9d959fb51..8685d9a39 100644 --- a/lib/crossword2/view/crossword2_view.dart +++ b/lib/crossword2/view/crossword2_view.dart @@ -131,6 +131,7 @@ class _CrosswordStack extends StatelessWidget { style: theme.io.wordInput.secondary, direction: word.axis.toAxis(), length: selectedWord.word.length, + characters: selectedWord.word.solvedCharacters, ), ); }, diff --git a/lib/crossword2/widgets/crossword_input.dart b/lib/crossword2/widgets/crossword_input.dart index 643a83de2..a90b573c1 100644 --- a/lib/crossword2/widgets/crossword_input.dart +++ b/lib/crossword2/widgets/crossword_input.dart @@ -7,6 +7,7 @@ import 'package:io_crossword_ui/io_crossword_ui.dart'; class CrosswordInput extends StatefulWidget { const CrosswordInput({ required this.length, + required this.characters, this.style, this.direction = Axis.horizontal, super.key, @@ -15,6 +16,7 @@ class CrosswordInput extends StatefulWidget { final IoWordInputStyle? style; final int length; final Axis direction; + final Map? characters; @override State createState() => _CrosswordInputState(); @@ -53,6 +55,7 @@ class _CrosswordInputState extends State { style: widget.style, direction: widget.direction, length: widget.length, + characters: widget.characters, onSubmit: (value) { context .read() diff --git a/lib/word_selection/view/word_solving_view.dart b/lib/word_selection/view/word_solving_view.dart index 22ba1c8cf..e856fd29a 100644 --- a/lib/word_selection/view/word_solving_view.dart +++ b/lib/word_selection/view/word_solving_view.dart @@ -114,6 +114,7 @@ class _WordSolvingSmallViewState extends State { const SizedBox(height: 32), CrosswordInput( length: selectedWord.word.length, + characters: selectedWord.word.solvedCharacters, ), const SizedBox(height: 16), Text( diff --git a/test/crossword2/view/crossword2_view_test.dart b/test/crossword2/view/crossword2_view_test.dart index 8292beaad..31a816a27 100644 --- a/test/crossword2/view/crossword2_view_test.dart +++ b/test/crossword2/view/crossword2_view_test.dart @@ -40,6 +40,7 @@ void main() { when(() => word.answer).thenReturn('word'); when(() => word.isSolved).thenReturn(false); when(() => word.solvedTimestamp).thenReturn(null); + when(() => word.solvedCharacters).thenReturn({}); }); testWidgets('requests chunk', (tester) async { diff --git a/test/crossword2/widgets/crossword_input_test.dart b/test/crossword2/widgets/crossword_input_test.dart index 25e0743a1..e92b81499 100644 --- a/test/crossword2/widgets/crossword_input_test.dart +++ b/test/crossword2/widgets/crossword_input_test.dart @@ -28,7 +28,10 @@ void main() { DefaultWordInputController( child: BlocProvider.value( value: wordSelectionBloc, - child: const CrosswordInput(length: 5), + child: const CrosswordInput( + length: 5, + characters: {}, + ), ), ), ); @@ -42,5 +45,35 @@ void main() { ).called(1); }, ); + + testWidgets( + 'sends characters correctly to IoWordInput', + (tester) async { + await tester.pumpApp( + DefaultWordInputController( + child: BlocProvider.value( + value: wordSelectionBloc, + child: const CrosswordInput( + length: 5, + characters: { + 1: 'a', + 4: 'y', + }, + ), + ), + ), + ); + + expect( + tester.widget(find.byType(IoWordInput)).characters, + equals( + { + 1: 'a', + 4: 'y', + }, + ), + ); + }, + ); }); } diff --git a/test/word_focused/view/word_selection_view_test.dart b/test/word_focused/view/word_selection_view_test.dart index 453d2e04b..2f58eef19 100644 --- a/test/word_focused/view/word_selection_view_test.dart +++ b/test/word_focused/view/word_selection_view_test.dart @@ -41,6 +41,9 @@ class _FakeWord extends Fake implements Word { @override Axis get axis => Axis.horizontal; + + @override + Map get solvedCharacters => {}; } void main() { diff --git a/test/word_focused/view/word_solving_view_test.dart b/test/word_focused/view/word_solving_view_test.dart index b828abf52..be9b53f35 100644 --- a/test/word_focused/view/word_solving_view_test.dart +++ b/test/word_focused/view/word_solving_view_test.dart @@ -37,6 +37,9 @@ class _FakeWord extends Fake implements Word { @override int get length => 6; + + @override + Map get solvedCharacters => {}; } void main() { @@ -257,6 +260,45 @@ void main() { }, ); + testWidgets( + 'a $CrosswordInput', + (tester) async { + await tester.pumpApp(widget); + expect(find.byType(CrosswordInput), findsOneWidget); + }, + ); + + testWidgets( + 'a $CrosswordInput with solved characters', + (tester) async { + final word = Word( + id: 'id', + position: Point(1, 2), + axis: Axis.horizontal, + clue: '', + answer: ' a y', + ); + + when(() => wordSelectionBloc.state).thenReturn( + WordSelectionState( + status: WordSelectionStatus.solving, + word: SelectedWord( + section: (0, 0), + word: word, + ), + ), + ); + + await tester.pumpApp(widget); + expect( + tester + .widget(find.byType(CrosswordInput)) + .characters, + equals({1: 'a', 4: 'y'}), + ); + }, + ); + testWidgets( 'incorrectAnswer text when the status is incorrect', (tester) async {