diff --git a/README.md b/README.md index 3559c90..65f55b2 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ An overview of the current state management libraries explored is presented belo | State Manager | Applied | Unit tests | Widget tests | |---------------|---------|:----------:|--------------| -| Provider | Yes | Yes | In Progress | +| Provider | Yes | Yes | Yes | | Riverpod | Yes | Yes | In Progress | | Bloc | Yes | Yes | Yes | | Cubit | Yes | Yes | Yes | diff --git a/lib/layers/presentation/using_provider/details_page/change_notifier/details_page_change_notifier.dart b/lib/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier.dart similarity index 53% rename from lib/layers/presentation/using_provider/details_page/change_notifier/details_page_change_notifier.dart rename to lib/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier.dart index 8ece3ab..a0be312 100644 --- a/lib/layers/presentation/using_provider/details_page/change_notifier/details_page_change_notifier.dart +++ b/lib/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier.dart @@ -1,8 +1,8 @@ import 'package:flutter/foundation.dart'; import 'package:rickmorty/layers/domain/entity/character.dart'; -class DetailsPageChangeNotifier extends ChangeNotifier { - DetailsPageChangeNotifier({required this.character}); +class CharacterDetailsChangeNotifier extends ChangeNotifier { + CharacterDetailsChangeNotifier({required this.character}); final Character character; } diff --git a/lib/layers/presentation/using_provider/details_page/view/character_details_page.dart b/lib/layers/presentation/using_provider/details_page/view/character_details_page.dart index 53cbda4..9c4f8ef 100644 --- a/lib/layers/presentation/using_provider/details_page/view/character_details_page.dart +++ b/lib/layers/presentation/using_provider/details_page/view/character_details_page.dart @@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:rickmorty/layers/domain/entity/character.dart'; -import 'package:rickmorty/layers/presentation/using_provider/details_page/change_notifier/details_page_change_notifier.dart'; +import 'package:rickmorty/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier.dart'; // ----------------------------------------------------------------------------- // Page @@ -14,7 +14,7 @@ class CharacterDetailsPage extends StatelessWidget { return MaterialPageRoute( builder: (context) { return ChangeNotifierProvider( - create: (_) => DetailsPageChangeNotifier(character: character), + create: (_) => CharacterDetailsChangeNotifier(character: character), child: const CharacterDetailsPage(), ); }, @@ -56,7 +56,7 @@ class _Content extends StatelessWidget { final colorScheme = theme.colorScheme; final character = context.select( - (DetailsPageChangeNotifier cn) => cn.character, + (CharacterDetailsChangeNotifier cn) => cn.character, ); return SingleChildScrollView( @@ -89,9 +89,7 @@ class _Content extends StatelessWidget { Text( 'Status: ${character.isAlive ? 'ALIVE!' : 'DEAD!!'}', style: textTheme.titleMedium!.copyWith( - color: character.isAlive - ? Colors.lightGreen - : Colors.redAccent, + color: character.isAlive ? Colors.lightGreen : Colors.redAccent, ), ), const SizedBox(height: 8), @@ -152,33 +150,48 @@ class _Content extends StatelessWidget { itemCount: character.episode?.length ?? 0, itemBuilder: (context, index) { final ep = character.episode![index]; - final name = ep.split('/').last; - return Padding( - padding: const EdgeInsets.only(left: 12.0, top: 8), - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(16), - ), - color: colorScheme.surfaceVariant, - ), - height: 80, - width: 80, - child: Center( - child: Text( - name, - style: textTheme.bodyLarge!.copyWith( - color: colorScheme.onSurfaceVariant, - ), - ), - ), - ), - ); + return EpisodeItem(ep: ep); }, ), - ) + ), ], ), ); } } + +// ----------------------------------------------------------------------------- +// Episode +// ----------------------------------------------------------------------------- +class EpisodeItem extends StatelessWidget { + const EpisodeItem({super.key, required this.ep}); + + final String ep; + + @override + Widget build(BuildContext context) { + final textTheme = Theme.of(context).textTheme; + final colorScheme = Theme.of(context).colorScheme; + final name = ep.split('/').last; + + return Padding( + padding: const EdgeInsets.only(left: 12.0, top: 8), + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(16)), + color: colorScheme.surfaceVariant, + ), + height: 80, + width: 80, + child: Center( + child: Text( + name, + style: textTheme.bodyLarge!.copyWith( + color: colorScheme.onSurfaceVariant, + ), + ), + ), + ), + ); + } +} diff --git a/test/lib/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier_test.dart b/test/lib/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier_test.dart new file mode 100644 index 0000000..2d5f2e7 --- /dev/null +++ b/test/lib/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier_test.dart @@ -0,0 +1,16 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:rickmorty/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier.dart'; + +import '../../../../../../fixtures/fixtures.dart'; + +void main() { + group('CharacterDetailsChangeNotifier', () { + test('initial state is correct', () { + final c = characterList1.first; + + final notifier = CharacterDetailsChangeNotifier(character: c); + + expect(notifier.character, c); + }); + }); +} diff --git a/test/lib/layers/presentation/using_provider/details_page/view/character_details_page_test.dart b/test/lib/layers/presentation/using_provider/details_page/view/character_details_page_test.dart new file mode 100644 index 0000000..5b03e7b --- /dev/null +++ b/test/lib/layers/presentation/using_provider/details_page/view/character_details_page_test.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:rickmorty/layers/presentation/using_provider/details_page/change_notifier/character_details_change_notifier.dart'; +import 'package:rickmorty/layers/presentation/using_provider/details_page/view/character_details_page.dart'; + +import '../../../../../../fixtures/fixtures.dart'; + +void main() { + testWidgets('CharacterDetailsPage should render correctly', (WidgetTester tester) async { + final character = characterList1.first; + + // Build our app and trigger a frame. + await tester.pumpWidget( + MaterialApp( + home: ChangeNotifierProvider( + create: (_) => CharacterDetailsChangeNotifier(character: character), + child: const CharacterDetailsPage(), + ), + ), + ); + + // Find items on the page + expect(find.text('Details'), findsOneWidget); + expect(find.text(character.name!), findsOneWidget); + expect(find.text('Origin: ${character.origin!.name}'), findsOneWidget); + expect(find.text('Species: ${character.species}'), findsOneWidget); + expect(find.text('Type: ${character.type}'), findsOneWidget); + expect(find.text('Gender: ${character.gender}'), findsOneWidget); + expect(find.text('Status: ${character.isAlive ? 'ALIVE!' : 'DEAD!'}'), findsOneWidget); + expect(find.text('Last location: ${character.location!.name}'), findsOneWidget); + expectLater(find.byType(EpisodeItem), findsNWidgets(character.episode!.length)); + }); +}