Skip to content

Commit

Permalink
Merge pull request #130 from canopas/Mayank/refactor-tournament-detai…
Browse files Browse the repository at this point in the history
…l-stats-filter

Refactor tournament detail stats filter
  • Loading branch information
cp-mayank authored Nov 7, 2024
2 parents 85b87c0 + 2ac1a46 commit 29a3043
Show file tree
Hide file tree
Showing 11 changed files with 332 additions and 291 deletions.
102 changes: 102 additions & 0 deletions data/lib/api/match/match_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,105 @@ class TeamStat with _$TeamStat {
@Default(0.0) double run_rate,
}) = _TeamStat;
}

extension TeamStatExtension on List<MatchModel> {
TeamStat teamStat(String teamId) {
if (isEmpty) return const TeamStat();

var runs = 0;
var wickets = 0;
var battingAverageTotal = 0.0;
var bowlingAverageTotal = 0.0;
var highestRuns = 0;
var lowestRuns = double.maxFinite.toInt();

for (final match in this) {
final team = _getTeam(match, teamId);
final opponentTeam = _getOpponentTeam(match, teamId);

runs += team.run;
wickets += team.wicket;

battingAverageTotal +=
opponentTeam.wicket > 0 ? team.run / opponentTeam.wicket : 0;
if (team.wicket > 0) {
bowlingAverageTotal += opponentTeam.run / team.wicket;
}

if (team.run > highestRuns) highestRuns = team.run;
if (team.run < lowestRuns) lowestRuns = team.run;
}

final bowlingAverage = length > 0.0 ? bowlingAverageTotal / length : 0.0;

return TeamStat(
played: length,
status: _teamMatchStatus(teamId),
run_rate: _runRate(teamId, runs),
runs: runs,
wickets: wickets,
batting_average: battingAverageTotal,
bowling_average: bowlingAverage,
highest_runs: highestRuns,
lowest_runs: lowestRuns == double.maxFinite.toInt() ? 0 : lowestRuns,
);
}

TeamMatchStatus _teamMatchStatus(String teamId) {
return fold<TeamMatchStatus>(
const TeamMatchStatus(),
(status, match) {
final firstTeam = match.teams.firstWhere(
(team) =>
team.team.id ==
(match.toss_decision == TossDecision.bat
? match.toss_winner_id
: match.teams
.firstWhere(
(team) => team.team.id != match.toss_winner_id,
)
.team
.id),
);

final secondTeam =
match.teams.firstWhere((team) => team.team.id != firstTeam.team.id);

if (firstTeam.run == secondTeam.run) {
return TeamMatchStatus(
win: status.win,
lost: status.lost,
tie: status.tie + 1,
);
} else if ((firstTeam.run > secondTeam.run &&
firstTeam.team.id == teamId) ||
(firstTeam.run < secondTeam.run && secondTeam.team.id == teamId)) {
return TeamMatchStatus(
win: status.win + 1,
lost: status.lost,
tie: status.tie,
);
} else {
return TeamMatchStatus(
win: status.win,
lost: status.lost + 1,
tie: status.tie,
);
}
},
);
}

MatchTeamModel _getTeam(MatchModel match, String teamId) =>
match.teams.firstWhere((team) => team.team.id == teamId);

MatchTeamModel _getOpponentTeam(MatchModel match, String teamId) =>
match.teams.firstWhere((team) => team.team.id != teamId);

double _runRate(String teamId, int runs) {
final totalOvers = map((match) => _getTeam(match, teamId))
.fold<double>(0.0, (total, team) => total + team.over);

return totalOvers > 0 ? runs / totalOvers : 0;
}
}
3 changes: 1 addition & 2 deletions data/lib/service/tournament/tournament_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ class TournamentService {
}
}
}
final keyStats = playerStatsList.getTopKeyStats()
..sort((a, b) => b.value?.compareTo(a.value ?? 0) ?? 0);
final keyStats = playerStatsList.getTopKeyStats();

return keyStats.where((element) => element.player.isActive).toList();
}
Expand Down
8 changes: 8 additions & 0 deletions khelo/assets/locales/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@
"tournament_detail_key_stat_most_fours_title": "Most Fours",
"tournament_detail_key_stat_most_sixes_title": "Most Sixes",

