mirror of https://github.com/flutter/pinball.git
feat: adding mobile controls (#377)
* feat: adding mobile controls * adding tests for pinball dpad button * feat: tests * lint * Apply suggestions from code review Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * suggestions Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com>pull/389/head
parent
bba5316dfd
commit
9d184fedf9
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball/l10n/l10n.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
import 'package:pinball_ui/pinball_ui.dart';
|
||||||
|
|
||||||
|
/// {@template mobile_controls}
|
||||||
|
/// Widget with the controls used to enable the user initials input on mobile.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class MobileControls extends StatelessWidget {
|
||||||
|
/// {@macro mobile_controls}
|
||||||
|
const MobileControls({
|
||||||
|
Key? key,
|
||||||
|
required this.game,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
/// Game instance
|
||||||
|
final PinballGame game;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
MobileDpad(
|
||||||
|
onTapUp: () => game.triggerVirtualKeyUp(LogicalKeyboardKey.arrowUp),
|
||||||
|
onTapDown: () => game.triggerVirtualKeyUp(
|
||||||
|
LogicalKeyboardKey.arrowDown,
|
||||||
|
),
|
||||||
|
onTapLeft: () => game.triggerVirtualKeyUp(
|
||||||
|
LogicalKeyboardKey.arrowLeft,
|
||||||
|
),
|
||||||
|
onTapRight: () => game.triggerVirtualKeyUp(
|
||||||
|
LogicalKeyboardKey.arrowRight,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PinballButton(
|
||||||
|
text: l10n.enter,
|
||||||
|
onTap: () => game.triggerVirtualKeyUp(LogicalKeyboardKey.enter),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball_ui/pinball_ui.dart';
|
||||||
|
|
||||||
|
/// {@template mobile_dpad}
|
||||||
|
/// Widget rendering 4 directional input arrows.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class MobileDpad extends StatelessWidget {
|
||||||
|
/// {@template mobile_dpad}
|
||||||
|
const MobileDpad({
|
||||||
|
Key? key,
|
||||||
|
required this.onTapUp,
|
||||||
|
required this.onTapDown,
|
||||||
|
required this.onTapLeft,
|
||||||
|
required this.onTapRight,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
static const _size = 180.0;
|
||||||
|
|
||||||
|
/// Called when dpad up is pressed
|
||||||
|
final VoidCallback onTapUp;
|
||||||
|
|
||||||
|
/// Called when dpad down is pressed
|
||||||
|
final VoidCallback onTapDown;
|
||||||
|
|
||||||
|
/// Called when dpad left is pressed
|
||||||
|
final VoidCallback onTapLeft;
|
||||||
|
|
||||||
|
/// Called when dpad right is pressed
|
||||||
|
final VoidCallback onTapRight;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: _size,
|
||||||
|
height: _size,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Spacer(),
|
||||||
|
PinballDpadButton(
|
||||||
|
direction: PinballDpadDirection.up,
|
||||||
|
onTap: onTapUp,
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
PinballDpadButton(
|
||||||
|
direction: PinballDpadDirection.left,
|
||||||
|
onTap: onTapLeft,
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
PinballDpadButton(
|
||||||
|
direction: PinballDpadDirection.right,
|
||||||
|
onTap: onTapRight,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Spacer(),
|
||||||
|
PinballDpadButton(
|
||||||
|
direction: PinballDpadDirection.down,
|
||||||
|
onTap: onTapDown,
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
export 'bonus_animation.dart';
|
export 'bonus_animation.dart';
|
||||||
export 'game_hud.dart';
|
export 'game_hud.dart';
|
||||||
|
export 'mobile_controls.dart';
|
||||||
|
export 'mobile_dpad.dart';
|
||||||
export 'play_button_overlay.dart';
|
export 'play_button_overlay.dart';
|
||||||
export 'round_count_display.dart';
|
export 'round_count_display.dart';
|
||||||
export 'score_view.dart';
|
export 'score_view.dart';
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
@ -0,0 +1,66 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball_ui/gen/gen.dart';
|
||||||
|
import 'package:pinball_ui/pinball_ui.dart';
|
||||||
|
|
||||||
|
/// Enum with all possibile directions of a [PinballDpadButton].
|
||||||
|
enum PinballDpadDirection {
|
||||||
|
/// Up
|
||||||
|
up,
|
||||||
|
|
||||||
|
/// Down
|
||||||
|
down,
|
||||||
|
|
||||||
|
/// Left
|
||||||
|
left,
|
||||||
|
|
||||||
|
/// Right
|
||||||
|
right,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension _PinballDpadDirectionX on PinballDpadDirection {
|
||||||
|
String toAsset() {
|
||||||
|
switch (this) {
|
||||||
|
case PinballDpadDirection.up:
|
||||||
|
return Assets.images.button.dpadUp.keyName;
|
||||||
|
case PinballDpadDirection.down:
|
||||||
|
return Assets.images.button.dpadDown.keyName;
|
||||||
|
case PinballDpadDirection.left:
|
||||||
|
return Assets.images.button.dpadLeft.keyName;
|
||||||
|
case PinballDpadDirection.right:
|
||||||
|
return Assets.images.button.dpadRight.keyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template pinball_dpad_button}
|
||||||
|
/// Widget that renders a Dpad button with a given direction.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class PinballDpadButton extends StatelessWidget {
|
||||||
|
/// {@macro pinball_dpad_button}
|
||||||
|
const PinballDpadButton({
|
||||||
|
Key? key,
|
||||||
|
required this.direction,
|
||||||
|
required this.onTap,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
/// Which [PinballDpadDirection] this button is.
|
||||||
|
final PinballDpadDirection direction;
|
||||||
|
|
||||||
|
/// The function executed when the button is pressed.
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
color: PinballColors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Image.asset(
|
||||||
|
direction.toAsset(),
|
||||||
|
width: 60,
|
||||||
|
height: 60,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
export 'animated_ellipsis_text.dart';
|
export 'animated_ellipsis_text.dart';
|
||||||
export 'crt_background.dart';
|
export 'crt_background.dart';
|
||||||
export 'pinball_button.dart';
|
export 'pinball_button.dart';
|
||||||
|
export 'pinball_dpad_button.dart';
|
||||||
export 'pinball_loading_indicator.dart';
|
export 'pinball_loading_indicator.dart';
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
// ignore_for_file: one_member_abstracts
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_ui/gen/gen.dart';
|
||||||
|
import 'package:pinball_ui/pinball_ui.dart';
|
||||||
|
|
||||||
|
extension _WidgetTesterX on WidgetTester {
|
||||||
|
Future<void> pumpButton({
|
||||||
|
required PinballDpadDirection direction,
|
||||||
|
required VoidCallback onTap,
|
||||||
|
}) async {
|
||||||
|
await pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: PinballDpadButton(
|
||||||
|
direction: direction,
|
||||||
|
onTap: onTap,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension _CommonFindersX on CommonFinders {
|
||||||
|
Finder byImagePath(String path) {
|
||||||
|
return find.byWidgetPredicate(
|
||||||
|
(widget) {
|
||||||
|
if (widget is Image) {
|
||||||
|
final image = widget.image;
|
||||||
|
|
||||||
|
if (image is AssetImage) {
|
||||||
|
return image.keyName == path;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _VoidCallbackStubBase {
|
||||||
|
void onCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VoidCallbackStub extends Mock implements _VoidCallbackStubBase {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('PinballDpadButton', () {
|
||||||
|
testWidgets('can be tapped', (tester) async {
|
||||||
|
final stub = _VoidCallbackStub();
|
||||||
|
await tester.pumpButton(
|
||||||
|
direction: PinballDpadDirection.up,
|
||||||
|
onTap: stub.onCall,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.byType(Image));
|
||||||
|
|
||||||
|
verify(stub.onCall).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('up', () {
|
||||||
|
testWidgets('renders the correct image', (tester) async {
|
||||||
|
await tester.pumpButton(
|
||||||
|
direction: PinballDpadDirection.up,
|
||||||
|
onTap: () {},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.byImagePath(Assets.images.button.dpadUp.keyName),
|
||||||
|
findsOneWidget,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('down', () {
|
||||||
|
testWidgets('renders the correct image', (tester) async {
|
||||||
|
await tester.pumpButton(
|
||||||
|
direction: PinballDpadDirection.down,
|
||||||
|
onTap: () {},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.byImagePath(Assets.images.button.dpadDown.keyName),
|
||||||
|
findsOneWidget,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('left', () {
|
||||||
|
testWidgets('renders the correct image', (tester) async {
|
||||||
|
await tester.pumpButton(
|
||||||
|
direction: PinballDpadDirection.left,
|
||||||
|
onTap: () {},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.byImagePath(Assets.images.button.dpadLeft.keyName),
|
||||||
|
findsOneWidget,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('right', () {
|
||||||
|
testWidgets('renders the correct image', (tester) async {
|
||||||
|
await tester.pumpButton(
|
||||||
|
direction: PinballDpadDirection.right,
|
||||||
|
onTap: () {},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.byImagePath(Assets.images.button.dpadRight.keyName),
|
||||||
|
findsOneWidget,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball/l10n/l10n.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
import 'package:pinball_ui/pinball_ui.dart';
|
||||||
|
|
||||||
|
class _MockPinballGame extends Mock implements PinballGame {}
|
||||||
|
|
||||||
|
extension _WidgetTesterX on WidgetTester {
|
||||||
|
Future<void> pumpMobileControls(PinballGame game) async {
|
||||||
|
await pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
localizationsDelegates: const [
|
||||||
|
AppLocalizations.delegate,
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
],
|
||||||
|
home: Scaffold(
|
||||||
|
body: MobileControls(game: game),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension _CommonFindersX on CommonFinders {
|
||||||
|
Finder byPinballDpadDirection(PinballDpadDirection direction) {
|
||||||
|
return byWidgetPredicate((widget) {
|
||||||
|
return widget is PinballDpadButton && widget.direction == direction;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('MobileControls', () {
|
||||||
|
testWidgets('renders', (tester) async {
|
||||||
|
await tester.pumpMobileControls(_MockPinballGame());
|
||||||
|
|
||||||
|
expect(find.byType(PinballButton), findsOneWidget);
|
||||||
|
expect(find.byType(MobileDpad), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('correctly triggers the arrow up', (tester) async {
|
||||||
|
var pressed = false;
|
||||||
|
final component = KeyboardInputController(
|
||||||
|
keyUp: {
|
||||||
|
LogicalKeyboardKey.arrowUp: () => pressed = true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final game = _MockPinballGame();
|
||||||
|
when(game.descendants).thenReturn([component]);
|
||||||
|
|
||||||
|
await tester.pumpMobileControls(game);
|
||||||
|
await tester.tap(find.byPinballDpadDirection(PinballDpadDirection.up));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(pressed, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('correctly triggers the arrow down', (tester) async {
|
||||||
|
var pressed = false;
|
||||||
|
final component = KeyboardInputController(
|
||||||
|
keyUp: {
|
||||||
|
LogicalKeyboardKey.arrowDown: () => pressed = true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final game = _MockPinballGame();
|
||||||
|
when(game.descendants).thenReturn([component]);
|
||||||
|
|
||||||
|
await tester.pumpMobileControls(game);
|
||||||
|
await tester.tap(find.byPinballDpadDirection(PinballDpadDirection.down));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(pressed, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('correctly triggers the arrow right', (tester) async {
|
||||||
|
var pressed = false;
|
||||||
|
final component = KeyboardInputController(
|
||||||
|
keyUp: {
|
||||||
|
LogicalKeyboardKey.arrowRight: () => pressed = true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final game = _MockPinballGame();
|
||||||
|
when(game.descendants).thenReturn([component]);
|
||||||
|
|
||||||
|
await tester.pumpMobileControls(game);
|
||||||
|
await tester.tap(find.byPinballDpadDirection(PinballDpadDirection.right));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(pressed, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('correctly triggers the arrow left', (tester) async {
|
||||||
|
var pressed = false;
|
||||||
|
final component = KeyboardInputController(
|
||||||
|
keyUp: {
|
||||||
|
LogicalKeyboardKey.arrowLeft: () => pressed = true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final game = _MockPinballGame();
|
||||||
|
when(game.descendants).thenReturn([component]);
|
||||||
|
|
||||||
|
await tester.pumpMobileControls(game);
|
||||||
|
await tester.tap(find.byPinballDpadDirection(PinballDpadDirection.left));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(pressed, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('correctly triggers the enter', (tester) async {
|
||||||
|
var pressed = false;
|
||||||
|
final component = KeyboardInputController(
|
||||||
|
keyUp: {
|
||||||
|
LogicalKeyboardKey.enter: () => pressed = true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final game = _MockPinballGame();
|
||||||
|
when(game.descendants).thenReturn([component]);
|
||||||
|
|
||||||
|
await tester.pumpMobileControls(game);
|
||||||
|
await tester.tap(find.byType(PinballButton));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(pressed, isTrue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
// ignore_for_file: one_member_abstracts
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_ui/pinball_ui.dart';
|
||||||
|
|
||||||
|
extension _WidgetTesterX on WidgetTester {
|
||||||
|
Future<void> pumpDpad({
|
||||||
|
required VoidCallback onTapUp,
|
||||||
|
required VoidCallback onTapDown,
|
||||||
|
required VoidCallback onTapLeft,
|
||||||
|
required VoidCallback onTapRight,
|
||||||
|
}) async {
|
||||||
|
await pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: MobileDpad(
|
||||||
|
onTapUp: onTapUp,
|
||||||
|
onTapDown: onTapDown,
|
||||||
|
onTapLeft: onTapLeft,
|
||||||
|
onTapRight: onTapRight,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension _CommonFindersX on CommonFinders {
|
||||||
|
Finder byPinballDpadDirection(PinballDpadDirection direction) {
|
||||||
|
return byWidgetPredicate((widget) {
|
||||||
|
return widget is PinballDpadButton && widget.direction == direction;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _VoidCallbackStubBase {
|
||||||
|
void onCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VoidCallbackStub extends Mock implements _VoidCallbackStubBase {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('MobileDpad', () {
|
||||||
|
testWidgets('renders correctly', (tester) async {
|
||||||
|
await tester.pumpDpad(
|
||||||
|
onTapUp: () {},
|
||||||
|
onTapDown: () {},
|
||||||
|
onTapLeft: () {},
|
||||||
|
onTapRight: () {},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.byType(PinballDpadButton),
|
||||||
|
findsNWidgets(4),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('can tap up', (tester) async {
|
||||||
|
final stub = _VoidCallbackStub();
|
||||||
|
await tester.pumpDpad(
|
||||||
|
onTapUp: stub.onCall,
|
||||||
|
onTapDown: () {},
|
||||||
|
onTapLeft: () {},
|
||||||
|
onTapRight: () {},
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.byPinballDpadDirection(PinballDpadDirection.up));
|
||||||
|
verify(stub.onCall).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('can tap down', (tester) async {
|
||||||
|
final stub = _VoidCallbackStub();
|
||||||
|
await tester.pumpDpad(
|
||||||
|
onTapUp: () {},
|
||||||
|
onTapDown: stub.onCall,
|
||||||
|
onTapLeft: () {},
|
||||||
|
onTapRight: () {},
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.byPinballDpadDirection(PinballDpadDirection.down));
|
||||||
|
verify(stub.onCall).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('can tap left', (tester) async {
|
||||||
|
final stub = _VoidCallbackStub();
|
||||||
|
await tester.pumpDpad(
|
||||||
|
onTapUp: () {},
|
||||||
|
onTapDown: () {},
|
||||||
|
onTapLeft: stub.onCall,
|
||||||
|
onTapRight: () {},
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.byPinballDpadDirection(PinballDpadDirection.left));
|
||||||
|
verify(stub.onCall).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('can tap left', (tester) async {
|
||||||
|
final stub = _VoidCallbackStub();
|
||||||
|
await tester.pumpDpad(
|
||||||
|
onTapUp: () {},
|
||||||
|
onTapDown: () {},
|
||||||
|
onTapLeft: () {},
|
||||||
|
onTapRight: stub.onCall,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.byPinballDpadDirection(PinballDpadDirection.right));
|
||||||
|
verify(stub.onCall).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in new issue