mirror of https://github.com/flutter/pinball.git
parent
671d236a7e
commit
12c8492b1c
@ -1,26 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:pinball/l10n/l10n.dart';
|
|
||||||
import 'package:pinball/start_game/start_game.dart';
|
|
||||||
|
|
||||||
/// {@template play_button_overlay}
|
|
||||||
/// [Widget] that renders the button responsible to starting the game
|
|
||||||
/// {@endtemplate}
|
|
||||||
class PlayButtonOverlay extends StatelessWidget {
|
|
||||||
/// {@macro play_button_overlay}
|
|
||||||
const PlayButtonOverlay({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final l10n = context.l10n;
|
|
||||||
|
|
||||||
return Center(
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
context.read<StartGameBloc>().add(const PlayTapped());
|
|
||||||
},
|
|
||||||
child: Text(l10n.play),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,130 +0,0 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:pinball/l10n/l10n.dart';
|
|
||||||
import 'package:pinball/select_character/select_character.dart';
|
|
||||||
import 'package:pinball/start_game/start_game.dart';
|
|
||||||
import 'package:pinball_theme/pinball_theme.dart';
|
|
||||||
import 'package:pinball_ui/pinball_ui.dart';
|
|
||||||
|
|
||||||
class CharacterSelectionDialog extends StatelessWidget {
|
|
||||||
const CharacterSelectionDialog({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
static Route route() {
|
|
||||||
return MaterialPageRoute<void>(
|
|
||||||
builder: (_) => const CharacterSelectionDialog(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocProvider(
|
|
||||||
create: (_) => CharacterThemeCubit(),
|
|
||||||
child: const CharacterSelectionView(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CharacterSelectionView extends StatelessWidget {
|
|
||||||
const CharacterSelectionView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final l10n = context.l10n;
|
|
||||||
|
|
||||||
return PixelatedDecoration(
|
|
||||||
header: Text(
|
|
||||||
l10n.characterSelectionTitle,
|
|
||||||
style: Theme.of(context).textTheme.headline3,
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const _CharacterSelectionGridView(),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
context.read<StartGameBloc>().add(const CharacterSelected());
|
|
||||||
},
|
|
||||||
child: Text(l10n.start),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CharacterSelectionGridView extends StatelessWidget {
|
|
||||||
const _CharacterSelectionGridView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: GridView.count(
|
|
||||||
shrinkWrap: true,
|
|
||||||
crossAxisCount: 2,
|
|
||||||
mainAxisSpacing: 20,
|
|
||||||
crossAxisSpacing: 20,
|
|
||||||
children: const [
|
|
||||||
CharacterImageButton(
|
|
||||||
DashTheme(),
|
|
||||||
key: Key('characterSelectionPage_dashButton'),
|
|
||||||
),
|
|
||||||
CharacterImageButton(
|
|
||||||
SparkyTheme(),
|
|
||||||
key: Key('characterSelectionPage_sparkyButton'),
|
|
||||||
),
|
|
||||||
CharacterImageButton(
|
|
||||||
AndroidTheme(),
|
|
||||||
key: Key('characterSelectionPage_androidButton'),
|
|
||||||
),
|
|
||||||
CharacterImageButton(
|
|
||||||
DinoTheme(),
|
|
||||||
key: Key('characterSelectionPage_dinoButton'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(allisonryan0002): remove visibility when adding final UI.
|
|
||||||
@visibleForTesting
|
|
||||||
class CharacterImageButton extends StatelessWidget {
|
|
||||||
const CharacterImageButton(
|
|
||||||
this.characterTheme, {
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final CharacterTheme characterTheme;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final currentCharacterTheme =
|
|
||||||
context.select<CharacterThemeCubit, CharacterTheme>(
|
|
||||||
(cubit) => cubit.state.characterTheme,
|
|
||||||
);
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () =>
|
|
||||||
context.read<CharacterThemeCubit>().characterSelected(characterTheme),
|
|
||||||
child: DecoratedBox(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: (currentCharacterTheme == characterTheme)
|
|
||||||
? Colors.blue.withOpacity(0.5)
|
|
||||||
: null,
|
|
||||||
borderRadius: BorderRadius.circular(6),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: characterTheme.icon.image(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
export 'character_selection_page.dart';
|
|
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 16 KiB |
@ -1,42 +0,0 @@
|
|||||||
import 'package:bloc_test/bloc_test.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:mocktail/mocktail.dart';
|
|
||||||
import 'package:pinball/game/game.dart';
|
|
||||||
import 'package:pinball/start_game/bloc/start_game_bloc.dart';
|
|
||||||
|
|
||||||
import '../../../helpers/helpers.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
group('PlayButtonOverlay', () {
|
|
||||||
late StartGameBloc startGameBloc;
|
|
||||||
|
|
||||||
setUp(() {
|
|
||||||
startGameBloc = MockStartGameBloc();
|
|
||||||
|
|
||||||
whenListen(
|
|
||||||
startGameBloc,
|
|
||||||
Stream.value(const StartGameState.initial()),
|
|
||||||
initialState: const StartGameState.initial(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('renders correctly', (tester) async {
|
|
||||||
await tester.pumpApp(const PlayButtonOverlay());
|
|
||||||
|
|
||||||
expect(find.text('Play'), findsOneWidget);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('adds PlayTapped event to StartGameBloc when taped',
|
|
||||||
(tester) async {
|
|
||||||
await tester.pumpApp(
|
|
||||||
const PlayButtonOverlay(),
|
|
||||||
startGameBloc: startGameBloc,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.tap(find.text('Play'));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
verify(() => startGameBloc.add(const PlayTapped())).called(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
// ignore_for_file: prefer_const_constructors
|
|
||||||
|
|
||||||
import 'package:bloc_test/bloc_test.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:mockingjay/mockingjay.dart';
|
|
||||||
import 'package:pinball/select_character/select_character.dart';
|
|
||||||
import 'package:pinball/start_game/start_game.dart';
|
|
||||||
import 'package:pinball_theme/pinball_theme.dart';
|
|
||||||
|
|
||||||
import '../../helpers/helpers.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
late CharacterThemeCubit characterThemeCubit;
|
|
||||||
late StartGameBloc startGameBloc;
|
|
||||||
|
|
||||||
setUp(() {
|
|
||||||
characterThemeCubit = MockCharacterThemeCubit();
|
|
||||||
startGameBloc = MockStartGameBloc();
|
|
||||||
|
|
||||||
whenListen(
|
|
||||||
characterThemeCubit,
|
|
||||||
const Stream<CharacterThemeState>.empty(),
|
|
||||||
initialState: const CharacterThemeState.initial(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
group('CharacterSelectionPage', () {
|
|
||||||
testWidgets('renders CharacterSelectionView', (tester) async {
|
|
||||||
await tester.pumpApp(
|
|
||||||
CharacterSelectionDialog(),
|
|
||||||
characterThemeCubit: characterThemeCubit,
|
|
||||||
);
|
|
||||||
expect(find.byType(CharacterSelectionView), findsOneWidget);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('route returns a valid navigation route', (tester) async {
|
|
||||||
await tester.pumpApp(
|
|
||||||
Scaffold(
|
|
||||||
body: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context)
|
|
||||||
.push<void>(CharacterSelectionDialog.route());
|
|
||||||
},
|
|
||||||
child: Text('Tap me'),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
characterThemeCubit: characterThemeCubit,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.tap(find.text('Tap me'));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
|
|
||||||
expect(find.byType(CharacterSelectionDialog), findsOneWidget);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group('CharacterSelectionView', () {
|
|
||||||
testWidgets('renders correctly', (tester) async {
|
|
||||||
const titleText = 'Choose your character!';
|
|
||||||
await tester.pumpApp(
|
|
||||||
CharacterSelectionView(),
|
|
||||||
characterThemeCubit: characterThemeCubit,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(find.text(titleText), findsOneWidget);
|
|
||||||
expect(find.byType(CharacterImageButton), findsNWidgets(4));
|
|
||||||
expect(find.byType(TextButton), findsOneWidget);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('calls characterSelected when a character image is tapped',
|
|
||||||
(tester) async {
|
|
||||||
const sparkyButtonKey = Key('characterSelectionPage_sparkyButton');
|
|
||||||
|
|
||||||
await tester.pumpApp(
|
|
||||||
CharacterSelectionView(),
|
|
||||||
characterThemeCubit: characterThemeCubit,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.tap(find.byKey(sparkyButtonKey));
|
|
||||||
|
|
||||||
verify(() => characterThemeCubit.characterSelected(SparkyTheme()))
|
|
||||||
.called(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('adds CharacterSelected event when start is tapped',
|
|
||||||
(tester) async {
|
|
||||||
whenListen(
|
|
||||||
startGameBloc,
|
|
||||||
Stream.value(const StartGameState.initial()),
|
|
||||||
initialState: const StartGameState.initial(),
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.pumpApp(
|
|
||||||
CharacterSelectionView(),
|
|
||||||
characterThemeCubit: characterThemeCubit,
|
|
||||||
startGameBloc: startGameBloc,
|
|
||||||
);
|
|
||||||
await tester.ensureVisible(find.byType(TextButton));
|
|
||||||
await tester.tap(find.byType(TextButton));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
|
|
||||||
verify(() => startGameBloc.add(CharacterSelected())).called(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('CharacterImageButton renders correctly', (tester) async {
|
|
||||||
await tester.pumpApp(
|
|
||||||
CharacterImageButton(DashTheme()),
|
|
||||||
characterThemeCubit: characterThemeCubit,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(find.byType(Image), findsOneWidget);
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
Reference in new issue