"key_stat_filter_runs": "Runs",
"key_stat_filter_wickets": "Wickets",
"key_stat_filter_fours": "Fours",
"key_stat_filter_sixes": "Sixes",
"key_stat_filter_most_hundreds": "Most hundreds",
"key_stat_filter_most_fifties": "Most fifties",
"key_stat_filter_boundaries": "Boundaries",

"tournament_detail_points_table_points_title": "Points",
"tournament_detail_points_table_empty_title": "No Points Yet!",
"tournament_detail_points_table_empty_description": "The points table will be updated once matches begin. Stay tuned for the latest standings!",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import 'package:khelo/domain/extensions/context_extensions.dart';
import 'package:khelo/domain/extensions/enum_extensions.dart';
import 'package:khelo/ui/flow/matches/add_match/add_match_view_model.dart';
import 'package:khelo/ui/flow/matches/add_match/components/section_title.dart';
import 'package:style/animations/on_tap_scale.dart';
import 'package:style/extensions/context_extensions.dart';
import 'package:style/text/app_text_style.dart';
import 'package:style/button/chip_button.dart';
import 'package:data/api/match/match_model.dart';

class PitchSelectionView extends StatelessWidget {
Expand All @@ -31,47 +29,18 @@ class PitchSelectionView extends StatelessWidget {
padding: const EdgeInsets.only(left: 16, right: 8),
child: Row(
children: PitchType.values
.map((type) => _capsuleCell(
context: context,
title: type.getString(context),
isSelected: state.pitchType == type,
onTap: () => notifier.onPitchTypeSelection(type),
.map((type) => Padding(
padding: const EdgeInsets.only(right: 8),
child: ChipButton(
title: type.getString(context),
isSelected: state.pitchType == type,
onTap: () => notifier.onPitchTypeSelection(type),
),
))
.toList(),
)),
],
),
);
}

