diff --git a/lib/about/view/about_project_details.dart b/lib/about/view/about_project_details.dart index 69fe652e1..c9612586f 100644 --- a/lib/about/view/about_project_details.dart +++ b/lib/about/view/about_project_details.dart @@ -24,36 +24,7 @@ class AboutProjectDetails extends StatelessWidget { child: const Icon(Icons.image, size: 50), ), const SizedBox(height: 24), - RichText( - text: TextSpan( - text: '${l10n.learn} ', - style: textTheme.titleMedium, - children: [ - TextSpan( - text: l10n.howMade, - style: textTheme.titleMedium?.copyWith( - color: linkColor, - ), - // TODO(Ayad): add link - // recognizer: TapGestureRecognizer()..onTap = () {}, - ), - TextSpan(text: ' ${l10n.and} '), - TextSpan( - text: l10n.openSourceCode, - style: textTheme.titleMedium?.copyWith( - color: linkColor, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - context.launchUrl(ProjectDetailsLinks.github); - }, - ), - const TextSpan( - text: '.', - ), - ], - ), - ), + const HowMade(), const SizedBox(height: 24), Text( '${l10n.otherLinks}:', diff --git a/lib/about/view/about_view.dart b/lib/about/view/about_view.dart index cce60903c..cdc9497e7 100644 --- a/lib/about/view/about_view.dart +++ b/lib/about/view/about_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:io_crossword/extensions/extensions.dart'; import 'package:io_crossword/l10n/l10n.dart'; import 'package:io_crossword/project_details/link/project_details_links.dart'; +import 'package:io_crossword/widget/widget.dart'; import 'package:io_crossword_ui/io_crossword_ui.dart'; part 'about_how_to_play.dart'; diff --git a/lib/end_game/view/end_game_page.dart b/lib/end_game/view/end_game_page.dart index c597d890b..d37ad0fa0 100644 --- a/lib/end_game/view/end_game_page.dart +++ b/lib/end_game/view/end_game_page.dart @@ -1,15 +1,13 @@ -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:game_domain/game_domain.dart'; import 'package:io_crossword/assets/assets.dart'; -import 'package:io_crossword/extensions/context_ext.dart'; import 'package:io_crossword/game_intro/game_intro.dart'; import 'package:io_crossword/l10n/l10n.dart'; import 'package:io_crossword/leaderboard/view/leaderboard_page.dart'; import 'package:io_crossword/player/player.dart'; -import 'package:io_crossword/project_details/link/project_details_links.dart'; import 'package:io_crossword/share/share.dart'; +import 'package:io_crossword/widget/widget.dart'; import 'package:io_crossword_ui/io_crossword_ui.dart'; part '../widgets/leaderboard_button.dart'; diff --git a/lib/end_game/view/end_game_view_content.dart b/lib/end_game/view/end_game_view_content.dart index 5c5c99d4f..e94f32c11 100644 --- a/lib/end_game/view/end_game_view_content.dart +++ b/lib/end_game/view/end_game_view_content.dart @@ -23,7 +23,7 @@ class EndGameContent extends StatelessWidget { textAlign: TextAlign.center, ), const SizedBox(height: 24), - const EndGameHowMade(), + const HowMade(), const SizedBox(height: 24), const Center( child: PlayerInitials(), @@ -105,52 +105,6 @@ class ActionButtonsEndGame extends StatelessWidget { } } -@visibleForTesting -class EndGameHowMade extends StatelessWidget { - @visibleForTesting - const EndGameHowMade({super.key}); - - @override - Widget build(BuildContext context) { - final l10n = context.l10n; - - final textTheme = Theme.of(context).textTheme; - const linkColor = IoCrosswordColors.linkBlue; - - return RichText( - textAlign: TextAlign.center, - text: TextSpan( - text: '${l10n.learn} ', - style: textTheme.titleMedium, - children: [ - TextSpan( - text: l10n.howMade, - style: textTheme.titleMedium?.copyWith( - color: linkColor, - ), - // TODO(Ayad): add link - // recognizer: TapGestureRecognizer()..onTap = () {}, - ), - TextSpan(text: ' ${l10n.and} '), - TextSpan( - text: l10n.openSourceCode, - style: textTheme.titleMedium?.copyWith( - color: linkColor, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - context.launchUrl(ProjectDetailsLinks.github); - }, - ), - const TextSpan( - text: '.', - ), - ], - ), - ); - } -} - @visibleForTesting class EndGameImage extends StatelessWidget { @visibleForTesting diff --git a/lib/project_details/view/project_details_view.dart b/lib/project_details/view/project_details_view.dart index b16713c21..915cc4859 100644 --- a/lib/project_details/view/project_details_view.dart +++ b/lib/project_details/view/project_details_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:io_crossword/extensions/extensions.dart'; import 'package:io_crossword/l10n/l10n.dart'; import 'package:io_crossword/project_details/link/project_details_links.dart'; +import 'package:io_crossword/widget/widget.dart'; import 'package:io_crossword_ui/io_crossword_ui.dart'; class ProjectDetailsView extends StatelessWidget { @@ -105,41 +106,7 @@ class ProjectDetailsContent extends StatelessWidget { child: const Icon(Icons.image, size: 50), ), SizedBox(height: verticalSpacing), - RichText( - textAlign: TextAlign.center, - text: TextSpan( - text: '${l10n.learn} ', - style: textTheme.titleMedium, - children: [ - TextSpan( - text: l10n.howMade, - style: textTheme.titleMedium?.copyWith( - color: linkColor, - decoration: TextDecoration.underline, - decorationColor: linkColor, - ), - // TODO(Ayad): add link - // recognizer: TapGestureRecognizer()..onTap = () {}, - ), - TextSpan(text: ' ${l10n.and} '), - TextSpan( - text: l10n.openSourceCode, - style: textTheme.titleMedium?.copyWith( - color: linkColor, - decoration: TextDecoration.underline, - decorationColor: linkColor, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - context.launchUrl(ProjectDetailsLinks.github); - }, - ), - const TextSpan( - text: '.', - ), - ], - ), - ), + const HowMade(), SizedBox(height: verticalSpacing), Text( '${l10n.otherLinks}:', diff --git a/lib/widget/how_made.dart b/lib/widget/how_made.dart new file mode 100644 index 000000000..9ed6cbba8 --- /dev/null +++ b/lib/widget/how_made.dart @@ -0,0 +1,50 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:io_crossword/extensions/context_ext.dart'; +import 'package:io_crossword/l10n/l10n.dart'; +import 'package:io_crossword/project_details/link/project_details_links.dart'; +import 'package:io_crossword_ui/io_crossword_ui.dart'; + +class HowMade extends StatelessWidget { + const HowMade({super.key}); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + + final textTheme = Theme.of(context).textTheme; + const linkColor = IoCrosswordColors.linkBlue; + + return RichText( + textAlign: TextAlign.center, + text: TextSpan( + text: '${l10n.learn} ', + style: textTheme.titleMedium, + children: [ + TextSpan( + text: l10n.howMade, + style: textTheme.titleMedium?.copyWith( + color: linkColor, + ), + // TODO(Ayad): add link + // recognizer: TapGestureRecognizer()..onTap = () {}, + ), + TextSpan(text: ' ${l10n.and} '), + TextSpan( + text: l10n.openSourceCode, + style: textTheme.titleMedium?.copyWith( + color: linkColor, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + context.launchUrl(ProjectDetailsLinks.github); + }, + ), + const TextSpan( + text: '.', + ), + ], + ), + ); + } +} diff --git a/lib/widget/widget.dart b/lib/widget/widget.dart new file mode 100644 index 000000000..933e2961b --- /dev/null +++ b/lib/widget/widget.dart @@ -0,0 +1 @@ +export 'how_made.dart'; diff --git a/test/about/view/about_project_details_test.dart b/test/about/view/about_project_details_test.dart index eb3826049..0a855f38e 100644 --- a/test/about/view/about_project_details_test.dart +++ b/test/about/view/about_project_details_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:io_crossword/about/view/about_view.dart'; import 'package:io_crossword/l10n/l10n.dart'; +import 'package:io_crossword/widget/widget.dart'; import 'package:mocktail/mocktail.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; @@ -37,41 +38,11 @@ void main() { }); testWidgets( - 'displays initial information how made and open source', + 'renders HowMade', (tester) async { await tester.pumpApp(AboutProjectDetails()); - final text = - '${l10n.learn} ${l10n.howMade} ${l10n.and} ${l10n.openSourceCode}.'; - - expect(find.text(text, findRichText: true), findsOneWidget); - }, - ); - - testWidgets( - 'calls launchUrl when tapped on open source code', - (tester) async { - await tester.pumpApp(AboutProjectDetails()); - - final finder = find.byWidgetPredicate( - (widget) => - widget is RichText && - find.tapTextSpan( - widget, - l10n.openSourceCode, - ), - ); - - await tester.tap(finder); - - await tester.pumpAndSettle(); - - verify( - () => urlLauncher.launchUrl( - 'https://github.com/VGVentures/io_crossword', - any(), - ), - ); + expect(find.byType(HowMade), findsOneWidget); }, ); diff --git a/test/end_game/view/end_game_view_content_test.dart b/test/end_game/view/end_game_view_content_test.dart index a93b3c0f1..f47eef7a2 100644 --- a/test/end_game/view/end_game_view_content_test.dart +++ b/test/end_game/view/end_game_view_content_test.dart @@ -10,18 +10,11 @@ import 'package:io_crossword/game_intro/game_intro.dart'; import 'package:io_crossword/l10n/l10n.dart'; import 'package:io_crossword/player/player.dart'; import 'package:io_crossword/share/share.dart'; +import 'package:io_crossword/widget/widget.dart'; import 'package:mocktail/mocktail.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; import '../../helpers/helpers.dart'; -class _MockUrlLauncherPlatform extends Mock - with MockPlatformInterfaceMixin - implements UrlLauncherPlatform {} - -class _FakeLaunchOptions extends Fake implements LaunchOptions {} - class _MockPlayerBloc extends MockBloc implements PlayerBloc {} @@ -39,10 +32,10 @@ void main() { expect(find.text(l10n.thanksForContributing), findsOneWidget); }); - testWidgets('displays EndGameHowMade', (tester) async { + testWidgets('displays HowMade', (tester) async { await tester.pumpApp(SingleChildScrollView(child: EndGameContent())); - expect(find.byType(EndGameHowMade), findsOneWidget); + expect(find.byType(HowMade), findsOneWidget); }); testWidgets('displays EndGameImage', (tester) async { @@ -110,63 +103,6 @@ void main() { }); }); - group('$EndGameHowMade', () { - late UrlLauncherPlatform urlLauncher; - - setUpAll(() { - registerFallbackValue(_FakeLaunchOptions()); - }); - - setUp(() { - urlLauncher = _MockUrlLauncherPlatform(); - - UrlLauncherPlatform.instance = urlLauncher; - - when(() => urlLauncher.canLaunch(any())).thenAnswer((_) async => true); - when(() => urlLauncher.launchUrl(any(), any())) - .thenAnswer((_) async => true); - }); - - testWidgets( - 'displays information how made and open source', - (tester) async { - await tester.pumpApp(EndGameHowMade()); - - final text = - '${l10n.learn} ${l10n.howMade} ${l10n.and} ${l10n.openSourceCode}.'; - - expect(find.text(text, findRichText: true), findsOneWidget); - }, - ); - - testWidgets( - 'calls launchUrl when tapped on open source code', - (tester) async { - await tester.pumpApp(EndGameHowMade()); - - final finder = find.byWidgetPredicate( - (widget) => - widget is RichText && - find.tapTextSpan( - widget, - l10n.openSourceCode, - ), - ); - - await tester.tap(finder); - - await tester.pumpAndSettle(); - - verify( - () => urlLauncher.launchUrl( - 'https://github.com/VGVentures/io_crossword', - any(), - ), - ); - }, - ); - }); - group('$EndGameImage', () { late PlayerBloc playerBloc; diff --git a/test/project_details/view/project_details_view_test.dart b/test/project_details/view/project_details_view_test.dart index 597e7135e..1f0d99dac 100644 --- a/test/project_details/view/project_details_view_test.dart +++ b/test/project_details/view/project_details_view_test.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:io_crossword/l10n/l10n.dart'; import 'package:io_crossword/project_details/view/project_details_view.dart'; +import 'package:io_crossword/widget/widget.dart'; import 'package:io_crossword_ui/io_crossword_ui.dart'; import 'package:mocktail/mocktail.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -59,41 +60,11 @@ void main() { }); testWidgets( - 'displays initial information how made and open source', + 'renders HowMade', (tester) async { await tester.pumpApp(const ProjectDetailsContent()); - final text = '${l10n.learn} ${l10n.howMade} ${l10n.and} ' - '${l10n.openSourceCode}.'; - - expect(find.text(text, findRichText: true), findsOneWidget); - }, - ); - - testWidgets( - 'calls launchUrl when tapped on open source code', - (tester) async { - await tester.pumpApp(const ProjectDetailsContent()); - - final finder = find.byWidgetPredicate( - (widget) => - widget is RichText && - find.tapTextSpan( - widget, - l10n.openSourceCode, - ), - ); - - await tester.tap(finder); - - await tester.pumpAndSettle(); - - verify( - () => urlLauncher.launchUrl( - 'https://github.com/VGVentures/io_crossword', - any(), - ), - ); + expect(find.byType(HowMade), findsOneWidget); }, ); diff --git a/test/widget/how_made_test.dart b/test/widget/how_made_test.dart new file mode 100644 index 000000000..a58e922f0 --- /dev/null +++ b/test/widget/how_made_test.dart @@ -0,0 +1,80 @@ +// ignore_for_file: prefer_const_constructors + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:io_crossword/l10n/l10n.dart'; +import 'package:io_crossword/widget/widget.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + +import '../helpers/helpers.dart'; + +class _MockUrlLauncherPlatform extends Mock + with MockPlatformInterfaceMixin + implements UrlLauncherPlatform {} + +class _FakeLaunchOptions extends Fake implements LaunchOptions {} + +void main() { + group('$HowMade', () { + late UrlLauncherPlatform urlLauncher; + + late AppLocalizations l10n; + + setUpAll(() async { + l10n = await AppLocalizations.delegate.load(Locale('en')); + registerFallbackValue(_FakeLaunchOptions()); + }); + + setUp(() { + urlLauncher = _MockUrlLauncherPlatform(); + + UrlLauncherPlatform.instance = urlLauncher; + + when(() => urlLauncher.canLaunch(any())).thenAnswer((_) async => true); + when(() => urlLauncher.launchUrl(any(), any())) + .thenAnswer((_) async => true); + }); + + testWidgets( + 'displays information how made and open source', + (tester) async { + await tester.pumpApp(HowMade()); + + final text = + '${l10n.learn} ${l10n.howMade} ${l10n.and} ${l10n.openSourceCode}.'; + + expect(find.text(text, findRichText: true), findsOneWidget); + }, + ); + + testWidgets( + 'calls launchUrl when tapped on open source code', + (tester) async { + await tester.pumpApp(HowMade()); + + final finder = find.byWidgetPredicate( + (widget) => + widget is RichText && + find.tapTextSpan( + widget, + l10n.openSourceCode, + ), + ); + + await tester.tap(finder); + + await tester.pumpAndSettle(); + + verify( + () => urlLauncher.launchUrl( + 'https://github.com/VGVentures/io_crossword', + any(), + ), + ); + }, + ); + }); +}