Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: creates PlayerBloc and adds the player to leaderboard_page.dart #282

Merged
merged 9 commits into from
Apr 15, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ class LeaderboardPlayer extends Equatable {
factory LeaderboardPlayer.fromJson(Map<String, dynamic> json) =>
_$LeaderboardPlayerFromJson(json);

/// Creates empty [LeaderboardPlayer].
static const empty = LeaderboardPlayer(
userId: '',
initials: '',
score: 0,
streak: 0,
mascot: Mascots.dash,
);

/// Unique identifier of the leaderboard player object
/// and session id for the player.
@JsonKey()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ import 'package:test/test.dart';

void main() {
group('LeaderboardPlayer', () {
test('empty', () {
expect(
LeaderboardPlayer.empty,
equals(
LeaderboardPlayer(
userId: '',
initials: '',
score: 0,
streak: 0,
mascot: Mascots.dash,
),
),
);
});

test('can be instantiated', () {
expect(
LeaderboardPlayer(
Expand Down
8 changes: 8 additions & 0 deletions lib/app/view/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:io_crossword/challenge/challenge.dart';
import 'package:io_crossword/crossword/crossword.dart';
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_ui/io_crossword_ui.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:provider/provider.dart';
Expand Down Expand Up @@ -51,6 +52,13 @@ class App extends StatelessWidget {
crosswordResource: crosswordResource,
),
),
BlocProvider(
// coverage:ignore-start
create: (_) => PlayerBloc(
leaderboardRepository: leaderboardRepository,
)..add(PlayerLoaded(userId: user.id)),
// coverage:ignore-end
),
BlocProvider(
create: (context) => ChallengeBloc(
boardInfoRepository: context.read(),
Expand Down
37 changes: 6 additions & 31 deletions lib/leaderboard/bloc/leaderboard_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,37 +45,12 @@ class LeaderboardBloc extends Bloc<LeaderboardEvent, LeaderboardState> {
return;
}

final foundCurrentUser =
players.where((player) => player.userId == event.userId);

// In this case we don't need to search for the player position
// because its in top 10 leaderboard.
if (foundCurrentUser.isNotEmpty) {
emit(
state.copyWith(
status: LeaderboardStatus.success,
players: players,
),
);
} else {
return emit.forEach(
_leaderboardRepository.getPlayerRanked(event.userId),
onData: (data) {
return state.copyWith(
currentPlayer: data.$1,
currentUserPosition: data.$2,
status: LeaderboardStatus.success,
players: players,
);
},
onError: (error, stackTrace) {
addError(error, stackTrace);
return state.copyWith(
status: LeaderboardStatus.failure,
);
},
);
}
emit(
state.copyWith(
status: LeaderboardStatus.success,
players: players,
),
);
} catch (error, stackTrace) {
addError(error, stackTrace);
emit(state.copyWith(status: LeaderboardStatus.failure));
Expand Down
14 changes: 1 addition & 13 deletions lib/leaderboard/bloc/leaderboard_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,21 @@ class LeaderboardState extends Equatable {
const LeaderboardState({
this.status = LeaderboardStatus.initial,
this.players = const [],
this.currentUserPosition = 0,
this.currentPlayer,
});

final LeaderboardStatus status;
final List<LeaderboardPlayer> players;

// TODO(Ayad): Remove currentUserPosition and currentPlayer
// https://very-good-ventures-team.monday.com/boards/6004820050/pulses/6445638020
final int currentUserPosition;
final LeaderboardPlayer? currentPlayer;

LeaderboardState copyWith({
LeaderboardStatus? status,
List<LeaderboardPlayer>? players,
int? currentUserPosition,
LeaderboardPlayer? currentPlayer,
}) {
return LeaderboardState(
status: status ?? this.status,
players: players ?? this.players,
currentUserPosition: currentUserPosition ?? this.currentUserPosition,
currentPlayer: currentPlayer ?? this.currentPlayer,
);
}

@override
List<Object?> get props =>
[status, players, currentUserPosition, currentPlayer];
List<Object?> get props => [status, players];
}
1 change: 1 addition & 0 deletions lib/leaderboard/view/leaderboard_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:game_domain/game_domain.dart';
import 'package:io_crossword/extensions/extensions.dart';
import 'package:io_crossword/l10n/l10n.dart';
import 'package:io_crossword/leaderboard/bloc/leaderboard_bloc.dart';
import 'package:io_crossword/player/player.dart';
import 'package:io_crossword_ui/io_crossword_ui.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';

Expand Down
9 changes: 4 additions & 5 deletions lib/leaderboard/view/leaderboard_success.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,14 @@ class CurrentPlayerNotTopRank extends StatelessWidget {

@override
Widget build(BuildContext context) {
final player =
context.select((LeaderboardBloc bloc) => bloc.state.currentPlayer);

if (player == null) return const SizedBox.shrink();
final player = context.select((PlayerBloc bloc) => bloc.state.player);

final rank = context.select(
(LeaderboardBloc bloc) => bloc.state.currentUserPosition,
(PlayerBloc bloc) => bloc.state.rank,
);

if (rank <= 10) return const SizedBox();

return Padding(
padding: const EdgeInsets.only(top: 8, bottom: 16),
child: CurrentUserPosition(
Expand Down
40 changes: 40 additions & 0 deletions lib/player/bloc/player_bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:game_domain/game_domain.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';

part 'player_event.dart';
part 'player_state.dart';

class PlayerBloc extends Bloc<PlayerEvent, PlayerState> {
PlayerBloc({
required LeaderboardRepository leaderboardRepository,
}) : _leaderboardRepository = leaderboardRepository,
super(const PlayerState()) {
on<PlayerLoaded>(_onPlayerLoaded);
}

final LeaderboardRepository _leaderboardRepository;

Future<void> _onPlayerLoaded(
PlayerLoaded event,
Emitter<PlayerState> emit,
) {
return emit.forEach(
_leaderboardRepository.getPlayerRanked(event.userId),
onData: (data) {
return PlayerState(
status: PlayerStatus.playing,
player: data.$1,
rank: data.$2,
);
},
onError: (error, stackTrace) {
addError(error, stackTrace);
return state.copyWith(
status: PlayerStatus.failure,
);
},
);
}
}
14 changes: 14 additions & 0 deletions lib/player/bloc/player_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
part of 'player_bloc.dart';

abstract class PlayerEvent extends Equatable {
const PlayerEvent();
}

class PlayerLoaded extends PlayerEvent {
const PlayerLoaded({required this.userId});

final String userId;

@override
List<Object?> get props => [userId];
}
35 changes: 35 additions & 0 deletions lib/player/bloc/player_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
part of 'player_bloc.dart';

enum PlayerStatus {
onboarding,
loading,
playing,
failure,
}

class PlayerState extends Equatable {
const PlayerState({
this.status = PlayerStatus.onboarding,
this.player = LeaderboardPlayer.empty,
this.rank = 0,
});

PlayerState copyWith({
PlayerStatus? status,
LeaderboardPlayer? player,
int? rank,
}) {
return PlayerState(
status: status ?? this.status,
player: player ?? this.player,
rank: rank ?? this.rank,
);
}

final PlayerStatus status;
final LeaderboardPlayer player;
final int rank;

@override
List<Object?> get props => [status, player, rank];
}
1 change: 1 addition & 0 deletions lib/player/player.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'bloc/player_bloc.dart';
Loading
Loading