From 29feef1e6b73fc959aaf746cc09a1a50e6384d58 Mon Sep 17 00:00:00 2001 From: sidhdhi canopas <122426509+cp-sidhdhi-p@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:11:26 +0530 Subject: [PATCH] Remove group option conditionally (#138) * remove group option conditionally * fix overflow error * make title center --- .../ball_score/ball_score_service.dart | 23 +- khelo/assets/locales/app_en.arb | 1 + khelo/lib/components/won_by_message_text.dart | 6 +- .../flow/home/components/tournament_item.dart | 31 ++- .../edit_profile/edit_profile_screen.dart | 2 + .../tournament/add/add_tournament_screen.dart | 2 + .../add/add_tournament_view_model.dart | 18 +- .../detail/components/filter_tab_view.dart | 10 +- .../detail/components/flexible_space.dart | 26 +- .../tabs/tournament_detail_overview_tab.dart | 240 +++++++++--------- .../match_selection/match_scheduler.dart | 7 +- .../match_selection_screen.dart | 34 +-- .../match_selection_view_model.dart | 34 +++ style/lib/pickers/date_and_time_picker.dart | 6 +- 14 files changed, 272 insertions(+), 168 deletions(-) diff --git a/data/lib/service/ball_score/ball_score_service.dart b/data/lib/service/ball_score/ball_score_service.dart index 144920ea..41bccc52 100644 --- a/data/lib/service/ball_score/ball_score_service.dart +++ b/data/lib/service/ball_score/ball_score_service.dart @@ -1,14 +1,16 @@ import 'dart:async'; + import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import '../../api/ball_score/ball_score_model.dart'; +import '../../api/match/match_model.dart'; import '../../errors/app_error.dart'; import '../../extensions/double_extensions.dart'; +import '../../extensions/list_extensions.dart'; +import '../../utils/constant/firestore_constant.dart'; import '../innings/inning_service.dart'; import '../match/match_service.dart'; -import '../../utils/constant/firestore_constant.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -import '../../api/match/match_model.dart'; final ballScoreServiceProvider = Provider((ref) { final service = BallScoreService( @@ -105,10 +107,15 @@ class BallScoreService { ) async { try { if (matchIds.isEmpty) return []; - final ballScoreRef = await _ballScoreCollection - .where(FireStoreConst.matchId, whereIn: matchIds) - .get(); - return ballScoreRef.docs.map((e) => e.data()).toList(); + final List data = []; + for (var ids in matchIds.chunked(30)) { + final ballScoreRef = await _ballScoreCollection + .where(FireStoreConst.matchId, whereIn: ids) + .get(); + data.addAll(ballScoreRef.docs.map((e) => e.data())); + } + + return data; } catch (error, stack) { throw AppError.fromError(error, stack); } diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index e9bcbd1b..cd2ecaab 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -817,6 +817,7 @@ "score_board_inning_complete_title": "Inning complete", "score_board_match_complete_title": "Match complete", "score_board_match_tied_text": "The match has been tied", + "score_board_match_tied": "Match tied", "score_board_start_next_inning_title": "Start Next Inning", "score_board_end_inning_title": "End Inning", "score_board_current_team_title": "Current Team", diff --git a/khelo/lib/components/won_by_message_text.dart b/khelo/lib/components/won_by_message_text.dart index aa94f46f..07b11819 100644 --- a/khelo/lib/components/won_by_message_text.dart +++ b/khelo/lib/components/won_by_message_text.dart @@ -24,7 +24,11 @@ class WonByMessageText extends StatelessWidget { return const SizedBox(); } if (matchResult!.winType == WinnerByType.tie) { - return Text(context.l10n.score_board_match_tied_text, + return Text( + isTournament + ? context.l10n.score_board_match_tied + : context.l10n.score_board_match_tied_text, + textAlign: isTournament ? TextAlign.center : TextAlign.left, style: textStyle ?? AppTextStyle.subtitle1 .copyWith(color: context.colorScheme.textPrimary)); diff --git a/khelo/lib/ui/flow/home/components/tournament_item.dart b/khelo/lib/ui/flow/home/components/tournament_item.dart index 0e7b0761..0c1ba756 100644 --- a/khelo/lib/ui/flow/home/components/tournament_item.dart +++ b/khelo/lib/ui/flow/home/components/tournament_item.dart @@ -1,5 +1,4 @@ import 'package:cached_network_image/cached_network_image.dart'; - import 'package:data/api/tournament/tournament_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -32,23 +31,37 @@ class TournamentItem extends StatefulWidget { } class _TournamentItemState extends State { - late ImageProvider imageProvider; + ImageProvider? imageProvider; PaletteGenerator? palette; @override void initState() { super.initState(); - if (widget.tournament.banner_img_url != null) { - imageProvider = - CachedNetworkImageProvider(widget.tournament.banner_img_url!); + _initializeImageProvider(widget.tournament.banner_img_url); + } + + void _initializeImageProvider(String? imageUrl) { + if (imageUrl != null) { + imageProvider = CachedNetworkImageProvider(imageUrl); if (widget.background == null) { - imageProvider.createPaletteGenerator().then((palette) { + imageProvider!.createPaletteGenerator().then((generatedPalette) { if (mounted) { - setState(() => this.palette = palette); + setState(() => palette = generatedPalette); } }); } + } else { + setState(() => imageProvider = null); + } + } + + @override + void didUpdateWidget(covariant TournamentItem oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.tournament.banner_img_url != + oldWidget.tournament.banner_img_url) { + _initializeImageProvider(widget.tournament.banner_img_url); } } @@ -101,10 +114,10 @@ class _TournamentItemState extends State { decoration: BoxDecoration( color: context.colorScheme.containerNormalOnSurface, borderRadius: BorderRadius.circular(8), - image: bannerUrl == null + image: bannerUrl == null || imageProvider == null ? null : DecorationImage( - image: imageProvider, + image: imageProvider!, fit: BoxFit.fill, ), ), diff --git a/khelo/lib/ui/flow/settings/edit_profile/edit_profile_screen.dart b/khelo/lib/ui/flow/settings/edit_profile/edit_profile_screen.dart index 5af8c206..2a7ec39f 100644 --- a/khelo/lib/ui/flow/settings/edit_profile/edit_profile_screen.dart +++ b/khelo/lib/ui/flow/settings/edit_profile/edit_profile_screen.dart @@ -178,6 +178,8 @@ class EditProfileScreen extends ConsumerWidget { context, helpText: context.l10n.edit_profile_select_birth_date_placeholder, initialDate: state.dob, + startDate: DateTime(1950), + endDate: DateTime.now(), onDateSelected: (date) { if (date != state.dob) { notifier.onDateSelect(selectedDate: date); diff --git a/khelo/lib/ui/flow/tournament/add/add_tournament_screen.dart b/khelo/lib/ui/flow/tournament/add/add_tournament_screen.dart index 85a909fd..d19cd96a 100644 --- a/khelo/lib/ui/flow/tournament/add/add_tournament_screen.dart +++ b/khelo/lib/ui/flow/tournament/add/add_tournament_screen.dart @@ -363,6 +363,7 @@ class _AddTournamentScreenState extends ConsumerState { onTap: () { selectDate( context, + startDate: widget.editTournament?.start_date, initialDate: state.startDate, onDateSelected: notifier.onStartDate, ); @@ -377,6 +378,7 @@ class _AddTournamentScreenState extends ConsumerState { onTap: () { selectDate( context, + startDate: widget.editTournament?.start_date, initialDate: state.endDate, onDateSelected: notifier.onEndDate, ); diff --git a/khelo/lib/ui/flow/tournament/add/add_tournament_view_model.dart b/khelo/lib/ui/flow/tournament/add/add_tournament_view_model.dart index 1a8521bd..f0dab3ce 100644 --- a/khelo/lib/ui/flow/tournament/add/add_tournament_view_model.dart +++ b/khelo/lib/ui/flow/tournament/add/add_tournament_view_model.dart @@ -112,12 +112,26 @@ class AddTournamentViewNotifier extends StateNotifier { } void onStartDate(DateTime startDate) { - state = state.copyWith(startDate: startDate); + DateTime endDate = state.endDate; + + if (startDate.isAfter(endDate)) { + endDate = startDate.add(Duration(days: 1)); + } + state = state.copyWith(startDate: startDate, endDate: endDate); onChange(); } void onEndDate(DateTime endDate) { - state = state.copyWith(endDate: endDate); + DateTime startDate = state.startDate; + + if (endDate.isBefore(startDate)) { + startDate = endDate.subtract(Duration(days: 1)); + if (_editedTournament != null && + startDate.isBefore(_editedTournament!.start_date)) { + startDate = _editedTournament!.start_date; + } + } + state = state.copyWith(endDate: endDate, startDate: startDate); onChange(); } diff --git a/khelo/lib/ui/flow/tournament/detail/components/filter_tab_view.dart b/khelo/lib/ui/flow/tournament/detail/components/filter_tab_view.dart index 04045675..c91905ce 100644 --- a/khelo/lib/ui/flow/tournament/detail/components/filter_tab_view.dart +++ b/khelo/lib/ui/flow/tournament/detail/components/filter_tab_view.dart @@ -22,10 +22,12 @@ class FilterTabView extends StatelessWidget { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - title, - style: AppTextStyle.header4.copyWith( - color: context.colorScheme.textPrimary, + Expanded( + child: Text( + title, + style: AppTextStyle.header4.copyWith( + color: context.colorScheme.textPrimary, + ), ), ), TextButton.icon( diff --git a/khelo/lib/ui/flow/tournament/detail/components/flexible_space.dart b/khelo/lib/ui/flow/tournament/detail/components/flexible_space.dart index bccfe54b..9f0b248d 100644 --- a/khelo/lib/ui/flow/tournament/detail/components/flexible_space.dart +++ b/khelo/lib/ui/flow/tournament/detail/components/flexible_space.dart @@ -25,21 +25,35 @@ class FlexibleSpace extends StatefulWidget { } class _FlexibleSpaceState extends State { - late ImageProvider imageProvider; + ImageProvider? imageProvider; PaletteGenerator? palette; @override void initState() { super.initState(); - if (widget.tournament.banner_img_url != null) { - imageProvider = - CachedNetworkImageProvider(widget.tournament.banner_img_url!); - imageProvider.createPaletteGenerator().then((palette) { + _initializeImageProvider(widget.tournament.banner_img_url); + } + + @override + void didUpdateWidget(covariant FlexibleSpace oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.tournament.banner_img_url != + oldWidget.tournament.banner_img_url) { + _initializeImageProvider(widget.tournament.banner_img_url); + } + } + + void _initializeImageProvider(String? imageUrl) { + if (imageUrl != null) { + imageProvider = CachedNetworkImageProvider(imageUrl); + imageProvider!.createPaletteGenerator().then((generatedPalette) { if (mounted) { - setState(() => this.palette = palette); + setState(() => palette = generatedPalette); } }); + } else { + setState(() => imageProvider = null); } } diff --git a/khelo/lib/ui/flow/tournament/detail/tabs/tournament_detail_overview_tab.dart b/khelo/lib/ui/flow/tournament/detail/tabs/tournament_detail_overview_tab.dart index 2b411cdf..fd04685a 100644 --- a/khelo/lib/ui/flow/tournament/detail/tabs/tournament_detail_overview_tab.dart +++ b/khelo/lib/ui/flow/tournament/detail/tabs/tournament_detail_overview_tab.dart @@ -81,31 +81,35 @@ class TournamentDetailOverviewTab extends ConsumerWidget { children: [ if (showMatchGroup) MatchGroupTag(tag: match.match_group!), _buildTeamInfo(context, team: match.teams.first.team), - const Spacer(), if (match.matchResult != null) ...[ - WonByMessageText( - isTournament: true, - matchResult: match.matchResult, + Expanded( + child: WonByMessageText( + isTournament: true, + matchResult: match.matchResult, + ), ), ] else ...[ - Column( - children: [ - Text( - match.start_at?.format(context, DateFormatType.time) ?? - DateTime.now().format(context, DateFormatType.time), - style: AppTextStyle.caption - .copyWith(color: context.colorScheme.textDisabled), - ), - Text( - match.start_at?.relativeTime(context) ?? - DateTime.now().relativeTime(context), - style: AppTextStyle.subtitle2 - .copyWith(color: context.colorScheme.textPrimary), - ), - ], + Expanded( + child: Column( + children: [ + Text( + match.start_at?.format(context, DateFormatType.time) ?? + DateTime.now().format(context, DateFormatType.time), + textAlign: TextAlign.center, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + ), + Text( + match.start_at?.relativeTime(context) ?? + DateTime.now().relativeTime(context), + textAlign: TextAlign.center, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + ], + ), ), ], - const Spacer(), _buildTeamInfo( context, team: match.teams.last.team, @@ -123,36 +127,38 @@ class TournamentDetailOverviewTab extends ConsumerWidget { bool isSecond = false, }) { final initials = team.name_initial ?? team.name.initials(limit: 2); - return Row( - children: [ - if (isSecond) ...[ - Text( - initials, - style: AppTextStyle.subtitle1.copyWith( - color: context.colorScheme.textPrimary, + return MediaQuery.withNoTextScaling( + child: Row( + children: [ + if (isSecond) ...[ + Text( + initials, + style: AppTextStyle.subtitle1.copyWith( + color: context.colorScheme.textPrimary, + ), ), - ), - const SizedBox(width: 16), - ImageAvatar( - initial: initials, - imageUrl: team.profile_img_url, - size: 40, - ), - ] else ...[ - ImageAvatar( - initial: initials, - imageUrl: team.profile_img_url, - size: 40, - ), - const SizedBox(width: 16), - Text( - initials, - style: AppTextStyle.subtitle1.copyWith( - color: context.colorScheme.textPrimary, + const SizedBox(width: 16), + ImageAvatar( + initial: initials, + imageUrl: team.profile_img_url, + size: 40, ), - ), + ] else ...[ + ImageAvatar( + initial: initials, + imageUrl: team.profile_img_url, + size: 40, + ), + const SizedBox(width: 16), + Text( + initials, + style: AppTextStyle.subtitle1.copyWith( + color: context.colorScheme.textPrimary, + ), + ), + ], ], - ], + ), ); } @@ -196,64 +202,66 @@ class TournamentDetailOverviewTab extends ConsumerWidget { Widget _keyStatsCellView(BuildContext context, PlayerKeyStat keyStat) { if (keyStat.tag == null && keyStat.value == null) return SizedBox(); - return Container( - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - color: context.colorScheme.surface, - borderRadius: BorderRadius.circular(16), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - keyStat.tag!.getString(context), - style: AppTextStyle.body2 - .copyWith(color: context.colorScheme.positive), - ), - Text( - keyStat.value.toString(), - style: AppTextStyle.subtitle1.copyWith( - color: context.colorScheme.textPrimary, + return MediaQuery.withNoTextScaling( + child: Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: context.colorScheme.surface, + borderRadius: BorderRadius.circular(16), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + keyStat.tag!.getString(context), + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.positive), ), - ) - ], - ), - Divider(color: context.colorScheme.outline), - Row( - children: [ - ImageAvatar( - initial: keyStat.player.nameInitial, - imageUrl: keyStat.player.profile_img_url, - size: 40, - ), - const SizedBox(width: 8), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - keyStat.player.name ?? '', - style: AppTextStyle.subtitle2.copyWith( - color: context.colorScheme.textPrimary, - ), - overflow: TextOverflow.ellipsis, - ), - Text( - keyStat.teamName, - style: AppTextStyle.caption.copyWith( - color: context.colorScheme.textDisabled, - ), - overflow: TextOverflow.ellipsis, - ) - ], + Text( + keyStat.value.toString(), + style: AppTextStyle.subtitle1.copyWith( + color: context.colorScheme.textPrimary, + ), + ) + ], + ), + Divider(color: context.colorScheme.outline), + Row( + children: [ + ImageAvatar( + initial: keyStat.player.nameInitial, + imageUrl: keyStat.player.profile_img_url, + size: 40, ), - ) - ], - ), - ], + const SizedBox(width: 8), + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + keyStat.player.name ?? '', + style: AppTextStyle.subtitle2.copyWith( + color: context.colorScheme.textPrimary, + ), + overflow: TextOverflow.ellipsis, + ), + Text( + keyStat.teamName, + style: AppTextStyle.caption.copyWith( + color: context.colorScheme.textDisabled, + ), + overflow: TextOverflow.ellipsis, + ) + ], + ), + ) + ], + ), + ], + ), ), ); } @@ -374,10 +382,13 @@ class TournamentDetailOverviewTab extends ConsumerWidget { padding: const EdgeInsets.all(16.0), child: Row( children: [ - Text( - title, - style: AppTextStyle.subtitle3 - .copyWith(color: context.colorScheme.textSecondary), + Expanded( + child: Text( + title, + style: AppTextStyle.subtitle3 + .copyWith(color: context.colorScheme.textSecondary), + textScaler: TextScaler.noScaling, + ), ), const SizedBox(width: 16), Expanded( @@ -402,14 +413,15 @@ class TournamentDetailOverviewTab extends ConsumerWidget { }) { return Row( children: [ - Text( - title, - style: AppTextStyle.header4 - .copyWith(color: context.colorScheme.textPrimary), + Expanded( + child: Text( + title, + style: AppTextStyle.header4 + .copyWith(color: context.colorScheme.textPrimary), + ), ), - const Spacer(), - Opacity( - opacity: showViewAll ? 1 : 0, + Visibility( + visible: showViewAll, child: TextButton( onPressed: onViewAll, child: Text( diff --git a/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart b/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart index 84a8a46f..6b5702d6 100644 --- a/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart +++ b/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart @@ -51,8 +51,11 @@ class MatchScheduler { GroupedMatchMap scheduleMatchesByType() { switch (matchType) { case TournamentType.knockOut: - return scheduleKnockOutMatchesWithArguments(scheduledMatches, teams, - addInitialRound: true); + return scheduleKnockOutMatchesWithArguments( + scheduledMatches, + teams, + addInitialRound: true, + ); case TournamentType.miniRobin: return scheduleMiniRoundRobinMatches(); case TournamentType.boxLeague: diff --git a/khelo/lib/ui/flow/tournament/match_selection/match_selection_screen.dart b/khelo/lib/ui/flow/tournament/match_selection/match_selection_screen.dart index 47f28820..411eb6db 100644 --- a/khelo/lib/ui/flow/tournament/match_selection/match_selection_screen.dart +++ b/khelo/lib/ui/flow/tournament/match_selection/match_selection_screen.dart @@ -56,19 +56,7 @@ class _MatchSelectionScreenState extends ConsumerState { _addButton( context, onPressed: () { - final option = MatchGroup.values.toList(); - if (state.matches.containsKey(MatchGroup.quarterfinal)) { - option.remove(MatchGroup.quarterfinal); - } - - if (state.matches.containsKey(MatchGroup.semifinal)) { - option.remove(MatchGroup.semifinal); - } - - if (state.matches.containsKey(MatchGroup.finals)) { - option.remove(MatchGroup.finals); - } - + final option = notifier.getMatchGroupOption(); showActionBottomSheet( context: context, items: option @@ -161,6 +149,11 @@ class _MatchSelectionScreenState extends ConsumerState { final roundDisplay = group == MatchGroup.round ? "${group.getString(context)} $number" : group.getString(context); + final showAddButton = + (group == MatchGroup.quarterfinal && matches.length < 4) || + (group == MatchGroup.semifinal && matches.length < 2) || + (group == MatchGroup.finals && matches.isEmpty) || + group == MatchGroup.round; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -178,13 +171,14 @@ class _MatchSelectionScreenState extends ConsumerState { ), ), ), - _addButton(context, onPressed: () { - AppRoute.addMatch( - tournamentId: tournamentId, - group: group, - groupNumber: number, - ).push(context); - }), + if (showAddButton) + _addButton(context, onPressed: () { + AppRoute.addMatch( + tournamentId: tournamentId, + group: group, + groupNumber: number, + ).push(context); + }), ], ), ), diff --git a/khelo/lib/ui/flow/tournament/match_selection/match_selection_view_model.dart b/khelo/lib/ui/flow/tournament/match_selection/match_selection_view_model.dart index ce87c509..416bb7c5 100644 --- a/khelo/lib/ui/flow/tournament/match_selection/match_selection_view_model.dart +++ b/khelo/lib/ui/flow/tournament/match_selection/match_selection_view_model.dart @@ -142,6 +142,40 @@ class MatchSelectionViewNotifier extends StateNotifier { return filteredMatches; } + List getMatchGroupOption() { + final options = MatchGroup.values.toList(); + final tournamentType = state.tournament?.type; + if (state.matches.containsKey(MatchGroup.round)) { + if (tournamentType == TournamentType.miniRobin || + (tournamentType == TournamentType.doubleOut && + (state.matches[MatchGroup.round]?.entries.length ?? 0) > 1)) { + options.remove(MatchGroup.round); + } + } + + void handleDoubleOutValidation(MatchGroup group) { + if (tournamentType == TournamentType.doubleOut || + state.matches.containsKey(group)) { + if (tournamentType == TournamentType.doubleOut || + tournamentType == TournamentType.miniRobin || + tournamentType == TournamentType.boxLeague || + tournamentType == TournamentType.custom || + tournamentType == TournamentType.knockOut) { + options.remove(group); + } + } + } + + handleDoubleOutValidation(MatchGroup.quarterfinal); + handleDoubleOutValidation(MatchGroup.semifinal); + + if (state.matches.containsKey(MatchGroup.finals)) { + options.remove(MatchGroup.finals); + } + + return options; + } + @override void dispose() { _tournamentSubscription?.cancel(); diff --git a/style/lib/pickers/date_and_time_picker.dart b/style/lib/pickers/date_and_time_picker.dart index cdadf2e9..fded5b58 100644 --- a/style/lib/pickers/date_and_time_picker.dart +++ b/style/lib/pickers/date_and_time_picker.dart @@ -6,6 +6,8 @@ import '../theme/colors.dart'; Future selectDate( BuildContext context, { String? helpText, + DateTime? startDate, + DateTime? endDate, required DateTime initialDate, required Function(DateTime) onDateSelected, }) async { @@ -15,8 +17,8 @@ Future selectDate( context: context, helpText: helpText, initialDate: initialDate, - firstDate: initialDate.isBefore(now) ? initialDate : now, - lastDate: DateTime(now.year + 1, now.month, now.day), + firstDate: startDate ?? (initialDate.isBefore(now) ? initialDate : now), + lastDate: endDate ?? DateTime(now.year + 1, now.month, now.day), builder: (context, child) { return Theme( data: context.brightness == Brightness.dark