feat: moved open links to info display and added link to OS

pull/359/head
RuiAlonso 3 years ago
parent b9e356cbbe
commit 883dfebad2

@ -8,8 +8,6 @@ import 'package:pinball/game/components/backbox/displays/displays.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:pinball_theme/pinball_theme.dart' hide Assets;
import 'package:pinball_ui/pinball_ui.dart';
import 'package:share_repository/share_repository.dart';
/// {@template backbox}
/// The [Backbox] of the pinball machine.
@ -79,12 +77,7 @@ class Backbox extends PositionComponent with ZIndex {
_display.add(
GameOverInfoDisplay(
onShare: () {
_bloc.add(
ShareScoreRequested(score: state.score),
);
},
onNavigate: () {
openLink(ShareRepository.googleIOEvent);
_bloc.add(ShareScoreRequested(score: state.score));
},
),
);

@ -7,15 +7,12 @@ import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:pinball_ui/pinball_ui.dart';
import 'package:share_repository/share_repository.dart';
/// Signature for the callback called when the user tries to share their score
/// from the [GameOverInfoDisplay].
typedef OnShareTap = void Function();
/// Signature for the callback called when the user tries to navigate to the
/// Google IO site from the [GameOverInfoDisplay].
typedef OnNavigateTap = void Function();
final _titleTextPaint = TextPaint(
style: const TextStyle(
fontSize: 1.6,
@ -57,12 +54,10 @@ class GameOverInfoDisplay extends Component with HasGameRef {
/// {@macro game_over_info_display}
GameOverInfoDisplay({
OnShareTap? onShare,
OnNavigateTap? onNavigate,
}) : super(
children: [
_InstructionsComponent(
onShare: onShare,
onNavigate: onNavigate,
),
],
);
@ -71,7 +66,6 @@ class GameOverInfoDisplay extends Component with HasGameRef {
class _InstructionsComponent extends PositionComponent with HasGameRef {
_InstructionsComponent({
OnShareTap? onShare,
OnNavigateTap? onNavigate,
}) : super(
anchor: Anchor.center,
position: Vector2(0, -25),
@ -79,7 +73,6 @@ class _InstructionsComponent extends PositionComponent with HasGameRef {
_TitleComponent(),
_LinksComponent(
onShare: onShare,
onNavigate: onNavigate,
),
_DescriptionComponent(),
],
@ -151,13 +144,12 @@ class _TitleBackgroundSpriteComponent extends SpriteComponent with HasGameRef {
class _LinksComponent extends PositionComponent with HasGameRef {
_LinksComponent({
OnShareTap? onShare,
OnNavigateTap? onNavigate,
}) : super(
anchor: Anchor.center,
position: Vector2(0, 9.2),
children: [
ShareLinkComponent(onTap: onShare),
GoogleIOLinkComponent(onTap: onNavigate),
GoogleIOLinkComponent(),
],
);
}
@ -205,20 +197,16 @@ class ShareLinkComponent extends TextComponent with HasGameRef, Tappable {
/// {@endtemplate}
class GoogleIOLinkComponent extends TextComponent with HasGameRef, Tappable {
/// {@macro google_io_link_component}
GoogleIOLinkComponent({
OnNavigateTap? onTap,
}) : _onTap = onTap,
super(
GoogleIOLinkComponent()
: super(
anchor: Anchor.center,
position: Vector2(6, 0),
textRenderer: _linkTextPaint,
);
final OnNavigateTap? _onTap;
@override
bool onTapDown(TapDownInfo info) {
_onTap?.call();
openLink(ShareRepository.googleIOEvent);
return true;
}
@ -245,7 +233,8 @@ class _DescriptionComponent extends PositionComponent with HasGameRef {
position: Vector2(0, 13),
children: [
_LearnMoreTextComponent(),
_FirebaseOrOpenSourceTextComponent(),
_FirebaseTextComponent(),
OpenSourceTextComponent(),
],
);
}
@ -265,17 +254,51 @@ class _LearnMoreTextComponent extends TextComponent with HasGameRef {
}
}
class _FirebaseOrOpenSourceTextComponent extends TextComponent with HasGameRef {
_FirebaseOrOpenSourceTextComponent()
class _FirebaseTextComponent extends TextComponent with HasGameRef {
_FirebaseTextComponent()
: super(
anchor: Anchor.center,
position: Vector2(-8.5, 2.5),
textRenderer: _descriptionTextPaint,
);
@override
Future<void> onLoad() async {
await super.onLoad();
text = readProvider<AppLocalizations>().firebaseOr;
}
}
/// {@template open_source_link_component}
/// Link text to navigate to Open Source site.
/// {@endtemplate}
@visibleForTesting
class OpenSourceTextComponent extends TextComponent with HasGameRef, Tappable {
/// {@macro open_source_link_component}
OpenSourceTextComponent()
: super(
anchor: Anchor.center,
position: Vector2(0, 2.5),
position: Vector2(13.5, 2.5),
textRenderer: _descriptionTextPaint,
);
@override
bool onTapDown(TapDownInfo info) {
openLink(ShareRepository.openSourceCode);
return true;
}
@override
Future<void> onLoad() async {
await super.onLoad();
text = readProvider<AppLocalizations>().firebaseOrOpenSource;
await add(
RectangleComponent(
size: Vector2(16, 0.2),
paint: Paint()..color = PinballColors.white,
anchor: Anchor.center,
position: Vector2(8, 2.3),
),
);
text = readProvider<AppLocalizations>().openSourceCode;
}
}

@ -101,7 +101,8 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.backbox.marquee.keyName),
images.load(components.Assets.images.backbox.displayDivider.keyName),
images.load(
components.Assets.images.backbox.displayTitleDecoration.keyName),
components.Assets.images.backbox.displayTitleDecoration.keyName,
),
images.load(components.Assets.images.googleWord.letter1.lit.keyName),
images.load(components.Assets.images.googleWord.letter1.dimmed.keyName),
images.load(components.Assets.images.googleWord.letter2.lit.keyName),

@ -176,8 +176,12 @@
"@learnMore": {
"description": "Text shown on description of info screen"
},
"firebaseOrOpenSource": "Firebase or dive right into the open source code.",
"@firebaseOrOpenSource": {
"firebaseOr": "Firebase or dive right into the",
"@firebaseOr": {
"description": "Text shown on description of info screen"
},
"openSourceCode": "open source code.",
"@openSourceCode": {
"description": "Text shown on description of info screen"
}
}

@ -92,7 +92,6 @@ flutter:
- assets/images/multiplier/x6/
- assets/images/score/
- assets/images/backbox/
- assets/images/backbox/button/
- assets/images/flapper/
- assets/images/skill_shot/

@ -13,6 +13,8 @@ class ShareRepository {
/// Url to the Github Open Source Pinball project.
static const openSourceCode = 'https://github.com/VGVentures/pinball';
/// Url to the Google IO Event.
static const googleIOEvent = 'https://events.google.com/io/';
/// Returns a url to share the [value] on the given [platform].

@ -20,9 +20,6 @@ import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:pinball_theme/pinball_theme.dart' as theme;
import 'package:pinball_ui/pinball_ui.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:share_repository/share_repository.dart';
class _TestGame extends Forge2DGame
with HasKeyboardHandlerComponents, HasTappables {
@ -77,10 +74,6 @@ class _MockLeaderboardRepository extends Mock implements LeaderboardRepository {
class _MockTapDownInfo extends Mock implements TapDownInfo {}
class _MockUrlLauncher extends Mock
with MockPlatformInterfaceMixin
implements UrlLauncherPlatform {}
class _MockAppLocalizations extends Mock implements AppLocalizations {
@override
String get score => '';
@ -125,7 +118,10 @@ class _MockAppLocalizations extends Mock implements AppLocalizations {
String get learnMore => '';
@override
String get firebaseOrOpenSource => '';
String get firebaseOr => '';
@override
String get openSourceCode => '';
}
void main() {
@ -235,169 +231,48 @@ void main() {
},
);
group('GameOverInfoDisplay', () {
late UrlLauncherPlatform urlLauncher;
setUp(() async {
urlLauncher = _MockUrlLauncher();
UrlLauncherPlatform.instance = urlLauncher;
});
flameTester.test(
'added on InitialsSuccessState',
(game) async {
final state = InitialsSuccessState(
score: 100,
initials: 'AAA',
character: theme.AndroidTheme(),
);
whenListen(
bloc,
const Stream<InitialsSuccessState>.empty(),
initialState: state,
);
final backbox = Backbox.test(bloc: bloc);
await game.pump(backbox);
expect(
game.descendants().whereType<GameOverInfoDisplay>().length,
equals(1),
);
},
);
flameTester.test(
'adds ShareScoreRequested event when sharing',
(game) async {
final state = InitialsSuccessState(
score: 100,
initials: 'AAA',
character: theme.AndroidTheme(),
);
whenListen(
bloc,
Stream.value(state),
initialState: state,
);
final backbox = Backbox.test(bloc: bloc);
await game.pump(backbox);
final shareLink =
game.descendants().whereType<ShareLinkComponent>().first;
shareLink.onTapDown(_MockTapDownInfo());
verify(
() => bloc.add(
ShareScoreRequested(
score: state.score,
initials: state.initials,
character: state.character,
),
),
).called(1);
},
);
flameTester.test(
'open Google IO Event url when navigating',
(game) async {
when(() => urlLauncher.canLaunch(any()))
.thenAnswer((_) async => true);
when(
() => urlLauncher.launch(
any(),
useSafariVC: any(named: 'useSafariVC'),
useWebView: any(named: 'useWebView'),
enableJavaScript: any(named: 'enableJavaScript'),
enableDomStorage: any(named: 'enableDomStorage'),
universalLinksOnly: any(named: 'universalLinksOnly'),
headers: any(named: 'headers'),
),
).thenAnswer((_) async => true);
final state = InitialsSuccessState(
score: 100,
initials: 'AAA',
character: theme.AndroidTheme(),
);
whenListen(
bloc,
Stream.value(state),
initialState: state,
);
final backbox = Backbox.test(bloc: bloc);
await game.pump(backbox);
final shareLink =
game.descendants().whereType<GoogleIOLinkComponent>().first;
shareLink.onTapDown(_MockTapDownInfo());
await game.ready();
verify(
() => urlLauncher.launch(
ShareRepository.googleIOEvent,
useSafariVC: any(named: 'useSafariVC'),
useWebView: any(named: 'useWebView'),
enableJavaScript: any(named: 'enableJavaScript'),
enableDomStorage: any(named: 'enableDomStorage'),
universalLinksOnly: any(named: 'universalLinksOnly'),
headers: any(named: 'headers'),
),
);
},
);
flameTester.test(
'open OpenSource url when navigating',
(game) async {
when(() => urlLauncher.canLaunch(any()))
.thenAnswer((_) async => true);
when(
() => urlLauncher.launch(
any(),
useSafariVC: any(named: 'useSafariVC'),
useWebView: any(named: 'useWebView'),
enableJavaScript: any(named: 'enableJavaScript'),
enableDomStorage: any(named: 'enableDomStorage'),
universalLinksOnly: any(named: 'universalLinksOnly'),
headers: any(named: 'headers'),
),
).thenAnswer((_) async => true);
final state = InitialsSuccessState(
score: 100,
initials: 'AAA',
character: theme.AndroidTheme(),
);
whenListen(
bloc,
Stream.value(state),
initialState: state,
);
final backbox = Backbox.test(bloc: bloc);
await game.pump(backbox);
final shareLink =
game.descendants().whereType<GoogleIOLinkComponent>().first;
shareLink.onTapDown(_MockTapDownInfo());
await game.ready();
verify(
() => urlLauncher.launch(
ShareRepository.openSourceCode,
useSafariVC: any(named: 'useSafariVC'),
useWebView: any(named: 'useWebView'),
enableJavaScript: any(named: 'enableJavaScript'),
enableDomStorage: any(named: 'enableDomStorage'),
universalLinksOnly: any(named: 'universalLinksOnly'),
headers: any(named: 'headers'),
),
);
},
);
});
flameTester.test(
'added GameOverInfoDisplay on InitialsSuccessState',
(game) async {
final state = InitialsSuccessState(score: 100);
whenListen(
bloc,
const Stream<InitialsSuccessState>.empty(),
initialState: state,
);
final backbox = Backbox.test(bloc: bloc);
await game.pump(backbox);
expect(
game.descendants().whereType<GameOverInfoDisplay>().length,
equals(1),
);
},
);
flameTester.test(
'adds ShareScoreRequested event when sharing',
(game) async {
final state = InitialsSuccessState(score: 100);
whenListen(
bloc,
Stream.value(state),
initialState: state,
);
final backbox = Backbox.test(bloc: bloc);
await game.pump(backbox);
final shareLink =
game.descendants().whereType<ShareLinkComponent>().first;
shareLink.onTapDown(_MockTapDownInfo());
verify(
() => bloc.add(
ShareScoreRequested(score: state.score),
),
).called(1);
},
);
flameTester.test(
'adds InitialsSubmissionFailureDisplay on InitialsFailureState',

@ -12,6 +12,9 @@ import 'package:pinball/game/components/backbox/displays/game_over_info_display.
import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:pinball_ui/pinball_ui.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:share_repository/share_repository.dart';
class _TestGame extends Forge2DGame with HasTappables {
@override
@ -57,16 +60,30 @@ class _MockAppLocalizations extends Mock implements AppLocalizations {
String get learnMore => '';
@override
String get firebaseOrOpenSource => '';
String get firebaseOr => '';
@override
String get openSourceCode => '';
}
class _MockTapDownInfo extends Mock implements TapDownInfo {}
class _MockUrlLauncher extends Mock
with MockPlatformInterfaceMixin
implements UrlLauncherPlatform {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
late UrlLauncherPlatform urlLauncher;
setUp(() async {
urlLauncher = _MockUrlLauncher();
UrlLauncherPlatform.instance = urlLauncher;
});
group('InfoDisplay', () {
flameTester.test(
'loads correctly',
@ -98,22 +115,80 @@ void main() {
);
flameTester.test(
'calls onNavigate when go to Google IO link is tapped',
'open Google IO Event url when navigating',
(game) async {
var tapped = false;
when(() => urlLauncher.canLaunch(any())).thenAnswer((_) async => true);
when(
() => urlLauncher.launch(
any(),
useSafariVC: any(named: 'useSafariVC'),
useWebView: any(named: 'useWebView'),
enableJavaScript: any(named: 'enableJavaScript'),
enableDomStorage: any(named: 'enableDomStorage'),
universalLinksOnly: any(named: 'universalLinksOnly'),
headers: any(named: 'headers'),
),
).thenAnswer((_) async => true);
final tapDownInfo = _MockTapDownInfo();
final component = GameOverInfoDisplay(
onNavigate: () => tapped = true,
);
final component = GameOverInfoDisplay();
await game.pump(component);
final googleLink =
component.descendants().whereType<GoogleIOLinkComponent>().first;
googleLink.onTapDown(_MockTapDownInfo());
await game.ready();
verify(
() => urlLauncher.launch(
ShareRepository.googleIOEvent,
useSafariVC: any(named: 'useSafariVC'),
useWebView: any(named: 'useWebView'),
enableJavaScript: any(named: 'enableJavaScript'),
enableDomStorage: any(named: 'enableDomStorage'),
universalLinksOnly: any(named: 'universalLinksOnly'),
headers: any(named: 'headers'),
),
);
},
);
flameTester.test(
'open OpenSource url when navigating',
(game) async {
when(() => urlLauncher.canLaunch(any())).thenAnswer((_) async => true);
when(
() => urlLauncher.launch(
any(),
useSafariVC: any(named: 'useSafariVC'),
useWebView: any(named: 'useWebView'),
enableJavaScript: any(named: 'enableJavaScript'),
enableDomStorage: any(named: 'enableDomStorage'),
universalLinksOnly: any(named: 'universalLinksOnly'),
headers: any(named: 'headers'),
),
).thenAnswer((_) async => true);
googleLink.onTapDown(tapDownInfo);
final component = GameOverInfoDisplay();
await game.pump(component);
expect(tapped, isTrue);
final openSourceLink =
component.descendants().whereType<OpenSourceTextComponent>().first;
openSourceLink.onTapDown(_MockTapDownInfo());
await game.ready();
verify(
() => urlLauncher.launch(
ShareRepository.openSourceCode,
useSafariVC: any(named: 'useSafariVC'),
useWebView: any(named: 'useWebView'),
enableJavaScript: any(named: 'enableJavaScript'),
enableDomStorage: any(named: 'enableDomStorage'),
universalLinksOnly: any(named: 'universalLinksOnly'),
headers: any(named: 'headers'),
),
);
},
);
});

Loading…
Cancel
Save