From a32a415eadd33811b74ab832772e0bd922e81098 Mon Sep 17 00:00:00 2001 From: sidhdhi canopas <122426509+cp-sidhdhi-p@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:18:47 +0530 Subject: [PATCH] Redesign match detail screen (#24) * redesign match detail * change highlight btn * code refactor * transform data in models * fix data repeating * change image avatar * add status tag * use tab button --- data/lib/api/ball_score/ball_score_model.dart | 438 +++++- .../ball_score/ball_score_model.freezed.dart | 1340 +++++++++++++++++ data/lib/api/innings/inning_model.dart | 2 +- data/lib/api/innings/inning_model.g.dart | 4 +- data/lib/api/match/match_model.dart | 65 + data/lib/api/network/client.dart | 2 +- data/lib/extensions/double_extensions.dart | 34 + data/lib/extensions/int_extensions.dart | 7 + data/lib/extensions/list_extensions.dart | 2 +- .../ball_score/ball_score_service.dart | 2 +- data/lib/service/user/user_service.dart | 3 +- data/lib/storage/app_preferences.dart | 5 +- .../provider/preferences_provider.dart | 3 +- .../constant/firebase_error_constant.dart | 2 +- .../utils/constant/firestore_constant.dart | 2 +- khelo/assets/locales/app_en.arb | 54 +- khelo/lib/components/app_page.dart | 12 +- khelo/lib/components/image_avatar.dart | 52 +- khelo/lib/components/match_detail_cell.dart | 15 +- .../lib/components/profile_image_avatar.dart | 48 +- khelo/lib/components/won_by_message_text.dart | 39 +- .../ball_score_model_extension.dart | 14 - .../match_model_extension.dart | 44 - .../domain/extensions/enum_extensions.dart | 13 + .../domain/extensions/string_extensions.dart | 13 + .../lib/domain/formatter/date_formatter.dart | 13 +- .../components/commentary_ball_summary.dart | 183 +-- .../components/commentary_over_overview.dart | 393 ++--- .../components/final_score_view.dart | 73 +- .../match_detail_commentary_view.dart | 161 +- .../match_detail_highlight_view.dart | 136 +- .../components/match_detail_info_view.dart | 132 +- .../components/match_detail_overs_view.dart | 134 +- .../match_detail_scorecard_view.dart | 949 ++++++------ .../components/match_detail_squad_view.dart | 258 ++-- .../components/over_score_view.dart | 12 +- .../match_detail/match_detail_tab_screen.dart | 108 +- .../match_detail_tab_view_model.dart | 383 ++++- .../match_detail_tab_view_model.freezed.dart | 154 +- .../ui/flow/matches/match_list_screen.dart | 4 +- khelo/lib/ui/flow/profile/profile_screen.dart | 27 +- .../components/match_complete_sheet.dart | 32 +- .../score_board/score_board_view_model.dart | 1 - .../flow/team/detail/team_detail_screen.dart | 4 +- khelo/pubspec.lock | 30 +- style/lib/animations/on_tap_scale.dart | 2 +- style/lib/button/large_icon_button.dart | 2 +- style/lib/button/tab_button.dart | 3 + style/lib/extensions/context_extensions.dart | 2 +- style/lib/extensions/date_extensions.dart | 2 +- style/lib/indicator/progress_indicator.dart | 2 +- style/lib/text/app_text_field.dart | 2 +- style/lib/text/app_text_style.dart | 2 +- style/lib/widgets/adaptive_outlined_tile.dart | 4 + 54 files changed, 3613 insertions(+), 1810 deletions(-) create mode 100644 data/lib/extensions/double_extensions.dart create mode 100644 data/lib/extensions/int_extensions.dart delete mode 100644 khelo/lib/domain/extensions/data_model_extensions/match_model_extension.dart diff --git a/data/lib/api/ball_score/ball_score_model.dart b/data/lib/api/ball_score/ball_score_model.dart index b64c42dc..ccb3e1e9 100644 --- a/data/lib/api/ball_score/ball_score_model.dart +++ b/data/lib/api/ball_score/ball_score_model.dart @@ -1,5 +1,7 @@ // ignore_for_file: non_constant_identifier_names +import 'package:data/extensions/double_extensions.dart'; +import 'package:data/extensions/int_extensions.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'ball_score_model.freezed.dart'; @@ -127,4 +129,438 @@ class TeamRunStat with _$TeamRunStat { factory TeamRunStat.fromJson(Map json) => _$TeamRunStatFromJson(json); -} \ No newline at end of file +} + +@freezed +class OverSummary with _$OverSummary { + const factory OverSummary({ + @Default('') String inning_id, + @Default('') String team_id, + @Default([]) List balls, + @Default(BowlerSummary()) BowlerSummary bowler, + @Default(BatsmanSummary()) BatsmanSummary striker, + @Default(BatsmanSummary()) BatsmanSummary nonStriker, + @Default([]) List outPlayers, + @Default(0) int overNumber, + @Default(ExtraSummary()) ExtraSummary extrasSummary, + @Default(0) int totalRuns, + @Default(0) int totalWickets, + }) = _OverSummary; +} + +@freezed +class BatsmanSummary with _$BatsmanSummary { + const factory BatsmanSummary({ + @Default(Player()) Player player, + Player? ballBy, + Player? catchBy, + WicketType? wicketType, + double? outAtOver, + @Default(0) int runs, + @Default(0) int ballFaced, + @Default(0) int sixes, + @Default(0) int fours, + }) = _BatsmanSummary; +} + +@freezed +class BowlerSummary with _$BowlerSummary { + const factory BowlerSummary({ + @Default(Player()) Player player, + @Default(0) int runsConceded, + @Default(0) int maiden, + @Default(0) double overDelivered, + @Default(0) int wicket, + @Default(0) int noBalls, + @Default(0) int wideBalls, + }) = _BowlerSummary; +} + +@freezed +class Player with _$Player { + const factory Player({ + @Default("") String id, + @Default("") String name, + }) = _Player; +} + +@freezed +class ExtraSummary with _$ExtraSummary { + const factory ExtraSummary({ + @Default(0) int bye, + @Default(0) int legBye, + @Default(0) int noBall, + @Default(0) int wideBall, + @Default(0) int penalty, + }) = _ExtraSummary; +} + +extension BallScoreModelBoolean on BallScoreModel? { + bool? isLegalDelivery() { + if (this == null) { + return null; + } + return this!.extras_type != ExtrasType.penaltyRun && + this!.extras_type != ExtrasType.noBall && + this!.extras_type != ExtrasType.wide && + this!.wicket_type != WicketType.timedOut && + this!.wicket_type != WicketType.retired && + this!.wicket_type != WicketType.retiredHurt; + } +} + +extension OverSummaryMetaData on OverSummary { + bool get isMaiden => + runs == 0 && + wickets == 0 && + extras == 0 && + balls.lastOrNull?.ball_number == 6 && + (balls.lastOrNull?.isLegalDelivery() ?? false); + + double get overCount { + int totalBalls = ((overNumber - 1) * 6) + legalDeliveriesCount; + return totalBalls.toOvers(); + } + + int get legalDeliveriesCount => + balls.where((ball) => (ball.isLegalDelivery() ?? false)).length; + + int get runs => + balls.fold(0, (runCount, element) => runCount += element.runs_scored); + + int get extras => balls.fold( + 0, (extraCount, element) => extraCount += (element.extras_awarded ?? 0)); + + int get wickets => balls.fold( + 0, + (wicketCount, element) => wicketCount += (element.wicket_type != null && + element.wicket_type != WicketType.retiredHurt + ? 1 + : 0)); + + DateTime get time => balls.lastOrNull?.time ?? DateTime.now(); + + BowlerSummary get bowlerStatAtStart { + final runsInOver = balls + .where((ball) => + ball.extras_type == null || + ball.extras_type == ExtrasType.noBall || + ball.extras_type == ExtrasType.wide) + .fold( + 0, + (runCount, ball) => + runCount += (ball.extras_awarded ?? 0) + ball.runs_scored); + final runsConceded = bowler.runsConceded - runsInOver; + final maiden = bowler.maiden - (isMaiden ? 1 : 0); + final wicketsInOver = balls + .where((element) => + element.wicket_type != null && + element.wicket_type != WicketType.retired && + element.wicket_type != WicketType.retiredHurt && + element.wicket_type != WicketType.timedOut) + .length; + final wickets = bowler.wicket - wicketsInOver; + final noBallInOver = balls + .where((element) => element.extras_type == ExtrasType.noBall) + .length; + final noBalls = bowler.noBalls - noBallInOver; + final wideBallInOver = + balls.where((element) => element.extras_type == ExtrasType.wide).length; + final wideBalls = bowler.wideBalls - wideBallInOver; + + final overDelivered = bowler.overDelivered.remove(legalDeliveriesCount); + return bowler.copyWith( + wideBalls: wideBalls, + runsConceded: runsConceded, + overDelivered: overDelivered, + noBalls: noBalls, + maiden: maiden, + wicket: wickets); + } + + OverSummary addBall(BallScoreModel ball, {Player? catchBy}) { + if (ball.over_number != overNumber && ball.inning_id != inning_id) { + return this; + } + final totalRunCount = + totalRuns + ball.runs_scored + (ball.extras_awarded ?? 0); + final totalWicketCount = totalWickets + + (ball.wicket_type != null && ball.wicket_type != WicketType.retiredHurt + ? 1 + : 0); + final extraSummaryDetail = extrasSummary.addExtra(ball); + + final ballScores = [...balls, ball].toList(); + ballScores.sort((a, b) => a.time.compareTo(b.time)); + + final configuredStriker = striker.addBall(ball, + ballBy: ball.player_out_id == striker.player.id ? bowler.player : null, + catchBy: ball.player_out_id == striker.player.id ? catchBy : null); + + final configuredNonStriker = nonStriker.addBall(ball, + ballBy: + ball.player_out_id == nonStriker.player.id ? bowler.player : null, + catchBy: ball.player_out_id == nonStriker.player.id ? catchBy : null); + + final outPlayersList = outPlayers.toList(); + if (ball.player_out_id == configuredStriker.player.id) { + outPlayersList.add(configuredStriker); + } else if (ball.player_out_id == configuredNonStriker.player.id) { + outPlayersList.add(configuredNonStriker); + } + return copyWith( + totalRuns: totalRunCount, + totalWickets: totalWicketCount, + extrasSummary: extraSummaryDetail, + balls: ballScores, + bowler: bowler.addBall(ball, + isMaidenWithoutTheBall: runs == 0 && wickets == 0 && extras == 0), + outPlayers: outPlayersList, + striker: configuredStriker, + nonStriker: configuredNonStriker, + ); + } + + OverSummary? removeBall(BallScoreModel ball) { + if (ball.over_number != overNumber && ball.inning_id != inning_id) { + return this; + } + final totalRunCount = + totalRuns - ball.runs_scored - (ball.extras_awarded ?? 0); + final totalWicketCount = totalWickets - + (ball.wicket_type != null && ball.wicket_type != WicketType.retiredHurt + ? 1 + : 0); + final extraSummaryDetail = extrasSummary.removeExtra(ball); + + final ballScores = balls.toList(); + ballScores.removeWhere((element) => element.id == ball.id); + ballScores.sort((a, b) => a.time.compareTo(b.time)); + + final configuredStriker = striker.removeBall(ball); + final configuredNonStriker = nonStriker.removeBall(ball); + + final outPlayersList = outPlayers; + if (ball.player_out_id == configuredStriker.player.id) { + outPlayersList.removeWhere( + (element) => element.player.id == configuredStriker.player.id); + } else if (ball.player_out_id == configuredNonStriker.player.id) { + outPlayersList.removeWhere( + (element) => element.player.id == configuredNonStriker.player.id); + } + + final lastBall = ballScores.lastOrNull; + if (ballScores.isEmpty) { + return null; + } + return copyWith( + totalRuns: totalRunCount, + totalWickets: totalWicketCount, + extrasSummary: extraSummaryDetail, + balls: ballScores, + bowler: bowler.removeBall(ball, isMaidenIncludingBall: isMaiden), + outPlayers: outPlayersList, + striker: lastBall?.batsman_id == configuredStriker.player.id + ? configuredStriker + : configuredNonStriker, + nonStriker: lastBall?.non_striker_id == configuredNonStriker.player.id + ? configuredNonStriker + : configuredStriker, + ); + } +} + +extension BowlerSummaryMetaData on BowlerSummary { + double get economy { + return double.parse((runsConceded / overDelivered).toStringAsFixed(1)); + } + + BowlerSummary addBall(BallScoreModel ball, + {required bool isMaidenWithoutTheBall}) { + if (ball.bowler_id != player.id) { + return this; + } + final wicketCount = ball.wicket_type != null && + ball.wicket_type != WicketType.retired && + ball.wicket_type != WicketType.retiredHurt && + ball.wicket_type != WicketType.timedOut + ? wicket + 1 + : wicket; + + final noBallCount = + ball.extras_type == ExtrasType.noBall ? noBalls + 1 : noBalls; + + final wideBallCount = + ball.extras_type == ExtrasType.wide ? wideBalls + 1 : wideBalls; + + final overDeliverCount = (ball.isLegalDelivery() ?? false) + ? overDelivered.add(1) + : overDelivered; + + final runCount = ball.extras_type == null || + ball.extras_type == ExtrasType.noBall || + ball.extras_type == ExtrasType.wide + ? runsConceded + (ball.extras_awarded ?? 0) + ball.runs_scored + : runsConceded; + + final maidenCount = isMaidenWithoutTheBall && + ball.ball_number == 6 && + (ball.isLegalDelivery() ?? false) && + ball.extras_type == null && + ball.wicket_type == null && + ball.runs_scored == 0 + ? maiden + 1 + : maiden; + + return copyWith( + wicket: wicketCount, + maiden: maidenCount, + noBalls: noBallCount, + overDelivered: overDeliverCount, + runsConceded: runCount, + wideBalls: wideBallCount); + } + + BowlerSummary removeBall(BallScoreModel ball, + {required bool isMaidenIncludingBall}) { + if (ball.bowler_id != player.id) { + return this; + } + final wicketCount = ball.wicket_type != null && + ball.wicket_type != WicketType.retired && + ball.wicket_type != WicketType.retiredHurt && + ball.wicket_type != WicketType.timedOut + ? wicket - 1 + : wicket; + + final noBallCount = + ball.extras_type == ExtrasType.noBall ? noBalls - 1 : noBalls; + + final wideBallCount = + ball.extras_type == ExtrasType.wide ? wideBalls - 1 : wideBalls; + + final overDeliverCount = (ball.isLegalDelivery() ?? false) + ? overDelivered.remove(1) + : overDelivered; + + final runCount = ball.extras_type == null || + ball.extras_type == ExtrasType.noBall || + ball.extras_type == ExtrasType.wide + ? runsConceded - ((ball.extras_awarded ?? 0) + ball.runs_scored) + : runsConceded; + + final maidenCount = isMaidenIncludingBall && + ball.ball_number == 6 && + (ball.isLegalDelivery() ?? false) && + ball.extras_type == null && + ball.wicket_type == null && + ball.runs_scored == 0 + ? maiden - 1 + : maiden; + + return copyWith( + wicket: wicketCount, + maiden: maidenCount, + noBalls: noBallCount, + overDelivered: overDeliverCount, + runsConceded: runCount, + wideBalls: wideBallCount); + } +} + +extension BatsmanSummaryMetaData on BatsmanSummary { + double get strikeRate { + return double.parse(((runs / ballFaced) * 100).toStringAsFixed(1)); + } + + BatsmanSummary addBall(BallScoreModel ball, + {Player? ballBy, Player? catchBy}) { + if (ball.batsman_id != player.id && ball.non_striker_id != player.id) { + return this; + } + final ballFacedCount = ball.extras_type != ExtrasType.wide && + ball.extras_type != ExtrasType.penaltyRun && + ball.batsman_id == player.id + ? ballFaced + 1 + : ballFaced; + return copyWith( + sixes: ball.batsman_id == player.id && ball.is_six ? sixes + 1 : sixes, + fours: ball.batsman_id == player.id && ball.is_four ? fours + 1 : fours, + catchBy: catchBy, + ballBy: ballBy, + ballFaced: ballFacedCount, + runs: ball.batsman_id == player.id ? runs + ball.runs_scored : runs, + outAtOver: ball.wicket_type != null && ball.player_out_id == player.id + ? double.parse("${ball.over_number - 1}.${ball.ball_number}") + : outAtOver, + wicketType: ball.player_out_id == player.id ? ball.wicket_type : null); + } + + BatsmanSummary removeBall(BallScoreModel ball) { + if (ball.batsman_id != player.id && ball.non_striker_id != player.id) { + return this; + } + final ballFacedCount = ball.extras_type != ExtrasType.wide && + ball.extras_type != ExtrasType.penaltyRun && + ball.batsman_id == player.id + ? ballFaced - 1 + : ballFaced; + return copyWith( + sixes: ball.batsman_id == player.id && ball.is_six ? sixes - 1 : sixes, + fours: ball.batsman_id == player.id && ball.is_four ? fours - 1 : fours, + catchBy: null, + ballBy: null, + ballFaced: ballFacedCount, + runs: ball.batsman_id == player.id ? runs - ball.runs_scored : runs, + outAtOver: null, + wicketType: null); + } +} + +extension ExtraSummaryMetaData on ExtraSummary { + int get total { + return bye + legBye + noBall + wideBall + penalty; + } + + ExtraSummary addExtra(BallScoreModel ball) { + if (ball.extras_type == null) { + return this; + } + final ExtraSummary extra; + switch (ball.extras_type!) { + case ExtrasType.wide: + extra = copyWith(wideBall: wideBall + (ball.extras_awarded ?? 0)); + case ExtrasType.noBall: + extra = copyWith(noBall: noBall + (ball.extras_awarded ?? 0)); + case ExtrasType.bye: + extra = copyWith(bye: bye + (ball.extras_awarded ?? 0)); + case ExtrasType.legBye: + extra = copyWith(legBye: legBye + (ball.extras_awarded ?? 0)); + case ExtrasType.penaltyRun: + extra = copyWith(penalty: penalty + (ball.extras_awarded ?? 0)); + } + + return extra; + } + + ExtraSummary removeExtra(BallScoreModel ball) { + if (ball.extras_type == null) { + return this; + } + final ExtraSummary extra; + switch (ball.extras_type!) { + case ExtrasType.wide: + extra = copyWith(wideBall: wideBall - (ball.extras_awarded ?? 0)); + case ExtrasType.noBall: + extra = copyWith(noBall: noBall - (ball.extras_awarded ?? 0)); + case ExtrasType.bye: + extra = copyWith(bye: bye - (ball.extras_awarded ?? 0)); + case ExtrasType.legBye: + extra = copyWith(legBye: legBye - (ball.extras_awarded ?? 0)); + case ExtrasType.penaltyRun: + extra = copyWith(penalty: penalty - (ball.extras_awarded ?? 0)); + } + + return extra; + } +} diff --git a/data/lib/api/ball_score/ball_score_model.freezed.dart b/data/lib/api/ball_score/ball_score_model.freezed.dart index 4edab392..030c838e 100644 --- a/data/lib/api/ball_score/ball_score_model.freezed.dart +++ b/data/lib/api/ball_score/ball_score_model.freezed.dart @@ -1578,3 +1578,1343 @@ abstract class _TeamRunStat implements TeamRunStat { _$$TeamRunStatImplCopyWith<_$TeamRunStatImpl> get copyWith => throw _privateConstructorUsedError; } + +/// @nodoc +mixin _$OverSummary { + String get inning_id => throw _privateConstructorUsedError; + String get team_id => throw _privateConstructorUsedError; + List get balls => throw _privateConstructorUsedError; + BowlerSummary get bowler => throw _privateConstructorUsedError; + BatsmanSummary get striker => throw _privateConstructorUsedError; + BatsmanSummary get nonStriker => throw _privateConstructorUsedError; + List get outPlayers => throw _privateConstructorUsedError; + int get overNumber => throw _privateConstructorUsedError; + ExtraSummary get extrasSummary => throw _privateConstructorUsedError; + int get totalRuns => throw _privateConstructorUsedError; + int get totalWickets => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $OverSummaryCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $OverSummaryCopyWith<$Res> { + factory $OverSummaryCopyWith( + OverSummary value, $Res Function(OverSummary) then) = + _$OverSummaryCopyWithImpl<$Res, OverSummary>; + @useResult + $Res call( + {String inning_id, + String team_id, + List balls, + BowlerSummary bowler, + BatsmanSummary striker, + BatsmanSummary nonStriker, + List outPlayers, + int overNumber, + ExtraSummary extrasSummary, + int totalRuns, + int totalWickets}); + + $BowlerSummaryCopyWith<$Res> get bowler; + $BatsmanSummaryCopyWith<$Res> get striker; + $BatsmanSummaryCopyWith<$Res> get nonStriker; + $ExtraSummaryCopyWith<$Res> get extrasSummary; +} + +/// @nodoc +class _$OverSummaryCopyWithImpl<$Res, $Val extends OverSummary> + implements $OverSummaryCopyWith<$Res> { + _$OverSummaryCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? inning_id = null, + Object? team_id = null, + Object? balls = null, + Object? bowler = null, + Object? striker = null, + Object? nonStriker = null, + Object? outPlayers = null, + Object? overNumber = null, + Object? extrasSummary = null, + Object? totalRuns = null, + Object? totalWickets = null, + }) { + return _then(_value.copyWith( + inning_id: null == inning_id + ? _value.inning_id + : inning_id // ignore: cast_nullable_to_non_nullable + as String, + team_id: null == team_id + ? _value.team_id + : team_id // ignore: cast_nullable_to_non_nullable + as String, + balls: null == balls + ? _value.balls + : balls // ignore: cast_nullable_to_non_nullable + as List, + bowler: null == bowler + ? _value.bowler + : bowler // ignore: cast_nullable_to_non_nullable + as BowlerSummary, + striker: null == striker + ? _value.striker + : striker // ignore: cast_nullable_to_non_nullable + as BatsmanSummary, + nonStriker: null == nonStriker + ? _value.nonStriker + : nonStriker // ignore: cast_nullable_to_non_nullable + as BatsmanSummary, + outPlayers: null == outPlayers + ? _value.outPlayers + : outPlayers // ignore: cast_nullable_to_non_nullable + as List, + overNumber: null == overNumber + ? _value.overNumber + : overNumber // ignore: cast_nullable_to_non_nullable + as int, + extrasSummary: null == extrasSummary + ? _value.extrasSummary + : extrasSummary // ignore: cast_nullable_to_non_nullable + as ExtraSummary, + totalRuns: null == totalRuns + ? _value.totalRuns + : totalRuns // ignore: cast_nullable_to_non_nullable + as int, + totalWickets: null == totalWickets + ? _value.totalWickets + : totalWickets // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $BowlerSummaryCopyWith<$Res> get bowler { + return $BowlerSummaryCopyWith<$Res>(_value.bowler, (value) { + return _then(_value.copyWith(bowler: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $BatsmanSummaryCopyWith<$Res> get striker { + return $BatsmanSummaryCopyWith<$Res>(_value.striker, (value) { + return _then(_value.copyWith(striker: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $BatsmanSummaryCopyWith<$Res> get nonStriker { + return $BatsmanSummaryCopyWith<$Res>(_value.nonStriker, (value) { + return _then(_value.copyWith(nonStriker: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $ExtraSummaryCopyWith<$Res> get extrasSummary { + return $ExtraSummaryCopyWith<$Res>(_value.extrasSummary, (value) { + return _then(_value.copyWith(extrasSummary: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$OverSummaryImplCopyWith<$Res> + implements $OverSummaryCopyWith<$Res> { + factory _$$OverSummaryImplCopyWith( + _$OverSummaryImpl value, $Res Function(_$OverSummaryImpl) then) = + __$$OverSummaryImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String inning_id, + String team_id, + List balls, + BowlerSummary bowler, + BatsmanSummary striker, + BatsmanSummary nonStriker, + List outPlayers, + int overNumber, + ExtraSummary extrasSummary, + int totalRuns, + int totalWickets}); + + @override + $BowlerSummaryCopyWith<$Res> get bowler; + @override + $BatsmanSummaryCopyWith<$Res> get striker; + @override + $BatsmanSummaryCopyWith<$Res> get nonStriker; + @override + $ExtraSummaryCopyWith<$Res> get extrasSummary; +} + +/// @nodoc +class __$$OverSummaryImplCopyWithImpl<$Res> + extends _$OverSummaryCopyWithImpl<$Res, _$OverSummaryImpl> + implements _$$OverSummaryImplCopyWith<$Res> { + __$$OverSummaryImplCopyWithImpl( + _$OverSummaryImpl _value, $Res Function(_$OverSummaryImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? inning_id = null, + Object? team_id = null, + Object? balls = null, + Object? bowler = null, + Object? striker = null, + Object? nonStriker = null, + Object? outPlayers = null, + Object? overNumber = null, + Object? extrasSummary = null, + Object? totalRuns = null, + Object? totalWickets = null, + }) { + return _then(_$OverSummaryImpl( + inning_id: null == inning_id + ? _value.inning_id + : inning_id // ignore: cast_nullable_to_non_nullable + as String, + team_id: null == team_id + ? _value.team_id + : team_id // ignore: cast_nullable_to_non_nullable + as String, + balls: null == balls + ? _value._balls + : balls // ignore: cast_nullable_to_non_nullable + as List, + bowler: null == bowler + ? _value.bowler + : bowler // ignore: cast_nullable_to_non_nullable + as BowlerSummary, + striker: null == striker + ? _value.striker + : striker // ignore: cast_nullable_to_non_nullable + as BatsmanSummary, + nonStriker: null == nonStriker + ? _value.nonStriker + : nonStriker // ignore: cast_nullable_to_non_nullable + as BatsmanSummary, + outPlayers: null == outPlayers + ? _value._outPlayers + : outPlayers // ignore: cast_nullable_to_non_nullable + as List, + overNumber: null == overNumber + ? _value.overNumber + : overNumber // ignore: cast_nullable_to_non_nullable + as int, + extrasSummary: null == extrasSummary + ? _value.extrasSummary + : extrasSummary // ignore: cast_nullable_to_non_nullable + as ExtraSummary, + totalRuns: null == totalRuns + ? _value.totalRuns + : totalRuns // ignore: cast_nullable_to_non_nullable + as int, + totalWickets: null == totalWickets + ? _value.totalWickets + : totalWickets // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$OverSummaryImpl implements _OverSummary { + const _$OverSummaryImpl( + {this.inning_id = '', + this.team_id = '', + final List balls = const [], + this.bowler = const BowlerSummary(), + this.striker = const BatsmanSummary(), + this.nonStriker = const BatsmanSummary(), + final List outPlayers = const [], + this.overNumber = 0, + this.extrasSummary = const ExtraSummary(), + this.totalRuns = 0, + this.totalWickets = 0}) + : _balls = balls, + _outPlayers = outPlayers; + + @override + @JsonKey() + final String inning_id; + @override + @JsonKey() + final String team_id; + final List _balls; + @override + @JsonKey() + List get balls { + if (_balls is EqualUnmodifiableListView) return _balls; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_balls); + } + + @override + @JsonKey() + final BowlerSummary bowler; + @override + @JsonKey() + final BatsmanSummary striker; + @override + @JsonKey() + final BatsmanSummary nonStriker; + final List _outPlayers; + @override + @JsonKey() + List get outPlayers { + if (_outPlayers is EqualUnmodifiableListView) return _outPlayers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_outPlayers); + } + + @override + @JsonKey() + final int overNumber; + @override + @JsonKey() + final ExtraSummary extrasSummary; + @override + @JsonKey() + final int totalRuns; + @override + @JsonKey() + final int totalWickets; + + @override + String toString() { + return 'OverSummary(inning_id: $inning_id, team_id: $team_id, balls: $balls, bowler: $bowler, striker: $striker, nonStriker: $nonStriker, outPlayers: $outPlayers, overNumber: $overNumber, extrasSummary: $extrasSummary, totalRuns: $totalRuns, totalWickets: $totalWickets)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$OverSummaryImpl && + (identical(other.inning_id, inning_id) || + other.inning_id == inning_id) && + (identical(other.team_id, team_id) || other.team_id == team_id) && + const DeepCollectionEquality().equals(other._balls, _balls) && + (identical(other.bowler, bowler) || other.bowler == bowler) && + (identical(other.striker, striker) || other.striker == striker) && + (identical(other.nonStriker, nonStriker) || + other.nonStriker == nonStriker) && + const DeepCollectionEquality() + .equals(other._outPlayers, _outPlayers) && + (identical(other.overNumber, overNumber) || + other.overNumber == overNumber) && + (identical(other.extrasSummary, extrasSummary) || + other.extrasSummary == extrasSummary) && + (identical(other.totalRuns, totalRuns) || + other.totalRuns == totalRuns) && + (identical(other.totalWickets, totalWickets) || + other.totalWickets == totalWickets)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + inning_id, + team_id, + const DeepCollectionEquality().hash(_balls), + bowler, + striker, + nonStriker, + const DeepCollectionEquality().hash(_outPlayers), + overNumber, + extrasSummary, + totalRuns, + totalWickets); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$OverSummaryImplCopyWith<_$OverSummaryImpl> get copyWith => + __$$OverSummaryImplCopyWithImpl<_$OverSummaryImpl>(this, _$identity); +} + +abstract class _OverSummary implements OverSummary { + const factory _OverSummary( + {final String inning_id, + final String team_id, + final List balls, + final BowlerSummary bowler, + final BatsmanSummary striker, + final BatsmanSummary nonStriker, + final List outPlayers, + final int overNumber, + final ExtraSummary extrasSummary, + final int totalRuns, + final int totalWickets}) = _$OverSummaryImpl; + + @override + String get inning_id; + @override + String get team_id; + @override + List get balls; + @override + BowlerSummary get bowler; + @override + BatsmanSummary get striker; + @override + BatsmanSummary get nonStriker; + @override + List get outPlayers; + @override + int get overNumber; + @override + ExtraSummary get extrasSummary; + @override + int get totalRuns; + @override + int get totalWickets; + @override + @JsonKey(ignore: true) + _$$OverSummaryImplCopyWith<_$OverSummaryImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$BatsmanSummary { + Player get player => throw _privateConstructorUsedError; + Player? get ballBy => throw _privateConstructorUsedError; + Player? get catchBy => throw _privateConstructorUsedError; + WicketType? get wicketType => throw _privateConstructorUsedError; + double? get outAtOver => throw _privateConstructorUsedError; + int get runs => throw _privateConstructorUsedError; + int get ballFaced => throw _privateConstructorUsedError; + int get sixes => throw _privateConstructorUsedError; + int get fours => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $BatsmanSummaryCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $BatsmanSummaryCopyWith<$Res> { + factory $BatsmanSummaryCopyWith( + BatsmanSummary value, $Res Function(BatsmanSummary) then) = + _$BatsmanSummaryCopyWithImpl<$Res, BatsmanSummary>; + @useResult + $Res call( + {Player player, + Player? ballBy, + Player? catchBy, + WicketType? wicketType, + double? outAtOver, + int runs, + int ballFaced, + int sixes, + int fours}); + + $PlayerCopyWith<$Res> get player; + $PlayerCopyWith<$Res>? get ballBy; + $PlayerCopyWith<$Res>? get catchBy; +} + +/// @nodoc +class _$BatsmanSummaryCopyWithImpl<$Res, $Val extends BatsmanSummary> + implements $BatsmanSummaryCopyWith<$Res> { + _$BatsmanSummaryCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? player = null, + Object? ballBy = freezed, + Object? catchBy = freezed, + Object? wicketType = freezed, + Object? outAtOver = freezed, + Object? runs = null, + Object? ballFaced = null, + Object? sixes = null, + Object? fours = null, + }) { + return _then(_value.copyWith( + player: null == player + ? _value.player + : player // ignore: cast_nullable_to_non_nullable + as Player, + ballBy: freezed == ballBy + ? _value.ballBy + : ballBy // ignore: cast_nullable_to_non_nullable + as Player?, + catchBy: freezed == catchBy + ? _value.catchBy + : catchBy // ignore: cast_nullable_to_non_nullable + as Player?, + wicketType: freezed == wicketType + ? _value.wicketType + : wicketType // ignore: cast_nullable_to_non_nullable + as WicketType?, + outAtOver: freezed == outAtOver + ? _value.outAtOver + : outAtOver // ignore: cast_nullable_to_non_nullable + as double?, + runs: null == runs + ? _value.runs + : runs // ignore: cast_nullable_to_non_nullable + as int, + ballFaced: null == ballFaced + ? _value.ballFaced + : ballFaced // ignore: cast_nullable_to_non_nullable + as int, + sixes: null == sixes + ? _value.sixes + : sixes // ignore: cast_nullable_to_non_nullable + as int, + fours: null == fours + ? _value.fours + : fours // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $PlayerCopyWith<$Res> get player { + return $PlayerCopyWith<$Res>(_value.player, (value) { + return _then(_value.copyWith(player: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $PlayerCopyWith<$Res>? get ballBy { + if (_value.ballBy == null) { + return null; + } + + return $PlayerCopyWith<$Res>(_value.ballBy!, (value) { + return _then(_value.copyWith(ballBy: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $PlayerCopyWith<$Res>? get catchBy { + if (_value.catchBy == null) { + return null; + } + + return $PlayerCopyWith<$Res>(_value.catchBy!, (value) { + return _then(_value.copyWith(catchBy: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$BatsmanSummaryImplCopyWith<$Res> + implements $BatsmanSummaryCopyWith<$Res> { + factory _$$BatsmanSummaryImplCopyWith(_$BatsmanSummaryImpl value, + $Res Function(_$BatsmanSummaryImpl) then) = + __$$BatsmanSummaryImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {Player player, + Player? ballBy, + Player? catchBy, + WicketType? wicketType, + double? outAtOver, + int runs, + int ballFaced, + int sixes, + int fours}); + + @override + $PlayerCopyWith<$Res> get player; + @override + $PlayerCopyWith<$Res>? get ballBy; + @override + $PlayerCopyWith<$Res>? get catchBy; +} + +/// @nodoc +class __$$BatsmanSummaryImplCopyWithImpl<$Res> + extends _$BatsmanSummaryCopyWithImpl<$Res, _$BatsmanSummaryImpl> + implements _$$BatsmanSummaryImplCopyWith<$Res> { + __$$BatsmanSummaryImplCopyWithImpl( + _$BatsmanSummaryImpl _value, $Res Function(_$BatsmanSummaryImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? player = null, + Object? ballBy = freezed, + Object? catchBy = freezed, + Object? wicketType = freezed, + Object? outAtOver = freezed, + Object? runs = null, + Object? ballFaced = null, + Object? sixes = null, + Object? fours = null, + }) { + return _then(_$BatsmanSummaryImpl( + player: null == player + ? _value.player + : player // ignore: cast_nullable_to_non_nullable + as Player, + ballBy: freezed == ballBy + ? _value.ballBy + : ballBy // ignore: cast_nullable_to_non_nullable + as Player?, + catchBy: freezed == catchBy + ? _value.catchBy + : catchBy // ignore: cast_nullable_to_non_nullable + as Player?, + wicketType: freezed == wicketType + ? _value.wicketType + : wicketType // ignore: cast_nullable_to_non_nullable + as WicketType?, + outAtOver: freezed == outAtOver + ? _value.outAtOver + : outAtOver // ignore: cast_nullable_to_non_nullable + as double?, + runs: null == runs + ? _value.runs + : runs // ignore: cast_nullable_to_non_nullable + as int, + ballFaced: null == ballFaced + ? _value.ballFaced + : ballFaced // ignore: cast_nullable_to_non_nullable + as int, + sixes: null == sixes + ? _value.sixes + : sixes // ignore: cast_nullable_to_non_nullable + as int, + fours: null == fours + ? _value.fours + : fours // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$BatsmanSummaryImpl implements _BatsmanSummary { + const _$BatsmanSummaryImpl( + {this.player = const Player(), + this.ballBy, + this.catchBy, + this.wicketType, + this.outAtOver, + this.runs = 0, + this.ballFaced = 0, + this.sixes = 0, + this.fours = 0}); + + @override + @JsonKey() + final Player player; + @override + final Player? ballBy; + @override + final Player? catchBy; + @override + final WicketType? wicketType; + @override + final double? outAtOver; + @override + @JsonKey() + final int runs; + @override + @JsonKey() + final int ballFaced; + @override + @JsonKey() + final int sixes; + @override + @JsonKey() + final int fours; + + @override + String toString() { + return 'BatsmanSummary(player: $player, ballBy: $ballBy, catchBy: $catchBy, wicketType: $wicketType, outAtOver: $outAtOver, runs: $runs, ballFaced: $ballFaced, sixes: $sixes, fours: $fours)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BatsmanSummaryImpl && + (identical(other.player, player) || other.player == player) && + (identical(other.ballBy, ballBy) || other.ballBy == ballBy) && + (identical(other.catchBy, catchBy) || other.catchBy == catchBy) && + (identical(other.wicketType, wicketType) || + other.wicketType == wicketType) && + (identical(other.outAtOver, outAtOver) || + other.outAtOver == outAtOver) && + (identical(other.runs, runs) || other.runs == runs) && + (identical(other.ballFaced, ballFaced) || + other.ballFaced == ballFaced) && + (identical(other.sixes, sixes) || other.sixes == sixes) && + (identical(other.fours, fours) || other.fours == fours)); + } + + @override + int get hashCode => Object.hash(runtimeType, player, ballBy, catchBy, + wicketType, outAtOver, runs, ballFaced, sixes, fours); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$BatsmanSummaryImplCopyWith<_$BatsmanSummaryImpl> get copyWith => + __$$BatsmanSummaryImplCopyWithImpl<_$BatsmanSummaryImpl>( + this, _$identity); +} + +abstract class _BatsmanSummary implements BatsmanSummary { + const factory _BatsmanSummary( + {final Player player, + final Player? ballBy, + final Player? catchBy, + final WicketType? wicketType, + final double? outAtOver, + final int runs, + final int ballFaced, + final int sixes, + final int fours}) = _$BatsmanSummaryImpl; + + @override + Player get player; + @override + Player? get ballBy; + @override + Player? get catchBy; + @override + WicketType? get wicketType; + @override + double? get outAtOver; + @override + int get runs; + @override + int get ballFaced; + @override + int get sixes; + @override + int get fours; + @override + @JsonKey(ignore: true) + _$$BatsmanSummaryImplCopyWith<_$BatsmanSummaryImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$BowlerSummary { + Player get player => throw _privateConstructorUsedError; + int get runsConceded => throw _privateConstructorUsedError; + int get maiden => throw _privateConstructorUsedError; + double get overDelivered => throw _privateConstructorUsedError; + int get wicket => throw _privateConstructorUsedError; + int get noBalls => throw _privateConstructorUsedError; + int get wideBalls => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $BowlerSummaryCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $BowlerSummaryCopyWith<$Res> { + factory $BowlerSummaryCopyWith( + BowlerSummary value, $Res Function(BowlerSummary) then) = + _$BowlerSummaryCopyWithImpl<$Res, BowlerSummary>; + @useResult + $Res call( + {Player player, + int runsConceded, + int maiden, + double overDelivered, + int wicket, + int noBalls, + int wideBalls}); + + $PlayerCopyWith<$Res> get player; +} + +/// @nodoc +class _$BowlerSummaryCopyWithImpl<$Res, $Val extends BowlerSummary> + implements $BowlerSummaryCopyWith<$Res> { + _$BowlerSummaryCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? player = null, + Object? runsConceded = null, + Object? maiden = null, + Object? overDelivered = null, + Object? wicket = null, + Object? noBalls = null, + Object? wideBalls = null, + }) { + return _then(_value.copyWith( + player: null == player + ? _value.player + : player // ignore: cast_nullable_to_non_nullable + as Player, + runsConceded: null == runsConceded + ? _value.runsConceded + : runsConceded // ignore: cast_nullable_to_non_nullable + as int, + maiden: null == maiden + ? _value.maiden + : maiden // ignore: cast_nullable_to_non_nullable + as int, + overDelivered: null == overDelivered + ? _value.overDelivered + : overDelivered // ignore: cast_nullable_to_non_nullable + as double, + wicket: null == wicket + ? _value.wicket + : wicket // ignore: cast_nullable_to_non_nullable + as int, + noBalls: null == noBalls + ? _value.noBalls + : noBalls // ignore: cast_nullable_to_non_nullable + as int, + wideBalls: null == wideBalls + ? _value.wideBalls + : wideBalls // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $PlayerCopyWith<$Res> get player { + return $PlayerCopyWith<$Res>(_value.player, (value) { + return _then(_value.copyWith(player: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$BowlerSummaryImplCopyWith<$Res> + implements $BowlerSummaryCopyWith<$Res> { + factory _$$BowlerSummaryImplCopyWith( + _$BowlerSummaryImpl value, $Res Function(_$BowlerSummaryImpl) then) = + __$$BowlerSummaryImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {Player player, + int runsConceded, + int maiden, + double overDelivered, + int wicket, + int noBalls, + int wideBalls}); + + @override + $PlayerCopyWith<$Res> get player; +} + +/// @nodoc +class __$$BowlerSummaryImplCopyWithImpl<$Res> + extends _$BowlerSummaryCopyWithImpl<$Res, _$BowlerSummaryImpl> + implements _$$BowlerSummaryImplCopyWith<$Res> { + __$$BowlerSummaryImplCopyWithImpl( + _$BowlerSummaryImpl _value, $Res Function(_$BowlerSummaryImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? player = null, + Object? runsConceded = null, + Object? maiden = null, + Object? overDelivered = null, + Object? wicket = null, + Object? noBalls = null, + Object? wideBalls = null, + }) { + return _then(_$BowlerSummaryImpl( + player: null == player + ? _value.player + : player // ignore: cast_nullable_to_non_nullable + as Player, + runsConceded: null == runsConceded + ? _value.runsConceded + : runsConceded // ignore: cast_nullable_to_non_nullable + as int, + maiden: null == maiden + ? _value.maiden + : maiden // ignore: cast_nullable_to_non_nullable + as int, + overDelivered: null == overDelivered + ? _value.overDelivered + : overDelivered // ignore: cast_nullable_to_non_nullable + as double, + wicket: null == wicket + ? _value.wicket + : wicket // ignore: cast_nullable_to_non_nullable + as int, + noBalls: null == noBalls + ? _value.noBalls + : noBalls // ignore: cast_nullable_to_non_nullable + as int, + wideBalls: null == wideBalls + ? _value.wideBalls + : wideBalls // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$BowlerSummaryImpl implements _BowlerSummary { + const _$BowlerSummaryImpl( + {this.player = const Player(), + this.runsConceded = 0, + this.maiden = 0, + this.overDelivered = 0, + this.wicket = 0, + this.noBalls = 0, + this.wideBalls = 0}); + + @override + @JsonKey() + final Player player; + @override + @JsonKey() + final int runsConceded; + @override + @JsonKey() + final int maiden; + @override + @JsonKey() + final double overDelivered; + @override + @JsonKey() + final int wicket; + @override + @JsonKey() + final int noBalls; + @override + @JsonKey() + final int wideBalls; + + @override + String toString() { + return 'BowlerSummary(player: $player, runsConceded: $runsConceded, maiden: $maiden, overDelivered: $overDelivered, wicket: $wicket, noBalls: $noBalls, wideBalls: $wideBalls)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BowlerSummaryImpl && + (identical(other.player, player) || other.player == player) && + (identical(other.runsConceded, runsConceded) || + other.runsConceded == runsConceded) && + (identical(other.maiden, maiden) || other.maiden == maiden) && + (identical(other.overDelivered, overDelivered) || + other.overDelivered == overDelivered) && + (identical(other.wicket, wicket) || other.wicket == wicket) && + (identical(other.noBalls, noBalls) || other.noBalls == noBalls) && + (identical(other.wideBalls, wideBalls) || + other.wideBalls == wideBalls)); + } + + @override + int get hashCode => Object.hash(runtimeType, player, runsConceded, maiden, + overDelivered, wicket, noBalls, wideBalls); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$BowlerSummaryImplCopyWith<_$BowlerSummaryImpl> get copyWith => + __$$BowlerSummaryImplCopyWithImpl<_$BowlerSummaryImpl>(this, _$identity); +} + +abstract class _BowlerSummary implements BowlerSummary { + const factory _BowlerSummary( + {final Player player, + final int runsConceded, + final int maiden, + final double overDelivered, + final int wicket, + final int noBalls, + final int wideBalls}) = _$BowlerSummaryImpl; + + @override + Player get player; + @override + int get runsConceded; + @override + int get maiden; + @override + double get overDelivered; + @override + int get wicket; + @override + int get noBalls; + @override + int get wideBalls; + @override + @JsonKey(ignore: true) + _$$BowlerSummaryImplCopyWith<_$BowlerSummaryImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$Player { + String get id => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $PlayerCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PlayerCopyWith<$Res> { + factory $PlayerCopyWith(Player value, $Res Function(Player) then) = + _$PlayerCopyWithImpl<$Res, Player>; + @useResult + $Res call({String id, String name}); +} + +/// @nodoc +class _$PlayerCopyWithImpl<$Res, $Val extends Player> + implements $PlayerCopyWith<$Res> { + _$PlayerCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$PlayerImplCopyWith<$Res> implements $PlayerCopyWith<$Res> { + factory _$$PlayerImplCopyWith( + _$PlayerImpl value, $Res Function(_$PlayerImpl) then) = + __$$PlayerImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String id, String name}); +} + +/// @nodoc +class __$$PlayerImplCopyWithImpl<$Res> + extends _$PlayerCopyWithImpl<$Res, _$PlayerImpl> + implements _$$PlayerImplCopyWith<$Res> { + __$$PlayerImplCopyWithImpl( + _$PlayerImpl _value, $Res Function(_$PlayerImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + }) { + return _then(_$PlayerImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$PlayerImpl implements _Player { + const _$PlayerImpl({this.id = "", this.name = ""}); + + @override + @JsonKey() + final String id; + @override + @JsonKey() + final String name; + + @override + String toString() { + return 'Player(id: $id, name: $name)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PlayerImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.name, name) || other.name == name)); + } + + @override + int get hashCode => Object.hash(runtimeType, id, name); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PlayerImplCopyWith<_$PlayerImpl> get copyWith => + __$$PlayerImplCopyWithImpl<_$PlayerImpl>(this, _$identity); +} + +abstract class _Player implements Player { + const factory _Player({final String id, final String name}) = _$PlayerImpl; + + @override + String get id; + @override + String get name; + @override + @JsonKey(ignore: true) + _$$PlayerImplCopyWith<_$PlayerImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$ExtraSummary { + int get bye => throw _privateConstructorUsedError; + int get legBye => throw _privateConstructorUsedError; + int get noBall => throw _privateConstructorUsedError; + int get wideBall => throw _privateConstructorUsedError; + int get penalty => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ExtraSummaryCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ExtraSummaryCopyWith<$Res> { + factory $ExtraSummaryCopyWith( + ExtraSummary value, $Res Function(ExtraSummary) then) = + _$ExtraSummaryCopyWithImpl<$Res, ExtraSummary>; + @useResult + $Res call({int bye, int legBye, int noBall, int wideBall, int penalty}); +} + +/// @nodoc +class _$ExtraSummaryCopyWithImpl<$Res, $Val extends ExtraSummary> + implements $ExtraSummaryCopyWith<$Res> { + _$ExtraSummaryCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? bye = null, + Object? legBye = null, + Object? noBall = null, + Object? wideBall = null, + Object? penalty = null, + }) { + return _then(_value.copyWith( + bye: null == bye + ? _value.bye + : bye // ignore: cast_nullable_to_non_nullable + as int, + legBye: null == legBye + ? _value.legBye + : legBye // ignore: cast_nullable_to_non_nullable + as int, + noBall: null == noBall + ? _value.noBall + : noBall // ignore: cast_nullable_to_non_nullable + as int, + wideBall: null == wideBall + ? _value.wideBall + : wideBall // ignore: cast_nullable_to_non_nullable + as int, + penalty: null == penalty + ? _value.penalty + : penalty // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ExtraSummaryImplCopyWith<$Res> + implements $ExtraSummaryCopyWith<$Res> { + factory _$$ExtraSummaryImplCopyWith( + _$ExtraSummaryImpl value, $Res Function(_$ExtraSummaryImpl) then) = + __$$ExtraSummaryImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({int bye, int legBye, int noBall, int wideBall, int penalty}); +} + +/// @nodoc +class __$$ExtraSummaryImplCopyWithImpl<$Res> + extends _$ExtraSummaryCopyWithImpl<$Res, _$ExtraSummaryImpl> + implements _$$ExtraSummaryImplCopyWith<$Res> { + __$$ExtraSummaryImplCopyWithImpl( + _$ExtraSummaryImpl _value, $Res Function(_$ExtraSummaryImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? bye = null, + Object? legBye = null, + Object? noBall = null, + Object? wideBall = null, + Object? penalty = null, + }) { + return _then(_$ExtraSummaryImpl( + bye: null == bye + ? _value.bye + : bye // ignore: cast_nullable_to_non_nullable + as int, + legBye: null == legBye + ? _value.legBye + : legBye // ignore: cast_nullable_to_non_nullable + as int, + noBall: null == noBall + ? _value.noBall + : noBall // ignore: cast_nullable_to_non_nullable + as int, + wideBall: null == wideBall + ? _value.wideBall + : wideBall // ignore: cast_nullable_to_non_nullable + as int, + penalty: null == penalty + ? _value.penalty + : penalty // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$ExtraSummaryImpl implements _ExtraSummary { + const _$ExtraSummaryImpl( + {this.bye = 0, + this.legBye = 0, + this.noBall = 0, + this.wideBall = 0, + this.penalty = 0}); + + @override + @JsonKey() + final int bye; + @override + @JsonKey() + final int legBye; + @override + @JsonKey() + final int noBall; + @override + @JsonKey() + final int wideBall; + @override + @JsonKey() + final int penalty; + + @override + String toString() { + return 'ExtraSummary(bye: $bye, legBye: $legBye, noBall: $noBall, wideBall: $wideBall, penalty: $penalty)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ExtraSummaryImpl && + (identical(other.bye, bye) || other.bye == bye) && + (identical(other.legBye, legBye) || other.legBye == legBye) && + (identical(other.noBall, noBall) || other.noBall == noBall) && + (identical(other.wideBall, wideBall) || + other.wideBall == wideBall) && + (identical(other.penalty, penalty) || other.penalty == penalty)); + } + + @override + int get hashCode => + Object.hash(runtimeType, bye, legBye, noBall, wideBall, penalty); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ExtraSummaryImplCopyWith<_$ExtraSummaryImpl> get copyWith => + __$$ExtraSummaryImplCopyWithImpl<_$ExtraSummaryImpl>(this, _$identity); +} + +abstract class _ExtraSummary implements ExtraSummary { + const factory _ExtraSummary( + {final int bye, + final int legBye, + final int noBall, + final int wideBall, + final int penalty}) = _$ExtraSummaryImpl; + + @override + int get bye; + @override + int get legBye; + @override + int get noBall; + @override + int get wideBall; + @override + int get penalty; + @override + @JsonKey(ignore: true) + _$$ExtraSummaryImplCopyWith<_$ExtraSummaryImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/data/lib/api/innings/inning_model.dart b/data/lib/api/innings/inning_model.dart index 4807784a..707639be 100644 --- a/data/lib/api/innings/inning_model.dart +++ b/data/lib/api/innings/inning_model.dart @@ -31,4 +31,4 @@ enum InningStatus { final int value; const InningStatus(this.value); -} \ No newline at end of file +} diff --git a/data/lib/api/innings/inning_model.g.dart b/data/lib/api/innings/inning_model.g.dart index 174bc158..7048effc 100644 --- a/data/lib/api/innings/inning_model.g.dart +++ b/data/lib/api/innings/inning_model.g.dart @@ -12,8 +12,8 @@ _$InningModelImpl _$$InningModelImplFromJson(Map json) => match_id: json['match_id'] as String, team_id: json['team_id'] as String, overs: (json['overs'] as num?)?.toDouble() ?? 0, - total_runs: (json['total_runs'] as num?)?.toInt() ?? 0, - total_wickets: (json['total_wickets'] as num?)?.toInt() ?? 0, + total_runs: json['total_runs'] as int? ?? 0, + total_wickets: json['total_wickets'] as int? ?? 0, innings_status: $enumDecodeNullable(_$InningStatusEnumMap, json['innings_status']), ); diff --git a/data/lib/api/match/match_model.dart b/data/lib/api/match/match_model.dart index 34e8c7d3..a76e825c 100644 --- a/data/lib/api/match/match_model.dart +++ b/data/lib/api/match/match_model.dart @@ -55,6 +55,71 @@ class MatchTeamModel with _$MatchTeamModel { _$MatchTeamModelFromJson(json); } +extension DataMatchModel on MatchModel { + MatchResult? get matchResult { + if (match_status != MatchStatus.finish) { + return null; + } + + final firstTeam = toss_decision == TossDecision.bat + ? teams.firstWhere((element) => element.team.id == toss_winner_id) + : teams.firstWhere((element) => element.team.id != toss_winner_id); + final secondTeam = + teams.firstWhere((element) => element.team.id != firstTeam.team.id); + + if (firstTeam.run > secondTeam.run) { + // first batting team won + final teamName = firstTeam.team.name; + + final runDifference = firstTeam.run - secondTeam.run; + return MatchResult( + teamId: firstTeam.team.id ?? "", + teamName: teamName, + difference: runDifference, + winType: WinnerByType.run); + } else if (firstTeam.run == secondTeam.run) { + return MatchResult( + teamId: "", + teamName: "", + difference: 0, + winType: WinnerByType.tie, + ); + } else { + // second batting team won + final teamName = secondTeam.team.name; + + final wicketDifference = secondTeam.squad.length - firstTeam.wicket; + + return MatchResult( + teamId: secondTeam.team.id ?? "", + teamName: teamName, + difference: wicketDifference, + winType: WinnerByType.wicket, + ); + } + } +} + +enum WinnerByType { + run, + wicket, + tie; +} + +class MatchResult { + String teamId; + int difference; + String teamName; + WinnerByType winType; + + MatchResult({ + required this.teamId, + required this.teamName, + required this.difference, + required this.winType, + }); +} + @freezed class MatchPlayer with _$MatchPlayer { const factory MatchPlayer({ diff --git a/data/lib/api/network/client.dart b/data/lib/api/network/client.dart index 4bb393d9..b745a41b 100644 --- a/data/lib/api/network/client.dart +++ b/data/lib/api/network/client.dart @@ -6,4 +6,4 @@ final rawDioProvider = Provider((ref) { ..options.connectTimeout = const Duration(seconds: 30) ..options.sendTimeout = const Duration(seconds: 30) ..options.receiveTimeout = const Duration(seconds: 30); -}); \ No newline at end of file +}); diff --git a/data/lib/extensions/double_extensions.dart b/data/lib/extensions/double_extensions.dart new file mode 100644 index 00000000..0feef681 --- /dev/null +++ b/data/lib/extensions/double_extensions.dart @@ -0,0 +1,34 @@ +import 'package:data/extensions/int_extensions.dart'; + +extension OverExtensionOnDouble on double { + double add(int ballsToAdd) { + int totalBalls = toBalls() + ballsToAdd; + return totalBalls.toOvers(); + } + + double remove(int ballsToRemove) { + int totalBalls = toBalls() - ballsToRemove; + if (totalBalls < 0) totalBalls = 0; + return totalBalls.toOvers(); + } + + int getBallNumberFromOver() { + String valueString = toString(); + + List parts = valueString.split('.'); + + if (parts.length > 1) { + return int.parse(parts[1]); + } else { + return 0; + } + } + + int getOverNumberFromOver() { + return toInt(); + } + + int toBalls() { + return (getOverNumberFromOver() * 6) + getBallNumberFromOver(); + } +} diff --git a/data/lib/extensions/int_extensions.dart b/data/lib/extensions/int_extensions.dart new file mode 100644 index 00000000..f81a4c29 --- /dev/null +++ b/data/lib/extensions/int_extensions.dart @@ -0,0 +1,7 @@ +extension OverExtensionOnInt on int { + double toOvers() { + int overs = this ~/ 6; + int additionalBalls = this % 6; + return double.parse("$overs.$additionalBalls"); + } +} diff --git a/data/lib/extensions/list_extensions.dart b/data/lib/extensions/list_extensions.dart index a90c883e..843e9214 100644 --- a/data/lib/extensions/list_extensions.dart +++ b/data/lib/extensions/list_extensions.dart @@ -25,4 +25,4 @@ extension ChunkedList on List { return sublist(start, start + size < length ? start + size : length); }); } -} \ No newline at end of file +} diff --git a/data/lib/service/ball_score/ball_score_service.dart b/data/lib/service/ball_score/ball_score_service.dart index 3a418b29..c8c7cbbf 100644 --- a/data/lib/service/ball_score/ball_score_service.dart +++ b/data/lib/service/ball_score/ball_score_service.dart @@ -201,4 +201,4 @@ class BallScoreChange { final BallScoreModel ballScore; BallScoreChange(this.type, this.ballScore); -} \ No newline at end of file +} diff --git a/data/lib/service/user/user_service.dart b/data/lib/service/user/user_service.dart index 6d01aed8..a1a2b72f 100644 --- a/data/lib/service/user/user_service.dart +++ b/data/lib/service/user/user_service.dart @@ -101,7 +101,8 @@ class UserService { .collection(FireStoreConst.usersCollection) .where(FireStoreConst.nameLowercase, isGreaterThanOrEqualTo: searchKey.toLowerCase()) - .where(FireStoreConst.nameLowercase, isLessThan: '${searchKey.toLowerCase()}z') + .where(FireStoreConst.nameLowercase, + isLessThan: '${searchKey.toLowerCase()}z') .get(); return snapshot.docs.map((doc) { diff --git a/data/lib/storage/app_preferences.dart b/data/lib/storage/app_preferences.dart index b4b5a78c..f204a10e 100644 --- a/data/lib/storage/app_preferences.dart +++ b/data/lib/storage/app_preferences.dart @@ -13,6 +13,5 @@ final currentUserPod = Provider((ref) { return json == null ? null : UserModel.fromJsonString(json); }); -final hasUserSession = Provider((ref) => ref.watch(currentUserPod) != null); - - +final hasUserSession = + Provider((ref) => ref.watch(currentUserPod) != null); diff --git a/data/lib/storage/provider/preferences_provider.dart b/data/lib/storage/provider/preferences_provider.dart index 5805f794..350b02be 100644 --- a/data/lib/storage/provider/preferences_provider.dart +++ b/data/lib/storage/provider/preferences_provider.dart @@ -1,7 +1,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; -final sharedPreferencesProvider = Provider((ref) => throw UnimplementedError()); +final sharedPreferencesProvider = + Provider((ref) => throw UnimplementedError()); StateProvider createPrefProvider({ required String prefKey, diff --git a/data/lib/utils/constant/firebase_error_constant.dart b/data/lib/utils/constant/firebase_error_constant.dart index bd99c7d4..dba2dcb9 100644 --- a/data/lib/utils/constant/firebase_error_constant.dart +++ b/data/lib/utils/constant/firebase_error_constant.dart @@ -5,4 +5,4 @@ const String errorInvalidPhoneNumber = "invalid-phone-number"; const String errorNetworkRequestFailed = "network-request-failed"; const String errorUserNotFound = "user-not-found"; const String errorUnauthenticated = "unauthenticated"; -const String errorTooManyRequest = "too-many-requests"; \ No newline at end of file +const String errorTooManyRequest = "too-many-requests"; diff --git a/data/lib/utils/constant/firestore_constant.dart b/data/lib/utils/constant/firestore_constant.dart index 83e08da0..9b371658 100644 --- a/data/lib/utils/constant/firestore_constant.dart +++ b/data/lib/utils/constant/firestore_constant.dart @@ -39,4 +39,4 @@ class FireStoreConst { static const String players = "players"; static const String createdBy = "created_by"; static const String nameLowercase = "name_lowercase"; -} \ No newline at end of file +} diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index ef83fe55..614098ec 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -17,8 +17,19 @@ "common_no_title": "No", "common_retry_title": "Retry", "common_not_specified_title": "Not Specified", - "common_runs_dot_title": " Runs.", - "common_wickets_dot_title": " Wickets.", + "common_runs_title": "{count, plural, =0{{count} runs} =1{{count} run} other{{count} runs}}", + "@common_runs_title": { + "placeholders": { + "count": {} + } + }, + "common_wickets_title": "{count, plural, =0{{count} wickets} =1{{count} wicket} other{{count} wickets}}", + "@common_wickets_title": { + "placeholders": { + "count": {} + } + }, + "common_tie_title": "Tie", "common_wicket_taken_title": " Wicket taken", "common_matches_title": "Matches", "common_edit_team_title": "Edit Team", @@ -276,28 +287,29 @@ "match_detail_commentary_tab_title": "Commentary", "match_detail_scorecard_tab_title": "Scorecard", "match_detail_squad_tab_title": "Squad", - "match_detail_match_info_tab_title": "Match Info", + "match_detail_match_info_tab_title": "Info", "match_detail_highlight_tab_title": "Highlight", + "match_detail_overs_tab_title": "Overs", - "match_info_match_title": "Match:", - "match_info_date_title": "Date:", - "match_info_toss_title": "Toss:", - "match_info_time_title": "Time:", - "match_info_umpire_title": "Umpire:", - "match_info_referee_title": "Referee:", - "match_info_squad_title": "{name} Squad:", + "match_info_match_title": "Match", + "match_info_date_title": "Date", + "match_info_toss_title": "Toss", + "match_info_time_title": "Time", + "match_info_umpire_title": "Umpire", + "match_info_referee_title": "Referee", + "match_info_date_and_time_title": "Date & Time", + "match_info_squad_title": "{name} Squad", "@match_info_squad_title": { - "description": "{name} Squad:", + "description": "{name} Squad", "placeholders": { "name": { "type": "String" } } }, - "match_info_playing_title": "Playing:", - "match_info_bench_title": "Bench:", "match_info_venue_title": "Venue", - "match_info_ground_title": "Ground:", + "match_info_ground_title": "Ground", + "match_info_city_title": "City", "match_info_captain_short_title": "(c)", "match_info_toss_detail_text": "{name} won the toss and opt to {decision}", "@match_info_toss_detail_text": { @@ -394,6 +406,15 @@ "match_commentary_end_inning_text_part_1": " wraps up their innings, leaving ", "match_commentary_end_inning_text_part_2": " for victory.", "match_commentary_empty_commentary_text": "Commentary will be shown here as soon as the match starts.", + "match_commentary_inning_count_text": "Inning {count}", + "@match_commentary_inning_count_text": { + "description": "Inning {count}", + "placeholders": { + "count": { + "type": "int" + } + } + }, "match_scorecard_fall_of_wicket_text": "Fall of Wicket", "match_scorecard_over_text": "Over", @@ -413,8 +434,8 @@ "match_scorecard_batter_text": "Batter", "match_scorecard_bowler_text": "Bowler", "match_scorecard_not_out_text": "Not out", - "match_scorecard_bowler_catcher_short_text": "b {bowler} c {fielder}", "match_scorecard_did_not_bat_text": "Did not bat", + "match_scorecard_bowler_catcher_short_text": "b {bowler} c {fielder}", "@match_scorecard_bowler_catcher_short_text": { "description": "b {bowler} c {fielder}", "placeholders": { @@ -471,7 +492,8 @@ } }, - "match_squad_bench_text": "Bench", + "match_squad_playing_title": "Playing", + "match_squad_bench_title": "Bench", "match_highlight_filter_all_text": "All", "match_highlight_filter_fours_text": "Fours", "match_highlight_filter_sixes_text": "Sixes", diff --git a/khelo/lib/components/app_page.dart b/khelo/lib/components/app_page.dart index e639b65a..a4b3d72d 100644 --- a/khelo/lib/components/app_page.dart +++ b/khelo/lib/components/app_page.dart @@ -7,7 +7,6 @@ import 'package:style/text/app_text_style.dart'; class AppPage extends StatelessWidget { final String? title; final Widget? titleWidget; - final TabBar? tabBar; final List? actions; final Widget? leading; final Widget? floatingActionButton; @@ -20,7 +19,6 @@ class AppPage extends StatelessWidget { super.key, this.title, this.titleWidget, - this.tabBar, this.actions, this.leading, this.body, @@ -66,15 +64,7 @@ class AppPage extends StatelessWidget { child: Stack( alignment: Alignment.bottomRight, children: [ - Column( - children: [ - Material( - type: MaterialType.transparency, - child: tabBar, - ), - Flexible(child: body ?? const SizedBox()), - ], - ), + body ?? const SizedBox(), SafeArea( child: Padding( padding: const EdgeInsets.only(right: 16, bottom: 16), diff --git a/khelo/lib/components/image_avatar.dart b/khelo/lib/components/image_avatar.dart index 7d1e7c3c..c888f027 100644 --- a/khelo/lib/components/image_avatar.dart +++ b/khelo/lib/components/image_avatar.dart @@ -1,5 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:style/extensions/context_extensions.dart'; import 'package:style/text/app_text_style.dart'; @@ -21,27 +22,42 @@ class ImageAvatar extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - height: size, - width: size, - alignment: Alignment.center, - decoration: BoxDecoration( + return MediaQuery.withNoTextScaling( + child: Container( + height: size, + width: size, + alignment: Alignment.center, + decoration: BoxDecoration( shape: BoxShape.circle, color: backgroundColor ?? context.colorScheme.containerHigh, - border: Border.all(color: context.colorScheme.textDisabled), - image: (imageUrl != null) - ? DecorationImage( - fit: BoxFit.cover, - image: CachedNetworkImageProvider(imageUrl!)) - : null), - child: imageUrl == null - ? Text( - initial, - style: AppTextStyle.header2.copyWith( - color: foregroundColor ?? context.colorScheme.secondary, + ), + child: imageUrl == null + ? _initialView(context) + : CachedNetworkImage( + imageUrl: imageUrl!, + fit: BoxFit.cover, + errorWidget: (context, url, error) => _initialView(context), + placeholder: (context, url) => _initialView(context), + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), + ), ), - ) - : null, + ), + ); + } + + Widget _initialView(BuildContext context) { + return Text( + initial, + style: AppTextStyle.subtitle1.copyWith( + color: foregroundColor ?? context.colorScheme.textPrimary, + fontSize: size / 2.15), ); } } diff --git a/khelo/lib/components/match_detail_cell.dart b/khelo/lib/components/match_detail_cell.dart index f7184e56..3ca80586 100644 --- a/khelo/lib/components/match_detail_cell.dart +++ b/khelo/lib/components/match_detail_cell.dart @@ -5,7 +5,6 @@ import 'package:khelo/components/image_avatar.dart'; import 'package:khelo/components/match_status_tag.dart'; import 'package:khelo/components/won_by_message_text.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; -import 'package:khelo/domain/extensions/data_model_extensions/match_model_extension.dart'; import 'package:khelo/domain/extensions/enum_extensions.dart'; import 'package:khelo/domain/formatter/date_formatter.dart'; import 'package:khelo/gen/assets.gen.dart'; @@ -150,19 +149,9 @@ class MatchDetailCell extends StatelessWidget { } Widget _winnerMessageText(BuildContext context) { - final winSummary = match.getWinnerSummary(context); - if (match.match_status == MatchStatus.finish && winSummary != null) { - if (winSummary.teamName.isEmpty) { - return Text( - context.l10n.score_board_match_tied_text, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - ); - } + if (match.match_status == MatchStatus.finish) { return WonByMessageText( - teamName: winSummary.teamName, - difference: winSummary.difference, - trailingText: winSummary.wonByText, + matchResult: match.matchResult, ); } else { return Text( diff --git a/khelo/lib/components/profile_image_avatar.dart b/khelo/lib/components/profile_image_avatar.dart index bd12079d..4385a2ba 100644 --- a/khelo/lib/components/profile_image_avatar.dart +++ b/khelo/lib/components/profile_image_avatar.dart @@ -1,5 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:khelo/gen/assets.gen.dart'; import 'package:style/animations/on_tap_scale.dart'; @@ -44,33 +45,46 @@ class ProfileImageAvatar extends StatelessWidget { width: size, alignment: Alignment.center, decoration: BoxDecoration( - shape: BoxShape.circle, - image: imageUrl != null && !isLoading - ? DecorationImage( - image: CachedNetworkImageProvider(imageUrl!), - fit: BoxFit.cover) - : null, - color: context.colorScheme.primary), - child: _imagePlaceHolder(context), + shape: BoxShape.circle, color: context.colorScheme.primary), + child: (imageUrl != null && !isLoading) + ? CachedNetworkImage( + imageUrl: imageUrl!, + fit: BoxFit.cover, + errorWidget: (context, url, error) => _placeHolderIcon(context), + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), + ), + ) + : _imagePlaceHolder(context), ); } Widget? _imagePlaceHolder(BuildContext context) { return imageUrl == null && !isLoading - ? SvgPicture.asset( - placeHolderImage ?? Assets.images.icProfileThin, - height: size / 2, - width: size / 2, - colorFilter: ColorFilter.mode( - context.colorScheme.textInversePrimary, - BlendMode.srcATop, - ), - ) + ? _placeHolderIcon(context) : isLoading ? AppProgressIndicator(color: context.colorScheme.surface) : null; } + Widget _placeHolderIcon(BuildContext context) { + return SvgPicture.asset( + placeHolderImage ?? Assets.images.icProfileThin, + height: size / 2, + width: size / 2, + colorFilter: ColorFilter.mode( + context.colorScheme.textInversePrimary, + BlendMode.srcATop, + ), + ); + } + Widget _editImageButton( BuildContext context, { required Function() onTap, diff --git a/khelo/lib/components/won_by_message_text.dart b/khelo/lib/components/won_by_message_text.dart index 72614fae..b65b1041 100644 --- a/khelo/lib/components/won_by_message_text.dart +++ b/khelo/lib/components/won_by_message_text.dart @@ -1,36 +1,45 @@ +import 'package:data/api/match/match_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/enum_extensions.dart'; import 'package:style/extensions/context_extensions.dart'; import 'package:style/text/app_text_style.dart'; class WonByMessageText extends StatelessWidget { - final String teamName; - final int difference; - final String trailingText; + final MatchResult? matchResult; + final TextStyle? textStyle; const WonByMessageText({ super.key, - required this.teamName, - required this.difference, - required this.trailingText, + this.matchResult, + this.textStyle, }); @override Widget build(BuildContext context) { + if (matchResult == null) { + return const SizedBox(); + } + if (matchResult!.winType == WinnerByType.tie) { + return Text(context.l10n.score_board_match_tied_text, + style: textStyle ?? + AppTextStyle.subtitle1 + .copyWith(color: context.colorScheme.textPrimary)); + } return Text.rich(TextSpan( - text: teamName, - style: AppTextStyle.subtitle2 - .copyWith(color: context.colorScheme.textPrimary), + text: matchResult!.teamName, + style: textStyle ?? + AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), children: [ TextSpan( text: context.l10n.score_board_won_by_title, - style: AppTextStyle.subtitle2 - .copyWith(color: context.colorScheme.textSecondary)), + style: textStyle ?? + AppTextStyle.body2 + .copyWith(color: context.colorScheme.textDisabled)), TextSpan( - text: "$difference", - ), - TextSpan( - text: trailingText, + text: matchResult!.winType + .getString(context, matchResult!.difference), ), ])); } diff --git a/khelo/lib/domain/extensions/data_model_extensions/ball_score_model_extension.dart b/khelo/lib/domain/extensions/data_model_extensions/ball_score_model_extension.dart index 63ae8302..977362be 100644 --- a/khelo/lib/domain/extensions/data_model_extensions/ball_score_model_extension.dart +++ b/khelo/lib/domain/extensions/data_model_extensions/ball_score_model_extension.dart @@ -1,19 +1,5 @@ import 'package:data/api/ball_score/ball_score_model.dart'; -extension BallScoreModelBoolean on BallScoreModel? { - bool? isLegalDelivery() { - if (this == null) { - return null; - } - return this!.extras_type != ExtrasType.penaltyRun && - this!.extras_type != ExtrasType.noBall && - this!.extras_type != ExtrasType.wide && - this!.wicket_type != WicketType.timedOut && - this!.wicket_type != WicketType.retired && - this!.wicket_type != WicketType.retiredHurt; - } -} - extension BallScoreModelList on List { List> chunkArrayByOver() { var groupedMap = groupBy(this, (BallScoreModel bs) => bs.over_number); diff --git a/khelo/lib/domain/extensions/data_model_extensions/match_model_extension.dart b/khelo/lib/domain/extensions/data_model_extensions/match_model_extension.dart deleted file mode 100644 index 41abf0f6..00000000 --- a/khelo/lib/domain/extensions/data_model_extensions/match_model_extension.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:data/api/match/match_model.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:khelo/domain/extensions/context_extensions.dart'; - -extension MatchModelString on MatchModel { - ({String teamName, int difference, String wonByText})? getWinnerSummary( - BuildContext context) { - if (match_status != MatchStatus.finish) { - return null; - } - - final firstTeam = toss_decision == TossDecision.bat - ? teams.firstWhere((element) => element.team.id == toss_winner_id) - : teams.firstWhere((element) => element.team.id != toss_winner_id); - final secondTeam = - teams.firstWhere((element) => element.team.id != firstTeam.team.id); - - if (firstTeam.run > secondTeam.run) { - // first batting team won - final teamName = firstTeam.team.name; - - final runDifference = firstTeam.run - secondTeam.run; - - return ( - teamName: teamName, - difference: runDifference, - wonByText: context.l10n.common_runs_dot_title, - ); - } else if (firstTeam.run == secondTeam.run) { - return (teamName: "", difference: 0, wonByText: ""); - } else { - // second batting team won - final teamName = secondTeam.team.name; - - final wicketDifference = secondTeam.squad.length - firstTeam.wicket; - - return ( - teamName: teamName, - difference: wicketDifference, - wonByText: context.l10n.common_wickets_dot_title, - ); - } - } -} diff --git a/khelo/lib/domain/extensions/enum_extensions.dart b/khelo/lib/domain/extensions/enum_extensions.dart index b047b80b..d280c8e2 100644 --- a/khelo/lib/domain/extensions/enum_extensions.dart +++ b/khelo/lib/domain/extensions/enum_extensions.dart @@ -218,3 +218,16 @@ extension ExtrasTypeString on ExtrasType { } } } + +extension WinnerByTypeString on WinnerByType { + String getString(BuildContext context, int difference) { + switch (this) { + case WinnerByType.run: + return context.l10n.common_runs_title(difference); + case WinnerByType.wicket: + return context.l10n.common_wickets_title(difference); + case WinnerByType.tie: + return context.l10n.common_tie_title; + } + } +} diff --git a/khelo/lib/domain/extensions/string_extensions.dart b/khelo/lib/domain/extensions/string_extensions.dart index 3574dfa3..66cb7ad2 100644 --- a/khelo/lib/domain/extensions/string_extensions.dart +++ b/khelo/lib/domain/extensions/string_extensions.dart @@ -5,4 +5,17 @@ extension EmailValidator on String { r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$') .hasMatch(this); } + + String initials({int? limit}) { + List words = trim().split(RegExp(r'\s+')); + String result = words.map((word) => word.isNotEmpty ? word[0] : '').join(); + result = result.toUpperCase(); + + // If limit is not null, apply the limit; otherwise, return all initials + if (limit != null) { + return result.substring(0, limit.clamp(0, result.length)); + } else { + return result; + } + } } diff --git a/khelo/lib/domain/formatter/date_formatter.dart b/khelo/lib/domain/formatter/date_formatter.dart index eb993d57..174cc793 100644 --- a/khelo/lib/domain/formatter/date_formatter.dart +++ b/khelo/lib/domain/formatter/date_formatter.dart @@ -2,7 +2,14 @@ import 'package:flutter/cupertino.dart'; import 'package:intl/intl.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; -enum DateFormatType { dateAndTime, date, time, shortDate, dayMonthYear } +enum DateFormatType { + dateAndTime, + date, + time, + shortDate, + shortDateTime, + dayMonthYear +} extension DateFormatter on DateTime { String format(BuildContext context, DateFormatType type) { @@ -20,6 +27,10 @@ extension DateFormatter on DateTime { .format(this); case DateFormatType.shortDate: return DateFormat('dd MMM yyyy').format(this); + case DateFormatType.shortDateTime: + return DateFormat( + 'dd MMM yyyy, ${context.is24HourFormat ? 'HH:mm' : 'hh:mm a'}') + .format(this); case DateFormatType.dayMonthYear: return DateFormat.yMMMd().format(this); } diff --git a/khelo/lib/ui/flow/matches/match_detail/components/commentary_ball_summary.dart b/khelo/lib/ui/flow/matches/match_detail/components/commentary_ball_summary.dart index ed8b10cf..86e60502 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/commentary_ball_summary.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/commentary_ball_summary.dart @@ -1,37 +1,33 @@ import 'package:data/api/ball_score/ball_score_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; import 'package:khelo/domain/extensions/enum_extensions.dart'; import 'package:khelo/ui/flow/matches/match_detail/components/over_score_view.dart'; -import 'package:khelo/ui/flow/matches/match_detail/match_detail_tab_view_model.dart'; import 'package:style/extensions/context_extensions.dart'; import 'package:style/text/app_text_style.dart'; -class CommentaryBallSummary extends ConsumerWidget { - final MatchDetailTabState state; +class CommentaryBallSummary extends StatelessWidget { + final OverSummary overSummary; final BallScoreModel ball; final bool showBallScore; const CommentaryBallSummary({ super.key, - required this.state, + required this.overSummary, required this.ball, this.showBallScore = true, }); @override - Widget build(BuildContext context, WidgetRef ref) { + Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ - Expanded(flex: 1, child: _ballNumberView(context)), - const SizedBox( - width: 16, - ), - Expanded(flex: 7, child: _ballSummaryTextView(context)), + _ballNumberView(context), + const SizedBox(width: 24), + Expanded(child: _ballSummaryTextView(context)), ], ), ); @@ -41,56 +37,58 @@ class CommentaryBallSummary extends ConsumerWidget { return Column( children: [ Text("${ball.over_number - 1}.${ball.ball_number}", - style: AppTextStyle.header3 - .copyWith(color: context.colorScheme.textPrimary)), - if (showBallScore) ...[ - BallScoreView( - ball: ball, - size: 35, - ) - ] + style: showBallScore + ? AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled) + : AppTextStyle.body1 + .copyWith(color: context.colorScheme.textDisabled)), + if (showBallScore) ...[BallScoreView(ball: ball, size: 24)] ], ); } - Widget _ballSummaryTextView( - BuildContext context, - ) { - final (batsMan, bowler, fielder, outPlayer) = _getPlayerName(state, ball); + Widget _ballSummaryTextView(BuildContext context) { + final outPlayerSummary = overSummary.outPlayers + .where((element) => element.player.id == ball.player_out_id) + .firstOrNull; final wicketTakerText = ball.wicket_type != null - ? " ${ball.wicket_type?.getString(context)}${fielder != null ? context.l10n.match_commentary_by_fielder_text(fielder) : ""}!!" + ? " ${ball.wicket_type?.getString(context)}${outPlayerSummary?.catchBy != null ? context.l10n.match_commentary_by_fielder_text(outPlayerSummary?.catchBy?.name ?? "") : ""}!!" : ""; - final (run, ballCount, fours, sixes) = - _getBatsmanSummary(context, state, ball); - String batsManSummary = " "; - if (ball.wicket_type != null) { - batsManSummary += outPlayer ?? batsMan; - - if (ball.wicket_type != WicketType.retired && - ball.wicket_type != WicketType.retiredHurt && - ball.wicket_type != WicketType.timedOut) { - batsManSummary += - context.l10n.match_commentary_b_bowler_text(bowler ?? ""); + final bowlerName = overSummary.bowler.player.name; + final batsmanName = _getBatsmanNameById(ball.batsman_id); - if (fielder != null) { - batsManSummary += - context.l10n.match_commentary_c_fielder_text(fielder); + String batsManSummary = " "; + if (outPlayerSummary != null && outPlayerSummary.wicketType != null) { + batsManSummary += outPlayerSummary.player.name; + + if (outPlayerSummary.wicketType != WicketType.retired && + outPlayerSummary.wicketType != WicketType.retiredHurt && + outPlayerSummary.wicketType != WicketType.timedOut) { + batsManSummary += context.l10n.match_commentary_b_bowler_text( + outPlayerSummary.ballBy?.name ?? ""); + + if (outPlayerSummary.catchBy != null) { + batsManSummary += context.l10n.match_commentary_c_fielder_text( + outPlayerSummary.catchBy?.name ?? ""); } } - batsManSummary += context.l10n - .match_commentary_runs_fours_sixes_text(run, ballCount, fours, sixes); + batsManSummary += context.l10n.match_commentary_runs_fours_sixes_text( + outPlayerSummary.runs, + outPlayerSummary.ballFaced, + outPlayerSummary.fours, + outPlayerSummary.sixes); } return Text.rich( + style: + AppTextStyle.body1.copyWith(color: context.colorScheme.textDisabled), TextSpan( text: context.l10n - .match_commentary_bowler_to_batsman_text(bowler ?? "", batsMan), - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), + .match_commentary_bowler_to_batsman_text(bowlerName, batsmanName), children: [ TextSpan( - text: " ${_getBallResult(context, ball)}", - style: AppTextStyle.header3 + text: " ${_getBallResult(context)}", + style: AppTextStyle.body1 .copyWith(color: context.colorScheme.textPrimary), ), TextSpan( @@ -98,94 +96,31 @@ class CommentaryBallSummary extends ConsumerWidget { ), TextSpan( text: batsManSummary, - style: AppTextStyle.header3 + style: AppTextStyle.body1 .copyWith(color: context.colorScheme.textPrimary), ) ]), - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), ); } - (String, String?, String?, String?) _getPlayerName( - MatchDetailTabState state, BallScoreModel ball) { - final battingTeamId = ball.inning_id == state.firstInning?.id - ? state.firstInning?.team_id - : state.secondInning?.team_id; - final bowlingTeamId = ball.inning_id == state.firstInning?.id - ? state.secondInning?.team_id - : state.firstInning?.team_id; - final battingSquad = state.match?.teams - .firstWhere((element) => battingTeamId == element.team.id) - .team - .players; - final bowlingSquad = state.match?.teams - .firstWhere((element) => bowlingTeamId == element.team.id) - .team - .players; - - final bowlerName = bowlingSquad - ?.firstWhere((element) => element.id == ball.bowler_id) - .name; - - final fielderName = bowlingSquad - ?.where((element) => element.id == ball.wicket_taker_id) - .firstOrNull - ?.name; - - final batsmanName = battingSquad - ?.firstWhere((element) => element.id == ball.batsman_id) - .name; - String? outPlayerName; - if (ball.player_out_id != ball.batsman_id) { - outPlayerName = battingSquad - ?.where((element) => element.id == ball.player_out_id) - .firstOrNull - ?.name; - } - return (batsmanName ?? "", bowlerName, fielderName, outPlayerName); - } - - (int, int, int, int) _getBatsmanSummary( - BuildContext context, MatchDetailTabState state, BallScoreModel ball) { - if (ball.wicket_type == null) { - return (0, 0, 0, 0); - } - final score = state.ballScores.where((element) => - element.inning_id == ball.inning_id && - element.batsman_id == ball.player_out_id && - element.extras_type != ExtrasType.penaltyRun && - element.wicket_type == WicketType.retired && - element.wicket_type == WicketType.retiredHurt && - element.wicket_type == WicketType.timedOut); - - int fours = 0; - int sixes = 0; - int ballCount = 0; - int run = 0; - for (var element in score) { - if (element.extras_type != ExtrasType.wide) { - ballCount = ballCount + 1; - } - - if (element.extras_type == ExtrasType.noBall) { - final extra = (element.extras_awarded ?? 0) > 1 - ? (element.extras_awarded ?? 1) - 1 - : 0; - run = run + extra; - } - run = run + element.runs_scored; - if (element.is_six && element.runs_scored == 6) { - sixes = sixes + 1; - } else if (element.is_four && element.runs_scored == 4) { - fours = fours + 1; - } + String _getBatsmanNameById(String batsmanId) { + if (overSummary.striker.player.id == batsmanId) { + return overSummary.striker.player.name; + } else if (overSummary.nonStriker.player.id == batsmanId) { + return overSummary.nonStriker.player.name; + } else if (overSummary.outPlayers + .map((e) => e.player.id) + .contains(batsmanId)) { + return overSummary.outPlayers + .firstWhere((e) => e.player.id == batsmanId) + .player + .name; + } else { + return ""; } - - return (run, ballCount, fours, sixes); } - String _getBallResult(BuildContext context, BallScoreModel ball) { + String _getBallResult(BuildContext context) { if (ball.extras_type == null && ball.wicket_type == null) { if (ball.runs_scored == 4 && ball.is_four) { return context.l10n.match_commentary_four_text; diff --git a/khelo/lib/ui/flow/matches/match_detail/components/commentary_over_overview.dart b/khelo/lib/ui/flow/matches/match_detail/components/commentary_over_overview.dart index b1e1af4e..32cf4451 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/commentary_over_overview.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/commentary_over_overview.dart @@ -1,318 +1,178 @@ import 'package:data/api/ball_score/ball_score_model.dart'; import 'package:data/api/team/team_model.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/image_avatar.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; -import 'package:khelo/domain/extensions/data_model_extensions/ball_score_model_extension.dart'; +import 'package:khelo/domain/extensions/string_extensions.dart'; import 'package:khelo/ui/flow/matches/match_detail/components/over_score_view.dart'; -import 'package:khelo/ui/flow/matches/match_detail/match_detail_tab_view_model.dart'; import 'package:style/extensions/context_extensions.dart'; import 'package:style/text/app_text_style.dart'; -class CommentaryOverOverview extends ConsumerWidget { - final int index; +class CommentaryOverOverview extends StatelessWidget { + final OverSummary overSummary; + final TeamModel? team; const CommentaryOverOverview({ super.key, - required this.index, + required this.overSummary, + required this.team, }); @override - Widget build(BuildContext context, WidgetRef ref) { - final state = ref.watch(matchDetailTabStateProvider); - - final over = _getOverBallScores(state, index); - final overLastBall = over.lastOrNull; - final overNumber = overLastBall?.over_number ?? 0; - final inningId = overLastBall?.inning_id ?? "INVALID ID"; - + Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - color: context.colorScheme.containerNormalOnSurface, + padding: const EdgeInsets.all(16), + color: context.colorScheme.containerLow, child: Column( children: [ IntrinsicHeight( child: Row( children: [ - Text( - "$overNumber", - style: AppTextStyle.header1 - .copyWith(color: context.colorScheme.textPrimary), - ), - const SizedBox( - width: 12, - ), + _overCount(context), + const SizedBox(width: 16), _divider(context, axis: Axis.vertical), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BowlerSummary( - state: state, - index: index + 1, - inningId: inningId, - bowlerId: overLastBall?.bowler_id ?? "INVALID ID"), - const SizedBox( - height: 4, - ), - OverScoreView( - over: over, - size: 30, - ) - ], - ), - ) + const SizedBox(width: 16), + _bowlerAndOverSummary(context) ], ), ), + const SizedBox(height: 16), _divider(context), - IntrinsicHeight( - child: Row( - children: [ - Expanded( - flex: 4, - child: _batsMenView( - context, - state, - inningId, - index, - overLastBall?.batsman_id ?? "INVALID ID", - overLastBall?.non_striker_id ?? "INVALID ID"), - ), - _divider(context, axis: Axis.vertical), - Expanded( - flex: 3, - child: _teamTotalView(context, state, inningId), - ), - ], - ), - ), + const SizedBox(height: 16), + _teamTotalView(context), + const SizedBox(height: 16), + _batsManScoreView(context, overSummary.striker), + const SizedBox(height: 4), + _batsManScoreView(context, overSummary.nonStriker), ], ), ); } - List _getOverBallScores( - MatchDetailTabState state, - int index, - ) { - final currentOverNumber = state.ballScores[index].over_number; - final currentInningId = state.ballScores[index].inning_id; - return state.ballScores - .where((element) => - element.over_number == currentOverNumber && - element.inning_id == currentInningId) - .toList(); + Widget _overCount(BuildContext context) { + return Column( + children: [ + Text( + context.l10n.match_scorecard_over_text, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + ), + Text( + "${overSummary.overNumber}", + style: AppTextStyle.header1 + .copyWith(color: context.colorScheme.textPrimary), + ), + ], + ); + } + + Widget _bowlerAndOverSummary(BuildContext context) { + return Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BowlerSummaryView(bowlerSummary: overSummary.bowler), + const SizedBox(height: 8), + OverScoreView(over: overSummary.balls, size: 32) + ], + ), + ); } Widget _divider(BuildContext context, {Axis axis = Axis.horizontal}) { if (axis == Axis.horizontal) { - return Divider( - color: context.colorScheme.outline, - ); + return Divider(height: 0, color: context.colorScheme.outline); } else { - return VerticalDivider( - color: context.colorScheme.outline, - ); + return VerticalDivider(width: 0, color: context.colorScheme.outline); } } - Widget _batsMenView(BuildContext context, MatchDetailTabState state, - String inningId, int index, String batsmanId, String nonStrikerId) { - return Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, + Widget _teamTotalView(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, children: [ - _batsManScoreView(context, state, index, batsmanId, inningId), - _batsManScoreView(context, state, index, nonStrikerId, inningId) + ImageAvatar( + initial: team?.name.initials(limit: 1) ?? "?", + imageUrl: team?.profile_img_url, + size: 35, + ), + const SizedBox(width: 6), + Expanded( + child: Text( + team?.name ?? "", + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: AppTextStyle.subtitle3 + .copyWith(color: context.colorScheme.textSecondary), + ), + ), + const SizedBox(width: 6), + Text("${overSummary.totalRuns}-${overSummary.totalWickets}", + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary)), ], ); } - Widget _batsManScoreView(BuildContext context, MatchDetailTabState state, - int index, String batsManId, String inningId) { - final (batsManName, runs, ball) = - _getBatsManSummaryTillIndex(state, index, batsManId, inningId); + Widget _batsManScoreView( + BuildContext context, + BatsmanSummary batsmanSummary, + ) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible( child: Text( - batsManName, - style: AppTextStyle.subtitle1 + batsmanSummary.player.name, + style: AppTextStyle.subtitle2 .copyWith(color: context.colorScheme.textPrimary), )), Text.rich(TextSpan( - text: "$runs", - style: AppTextStyle.subtitle1 + text: batsmanSummary.runs.toString(), + style: AppTextStyle.subtitle2 .copyWith(color: context.colorScheme.textPrimary), children: [ TextSpan( - text: "($ball)", - style: AppTextStyle.body1 - .copyWith(color: context.colorScheme.textPrimary), + text: "(${batsmanSummary.ballFaced})", + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textSecondary), ) ])), ], ); } - - (String, int, int) _getBatsManSummaryTillIndex( - MatchDetailTabState state, - int index, - String batsManId, - String inningId, - ) { - final battingTeamId = inningId == state.firstInning?.id - ? state.firstInning?.team_id - : state.secondInning?.team_id; - - final batterName = state.match?.teams - .firstWhere((element) => battingTeamId == element.team.id) - .team - .players - ?.firstWhere((element) => element.id == batsManId) - .name; - - final score = state.ballScores.getRange(0, index + 1).where((element) => - element.inning_id == inningId && - element.batsman_id == batsManId && - element.extras_type != ExtrasType.penaltyRun && - element.wicket_type != WicketType.retired && - element.wicket_type != WicketType.retiredHurt && - element.wicket_type != WicketType.timedOut); - - int ballCount = 0; - int run = 0; - for (var element in score) { - if (element.extras_type != ExtrasType.wide) { - ballCount = ballCount + 1; - } - - if (element.extras_type == ExtrasType.noBall) { - final extra = (element.extras_awarded ?? 0) > 1 - ? (element.extras_awarded ?? 1) - 1 - : 0; - run = run + extra; - } - run = run + element.runs_scored; - } - - return (batterName ?? "--", run, ballCount); - } - - Widget _teamTotalView( - BuildContext context, MatchDetailTabState state, String inningId) { - final team = _getTeamByInningId(state, inningId); - final (run, wicket) = _getTeamScoreTillIndex(state, inningId); - - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ImageAvatar( - initial: team?.name[0].toUpperCase() ?? "?", - imageUrl: team?.profile_img_url, - size: 35, - ), - const SizedBox(width: 6), - Flexible( - child: Column( - children: [ - Text( - team?.name ?? "", - textAlign: TextAlign.center, - style: AppTextStyle.subtitle2 - .copyWith(color: context.colorScheme.textPrimary), - ), - Text.rich(TextSpan( - text: "$run", - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - children: [ - TextSpan( - text: "($wicket)", - style: AppTextStyle.body1 - .copyWith(color: context.colorScheme.textPrimary)) - ])), - ], - ), - ), - ], - ); - } - - TeamModel? _getTeamByInningId(MatchDetailTabState state, String inningId) { - final teamId = state.firstInning?.id == inningId - ? state.firstInning?.team_id - : state.secondInning?.team_id; - - final team = state.match?.teams - .where((element) => element.team.id == teamId) - .firstOrNull - ?.team; - return team; - } - - (int, int) _getTeamScoreTillIndex( - MatchDetailTabState state, String inningId) { - final ballScore = state.ballScores - .getRange(0, index + 1) - .where((element) => element.inning_id == inningId); - final runs = ballScore.fold( - 0, - (lastTotal, element) => - lastTotal + element.runs_scored + (element.extras_awarded ?? 0)); - final wicket = ballScore - .where((element) => - element.wicket_type != null && - element.wicket_type != WicketType.retiredHurt) - .length; - - return (runs, wicket); - } } -class BowlerSummary extends StatelessWidget { - final MatchDetailTabState state; - final int index; - final String inningId; - final String bowlerId; +class BowlerSummaryView extends StatelessWidget { + final BowlerSummary bowlerSummary; final bool isForBowlerIntro; - const BowlerSummary({ + const BowlerSummaryView({ super.key, - required this.state, - required this.index, - required this.inningId, - required this.bowlerId, + required this.bowlerSummary, this.isForBowlerIntro = false, }); @override Widget build(BuildContext context) { - final (bowlerName, over, maidenOversCount, runsConceded, wicketCount) = - _getBowlerSummaryTillIndex(state, - index: index, inningId: inningId, bowlerId: bowlerId); - if (over == 0) { + if (bowlerSummary.overDelivered == 0) { return const SizedBox(); } + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.symmetric(horizontal: isForBowlerIntro ? 16 : 0), child: Text.rich(TextSpan( - text: "$bowlerName", - style: isForBowlerIntro - ? AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary) - : AppTextStyle.subtitle2 - .copyWith(color: context.colorScheme.textPrimary), + text: bowlerSummary.player.name, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), children: [ TextSpan( text: - " [$over - $maidenOversCount - $runsConceded - $wicketCount]", - style: AppTextStyle.body1 + " [${bowlerSummary.overDelivered} - ${bowlerSummary.maiden} - ${bowlerSummary.runsConceded} - ${bowlerSummary.wicket}]", + style: AppTextStyle.subtitle3 .copyWith(color: context.colorScheme.textPrimary), ), if (isForBowlerIntro) ...[ @@ -325,69 +185,4 @@ class BowlerSummary extends StatelessWidget { ], ); } - - (String?, double, int, int, int) _getBowlerSummaryTillIndex( - MatchDetailTabState state, { - required int index, - required String inningId, - required String bowlerId, - }) { - final bowlingTeamId = inningId == state.firstInning?.id - ? state.secondInning?.team_id - : state.firstInning?.team_id; - - final bowlerName = state.match?.teams - .firstWhere((element) => bowlingTeamId == element.team.id) - .team - .players - ?.firstWhere((element) => element.id == bowlerId) - .name; - - final scoreList = state.ballScores - .getRange(0, index) - .where((element) => - element.bowler_id == bowlerId && element.inning_id == inningId) - .toList(); - // over - final legalDeliveryCount = - scoreList.where((element) => element.isLegalDelivery() ?? false).length; - final over = legalDeliveryCount / 6; - // maiden - final emptyBalls = scoreList.where((element) => - element.extras_type == null && - element.wicket_type == null && - element.runs_scored == 0); - - int maidenOversCount = 0; - int overNumber = 0; - int ballNumber = 0; - for (final ball in emptyBalls) { - if (overNumber != ball.over_number) { - if (ballNumber == 6) { - maidenOversCount++; - } - overNumber = ball.over_number; - ballNumber = 0; - } else { - ballNumber++; - } - } - // runs conceded - final runsConceded = scoreList - .where((element) => element.extras_type != ExtrasType.penaltyRun) - .fold( - 0, - (sum, element) => - sum + element.runs_scored + (element.extras_awarded ?? 0)); - // wickets - final wicketCount = scoreList - .where((element) => - element.wicket_type != null && - element.wicket_type != WicketType.retired && - element.wicket_type != WicketType.retiredHurt && - element.wicket_type != WicketType.timedOut) - .length; - - return (bowlerName, over, maidenOversCount, runsConceded, wicketCount); - } } diff --git a/khelo/lib/ui/flow/matches/match_detail/components/final_score_view.dart b/khelo/lib/ui/flow/matches/match_detail/components/final_score_view.dart index cb0e86fa..d097eaa6 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/final_score_view.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/final_score_view.dart @@ -2,8 +2,7 @@ import 'package:data/api/match/match_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/image_avatar.dart'; -import 'package:khelo/domain/extensions/context_extensions.dart'; -import 'package:khelo/domain/extensions/data_model_extensions/match_model_extension.dart'; +import 'package:khelo/components/match_status_tag.dart'; import 'package:khelo/ui/flow/matches/match_detail/match_detail_tab_view_model.dart'; import 'package:khelo/components/won_by_message_text.dart'; import 'package:style/extensions/context_extensions.dart'; @@ -37,11 +36,20 @@ class FinalScoreView extends ConsumerWidget { children.add(const SizedBox(height: 8)); } children.add(const SizedBox(height: 8)); + children.add(Divider(color: context.colorScheme.outline)); if (state.match!.match_status == MatchStatus.finish) { - children.add(Divider( - color: context.colorScheme.outline, - )); children.add(_winnerMessageText(context, state.match!)); + } else if (state.match?.match_status == MatchStatus.running) { + children.add(Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.only(top: 16, bottom: 24), + child: MatchStatusTag( + status: state.match?.match_status ?? MatchStatus.running), + ), + ], + )); } return children; @@ -53,21 +61,24 @@ class FinalScoreView extends ConsumerWidget { ImageAvatar( initial: team.team.name[0].toUpperCase(), imageUrl: team.team.profile_img_url, - size: 35, + size: 32, + ), + const SizedBox(width: 12), + Expanded( + child: Text(team.team.name, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: AppTextStyle.subtitle3 + .copyWith(color: context.colorScheme.textSecondary)), ), - const SizedBox(width: 8), - Text(team.team.name, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary)), - const Spacer(), Text.rich(TextSpan( text: "${team.run}-$wicket", - style: AppTextStyle.header3 + style: AppTextStyle.subtitle2 .copyWith(color: context.colorScheme.textPrimary), children: [ TextSpan( text: " ${team.over}", - style: AppTextStyle.subtitle2 + style: AppTextStyle.body2 .copyWith(color: context.colorScheme.textSecondary), ) ])) @@ -76,34 +87,14 @@ class FinalScoreView extends ConsumerWidget { } Widget _winnerMessageText(BuildContext context, MatchModel match) { - final winSummary = match.getWinnerSummary(context); - if (match.match_status == MatchStatus.finish && winSummary != null) { - if (winSummary.teamName.isEmpty) { - return Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Text( - context.l10n.score_board_match_tied_text, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.primary), - ), - ), - ); - } - return Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: WonByMessageText( - teamName: winSummary.teamName, - difference: winSummary.difference, - trailingText: winSummary.wonByText, - ), + return Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: WonByMessageText( + matchResult: match.matchResult, ), - ); - } else { - return const SizedBox(); - } + ), + ); } } diff --git a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_commentary_view.dart b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_commentary_view.dart index 53f8b971..45896af8 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_commentary_view.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_commentary_view.dart @@ -1,4 +1,5 @@ -import 'package:data/api/innings/inning_model.dart'; +import 'package:data/api/ball_score/ball_score_model.dart'; +import 'package:data/api/team/team_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -33,21 +34,18 @@ class MatchDetailCommentaryView extends ConsumerWidget { if (state.error != null) { return ErrorScreen( error: state.error, - onRetryTap: () async { - await notifier.cancelStreamSubscription(); - notifier.loadMatch(); - }, + onRetryTap: notifier.onResume, ); } - if (state.ballScores.isEmpty) { + if (state.overList.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Text( context.l10n.match_commentary_empty_commentary_text, textAlign: TextAlign.center, - style: AppTextStyle.subtitle1 + style: AppTextStyle.body1 .copyWith(color: context.colorScheme.textPrimary), ), ), @@ -61,104 +59,85 @@ class MatchDetailCommentaryView extends ConsumerWidget { } List _buildCommentaryList( - BuildContext context, MatchDetailTabState state) { + BuildContext context, + MatchDetailTabState state, + ) { List children = []; children.add(const Padding( padding: EdgeInsets.symmetric(horizontal: 16.0), child: FinalScoreView(), )); + for (int index = state.overList.length - 1; index >= 0; index--) { + final overSummary = state.overList[index]; + final team = _getTeamByTeamId(state, overSummary.team_id); + + final nextOverSummary = state.overList.elementAtOrNull(index + 1); + if (nextOverSummary != null && + nextOverSummary.overNumber != overSummary.overNumber) { + children.add(BowlerSummaryView( + bowlerSummary:nextOverSummary.bowlerStatAtStart, + isForBowlerIntro: true, + )); + children.add(const SizedBox(height: 24)); + } - for (int index = state.ballScores.length - 1; index >= 0; index--) { - if (_isLastBallOfOver(index, state)) { - if (_isNewInning(index, state)) { - children.add(_inningOverview( - context, state, state.ballScores[index].inning_id)); - } else { - children.add(BowlerSummary( - state: state, - index: index + 1, - inningId: state.ballScores[index + 1].inning_id, - bowlerId: state.ballScores[index + 1].bowler_id, - isForBowlerIntro: true, - )); - children.add(const SizedBox(height: 24)); - children.add(CommentaryOverOverview(index: index)); - children.add(const SizedBox( - height: 8, - )); - } + if ((overSummary.balls.lastOrNull?.isLegalDelivery() ?? false) && + overSummary.balls.lastOrNull?.ball_number == 6 && + nextOverSummary?.inning_id == overSummary.inning_id) { + children + .add(CommentaryOverOverview(overSummary: overSummary, team: team)); + children.add(const SizedBox(height: 24)); + } else if (nextOverSummary != null && + nextOverSummary.inning_id != overSummary.inning_id) { + children.add(_inningOverview(context, + teamName: team?.name ?? "", targetRun: overSummary.totalRuns + 1)); } - children.add(CommentaryBallSummary( - state: state, - ball: state.ballScores[index], - showBallScore: false, - )); - children.add(const SizedBox(height: 8)); + for (final ball in overSummary.balls.reversed) { + children.add(CommentaryBallSummary( + ball: ball, + overSummary: overSummary, + showBallScore: false, + )); + children.add(const SizedBox(height: 8)); + } } return children; } - bool _isNewInning(int index, MatchDetailTabState state) { - return state.ballScores[index].inning_id != - state.ballScores.elementAtOrNull(index + 1)?.inning_id; - } - - bool _isLastBallOfOver(int index, MatchDetailTabState state) { - return state.ballScores[index].over_number != - state.ballScores.elementAtOrNull(index + 1)?.over_number; + TeamModel? _getTeamByTeamId(MatchDetailTabState state, String teamId) { + return state.match?.teams + .where((element) => element.team.id == teamId) + .firstOrNull + ?.team; } - Widget _inningOverview( - BuildContext context, - MatchDetailTabState state, - String inningId, - ) { - final inningStatus = state.firstInning?.id == inningId - ? state.firstInning?.innings_status - : state.secondInning?.innings_status; - if (inningStatus == InningStatus.finish && - state.firstInning?.id == inningId) { - final teamId = state.firstInning?.team_id; - final teamName = state.match?.teams - .firstWhere((element) => element.team.id == teamId) - .team - .name; - return Column( - children: [ - const SizedBox( - height: 16, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Text.rich(TextSpan( - text: "$teamName", - style: AppTextStyle.header4 - .copyWith(color: context.colorScheme.primary), - children: [ - TextSpan( - text: context.l10n.match_commentary_end_inning_text_part_1, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - ), - TextSpan( - text: context.l10n.match_commentary_runs_text( - (state.firstInning?.total_runs ?? 0) + 1)), - TextSpan( - text: context.l10n.match_commentary_end_inning_text_part_2, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - ), - ])), - ), - const SizedBox( - height: 8, - ), - ], - ); - } else { - return const SizedBox(); - } + Widget _inningOverview(BuildContext context, + {required String teamName, required int targetRun}) { + return Container( + padding: const EdgeInsets.all(16), + margin: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: context.colorScheme.containerLow, + borderRadius: BorderRadius.circular(8)), + child: Text.rich(TextSpan( + text: teamName, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.primary), + children: [ + TextSpan( + text: context.l10n.match_commentary_end_inning_text_part_1, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + TextSpan(text: context.l10n.match_commentary_runs_text(targetRun)), + TextSpan( + text: context.l10n.match_commentary_end_inning_text_part_2, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + ])), + ); } } diff --git a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_highlight_view.dart b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_highlight_view.dart index 27dd0aa4..a5b4d556 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_highlight_view.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_highlight_view.dart @@ -8,10 +8,10 @@ import 'package:khelo/components/error_screen.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; import 'package:khelo/ui/flow/matches/match_detail/components/commentary_ball_summary.dart'; import 'package:khelo/ui/flow/matches/match_detail/match_detail_tab_view_model.dart'; -import 'package:style/animations/on_tap_scale.dart'; import 'package:style/extensions/context_extensions.dart'; import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_style.dart'; +import 'package:style/widgets/adaptive_outlined_tile.dart'; class MatchDetailHighlightView extends ConsumerWidget { const MatchDetailHighlightView({super.key}); @@ -62,16 +62,13 @@ class MatchDetailHighlightView extends ConsumerWidget { MatchDetailTabState state, ) { if (state.loading) { - return const AppProgressIndicator(); + return const Center(child: AppProgressIndicator()); } if (state.error != null) { return ErrorScreen( error: state.error, - onRetryTap: () async { - await notifier.cancelStreamSubscription(); - notifier.loadMatch(); - }, + onRetryTap: notifier.onResume, ); } @@ -81,34 +78,38 @@ class MatchDetailHighlightView extends ConsumerWidget { padding: context.mediaQueryPadding, child: Column( children: [ - IntrinsicHeight( + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ Expanded( - child: _highlightFilterButton(context, teamName, - notifier.showHighlightTeamSelectionDialog), - ), - const VerticalDivider( - width: 1, - ), + child: AdaptiveOutlinedTile( + placeholder: teamName, + title: teamName, + maxLines: 1, + onTap: notifier.showHighlightTeamSelectionDialog, + showTrailingIcon: true, + )), + const SizedBox(width: 8), Expanded( - child: _highlightFilterButton( - context, - state.highlightFilterOption.getString(context), - notifier.showHighlightFilterSelectionDialog), - ), + child: AdaptiveOutlinedTile( + placeholder: state.highlightFilterOption.getString(context), + title: state.highlightFilterOption.getString(context), + maxLines: 1, + onTap: notifier.showHighlightFilterSelectionDialog, + showTrailingIcon: true, + )), ], ), ), - Expanded(child: _highlightList(context, notifier, state)), + Expanded(child: _highlightList(context, state)), ], ), ); } - Widget _highlightList(BuildContext context, - MatchDetailTabViewNotifier notifier, MatchDetailTabState state) { - final highlight = _getHighlightsScore(state); + Widget _highlightList(BuildContext context, MatchDetailTabState state) { + final highlight = state.filteredHighlight; if (highlight.isEmpty) { return Center( @@ -117,7 +118,7 @@ class MatchDetailHighlightView extends ConsumerWidget { child: Text( context.l10n.match_highlight_empty_highlight_text, textAlign: TextAlign.center, - style: AppTextStyle.subtitle1 + style: AppTextStyle.body1 .copyWith(color: context.colorScheme.textPrimary), ), ), @@ -126,14 +127,32 @@ class MatchDetailHighlightView extends ConsumerWidget { return ListView.separated( itemCount: highlight.length, - padding: const EdgeInsets.only(left: 16, right: 16, top: 24), - separatorBuilder: (context, index) => const Divider(), + padding: const EdgeInsets.only(top: 24), + separatorBuilder: (context, index) => + Divider(color: context.colorScheme.outline, height: 32), itemBuilder: (context, index) { - return CommentaryBallSummary(state: state, ball: highlight[index]); + final overSummary = highlight[index]; + return Column(children: _buildHighlightList(context, overSummary)); }, ); } + List _buildHighlightList( + BuildContext context, OverSummary overSummary) { + List children = []; + for (int index = 0; index < overSummary.balls.length; index++) { + children.add(CommentaryBallSummary( + ball: overSummary.balls[index], overSummary: overSummary)); + if (index != overSummary.balls.length - 1) { + children.add(Divider( + color: context.colorScheme.outline, + height: 32, + )); + } + } + return children; + } + String _getTeamNameByInningId(MatchDetailTabState state) { final teamName = state.match?.teams .where((element) => element.team.id == state.highlightTeamId) @@ -143,64 +162,6 @@ class MatchDetailHighlightView extends ConsumerWidget { return teamName ?? "--"; } - Widget _highlightFilterButton( - BuildContext context, String title, Function() onTap) { - return OnTapScale( - onTap: onTap, - child: Container( - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), - color: context.colorScheme.containerNormalOnSurface, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - title, - style: AppTextStyle.subtitle1.copyWith( - color: context.colorScheme.textPrimary, - overflow: TextOverflow.ellipsis), - ), - ), - Icon( - Icons.expand_more_sharp, - color: context.colorScheme.textPrimary, - ) - ], - ), - ), - ); - } - - List _getHighlightsScore(MatchDetailTabState state) { - final inningId = state.firstInning?.team_id == state.highlightTeamId - ? state.firstInning?.id - : state.secondInning?.id; - switch (state.highlightFilterOption) { - case HighlightFilterOption.all: - return state.ballScores - .where((element) => - element.inning_id == inningId && - (element.wicket_type != null || - element.is_four || - element.is_six)) - .toList(); - case HighlightFilterOption.fours: - return state.ballScores - .where( - (element) => element.inning_id == inningId && element.is_four) - .toList(); - case HighlightFilterOption.sixes: - return state.ballScores - .where((element) => element.inning_id == inningId && element.is_six) - .toList(); - case HighlightFilterOption.wickets: - return state.ballScores - .where((element) => - element.inning_id == inningId && element.wicket_type != null) - .toList(); - } - } - void showFilterOptionSelectionSheet( BuildContext context, Function(HighlightFilterOption) onTap) { showActionBottomSheet( @@ -216,8 +177,11 @@ class MatchDetailHighlightView extends ConsumerWidget { .toList()); } - void showTeamSelectionSheet(BuildContext context, List? teams, - Function(String) onTap) { + void showTeamSelectionSheet( + BuildContext context, + List? teams, + Function(String) onTap, + ) { showActionBottomSheet( context: context, items: teams diff --git a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_info_view.dart b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_info_view.dart index 37255a42..a50e0942 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_info_view.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_info_view.dart @@ -26,46 +26,51 @@ class MatchDetailInfoView extends ConsumerWidget { Widget _body(BuildContext context, MatchDetailTabViewNotifier notifier, MatchDetailTabState state) { if (state.loading) { - return const AppProgressIndicator(); + return const Center(child: AppProgressIndicator()); } if (state.error != null) { return ErrorScreen( error: state.error, - onRetryTap: () async { - await notifier.cancelStreamSubscription(); - notifier.loadMatch(); - }, + onRetryTap: notifier.onResume, ); } return ListView( - padding: context.mediaQueryPadding, + padding: context.mediaQueryPadding + + const EdgeInsets.symmetric(horizontal: 16), children: [ _sectionTitle(context, context.l10n.match_detail_match_info_tab_title), _matchTitleView(context, state.match!), - _matchDateTimeView(context, state.match?.start_time ?? DateTime.now()), + _dataRowView(context, + title: context.l10n.match_info_date_and_time_title, + subtitle: state.match?.start_time + .format(context, DateFormatType.shortDateTime)), _tossDetailView(context, state.match!), - _matchOfficialView(context, state.match!), - for (final team in state.match?.teams ?? []) ...[ - _teamPlayerView(context, team: team) - ], - const SizedBox(height: 16), - _sectionTitle(context, context.l10n.match_info_venue_title), _dataRowView(context, - title: context.l10n.match_info_ground_title, - subtitle: state.match?.ground ?? "-"), + title: context.l10n.match_info_venue_title, + subtitle: state.match?.ground), + _dataRowView(context, + title: context.l10n.add_match_officials_umpires_title, + subtitle: state.match?.umpires?.map((e) => e.name).join(", ")), + _dataRowView( + context, + title: context.l10n.add_match_officials_referee_title, + subtitle: state.match?.referee?.name, + ), + _dataRowView(context, + title: context.l10n.add_match_officials_commentators_title, + subtitle: state.match?.commentators?.map((e) => e.name).join(", ")), _dataRowView(context, - title: context.l10n.common_city_title, - subtitle: state.match?.city ?? "-"), + title: context.l10n.add_match_officials_scorers_title, + subtitle: state.match?.scorers?.map((e) => e.name).join(", ")), ], ); } Widget _sectionTitle(BuildContext context, String title) { - return Container( - color: context.colorScheme.containerNormalOnSurface, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + return Padding( + padding: const EdgeInsets.only(top: 24, bottom: 16), child: Text( title, style: AppTextStyle.subtitle1 @@ -79,27 +84,27 @@ class MatchDetailInfoView extends ConsumerWidget { required String title, String? subtitle, }) { + if (subtitle == null || subtitle.isEmpty) { + return const SizedBox(); + } return Padding( - padding: const EdgeInsets.only(left: 16, right: 16, top: 6), + padding: const EdgeInsets.symmetric(vertical: 16), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + title, + style: AppTextStyle.body1 + .copyWith(color: context.colorScheme.textSecondary), + ), + const SizedBox(width: 16), Expanded( - flex: 1, child: Text( - title, - style: AppTextStyle.header4 - .copyWith(color: context.colorScheme.textPrimary), - )), - if (subtitle != null) ...[ - Expanded( - flex: 3, - child: Text( - subtitle, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - )), - ], + subtitle, + textAlign: TextAlign.right, + style: AppTextStyle.subtitle1 + .copyWith(color: context.colorScheme.textPrimary), + )), ], ), ); @@ -113,19 +118,6 @@ class MatchDetailInfoView extends ConsumerWidget { title: context.l10n.match_info_match_title, subtitle: title); } - Widget _matchDateTimeView(BuildContext context, DateTime matchTime) { - return Column( - children: [ - _dataRowView(context, - title: context.l10n.match_info_date_title, - subtitle: matchTime.format(context, DateFormatType.date)), - _dataRowView(context, - title: context.l10n.match_info_time_title, - subtitle: matchTime.format(context, DateFormatType.time)), - ], - ); - } - Widget _tossDetailView(BuildContext context, MatchModel match) { String? teamName = match.teams .where((element) => element.team.id == match.toss_winner_id) @@ -145,48 +137,4 @@ class MatchDetailInfoView extends ConsumerWidget { return const SizedBox(); } } - - Widget _teamPlayerView( - BuildContext context, { - required MatchTeamModel team, - }) { - String playing = team.squad - .map((e) => - "${e.player.name}${team.captain_id == e.player.id ? context.l10n.match_info_captain_short_title : ""}") - .join(", "); - String? bench = team.team.players - ?.where((element) => - !team.squad.map((e) => e.player.id).contains(element.id)) - .join(", "); - return Column( - children: [ - _dataRowView(context, - title: context.l10n.match_info_squad_title(team.team.name)), - _dataRowView(context, - title: context.l10n.match_info_playing_title, subtitle: playing), - if (bench != null && (bench).isNotEmpty) ...[ - _dataRowView(context, - title: context.l10n.match_info_bench_title, subtitle: bench), - ], - ], - ); - } - - Widget _matchOfficialView(BuildContext context, MatchModel match) { - String? umpires = match.umpires?.map((e) => e.name).join(", "); - return Column( - children: [ - if (umpires != null && umpires.isNotEmpty) ...[ - _dataRowView(context, - title: context.l10n.match_info_umpire_title, subtitle: umpires), - ], - if (match.referee?.name != null && - (match.referee?.name ?? "").isNotEmpty) ...[ - _dataRowView(context, - title: context.l10n.match_info_referee_title, - subtitle: match.referee?.name), - ], - ], - ); - } } diff --git a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_overs_view.dart b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_overs_view.dart index d0059c43..9c94edbe 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_overs_view.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_overs_view.dart @@ -6,7 +6,6 @@ import 'package:khelo/domain/extensions/context_extensions.dart'; import 'package:khelo/ui/flow/matches/match_detail/components/final_score_view.dart'; import 'package:khelo/ui/flow/matches/match_detail/components/over_score_view.dart'; import 'package:khelo/ui/flow/matches/match_detail/match_detail_tab_view_model.dart'; -import 'package:khelo/domain/extensions/data_model_extensions/ball_score_model_extension.dart'; import 'package:style/extensions/context_extensions.dart'; import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_style.dart'; @@ -31,21 +30,18 @@ class MatchDetailOversView extends ConsumerWidget { if (state.error != null) { return ErrorScreen( error: state.error, - onRetryTap: () async { - await notifier.cancelStreamSubscription(); - notifier.loadMatch(); - }, + onRetryTap: notifier.onResume, ); } - if (state.ballScores.isEmpty) { + if (state.overList.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Text( context.l10n.match_overs_empty_over_text, textAlign: TextAlign.center, - style: AppTextStyle.subtitle1 + style: AppTextStyle.body1 .copyWith(color: context.colorScheme.textPrimary), ), ), @@ -53,41 +49,40 @@ class MatchDetailOversView extends ConsumerWidget { } return ListView( - padding: context.mediaQueryPadding + - const EdgeInsets.symmetric(horizontal: 16), + padding: context.mediaQueryPadding, children: [ - const FinalScoreView(), - ..._buildOverList(context, state, state.firstInning?.id ?? ""), - ..._buildOverList(context, state, state.secondInning?.id ?? ""), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16.0), + child: FinalScoreView(), + ), + ..._buildOverList(context, state), ], ); } - List _buildOverList( - BuildContext context, MatchDetailTabState state, String inningId) { - final filterBallScore = state.ballScores - .where((element) => inningId == element.inning_id) - .toList(); - - final oversList = filterBallScore.chunkArrayByOver(); + List _buildOverList(BuildContext context, MatchDetailTabState state) { List children = []; - for (int i = oversList.length - 1; i >= 0; i--) { - final over = oversList[i]; - - children.add(const SizedBox(height: 16)); - children.add(_overCellView(context, over)); + for (int i = state.overList.length - 1; i >= 0; i--) { + final over = state.overList.elementAt(i); + final nextOver = state.overList.elementAtOrNull(i + 1); + if (nextOver?.inning_id != over.inning_id) { + children.add( + _teamNameTitleView(context, state, over.inning_id, + state.firstInning?.id == over.inning_id ? 1 : 2), + ); + } else { + children.add(Divider(height: 32, color: context.colorScheme.outline)); + } + + children.add(_overCellView(context, over.balls, over.bowler.player.name, + over.striker.player.name, over.nonStriker.player.name)); } - if (oversList.isNotEmpty) { - children.add( - _teamNameTitleView(context, state, inningId), - ); - } - return children; } - Widget _overCellView(BuildContext context, List over) { + Widget _overCellView(BuildContext context, List over, + String bowler, String striker, String nonStriker) { final overCount = over.first.over_number; final runs = over.fold( 0, @@ -95,31 +90,46 @@ class MatchDetailOversView extends ConsumerWidget { previousValue + element.runs_scored + (element.extras_awarded ?? 0)); - return Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - context.l10n.match_commentary_former_over_short_text(overCount), - style: AppTextStyle.header4 - .copyWith(color: context.colorScheme.textPrimary), - ), - Text( - context.l10n.match_commentary_runs_text(runs), - style: AppTextStyle.body2 - .copyWith(color: context.colorScheme.textSecondary), - ), - ], - )), - Expanded( - flex: 4, - child: OverScoreView( - over: over, - size: 35, - )) - ], + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.l10n.match_commentary_former_over_short_text(overCount), + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textPrimary), + ), + const SizedBox(height: 8), + Text( + context.l10n.match_commentary_runs_text(runs), + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + ), + ], + ), + const SizedBox(width: 24), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${context.l10n.match_commentary_bowler_to_batsman_text(bowler, striker)} & $nonStriker", + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + const SizedBox(height: 4), + OverScoreView( + over: over, + size: 24, + ), + ], + )) + ], + ), ); } @@ -136,15 +146,15 @@ class MatchDetailOversView extends ConsumerWidget { return teamName ?? "--"; } - Widget _teamNameTitleView( - BuildContext context, MatchDetailTabState state, String inningId) { + Widget _teamNameTitleView(BuildContext context, MatchDetailTabState state, + String inningId, int inningCount) { final title = _getTeamNameByInningId(state, inningId); return Padding( - padding: const EdgeInsets.only(bottom: 8, top: 8, left: 4, right: 4), + padding: const EdgeInsets.only(top: 32, bottom: 16, left: 16, right: 16), child: Text( - title, - style: AppTextStyle.header1 - .copyWith(color: context.colorScheme.textSecondary), + "${context.l10n.match_commentary_inning_count_text(inningCount)}: $title", + style: AppTextStyle.subtitle1 + .copyWith(color: context.colorScheme.textPrimary), ), ); } diff --git a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_scorecard_view.dart b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_scorecard_view.dart index 55b795a8..a3eeccf6 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_scorecard_view.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_scorecard_view.dart @@ -1,12 +1,12 @@ import 'package:data/api/ball_score/ball_score_model.dart'; import 'package:data/api/match/match_model.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:khelo/components/error_screen.dart'; import 'package:khelo/components/won_by_message_text.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; -import 'package:khelo/domain/extensions/data_model_extensions/match_model_extension.dart'; import 'package:khelo/domain/extensions/enum_extensions.dart'; import 'package:khelo/ui/flow/matches/match_detail/match_detail_tab_view_model.dart'; import 'package:style/extensions/context_extensions.dart'; @@ -26,260 +26,182 @@ class MatchDetailScorecardView extends ConsumerWidget { Widget _body(BuildContext context, MatchDetailTabViewNotifier notifier, MatchDetailTabState state) { if (state.loading) { - return const AppProgressIndicator(); + return const Center(child: AppProgressIndicator()); } if (state.error != null) { return ErrorScreen( error: state.error, - onRetryTap: () async { - await notifier.cancelStreamSubscription(); - notifier.loadMatch(); - }, + onRetryTap: notifier.onResume, ); } - if (state.ballScores.isEmpty) { + if (state.overList.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( context.l10n.match_scorecard_empty_scorecard_text, textAlign: TextAlign.center, - style: AppTextStyle.subtitle1 + style: AppTextStyle.body1 .copyWith(color: context.colorScheme.textPrimary), ), ), ); } - return _scorecardView(context, state); - } - - Widget _scorecardView(BuildContext context, MatchDetailTabState state) { - if (state.match == null) { - return const SizedBox(); - } return ListView( padding: context.mediaQueryPadding, - children: [ - _winnerMessageText(context, state.match!), - for (final team in state.match!.teams) ...[ - _teamTitleView( - context, - team, - state.match!.teams - .where((element) => element.team.id != team.team.id) - .firstOrNull - ?.wicket ?? - 0), - _dataTable(context, state, team, isForBatting: true), - const SizedBox( - height: 16, - ), - _fallOfWicketView( - context, - state, - state.firstInning?.team_id == team.team.id - ? state.firstInning?.id ?? 'INVALID ID' - : state.secondInning?.id ?? 'INVALID ID'), - const SizedBox( - height: 16, - ), - _dataTable(context, state, team, isForBatting: false), - const SizedBox( - height: 16, - ), - _powerPlayView( - context, - state, - state.firstInning?.team_id == team.team.id - ? state.firstInning?.id ?? 'INVALID ID' - : state.secondInning?.id ?? 'INVALID ID'), - const SizedBox( - height: 20, - ) - ] - ], + children: _buildChildren(context, notifier, state), ); } - Widget _fallOfWicketView( + List _buildChildren( BuildContext context, + MatchDetailTabViewNotifier notifier, MatchDetailTabState state, - String inningId, ) { - final wickets = _getFallOfTheWicketDetail(state, inningId) - .map((e) => "${e.$1} (${e.$2}, ${e.$3})") - .join(", "); - if (wickets.isEmpty) { - return const SizedBox(); - } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _tableRow(context, - data: [], - highlightRow: true, - header: Text( - context.l10n.match_scorecard_fall_of_wicket_text, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - )), - const SizedBox( - height: 4, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Text( - wickets, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - ), - ), - ], - ); - } + List children = []; + children.add(_winnerMessageText(context, state.match!)); + for (final inningOvers in groupOversByInning(state.overList)) { + final overs = inningOvers.lastOrNull; + final batsmen = _getBatsmen(inningOvers); + final bowler = _getBowlers(inningOvers); + + final yetToPlayPlayers = state.match?.teams + .where((element) => element.team.id == overs?.team_id) + .firstOrNull + ?.squad + .where((element) => element.index == null) + .map((e) => e.player.name) + .join(", "); + + List> powerPlays = []; + if ((state.match?.power_play_overs1 ?? []).isNotEmpty) { + powerPlays.add(state.match!.power_play_overs1); + } + if ((state.match?.power_play_overs2 ?? []).isNotEmpty) { + powerPlays.add(state.match!.power_play_overs2); + } + if ((state.match?.power_play_overs3 ?? []).isNotEmpty) { + powerPlays.add(state.match!.power_play_overs3); + } - List<(int, String, String)> _getFallOfTheWicketDetail( - MatchDetailTabState state, - String inningId, - ) { - List<(int, String, String)> wickets = []; - final scores = state.ballScores.where((element) => - element.inning_id == inningId && - element.wicket_type != null && - element.wicket_type != WicketType.retiredHurt); - for (final ball in scores) { - final teamId = state.firstInning?.id == inningId - ? state.firstInning?.team_id - : state.secondInning?.team_id; - final playerName = state.match?.teams - .firstWhere((element) => element.team.id == teamId) - .squad - .firstWhere((element) => element.player.id == ball.player_out_id) - .player - .name; - final over = "${ball.over_number - 1}.${ball.ball_number}"; - final runs = _getTotalRunsBetweenOvers(state, inningId, - endOver: ball.over_number, endBall: ball.ball_number); - wickets.add((runs, playerName ?? "--", over)); + children.add(_teamTitleView(context, + teamName: _getTeamNameByTeamId(state, overs?.team_id ?? ""), + over: overs ?? const OverSummary(), + initiallyExpanded: + state.expandedTeamScorecard.contains(overs?.team_id ?? ""), + onExpansionChanged: (isExpanded) => notifier + .onScorecardExpansionChange(overs?.team_id ?? "", isExpanded), + children: [ + // batsmen summary + _dataTable(context, batsmen: batsmen), + + // total summary (extra, total, didNotBat) + ..._buildMatchTotalView(context, + inningLastOver: overs ?? const OverSummary(), + didNotBatPlayers: yetToPlayPlayers ?? ""), + + // fallOfWicket summary + _fallOfWicketView(context, inningOvers), + + // bowlers summary + _dataTable(context, bowler: bowler), + + // powerPlay summary + _powerPlayView(context, powerPlays, inningOvers), + ])); + children.add(const SizedBox(height: 16)); } + return children; + } - return wickets; + Widget _winnerMessageText(BuildContext context, MatchModel match) { + return Padding( + padding: const EdgeInsets.all(16), + child: WonByMessageText( + textStyle: AppTextStyle.body1 + .copyWith(color: context.colorScheme.textDisabled), + matchResult: match.matchResult, + ), + ); } - Widget _powerPlayView( - BuildContext context, - MatchDetailTabState state, - String inningId, - ) { - final List<(String overs, int run)> powerPlays = - _getPowerPlayDetails(state, inningId); - if (powerPlays.isEmpty) { - return const SizedBox(); - } else { - List children = []; - children.add(_tableRow(context, - data: [ - context.l10n.match_scorecard_over_text, - context.l10n.match_scorecard_run_text + Widget _teamTitleView( + BuildContext context, { + required String teamName, + required OverSummary over, + required bool initiallyExpanded, + required List children, + required Function(bool) onExpansionChanged, + }) { + return Material( + type: MaterialType.transparency, + child: ExpansionTile( + backgroundColor: context.colorScheme.primary, + collapsedBackgroundColor: context.colorScheme.primary, + collapsedIconColor: context.colorScheme.onPrimary, + controlAffinity: ListTileControlAffinity.platform, + iconColor: context.colorScheme.onPrimary, + initiallyExpanded: initiallyExpanded, + onExpansionChanged: onExpansionChanged, + trailing: AnimatedRotation( + turns: initiallyExpanded ? 0.5 : 0, + duration: const Duration(milliseconds: 300), + child: Icon( + CupertinoIcons.chevron_up, + size: 24, + color: context.colorScheme.onPrimary, + ), + ), + collapsedShape: const RoundedRectangleBorder( + side: BorderSide.none, + ), + shape: const RoundedRectangleBorder( + side: BorderSide.none, + ), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + teamName, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: AppTextStyle.subtitle1 + .copyWith(color: context.colorScheme.onPrimary), + ), + ), + Text.rich( + TextSpan( + text: "${over.totalRuns}-${over.totalWickets} ", + children: [ + TextSpan( + text: "(${over.overCount})", + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.onPrimary)) + ]), + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.onPrimary), + ), ], - highlightRow: true, - header: Text( - context.l10n.match_scorecard_power_play_text, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - ))); - children.add( - const SizedBox( - height: 4, ), - ); - int index = 0; - for (var element in powerPlays) { - index++; - children.add(_tableRow(context, - data: [(element.$1), "${element.$2}"], - header: Text( - context.l10n.power_play_text(index), - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - ))); - } - return Column( children: children, - ); - } - } - - List<(String, int)> _getPowerPlayDetails( - MatchDetailTabState state, String inningId) { - List<(String, int)> powerPlays = []; - - void addPowerPlayDetails(List? powerPlayOvers) { - if (powerPlayOvers != null) { - final start = powerPlayOvers.firstOrNull; - final end = powerPlayOvers.lastOrNull; - if (start != null && end != null) { - powerPlays.add(( - start == end ? "$start" : "$start - $end", - _getTotalRunsBetweenOvers(state, inningId, - startOver: start, endOver: end) - )); - } - } - } - - addPowerPlayDetails(state.match?.power_play_overs1); - addPowerPlayDetails(state.match?.power_play_overs2); - addPowerPlayDetails(state.match?.power_play_overs3); - - return powerPlays; - } - - int _getTotalRunsBetweenOvers( - MatchDetailTabState state, - String inningId, { - int startOver = 0, - required int endOver, - int endBall = 6, - }) { - final runs = state.ballScores - .where((element) => - element.inning_id == inningId && - element.over_number >= startOver && - (element.over_number < endOver || - (element.over_number == endOver && - element.ball_number <= endBall))) - .fold( - 0, - (previousValue, element) => - previousValue + - element.runs_scored + - (element.extras_awarded ?? 0)); - return runs; + ), + ); } Widget _dataTable( - BuildContext context, - MatchDetailTabState state, - MatchTeamModel team, { - required bool isForBatting, + BuildContext context, { + List? batsmen, + List? bowler, }) { - final teamInningId = state.firstInning?.team_id == team.team.id - ? state.firstInning?.id - : state.secondInning?.id; - - final bowlingSquad = state.match?.teams - .firstWhere((element) => element.team.id != team.team.id) - .squad; - return Column( children: [ _tableRow(context, highlightRow: true, - data: isForBatting + data: batsmen != null ? [ context.l10n.match_scorecard_run_short_text, context.l10n.match_scorecard_ball_short_text, @@ -296,27 +218,17 @@ class MatchDetailScorecardView extends ConsumerWidget { context.l10n.match_scorecard_wide_ball_short_text, context.l10n.match_scorecard_economy_short_text ], - header: Text(isForBatting - ? context.l10n.match_scorecard_batter_text - : context.l10n.match_scorecard_bowler_text)), - const SizedBox( - height: 4, - ), - if (isForBatting) - ..._buildBatsmanList( - context, - state, - bowlingSquad: bowlingSquad ?? [], - inningId: teamInningId ?? "INVALID ID", - players: team.squad, - ) + header: Text( + batsmen != null + ? context.l10n.match_scorecard_batter_text + : context.l10n.match_scorecard_bowler_text, + style: AppTextStyle.body1 + .copyWith(color: context.colorScheme.textDisabled), + )), + if (batsmen != null) + ..._buildBatsmanList(context, batsmen: batsmen) else - ..._buildBowlerList( - context, - state, - inningId: teamInningId ?? "INVALID ID", - players: bowlingSquad ?? [], - ), + ..._buildBowlerList(context, bowlers: bowler ?? []), ], ); } @@ -329,12 +241,11 @@ class MatchDetailScorecardView extends ConsumerWidget { required List data, }) { return Container( - padding: EdgeInsets.symmetric( - horizontal: 16.0, vertical: highlightRow ? 2 : 0), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: highlightRow - ? context.colorScheme.containerNormalOnSurface - : Colors.transparent, + ? context.colorScheme.containerLowOnSurface + : context.colorScheme.surface, ), child: Row( children: [ @@ -346,10 +257,10 @@ class MatchDetailScorecardView extends ConsumerWidget { child: Text( data[i], style: i == highlightColumnNumber - ? AppTextStyle.header3 + ? AppTextStyle.caption .copyWith(color: context.colorScheme.textPrimary) - : AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), + : AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), textAlign: TextAlign.center, )), ] @@ -359,377 +270,367 @@ class MatchDetailScorecardView extends ConsumerWidget { } List _buildBatsmanList( - BuildContext context, - MatchDetailTabState state, { - required String inningId, - required List players, - required List bowlingSquad, + BuildContext context, { + required List batsmen, }) { - List filteredPlayer = - players.where((element) => element.index != null).toList(); - filteredPlayer.sort((a, b) => a.index?.compareTo(b.index ?? 0) ?? 0); List children = []; - for (final player in filteredPlayer) { - final (run, ball, four, six, strikeRate) = - _getBattingPerformance(state, inningId, player.player.id); - - final (bowler, fielder, wicketType) = - _getWicketDetail(state, bowlingSquad, inningId, player.player.id); - + for (final player in batsmen) { String wicketString = ""; - if (wicketType == null) { + if (player.wicketType == null) { wicketString = context.l10n.match_scorecard_not_out_text; } else { - if (fielder == null) { - wicketString = wicketType.getString(context); + if (player.catchBy == null) { + wicketString = player.wicketType?.getString(context) ?? ""; - if (wicketType != WicketType.timedOut && - wicketType != WicketType.retired && - wicketType != WicketType.retiredHurt) { - wicketString += " ($bowler)"; + if (player.wicketType != WicketType.timedOut && + player.wicketType != WicketType.retired && + player.wicketType != WicketType.retiredHurt) { + wicketString += " (${player.ballBy?.name})"; } } else { - wicketString = context.l10n - .match_scorecard_bowler_catcher_short_text(bowler ?? "", fielder); + wicketString = context.l10n.match_scorecard_bowler_catcher_short_text( + player.ballBy?.name ?? "", player.catchBy?.name ?? ""); } } children.add(_tableRow(context, highlightColumnNumber: 0, data: [ - run.toString(), - ball.toString(), - four.toString(), - six.toString(), - strikeRate.toStringAsFixed(1) + player.runs.toString(), + player.ballFaced.toString(), + player.fours.toString(), + player.sixes.toString(), + player.strikeRate.toString(), ], header: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( - "${player.player.name}", - style: AppTextStyle.subtitle1.copyWith( - color: context.colorScheme.textPrimary, fontSize: 20), + player.player.name, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), ), Text( wicketString, - style: AppTextStyle.body1 - .copyWith(color: context.colorScheme.textSecondary), + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), ), ], ))); + + children.add(Divider( + height: 0, + color: context.colorScheme.outline, + )); } - final (bye, legBye, wide, noBall, penalty) = - _getExtraCounts(state, inningId); + return children; + } + + List _buildBowlerList( + BuildContext context, { + required List bowlers, + }) { + List children = []; + for (int index = 0; index < bowlers.length; index++) { + final bowler = bowlers[index]; + + if (index != 0) { + children.add(Divider( + height: 0, + color: context.colorScheme.outline, + )); + } + + children.add(_tableRow(context, + highlightColumnNumber: 3, + data: [ + bowler.overDelivered.toString(), + bowler.maiden.toString(), + bowler.runsConceded.toString(), + bowler.wicket.toString(), + bowler.noBalls.toString(), + bowler.wideBalls.toString(), + bowler.economy.toString(), + ], + header: Text( + bowler.player.name, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ))); + } + return children; + } + + List _buildMatchTotalView( + BuildContext context, { + required OverSummary inningLastOver, + required String didNotBatPlayers, + }) { + List children = []; + // Extra Summary children.add(_matchTotalView(context, title: context.l10n.match_scorecard_extra_text, - count: (bye + legBye + wide + noBall + penalty), + count: inningLastOver.extrasSummary.total, countDescription: context.l10n.match_scorecard_extras_short_text( - bye, legBye, wide, noBall, penalty))); - - final inning = state.firstInning?.id == inningId - ? state.firstInning - : state.secondInning; - final bowlingInning = state.firstInning?.id == inningId - ? state.secondInning - : state.firstInning; + inningLastOver.extrasSummary.bye, + inningLastOver.extrasSummary.legBye, + inningLastOver.extrasSummary.wideBall, + inningLastOver.extrasSummary.noBall, + inningLastOver.extrasSummary.penalty))); + children.add(Divider( + height: 0, + color: context.colorScheme.outline, + )); + + // total summary children.add(_matchTotalView(context, title: context.l10n.match_scorecard_total_text, - count: inning?.total_runs ?? 0, + count: inningLastOver.totalRuns, countDescription: context.l10n.match_scorecard_wicket_over_text( - bowlingInning?.total_wickets ?? 0, inning?.overs ?? 0))); - - String yetToPlayPlayers = players - .where((element) => element.index == null) - .map((e) => e.player.name) - .join(", "); - if (yetToPlayPlayers.isNotEmpty) { - children.add(_didNotBatView(context, yetToPlayPlayers)); + inningLastOver.totalWickets, inningLastOver.overCount))); + children.add(Divider( + height: 0, + color: context.colorScheme.outline, + )); + + // did not bat summary + if (didNotBatPlayers.isNotEmpty) { + children.add(_didNotBatView(context, didNotBatPlayers)); } - return children; } - Widget _didNotBatView(BuildContext context, String players) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Row( - children: [ - Expanded( - child: Text( - context.l10n.match_scorecard_did_not_bat_text, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - )), - Expanded( - child: Text(players, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary))), - ], - ), - ); - } - - (int, int, int, int, int) _getExtraCounts( - MatchDetailTabState state, String inningId) { - int wide = 0; - int noBall = 0; - int penalty = 0; - int legBye = 0; - int bye = 0; - final extrasScore = state.ballScores.where((element) => - element.inning_id == inningId && element.extras_type != null); - - for (var element in extrasScore) { - switch (element.extras_type) { - case ExtrasType.wide: - wide = wide + (element.extras_awarded ?? 0); - case ExtrasType.noBall: - noBall = noBall + (element.extras_awarded ?? 0); - case ExtrasType.bye: - penalty = penalty + (element.extras_awarded ?? 0); - case ExtrasType.legBye: - legBye = legBye + (element.extras_awarded ?? 0); - case ExtrasType.penaltyRun: - bye = bye + (element.extras_awarded ?? 0); - default: - break; - } - } - return (bye, legBye, wide, noBall, penalty); - } - Widget _matchTotalView( BuildContext context, { required String title, required int count, required String countDescription, }) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + color: context.colorScheme.surface, child: Row( children: [ Expanded( child: Text( title, - style: AppTextStyle.subtitle1 + style: AppTextStyle.subtitle2 .copyWith(color: context.colorScheme.textPrimary), )), Expanded( child: Text.rich( - style: AppTextStyle.header3 + style: AppTextStyle.caption .copyWith(color: context.colorScheme.textPrimary), TextSpan(text: "$count", children: [ TextSpan( text: " ($countDescription)", - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary)) + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled)) ]))), ], ), ); } - (int, int, int, int, double) _getBattingPerformance( - MatchDetailTabState state, - String inningId, - String batsManId, - ) { - final batScore = state.ballScores.where( - (element) => - element.inning_id == inningId && - element.batsman_id == batsManId && - element.extras_type != ExtrasType.penaltyRun && - element.wicket_type != WicketType.timedOut && - element.wicket_type != WicketType.retiredHurt && - element.wicket_type != WicketType.retired, + Widget _didNotBatView(BuildContext context, String players) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + color: context.colorScheme.surface, + child: Row( + children: [ + Expanded( + child: Text( + context.l10n.match_scorecard_did_not_bat_text, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + )), + Expanded( + child: Text(players, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textPrimary))), + ], + ), ); - int run = 0; - int ball = 0; - int fours = 0; - int sixes = 0; - - for (var element in batScore) { - if (element.extras_type != ExtrasType.wide) { - ball = ball + 1; - } + } - if (element.extras_type == ExtrasType.noBall) { - final extra = (element.extras_awarded ?? 0) > 1 - ? (element.extras_awarded ?? 1) - 1 - : 0; - run = run + extra; - } - run = run + element.runs_scored; - if (element.is_six && element.runs_scored == 6) { - sixes = sixes + 1; - } else if (element.is_four && element.runs_scored == 4) { - fours = fours + 1; - } - } + Widget _fallOfWicketView( + BuildContext context, List inningOvers) { + final oversWithWicket = + inningOvers.expand((over) => over.outPlayers).toList(); - final strikeRate = (run / ball) * 100; - return (run, ball, fours, sixes, strikeRate.isNaN ? 0 : strikeRate); + if (oversWithWicket.isEmpty) { + return const SizedBox(); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _tableRow(context, + data: [], + highlightRow: true, + header: Text( + context.l10n.match_scorecard_fall_of_wicket_text, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + )), + Container( + width: double.infinity, + color: context.colorScheme.surface, + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), + child: Text.rich( + TextSpan( + children: _buildFallOfWicketText(context, oversWithWicket)), + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textPrimary), + ), + ), + ], + ); } - (String?, String?, WicketType?) _getWicketDetail( - MatchDetailTabState state, - List bowlingSquad, - String inningId, - String batsManId, + List _buildFallOfWicketText( + BuildContext context, + List oversWithWicket, ) { - final batScore = state.ballScores - .where( - (element) => - element.inning_id == inningId && - element.player_out_id == batsManId, - ) - .firstOrNull; - if (batScore == null) { - return (null, null, null); + List children = []; + + for (int index = 0; index < oversWithWicket.length; index++) { + final batsmen = oversWithWicket[index]; + children.add(TextSpan(text: "${batsmen.runs} (")); + children.add(TextSpan( + text: batsmen.player.name, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.secondary))); + children.add(TextSpan( + text: + ", ${batsmen.outAtOver})${index == oversWithWicket.length - 1 ? "" : ", "}")); } - - final bowlerName = bowlingSquad - .where((element) => element.player.id == batScore.bowler_id) - .firstOrNull - ?.player - .name; - final fielderName = bowlingSquad - .where((element) => element.player.id == batScore.wicket_taker_id) - .firstOrNull - ?.player - .name; - - return (bowlerName, fielderName, batScore.wicket_type); + return children; } - List _buildBowlerList( + Widget _powerPlayView( BuildContext context, - MatchDetailTabState state, { - required String inningId, - required List players, - }) { - List children = []; - for (final player in players) { - final (over, maiden, runsConceded, wicket, noBall, wideBall, economy) = - _getBowlingPerformance(state, inningId, player.player.id); - if (over != null) { + List> powerPlays, + List inningOvers, + ) { + if (powerPlays.isEmpty) { + return const SizedBox(); + } else { + List children = []; + children.add(_tableRow(context, + data: [ + context.l10n.match_scorecard_over_text, + context.l10n.match_scorecard_run_text + ], + highlightRow: true, + header: Text( + context.l10n.match_scorecard_power_play_text, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ))); + int index = 0; + for (var powerPlay in powerPlays) { + final start = powerPlay.first; + final end = powerPlay.last; + index++; children.add(_tableRow(context, - highlightColumnNumber: 3, data: [ - over.toStringAsFixed(1), - maiden.toString(), - runsConceded.toString(), - wicket.toString(), - noBall.toString(), - wideBall.toString(), - economy.toStringAsFixed(1) + "$start-$end", + "${_getTotalRunsBetweenOvers(inningOvers, start, end)}" ], - header: Text("${player.player.name}"))); + header: Text( + context.l10n.power_play_text(index), + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ))); } + return Column( + children: children, + ); } - return children; } - (double?, int, int, int, int, int, double) _getBowlingPerformance( - MatchDetailTabState state, - String inningId, - String bowlerId, - ) { - final batScore = state.ballScores.where( - (element) => - element.inning_id == inningId && - element.bowler_id == bowlerId && - element.extras_type != ExtrasType.penaltyRun && - element.wicket_type != WicketType.timedOut && - element.wicket_type != WicketType.retiredHurt && - element.wicket_type != WicketType.retired, - ); - if (batScore.isEmpty) { - return (null, 0, 0, 0, 0, 0, 0); - } - int ball = 0; - int maiden = 0; - int run = 0; - int wicket = 0; - int noBall = 0; - int wide = 0; - - for (var element in batScore) { - if (element.extras_type == ExtrasType.noBall) { - final extra = (element.extras_awarded ?? 0) > 1 - ? (element.extras_awarded ?? 1) - 1 - : 0; - run = run + element.runs_scored + extra; - noBall = noBall + 1; - } else if (element.extras_type == ExtrasType.wide) { - wide = wide + 1; + List> groupOversByInning(List overs) { + Map> groupedOvers = {}; + + for (var over in overs) { + if (groupedOvers.containsKey(over.inning_id)) { + groupedOvers[over.inning_id]!.add(over); } else { - run = run + element.runs_scored + (element.extras_awarded ?? 0); - ball = ball + 1; - if (element.wicket_type != null) { - wicket = wicket + 1; - } + groupedOvers[over.inning_id] = [over]; } } - final over = ball / 6; - final economy = run / over; - return ( - over, - maiden, - run, - wicket, - noBall, - wide, - economy.isNaN ? 0 : economy - ); + + return groupedOvers.values.toList(); } - Widget _winnerMessageText(BuildContext context, MatchModel match) { - final winSummary = match.getWinnerSummary(context); - if (match.match_status == MatchStatus.finish && winSummary != null) { - if (winSummary.teamName.isEmpty) { - return Padding( - padding: const EdgeInsets.all(16), - child: Text( - context.l10n.score_board_match_tied_text, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.primary), - ), - ); - } - return Padding( - padding: const EdgeInsets.all(16), - child: WonByMessageText( - teamName: winSummary.teamName, - difference: winSummary.difference, - trailingText: winSummary.wonByText, - ), - ); - } else { - return const SizedBox(); + String _getTeamNameByTeamId(MatchDetailTabState state, String teamId) { + return state.match?.teams + .where((element) => element.team.id == teamId) + .firstOrNull + ?.team + .name ?? + ""; + } + + List _getBatsmen(List inningOvers) { + final lastOver = inningOvers.lastOrNull; + List batsmen = + inningOvers.expand((over) => over.outPlayers).toList(); + if (!batsmen + .map((e) => e.player.id) + .contains(lastOver?.striker.player.id) && + lastOver != null) { + batsmen.add(lastOver.striker); + } + if (!batsmen + .map((e) => e.player.id) + .contains(lastOver?.nonStriker.player.id) && + lastOver != null) { + batsmen.add(lastOver.nonStriker); + } + + // remove duplicate + Map batsManMap = {}; + for (final batsman in batsmen) { + batsManMap[batsman.player.id] = batsman; } + + return batsManMap.values.toList(); } - Widget _teamTitleView(BuildContext context, MatchTeamModel team, int wicket) { - return Container( - color: context.colorScheme.primary, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - team.team.name, - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary, fontSize: 20), - ), - Text( - "${team.run} - $wicket ${context.l10n.match_commentary_trailing_over_short_text(team.over)}", - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary, fontSize: 20), - ) - ], - ), - ); + List _getBowlers(List inningOvers) { + Map bowlerMap = {}; + + // remove duplicate + for (OverSummary over in inningOvers) { + bowlerMap[over.bowler.player.id] = over.bowler; + } + List bowlers = bowlerMap.values.toList(); + + return bowlers; + } + + int _getTotalRunsBetweenOvers( + List inningOvers, + int startOver, + int endOver, + ) { + if (startOver > endOver) return 0; + final runsBeforeStartOver = + (startOver - 1).isNegative || (startOver - 1) == 0 + ? 0 + : inningOvers + .where((element) => element.overNumber == startOver - 1) + .firstOrNull + ?.totalRuns ?? + 0; + + final runsAfterEndOver = inningOvers + .where((element) => element.overNumber == endOver) + .firstOrNull + ?.totalRuns ?? + 0; + + return runsAfterEndOver - runsBeforeStartOver; } } diff --git a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_squad_view.dart b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_squad_view.dart index 55225722..d3154f75 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/match_detail_squad_view.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/match_detail_squad_view.dart @@ -1,4 +1,3 @@ -import 'package:data/api/match/match_model.dart'; import 'package:data/api/user/user_models.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -30,136 +29,195 @@ class MatchDetailSquadView extends ConsumerWidget { if (state.error != null) { return ErrorScreen( error: state.error, - onRetryTap: () async { - await notifier.cancelStreamSubscription(); - notifier.loadMatch(); - }, + onRetryTap: notifier.onResume, ); } + return _listView(context, state); + } + + Widget _listView(BuildContext context, MatchDetailTabState state) { + final firstTeam = state.match!.teams.firstOrNull; + final secondTeam = state.match!.teams.elementAtOrNull(1); + final firstTeamSquad = firstTeam?.squad.map((e) => e.player).toList() ?? []; + final secondTeamSquad = + secondTeam?.squad.map((e) => e.player).toList() ?? []; + + final firstTeamBench = firstTeam?.team.players + ?.where((element) => + !firstTeamSquad.map((e) => e.id).contains(element.id)) + .toList() ?? + []; + + final secondTeamBench = secondTeam?.team.players + ?.where((element) => + !secondTeamSquad.map((e) => e.id).contains(element.id)) + .toList() ?? + []; + return ListView( - padding: context.mediaQueryPadding, - children: _buildTeamList(context, state)); + padding: context.mediaQueryPadding, + children: [ + _teamNameView(context, + firstTeamName: firstTeam?.team.name ?? "", + secondTeamName: secondTeam?.team.name ?? ""), + ..._buildTeamList(context, + title: context.l10n.match_squad_playing_title, + firstTeamPlayers: firstTeamSquad, + secondPlayers: secondTeamSquad, + firstTeamCaptainId: state.match!.teams.firstOrNull?.captain_id, + secondTeamCaptainId: + state.match!.teams.elementAtOrNull(1)?.captain_id), + ..._buildTeamList(context, + title: context.l10n.match_squad_bench_title, + firstTeamPlayers: firstTeamBench, + secondPlayers: secondTeamBench) + ], + ); } - List _buildTeamList(BuildContext context, MatchDetailTabState state) { - List children = []; - if (state.match == null) { - return children; - } - for (final team in state.match!.teams) { - children.add(_sectionTitleView(context, team.team.name)); - children.add(const SizedBox(height: 8)); - children.addAll(_buildSquadList( - context, - team.squad, - captainId: team.captain_id ?? "", - )); - children.addAll(_buildBenchList(context, team)); - children.add(const SizedBox(height: 16)); - } - return children; + Widget _teamNameView( + BuildContext context, { + required String firstTeamName, + required String secondTeamName, + }) { + return Container( + color: context.colorScheme.containerLow, + child: Row( + children: [ + Expanded( + child: _titleView( + context, + title: firstTeamName, + textAlign: TextAlign.left, + verticalPadding: 8, + textStyle: AppTextStyle.header4, + )), + _titleView(context, + title: context.l10n.common_versus_short_title, + verticalPadding: 8), + Expanded( + child: _titleView( + context, + title: secondTeamName, + textAlign: TextAlign.right, + verticalPadding: 8, + textStyle: AppTextStyle.header4, + )), + ], + ), + ); } - List _buildSquadList( - BuildContext context, - List squad, { - required String captainId, + List _buildTeamList( + BuildContext context, { + required String title, + required List firstTeamPlayers, + required List secondPlayers, + String? firstTeamCaptainId, + String? secondTeamCaptainId, }) { List children = []; - for (final player in squad) { - children.add(const SizedBox(height: 8)); - - children.add(_squadCellView( - context, - player.player, - isCaptain: player.player.id == captainId, - )); + final listLength = firstTeamPlayers.length > firstTeamPlayers.length + ? firstTeamPlayers.length + : firstTeamPlayers.length; + if (listLength > 0) { + children.add(const SizedBox(height: 16)); + children.add(_titleView(context, title: title)); } - return children; - } - List _buildBenchList(BuildContext context, MatchTeamModel team) { - List children = []; - final squadPlayerIds = team.squad.map((e) => e.player.id).toSet(); - final players = team.team.players - ?.where((element) => !squadPlayerIds.contains(element.id)) - .toList(); - if (players == null || players.isEmpty) { - return children; - } - children.add(_sectionTitleView( - context, - context.l10n.match_squad_bench_text, - isSemiTitle: false, - )); - for (final player in players) { - children.add(_squadCellView( - context, - player, - isCaptain: false, + for (int index = 0; index < listLength; index++) { + final firstTeamPlayer = firstTeamPlayers.elementAtOrNull(index); + final secondTeamPlayer = secondPlayers.elementAtOrNull(index); + children.add(Padding( + padding: EdgeInsets.symmetric(horizontal: index == 0 ? 0 : 16), + child: Divider( + height: 0, + color: context.colorScheme.outline, + ), + )); + children.add(Row( + children: [ + Expanded( + child: _playerProfileView(context, + user: firstTeamPlayer, captainId: firstTeamCaptainId)), + Expanded( + child: _playerProfileView(context, + user: secondTeamPlayer, + isFirstCell: false, + captainId: secondTeamCaptainId)) + ], )); } return children; } - Widget _sectionTitleView( - BuildContext context, - String title, { - bool isSemiTitle = true, + Widget _titleView( + BuildContext context, { + required String title, + TextAlign textAlign = TextAlign.center, + TextStyle textStyle = AppTextStyle.subtitle1, + double verticalPadding = 12, }) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - color: isSemiTitle - ? context.colorScheme.containerNormalOnSurface - : Colors.transparent, + return Padding( + padding: EdgeInsets.symmetric(vertical: verticalPadding, horizontal: 16), child: Text( title, - style: isSemiTitle - ? AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary) - : AppTextStyle.header3 - .copyWith(color: context.colorScheme.textPrimary), + maxLines: 2, + overflow: TextOverflow.ellipsis, + textAlign: textAlign, + style: textStyle.copyWith(color: context.colorScheme.textPrimary), ), ); } - Widget _squadCellView( - BuildContext context, - UserModel player, { - bool isCaptain = false, + Widget _playerProfileView( + BuildContext context, { + UserModel? user, + bool isFirstCell = true, + String? captainId, }) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + if (user == null) { + return const SizedBox(); + } + bool isCaptain = user.id == captainId; + return Container( + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), + decoration: BoxDecoration( + border: BorderDirectional( + end: BorderSide( + color: isFirstCell + ? context.colorScheme.outline + : Colors.transparent))), child: Row( children: [ ImageAvatar( - initial: player.nameInitial, - imageUrl: player.profile_img_url, - size: 50, + initial: user.nameInitial, + imageUrl: user.profile_img_url, + size: 40, ), - const SizedBox( - width: 8, + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + user.name == null + ? context.l10n.common_anonymous_title + : "${user.name}${isCaptain ? context.l10n.match_info_captain_short_title : ""}", + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + Text( + user.player_role != null + ? user.player_role!.getString(context) + : context.l10n.common_not_specified_title, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled)), + ], + ), ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "${player.name}${isCaptain ? context.l10n.match_info_captain_short_title : ""}", - style: AppTextStyle.header4 - .copyWith(color: context.colorScheme.textPrimary), - ), - const SizedBox( - height: 4, - ), - Text( - player.player_role?.getString(context) ?? "", - style: AppTextStyle.subtitle1 - .copyWith(color: context.colorScheme.textPrimary), - ) - ], - ) ], ), ); diff --git a/khelo/lib/ui/flow/matches/match_detail/components/over_score_view.dart b/khelo/lib/ui/flow/matches/match_detail/components/over_score_view.dart index 4373f4b9..8337141e 100644 --- a/khelo/lib/ui/flow/matches/match_detail/components/over_score_view.dart +++ b/khelo/lib/ui/flow/matches/match_detail/components/over_score_view.dart @@ -13,8 +13,8 @@ class OverScoreView extends StatelessWidget { @override Widget build(BuildContext context) { return Wrap( - runSpacing: 4, - spacing: 4, + runSpacing: 8, + spacing: 8, children: over.map((ball) { return BallScoreView( ball: ball, @@ -44,7 +44,7 @@ class BallScoreView extends StatelessWidget { ), child: Text( title, - style: AppTextStyle.header4.copyWith(color: textColor), + style: AppTextStyle.caption.copyWith(color: textColor), ), ); } @@ -80,10 +80,10 @@ class BallScoreView extends StatelessWidget { ? context.colorScheme.secondary : ball.is_six ? context.colorScheme.primary - : context.colorScheme.containerNormalOnSurface, + : context.colorScheme.containerLow, (ball.is_four || ball.is_six) - ? context.colorScheme.textInversePrimary - : context.colorScheme.secondary + ? context.colorScheme.onPrimary + : context.colorScheme.textDisabled ); } } diff --git a/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_screen.dart b/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_screen.dart index 2b2b8542..a00129a2 100644 --- a/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_screen.dart +++ b/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_screen.dart @@ -2,9 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/app_page.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/string_extensions.dart'; import 'package:khelo/domain/extensions/widget_extension.dart'; import 'package:khelo/ui/flow/matches/match_detail/match_detail_tab_view_model.dart'; -import 'package:style/extensions/context_extensions.dart'; +import 'package:style/button/tab_button.dart'; class MatchDetailTabScreen extends ConsumerStatefulWidget { final String matchId; @@ -17,39 +18,100 @@ class MatchDetailTabScreen extends ConsumerStatefulWidget { class _MatchDetailTabScreenState extends ConsumerState { late MatchDetailTabViewNotifier notifier; + late PageController _controller; + final ScrollController _scrollController = ScrollController(); + + int get _selectedTab => _controller.hasClients + ? _controller.page?.round() ?? 0 + : _controller.initialPage; @override void initState() { super.initState(); notifier = ref.read(matchDetailTabStateProvider.notifier); runPostFrame(() => notifier.setData(widget.matchId)); + _controller = PageController( + initialPage: ref.read(matchDetailTabStateProvider).selectedTab, + ); + } + + final List _keys = List.generate(50, (index) => GlobalKey()); + + void _scrollToIndex(int index) { + _scrollController.position.ensureVisible( + _keys[index].currentContext!.findRenderObject() as RenderBox, + duration: const Duration(milliseconds: 400), + curve: Curves.easeInOut); } @override Widget build(BuildContext context) { - notifier = ref.watch(matchDetailTabStateProvider.notifier); - - return DefaultTabController( - length: MatchDetailTab.values.length, - child: AppPage( - title: context.l10n.match_detail_screen_title, - tabBar: TabBar( - tabAlignment: TabAlignment.start, - indicatorColor: context.colorScheme.primary, - labelColor: context.colorScheme.primary, - unselectedLabelColor: context.colorScheme.textSecondary, - dividerColor: context.colorScheme.outline, - splashFactory: NoSplash.splashFactory, - isScrollable: true, - tabs: MatchDetailTab.values - .map((tab) => Tab(text: tab.getString(context))) - .toList(), - ), - body: TabBarView( - children: MatchDetailTab.values - .map((tab) => tab.getTabScreen()) - .toList()), + final state = ref.watch(matchDetailTabStateProvider); + + return AppPage( + title: _getScreenTitle(context, state), + body: Builder( + builder: (context) { + return _content(context, notifier); + }, ), ); } + + String _getScreenTitle(BuildContext context, MatchDetailTabState state) { + if (state.match != null) { + String title = state.match!.teams + .map((e) => e.team.name.initials(limit: 3)) + .join(" ${context.l10n.common_versus_short_title} "); + return title; + } + return "${context.l10n.common_a_title} ${context.l10n.common_versus_short_title} ${context.l10n.add_match_team_b_title}"; + } + + Widget _content(BuildContext context, MatchDetailTabViewNotifier notifier) { + return SafeArea( + child: Column( + children: [ + _tabView(context), + Expanded( + child: PageView( + controller: _controller, + children: MatchDetailTab.values + .map((tab) => tab.getTabScreen()) + .toList(), + onPageChanged: (index) { + notifier.onTabChange(index); + _scrollToIndex(index); + setState(() {}); + }, + ), + ), + ], + ), + ); + } + + Widget _tabView(BuildContext context) { + return SingleChildScrollView( + controller: _scrollController, + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), + child: Row( + children: MatchDetailTab.values + .map( + (tab) => Padding( + padding: const EdgeInsets.only(right: 16), + child: TabButton( + tab.getString(context), + selected: _selectedTab == tab.index, + globalKey: _keys[tab.index], + onTap: () { + _controller.jumpToPage(tab.index); + }, + ), + ), + ) + .toList()), + ); + } } diff --git a/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_view_model.dart b/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_view_model.dart index e98c624b..2edc13ea 100644 --- a/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_view_model.dart +++ b/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_view_model.dart @@ -1,13 +1,14 @@ import 'dart:async'; - import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/ball_score/ball_score_model.dart'; import 'package:data/api/innings/inning_model.dart'; import 'package:data/api/match/match_model.dart'; +import 'package:data/errors/app_error.dart'; import 'package:data/service/ball_score/ball_score_service.dart'; import 'package:data/service/innings/inning_service.dart'; import 'package:data/service/match/match_service.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; @@ -17,6 +18,7 @@ import 'package:khelo/ui/flow/matches/match_detail/components/match_detail_info_ import 'package:khelo/ui/flow/matches/match_detail/components/match_detail_overs_view.dart'; import 'package:khelo/ui/flow/matches/match_detail/components/match_detail_scorecard_view.dart'; import 'package:khelo/ui/flow/matches/match_detail/components/match_detail_squad_view.dart'; +import 'package:rxdart/rxdart.dart'; part 'match_detail_tab_view_model.freezed.dart'; @@ -35,7 +37,6 @@ class MatchDetailTabViewNotifier extends StateNotifier { final BallScoreService _ballScoreService; late String _matchId; late StreamSubscription matchStreamSubscription; - late StreamSubscription inningStreamSubscription; late StreamSubscription ballScoreStreamSubscription; MatchDetailTabViewNotifier( @@ -46,70 +47,66 @@ class MatchDetailTabViewNotifier extends StateNotifier { void setData(String matchId) { _matchId = matchId; - loadMatch(); + _loadMatchesAndInning(); } - void loadMatch() { - state = state.copyWith(loading: true); - matchStreamSubscription = _matchService.getMatchStreamById(_matchId).listen( - (match) { - state = state.copyWith( - match: match, - highlightTeamId: match.teams.first.team.id, - error: null); - if (!state.inningsQueryListenerSet) { - _loadInnings(); - } - }, - onError: (e, stack) { - state = state.copyWith( - error: state.match == null ? e : null, loading: false); - debugPrint( - "MatchDetailTabViewNotifier: error while load match -> $e. \n stack -> $stack"); - }, - ); - } + void _loadMatchesAndInning() { + try { + state = state.copyWith(loading: true); + final matchInningStream = Rx.combineLatest2( + _matchService.getMatchStreamById(_matchId), + _inningService.getInningsStreamByMatchId(matchId: _matchId), + (match, innings) => (match: match, innings: innings), + ); - void _loadInnings() { - if (state.match == null) { - return; - } - if (state.match?.match_status == MatchStatus.yetToStart) { - state = state.copyWith(loading: false); - return; - } - state = state.copyWith(inningsQueryListenerSet: true); - inningStreamSubscription = - _inningService.getInningsStreamByMatchId(matchId: _matchId).listen( - (innings) { - final firstInning = innings.firstWhere((element) => - (state.match?.toss_decision == TossDecision.bat && - element.team_id == state.match?.toss_winner_id) || - (state.match?.toss_decision == TossDecision.bowl && - element.team_id != state.match?.toss_winner_id)); - - final secondInning = innings.firstWhere((element) => - (state.match?.toss_decision == TossDecision.bowl && - element.team_id == state.match?.toss_winner_id) || - (state.match?.toss_decision == TossDecision.bat && - element.team_id != state.match?.toss_winner_id)); + matchStreamSubscription = matchInningStream.listen((data) { + final match = data.match; + final innings = data.innings; + state = state.copyWith(match: match); + final firstInning = innings + .where((element) => + (state.match?.toss_decision == TossDecision.bat && + element.team_id == state.match?.toss_winner_id) || + (state.match?.toss_decision == TossDecision.bowl && + element.team_id != state.match?.toss_winner_id)) + .firstOrNull; + final secondInning = innings + .where((element) => + (state.match?.toss_decision == TossDecision.bowl && + element.team_id == state.match?.toss_winner_id) || + (state.match?.toss_decision == TossDecision.bat && + element.team_id != state.match?.toss_winner_id)) + .firstOrNull; + + onScorecardExpansionChange( + match.matchResult?.teamId ?? match.teams.firstOrNull?.team.id ?? "", + true, + ); state = state.copyWith( - firstInning: firstInning, secondInning: secondInning, error: null); + highlightTeamId: state.highlightTeamId ?? match.teams.first.team.id, + firstInning: firstInning, + secondInning: secondInning, + error: null); + if (!state.ballScoreQueryListenerSet) { _loadBallScores(); } - }, - onError: (e, stack) { - state = state.copyWith(error: e, loading: false); + }, onError: (e) { debugPrint( - "MatchDetailTabViewNotifier: error while load innings -> $e. \n stack -> $stack"); - }, - ); + "MatchDetailTabViewNotifier: error while loading match and inning -> $e"); + state = state.copyWith(error: AppError.fromError(e), loading: false); + }); + } catch (e) { + debugPrint( + "MatchDetailTabViewNotifier: error while loading match and inning -> $e"); + state = state.copyWith(error: AppError.fromError(e), loading: false); + } } void _loadBallScores() { if (state.firstInning == null || state.secondInning == null) { + state = state.copyWith(loading: false); return; } state = state.copyWith(ballScoreQueryListenerSet: true); @@ -120,53 +117,289 @@ class MatchDetailTabViewNotifier extends StateNotifier { state.secondInning?.id ?? "INVALID ID" ]).listen( (scores) { - List sortedList = state.ballScores.toList(); - for (final score in scores) { + final sortedList = scores.toList(); + sortedList.sort((a, b) => a.ballScore.time.compareTo(b.ballScore.time)); + + final overList = state.overList.toList(); + for (final score in sortedList) { if (score.type == DocumentChangeType.added) { - sortedList.add(score.ballScore); + final overSummary = + _configureOverSummary(overList, score.ballScore); + overList.removeWhere((element) => + element.overNumber == overSummary?.overNumber && + element.inning_id == overSummary?.inning_id); + if (overSummary != null) { + overList.add(overSummary); + } } else if (score.type == DocumentChangeType.removed) { - sortedList - .removeWhere((element) => element.id == score.ballScore.id); + final overSummary = + _configureOverSummary(overList, score.ballScore, isUndo: true); + overList.removeWhere((element) => + element.overNumber == score.ballScore.over_number && + element.inning_id == score.ballScore.inning_id); + if (overSummary != null) { + overList.add(overSummary); + } } } - sortedList.sort( - (a, b) => a.time.compareTo(b.time), - ); - state = - state.copyWith(ballScores: sortedList, loading: false, error: null); + + overList.sort((a, b) => a.time.compareTo(b.time)); + state = state.copyWith(overList: overList, loading: false, error: null); + changeHighlightFilter(); }, onError: (e, stack) { state = state.copyWith(error: e, loading: false); debugPrint( - "MatchDetailTabViewNotifier: error while load ball scores -> $e. \n stack -> $stack"); + "MatchDetailTabViewNotifier: error while load ball scores -> $e"); }, ); } - showHighlightTeamSelectionDialog() { + OverSummary? _configureOverSummary( + List overList, + BallScoreModel ball, { + bool isUndo = false, + }) { + if (isUndo) { + final overToUpdate = overList.firstWhere((element) => + element.overNumber == ball.over_number && + element.inning_id == ball.inning_id); + return overToUpdate.removeBall(ball); + } + + BatsmanSummary striker = _configureBatsman( + overList: overList, + playerId: ball.batsman_id, + inningId: ball.inning_id); + BatsmanSummary nonStriker = _configureBatsman( + overList: overList, + playerId: ball.non_striker_id, + inningId: ball.inning_id); + + final lastPlayerSummary = overList + .where( + (element) => + element.inning_id == ball.inning_id && + element.bowler.player.id == ball.bowler_id, + ) + .lastOrNull + ?.bowler; + BowlerSummary bowler = _configureBowler( + inningId: ball.inning_id, + playerId: ball.bowler_id, + lastPlayerSummary: lastPlayerSummary); + Player? catchBy; + if (ball.wicket_taker_id != null) { + catchBy = _getPlayerByInningId( + inningId: ball.inning_id, + playerId: ball.wicket_taker_id!, + isFieldingTeam: true); + } + + final currentOver = overList + .where((element) => + element.overNumber == ball.over_number && + element.inning_id == ball.inning_id) + .firstOrNull; + + if (currentOver != null) { + return currentOver + .copyWith(striker: striker, nonStriker: nonStriker, bowler: bowler) + .addBall(ball, catchBy: catchBy); + } else { + final lastOver = overList + .where((element) => + element.overNumber == ball.over_number - 1 && + element.inning_id == ball.inning_id) + .firstOrNull; + return OverSummary( + inning_id: ball.inning_id, + overNumber: ball.over_number, + team_id: _getTeamIdByInningId(ball.inning_id), + striker: striker, + nonStriker: nonStriker, + bowler: bowler, + totalRuns: lastOver?.inning_id == ball.inning_id + ? lastOver?.totalRuns ?? 0 + : 0, + totalWickets: lastOver?.inning_id == ball.inning_id + ? lastOver?.totalWickets ?? 0 + : 0) + .addBall(ball, catchBy: catchBy); + } + } + + String _getTeamIdByInningId(String inningId) { + final teamId = state.firstInning?.id == inningId + ? state.firstInning?.team_id + : state.secondInning?.team_id; + return teamId ?? ""; + } + + BowlerSummary _configureBowler({ + BowlerSummary? lastPlayerSummary, + required String inningId, + required String playerId, + }) { + BowlerSummary? bowler = lastPlayerSummary; + + if (bowler == null) { + final player = _getPlayerByInningId( + inningId: inningId, playerId: playerId, isFieldingTeam: true); + bowler = BowlerSummary(player: player); + } + + return bowler; + } + + int getFractionalPart(double value) { + String valueString = value.toString(); + + List parts = valueString.split('.'); + + if (parts.length > 1) { + return int.parse(parts[1]); + } else { + return 0; + } + } + + BatsmanSummary _configureBatsman({ + required List overList, + required String playerId, + required String inningId, + }) { + OverSummary? lastPlayerContainedOver = overList + .where((element) => + element.inning_id == inningId && + (element.striker.player.id == playerId || + element.nonStriker.player.id == playerId)) + .lastOrNull; + BatsmanSummary? lastBatsman; + if (lastPlayerContainedOver != null) { + lastBatsman = lastPlayerContainedOver.striker.player.id == playerId + ? lastPlayerContainedOver.striker + : lastPlayerContainedOver.nonStriker; + } + if (lastBatsman == null) { + final overContainingOutPlayers = overList + .where((element) => + element.inning_id == inningId && + element.outPlayers.any((e) => e.player.id == playerId)) + .lastOrNull; + lastBatsman = overContainingOutPlayers?.outPlayers + .firstWhere((element) => element.player.id == playerId); + } + if (lastBatsman == null) { + Player player = + _getPlayerByInningId(inningId: inningId, playerId: playerId); + lastBatsman = BatsmanSummary(player: player); + } + + return lastBatsman; + } + + Player _getPlayerByInningId({ + required String inningId, + required String playerId, + bool isFieldingTeam = false, + }) { + final teamId = [state.firstInning, state.secondInning] + .where((element) => + isFieldingTeam ? element?.id != inningId : element?.id == inningId) + .firstOrNull + ?.team_id; + + final player = state.match?.teams + .where((element) => teamId == element.team.id) + .firstOrNull + ?.squad + .where((element) => element.player.id == playerId) + .firstOrNull + ?.player; + + return Player(id: player?.id ?? "", name: player?.name ?? ""); + } + + void showHighlightTeamSelectionDialog() { state = state.copyWith(showTeamSelectionSheet: DateTime.now()); } - showHighlightFilterSelectionDialog() { + void showHighlightFilterSelectionDialog() { state = state.copyWith(showHighlightOptionSelectionSheet: DateTime.now()); } - onHighlightFilterSelection(HighlightFilterOption selection) { + void onHighlightFilterSelection(HighlightFilterOption selection) { + if (state.highlightFilterOption == selection) return; + state = state.copyWith(highlightFilterOption: selection); + changeHighlightFilter(); } - onHighlightTeamSelection(String teamId) { + void onHighlightTeamSelection(String teamId) { + if (state.highlightTeamId == teamId) return; + state = state.copyWith(highlightTeamId: teamId); + changeHighlightFilter(); + } + + void changeHighlightFilter() { + final highlightList = state.overList.where((element) { + return element.team_id == state.highlightTeamId && + element.balls.any(shouldIncludeInHighlight); + }).map((over) { + final filteredBalls = over.balls.where(shouldIncludeInHighlight).toList(); + return over.copyWith(balls: filteredBalls); + }).toList(); + + state = state.copyWith(filteredHighlight: highlightList); + } + + bool shouldIncludeInHighlight(BallScoreModel ball) { + switch (state.highlightFilterOption) { + case HighlightFilterOption.all: + return ball.extras_type != null || + ball.wicket_type != null || + ball.is_six || + ball.is_four; + case HighlightFilterOption.fours: + return ball.is_four; + case HighlightFilterOption.sixes: + return ball.is_six; + case HighlightFilterOption.wickets: + return ball.wicket_type != null && + ball.wicket_type != WicketType.retiredHurt; + } } - cancelStreamSubscription() async { - state = state.copyWith( - inningsQueryListenerSet: false, ballScoreQueryListenerSet: false); + Future cancelStreamSubscription() async { + state = state.copyWith(ballScoreQueryListenerSet: false); await matchStreamSubscription.cancel(); - await inningStreamSubscription.cancel(); await ballScoreStreamSubscription.cancel(); } + void onTabChange(int tab) { + if (state.selectedTab != tab) { + state = state.copyWith(selectedTab: tab); + } + } + + void onScorecardExpansionChange(String teamId, bool isExpanded) { + List expandedList = state.expandedTeamScorecard.toList(); + if (isExpanded) { + expandedList.add(teamId); + } else { + expandedList.remove(teamId); + } + state = + state.copyWith(expandedTeamScorecard: expandedList.toSet().toList()); + } + + Future onResume() async { + await cancelStreamSubscription(); + _loadMatchesAndInning(); + } + @override void dispose() { cancelStreamSubscription(); @@ -184,9 +417,11 @@ class MatchDetailTabState with _$MatchDetailTabState { String? highlightTeamId, DateTime? showTeamSelectionSheet, DateTime? showHighlightOptionSelectionSheet, - @Default([]) List ballScores, + @Default(0) int selectedTab, + @Default([]) List overList, + @Default([]) List filteredHighlight, + @Default([]) List expandedTeamScorecard, @Default(false) bool loading, - @Default(false) bool inningsQueryListenerSet, @Default(false) bool ballScoreQueryListenerSet, @Default(HighlightFilterOption.all) HighlightFilterOption highlightFilterOption, diff --git a/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_view_model.freezed.dart b/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_view_model.freezed.dart index 24b3a41f..cae6b9f6 100644 --- a/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_view_model.freezed.dart +++ b/khelo/lib/ui/flow/matches/match_detail/match_detail_tab_view_model.freezed.dart @@ -24,9 +24,11 @@ mixin _$MatchDetailTabState { DateTime? get showTeamSelectionSheet => throw _privateConstructorUsedError; DateTime? get showHighlightOptionSelectionSheet => throw _privateConstructorUsedError; - List get ballScores => throw _privateConstructorUsedError; + int get selectedTab => throw _privateConstructorUsedError; + List get overList => throw _privateConstructorUsedError; + List get filteredHighlight => throw _privateConstructorUsedError; + List get expandedTeamScorecard => throw _privateConstructorUsedError; bool get loading => throw _privateConstructorUsedError; - bool get inningsQueryListenerSet => throw _privateConstructorUsedError; bool get ballScoreQueryListenerSet => throw _privateConstructorUsedError; HighlightFilterOption get highlightFilterOption => throw _privateConstructorUsedError; @@ -50,9 +52,11 @@ abstract class $MatchDetailTabStateCopyWith<$Res> { String? highlightTeamId, DateTime? showTeamSelectionSheet, DateTime? showHighlightOptionSelectionSheet, - List ballScores, + int selectedTab, + List overList, + List filteredHighlight, + List expandedTeamScorecard, bool loading, - bool inningsQueryListenerSet, bool ballScoreQueryListenerSet, HighlightFilterOption highlightFilterOption}); @@ -81,9 +85,11 @@ class _$MatchDetailTabStateCopyWithImpl<$Res, $Val extends MatchDetailTabState> Object? highlightTeamId = freezed, Object? showTeamSelectionSheet = freezed, Object? showHighlightOptionSelectionSheet = freezed, - Object? ballScores = null, + Object? selectedTab = null, + Object? overList = null, + Object? filteredHighlight = null, + Object? expandedTeamScorecard = null, Object? loading = null, - Object? inningsQueryListenerSet = null, Object? ballScoreQueryListenerSet = null, Object? highlightFilterOption = null, }) { @@ -114,18 +120,26 @@ class _$MatchDetailTabStateCopyWithImpl<$Res, $Val extends MatchDetailTabState> ? _value.showHighlightOptionSelectionSheet : showHighlightOptionSelectionSheet // ignore: cast_nullable_to_non_nullable as DateTime?, - ballScores: null == ballScores - ? _value.ballScores - : ballScores // ignore: cast_nullable_to_non_nullable - as List, + selectedTab: null == selectedTab + ? _value.selectedTab + : selectedTab // ignore: cast_nullable_to_non_nullable + as int, + overList: null == overList + ? _value.overList + : overList // ignore: cast_nullable_to_non_nullable + as List, + filteredHighlight: null == filteredHighlight + ? _value.filteredHighlight + : filteredHighlight // ignore: cast_nullable_to_non_nullable + as List, + expandedTeamScorecard: null == expandedTeamScorecard + ? _value.expandedTeamScorecard + : expandedTeamScorecard // ignore: cast_nullable_to_non_nullable + as List, loading: null == loading ? _value.loading : loading // ignore: cast_nullable_to_non_nullable as bool, - inningsQueryListenerSet: null == inningsQueryListenerSet - ? _value.inningsQueryListenerSet - : inningsQueryListenerSet // ignore: cast_nullable_to_non_nullable - as bool, ballScoreQueryListenerSet: null == ballScoreQueryListenerSet ? _value.ballScoreQueryListenerSet : ballScoreQueryListenerSet // ignore: cast_nullable_to_non_nullable @@ -190,9 +204,11 @@ abstract class _$$MatchDetailTabStateImplCopyWith<$Res> String? highlightTeamId, DateTime? showTeamSelectionSheet, DateTime? showHighlightOptionSelectionSheet, - List ballScores, + int selectedTab, + List overList, + List filteredHighlight, + List expandedTeamScorecard, bool loading, - bool inningsQueryListenerSet, bool ballScoreQueryListenerSet, HighlightFilterOption highlightFilterOption}); @@ -222,9 +238,11 @@ class __$$MatchDetailTabStateImplCopyWithImpl<$Res> Object? highlightTeamId = freezed, Object? showTeamSelectionSheet = freezed, Object? showHighlightOptionSelectionSheet = freezed, - Object? ballScores = null, + Object? selectedTab = null, + Object? overList = null, + Object? filteredHighlight = null, + Object? expandedTeamScorecard = null, Object? loading = null, - Object? inningsQueryListenerSet = null, Object? ballScoreQueryListenerSet = null, Object? highlightFilterOption = null, }) { @@ -255,18 +273,26 @@ class __$$MatchDetailTabStateImplCopyWithImpl<$Res> ? _value.showHighlightOptionSelectionSheet : showHighlightOptionSelectionSheet // ignore: cast_nullable_to_non_nullable as DateTime?, - ballScores: null == ballScores - ? _value._ballScores - : ballScores // ignore: cast_nullable_to_non_nullable - as List, + selectedTab: null == selectedTab + ? _value.selectedTab + : selectedTab // ignore: cast_nullable_to_non_nullable + as int, + overList: null == overList + ? _value._overList + : overList // ignore: cast_nullable_to_non_nullable + as List, + filteredHighlight: null == filteredHighlight + ? _value._filteredHighlight + : filteredHighlight // ignore: cast_nullable_to_non_nullable + as List, + expandedTeamScorecard: null == expandedTeamScorecard + ? _value._expandedTeamScorecard + : expandedTeamScorecard // ignore: cast_nullable_to_non_nullable + as List, loading: null == loading ? _value.loading : loading // ignore: cast_nullable_to_non_nullable as bool, - inningsQueryListenerSet: null == inningsQueryListenerSet - ? _value.inningsQueryListenerSet - : inningsQueryListenerSet // ignore: cast_nullable_to_non_nullable - as bool, ballScoreQueryListenerSet: null == ballScoreQueryListenerSet ? _value.ballScoreQueryListenerSet : ballScoreQueryListenerSet // ignore: cast_nullable_to_non_nullable @@ -290,12 +316,16 @@ class _$MatchDetailTabStateImpl implements _MatchDetailTabState { this.highlightTeamId, this.showTeamSelectionSheet, this.showHighlightOptionSelectionSheet, - final List ballScores = const [], + this.selectedTab = 0, + final List overList = const [], + final List filteredHighlight = const [], + final List expandedTeamScorecard = const [], this.loading = false, - this.inningsQueryListenerSet = false, this.ballScoreQueryListenerSet = false, this.highlightFilterOption = HighlightFilterOption.all}) - : _ballScores = ballScores; + : _overList = overList, + _filteredHighlight = filteredHighlight, + _expandedTeamScorecard = expandedTeamScorecard; @override final Object? error; @@ -311,21 +341,41 @@ class _$MatchDetailTabStateImpl implements _MatchDetailTabState { final DateTime? showTeamSelectionSheet; @override final DateTime? showHighlightOptionSelectionSheet; - final List _ballScores; @override @JsonKey() - List get ballScores { - if (_ballScores is EqualUnmodifiableListView) return _ballScores; + final int selectedTab; + final List _overList; + @override + @JsonKey() + List get overList { + if (_overList is EqualUnmodifiableListView) return _overList; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_ballScores); + return EqualUnmodifiableListView(_overList); } + final List _filteredHighlight; @override @JsonKey() - final bool loading; + List get filteredHighlight { + if (_filteredHighlight is EqualUnmodifiableListView) + return _filteredHighlight; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_filteredHighlight); + } + + final List _expandedTeamScorecard; @override @JsonKey() - final bool inningsQueryListenerSet; + List get expandedTeamScorecard { + if (_expandedTeamScorecard is EqualUnmodifiableListView) + return _expandedTeamScorecard; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_expandedTeamScorecard); + } + + @override + @JsonKey() + final bool loading; @override @JsonKey() final bool ballScoreQueryListenerSet; @@ -335,7 +385,7 @@ class _$MatchDetailTabStateImpl implements _MatchDetailTabState { @override String toString() { - return 'MatchDetailTabState(error: $error, match: $match, firstInning: $firstInning, secondInning: $secondInning, highlightTeamId: $highlightTeamId, showTeamSelectionSheet: $showTeamSelectionSheet, showHighlightOptionSelectionSheet: $showHighlightOptionSelectionSheet, ballScores: $ballScores, loading: $loading, inningsQueryListenerSet: $inningsQueryListenerSet, ballScoreQueryListenerSet: $ballScoreQueryListenerSet, highlightFilterOption: $highlightFilterOption)'; + return 'MatchDetailTabState(error: $error, match: $match, firstInning: $firstInning, secondInning: $secondInning, highlightTeamId: $highlightTeamId, showTeamSelectionSheet: $showTeamSelectionSheet, showHighlightOptionSelectionSheet: $showHighlightOptionSelectionSheet, selectedTab: $selectedTab, overList: $overList, filteredHighlight: $filteredHighlight, expandedTeamScorecard: $expandedTeamScorecard, loading: $loading, ballScoreQueryListenerSet: $ballScoreQueryListenerSet, highlightFilterOption: $highlightFilterOption)'; } @override @@ -357,12 +407,14 @@ class _$MatchDetailTabStateImpl implements _MatchDetailTabState { showHighlightOptionSelectionSheet) || other.showHighlightOptionSelectionSheet == showHighlightOptionSelectionSheet) && + (identical(other.selectedTab, selectedTab) || + other.selectedTab == selectedTab) && + const DeepCollectionEquality().equals(other._overList, _overList) && + const DeepCollectionEquality() + .equals(other._filteredHighlight, _filteredHighlight) && const DeepCollectionEquality() - .equals(other._ballScores, _ballScores) && + .equals(other._expandedTeamScorecard, _expandedTeamScorecard) && (identical(other.loading, loading) || other.loading == loading) && - (identical( - other.inningsQueryListenerSet, inningsQueryListenerSet) || - other.inningsQueryListenerSet == inningsQueryListenerSet) && (identical(other.ballScoreQueryListenerSet, ballScoreQueryListenerSet) || other.ballScoreQueryListenerSet == ballScoreQueryListenerSet) && @@ -380,9 +432,11 @@ class _$MatchDetailTabStateImpl implements _MatchDetailTabState { highlightTeamId, showTeamSelectionSheet, showHighlightOptionSelectionSheet, - const DeepCollectionEquality().hash(_ballScores), + selectedTab, + const DeepCollectionEquality().hash(_overList), + const DeepCollectionEquality().hash(_filteredHighlight), + const DeepCollectionEquality().hash(_expandedTeamScorecard), loading, - inningsQueryListenerSet, ballScoreQueryListenerSet, highlightFilterOption); @@ -403,9 +457,11 @@ abstract class _MatchDetailTabState implements MatchDetailTabState { final String? highlightTeamId, final DateTime? showTeamSelectionSheet, final DateTime? showHighlightOptionSelectionSheet, - final List ballScores, + final int selectedTab, + final List overList, + final List filteredHighlight, + final List expandedTeamScorecard, final bool loading, - final bool inningsQueryListenerSet, final bool ballScoreQueryListenerSet, final HighlightFilterOption highlightFilterOption}) = _$MatchDetailTabStateImpl; @@ -425,11 +481,15 @@ abstract class _MatchDetailTabState implements MatchDetailTabState { @override DateTime? get showHighlightOptionSelectionSheet; @override - List get ballScores; + int get selectedTab; @override - bool get loading; + List get overList; + @override + List get filteredHighlight; @override - bool get inningsQueryListenerSet; + List get expandedTeamScorecard; + @override + bool get loading; @override bool get ballScoreQueryListenerSet; @override diff --git a/khelo/lib/ui/flow/matches/match_list_screen.dart b/khelo/lib/ui/flow/matches/match_list_screen.dart index 6e37f492..a4f7d371 100644 --- a/khelo/lib/ui/flow/matches/match_list_screen.dart +++ b/khelo/lib/ui/flow/matches/match_list_screen.dart @@ -64,9 +64,7 @@ class _MatchListScreenState extends ConsumerState MatchListViewState state, ) { if (state.loading) { - return const Center( - child: AppProgressIndicator(), - ); + return const Center(child: AppProgressIndicator()); } if (state.error != null) { return ErrorScreen( diff --git a/khelo/lib/ui/flow/profile/profile_screen.dart b/khelo/lib/ui/flow/profile/profile_screen.dart index 22b9d052..c329d386 100644 --- a/khelo/lib/ui/flow/profile/profile_screen.dart +++ b/khelo/lib/ui/flow/profile/profile_screen.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:data/api/user/user_models.dart'; import 'package:data/storage/app_preferences.dart'; import 'package:flutter/material.dart'; @@ -6,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/app_page.dart'; import 'package:khelo/components/confirmation_dialog.dart'; import 'package:khelo/components/error_snackbar.dart'; +import 'package:khelo/components/image_avatar.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; import 'package:khelo/ui/app_route.dart'; import 'package:khelo/ui/flow/profile/profile_view_model.dart'; @@ -70,27 +70,10 @@ class ProfileScreen extends ConsumerWidget { borderRadius: BorderRadius.circular(16)), child: Row( children: [ - Container( - height: 80, - width: 80, - alignment: Alignment.center, - decoration: BoxDecoration( - color: context.colorScheme.containerHigh, - shape: BoxShape.circle, - image: state.currentUser?.profile_img_url != null - ? DecorationImage( - image: CachedNetworkImageProvider( - state.currentUser!.profile_img_url!), - fit: BoxFit.cover) - : null, - ), - child: state.currentUser?.profile_img_url == null - ? Text(state.currentUser?.nameInitial ?? '?', - textAlign: TextAlign.center, - style: AppTextStyle.header2.copyWith( - color: context.colorScheme.textPrimary, - )) - : null, + ImageAvatar( + size: 80, + imageUrl: state.currentUser?.profile_img_url, + initial: state.currentUser?.nameInitial ?? '?', ), const SizedBox( width: 16, diff --git a/khelo/lib/ui/flow/score_board/components/match_complete_sheet.dart b/khelo/lib/ui/flow/score_board/components/match_complete_sheet.dart index b638c9bc..61f60d51 100644 --- a/khelo/lib/ui/flow/score_board/components/match_complete_sheet.dart +++ b/khelo/lib/ui/flow/score_board/components/match_complete_sheet.dart @@ -4,8 +4,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:khelo/components/won_by_message_text.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; -import 'package:khelo/domain/extensions/data_model_extensions/match_model_extension.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/button/primary_button.dart'; @@ -89,7 +89,10 @@ class MatchCompleteSheet extends ConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _winnerMessageText(context, state.match), + WonByMessageText( + matchResult: state.match?.matchResult, + textStyle: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary)), const SizedBox(height: 16), _table(context, state), ], @@ -201,29 +204,4 @@ class MatchCompleteSheet extends ConsumerWidget { : context.colorScheme.textPrimary), ); } - - Widget _winnerMessageText(BuildContext context, MatchModel? match) { - if (match == null) { - return const SizedBox(); - } - final winSummary = match - .copyWith(match_status: MatchStatus.finish) - .getWinnerSummary(context); - if (winSummary != null) { - if (winSummary.teamName.isEmpty) { - return Text( - context.l10n.score_board_match_tied_text, - style: AppTextStyle.subtitle2 - .copyWith(color: context.colorScheme.textPrimary), - ); - } - return Text( - "${winSummary.teamName} ${context.l10n.score_board_won_by_title} ${winSummary.difference} ${winSummary.wonByText}", - style: AppTextStyle.subtitle2 - .copyWith(color: context.colorScheme.textPrimary), - ); - } else { - return const SizedBox(); - } - } } diff --git a/khelo/lib/ui/flow/score_board/score_board_view_model.dart b/khelo/lib/ui/flow/score_board/score_board_view_model.dart index c1188d98..db466936 100644 --- a/khelo/lib/ui/flow/score_board/score_board_view_model.dart +++ b/khelo/lib/ui/flow/score_board/score_board_view_model.dart @@ -11,7 +11,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; -import 'package:khelo/domain/extensions/data_model_extensions/ball_score_model_extension.dart'; import 'package:khelo/ui/flow/score_board/components/select_player_sheet.dart'; import 'package:rxdart/rxdart.dart'; diff --git a/khelo/lib/ui/flow/team/detail/team_detail_screen.dart b/khelo/lib/ui/flow/team/detail/team_detail_screen.dart index e4d87178..aa0dc8ef 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_screen.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_screen.dart @@ -63,9 +63,7 @@ class _TeamDetailScreenState extends ConsumerState { Widget _body(BuildContext context, TeamDetailState state) { if (state.loading) { - return const Center( - child: AppProgressIndicator(), - ); + return const Center(child: AppProgressIndicator()); } if (state.error != null) { return ErrorScreen( diff --git a/khelo/pubspec.lock b/khelo/pubspec.lock index e85ab086..675faea1 100644 --- a/khelo/pubspec.lock +++ b/khelo/pubspec.lock @@ -550,10 +550,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" + sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e url: "https://pub.dev" source: hosted - version: "2.0.19" + version: "2.0.20" flutter_riverpod: dependency: "direct main" description: @@ -728,18 +728,18 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720" + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "0f57fee1e8bfadf8cc41818bbcd7f72e53bb768a54d9496355d5e8a5681a19f1" + sha256: "4161e1f843d8480d2e9025ee22411778c3c9eb7e40076dcf2da23d8242b7b51c" url: "https://pub.dev" source: hosted - version: "0.8.12+1" + version: "0.8.12+3" image_picker_for_web: dependency: transitive description: @@ -752,10 +752,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "4824d8c7f6f89121ef0122ff79bb00b009607faecc8545b86bca9ab5ce1e95bf" + sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447" url: "https://pub.dev" source: hosted - version: "0.8.11+2" + version: "0.8.12" image_picker_linux: dependency: transitive description: @@ -976,10 +976,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.5" path_provider_foundation: dependency: transitive description: @@ -1056,10 +1056,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.3.0" riverpod: dependency: transitive description: @@ -1104,10 +1104,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" + sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences_foundation: dependency: transitive description: @@ -1490,4 +1490,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.4.0 <4.0.0" - flutter: ">=3.19.0" + flutter: ">=3.22.0" diff --git a/style/lib/animations/on_tap_scale.dart b/style/lib/animations/on_tap_scale.dart index 71a471d5..9ea5f74b 100644 --- a/style/lib/animations/on_tap_scale.dart +++ b/style/lib/animations/on_tap_scale.dart @@ -88,4 +88,4 @@ class _OnTapScaleState extends State with TickerProviderStateMixin { _animationController = null; super.dispose(); } -} \ No newline at end of file +} diff --git a/style/lib/button/large_icon_button.dart b/style/lib/button/large_icon_button.dart index 05764fd2..42b7213b 100644 --- a/style/lib/button/large_icon_button.dart +++ b/style/lib/button/large_icon_button.dart @@ -44,4 +44,4 @@ class LargeIconButton extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/style/lib/button/tab_button.dart b/style/lib/button/tab_button.dart index 7e52a370..c500683e 100644 --- a/style/lib/button/tab_button.dart +++ b/style/lib/button/tab_button.dart @@ -6,12 +6,14 @@ import 'package:style/text/app_text_style.dart'; class TabButton extends StatelessWidget { final Function() onTap; final String text; + final GlobalKey? globalKey; final bool selected; const TabButton( this.text, { super.key, required this.onTap, + this.globalKey, this.selected = false, }); @@ -20,6 +22,7 @@ class TabButton extends StatelessWidget { return OnTapScale( onTap: onTap, child: Container( + key: globalKey, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: selected diff --git a/style/lib/extensions/context_extensions.dart b/style/lib/extensions/context_extensions.dart index 9e22a6eb..468299ee 100644 --- a/style/lib/extensions/context_extensions.dart +++ b/style/lib/extensions/context_extensions.dart @@ -11,4 +11,4 @@ extension BuildContextExtensions on BuildContext { Size get mediaQuerySize => MediaQuery.of(this).size; EdgeInsets get mediaQueryPadding => MediaQuery.of(this).padding; -} \ No newline at end of file +} diff --git a/style/lib/extensions/date_extensions.dart b/style/lib/extensions/date_extensions.dart index 6317fa18..fa7b7a8f 100644 --- a/style/lib/extensions/date_extensions.dart +++ b/style/lib/extensions/date_extensions.dart @@ -1,3 +1,3 @@ extension DateTimeExtensions on DateTime { DateTime get startOfDay => DateTime(year, month, day); -} \ No newline at end of file +} diff --git a/style/lib/indicator/progress_indicator.dart b/style/lib/indicator/progress_indicator.dart index 3652c520..5037c63f 100644 --- a/style/lib/indicator/progress_indicator.dart +++ b/style/lib/indicator/progress_indicator.dart @@ -69,4 +69,4 @@ class _AppProgressIndicatorState extends State { ); } } -} \ No newline at end of file +} diff --git a/style/lib/text/app_text_field.dart b/style/lib/text/app_text_field.dart index b5f40259..b4bc0de9 100644 --- a/style/lib/text/app_text_field.dart +++ b/style/lib/text/app_text_field.dart @@ -183,4 +183,4 @@ class BorderColor { Color? unFocusColor; BorderColor({this.focusColor, this.unFocusColor}); -} \ No newline at end of file +} diff --git a/style/lib/text/app_text_style.dart b/style/lib/text/app_text_style.dart index 4c8ae489..10d2851a 100644 --- a/style/lib/text/app_text_style.dart +++ b/style/lib/text/app_text_style.dart @@ -86,4 +86,4 @@ class AppTextStyle { fontSize: 12, package: 'style', ); -} \ No newline at end of file +} diff --git a/style/lib/widgets/adaptive_outlined_tile.dart b/style/lib/widgets/adaptive_outlined_tile.dart index f4631ddf..11a9b332 100644 --- a/style/lib/widgets/adaptive_outlined_tile.dart +++ b/style/lib/widgets/adaptive_outlined_tile.dart @@ -8,6 +8,7 @@ class AdaptiveOutlinedTile extends StatelessWidget { final String? headerText; final String? headerImage; final String? title; + final int? maxLines; final String placeholder; final bool showTrailingIcon; final Function()? onTap; @@ -17,6 +18,7 @@ class AdaptiveOutlinedTile extends StatelessWidget { this.headerText, this.headerImage, this.title, + this.maxLines, required this.placeholder, this.showTrailingIcon = false, this.onTap, @@ -61,6 +63,8 @@ class AdaptiveOutlinedTile extends StatelessWidget { Expanded( child: Text( title ?? placeholder, + maxLines: maxLines, + overflow: TextOverflow.ellipsis, style: AppTextStyle.subtitle3.copyWith( color: title != null ? context.colorScheme.textPrimary