feat: added leaderbloc to screen

pull/51/head
RuiAlonso 4 years ago
parent 424921415e
commit 2ad561e8a8

@ -40,8 +40,8 @@
"@character": {
"description": "Text displayed on the leaders board page header character column"
},
"userName": "UserName",
"@userName": {
"username": "Username",
"@username": {
"description": "Text displayed on the leaders board page header userName column"
},
"score": "Score",

@ -8,14 +8,9 @@ import 'package:pinball/leaderboard/leaderboard.dart';
import 'package:pinball/theme/theme.dart';
import 'package:pinball_theme/pinball_theme.dart';
/// {@template leaderboard_page}
/// Shows the leaderboard page of [Competitor]s.
/// {@endtemplate}
class LeaderboardPage extends StatelessWidget {
/// {@macro leaderboard_page}
const LeaderboardPage({Key? key, required this.theme}) : super(key: key);
/// Current [CharacterTheme] to customize screen
final CharacterTheme theme;
static Route route({required CharacterTheme theme}) {
@ -29,7 +24,7 @@ class LeaderboardPage extends StatelessWidget {
return BlocProvider(
create: (context) => LeaderboardBloc(
context.read<LeaderboardRepository>(),
),
)..add(const Top10Fetched()),
child: LeaderboardView(theme: theme),
);
}
@ -56,7 +51,21 @@ class LeaderboardView extends StatelessWidget {
style: Theme.of(context).textTheme.headline3,
),
const SizedBox(height: 80),
_LeaderboardRanking(theme: theme),
BlocBuilder<LeaderboardBloc, LeaderboardState>(
builder: (context, state) {
switch (state.status) {
case LeaderboardStatus.loading:
return _LeaderboardLoading(theme: theme);
case LeaderboardStatus.success:
return _LeaderboardRanking(
ranking: state.leaderboard,
theme: theme,
);
case LeaderboardStatus.error:
return _LeaderboardError(theme: theme);
}
},
),
const SizedBox(height: 20),
TextButton(
onPressed: () => Navigator.of(context).push<void>(
@ -72,9 +81,45 @@ class LeaderboardView extends StatelessWidget {
}
}
class _LeaderboardLoading extends StatelessWidget {
const _LeaderboardLoading({Key? key, required this.theme}) : super(key: key);
final CharacterTheme theme;
@override
Widget build(BuildContext context) {
return const Center(
child: CircularProgressIndicator(),
);
}
}
class _LeaderboardError extends StatelessWidget {
const _LeaderboardError({Key? key, required this.theme}) : super(key: key);
final CharacterTheme theme;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(20),
child: Text(
'There was en error loading data!',
style:
Theme.of(context).textTheme.headline6?.copyWith(color: Colors.red),
),
);
}
}
class _LeaderboardRanking extends StatelessWidget {
const _LeaderboardRanking({Key? key, required this.theme}) : super(key: key);
const _LeaderboardRanking({
Key? key,
required this.ranking,
required this.theme,
}) : super(key: key);
final List<LeaderboardEntry> ranking;
final CharacterTheme theme;
@override
@ -85,7 +130,10 @@ class _LeaderboardRanking extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
_LeaderboardHeaders(theme: theme),
_LeaderboardList(theme: theme),
_LeaderboardList(
ranking: ranking,
theme: theme,
),
],
),
);
@ -106,7 +154,7 @@ class _LeaderboardHeaders extends StatelessWidget {
children: [
_LeaderboardHeaderItem(title: l10n.rank, theme: theme),
_LeaderboardHeaderItem(title: l10n.character, theme: theme),
_LeaderboardHeaderItem(title: l10n.userName, theme: theme),
_LeaderboardHeaderItem(title: l10n.username, theme: theme),
_LeaderboardHeaderItem(title: l10n.score, theme: theme),
],
);
@ -140,8 +188,13 @@ class _LeaderboardHeaderItem extends StatelessWidget {
}
class _LeaderboardList extends StatelessWidget {
const _LeaderboardList({Key? key, required this.theme}) : super(key: key);
const _LeaderboardList({
Key? key,
required this.ranking,
required this.theme,
}) : super(key: key);
final List<LeaderboardEntry> ranking;
final CharacterTheme theme;
@override
@ -159,7 +212,7 @@ class _LeaderboardList extends StatelessWidget {
),
theme: theme,
),
itemCount: 10,
itemCount: ranking.length,
);
}
}