Widget _capsuleCell({
required BuildContext context,
required String title,
required bool isSelected,
required VoidCallback onTap,
}) {
return Padding(
padding: const EdgeInsets.only(right: 8),
child: OnTapScale(
onTap: () => onTap(),
child: Chip(
label: Text(
title,
style: AppTextStyle.body2.copyWith(
color: isSelected
? context.colorScheme.onPrimary
: context.colorScheme.textDisabled),
),
backgroundColor: isSelected
? context.colorScheme.primary
: context.colorScheme.containerLowOnSurface,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
side: const BorderSide(color: Colors.transparent),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import 'package:khelo/domain/extensions/context_extensions.dart';
import 'package:khelo/domain/extensions/enum_extensions.dart';
import 'package:khelo/ui/flow/score_board/components/bottom_sheet_wrapper.dart';
import 'package:khelo/ui/flow/score_board/score_board_view_model.dart';
import 'package:style/animations/on_tap_scale.dart';
import 'package:style/button/chip_button.dart';
import 'package:style/button/primary_button.dart';
import 'package:style/extensions/context_extensions.dart';
import 'package:style/text/app_text_style.dart';

class SelectWicketTypeSheet extends ConsumerStatefulWidget {
static Future<T?> show<T>(BuildContext context) {
Expand Down Expand Up @@ -64,26 +63,10 @@ class _SelectWicketTypeSheetState extends ConsumerState<SelectWicketTypeSheet> {
children: WicketType.values.map(
(element) {
final isSelected = selectedType == element;
return OnTapScale(
return ChipButton(
isSelected: isSelected,
title: element.getString(context),
onTap: () => setState(() => selectedType = element),
child: Chip(
label: Text(
element.getString(context),
style: AppTextStyle.body2.copyWith(
color: isSelected
? context.colorScheme.onPrimary
: context.colorScheme.textSecondary,
),
),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
side: const BorderSide(color: Colors.transparent),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
backgroundColor: isSelected
? context.colorScheme.primary
: context.colorScheme.containerLowOnSurface,
),
);
},
).toList(),
Expand Down
120 changes: 2 additions & 118 deletions khelo/lib/ui/flow/team/detail/team_detail_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,126 +58,10 @@ class TeamDetailViewNotifier extends StateNotifier<TeamDetailState> {
}

TeamStat _calculateTeamStat(String teamId, List<MatchModel> matches) {
final finishedMatches = _filterFinishedMatches(matches);
if (finishedMatches.isEmpty) return const TeamStat();
final totalRuns = _totalRuns(teamId, finishedMatches);
return TeamStat(
played: finishedMatches.length,
status: _teamMatchStatus(teamId, finishedMatches),
runs: totalRuns,
wickets: _wickets(teamId, finishedMatches),
batting_average: _battingAverage(teamId, finishedMatches),
bowling_average: _bowlingAverage(teamId, finishedMatches),
highest_runs: _highestAndLowestRuns(teamId, finishedMatches).$1,
lowest_runs: _highestAndLowestRuns(teamId, finishedMatches).$2,
run_rate: _runRate(teamId, finishedMatches, totalRuns),
);
}

List<MatchModel> _filterFinishedMatches(List<MatchModel> matches) {
return matches
final finishedMatches = matches
.where((match) => match.match_status == MatchStatus.finish)
.toList();
}

int _totalRuns(String teamId, List<MatchModel> finishedMatches) {
return finishedMatches
.map((match) => _getTeam(match, teamId))
.fold<int>(0, (totalRuns, team) => totalRuns + team.run);
}

int _wickets(String teamId, List<MatchModel> finishedMatches) {
return finishedMatches
.map((match) => _getTeam(match, teamId))
.fold<int>(0, (totalWickets, team) => totalWickets + team.wicket);
}

double _battingAverage(String teamId, List<MatchModel> finishedMatches) {
return finishedMatches.fold<double>(
0,
(total, match) {
final team = _getTeam(match, teamId);
final opponentTeam = _getOpponentTeam(match, teamId);

return total +
(opponentTeam.wicket > 0 ? team.run / opponentTeam.wicket : 0);
},
);
}

MatchTeamModel _getTeam(MatchModel match, String teamId) =>
match.teams.firstWhere((team) => team.team.id == teamId);

MatchTeamModel _getOpponentTeam(MatchModel match, String teamId) =>
match.teams.firstWhere((team) => team.team.id != teamId);

double _bowlingAverage(String teamId, List<MatchModel> finishedMatches) {
return finishedMatches.fold<double>(
0,
(total, match) {
final team = _getTeam(match, teamId);
final opponentTeam = _getOpponentTeam(match, teamId);

return total +
(team.wicket > 0 ? opponentTeam.run / team.wicket : 0);
},
) /
finishedMatches.length;
}

(int, int) _highestAndLowestRuns(
String teamId, List<MatchModel> finishedMatches) {
final firstTeamRuns =
finishedMatches.map((match) => _getTeam(match, teamId).run).toList();
if (firstTeamRuns.isEmpty) {
return (0, 0);
}
final highestRuns = firstTeamRuns
.reduce((value, element) => element > value ? element : value);
final lowestRuns = firstTeamRuns
.reduce((value, element) => element < value ? element : value);
return (highestRuns, lowestRuns);
}

double _runRate(String teamId, List<MatchModel> finishedMatches, int runs) {
final totalOvers = finishedMatches
.map((match) => _getTeam(match, teamId))
.fold<double>(0.0, (total, team) => total + team.over);

return totalOvers > 0 ? runs / totalOvers : 0;
}

TeamMatchStatus _teamMatchStatus(
String teamId, List<MatchModel> finishedMatches) {
return finishedMatches.fold<TeamMatchStatus>(
const TeamMatchStatus(),
(status, match) {
final firstTeam = match.teams.firstWhere((team) =>
team.team.id ==
(match.toss_decision == TossDecision.bat
? match.toss_winner_id
: match.teams
.firstWhere((team) => team.team.id != match.toss_winner_id)
.team
.id));

final secondTeam =
match.teams.firstWhere((team) => team.team.id != firstTeam.team.id);

if (firstTeam.run == secondTeam.run) {
return TeamMatchStatus(
win: status.win, lost: status.lost, tie: status.tie + 1);
} else if ((firstTeam.run > secondTeam.run &&
firstTeam.team.id == teamId) ||
(firstTeam.run < secondTeam.run && secondTeam.team.id == teamId)) {
return TeamMatchStatus(
win: status.win + 1, lost: status.lost, tie: status.tie);
} else {
return TeamMatchStatus(
win: status.win, lost: status.lost + 1, tie: status.tie);
}
},
);
return finishedMatches.teamStat(teamId);
}

void onTabChange(int tab) {
Expand Down
Loading

0 comments on commit 29a3043

Please sign in to comment.