From 28b29d7b5715c0afe28cb027bef9e3aa3d29efc1 Mon Sep 17 00:00:00 2001 From: sidhdhi canopas Date: Mon, 30 Sep 2024 17:14:40 +0530 Subject: [PATCH] team initials --- data/lib/api/team/team_model.dart | 1 + data/lib/api/team/team_model.freezed.dart | 24 ++++++++++++++++- data/lib/api/team/team_model.g.dart | 2 ++ khelo/assets/locales/app_en.arb | 1 + khelo/ios/Runner.xcodeproj/project.pbxproj | 26 +++++++++---------- khelo/lib/components/image_avatar.dart | 17 ++++++++---- khelo/lib/ui/flow/home/home_screen.dart | 4 ++- .../components/team_selection_view.dart | 3 ++- .../components/commentary_over_overview.dart | 2 +- .../components/final_score_view.dart | 3 ++- .../match_detail/match_detail_tab_screen.dart | 2 +- .../add_toss_detail_screen.dart | 8 +++--- .../components/add_penalty_run_sheet.dart | 9 +++++-- .../flow/team/add_team/add_team_screen.dart | 21 +++++++++++++-- .../team/add_team/add_team_view_model.dart | 6 +++++ .../add_team/add_team_view_model.freezed.dart | 25 +++++++++++++++++- .../flow/team/detail/team_detail_screen.dart | 3 ++- .../team/search_team/search_team_screen.dart | 3 ++- khelo/lib/ui/flow/team/team_list_screen.dart | 3 ++- .../team/user_detail/user_detail_screen.dart | 3 +-- khelo/macos/Runner.xcodeproj/project.pbxproj | 4 +-- style/lib/text/app_text_field.dart | 3 +++ style/lib/text/text_input_formatter.dart | 12 +++++++++ 23 files changed, 146 insertions(+), 39 deletions(-) create mode 100644 style/lib/text/text_input_formatter.dart diff --git a/data/lib/api/team/team_model.dart b/data/lib/api/team/team_model.dart index 9f694c5b..e73273ff 100644 --- a/data/lib/api/team/team_model.dart +++ b/data/lib/api/team/team_model.dart @@ -18,6 +18,7 @@ abstract class TeamModel with _$TeamModel { required String name, required String name_lowercase, String? city, + String? initials, String? profile_img_url, String? created_by, DateTime? created_at, diff --git a/data/lib/api/team/team_model.freezed.dart b/data/lib/api/team/team_model.freezed.dart index d3db216b..cda0c3cd 100644 --- a/data/lib/api/team/team_model.freezed.dart +++ b/data/lib/api/team/team_model.freezed.dart @@ -24,6 +24,7 @@ mixin _$TeamModel { String get name => throw _privateConstructorUsedError; String get name_lowercase => throw _privateConstructorUsedError; String? get city => throw _privateConstructorUsedError; + String? get initials => throw _privateConstructorUsedError; String? get profile_img_url => throw _privateConstructorUsedError; String? get created_by => throw _privateConstructorUsedError; DateTime? get created_at => throw _privateConstructorUsedError; @@ -48,6 +49,7 @@ abstract class $TeamModelCopyWith<$Res> { String name, String name_lowercase, String? city, + String? initials, String? profile_img_url, String? created_by, DateTime? created_at, @@ -72,6 +74,7 @@ class _$TeamModelCopyWithImpl<$Res, $Val extends TeamModel> Object? name = null, Object? name_lowercase = null, Object? city = freezed, + Object? initials = freezed, Object? profile_img_url = freezed, Object? created_by = freezed, Object? created_at = freezed, @@ -95,6 +98,10 @@ class _$TeamModelCopyWithImpl<$Res, $Val extends TeamModel> ? _value.city : city // ignore: cast_nullable_to_non_nullable as String?, + initials: freezed == initials + ? _value.initials + : initials // ignore: cast_nullable_to_non_nullable + as String?, profile_img_url: freezed == profile_img_url ? _value.profile_img_url : profile_img_url // ignore: cast_nullable_to_non_nullable @@ -132,6 +139,7 @@ abstract class _$$TeamModelImplCopyWith<$Res> String name, String name_lowercase, String? city, + String? initials, String? profile_img_url, String? created_by, DateTime? created_at, @@ -154,6 +162,7 @@ class __$$TeamModelImplCopyWithImpl<$Res> Object? name = null, Object? name_lowercase = null, Object? city = freezed, + Object? initials = freezed, Object? profile_img_url = freezed, Object? created_by = freezed, Object? created_at = freezed, @@ -177,6 +186,10 @@ class __$$TeamModelImplCopyWithImpl<$Res> ? _value.city : city // ignore: cast_nullable_to_non_nullable as String?, + initials: freezed == initials + ? _value.initials + : initials // ignore: cast_nullable_to_non_nullable + as String?, profile_img_url: freezed == profile_img_url ? _value.profile_img_url : profile_img_url // ignore: cast_nullable_to_non_nullable @@ -210,6 +223,7 @@ class _$TeamModelImpl implements _TeamModel { required this.name, required this.name_lowercase, this.city, + this.initials, this.profile_img_url, this.created_by, this.created_at, @@ -230,6 +244,8 @@ class _$TeamModelImpl implements _TeamModel { @override final String? city; @override + final String? initials; + @override final String? profile_img_url; @override final String? created_by; @@ -249,7 +265,7 @@ class _$TeamModelImpl implements _TeamModel { @override String toString() { - return 'TeamModel(id: $id, name: $name, name_lowercase: $name_lowercase, city: $city, profile_img_url: $profile_img_url, created_by: $created_by, created_at: $created_at, created_time: $created_time, players: $players)'; + return 'TeamModel(id: $id, name: $name, name_lowercase: $name_lowercase, city: $city, initials: $initials, profile_img_url: $profile_img_url, created_by: $created_by, created_at: $created_at, created_time: $created_time, players: $players)'; } @override @@ -262,6 +278,8 @@ class _$TeamModelImpl implements _TeamModel { (identical(other.name_lowercase, name_lowercase) || other.name_lowercase == name_lowercase) && (identical(other.city, city) || other.city == city) && + (identical(other.initials, initials) || + other.initials == initials) && (identical(other.profile_img_url, profile_img_url) || other.profile_img_url == profile_img_url) && (identical(other.created_by, created_by) || @@ -281,6 +299,7 @@ class _$TeamModelImpl implements _TeamModel { name, name_lowercase, city, + initials, profile_img_url, created_by, created_at, @@ -307,6 +326,7 @@ abstract class _TeamModel implements TeamModel { required final String name, required final String name_lowercase, final String? city, + final String? initials, final String? profile_img_url, final String? created_by, final DateTime? created_at, @@ -326,6 +346,8 @@ abstract class _TeamModel implements TeamModel { @override String? get city; @override + String? get initials; + @override String? get profile_img_url; @override String? get created_by; diff --git a/data/lib/api/team/team_model.g.dart b/data/lib/api/team/team_model.g.dart index f81cb978..3d6f8a02 100644 --- a/data/lib/api/team/team_model.g.dart +++ b/data/lib/api/team/team_model.g.dart @@ -12,6 +12,7 @@ _$TeamModelImpl _$$TeamModelImplFromJson(Map json) => name: json['name'] as String, name_lowercase: json['name_lowercase'] as String, city: json['city'] as String?, + initials: json['initials'] as String?, profile_img_url: json['profile_img_url'] as String?, created_by: json['created_by'] as String?, created_at: json['created_at'] == null @@ -31,6 +32,7 @@ Map _$$TeamModelImplToJson(_$TeamModelImpl instance) => 'name': instance.name, 'name_lowercase': instance.name_lowercase, 'city': instance.city, + 'initials': instance.initials, 'profile_img_url': instance.profile_img_url, 'created_by': instance.created_by, 'created_at': instance.created_at?.toIso8601String(), diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index f46f3391..8100aeea 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -144,6 +144,7 @@ "add_team_edit_team_screen_title": "Edit Team", "add_team_add_as_member_description_text": "Add me as a team member", "add_team_enter_team_name_placeholder_text": "Enter team name", + "add_team_team_initial_placeholder_text": "Team initials (e.g. IND, AUS, PBKS)", "add_team_player_role_title": "Playing role", "add_team_player_add_via_contact_title": "Add via Contact", "add_team_players_text": "Players", diff --git a/khelo/ios/Runner.xcodeproj/project.pbxproj b/khelo/ios/Runner.xcodeproj/project.pbxproj index 682ace3b..d8f5e503 100644 --- a/khelo/ios/Runner.xcodeproj/project.pbxproj +++ b/khelo/ios/Runner.xcodeproj/project.pbxproj @@ -206,7 +206,7 @@ 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 9C8DD79CF293961A8F4177C2 /* [CP] Embed Pods Frameworks */, 9EE7146958D62CE1CD764FEE /* [CP] Copy Pods Resources */, - 3526C9B46C8E72D356D2469A /* FlutterFire: "flutterfire upload-crashlytics-symbols" */, + 4355A474366F3412FC529595 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */, ); buildRules = ( ); @@ -301,39 +301,39 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 3526C9B46C8E72D356D2469A /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); - name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\""; - outputFileListPaths = ( - ); + name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\n#!/bin/bash\nPATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=$PODS_ROOT/FirebaseCrashlytics/upload-symbols --platform=ios --apple-project-path=${SRCROOT} --env-platform-name=${PLATFORM_NAME} --env-configuration=${CONFIGURATION} --env-project-dir=${PROJECT_DIR} --env-built-products-dir=${BUILT_PRODUCTS_DIR} --env-dwarf-dsym-folder-path=${DWARF_DSYM_FOLDER_PATH} --env-dwarf-dsym-file-name=${DWARF_DSYM_FILE_NAME} --env-infoplist-path=${INFOPLIST_PATH} --default-config=default\n"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 4355A474366F3412FC529595 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); - name = "Thin Binary"; + name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\""; + outputFileListPaths = ( + ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; + shellScript = "\n#!/bin/bash\nPATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=$PODS_ROOT/FirebaseCrashlytics/upload-symbols --platform=ios --apple-project-path=${SRCROOT} --env-platform-name=${PLATFORM_NAME} --env-configuration=${CONFIGURATION} --env-project-dir=${PROJECT_DIR} --env-built-products-dir=${BUILT_PRODUCTS_DIR} --env-dwarf-dsym-folder-path=${DWARF_DSYM_FOLDER_PATH} --env-dwarf-dsym-file-name=${DWARF_DSYM_FILE_NAME} --env-infoplist-path=${INFOPLIST_PATH} --default-config=default\n"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; diff --git a/khelo/lib/components/image_avatar.dart b/khelo/lib/components/image_avatar.dart index c888f027..ef8dbcb7 100644 --- a/khelo/lib/components/image_avatar.dart +++ b/khelo/lib/components/image_avatar.dart @@ -53,11 +53,18 @@ class ImageAvatar extends StatelessWidget { } Widget _initialView(BuildContext context) { - return Text( - initial, - style: AppTextStyle.subtitle1.copyWith( - color: foregroundColor ?? context.colorScheme.textPrimary, - fontSize: size / 2.15), + return Padding( + padding: const EdgeInsets.all(4), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text( + initial, + textAlign: TextAlign.center, + style: AppTextStyle.subtitle1.copyWith( + color: foregroundColor ?? context.colorScheme.textPrimary, + fontSize: size / 2.15), + ), + ), ); } } diff --git a/khelo/lib/ui/flow/home/home_screen.dart b/khelo/lib/ui/flow/home/home_screen.dart index eafe8a46..27313761 100644 --- a/khelo/lib/ui/flow/home/home_screen.dart +++ b/khelo/lib/ui/flow/home/home_screen.dart @@ -7,6 +7,7 @@ import 'package:khelo/components/empty_screen.dart'; import 'package:khelo/components/error_screen.dart'; import 'package:khelo/components/image_avatar.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/string_extensions.dart'; import 'package:khelo/domain/formatter/date_formatter.dart'; import 'package:khelo/ui/app_route.dart'; import 'package:khelo/ui/flow/home/home_view_model.dart'; @@ -246,7 +247,8 @@ class _HomeScreenState extends ConsumerState { mainAxisSize: MainAxisSize.min, children: [ ImageAvatar( - initial: matchTeam.team.name[0].toUpperCase(), + initial: + matchTeam.team.initials ?? matchTeam.team.name.initials(limit: 1), imageUrl: matchTeam.team.profile_img_url, size: 32, ), diff --git a/khelo/lib/ui/flow/matches/add_match/components/team_selection_view.dart b/khelo/lib/ui/flow/matches/add_match/components/team_selection_view.dart index bfbe7e66..5707a2ea 100644 --- a/khelo/lib/ui/flow/matches/add_match/components/team_selection_view.dart +++ b/khelo/lib/ui/flow/matches/add_match/components/team_selection_view.dart @@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:data/api/team/team_model.dart'; import 'package:flutter/material.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/string_extensions.dart'; import 'package:khelo/ui/app_route.dart'; import 'package:khelo/ui/flow/matches/add_match/add_match_view_model.dart'; import 'package:style/animations/on_tap_scale.dart'; @@ -111,7 +112,7 @@ class TeamSelectionView extends StatelessWidget { ) : (team.profile_img_url == null) ? Text( - team.name[0].toUpperCase(), + team.initials ?? team.name.initials(limit: 1), style: AppTextStyle.subtitle1.copyWith( color: context.colorScheme.textDisabled), ) 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 d31b444a..17596c1a 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 @@ -95,7 +95,7 @@ class CommentaryOverOverview extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, children: [ ImageAvatar( - initial: team?.name.initials(limit: 1) ?? "?", + initial: team?.initials ?? team?.name.initials(limit: 1) ?? "?", imageUrl: team?.profile_img_url, size: 35, ), 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 d097eaa6..e7f647ca 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 @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/image_avatar.dart'; import 'package:khelo/components/match_status_tag.dart'; +import 'package:khelo/domain/extensions/string_extensions.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'; @@ -59,7 +60,7 @@ class FinalScoreView extends ConsumerWidget { return Row( children: [ ImageAvatar( - initial: team.team.name[0].toUpperCase(), + initial: team.team.initials ?? team.team.name.initials(limit: 1), imageUrl: team.team.profile_img_url, size: 32, ), 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 a6447731..49c8553e 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 @@ -61,7 +61,7 @@ class _MatchDetailTabScreenState extends ConsumerState { String _getScreenTitle(BuildContext context, MatchDetailTabState state) { if (state.match != null) { String title = state.match!.teams - .map((e) => e.team.name.initials(limit: 3)) + .map((e) => e.team.initials ?? e.team.name.initials(limit: 3)) .join(" ${context.l10n.common_versus_short_title} "); return title; } diff --git a/khelo/lib/ui/flow/score_board/add_toss_detail/add_toss_detail_screen.dart b/khelo/lib/ui/flow/score_board/add_toss_detail/add_toss_detail_screen.dart index 9f1642ce..e82dccae 100644 --- a/khelo/lib/ui/flow/score_board/add_toss_detail/add_toss_detail_screen.dart +++ b/khelo/lib/ui/flow/score_board/add_toss_detail/add_toss_detail_screen.dart @@ -10,6 +10,7 @@ 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/domain/extensions/enum_extensions.dart'; +import 'package:khelo/domain/extensions/string_extensions.dart'; import 'package:khelo/domain/extensions/widget_extension.dart'; import 'package:khelo/gen/assets.gen.dart'; import 'package:khelo/ui/app_route.dart'; @@ -101,11 +102,12 @@ class _AddTossDetailScreenState extends ConsumerState { (team) => _tossCellView( context: context, imageUrl: team.team.profile_img_url, - initial: team.team.name[0].toUpperCase(), + initial: team.team.initials ?? + team.team.name.initials(limit: 1), title: team.team.name, isSelected: tossWinnerTeamId == team.team.id, - onTap: () => notifier - .onTossWinnerSelect(team.team.id), + onTap: () => + notifier.onTossWinnerSelect(team.team.id), ), ) .toList() ?? diff --git a/khelo/lib/ui/flow/score_board/components/add_penalty_run_sheet.dart b/khelo/lib/ui/flow/score_board/components/add_penalty_run_sheet.dart index d6cda8dc..20f7de3b 100644 --- a/khelo/lib/ui/flow/score_board/components/add_penalty_run_sheet.dart +++ b/khelo/lib/ui/flow/score_board/components/add_penalty_run_sheet.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/string_extensions.dart'; import 'package:khelo/ui/flow/score_board/components/bottom_sheet_wrapper.dart'; import 'package:khelo/ui/flow/score_board/components/user_cell_view.dart'; import 'package:khelo/ui/flow/score_board/score_board_view_model.dart'; @@ -153,7 +154,9 @@ class _AddPenaltyRunSheetState extends ConsumerState { title: firstTeam?.name ?? "", imageUrl: firstTeam?.profile_img_url, outerPadding: 32, - initial: firstTeam?.name[0].toUpperCase(), + initial: firstTeam?.initials ?? + firstTeam?.name.initials(limit: 1) ?? + "?", isSelected: selectedTeamId == firstTeam?.id, onTap: () => setState(() { selectedTeamId = firstTeam?.id; @@ -165,7 +168,9 @@ class _AddPenaltyRunSheetState extends ConsumerState { UserCellView( title: secondTeam?.name ?? "", imageUrl: secondTeam?.profile_img_url, - initial: secondTeam?.name[0].toUpperCase(), + initial: secondTeam?.initials ?? + secondTeam?.name.initials(limit: 1) ?? + "?", outerPadding: 32, isSelected: selectedTeamId == secondTeam?.id, onTap: () => setState(() { diff --git a/khelo/lib/ui/flow/team/add_team/add_team_screen.dart b/khelo/lib/ui/flow/team/add_team/add_team_screen.dart index b95eab92..c262cf82 100644 --- a/khelo/lib/ui/flow/team/add_team/add_team_screen.dart +++ b/khelo/lib/ui/flow/team/add_team/add_team_screen.dart @@ -20,6 +20,7 @@ import 'package:style/extensions/context_extensions.dart'; import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_field.dart'; import 'package:style/text/app_text_style.dart'; +import 'package:style/text/text_input_formatter.dart'; import 'package:style/button/action_button.dart'; import 'package:style/button/back_button.dart'; import 'package:style/button/bottom_sticky_overlay.dart'; @@ -131,12 +132,24 @@ class _AddTeamScreenState extends ConsumerState { : null, hintText: context.l10n.add_team_enter_team_name_placeholder_text), - const SizedBox(height: 8), + const SizedBox(height: 16), _textInputField( controller: state.locationController, onChanged: (p0) => notifier.onValueChange(), hintText: context.l10n.common_location_title, ), + const SizedBox(height: 16), + _textInputField( + controller: state.nameInitialsController, + textCapitalization: TextCapitalization.characters, + maxLength: 4, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z]')), + UpperCaseTextFormatter(), + ], + onChanged: (p0) => notifier.onValueChange(), + hintText: context.l10n.add_team_team_initial_placeholder_text, + ), if (widget.editTeam == null) ...[ const SizedBox(height: 8), Padding( @@ -221,8 +234,10 @@ class _AddTeamScreenState extends ConsumerState { required TextEditingController controller, required String hintText, required Function(String)? onChanged, + TextCapitalization textCapitalization = TextCapitalization.none, List? inputFormatters, Widget? suffixIcon, + int? maxLength, }) { return AppTextField( controller: controller, @@ -235,7 +250,9 @@ class _AddTeamScreenState extends ConsumerState { hintStyle: AppTextStyle.subtitle3 .copyWith(color: context.colorScheme.textDisabled), borderRadius: BorderRadius.circular(12), + textCapitalization: textCapitalization, borderType: AppTextFieldBorderType.outline, + maxLength: maxLength, backgroundColor: context.colorScheme.containerLow, borderColor: BorderColor( focusColor: Colors.transparent, unFocusColor: Colors.transparent), @@ -287,4 +304,4 @@ class _AddTeamScreenState extends ConsumerState { }, ); } -} +} \ No newline at end of file diff --git a/khelo/lib/ui/flow/team/add_team/add_team_view_model.dart b/khelo/lib/ui/flow/team/add_team/add_team_view_model.dart index 6357c591..8bb4a6b0 100644 --- a/khelo/lib/ui/flow/team/add_team/add_team_view_model.dart +++ b/khelo/lib/ui/flow/team/add_team/add_team_view_model.dart @@ -36,11 +36,13 @@ class AddTeamViewNotifier extends StateNotifier { : super(AddTeamState( nameController: TextEditingController(), locationController: TextEditingController(), + nameInitialsController: TextEditingController(), currentUser: user)); void setData({TeamModel? editTeam}) { state.nameController.text = editTeam?.name ?? ""; state.locationController.text = editTeam?.city ?? ""; + state.nameInitialsController.text = editTeam?.initials ?? ""; state = state.copyWith( editTeam: editTeam, teamMembers: editTeam?.players ?? []); } @@ -85,6 +87,7 @@ class AddTeamViewNotifier extends StateNotifier { final name = state.nameController.text.trim(); final location = state.locationController.text.trim(); + final initials = state.nameInitialsController.text.trim().toUpperCase(); List players = []; @@ -108,6 +111,7 @@ class AddTeamViewNotifier extends StateNotifier { name_lowercase: name.caseAndSpaceInsensitive, profile_img_url: imageUrl, city: location.toLowerCase(), + initials: initials, created_by: state.currentUser!.id, players: players, created_at: state.editTeam?.created_at ?? DateTime.now(), @@ -139,6 +143,7 @@ class AddTeamViewNotifier extends StateNotifier { name_lowercase: name.caseAndSpaceInsensitive, profile_img_url: imageUrl, city: location.toLowerCase(), + initials: initials, created_by: state.currentUser!.id, players: players, created_at: state.editTeam?.created_at ?? DateTime.now(), @@ -234,6 +239,7 @@ class AddTeamState with _$AddTeamState { const factory AddTeamState({ required TextEditingController nameController, required TextEditingController locationController, + required TextEditingController nameInitialsController, Object? actionError, String? filePath, bool? isNameAvailable, diff --git a/khelo/lib/ui/flow/team/add_team/add_team_view_model.freezed.dart b/khelo/lib/ui/flow/team/add_team/add_team_view_model.freezed.dart index f9521889..03c955c2 100644 --- a/khelo/lib/ui/flow/team/add_team/add_team_view_model.freezed.dart +++ b/khelo/lib/ui/flow/team/add_team/add_team_view_model.freezed.dart @@ -20,6 +20,8 @@ mixin _$AddTeamState { throw _privateConstructorUsedError; TextEditingController get locationController => throw _privateConstructorUsedError; + TextEditingController get nameInitialsController => + throw _privateConstructorUsedError; Object? get actionError => throw _privateConstructorUsedError; String? get filePath => throw _privateConstructorUsedError; bool? get isNameAvailable => throw _privateConstructorUsedError; @@ -50,6 +52,7 @@ abstract class $AddTeamStateCopyWith<$Res> { $Res call( {TextEditingController nameController, TextEditingController locationController, + TextEditingController nameInitialsController, Object? actionError, String? filePath, bool? isNameAvailable, @@ -86,6 +89,7 @@ class _$AddTeamStateCopyWithImpl<$Res, $Val extends AddTeamState> $Res call({ Object? nameController = null, Object? locationController = null, + Object? nameInitialsController = null, Object? actionError = freezed, Object? filePath = freezed, Object? isNameAvailable = freezed, @@ -109,6 +113,10 @@ class _$AddTeamStateCopyWithImpl<$Res, $Val extends AddTeamState> ? _value.locationController : locationController // ignore: cast_nullable_to_non_nullable as TextEditingController, + nameInitialsController: null == nameInitialsController + ? _value.nameInitialsController + : nameInitialsController // ignore: cast_nullable_to_non_nullable + as TextEditingController, actionError: freezed == actionError ? _value.actionError : actionError, filePath: freezed == filePath ? _value.filePath @@ -215,6 +223,7 @@ abstract class _$$AddTeamStateImplCopyWith<$Res> $Res call( {TextEditingController nameController, TextEditingController locationController, + TextEditingController nameInitialsController, Object? actionError, String? filePath, bool? isNameAvailable, @@ -252,6 +261,7 @@ class __$$AddTeamStateImplCopyWithImpl<$Res> $Res call({ Object? nameController = null, Object? locationController = null, + Object? nameInitialsController = null, Object? actionError = freezed, Object? filePath = freezed, Object? isNameAvailable = freezed, @@ -275,6 +285,10 @@ class __$$AddTeamStateImplCopyWithImpl<$Res> ? _value.locationController : locationController // ignore: cast_nullable_to_non_nullable as TextEditingController, + nameInitialsController: null == nameInitialsController + ? _value.nameInitialsController + : nameInitialsController // ignore: cast_nullable_to_non_nullable + as TextEditingController, actionError: freezed == actionError ? _value.actionError : actionError, filePath: freezed == filePath ? _value.filePath @@ -334,6 +348,7 @@ class _$AddTeamStateImpl implements _AddTeamState { const _$AddTeamStateImpl( {required this.nameController, required this.locationController, + required this.nameInitialsController, this.actionError, this.filePath, this.isNameAvailable, @@ -354,6 +369,8 @@ class _$AddTeamStateImpl implements _AddTeamState { @override final TextEditingController locationController; @override + final TextEditingController nameInitialsController; + @override final Object? actionError; @override final String? filePath; @@ -394,7 +411,7 @@ class _$AddTeamStateImpl implements _AddTeamState { @override String toString() { - return 'AddTeamState(nameController: $nameController, locationController: $locationController, actionError: $actionError, filePath: $filePath, isNameAvailable: $isNameAvailable, team: $team, editTeam: $editTeam, currentUser: $currentUser, isImageUploading: $isImageUploading, isAddMeCheckBoxEnable: $isAddMeCheckBoxEnable, checkingForAvailability: $checkingForAvailability, isAddBtnEnable: $isAddBtnEnable, isAddInProgress: $isAddInProgress, isPop: $isPop, teamMembers: $teamMembers)'; + return 'AddTeamState(nameController: $nameController, locationController: $locationController, nameInitialsController: $nameInitialsController, actionError: $actionError, filePath: $filePath, isNameAvailable: $isNameAvailable, team: $team, editTeam: $editTeam, currentUser: $currentUser, isImageUploading: $isImageUploading, isAddMeCheckBoxEnable: $isAddMeCheckBoxEnable, checkingForAvailability: $checkingForAvailability, isAddBtnEnable: $isAddBtnEnable, isAddInProgress: $isAddInProgress, isPop: $isPop, teamMembers: $teamMembers)'; } @override @@ -406,6 +423,8 @@ class _$AddTeamStateImpl implements _AddTeamState { other.nameController == nameController) && (identical(other.locationController, locationController) || other.locationController == locationController) && + (identical(other.nameInitialsController, nameInitialsController) || + other.nameInitialsController == nameInitialsController) && const DeepCollectionEquality() .equals(other.actionError, actionError) && (identical(other.filePath, filePath) || @@ -438,6 +457,7 @@ class _$AddTeamStateImpl implements _AddTeamState { runtimeType, nameController, locationController, + nameInitialsController, const DeepCollectionEquality().hash(actionError), filePath, isNameAvailable, @@ -465,6 +485,7 @@ abstract class _AddTeamState implements AddTeamState { const factory _AddTeamState( {required final TextEditingController nameController, required final TextEditingController locationController, + required final TextEditingController nameInitialsController, final Object? actionError, final String? filePath, final bool? isNameAvailable, @@ -484,6 +505,8 @@ abstract class _AddTeamState implements AddTeamState { @override TextEditingController get locationController; @override + TextEditingController get nameInitialsController; + @override Object? get actionError; @override String? get filePath; 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 8b734e06..050018c3 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_screen.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_screen.dart @@ -7,6 +7,7 @@ import 'package:khelo/components/app_page.dart'; import 'package:khelo/components/error_screen.dart'; import 'package:khelo/components/image_avatar.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/domain/formatter/date_formatter.dart'; import 'package:khelo/ui/app_route.dart'; @@ -91,7 +92,7 @@ class _TeamDetailScreenState extends ConsumerState { children: [ // profile view ImageAvatar( - initial: state.team?.name[0].toUpperCase() ?? "?", + initial: state.team?.initials ?? state.team?.name.initials(limit: 1) ?? "?", imageUrl: state.team?.profile_img_url, size: 48, ), diff --git a/khelo/lib/ui/flow/team/search_team/search_team_screen.dart b/khelo/lib/ui/flow/team/search_team/search_team_screen.dart index eae3d785..371bd031 100644 --- a/khelo/lib/ui/flow/team/search_team/search_team_screen.dart +++ b/khelo/lib/ui/flow/team/search_team/search_team_screen.dart @@ -8,6 +8,7 @@ import 'package:khelo/components/error_screen.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/domain/extensions/string_extensions.dart'; import 'package:khelo/domain/extensions/widget_extension.dart'; import 'package:khelo/ui/app_route.dart'; import 'package:khelo/ui/flow/team/search_team/components/team_member_sheet.dart'; @@ -167,7 +168,7 @@ class _SearchTeamScreenState extends ConsumerState { dense: true, contentPadding: EdgeInsets.zero, leading: ImageAvatar( - initial: team.name[0].toUpperCase(), + initial: team.initials ?? team.name.initials(limit: 1), imageUrl: team.profile_img_url, size: 40, ), diff --git a/khelo/lib/ui/flow/team/team_list_screen.dart b/khelo/lib/ui/flow/team/team_list_screen.dart index 143cb82e..5ab92f45 100644 --- a/khelo/lib/ui/flow/team/team_list_screen.dart +++ b/khelo/lib/ui/flow/team/team_list_screen.dart @@ -9,6 +9,7 @@ import 'package:khelo/components/empty_screen.dart'; import 'package:khelo/components/error_screen.dart'; import 'package:khelo/components/image_avatar.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/string_extensions.dart'; import 'package:khelo/ui/app_route.dart'; import 'package:khelo/ui/flow/team/team_list_view_model.dart'; import 'package:style/animations/on_tap_scale.dart'; @@ -111,7 +112,7 @@ class _TeamListScreenState extends ConsumerState child: ListTile( contentPadding: EdgeInsets.zero, leading: ImageAvatar( - initial: team.name[0].toUpperCase(), + initial: team.initials ?? team.name.initials(limit: 1), imageUrl: team.profile_img_url, size: 40, ), diff --git a/khelo/lib/ui/flow/team/user_detail/user_detail_screen.dart b/khelo/lib/ui/flow/team/user_detail/user_detail_screen.dart index 5b4a98b1..cec67da3 100644 --- a/khelo/lib/ui/flow/team/user_detail/user_detail_screen.dart +++ b/khelo/lib/ui/flow/team/user_detail/user_detail_screen.dart @@ -5,7 +5,6 @@ import 'package:khelo/components/app_page.dart'; import 'package:khelo/components/error_screen.dart'; import 'package:khelo/components/image_avatar.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/domain/formatter/string_formatter.dart'; import 'package:khelo/ui/flow/team/user_detail/component/user_detail_info_content.dart'; @@ -95,7 +94,7 @@ class _UserDetailScreenState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.start, children: [ ImageAvatar( - initial: state.user?.name?.initials(limit: 1) ?? "?", + initial: state.user?.nameInitial ?? "?", imageUrl: state.user?.profile_img_url, size: 48, ), diff --git a/khelo/macos/Runner.xcodeproj/project.pbxproj b/khelo/macos/Runner.xcodeproj/project.pbxproj index b3014c8b..2841b4f4 100644 --- a/khelo/macos/Runner.xcodeproj/project.pbxproj +++ b/khelo/macos/Runner.xcodeproj/project.pbxproj @@ -212,7 +212,7 @@ 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - C6EC651590B00B7478981FF0 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */, + 85D131AFCC1E02E7FB7F623B /* FlutterFire: "flutterfire upload-crashlytics-symbols" */, ); buildRules = ( ); @@ -333,7 +333,7 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - C6EC651590B00B7478981FF0 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = { + 85D131AFCC1E02E7FB7F623B /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( diff --git a/style/lib/text/app_text_field.dart b/style/lib/text/app_text_field.dart index 4a64f19a..9996c72b 100644 --- a/style/lib/text/app_text_field.dart +++ b/style/lib/text/app_text_field.dart @@ -37,6 +37,7 @@ class AppTextField extends StatelessWidget { final Widget? prefixIcon; final BoxConstraints? prefixIconConstraints; final List? inputFormatters; + final TextCapitalization textCapitalization; final Function(PointerDownEvent)? onTapOutside; const AppTextField({ @@ -70,6 +71,7 @@ class AppTextField extends StatelessWidget { this.keyboardType, this.focusNode, this.inputFormatters, + this.textCapitalization = TextCapitalization.none, this.prefixIcon, this.prefixIconConstraints, this.textAlign = TextAlign.start, @@ -109,6 +111,7 @@ class AppTextField extends StatelessWidget { maxLines: maxLines, minLines: minLines, inputFormatters: inputFormatters, + textCapitalization: textCapitalization, expands: expands, textInputAction: textInputAction, autofocus: autoFocus, diff --git a/style/lib/text/text_input_formatter.dart b/style/lib/text/text_input_formatter.dart new file mode 100644 index 00000000..3cae183c --- /dev/null +++ b/style/lib/text/text_input_formatter.dart @@ -0,0 +1,12 @@ +import 'package:flutter/services.dart'; + +class UpperCaseTextFormatter extends TextInputFormatter { + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { + return TextEditingValue( + text: newValue.text.toUpperCase(), + selection: newValue.selection, + ); + } +}