@ -7,11 +7,10 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/app/app.dart';
import 'package:pinball/landing/landing.dart';
class MockLeaderboardRepository extends Mock implements LeaderboardRepository {}
import '../../helpers/mocks.dart';
void main() {
group('App', () {

@ -1,9 +1,12 @@
import 'package:bloc_test/bloc_test.dart';
import 'package:flame/input.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball/leaderboard/leaderboard.dart';
import 'package:pinball/theme/theme.dart';
class MockPinballGame extends Mock implements PinballGame {}
@ -32,6 +35,11 @@ class MockGameState extends Mock implements GameState {}
class MockThemeCubit extends Mock implements ThemeCubit {}
class MockLeaderboardBloc extends MockBloc<LeaderboardEvent, LeaderboardState>
implements LeaderboardBloc {}
class MockLeaderboardRepository extends Mock implements LeaderboardRepository {}
class MockRawKeyDownEvent extends Mock implements RawKeyDownEvent {
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {

@ -9,6 +9,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:mockingjay/mockingjay.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball/l10n/l10n.dart';
@ -22,9 +23,16 @@ extension PumpApp on WidgetTester {
MockNavigator? navigator,
GameBloc? gameBloc,
ThemeCubit? themeCubit,
LeaderboardRepository? leaderboardRepository,
}) {
return pumpWidget(
MultiBlocProvider(
MultiRepositoryProvider(
providers: [
RepositoryProvider.value(
value: leaderboardRepository ?? MockLeaderboardRepository(),
)
],
child: MultiBlocProvider(
providers: [
BlocProvider.value(
value: themeCubit ?? MockThemeCubit(),
@ -44,6 +52,7 @@ extension PumpApp on WidgetTester {
: widget,
),
),
),
);
}
}

@ -1,10 +1,13 @@
// ignore_for_file: prefer_const_constructors
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:mockingjay/mockingjay.dart';
import 'package:pinball/l10n/l10n.dart';
import 'package:pinball/leaderboard/leaderboard.dart';
import 'package:pinball/leaderboard/view/leaderboard_page.dart';
import 'package:pinball_theme/pinball_theme.dart';
@ -33,18 +36,101 @@ void main() {
});
group('LeaderboardView', () {
late LeaderboardBloc leaderboardBloc;
setUp(() {
leaderboardBloc = MockLeaderboardBloc();
});
testWidgets('renders correctly', (tester) async {
final l10n = await AppLocalizations.delegate.load(Locale('en'));
when(() => leaderboardBloc.state).thenReturn(LeaderboardState.initial());
await tester.pumpApp(
LeaderboardPage(
BlocProvider.value(
value: leaderboardBloc,
child: LeaderboardView(
theme: DashTheme(),
),
),
);
expect(find.text(l10n.leadersboard), findsOneWidget);
expect(find.text(l10n.retry), findsOneWidget);
});
testWidgets('renders loading view when bloc emits [loading]',
(tester) async {
when(() => leaderboardBloc.state).thenReturn(LeaderboardState.initial());
await tester.pumpApp(
BlocProvider.value(
value: leaderboardBloc,
child: LeaderboardView(
theme: DashTheme(),
),
),
);
expect(find.byType(CircularProgressIndicator), findsOneWidget);
expect(find.text('There was en error loading data!'), findsNothing);
expect(find.byType(ListView), findsNothing);
});
testWidgets('renders error view when bloc emits [error]', (tester) async {
when(() => leaderboardBloc.state).thenReturn(
LeaderboardState.initial().copyWith(status: LeaderboardStatus.error),
);
await tester.pumpApp(
BlocProvider.value(
value: leaderboardBloc,
child: LeaderboardView(
theme: DashTheme(),
),
),
);
expect(find.byType(CircularProgressIndicator), findsNothing);
expect(find.text('There was en error loading data!'), findsOneWidget);
expect(find.byType(ListView), findsNothing);
});
testWidgets('renders success view when bloc emits [success]',
(tester) async {
final l10n = await AppLocalizations.delegate.load(Locale('en'));
when(() => leaderboardBloc.state).thenReturn(
LeaderboardState(
status: LeaderboardStatus.success,
ranking: LeaderboardRanking(ranking: 0, outOf: 0),
leaderboard: const [
LeaderboardEntry(
playerInitials: 'ABC',
score: 10000,
character: CharacterType.dash,
),
],
),
);
await tester.pumpApp(
BlocProvider.value(
value: leaderboardBloc,
child: LeaderboardView(
theme: DashTheme(),
),
),
);
expect(find.byType(CircularProgressIndicator), findsNothing);
expect(find.text('There was en error loading data!'), findsNothing);
expect(find.text(l10n.rank), findsOneWidget);
expect(find.text(l10n.character), findsOneWidget);
expect(find.text(l10n.username), findsOneWidget);
expect(find.text(l10n.score), findsOneWidget);
expect(find.byType(ListView), findsOneWidget);
});
testWidgets('navigates to CharacterSelectionPage when retry is tapped',
(tester) async {
final navigator = MockNavigator();

Loading…
Cancel
Save