From 2e0d11930273e7e00f5ba1f1d6ed37253aa6d665 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Fri, 9 Aug 2024 11:24:00 +0530 Subject: [PATCH 01/20] Allow team to add multiple admin --- data/lib/api/team/team_model.dart | 49 ++- data/lib/api/team/team_model.freezed.dart | 339 +++++++----------- data/lib/api/team/team_model.g.dart | 39 +- data/lib/service/team/team_service.dart | 213 ++++------- .../utils/constant/firestore_constant.dart | 1 + khelo/assets/locales/app_en.arb | 2 + .../add_match/add_match_view_model.dart | 3 +- .../select_squad/select_squad_screen.dart | 3 +- .../components/match_detail_squad_view.dart | 6 +- .../flow/team/add_team/add_team_screen.dart | 10 +- .../team/add_team/add_team_view_model.dart | 23 +- .../add_team/add_team_view_model.freezed.dart | 20 +- .../add_team_member_screen.dart | 24 +- .../add_team_member_view_model.dart | 12 +- .../add_team_member_view_model.freezed.dart | 20 +- .../components/team_detail_match_content.dart | 6 +- .../team_detail_member_content.dart | 18 +- .../flow/team/detail/team_detail_screen.dart | 6 +- .../team/detail/team_detail_view_model.dart | 3 +- .../components/team_member_sheet.dart | 33 +- .../search_team/search_team_view_model.dart | 8 +- .../ui/flow/team/team_list_view_model.dart | 2 +- khelo/pubspec.lock | 32 +- 23 files changed, 368 insertions(+), 504 deletions(-) diff --git a/data/lib/api/team/team_model.dart b/data/lib/api/team/team_model.dart index 26a45352..9794a9fb 100644 --- a/data/lib/api/team/team_model.dart +++ b/data/lib/api/team/team_model.dart @@ -18,31 +18,42 @@ class TeamModel with _$TeamModel { String? profile_img_url, String? created_by, DateTime? created_at, - List? players, + @JsonKey(includeToJson: false, includeFromJson: false) + List? players, }) = _TeamModel; factory TeamModel.fromJson(Map json) => _$TeamModelFromJson(json); + + factory TeamModel.fromFireStore( + DocumentSnapshot> snapshot, + SnapshotOptions? options) => + TeamModel.fromJson(snapshot.data()!); } -@freezed -class AddTeamRequestModel with _$AddTeamRequestModel { - const factory AddTeamRequestModel({ - String? id, - required String name, - required String name_lowercase, - String? city, - String? profile_img_url, - String? created_by, - DateTime? created_at, - List? players, - }) = _AddTeamRequestModel; +enum TeamPlayerRole { + admin, + player; - factory AddTeamRequestModel.fromJson(Map json) => - _$AddTeamRequestModelFromJson(json); + bool get isAdmin => this == TeamPlayerRole.admin; - factory AddTeamRequestModel.fromFireStore( - DocumentSnapshot> snapshot, - SnapshotOptions? options) => - AddTeamRequestModel.fromJson(snapshot.data()!); + bool get isMember => this == TeamPlayerRole.player; +} + +@freezed +class TeamPlayer with _$TeamPlayer { + const factory TeamPlayer({ + required String id, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? detail, + @Default(TeamPlayerRole.player) TeamPlayerRole role, + }) = _TeamPlayer; + + factory TeamPlayer.fromJson(Map json) => + _$TeamPlayerFromJson(json); + + factory TeamPlayer.fromFireStore( + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => + TeamPlayer.fromJson(snapshot.data()!); } diff --git a/data/lib/api/team/team_model.freezed.dart b/data/lib/api/team/team_model.freezed.dart index 9edd4616..e40e7bc2 100644 --- a/data/lib/api/team/team_model.freezed.dart +++ b/data/lib/api/team/team_model.freezed.dart @@ -27,7 +27,8 @@ mixin _$TeamModel { String? get profile_img_url => throw _privateConstructorUsedError; String? get created_by => throw _privateConstructorUsedError; DateTime? get created_at => throw _privateConstructorUsedError; - List? get players => throw _privateConstructorUsedError; + @JsonKey(includeToJson: false, includeFromJson: false) + List? get players => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -48,7 +49,8 @@ abstract class $TeamModelCopyWith<$Res> { String? profile_img_url, String? created_by, DateTime? created_at, - List? players}); + @JsonKey(includeToJson: false, includeFromJson: false) + List? players}); } /// @nodoc @@ -105,7 +107,7 @@ class _$TeamModelCopyWithImpl<$Res, $Val extends TeamModel> players: freezed == players ? _value.players : players // ignore: cast_nullable_to_non_nullable - as List?, + as List?, ) as $Val); } } @@ -126,7 +128,8 @@ abstract class _$$TeamModelImplCopyWith<$Res> String? profile_img_url, String? created_by, DateTime? created_at, - List? players}); + @JsonKey(includeToJson: false, includeFromJson: false) + List? players}); } /// @nodoc @@ -181,7 +184,7 @@ class __$$TeamModelImplCopyWithImpl<$Res> players: freezed == players ? _value._players : players // ignore: cast_nullable_to_non_nullable - as List?, + as List?, )); } } @@ -197,7 +200,8 @@ class _$TeamModelImpl implements _TeamModel { this.profile_img_url, this.created_by, this.created_at, - final List? players}) + @JsonKey(includeToJson: false, includeFromJson: false) + final List? players}) : _players = players; factory _$TeamModelImpl.fromJson(Map json) => @@ -217,9 +221,10 @@ class _$TeamModelImpl implements _TeamModel { final String? created_by; @override final DateTime? created_at; - final List? _players; + final List? _players; @override - List? get players { + @JsonKey(includeToJson: false, includeFromJson: false) + List? get players { final value = _players; if (value == null) return null; if (_players is EqualUnmodifiableListView) return _players; @@ -287,7 +292,8 @@ abstract class _TeamModel implements TeamModel { final String? profile_img_url, final String? created_by, final DateTime? created_at, - final List? players}) = _$TeamModelImpl; + @JsonKey(includeToJson: false, includeFromJson: false) + final List? players}) = _$TeamModelImpl; factory _TeamModel.fromJson(Map json) = _$TeamModelImpl.fromJson; @@ -307,55 +313,49 @@ abstract class _TeamModel implements TeamModel { @override DateTime? get created_at; @override - List? get players; + @JsonKey(includeToJson: false, includeFromJson: false) + List? get players; @override @JsonKey(ignore: true) _$$TeamModelImplCopyWith<_$TeamModelImpl> get copyWith => throw _privateConstructorUsedError; } -AddTeamRequestModel _$AddTeamRequestModelFromJson(Map json) { - return _AddTeamRequestModel.fromJson(json); +TeamPlayer _$TeamPlayerFromJson(Map json) { + return _TeamPlayer.fromJson(json); } /// @nodoc -mixin _$AddTeamRequestModel { - String? get id => throw _privateConstructorUsedError; - String get name => throw _privateConstructorUsedError; - String get name_lowercase => throw _privateConstructorUsedError; - String? get city => throw _privateConstructorUsedError; - String? get profile_img_url => throw _privateConstructorUsedError; - String? get created_by => throw _privateConstructorUsedError; - DateTime? get created_at => throw _privateConstructorUsedError; - List? get players => throw _privateConstructorUsedError; +mixin _$TeamPlayer { + String get id => throw _privateConstructorUsedError; + @JsonKey(includeToJson: false, includeFromJson: false) + UserModel? get detail => throw _privateConstructorUsedError; + TeamPlayerRole get role => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) - $AddTeamRequestModelCopyWith get copyWith => + $TeamPlayerCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class $AddTeamRequestModelCopyWith<$Res> { - factory $AddTeamRequestModelCopyWith( - AddTeamRequestModel value, $Res Function(AddTeamRequestModel) then) = - _$AddTeamRequestModelCopyWithImpl<$Res, AddTeamRequestModel>; +abstract class $TeamPlayerCopyWith<$Res> { + factory $TeamPlayerCopyWith( + TeamPlayer value, $Res Function(TeamPlayer) then) = + _$TeamPlayerCopyWithImpl<$Res, TeamPlayer>; @useResult $Res call( - {String? id, - String name, - String name_lowercase, - String? city, - String? profile_img_url, - String? created_by, - DateTime? created_at, - List? players}); + {String id, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? detail, + TeamPlayerRole role}); + + $UserModelCopyWith<$Res>? get detail; } /// @nodoc -class _$AddTeamRequestModelCopyWithImpl<$Res, $Val extends AddTeamRequestModel> - implements $AddTeamRequestModelCopyWith<$Res> { - _$AddTeamRequestModelCopyWithImpl(this._value, this._then); +class _$TeamPlayerCopyWithImpl<$Res, $Val extends TeamPlayer> + implements $TeamPlayerCopyWith<$Res> { + _$TeamPlayerCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; @@ -365,253 +365,160 @@ class _$AddTeamRequestModelCopyWithImpl<$Res, $Val extends AddTeamRequestModel> @pragma('vm:prefer-inline') @override $Res call({ - Object? id = freezed, - Object? name = null, - Object? name_lowercase = null, - Object? city = freezed, - Object? profile_img_url = freezed, - Object? created_by = freezed, - Object? created_at = freezed, - Object? players = freezed, + Object? id = null, + Object? detail = freezed, + Object? role = null, }) { return _then(_value.copyWith( - id: freezed == id + 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, - name_lowercase: null == name_lowercase - ? _value.name_lowercase - : name_lowercase // ignore: cast_nullable_to_non_nullable as String, - city: freezed == city - ? _value.city - : city // 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 - as String?, - created_by: freezed == created_by - ? _value.created_by - : created_by // ignore: cast_nullable_to_non_nullable - as String?, - created_at: freezed == created_at - ? _value.created_at - : created_at // ignore: cast_nullable_to_non_nullable - as DateTime?, - players: freezed == players - ? _value.players - : players // ignore: cast_nullable_to_non_nullable - as List?, + detail: freezed == detail + ? _value.detail + : detail // ignore: cast_nullable_to_non_nullable + as UserModel?, + role: null == role + ? _value.role + : role // ignore: cast_nullable_to_non_nullable + as TeamPlayerRole, ) as $Val); } + + @override + @pragma('vm:prefer-inline') + $UserModelCopyWith<$Res>? get detail { + if (_value.detail == null) { + return null; + } + + return $UserModelCopyWith<$Res>(_value.detail!, (value) { + return _then(_value.copyWith(detail: value) as $Val); + }); + } } /// @nodoc -abstract class _$$AddTeamRequestModelImplCopyWith<$Res> - implements $AddTeamRequestModelCopyWith<$Res> { - factory _$$AddTeamRequestModelImplCopyWith(_$AddTeamRequestModelImpl value, - $Res Function(_$AddTeamRequestModelImpl) then) = - __$$AddTeamRequestModelImplCopyWithImpl<$Res>; +abstract class _$$TeamPlayerImplCopyWith<$Res> + implements $TeamPlayerCopyWith<$Res> { + factory _$$TeamPlayerImplCopyWith( + _$TeamPlayerImpl value, $Res Function(_$TeamPlayerImpl) then) = + __$$TeamPlayerImplCopyWithImpl<$Res>; @override @useResult $Res call( - {String? id, - String name, - String name_lowercase, - String? city, - String? profile_img_url, - String? created_by, - DateTime? created_at, - List? players}); + {String id, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? detail, + TeamPlayerRole role}); + + @override + $UserModelCopyWith<$Res>? get detail; } /// @nodoc -class __$$AddTeamRequestModelImplCopyWithImpl<$Res> - extends _$AddTeamRequestModelCopyWithImpl<$Res, _$AddTeamRequestModelImpl> - implements _$$AddTeamRequestModelImplCopyWith<$Res> { - __$$AddTeamRequestModelImplCopyWithImpl(_$AddTeamRequestModelImpl _value, - $Res Function(_$AddTeamRequestModelImpl) _then) +class __$$TeamPlayerImplCopyWithImpl<$Res> + extends _$TeamPlayerCopyWithImpl<$Res, _$TeamPlayerImpl> + implements _$$TeamPlayerImplCopyWith<$Res> { + __$$TeamPlayerImplCopyWithImpl( + _$TeamPlayerImpl _value, $Res Function(_$TeamPlayerImpl) _then) : super(_value, _then); @pragma('vm:prefer-inline') @override $Res call({ - Object? id = freezed, - Object? name = null, - Object? name_lowercase = null, - Object? city = freezed, - Object? profile_img_url = freezed, - Object? created_by = freezed, - Object? created_at = freezed, - Object? players = freezed, + Object? id = null, + Object? detail = freezed, + Object? role = null, }) { - return _then(_$AddTeamRequestModelImpl( - id: freezed == id + return _then(_$TeamPlayerImpl( + 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, - name_lowercase: null == name_lowercase - ? _value.name_lowercase - : name_lowercase // ignore: cast_nullable_to_non_nullable as String, - city: freezed == city - ? _value.city - : city // 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 - as String?, - created_by: freezed == created_by - ? _value.created_by - : created_by // ignore: cast_nullable_to_non_nullable - as String?, - created_at: freezed == created_at - ? _value.created_at - : created_at // ignore: cast_nullable_to_non_nullable - as DateTime?, - players: freezed == players - ? _value._players - : players // ignore: cast_nullable_to_non_nullable - as List?, + detail: freezed == detail + ? _value.detail + : detail // ignore: cast_nullable_to_non_nullable + as UserModel?, + role: null == role + ? _value.role + : role // ignore: cast_nullable_to_non_nullable + as TeamPlayerRole, )); } } /// @nodoc @JsonSerializable() -class _$AddTeamRequestModelImpl implements _AddTeamRequestModel { - const _$AddTeamRequestModelImpl( - {this.id, - required this.name, - required this.name_lowercase, - this.city, - this.profile_img_url, - this.created_by, - this.created_at, - final List? players}) - : _players = players; +class _$TeamPlayerImpl implements _TeamPlayer { + const _$TeamPlayerImpl( + {required this.id, + @JsonKey(includeToJson: false, includeFromJson: false) this.detail, + this.role = TeamPlayerRole.player}); - factory _$AddTeamRequestModelImpl.fromJson(Map json) => - _$$AddTeamRequestModelImplFromJson(json); + factory _$TeamPlayerImpl.fromJson(Map json) => + _$$TeamPlayerImplFromJson(json); @override - final String? id; + final String id; @override - final String name; + @JsonKey(includeToJson: false, includeFromJson: false) + final UserModel? detail; @override - final String name_lowercase; - @override - final String? city; - @override - final String? profile_img_url; - @override - final String? created_by; - @override - final DateTime? created_at; - final List? _players; - @override - List? get players { - final value = _players; - if (value == null) return null; - if (_players is EqualUnmodifiableListView) return _players; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(value); - } + @JsonKey() + final TeamPlayerRole role; @override String toString() { - return 'AddTeamRequestModel(id: $id, name: $name, name_lowercase: $name_lowercase, city: $city, profile_img_url: $profile_img_url, created_by: $created_by, created_at: $created_at, players: $players)'; + return 'TeamPlayer(id: $id, detail: $detail, role: $role)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$AddTeamRequestModelImpl && + other is _$TeamPlayerImpl && (identical(other.id, id) || other.id == id) && - (identical(other.name, name) || other.name == name) && - (identical(other.name_lowercase, name_lowercase) || - other.name_lowercase == name_lowercase) && - (identical(other.city, city) || other.city == city) && - (identical(other.profile_img_url, profile_img_url) || - other.profile_img_url == profile_img_url) && - (identical(other.created_by, created_by) || - other.created_by == created_by) && - (identical(other.created_at, created_at) || - other.created_at == created_at) && - const DeepCollectionEquality().equals(other._players, _players)); + (identical(other.detail, detail) || other.detail == detail) && + (identical(other.role, role) || other.role == role)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash( - runtimeType, - id, - name, - name_lowercase, - city, - profile_img_url, - created_by, - created_at, - const DeepCollectionEquality().hash(_players)); + int get hashCode => Object.hash(runtimeType, id, detail, role); @JsonKey(ignore: true) @override @pragma('vm:prefer-inline') - _$$AddTeamRequestModelImplCopyWith<_$AddTeamRequestModelImpl> get copyWith => - __$$AddTeamRequestModelImplCopyWithImpl<_$AddTeamRequestModelImpl>( - this, _$identity); + _$$TeamPlayerImplCopyWith<_$TeamPlayerImpl> get copyWith => + __$$TeamPlayerImplCopyWithImpl<_$TeamPlayerImpl>(this, _$identity); @override Map toJson() { - return _$$AddTeamRequestModelImplToJson( + return _$$TeamPlayerImplToJson( this, ); } } -abstract class _AddTeamRequestModel implements AddTeamRequestModel { - const factory _AddTeamRequestModel( - {final String? id, - required final String name, - required final String name_lowercase, - final String? city, - final String? profile_img_url, - final String? created_by, - final DateTime? created_at, - final List? players}) = _$AddTeamRequestModelImpl; +abstract class _TeamPlayer implements TeamPlayer { + const factory _TeamPlayer( + {required final String id, + @JsonKey(includeToJson: false, includeFromJson: false) + final UserModel? detail, + final TeamPlayerRole role}) = _$TeamPlayerImpl; - factory _AddTeamRequestModel.fromJson(Map json) = - _$AddTeamRequestModelImpl.fromJson; + factory _TeamPlayer.fromJson(Map json) = + _$TeamPlayerImpl.fromJson; @override - String? get id; - @override - String get name; - @override - String get name_lowercase; - @override - String? get city; + String get id; @override - String? get profile_img_url; - @override - String? get created_by; - @override - DateTime? get created_at; + @JsonKey(includeToJson: false, includeFromJson: false) + UserModel? get detail; @override - List? get players; + TeamPlayerRole get role; @override @JsonKey(ignore: true) - _$$AddTeamRequestModelImplCopyWith<_$AddTeamRequestModelImpl> get copyWith => + _$$TeamPlayerImplCopyWith<_$TeamPlayerImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/data/lib/api/team/team_model.g.dart b/data/lib/api/team/team_model.g.dart index 0abcb73f..1e9d2795 100644 --- a/data/lib/api/team/team_model.g.dart +++ b/data/lib/api/team/team_model.g.dart @@ -17,9 +17,6 @@ _$TeamModelImpl _$$TeamModelImplFromJson(Map json) => created_at: json['created_at'] == null ? null : DateTime.parse(json['created_at'] as String), - players: (json['players'] as List?) - ?.map((e) => UserModel.fromJson(e as Map)) - .toList(), ); Map _$$TeamModelImplToJson(_$TeamModelImpl instance) => @@ -31,34 +28,22 @@ Map _$$TeamModelImplToJson(_$TeamModelImpl instance) => 'profile_img_url': instance.profile_img_url, 'created_by': instance.created_by, 'created_at': instance.created_at?.toIso8601String(), - 'players': instance.players, }; -_$AddTeamRequestModelImpl _$$AddTeamRequestModelImplFromJson( - Map json) => - _$AddTeamRequestModelImpl( - id: json['id'] as String?, - name: json['name'] as String, - name_lowercase: json['name_lowercase'] as String, - city: json['city'] as String?, - profile_img_url: json['profile_img_url'] as String?, - created_by: json['created_by'] as String?, - created_at: json['created_at'] == null - ? null - : DateTime.parse(json['created_at'] as String), - players: - (json['players'] as List?)?.map((e) => e as String).toList(), +_$TeamPlayerImpl _$$TeamPlayerImplFromJson(Map json) => + _$TeamPlayerImpl( + id: json['id'] as String, + role: $enumDecodeNullable(_$TeamPlayerRoleEnumMap, json['role']) ?? + TeamPlayerRole.player, ); -Map _$$AddTeamRequestModelImplToJson( - _$AddTeamRequestModelImpl instance) => +Map _$$TeamPlayerImplToJson(_$TeamPlayerImpl instance) => { 'id': instance.id, - 'name': instance.name, - 'name_lowercase': instance.name_lowercase, - 'city': instance.city, - 'profile_img_url': instance.profile_img_url, - 'created_by': instance.created_by, - 'created_at': instance.created_at?.toIso8601String(), - 'players': instance.players, + 'role': _$TeamPlayerRoleEnumMap[instance.role]!, }; + +const _$TeamPlayerRoleEnumMap = { + TeamPlayerRole.admin: 'admin', + TeamPlayerRole.player: 'player', +}; diff --git a/data/lib/service/team/team_service.dart b/data/lib/service/team/team_service.dart index 62e2c5b9..65f1b0b1 100644 --- a/data/lib/service/team/team_service.dart +++ b/data/lib/service/team/team_service.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/team/team_model.dart'; -import 'package:data/api/user/user_models.dart'; import 'package:data/errors/app_error.dart'; import 'package:data/extensions/string_extensions.dart'; import 'package:data/service/user/user_service.dart'; @@ -27,131 +26,85 @@ class TeamService { final FirebaseFirestore firestore; final UserService _userService; - final CollectionReference _teamsCollection; - TeamService(this._currentUserId, this.firestore, this._userService) - : _teamsCollection = firestore - .collection(FireStoreConst.teamsCollection) - .withConverter( - fromFirestore: AddTeamRequestModel.fromFireStore, - toFirestore: (AddTeamRequestModel team, _) => team.toJson()); + TeamService(this._currentUserId, this.firestore, this._userService); - Future getTeamById(String teamId) async { - try { - final teamDoc = await _teamsCollection.doc(teamId).get(); - - final teamRequestModel = teamDoc.data(); - - if (teamRequestModel == null) { - return deActiveDummyTeamModel(teamId); - } + CollectionReference get _teamCollection => + firestore.collection(FireStoreConst.teamsCollection).withConverter( + fromFirestore: TeamModel.fromFireStore, + toFirestore: (TeamModel team, _) => team.toJson()); - final member = (teamRequestModel.players?.isNotEmpty ?? false) - ? await getMemberListFromUserIds(teamRequestModel.players ?? []) - : null; + CollectionReference _playersCollection(String teamId) => + _teamCollection + .doc(teamId) + .collection(FireStoreConst.playersCollection) + .withConverter( + fromFirestore: TeamPlayer.fromFireStore, + toFirestore: (value, options) => value.toJson()); - final team = TeamModel( - name: teamRequestModel.name, - name_lowercase: teamRequestModel.name_lowercase, - id: teamRequestModel.id, - city: teamRequestModel.city, - created_at: teamRequestModel.created_at, - created_by: teamRequestModel.created_by, - profile_img_url: teamRequestModel.profile_img_url, - players: member); - - return team; + Future getTeamById(String teamId) async { + try { + final team = await _teamCollection.doc(teamId).get(); + final players = await getTeamPlayers(teamId); + return team.data()?.copyWith(players: players) ?? + deActiveDummyTeamModel(teamId); } catch (error, stack) { throw AppError.fromError(error, stack); } } - Stream getTeamStreamById(String teamId) { - return _teamsCollection.doc(teamId).snapshots().asyncMap((teamDoc) async { - final teamRequestModel = teamDoc.data(); - if (teamRequestModel == null) { - return deActiveDummyTeamModel(teamId); - } - final member = (teamRequestModel.players?.isNotEmpty ?? false) - ? await getMemberListFromUserIds(teamRequestModel.players ?? []) - : null; - - final team = TeamModel( - name: teamRequestModel.name, - name_lowercase: teamRequestModel.name_lowercase, - id: teamRequestModel.id, - city: teamRequestModel.city, - created_at: teamRequestModel.created_at, - created_by: teamRequestModel.created_by, - profile_img_url: teamRequestModel.profile_img_url, - players: member); - return team; + Stream streamTeam(String teamId) { + return _teamCollection.doc(teamId).snapshots().asyncMap((event) async { + final players = await getTeamPlayers(teamId); + return event.data()?.copyWith(players: players) ?? + deActiveDummyTeamModel(teamId); }).handleError((error, stack) => AppError.fromError(error, stack)); } - Stream> getUserRelatedTeams() { + Future> getTeamPlayers(String teamId) async { + final data = await _playersCollection(teamId).get(); + + final futures = data.docs.map((player) async { + final detail = await _userService.getUserById(player.id); + return player.data().copyWith(detail: detail); + }).toList(); + + return Future.wait(futures); + } + + Stream> streamUserRelatedTeams() { if (_currentUserId == null) { return Stream.value([]); } - final filter = Filter.or( - Filter(FireStoreConst.createdBy, isEqualTo: _currentUserId), - Filter(FireStoreConst.players, arrayContains: _currentUserId), - ); - return _teamsCollection - .where(filter) - .snapshots() - .asyncMap((snapshot) async { - return await Future.wait(snapshot.docs.map((mainDoc) async { - AddTeamRequestModel teamRequestModel = mainDoc.data(); - final member = (teamRequestModel.players?.isNotEmpty ?? false) - ? await getMemberListFromUserIds(teamRequestModel.players ?? []) + return _teamCollection.snapshots().asyncMap((snapshot) async { + final futures = snapshot.docs.map((doc) async { + final teamId = doc.id; + final playersSnapshot = await _playersCollection(teamId) + .where('id', isEqualTo: _currentUserId) + .get(); + final players = playersSnapshot.docs.map((e) => e.data()).toList(); + return (players.isNotEmpty) + ? doc.data().copyWith(players: players) : null; + }).toList(); - final team = TeamModel( - name: teamRequestModel.name, - name_lowercase: teamRequestModel.name_lowercase, - id: teamRequestModel.id, - city: teamRequestModel.city, - created_at: teamRequestModel.created_at, - created_by: teamRequestModel.created_by, - profile_img_url: teamRequestModel.profile_img_url, - players: member, - ); - return team; - })); + final results = await Future.wait(futures); + return results.whereType().toList(); }).handleError((error, stack) => throw AppError.fromError(error, stack)); } Stream> getUserOwnedTeams() { - return _teamsCollection + return _teamCollection .where(FireStoreConst.createdBy, isEqualTo: _currentUserId) .snapshots() - .asyncMap((snapshot) async { - return await Future.wait(snapshot.docs.map((mainDoc) async { - AddTeamRequestModel teamRequestModel = mainDoc.data(); - - final member = (teamRequestModel.players?.isNotEmpty ?? false) - ? await getMemberListFromUserIds(teamRequestModel.players ?? []) - : null; - - final team = TeamModel( - name: teamRequestModel.name, - name_lowercase: teamRequestModel.name_lowercase, - id: teamRequestModel.id, - city: teamRequestModel.city, - created_at: teamRequestModel.created_at, - created_by: teamRequestModel.created_by, - profile_img_url: teamRequestModel.profile_img_url, - players: member); - return team; - }).toList()); - }).handleError((error, stack) => throw AppError.fromError(error, stack)); + .map((event) => event.docs.map((e) => e.data()).toList()) + .handleError((error, stack) => throw AppError.fromError(error, stack)); } - Future updateTeam(AddTeamRequestModel team) async { + Future updateTeam(TeamModel team) async { try { - final teamRef = _teamsCollection.doc(team.id); + final teamRef = _teamCollection.doc(team.id); await teamRef.set(team.copyWith(id: teamRef.id), SetOptions(merge: true)); return teamRef.id; } catch (error, stack) { @@ -161,7 +114,7 @@ class TeamService { Future updateProfileImageUrl(String teamId, String? imageUrl) async { try { - final teamRef = _teamsCollection.doc(teamId); + final teamRef = _teamCollection.doc(teamId); await teamRef.update({ FireStoreConst.profileImageUrl: imageUrl, }); @@ -170,11 +123,14 @@ class TeamService { } } - Future addPlayersToTeam(String teamId, List players) async { + Future addPlayersToTeam(String teamId, List players) async { try { - final teamRef = _teamsCollection.doc(teamId); - await teamRef - .update({FireStoreConst.players: FieldValue.arrayUnion(players)}); + WriteBatch batch = firestore.batch(); + for (final player in players) { + batch.set(_playersCollection(teamId).doc(player.id), player, + SetOptions(merge: true)); + } + await batch.commit(); } catch (error, stack) { throw AppError.fromError(error, stack); } @@ -183,9 +139,12 @@ class TeamService { Future removePlayersFromTeam( String teamId, List playerIds) async { try { - final teamRef = _teamsCollection.doc(teamId); - await teamRef - .update({FireStoreConst.players: FieldValue.arrayRemove(playerIds)}); + WriteBatch batch = firestore.batch(); + final playerRef = _playersCollection(teamId); + for (final id in playerIds) { + batch.delete(playerRef.doc(id)); + } + batch.commit(); } catch (error, stack) { throw AppError.fromError(error, stack); } @@ -193,7 +152,7 @@ class TeamService { Future isTeamNameAvailable(String teamName) async { try { - QuerySnapshot teamSnap = await _teamsCollection + QuerySnapshot teamSnap = await _teamCollection .where(FireStoreConst.nameLowercase, isEqualTo: teamName.caseAndSpaceInsensitive) .get(); @@ -206,36 +165,14 @@ class TeamService { Future> searchTeam(String searchKey) async { try { - final snapshot = await _teamsCollection + final snapshot = await _teamCollection .where(FireStoreConst.nameLowercase, isGreaterThanOrEqualTo: searchKey.caseAndSpaceInsensitive) .where(FireStoreConst.nameLowercase, isLessThan: '${searchKey.caseAndSpaceInsensitive}z') .get(); - List teams = []; - - for (final mainDoc in snapshot.docs) { - AddTeamRequestModel teamRequestModel = mainDoc.data(); - - final member = (teamRequestModel.players?.isNotEmpty ?? false) - ? await getMemberListFromUserIds(teamRequestModel.players ?? []) - : null; - - final team = TeamModel( - name: teamRequestModel.name, - name_lowercase: teamRequestModel.name_lowercase, - id: teamRequestModel.id, - city: teamRequestModel.city, - created_at: teamRequestModel.created_at, - created_by: teamRequestModel.created_by, - profile_img_url: teamRequestModel.profile_img_url, - players: member); - - teams.add(team); - } - - return teams; + return snapshot.docs.map((e) => e.data()).toList(); } catch (error, stack) { throw AppError.fromError(error, stack); } @@ -243,17 +180,7 @@ class TeamService { Future deleteTeam(String teamId) async { try { - await _teamsCollection.doc(teamId).delete(); - } catch (error, stack) { - throw AppError.fromError(error, stack); - } - } - - // Helper Method - Future> getMemberListFromUserIds(List users) async { - try { - final userList = await _userService.getUsersByIds(users); - return userList; + await _teamCollection.doc(teamId).delete(); } catch (error, stack) { throw AppError.fromError(error, stack); } diff --git a/data/lib/utils/constant/firestore_constant.dart b/data/lib/utils/constant/firestore_constant.dart index cee197bc..1b58a37b 100644 --- a/data/lib/utils/constant/firestore_constant.dart +++ b/data/lib/utils/constant/firestore_constant.dart @@ -2,6 +2,7 @@ class FireStoreConst { // collection static const String matchesCollection = "matches"; static const String teamsCollection = "teams"; + static const String playersCollection="team_players"; static const String inningsCollection = "innings"; static const String ballScoresCollection = "ball_scores"; static const String usersCollection = "users"; diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index edacd85b..6ace53ba 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -244,6 +244,8 @@ "team_detail_empty_stat_title": "No stats available yet!", "team_detail_empty_stat_description_text": "The players are warming up! Stay tuned for exciting stats as the team progresses.", "team_detail_add_member_title": "Add member", + "team_detail_make_admin": "Make admin", + "team_detail_admin": "{count} admin", "team_detail_match_tab_title": "Match", "team_detail_stat_tab_title": "Stat", "team_detail_won_title": "Won({win})", diff --git a/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart b/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart index 00c1d658..8bf70e25 100644 --- a/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart +++ b/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart @@ -234,7 +234,8 @@ class AddMatchViewNotifier extends StateNotifier { void onTeamSelect(TeamModel team, TeamType type) { final matchPlayer = team.players ?.take(11) - .map((e) => MatchPlayer(player: e, status: PlayerStatus.yetToPlay)) + .map((e) => + MatchPlayer(player: e.detail!, status: PlayerStatus.yetToPlay)) .toList(); final captainAndAdminId = matchPlayer?.firstOrNull?.player.id; diff --git a/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart b/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart index 24b7d003..3858b710 100644 --- a/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart +++ b/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart @@ -188,7 +188,8 @@ class _SelectSquadScreenState extends ConsumerState { return state.team?.players ?.where((element) => !state.squad.map((e) => e.player.id).contains(element.id) && - element.isActive) + element.detail!.isActive) + .map((e) => e.detail!) .toList() ?? []; } 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 15a6ab17..a13fbb5a 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 @@ -55,14 +55,16 @@ class MatchDetailSquadView extends ConsumerWidget { final firstTeamBench = firstTeam?.team.players ?.where((element) => !firstTeamSquad.map((e) => e.id).contains(element.id) && - element.isActive) + element.detail!.isActive) + .map((e) => e.detail!) .toList() ?? []; final secondTeamBench = secondTeam?.team.players ?.where((element) => !secondTeamSquad.map((e) => e.id).contains(element.id) && - element.isActive) + element.detail!.isActive) + .map((e) => e.detail!) .toList() ?? []; 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 88f2641c..963670c1 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 @@ -1,5 +1,4 @@ import 'package:data/api/team/team_model.dart'; -import 'package:data/api/user/user_models.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -157,7 +156,7 @@ class _AddTeamScreenState extends ConsumerState { final members = await AppRoute.addTeamMember( team: widget.editTeam! .copyWith(players: state.teamMembers)) - .push>(context); + .push>(context); if (context.mounted && (members ?? []).isNotEmpty) { notifier.updatePlayersList(members!); } @@ -187,10 +186,11 @@ class _AddTeamScreenState extends ConsumerState { (player) => Padding( padding: const EdgeInsets.only(top: 16), child: UserDetailCell( - user: player, - onTap: () => UserDetailSheet.show(context, player), + user: player.detail!, + onTap: () => UserDetailSheet.show(context, player.detail!), trailing: actionButton(context, - onPressed: () => notifier.onRemoveUserFromTeam(player), + onPressed: () => + notifier.onRemoveUserFromTeam(player.detail!), padding: const EdgeInsets.only( left: 10, top: 10, bottom: 10), icon: Icon( 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 e394fcec..03db5180 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 @@ -49,7 +49,7 @@ class AddTeamViewNotifier extends StateNotifier { state = state.copyWith(currentUser: user); } - void updatePlayersList(List players) { + void updatePlayersList(List players) { if (state.editTeam == null) { return; } @@ -86,29 +86,37 @@ class AddTeamViewNotifier extends StateNotifier { final name = state.nameController.text.trim(); final location = state.locationController.text.trim(); - List players = []; + List players = []; if (state.isAddMeCheckBoxEnable && state.currentUser != null && state.editTeam == null) { - players.add(state.currentUser!); + final player = TeamPlayer( + id: state.currentUser!.id, + role: TeamPlayerRole.admin, + detail: state.currentUser); + players.add(player); } if (state.editTeam != null) { players = state.teamMembers; } String? imageUrl = state.editTeam?.profile_img_url; - AddTeamRequestModel team = AddTeamRequestModel( + final team = TeamModel( id: state.editTeam?.id, name: name, name_lowercase: name.caseAndSpaceInsensitive, profile_img_url: imageUrl, city: location.toLowerCase(), - created_by: state.currentUser!.id, - players: players.map((e) => e.id).toList(), + created_by: state.currentUser?.id, created_at: state.editTeam?.created_at ?? DateTime.now()); final newTeamId = await _teamService.updateTeam(team); + if (newTeamId.isNotEmpty && + state.editTeam == null && + state.isAddMeCheckBoxEnable) { + await _teamService.addPlayersToTeam(newTeamId, players); + } if (state.filePath != null) { imageUrl = await _fileUploadService.uploadProfileImage( filePath: state.filePath!, @@ -136,7 +144,6 @@ class AddTeamViewNotifier extends StateNotifier { profile_img_url: imageUrl, city: location.toLowerCase(), created_by: state.currentUser!.id, - players: players, created_at: state.editTeam?.created_at ?? DateTime.now()); state = state.copyWith(isAddInProgress: false, team: teamModel); } @@ -241,6 +248,6 @@ class AddTeamState with _$AddTeamState { @Default(false) bool isAddBtnEnable, @Default(false) bool isAddInProgress, @Default(false) bool isPop, - @Default([]) List teamMembers, + @Default([]) List teamMembers, }) = _AddTeamState; } 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 82eac93e..092c8d52 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 @@ -32,7 +32,7 @@ mixin _$AddTeamState { bool get isAddBtnEnable => throw _privateConstructorUsedError; bool get isAddInProgress => throw _privateConstructorUsedError; bool get isPop => throw _privateConstructorUsedError; - List get teamMembers => throw _privateConstructorUsedError; + List get teamMembers => throw _privateConstructorUsedError; @JsonKey(ignore: true) $AddTeamStateCopyWith get copyWith => @@ -60,7 +60,7 @@ abstract class $AddTeamStateCopyWith<$Res> { bool isAddBtnEnable, bool isAddInProgress, bool isPop, - List teamMembers}); + List teamMembers}); $TeamModelCopyWith<$Res>? get team; $TeamModelCopyWith<$Res>? get editTeam; @@ -153,7 +153,7 @@ class _$AddTeamStateCopyWithImpl<$Res, $Val extends AddTeamState> teamMembers: null == teamMembers ? _value.teamMembers : teamMembers // ignore: cast_nullable_to_non_nullable - as List, + as List, ) as $Val); } @@ -217,7 +217,7 @@ abstract class _$$AddTeamStateImplCopyWith<$Res> bool isAddBtnEnable, bool isAddInProgress, bool isPop, - List teamMembers}); + List teamMembers}); @override $TeamModelCopyWith<$Res>? get team; @@ -311,7 +311,7 @@ class __$$AddTeamStateImplCopyWithImpl<$Res> teamMembers: null == teamMembers ? _value._teamMembers : teamMembers // ignore: cast_nullable_to_non_nullable - as List, + as List, )); } } @@ -334,7 +334,7 @@ class _$AddTeamStateImpl implements _AddTeamState { this.isAddBtnEnable = false, this.isAddInProgress = false, this.isPop = false, - final List teamMembers = const []}) + final List teamMembers = const []}) : _teamMembers = teamMembers; @override @@ -371,10 +371,10 @@ class _$AddTeamStateImpl implements _AddTeamState { @override @JsonKey() final bool isPop; - final List _teamMembers; + final List _teamMembers; @override @JsonKey() - List get teamMembers { + List get teamMembers { if (_teamMembers is EqualUnmodifiableListView) return _teamMembers; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_teamMembers); @@ -463,7 +463,7 @@ abstract class _AddTeamState implements AddTeamState { final bool isAddBtnEnable, final bool isAddInProgress, final bool isPop, - final List teamMembers}) = _$AddTeamStateImpl; + final List teamMembers}) = _$AddTeamStateImpl; @override TextEditingController get nameController; @@ -494,7 +494,7 @@ abstract class _AddTeamState implements AddTeamState { @override bool get isPop; @override - List get teamMembers; + List get teamMembers; @override @JsonKey(ignore: true) _$$AddTeamStateImplCopyWith<_$AddTeamStateImpl> get copyWith => diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart index c7bec880..f3feb234 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart @@ -135,8 +135,8 @@ class _AddTeamMemberScreenState extends ConsumerState { context, user, actionButtonTitle: - widget.team.players?.contains(user) == true || - state.selectedUsers.contains(user) + widget.team.players?.contains(user.id) == true || + state.selectedUsers.contains(user.id) ? null : context.l10n.common_select_title, onButtonTap: () async { @@ -151,13 +151,18 @@ class _AddTeamMemberScreenState extends ConsumerState { }, ), trailing: SecondaryButton( - widget.team.players?.contains(user) == true || - state.selectedUsers.contains(user) + widget.team.players?.any((element) => + element.detail == user) == + true || + state.selectedUsers + .any((element) => element.detail == user) ? context.l10n.add_team_member_added_text : context.l10n.common_add_title.toUpperCase(), - enabled: - widget.team.players?.contains(user) != true && - !state.selectedUsers.contains(user), + enabled: widget.team.players?.any( + (element) => element.id == user.id) != + true && + !state.selectedUsers + .any((element) => element.id == user.id), onPressed: () async { if (user.phone != null) { final res = await VerifyTeamMemberSheet.show( @@ -216,9 +221,10 @@ class _AddTeamMemberScreenState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 8), - _selectedProfileView(context, user), + if (user.detail != null) + _selectedProfileView(context, user.detail!), const SizedBox(height: 4), - Text(user.name ?? "", + Text(user.detail?.name ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, style: AppTextStyle.caption.copyWith( diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart index 905892f6..8cfbb019 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:data/api/team/team_model.dart'; import 'package:data/api/user/user_models.dart'; import 'package:data/service/team/team_service.dart'; import 'package:data/service/user/user_service.dart'; @@ -50,7 +51,9 @@ class AddTeamMemberViewNotifier extends StateNotifier { } void selectUser(UserModel user) { - state = state.copyWith(selectedUsers: [...state.selectedUsers, user]); + final player = + TeamPlayer(id: user.id, role: TeamPlayerRole.player, detail: user); + state = state.copyWith(selectedUsers: [...state.selectedUsers, player]); } void unSelectUser(UserModel user) { @@ -66,10 +69,7 @@ class AddTeamMemberViewNotifier extends StateNotifier { state = state.copyWith(isAddInProgress: true, actionError: null); try { - await _teamService.addPlayersToTeam( - id, - state.selectedUsers.map((e) => e.id).toList(), - ); + await _teamService.addPlayersToTeam(id, state.selectedUsers); state = state.copyWith(isAddInProgress: false, isAdded: true); } catch (e) { state = state.copyWith(isAddInProgress: false, actionError: e); @@ -92,7 +92,7 @@ class AddTeamMemberState with _$AddTeamMemberState { Object? error, Object? actionError, @Default([]) List searchedUsers, - @Default([]) List selectedUsers, + @Default([]) List selectedUsers, @Default(false) bool isAdded, @Default(false) bool isAddInProgress, }) = _AddTeamMemberState; diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.freezed.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.freezed.dart index c6371234..0b966f90 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.freezed.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.freezed.dart @@ -21,7 +21,7 @@ mixin _$AddTeamMemberState { Object? get error => throw _privateConstructorUsedError; Object? get actionError => throw _privateConstructorUsedError; List get searchedUsers => throw _privateConstructorUsedError; - List get selectedUsers => throw _privateConstructorUsedError; + List get selectedUsers => throw _privateConstructorUsedError; bool get isAdded => throw _privateConstructorUsedError; bool get isAddInProgress => throw _privateConstructorUsedError; @@ -41,7 +41,7 @@ abstract class $AddTeamMemberStateCopyWith<$Res> { Object? error, Object? actionError, List searchedUsers, - List selectedUsers, + List selectedUsers, bool isAdded, bool isAddInProgress}); } @@ -81,7 +81,7 @@ class _$AddTeamMemberStateCopyWithImpl<$Res, $Val extends AddTeamMemberState> selectedUsers: null == selectedUsers ? _value.selectedUsers : selectedUsers // ignore: cast_nullable_to_non_nullable - as List, + as List, isAdded: null == isAdded ? _value.isAdded : isAdded // ignore: cast_nullable_to_non_nullable @@ -107,7 +107,7 @@ abstract class _$$AddTeamMemberStateImplCopyWith<$Res> Object? error, Object? actionError, List searchedUsers, - List selectedUsers, + List selectedUsers, bool isAdded, bool isAddInProgress}); } @@ -145,7 +145,7 @@ class __$$AddTeamMemberStateImplCopyWithImpl<$Res> selectedUsers: null == selectedUsers ? _value._selectedUsers : selectedUsers // ignore: cast_nullable_to_non_nullable - as List, + as List, isAdded: null == isAdded ? _value.isAdded : isAdded // ignore: cast_nullable_to_non_nullable @@ -166,7 +166,7 @@ class _$AddTeamMemberStateImpl implements _AddTeamMemberState { this.error, this.actionError, final List searchedUsers = const [], - final List selectedUsers = const [], + final List selectedUsers = const [], this.isAdded = false, this.isAddInProgress = false}) : _searchedUsers = searchedUsers, @@ -187,10 +187,10 @@ class _$AddTeamMemberStateImpl implements _AddTeamMemberState { return EqualUnmodifiableListView(_searchedUsers); } - final List _selectedUsers; + final List _selectedUsers; @override @JsonKey() - List get selectedUsers { + List get selectedUsers { if (_selectedUsers is EqualUnmodifiableListView) return _selectedUsers; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_selectedUsers); @@ -252,7 +252,7 @@ abstract class _AddTeamMemberState implements AddTeamMemberState { final Object? error, final Object? actionError, final List searchedUsers, - final List selectedUsers, + final List selectedUsers, final bool isAdded, final bool isAddInProgress}) = _$AddTeamMemberStateImpl; @@ -265,7 +265,7 @@ abstract class _AddTeamMemberState implements AddTeamMemberState { @override List get searchedUsers; @override - List get selectedUsers; + List get selectedUsers; @override bool get isAdded; @override diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart index ac79fc9c..29967a00 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart @@ -1,4 +1,5 @@ import 'package:data/api/match/match_model.dart'; +import 'package:data/api/team/team_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/empty_screen.dart'; @@ -49,7 +50,10 @@ class TeamDetailMatchContent extends ConsumerWidget { description: (state.team?.created_by == state.currentUserId) ? context.l10n.team_detail_empty_matches_description_text : context.l10n.team_detail_visitor_empty_matches_description_text, - isShowButton: state.team?.created_by == state.currentUserId, + isShowButton: state.team?.players?.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == + true, buttonTitle: context.l10n.add_match_screen_title, onTap: () async { bool? isUpdated = await AppRoute.addMatch( diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart index b5675b7b..2c1bc5e2 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart @@ -1,3 +1,4 @@ +import 'package:data/api/team/team_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/empty_screen.dart'; @@ -22,12 +23,13 @@ class TeamDetailMemberContent extends ConsumerWidget { state.team?.players?.isNotEmpty == true) { return Column( children: [ - if (state.team!.created_by == state.currentUserId) ...[ - _addMemberButton( - context, - onTap: () => - AppRoute.addTeamMember(team: state.team!).push(context), - ), + if (state.team?.players?.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == + true) ...[ + _addMemberButton(context, + onTap: () => + AppRoute.addTeamMember(team: state.team!).push(context)), ], Expanded( child: ListView.separated( @@ -36,8 +38,8 @@ class TeamDetailMemberContent extends ConsumerWidget { itemBuilder: (context, index) { final member = state.team!.players![index]; return UserDetailCell( - user: member, - onTap: () => UserDetailSheet.show(context, member), + user: member.detail!, + onTap: () => UserDetailSheet.show(context, member.detail!), showPhoneNumber: false); }, separatorBuilder: (context, index) => const SizedBox(height: 16), 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 4c13ba7b..85361a86 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_screen.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_screen.dart @@ -1,3 +1,4 @@ +import 'package:data/api/team/team_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -70,7 +71,10 @@ class _TeamDetailScreenState extends ConsumerState { size: 24, color: context.colorScheme.textPrimary, )), - actions: (state.currentUserId == state.team?.created_by) + actions: (state.team?.players?.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == + true) ? [ moreOptionButton( context, diff --git a/khelo/lib/ui/flow/team/detail/team_detail_view_model.dart b/khelo/lib/ui/flow/team/detail/team_detail_view_model.dart index 9da0ba27..2be72312 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_view_model.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_view_model.dart @@ -38,8 +38,7 @@ class TeamDetailViewNotifier extends StateNotifier { if (teamId == null) return; state = state.copyWith(loading: state.team == null); - _teamStreamSubscription = - _teamService.getTeamStreamById(teamId!).listen((team) { + _teamStreamSubscription = _teamService.streamTeam(teamId!).listen((team) { state = state.copyWith(team: team, loading: false); loadTeamMatches(); }, onError: (e) { diff --git a/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart b/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart index 36bace54..44db6c45 100644 --- a/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart +++ b/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart @@ -63,22 +63,25 @@ class TeamMemberSheet extends StatelessWidget { Wrap( runSpacing: 16, children: (team.players ?? []) - .map((member) => UserDetailCell( - user: member, - onTap: () => UserDetailSheet.show( - context, - member, - actionButtonTitle: - isForVerification && member.isActive - ? context.l10n.common_select_title + .map((member) => (member.detail != null) + ? UserDetailCell( + user: member.detail!, + onTap: () => UserDetailSheet.show( + context, + member.detail!, + actionButtonTitle: + isForVerification && member.detail!.isActive + ? context.l10n.common_select_title + : null, + onButtonTap: () => + _onSelectButtonTap(context, member.detail!), + ), + trailing: + isForVerification && member.detail!.isActive + ? _selectButton(context, member.detail!) : null, - onButtonTap: () => - _onSelectButtonTap(context, member), - ), - trailing: isForVerification && member.isActive - ? _selectButton(context, member) - : null, - )) + ) + : SizedBox()) .toList()), ], ), diff --git a/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart b/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart index 73ba3cf2..16a02422 100644 --- a/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart +++ b/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart @@ -90,9 +90,11 @@ class SearchTeamViewNotifier extends StateNotifier { void onTeamCellTap(TeamModel team) { state = state.copyWith(showSelectionError: false); - final playersCount = - (team.players?.where((player) => player.isActive).toList() ?? []) - .length; + final playersCount = (team.players + ?.where((player) => player.detail?.isActive ?? false) + .toList() ?? + []) + .length; if (playersCount >= 2) { final isAlreadySelected = state.selectedTeam?.id == team.id; state = state.copyWith(selectedTeam: isAlreadySelected ? null : team); diff --git a/khelo/lib/ui/flow/team/team_list_view_model.dart b/khelo/lib/ui/flow/team/team_list_view_model.dart index 04e7e395..75487db8 100644 --- a/khelo/lib/ui/flow/team/team_list_view_model.dart +++ b/khelo/lib/ui/flow/team/team_list_view_model.dart @@ -41,7 +41,7 @@ class TeamListViewNotifier extends StateNotifier { state = state.copyWith(loading: state.teams.isEmpty); try { _teamsStreamSubscription = - _teamService.getUserRelatedTeams().listen((teams) { + _teamService.streamUserRelatedTeams().listen((teams) { state = state.copyWith(teams: teams, loading: false, error: null); _filterTeamList(); }, onError: (e) { diff --git a/khelo/pubspec.lock b/khelo/pubspec.lock index 95fbd256..50294e23 100644 --- a/khelo/pubspec.lock +++ b/khelo/pubspec.lock @@ -864,18 +864,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -912,18 +912,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" mime: dependency: transitive description: @@ -1348,26 +1348,26 @@ packages: dependency: transitive description: name: test - sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" url: "https://pub.dev" source: hosted - version: "1.25.2" + version: "1.25.7" test_api: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.2" test_core: dependency: transitive description: name: test_core - sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.4" time: dependency: transitive description: @@ -1508,10 +1508,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.4" watcher: dependency: transitive description: From d5e719d70155bb91f5cd99f753092bec86405e2d Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 13 Aug 2024 16:21:48 +0530 Subject: [PATCH 02/20] Refactor teams --- data/lib/api/team/team_model.dart | 12 +- data/lib/api/team/team_model.freezed.dart | 115 +++++----- data/lib/api/team/team_model.g.dart | 5 + data/lib/service/team/team_service.dart | 177 +++++++++------ .../utils/constant/firestore_constant.dart | 1 - khelo/lib/components/action_bottom_sheet.dart | 4 +- khelo/lib/ui/app_route.dart | 16 ++ .../add_match/add_match_view_model.dart | 8 +- .../select_squad/select_squad_screen.dart | 11 +- .../components/match_detail_squad_view.dart | 12 +- .../match_detail_tab_view_model.dart | 3 +- .../flow/team/add_team/add_team_screen.dart | 22 +- .../team/add_team/add_team_view_model.dart | 14 +- .../add_team_member_screen.dart | 29 +-- .../add_team_member_view_model.dart | 2 +- .../components/team_detail_match_content.dart | 8 +- .../team_detail_member_content.dart | 21 +- .../make_admin/make_team_admin_screen.dart | 113 ++++++++++ .../make_team_admin_view_model.dart | 65 ++++++ .../make_team_admin_view_model.freezed.dart | 208 ++++++++++++++++++ .../flow/team/detail/team_detail_screen.dart | 20 +- .../team/detail/team_detail_view_model.dart | 3 +- .../components/team_member_sheet.dart | 35 ++- .../team/search_team/search_team_screen.dart | 2 +- .../search_team/search_team_view_model.dart | 5 +- khelo/lib/ui/flow/team/team_list_screen.dart | 9 +- .../ui/flow/team/team_list_view_model.dart | 7 +- 27 files changed, 688 insertions(+), 239 deletions(-) create mode 100644 khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart create mode 100644 khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart create mode 100644 khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.freezed.dart diff --git a/data/lib/api/team/team_model.dart b/data/lib/api/team/team_model.dart index 9794a9fb..2fdcc7e0 100644 --- a/data/lib/api/team/team_model.dart +++ b/data/lib/api/team/team_model.dart @@ -18,8 +18,7 @@ class TeamModel with _$TeamModel { String? profile_img_url, String? created_by, DateTime? created_at, - @JsonKey(includeToJson: false, includeFromJson: false) - List? players, + @Default([]) List players, }) = _TeamModel; factory TeamModel.fromJson(Map json) => @@ -42,18 +41,13 @@ enum TeamPlayerRole { @freezed class TeamPlayer with _$TeamPlayer { + @JsonSerializable(explicitToJson: true) const factory TeamPlayer({ required String id, - @JsonKey(includeToJson: false, includeFromJson: false) UserModel? detail, @Default(TeamPlayerRole.player) TeamPlayerRole role, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user, }) = _TeamPlayer; factory TeamPlayer.fromJson(Map json) => _$TeamPlayerFromJson(json); - - factory TeamPlayer.fromFireStore( - DocumentSnapshot> snapshot, - SnapshotOptions? options, - ) => - TeamPlayer.fromJson(snapshot.data()!); } diff --git a/data/lib/api/team/team_model.freezed.dart b/data/lib/api/team/team_model.freezed.dart index e40e7bc2..57b00c54 100644 --- a/data/lib/api/team/team_model.freezed.dart +++ b/data/lib/api/team/team_model.freezed.dart @@ -27,8 +27,7 @@ mixin _$TeamModel { String? get profile_img_url => throw _privateConstructorUsedError; String? get created_by => throw _privateConstructorUsedError; DateTime? get created_at => throw _privateConstructorUsedError; - @JsonKey(includeToJson: false, includeFromJson: false) - List? get players => throw _privateConstructorUsedError; + List get players => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -49,8 +48,7 @@ abstract class $TeamModelCopyWith<$Res> { String? profile_img_url, String? created_by, DateTime? created_at, - @JsonKey(includeToJson: false, includeFromJson: false) - List? players}); + List players}); } /// @nodoc @@ -73,7 +71,7 @@ class _$TeamModelCopyWithImpl<$Res, $Val extends TeamModel> Object? profile_img_url = freezed, Object? created_by = freezed, Object? created_at = freezed, - Object? players = freezed, + Object? players = null, }) { return _then(_value.copyWith( id: freezed == id @@ -104,10 +102,10 @@ class _$TeamModelCopyWithImpl<$Res, $Val extends TeamModel> ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable as DateTime?, - players: freezed == players + players: null == players ? _value.players : players // ignore: cast_nullable_to_non_nullable - as List?, + as List, ) as $Val); } } @@ -128,8 +126,7 @@ abstract class _$$TeamModelImplCopyWith<$Res> String? profile_img_url, String? created_by, DateTime? created_at, - @JsonKey(includeToJson: false, includeFromJson: false) - List? players}); + List players}); } /// @nodoc @@ -150,7 +147,7 @@ class __$$TeamModelImplCopyWithImpl<$Res> Object? profile_img_url = freezed, Object? created_by = freezed, Object? created_at = freezed, - Object? players = freezed, + Object? players = null, }) { return _then(_$TeamModelImpl( id: freezed == id @@ -181,10 +178,10 @@ class __$$TeamModelImplCopyWithImpl<$Res> ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable as DateTime?, - players: freezed == players + players: null == players ? _value._players : players // ignore: cast_nullable_to_non_nullable - as List?, + as List, )); } } @@ -200,8 +197,7 @@ class _$TeamModelImpl implements _TeamModel { this.profile_img_url, this.created_by, this.created_at, - @JsonKey(includeToJson: false, includeFromJson: false) - final List? players}) + final List players = const []}) : _players = players; factory _$TeamModelImpl.fromJson(Map json) => @@ -221,15 +217,13 @@ class _$TeamModelImpl implements _TeamModel { final String? created_by; @override final DateTime? created_at; - final List? _players; + final List _players; @override - @JsonKey(includeToJson: false, includeFromJson: false) - List? get players { - final value = _players; - if (value == null) return null; + @JsonKey() + List get players { if (_players is EqualUnmodifiableListView) return _players; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(value); + return EqualUnmodifiableListView(_players); } @override @@ -292,8 +286,7 @@ abstract class _TeamModel implements TeamModel { final String? profile_img_url, final String? created_by, final DateTime? created_at, - @JsonKey(includeToJson: false, includeFromJson: false) - final List? players}) = _$TeamModelImpl; + final List players}) = _$TeamModelImpl; factory _TeamModel.fromJson(Map json) = _$TeamModelImpl.fromJson; @@ -313,8 +306,7 @@ abstract class _TeamModel implements TeamModel { @override DateTime? get created_at; @override - @JsonKey(includeToJson: false, includeFromJson: false) - List? get players; + List get players; @override @JsonKey(ignore: true) _$$TeamModelImplCopyWith<_$TeamModelImpl> get copyWith => @@ -328,9 +320,9 @@ TeamPlayer _$TeamPlayerFromJson(Map json) { /// @nodoc mixin _$TeamPlayer { String get id => throw _privateConstructorUsedError; - @JsonKey(includeToJson: false, includeFromJson: false) - UserModel? get detail => throw _privateConstructorUsedError; TeamPlayerRole get role => throw _privateConstructorUsedError; + @JsonKey(includeToJson: false, includeFromJson: false) + UserModel? get user => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -346,10 +338,10 @@ abstract class $TeamPlayerCopyWith<$Res> { @useResult $Res call( {String id, - @JsonKey(includeToJson: false, includeFromJson: false) UserModel? detail, - TeamPlayerRole role}); + TeamPlayerRole role, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user}); - $UserModelCopyWith<$Res>? get detail; + $UserModelCopyWith<$Res>? get user; } /// @nodoc @@ -366,34 +358,34 @@ class _$TeamPlayerCopyWithImpl<$Res, $Val extends TeamPlayer> @override $Res call({ Object? id = null, - Object? detail = freezed, Object? role = null, + Object? user = freezed, }) { return _then(_value.copyWith( id: null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as String, - detail: freezed == detail - ? _value.detail - : detail // ignore: cast_nullable_to_non_nullable - as UserModel?, role: null == role ? _value.role : role // ignore: cast_nullable_to_non_nullable as TeamPlayerRole, + user: freezed == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as UserModel?, ) as $Val); } @override @pragma('vm:prefer-inline') - $UserModelCopyWith<$Res>? get detail { - if (_value.detail == null) { + $UserModelCopyWith<$Res>? get user { + if (_value.user == null) { return null; } - return $UserModelCopyWith<$Res>(_value.detail!, (value) { - return _then(_value.copyWith(detail: value) as $Val); + return $UserModelCopyWith<$Res>(_value.user!, (value) { + return _then(_value.copyWith(user: value) as $Val); }); } } @@ -408,11 +400,11 @@ abstract class _$$TeamPlayerImplCopyWith<$Res> @useResult $Res call( {String id, - @JsonKey(includeToJson: false, includeFromJson: false) UserModel? detail, - TeamPlayerRole role}); + TeamPlayerRole role, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user}); @override - $UserModelCopyWith<$Res>? get detail; + $UserModelCopyWith<$Res>? get user; } /// @nodoc @@ -427,33 +419,34 @@ class __$$TeamPlayerImplCopyWithImpl<$Res> @override $Res call({ Object? id = null, - Object? detail = freezed, Object? role = null, + Object? user = freezed, }) { return _then(_$TeamPlayerImpl( id: null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as String, - detail: freezed == detail - ? _value.detail - : detail // ignore: cast_nullable_to_non_nullable - as UserModel?, role: null == role ? _value.role : role // ignore: cast_nullable_to_non_nullable as TeamPlayerRole, + user: freezed == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as UserModel?, )); } } /// @nodoc -@JsonSerializable() + +@JsonSerializable(explicitToJson: true) class _$TeamPlayerImpl implements _TeamPlayer { const _$TeamPlayerImpl( {required this.id, - @JsonKey(includeToJson: false, includeFromJson: false) this.detail, - this.role = TeamPlayerRole.player}); + this.role = TeamPlayerRole.player, + @JsonKey(includeToJson: false, includeFromJson: false) this.user}); factory _$TeamPlayerImpl.fromJson(Map json) => _$$TeamPlayerImplFromJson(json); @@ -461,15 +454,15 @@ class _$TeamPlayerImpl implements _TeamPlayer { @override final String id; @override - @JsonKey(includeToJson: false, includeFromJson: false) - final UserModel? detail; - @override @JsonKey() final TeamPlayerRole role; + @override + @JsonKey(includeToJson: false, includeFromJson: false) + final UserModel? user; @override String toString() { - return 'TeamPlayer(id: $id, detail: $detail, role: $role)'; + return 'TeamPlayer(id: $id, role: $role, user: $user)'; } @override @@ -478,13 +471,13 @@ class _$TeamPlayerImpl implements _TeamPlayer { (other.runtimeType == runtimeType && other is _$TeamPlayerImpl && (identical(other.id, id) || other.id == id) && - (identical(other.detail, detail) || other.detail == detail) && - (identical(other.role, role) || other.role == role)); + (identical(other.role, role) || other.role == role) && + (identical(other.user, user) || other.user == user)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash(runtimeType, id, detail, role); + int get hashCode => Object.hash(runtimeType, id, role, user); @JsonKey(ignore: true) @override @@ -503,9 +496,9 @@ class _$TeamPlayerImpl implements _TeamPlayer { abstract class _TeamPlayer implements TeamPlayer { const factory _TeamPlayer( {required final String id, + final TeamPlayerRole role, @JsonKey(includeToJson: false, includeFromJson: false) - final UserModel? detail, - final TeamPlayerRole role}) = _$TeamPlayerImpl; + final UserModel? user}) = _$TeamPlayerImpl; factory _TeamPlayer.fromJson(Map json) = _$TeamPlayerImpl.fromJson; @@ -513,11 +506,11 @@ abstract class _TeamPlayer implements TeamPlayer { @override String get id; @override - @JsonKey(includeToJson: false, includeFromJson: false) - UserModel? get detail; - @override TeamPlayerRole get role; @override + @JsonKey(includeToJson: false, includeFromJson: false) + UserModel? get user; + @override @JsonKey(ignore: true) _$$TeamPlayerImplCopyWith<_$TeamPlayerImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/data/lib/api/team/team_model.g.dart b/data/lib/api/team/team_model.g.dart index 1e9d2795..ca6944cb 100644 --- a/data/lib/api/team/team_model.g.dart +++ b/data/lib/api/team/team_model.g.dart @@ -17,6 +17,10 @@ _$TeamModelImpl _$$TeamModelImplFromJson(Map json) => created_at: json['created_at'] == null ? null : DateTime.parse(json['created_at'] as String), + players: (json['players'] as List?) + ?.map((e) => TeamPlayer.fromJson(e as Map)) + .toList() ?? + const [], ); Map _$$TeamModelImplToJson(_$TeamModelImpl instance) => @@ -28,6 +32,7 @@ Map _$$TeamModelImplToJson(_$TeamModelImpl instance) => 'profile_img_url': instance.profile_img_url, 'created_by': instance.created_by, 'created_at': instance.created_at?.toIso8601String(), + 'players': instance.players, }; _$TeamPlayerImpl _$$TeamPlayerImplFromJson(Map json) => diff --git a/data/lib/service/team/team_service.dart b/data/lib/service/team/team_service.dart index 65f1b0b1..084c345e 100644 --- a/data/lib/service/team/team_service.dart +++ b/data/lib/service/team/team_service.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/team/team_model.dart'; +import 'package:data/api/user/user_models.dart'; import 'package:data/errors/app_error.dart'; import 'package:data/extensions/string_extensions.dart'; import 'package:data/service/user/user_service.dart'; @@ -29,82 +30,98 @@ class TeamService { TeamService(this._currentUserId, this.firestore, this._userService); - CollectionReference get _teamCollection => + CollectionReference get _teamsCollection => firestore.collection(FireStoreConst.teamsCollection).withConverter( fromFirestore: TeamModel.fromFireStore, toFirestore: (TeamModel team, _) => team.toJson()); - CollectionReference _playersCollection(String teamId) => - _teamCollection - .doc(teamId) - .collection(FireStoreConst.playersCollection) - .withConverter( - fromFirestore: TeamPlayer.fromFireStore, - toFirestore: (value, options) => value.toJson()); - Future getTeamById(String teamId) async { try { - final team = await _teamCollection.doc(teamId).get(); - final players = await getTeamPlayers(teamId); - return team.data()?.copyWith(players: players) ?? + final teamDoc = await _teamsCollection.doc(teamId).get(); + final team = teamDoc.data(); + final users = await getMemberListFromUserIds( + team?.players.map((e) => e.id).toList() ?? []); + + final players = team?.players.map((player) { + final user = users.firstWhere((element) => element.id == player.id); + return player.copyWith(user: user); + }).toList(); + + return team?.copyWith(players: players ?? []) ?? deActiveDummyTeamModel(teamId); } catch (error, stack) { throw AppError.fromError(error, stack); } } - Stream streamTeam(String teamId) { - return _teamCollection.doc(teamId).snapshots().asyncMap((event) async { - final players = await getTeamPlayers(teamId); - return event.data()?.copyWith(players: players) ?? - deActiveDummyTeamModel(teamId); - }).handleError((error, stack) => AppError.fromError(error, stack)); - } + Stream streamTeamById(String teamId) { + return _teamsCollection.doc(teamId).snapshots().asyncMap((teamDoc) async { + final team = teamDoc.data(); - Future> getTeamPlayers(String teamId) async { - final data = await _playersCollection(teamId).get(); + final users = await getMemberListFromUserIds( + team?.players.map((e) => e.id).toList() ?? []); - final futures = data.docs.map((player) async { - final detail = await _userService.getUserById(player.id); - return player.data().copyWith(detail: detail); - }).toList(); + final players = team?.players.map((player) { + final user = users.firstWhere((element) => element.id == player.id); + return player.copyWith(user: user); + }).toList(); - return Future.wait(futures); + return team?.copyWith(players: players ?? []) ?? + deActiveDummyTeamModel(teamId); + }).handleError((error, stack) => AppError.fromError(error, stack)); } - Stream> streamUserRelatedTeams() { + Stream> getUserRelatedTeams() { if (_currentUserId == null) { return Stream.value([]); } - - return _teamCollection.snapshots().asyncMap((snapshot) async { - final futures = snapshot.docs.map((doc) async { - final teamId = doc.id; - final playersSnapshot = await _playersCollection(teamId) - .where('id', isEqualTo: _currentUserId) - .get(); - final players = playersSnapshot.docs.map((e) => e.data()).toList(); - return (players.isNotEmpty) - ? doc.data().copyWith(players: players) - : null; - }).toList(); - - final results = await Future.wait(futures); - return results.whereType().toList(); + return _teamsCollection.snapshots().asyncMap((snapshot) async { + final teams = await Future.wait(snapshot.docs.map((mainDoc) async { + final team = mainDoc.data(); + final isUserInTeam = + team.players.any((element) => element.id == _currentUserId); + if (isUserInTeam) { + final users = await getMemberListFromUserIds( + team.players.map((e) => e.id).toList()); + + final players = team.players.map((player) { + final user = users.firstWhere((element) => element.id == player.id); + return player.copyWith(user: user); + }).toList(); + + return team.copyWith(players: players); + } else { + return null; + } + })); + return teams.whereType().toList(); }).handleError((error, stack) => throw AppError.fromError(error, stack)); } Stream> getUserOwnedTeams() { - return _teamCollection + return _teamsCollection .where(FireStoreConst.createdBy, isEqualTo: _currentUserId) .snapshots() - .map((event) => event.docs.map((e) => e.data()).toList()) - .handleError((error, stack) => throw AppError.fromError(error, stack)); + .asyncMap((snapshot) async { + return await Future.wait(snapshot.docs.map((mainDoc) async { + final team = mainDoc.data(); + + final users = await getMemberListFromUserIds( + team.players.map((e) => e.id).toList()); + + final players = team.players.map((player) { + final user = users.firstWhere((element) => element.id == player.id); + return player.copyWith(user: user); + }).toList(); + + return team.copyWith(players: players); + }).toList()); + }).handleError((error, stack) => throw AppError.fromError(error, stack)); } Future updateTeam(TeamModel team) async { try { - final teamRef = _teamCollection.doc(team.id); + final teamRef = _teamsCollection.doc(team.id); await teamRef.set(team.copyWith(id: teamRef.id), SetOptions(merge: true)); return teamRef.id; } catch (error, stack) { @@ -114,7 +131,7 @@ class TeamService { Future updateProfileImageUrl(String teamId, String? imageUrl) async { try { - final teamRef = _teamCollection.doc(teamId); + final teamRef = _teamsCollection.doc(teamId); await teamRef.update({ FireStoreConst.profileImageUrl: imageUrl, }); @@ -125,26 +142,31 @@ class TeamService { Future addPlayersToTeam(String teamId, List players) async { try { - WriteBatch batch = firestore.batch(); - for (final player in players) { - batch.set(_playersCollection(teamId).doc(player.id), player, - SetOptions(merge: true)); - } - await batch.commit(); + await _teamsCollection.doc(teamId).update({ + FireStoreConst.players: + FieldValue.arrayUnion(players.map((e) => e.toJson()).toList()) + }); + } catch (error, stack) { + throw AppError.fromError(error, stack); + } + } + + Future editPlayersToTeam( + String teamId, List players) async { + try { + await _teamsCollection.doc(teamId).update( + {FireStoreConst.players: players.map((e) => e.toJson()).toList()}); } catch (error, stack) { throw AppError.fromError(error, stack); } } Future removePlayersFromTeam( - String teamId, List playerIds) async { + String teamId, List players) async { try { - WriteBatch batch = firestore.batch(); - final playerRef = _playersCollection(teamId); - for (final id in playerIds) { - batch.delete(playerRef.doc(id)); - } - batch.commit(); + final teamRef = _teamsCollection.doc(teamId); + await teamRef + .update({FireStoreConst.players: FieldValue.arrayRemove(players)}); } catch (error, stack) { throw AppError.fromError(error, stack); } @@ -152,27 +174,44 @@ class TeamService { Future isTeamNameAvailable(String teamName) async { try { - QuerySnapshot teamSnap = await _teamCollection + QuerySnapshot teamSnap = await _teamsCollection .where(FireStoreConst.nameLowercase, isEqualTo: teamName.caseAndSpaceInsensitive) .get(); return teamSnap.docs.isEmpty; } catch (error, stack) { + print(error); throw AppError.fromError(error, stack); } } Future> searchTeam(String searchKey) async { try { - final snapshot = await _teamCollection + final snapshot = await _teamsCollection .where(FireStoreConst.nameLowercase, isGreaterThanOrEqualTo: searchKey.caseAndSpaceInsensitive) .where(FireStoreConst.nameLowercase, isLessThan: '${searchKey.caseAndSpaceInsensitive}z') .get(); - return snapshot.docs.map((e) => e.data()).toList(); + List teams = []; + + for (final mainDoc in snapshot.docs) { + final team = mainDoc.data(); + + final users = await getMemberListFromUserIds( + team.players.map((e) => e.id).toList()); + + final players = team.players.map((player) { + final user = users.firstWhere((element) => element.id == player.id); + return player.copyWith(user: user); + }).toList(); + + teams.add(team.copyWith(players: players)); + } + + return teams; } catch (error, stack) { throw AppError.fromError(error, stack); } @@ -180,7 +219,17 @@ class TeamService { Future deleteTeam(String teamId) async { try { - await _teamCollection.doc(teamId).delete(); + await _teamsCollection.doc(teamId).delete(); + } catch (error, stack) { + throw AppError.fromError(error, stack); + } + } + + // Helper Method + Future> getMemberListFromUserIds(List users) async { + try { + final userList = await _userService.getUsersByIds(users); + return userList; } catch (error, stack) { throw AppError.fromError(error, stack); } diff --git a/data/lib/utils/constant/firestore_constant.dart b/data/lib/utils/constant/firestore_constant.dart index 1b58a37b..cee197bc 100644 --- a/data/lib/utils/constant/firestore_constant.dart +++ b/data/lib/utils/constant/firestore_constant.dart @@ -2,7 +2,6 @@ class FireStoreConst { // collection static const String matchesCollection = "matches"; static const String teamsCollection = "teams"; - static const String playersCollection="team_players"; static const String inningsCollection = "innings"; static const String ballScoresCollection = "ball_scores"; static const String usersCollection = "users"; diff --git a/khelo/lib/components/action_bottom_sheet.dart b/khelo/lib/components/action_bottom_sheet.dart index 589d153c..5a257856 100644 --- a/khelo/lib/components/action_bottom_sheet.dart +++ b/khelo/lib/components/action_bottom_sheet.dart @@ -53,12 +53,14 @@ class BottomSheetAction extends StatelessWidget { final Widget? icon; final String title; final Widget? child; + final bool enabled; final void Function()? onTap; const BottomSheetAction({ super.key, this.icon, required this.title, + this.enabled = true, this.child, this.onTap, }); @@ -66,7 +68,7 @@ class BottomSheetAction extends StatelessWidget { @override Widget build(BuildContext context) { return OnTapScale( - enabled: child == null, + enabled: enabled, onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 24), diff --git a/khelo/lib/ui/app_route.dart b/khelo/lib/ui/app_route.dart index 8326e3d4..78698ea9 100644 --- a/khelo/lib/ui/app_route.dart +++ b/khelo/lib/ui/app_route.dart @@ -17,6 +17,7 @@ import 'package:khelo/ui/flow/settings/edit_profile/edit_profile_screen.dart'; import 'package:khelo/ui/flow/sign_in/phone_verification/phone_verification_screen.dart'; import 'package:khelo/ui/flow/team/add_team/add_team_screen.dart'; import 'package:khelo/ui/flow/team/add_team_member/add_team_member_screen.dart'; +import 'package:khelo/ui/flow/team/detail/make_admin/make_team_admin_screen.dart'; import 'package:khelo/ui/flow/team/detail/team_detail_screen.dart'; import 'package:khelo/ui/flow/team/search_team/search_team_screen.dart'; import 'flow/main/main_screen.dart'; @@ -32,6 +33,7 @@ class AppRoute { static const pathPowerPlay = '/power-play'; static const pathSelectSquad = '/select-squad'; static const pathAddMatchOfficials = '/add-match-officials'; + static const pathMakeTeamAdmin = "/make-admin"; static const pathSearchTeam = '/search-team'; static const pathAddMatch = '/add-match'; static const pathAddTossDetail = '/add-toss-detail'; @@ -154,6 +156,16 @@ class AppRoute { builder: (_) => AddTeamScreen(editTeam: team), ); + static AppRoute makeTeamAdmin({ + required String teamId, + required List players, + }) => + AppRoute(pathMakeTeamAdmin, + builder: (context) => MakeTeamAdminScreen( + teamId: teamId, + players: players, + )); + static AppRoute searchTeam( {List? excludedIds, required bool onlyUserTeams}) => AppRoute( @@ -295,6 +307,10 @@ class AppRoute { path: pathTeamDetail, builder: (context, state) => state.widget(context), ), + GoRoute( + path: pathMakeTeamAdmin, + builder: (context, state) => state.widget(context), + ), GoRoute( path: pathAddTeam, pageBuilder: (context, state) => adaptivePage( diff --git a/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart b/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart index 8bf70e25..4173d9e4 100644 --- a/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart +++ b/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart @@ -233,12 +233,12 @@ class AddMatchViewNotifier extends StateNotifier { void onTeamSelect(TeamModel team, TeamType type) { final matchPlayer = team.players - ?.take(11) - .map((e) => - MatchPlayer(player: e.detail!, status: PlayerStatus.yetToPlay)) + .take(11) + .map( + (e) => MatchPlayer(player: e.user!, status: PlayerStatus.yetToPlay)) .toList(); - final captainAndAdminId = matchPlayer?.firstOrNull?.player.id; + final captainAndAdminId = matchPlayer.firstOrNull?.player.id; switch (type) { case TeamType.a: state = state.copyWith( diff --git a/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart b/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart index 3858b710..73af9b18 100644 --- a/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart +++ b/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart @@ -139,11 +139,10 @@ class _SelectSquadScreenState extends ConsumerState { return Wrap( children: [ - if (memberList.isNotEmpty || - (state.team?.players?.isEmpty ?? true)) ...[ + if (memberList.isNotEmpty || (state.team?.players.isEmpty ?? true)) ...[ _sectionTitle(context, context.l10n.select_squad_rest_of_team_title), ], - if (state.team?.players?.isEmpty ?? true) ...[ + if (state.team?.players.isEmpty ?? true) ...[ _emptyList(context.l10n.select_squad_empty_team_member_text) ] else ...[ for (final member in memberList) ...[ @@ -186,10 +185,10 @@ class _SelectSquadScreenState extends ConsumerState { List getFilteredList(SelectSquadViewState state) { return state.team?.players - ?.where((element) => + .where((element) => !state.squad.map((e) => e.player.id).contains(element.id) && - element.detail!.isActive) - .map((e) => e.detail!) + element.user!.isActive) + .map((e) => e.user!) .toList() ?? []; } 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 a13fbb5a..367f37e4 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 @@ -53,18 +53,18 @@ class MatchDetailSquadView extends ConsumerWidget { []; final firstTeamBench = firstTeam?.team.players - ?.where((element) => + .where((element) => !firstTeamSquad.map((e) => e.id).contains(element.id) && - element.detail!.isActive) - .map((e) => e.detail!) + element.user!.isActive) + .map((e) => e.user!) .toList() ?? []; final secondTeamBench = secondTeam?.team.players - ?.where((element) => + .where((element) => !secondTeamSquad.map((e) => e.id).contains(element.id) && - element.detail!.isActive) - .map((e) => e.detail!) + element.user!.isActive) + .map((e) => e.user!) .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 8efb07c6..1d8250d3 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 @@ -3,6 +3,7 @@ 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/api/team/team_model.dart'; import 'package:data/api/user/user_models.dart'; import 'package:data/errors/app_error.dart'; import 'package:data/service/ball_score/ball_score_service.dart'; @@ -291,7 +292,7 @@ class MatchDetailTabViewNotifier extends StateNotifier { .firstWhere((element) => element.player.id == playerId); } if (lastBatsman == null) { - UserModel player = + final player = _getPlayerByInningId(inningId: inningId, playerId: playerId); lastBatsman = BatsmanSummary(player: player); } 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 963670c1..d7265cb9 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 @@ -153,12 +153,12 @@ class _AddTeamScreenState extends ConsumerState { actionButton( context, onPressed: () async { - final members = await AppRoute.addTeamMember( + final players = await AppRoute.addTeamMember( team: widget.editTeam! .copyWith(players: state.teamMembers)) .push>(context); - if (context.mounted && (members ?? []).isNotEmpty) { - notifier.updatePlayersList(members!); + if (context.mounted && (players ?? []).isNotEmpty) { + notifier.updatePlayersList(players!); } }, icon: Icon( @@ -182,15 +182,15 @@ class _AddTeamScreenState extends ConsumerState { ), ), ], - ...state.teamMembers.map( - (player) => Padding( + ...state.teamMembers.map((player) { + final detail = player.user!; + return Padding( padding: const EdgeInsets.only(top: 16), child: UserDetailCell( - user: player.detail!, - onTap: () => UserDetailSheet.show(context, player.detail!), + user: detail, + onTap: () => UserDetailSheet.show(context, detail), trailing: actionButton(context, - onPressed: () => - notifier.onRemoveUserFromTeam(player.detail!), + onPressed: () => notifier.onRemoveUserFromTeam(detail), padding: const EdgeInsets.only( left: 10, top: 10, bottom: 10), icon: Icon( @@ -199,8 +199,8 @@ class _AddTeamScreenState extends ConsumerState { color: context.colorScheme.textDisabled, )), ), - ), - ), + ); + }), const SizedBox(height: 24), ], ], 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 03db5180..3371390f 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 @@ -94,7 +94,7 @@ class AddTeamViewNotifier extends StateNotifier { final player = TeamPlayer( id: state.currentUser!.id, role: TeamPlayerRole.admin, - detail: state.currentUser); + user: state.currentUser); players.add(player); } @@ -108,15 +108,11 @@ class AddTeamViewNotifier extends StateNotifier { name_lowercase: name.caseAndSpaceInsensitive, profile_img_url: imageUrl, city: location.toLowerCase(), - created_by: state.currentUser?.id, + created_by: state.currentUser!.id, + players: players, created_at: state.editTeam?.created_at ?? DateTime.now()); final newTeamId = await _teamService.updateTeam(team); - if (newTeamId.isNotEmpty && - state.editTeam == null && - state.isAddMeCheckBoxEnable) { - await _teamService.addPlayersToTeam(newTeamId, players); - } if (state.filePath != null) { imageUrl = await _fileUploadService.uploadProfileImage( filePath: state.filePath!, @@ -127,9 +123,8 @@ class AddTeamViewNotifier extends StateNotifier { } if (state.editTeam != null) { - final filterList = (state.editTeam!.players ?? []) + final filterList = (state.editTeam!.players) .where((element) => !state.teamMembers.contains(element)) - .map((e) => e.id) .toList(); await _teamService.removePlayersFromTeam( @@ -144,6 +139,7 @@ class AddTeamViewNotifier extends StateNotifier { profile_img_url: imageUrl, city: location.toLowerCase(), created_by: state.currentUser!.id, + players: players, created_at: state.editTeam?.created_at ?? DateTime.now()); state = state.copyWith(isAddInProgress: false, team: teamModel); } diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart index f3feb234..2c7adf4f 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart @@ -118,6 +118,11 @@ class _AddTeamMemberScreenState extends ConsumerState { itemCount: state.searchedUsers.length, itemBuilder: (context, index) { UserModel user = state.searchedUsers[index]; + final isAdded = widget.team.players + .any((element) => element.user == user) == + true || + state.selectedUsers.any((element) => element.user == user); + return Column( children: [ if (index == 0 && state.selectedUsers.isNotEmpty) ...[ @@ -135,10 +140,7 @@ class _AddTeamMemberScreenState extends ConsumerState { context, user, actionButtonTitle: - widget.team.players?.contains(user.id) == true || - state.selectedUsers.contains(user.id) - ? null - : context.l10n.common_select_title, + isAdded ? null : context.l10n.common_select_title, onButtonTap: () async { if (user.phone != null) { final res = await VerifyTeamMemberSheet.show( @@ -151,18 +153,10 @@ class _AddTeamMemberScreenState extends ConsumerState { }, ), trailing: SecondaryButton( - widget.team.players?.any((element) => - element.detail == user) == - true || - state.selectedUsers - .any((element) => element.detail == user) + isAdded ? context.l10n.add_team_member_added_text : context.l10n.common_add_title.toUpperCase(), - enabled: widget.team.players?.any( - (element) => element.id == user.id) != - true && - !state.selectedUsers - .any((element) => element.id == user.id), + enabled: !isAdded, onPressed: () async { if (user.phone != null) { final res = await VerifyTeamMemberSheet.show( @@ -213,7 +207,7 @@ class _AddTeamMemberScreenState extends ConsumerState { child: Row( mainAxisAlignment: MainAxisAlignment.start, children: state.selectedUsers - .map((user) => Padding( + .map((player) => Padding( padding: const EdgeInsets.only(right: 16.0), child: SizedBox( width: 58, @@ -221,10 +215,9 @@ class _AddTeamMemberScreenState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 8), - if (user.detail != null) - _selectedProfileView(context, user.detail!), + _selectedProfileView(context, player.user!), const SizedBox(height: 4), - Text(user.detail?.name ?? "", + Text(player.user?.name ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, style: AppTextStyle.caption.copyWith( diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart index 8cfbb019..27d41e08 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart @@ -52,7 +52,7 @@ class AddTeamMemberViewNotifier extends StateNotifier { void selectUser(UserModel user) { final player = - TeamPlayer(id: user.id, role: TeamPlayerRole.player, detail: user); + TeamPlayer(id: user.id, role: TeamPlayerRole.player, user: user); state = state.copyWith(selectedUsers: [...state.selectedUsers, player]); } diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart index 29967a00..9515eb7d 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart @@ -50,14 +50,14 @@ class TeamDetailMatchContent extends ConsumerWidget { description: (state.team?.created_by == state.currentUserId) ? context.l10n.team_detail_empty_matches_description_text : context.l10n.team_detail_visitor_empty_matches_description_text, - isShowButton: state.team?.players?.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == + isShowButton: state.team?.players.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == true, buttonTitle: context.l10n.add_match_screen_title, onTap: () async { bool? isUpdated = await AppRoute.addMatch( - defaultTeam: (state.team?.players?.length ?? 0) >= 2 + defaultTeam: (state.team?.players.length ?? 0) >= 2 ? state.team : null) .push(context); diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart index 2c1bc5e2..4b11f6f5 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart @@ -19,27 +19,28 @@ class TeamDetailMemberContent extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(teamDetailStateProvider); - if (state.team?.players != null && - state.team?.players?.isNotEmpty == true) { + if (state.team?.players != null && state.team?.players.isNotEmpty == true) { return Column( children: [ - if (state.team?.players?.any((element) => + if (state.team?.players.any((element) => element.id == state.currentUserId && element.role == TeamPlayerRole.admin) == true) ...[ - _addMemberButton(context, - onTap: () => - AppRoute.addTeamMember(team: state.team!).push(context)), + _addMemberButton( + context, + onTap: () => + AppRoute.addTeamMember(team: state.team!).push(context), + ), ], Expanded( child: ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - itemCount: state.team!.players!.length, + itemCount: state.team!.players.length, itemBuilder: (context, index) { - final member = state.team!.players![index]; + final member = state.team!.players[index].user!; return UserDetailCell( - user: member.detail!, - onTap: () => UserDetailSheet.show(context, member.detail!), + user: member, + onTap: () => UserDetailSheet.show(context, member), showPhoneNumber: false); }, separatorBuilder: (context, index) => const SizedBox(height: 16), diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart new file mode 100644 index 00000000..653e7b9b --- /dev/null +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart @@ -0,0 +1,113 @@ +import 'package:data/api/team/team_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.dart'; +import 'package:khelo/components/app_page.dart'; +import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/widget_extension.dart'; +import 'package:khelo/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart'; +import 'package:style/button/action_button.dart'; +import 'package:style/extensions/context_extensions.dart'; +import 'package:style/widgets/rounded_check_box.dart'; + +import '../../../../../components/error_snackbar.dart'; +import '../../../../../components/user_detail_cell.dart'; +import '../../../../../gen/assets.gen.dart'; +import '../../../matches/add_match/select_squad/components/user_detail_sheet.dart'; + +class MakeTeamAdminScreen extends ConsumerStatefulWidget { + final String teamId; + final List players; + + const MakeTeamAdminScreen({ + super.key, + required this.teamId, + required this.players, + }); + + @override + ConsumerState createState() => _MakeAdminScreenState(); +} + +class _MakeAdminScreenState extends ConsumerState { + late MakeTeamAdminViewNotifier notifier; + + @override + void initState() { + super.initState(); + notifier = ref.read(makeTeamAdminStateProvider.notifier); + runPostFrame(() => notifier.setData( + teamId: widget.teamId, + players: widget.players, + )); + } + + @override + Widget build(BuildContext context) { + _observePop(); + _observeActionError(); + final state = ref.watch(makeTeamAdminStateProvider); + return AppPage( + title: context.l10n.team_detail_make_admin, + actions: (state.isButtonEnabled) + ? [ + actionButton(context, + onPressed: notifier.onSave, + icon: SvgPicture.asset( + Assets.images.icCheck, + height: 24, + width: 24, + fit: BoxFit.contain, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcIn, + ), + )) + ] + : null, + body: Builder(builder: (context) => _body(context, state)), + ); + } + + void _observePop() { + ref.listen( + makeTeamAdminStateProvider.select((value) => value.pop), + (previous, next) { + if (next) context.pop(); + }, + ); + } + + void _observeActionError() { + ref.listen(makeTeamAdminStateProvider.select((value) => value.actionError), + (previous, next) { + if (next != null) { + showErrorSnackBar(context: context, error: next); + } + }); + } + + Widget _body(BuildContext context, MakeTeamAdminState state) { + return ListView.separated( + padding: const EdgeInsets.all(16) + context.mediaQueryPadding, + itemCount: widget.players.length, + itemBuilder: (context, index) { + final player = widget.players[index]; + return (player.user != null) + ? UserDetailCell( + user: player.user!, + onTap: () => UserDetailSheet.show(context, player.user!), + showPhoneNumber: false, + trailing: RoundedCheckBox( + isSelected: state.selectedPlayers + .any((element) => element.user == player.user), + onTap: (_) => notifier.selectAdmin(player), + ), + ) + : SizedBox(); + }, + separatorBuilder: (context, index) => SizedBox(height: 16), + ); + } +} diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart new file mode 100644 index 00000000..b216a149 --- /dev/null +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart @@ -0,0 +1,65 @@ +import 'package:data/api/team/team_model.dart'; +import 'package:data/service/team/team_service.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'make_team_admin_view_model.freezed.dart'; + +final makeTeamAdminStateProvider = StateNotifierProvider.autoDispose< + MakeTeamAdminViewNotifier, MakeTeamAdminState>( + (ref) => MakeTeamAdminViewNotifier(ref.read(teamServiceProvider))); + +class MakeTeamAdminViewNotifier extends StateNotifier { + final TeamService _teamService; + + MakeTeamAdminViewNotifier(this._teamService) : super(MakeTeamAdminState()); + + late String _teamId; + late List _players; + + void setData({ + required String teamId, + required List players, + }) { + _teamId = teamId; + _players = players; + final admins = players + .where((element) => element.role == TeamPlayerRole.admin) + .toList(); + state = state.copyWith(selectedPlayers: admins); + } + + void selectAdmin(TeamPlayer player) { + final admins = state.selectedPlayers.toList(); + (admins.contains(player)) ? admins.remove(player) : admins.add(player); + state = state.copyWith(selectedPlayers: admins, isButtonEnabled: true); + } + + void onSave() async { + try { + final players = _players.map((player) { + final role = state.selectedPlayers.contains(player) + ? TeamPlayerRole.admin + : TeamPlayerRole.player; + return player.copyWith(role: role); + }).toList(); + + await _teamService.editPlayersToTeam(_teamId, players); + state = state.copyWith(pop: true, actionError: null); + } catch (e) { + state = state.copyWith(pop: false, actionError: e); + debugPrint("MakeTeamAdminViewNotifier: error while making admins -> $e"); + } + } +} + +@freezed +class MakeTeamAdminState with _$MakeTeamAdminState { + const factory MakeTeamAdminState({ + Object? actionError, + @Default(false) bool pop, + @Default(false) bool isButtonEnabled, + @Default([]) List selectedPlayers, + }) = _MakeTeamAdminState; +} diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.freezed.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.freezed.dart new file mode 100644 index 00000000..34537da0 --- /dev/null +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.freezed.dart @@ -0,0 +1,208 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'make_team_admin_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$MakeTeamAdminState { + Object? get actionError => throw _privateConstructorUsedError; + bool get pop => throw _privateConstructorUsedError; + bool get isButtonEnabled => throw _privateConstructorUsedError; + List get selectedPlayers => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $MakeTeamAdminStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MakeTeamAdminStateCopyWith<$Res> { + factory $MakeTeamAdminStateCopyWith( + MakeTeamAdminState value, $Res Function(MakeTeamAdminState) then) = + _$MakeTeamAdminStateCopyWithImpl<$Res, MakeTeamAdminState>; + @useResult + $Res call( + {Object? actionError, + bool pop, + bool isButtonEnabled, + List selectedPlayers}); +} + +/// @nodoc +class _$MakeTeamAdminStateCopyWithImpl<$Res, $Val extends MakeTeamAdminState> + implements $MakeTeamAdminStateCopyWith<$Res> { + _$MakeTeamAdminStateCopyWithImpl(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? actionError = freezed, + Object? pop = null, + Object? isButtonEnabled = null, + Object? selectedPlayers = null, + }) { + return _then(_value.copyWith( + actionError: freezed == actionError ? _value.actionError : actionError, + pop: null == pop + ? _value.pop + : pop // ignore: cast_nullable_to_non_nullable + as bool, + isButtonEnabled: null == isButtonEnabled + ? _value.isButtonEnabled + : isButtonEnabled // ignore: cast_nullable_to_non_nullable + as bool, + selectedPlayers: null == selectedPlayers + ? _value.selectedPlayers + : selectedPlayers // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$MakeTeamAdminStateImplCopyWith<$Res> + implements $MakeTeamAdminStateCopyWith<$Res> { + factory _$$MakeTeamAdminStateImplCopyWith(_$MakeTeamAdminStateImpl value, + $Res Function(_$MakeTeamAdminStateImpl) then) = + __$$MakeTeamAdminStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {Object? actionError, + bool pop, + bool isButtonEnabled, + List selectedPlayers}); +} + +/// @nodoc +class __$$MakeTeamAdminStateImplCopyWithImpl<$Res> + extends _$MakeTeamAdminStateCopyWithImpl<$Res, _$MakeTeamAdminStateImpl> + implements _$$MakeTeamAdminStateImplCopyWith<$Res> { + __$$MakeTeamAdminStateImplCopyWithImpl(_$MakeTeamAdminStateImpl _value, + $Res Function(_$MakeTeamAdminStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? actionError = freezed, + Object? pop = null, + Object? isButtonEnabled = null, + Object? selectedPlayers = null, + }) { + return _then(_$MakeTeamAdminStateImpl( + actionError: freezed == actionError ? _value.actionError : actionError, + pop: null == pop + ? _value.pop + : pop // ignore: cast_nullable_to_non_nullable + as bool, + isButtonEnabled: null == isButtonEnabled + ? _value.isButtonEnabled + : isButtonEnabled // ignore: cast_nullable_to_non_nullable + as bool, + selectedPlayers: null == selectedPlayers + ? _value._selectedPlayers + : selectedPlayers // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$MakeTeamAdminStateImpl implements _MakeTeamAdminState { + const _$MakeTeamAdminStateImpl( + {this.actionError, + this.pop = false, + this.isButtonEnabled = false, + final List selectedPlayers = const []}) + : _selectedPlayers = selectedPlayers; + + @override + final Object? actionError; + @override + @JsonKey() + final bool pop; + @override + @JsonKey() + final bool isButtonEnabled; + final List _selectedPlayers; + @override + @JsonKey() + List get selectedPlayers { + if (_selectedPlayers is EqualUnmodifiableListView) return _selectedPlayers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_selectedPlayers); + } + + @override + String toString() { + return 'MakeTeamAdminState(actionError: $actionError, pop: $pop, isButtonEnabled: $isButtonEnabled, selectedPlayers: $selectedPlayers)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MakeTeamAdminStateImpl && + const DeepCollectionEquality() + .equals(other.actionError, actionError) && + (identical(other.pop, pop) || other.pop == pop) && + (identical(other.isButtonEnabled, isButtonEnabled) || + other.isButtonEnabled == isButtonEnabled) && + const DeepCollectionEquality() + .equals(other._selectedPlayers, _selectedPlayers)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(actionError), + pop, + isButtonEnabled, + const DeepCollectionEquality().hash(_selectedPlayers)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MakeTeamAdminStateImplCopyWith<_$MakeTeamAdminStateImpl> get copyWith => + __$$MakeTeamAdminStateImplCopyWithImpl<_$MakeTeamAdminStateImpl>( + this, _$identity); +} + +abstract class _MakeTeamAdminState implements MakeTeamAdminState { + const factory _MakeTeamAdminState( + {final Object? actionError, + final bool pop, + final bool isButtonEnabled, + final List selectedPlayers}) = _$MakeTeamAdminStateImpl; + + @override + Object? get actionError; + @override + bool get pop; + @override + bool get isButtonEnabled; + @override + List get selectedPlayers; + @override + @JsonKey(ignore: true) + _$$MakeTeamAdminStateImplCopyWith<_$MakeTeamAdminStateImpl> get copyWith => + throw _privateConstructorUsedError; +} 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 85361a86..065de74d 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_screen.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_screen.dart @@ -71,7 +71,7 @@ class _TeamDetailScreenState extends ConsumerState { size: 24, color: context.colorScheme.textPrimary, )), - actions: (state.team?.players?.any((element) => + actions: (state.team?.players.any((element) => element.id == state.currentUserId && element.role == TeamPlayerRole.admin) == true) @@ -199,12 +199,28 @@ class _TeamDetailScreenState extends ConsumerState { onTap: () { context.pop(); AppRoute.addMatch( - defaultTeam: (state.team?.players?.length ?? 0) >= 2 + defaultTeam: (state.team?.players.length ?? 0) >= 2 ? state.team : null) .push(context); }, ), + BottomSheetAction( + title: context.l10n.team_detail_make_admin, + child: Text(context.l10n.team_detail_admin(state.team!.players + .where((element) => element.role == TeamPlayerRole.admin) + .toList() + .length)), + onTap: () { + context.pop(); + if (state.team!.players.isNotEmpty) { + AppRoute.makeTeamAdmin( + teamId: state.team!.id ?? 'INVALID ID', + players: state.team!.players) + .push(context); + } + }, + ), ]); } diff --git a/khelo/lib/ui/flow/team/detail/team_detail_view_model.dart b/khelo/lib/ui/flow/team/detail/team_detail_view_model.dart index 2be72312..61b91305 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_view_model.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_view_model.dart @@ -38,7 +38,8 @@ class TeamDetailViewNotifier extends StateNotifier { if (teamId == null) return; state = state.copyWith(loading: state.team == null); - _teamStreamSubscription = _teamService.streamTeam(teamId!).listen((team) { + _teamStreamSubscription = + _teamService.streamTeamById(teamId!).listen((team) { state = state.copyWith(team: team, loading: false); loadTeamMatches(); }, onError: (e) { diff --git a/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart b/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart index 44db6c45..b6217953 100644 --- a/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart +++ b/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart @@ -62,26 +62,23 @@ class TeamMemberSheet extends StatelessWidget { const SizedBox(height: 16), Wrap( runSpacing: 16, - children: (team.players ?? []) - .map((member) => (member.detail != null) - ? UserDetailCell( - user: member.detail!, - onTap: () => UserDetailSheet.show( - context, - member.detail!, - actionButtonTitle: - isForVerification && member.detail!.isActive - ? context.l10n.common_select_title - : null, - onButtonTap: () => - _onSelectButtonTap(context, member.detail!), - ), - trailing: - isForVerification && member.detail!.isActive - ? _selectButton(context, member.detail!) + children: (team.players) + .map((player) => UserDetailCell( + user: player.user!, + onTap: () => UserDetailSheet.show( + context, + player.user!, + actionButtonTitle: + isForVerification && player.user!.isActive + ? context.l10n.common_select_title : null, - ) - : SizedBox()) + onButtonTap: () => + _onSelectButtonTap(context, player.user!), + ), + trailing: isForVerification && player.user!.isActive + ? _selectButton(context, player.user!) + : null, + )) .toList()), ], ), 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 1a4f9cd5..89b91bd9 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 @@ -195,7 +195,7 @@ class _SearchTeamScreenState extends ConsumerState { )), TextSpan( text: context.l10n - .search_team_player_title(team.players?.length ?? 0), + .search_team_player_title(team.players.length), ), ], ), diff --git a/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart b/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart index 16a02422..bff1e1f1 100644 --- a/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart +++ b/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart @@ -91,9 +91,8 @@ class SearchTeamViewNotifier extends StateNotifier { void onTeamCellTap(TeamModel team) { state = state.copyWith(showSelectionError: false); final playersCount = (team.players - ?.where((player) => player.detail?.isActive ?? false) - .toList() ?? - []) + .where((player) => player.user?.isActive ?? false) + .toList()) .length; if (playersCount >= 2) { final isAlreadySelected = state.selectedTeam?.id == team.id; diff --git a/khelo/lib/ui/flow/team/team_list_screen.dart b/khelo/lib/ui/flow/team/team_list_screen.dart index ba641725..c445a7db 100644 --- a/khelo/lib/ui/flow/team/team_list_screen.dart +++ b/khelo/lib/ui/flow/team/team_list_screen.dart @@ -88,7 +88,10 @@ class _TeamListScreenState extends ConsumerState return _teamListCell( context, team: team, - showMoreOptionButton: state.currentUserId == team.created_by, + showMoreOptionButton: team.players.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == + true, ); }, ) @@ -121,11 +124,11 @@ class _TeamListScreenState extends ConsumerState style: AppTextStyle.subtitle2 .copyWith(color: context.colorScheme.textPrimary), ), - subtitle: team.players != null + subtitle: team.players.isNotEmpty ? Padding( padding: const EdgeInsets.only(top: 4), child: Text( - '${team.players!.length} ${context.l10n.add_team_players_text}', + '${team.players.length} ${context.l10n.add_team_players_text}', style: AppTextStyle.subtitle2 .copyWith(color: context.colorScheme.textSecondary)), ) diff --git a/khelo/lib/ui/flow/team/team_list_view_model.dart b/khelo/lib/ui/flow/team/team_list_view_model.dart index 75487db8..81ee3d9b 100644 --- a/khelo/lib/ui/flow/team/team_list_view_model.dart +++ b/khelo/lib/ui/flow/team/team_list_view_model.dart @@ -41,7 +41,7 @@ class TeamListViewNotifier extends StateNotifier { state = state.copyWith(loading: state.teams.isEmpty); try { _teamsStreamSubscription = - _teamService.streamUserRelatedTeams().listen((teams) { + _teamService.getUserRelatedTeams().listen((teams) { state = state.copyWith(teams: teams, loading: false, error: null); _filterTeamList(); }, onError: (e) { @@ -66,9 +66,8 @@ class TeamListViewNotifier extends StateNotifier { .where((element) => element.created_by == state.currentUserId || (element.players - ?.map((e) => e.id) - .contains(state.currentUserId) ?? - false)) + .map((e) => e.id) + .contains(state.currentUserId))) .toList(); default: filteredTeams = state.teams; From c27f7cb8b4a47e6b47927e36813957e485e5a9a2 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 13 Aug 2024 16:22:21 +0530 Subject: [PATCH 03/20] Clean code --- .../flow/matches/match_detail/match_detail_tab_view_model.dart | 1 - 1 file changed, 1 deletion(-) 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 1d8250d3..40c8ad26 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 @@ -3,7 +3,6 @@ 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/api/team/team_model.dart'; import 'package:data/api/user/user_models.dart'; import 'package:data/errors/app_error.dart'; import 'package:data/service/ball_score/ball_score_service.dart'; From 84f62e1c12cce6a2f8e1651f5f82c7b5bfcddc9a Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 13 Aug 2024 17:08:35 +0530 Subject: [PATCH 04/20] Fix lint --- data/analysis_options.yaml | 16 ++++++++++++++++ data/lib/api/team/team_model.dart | 10 ++++++---- data/lib/api/team/team_model.freezed.dart | 3 ++- data/lib/api/team/team_model.g.dart | 2 +- data/lib/service/team/team_service.dart | 1 - 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/data/analysis_options.yaml b/data/analysis_options.yaml index a5744c1c..d51fd166 100644 --- a/data/analysis_options.yaml +++ b/data/analysis_options.yaml @@ -1,4 +1,20 @@ include: package:flutter_lints/flutter.yaml +analyzer: + exclude: + - '**.freezed.dart' + - '**.g.dart' + - '**.gr.dart' + - '**/generated_plugin_registrant.dart' + + errors: + invalid_annotation_target: ignore + +linter: + rules: + prefer_relative_imports: true + prefer_final_locals: true + require_trailing_commas: true + always_declare_return_types: true # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options diff --git a/data/lib/api/team/team_model.dart b/data/lib/api/team/team_model.dart index 2fdcc7e0..c86f94ab 100644 --- a/data/lib/api/team/team_model.dart +++ b/data/lib/api/team/team_model.dart @@ -1,7 +1,7 @@ // ignore_for_file: non_constant_identifier_names import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/user/user_models.dart'; +import '../user/user_models.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'team_model.freezed.dart'; @@ -9,7 +9,8 @@ part 'team_model.freezed.dart'; part 'team_model.g.dart'; @freezed -class TeamModel with _$TeamModel { +abstract class TeamModel with _$TeamModel { + @JsonSerializable(explicitToJson: true) const factory TeamModel({ String? id, required String name, @@ -25,8 +26,9 @@ class TeamModel with _$TeamModel { _$TeamModelFromJson(json); factory TeamModel.fromFireStore( - DocumentSnapshot> snapshot, - SnapshotOptions? options) => + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => TeamModel.fromJson(snapshot.data()!); } diff --git a/data/lib/api/team/team_model.freezed.dart b/data/lib/api/team/team_model.freezed.dart index 57b00c54..acf14ae0 100644 --- a/data/lib/api/team/team_model.freezed.dart +++ b/data/lib/api/team/team_model.freezed.dart @@ -187,7 +187,8 @@ class __$$TeamModelImplCopyWithImpl<$Res> } /// @nodoc -@JsonSerializable() + +@JsonSerializable(explicitToJson: true) class _$TeamModelImpl implements _TeamModel { const _$TeamModelImpl( {this.id, diff --git a/data/lib/api/team/team_model.g.dart b/data/lib/api/team/team_model.g.dart index ca6944cb..91f9992e 100644 --- a/data/lib/api/team/team_model.g.dart +++ b/data/lib/api/team/team_model.g.dart @@ -32,7 +32,7 @@ Map _$$TeamModelImplToJson(_$TeamModelImpl instance) => 'profile_img_url': instance.profile_img_url, 'created_by': instance.created_by, 'created_at': instance.created_at?.toIso8601String(), - 'players': instance.players, + 'players': instance.players.map((e) => e.toJson()).toList(), }; _$TeamPlayerImpl _$$TeamPlayerImplFromJson(Map json) => diff --git a/data/lib/service/team/team_service.dart b/data/lib/service/team/team_service.dart index 084c345e..85107cd6 100644 --- a/data/lib/service/team/team_service.dart +++ b/data/lib/service/team/team_service.dart @@ -181,7 +181,6 @@ class TeamService { return teamSnap.docs.isEmpty; } catch (error, stack) { - print(error); throw AppError.fromError(error, stack); } } From d50ab31762b68f144a120e3d9d949a1ccd4154ba Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 13 Aug 2024 17:18:19 +0530 Subject: [PATCH 05/20] Fix lint --- data/lib/api/ball_score/ball_score_model.dart | 189 +++++---- data/lib/api/innings/inning_model.dart | 5 +- data/lib/api/match/match_model.dart | 14 +- data/lib/api/support/support_models.dart | 5 +- data/lib/api/user/user_models.dart | 7 +- data/lib/service/auth/auth_service.dart | 28 +- .../ball_score/ball_score_service.dart | 116 +++--- data/lib/service/device/device_service.dart | 2 +- .../file_upload/file_upload_service.dart | 8 +- data/lib/service/innings/inning_service.dart | 12 +- data/lib/service/match/match_service.dart | 375 ++++++++++-------- data/lib/service/support/support_service.dart | 13 +- data/lib/service/team/team_service.dart | 126 +++--- data/lib/utils/dummy_deactivated_account.dart | 26 +- 14 files changed, 524 insertions(+), 402 deletions(-) diff --git a/data/lib/api/ball_score/ball_score_model.dart b/data/lib/api/ball_score/ball_score_model.dart index 62b49498..be6901ff 100644 --- a/data/lib/api/ball_score/ball_score_model.dart +++ b/data/lib/api/ball_score/ball_score_model.dart @@ -1,9 +1,9 @@ // ignore_for_file: non_constant_identifier_names import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/user/user_models.dart'; -import 'package:data/extensions/double_extensions.dart'; -import 'package:data/extensions/int_extensions.dart'; +import '../user/user_models.dart'; +import '../../extensions/double_extensions.dart'; +import '../../extensions/int_extensions.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'ball_score_model.freezed.dart'; @@ -36,8 +36,9 @@ class BallScoreModel with _$BallScoreModel { _$BallScoreModelFromJson(json); factory BallScoreModel.fromFireStore( - DocumentSnapshot> snapshot, - SnapshotOptions? options) => + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => BallScoreModel.fromJson(snapshot.data()!); } @@ -279,7 +280,7 @@ extension OverSummaryMetaData on OverSummary { (balls.lastOrNull?.isLegalDelivery() ?? false); double get overCount { - int totalBalls = ((overNumber - 1) * 6) + legalDeliveriesCount; + final int totalBalls = ((overNumber - 1) * 6) + legalDeliveriesCount; return totalBalls.toOvers(); } @@ -290,35 +291,43 @@ extension OverSummaryMetaData on OverSummary { balls.fold(0, (runCount, element) => runCount += element.runs_scored); int get extras => balls.fold( - 0, (extraCount, element) => extraCount += (element.extras_awarded ?? 0)); + 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)); + 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) + .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); + 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) + .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 @@ -331,12 +340,13 @@ extension OverSummaryMetaData on OverSummary { final overDelivered = bowler.overDelivered.remove(legalDeliveriesCount); return bowler.copyWith( - wideBalls: wideBalls, - runsConceded: runsConceded, - overDelivered: overDelivered, - noBalls: noBalls, - maiden: maiden, - wicket: wickets); + wideBalls: wideBalls, + runsConceded: runsConceded, + overDelivered: overDelivered, + noBalls: noBalls, + maiden: maiden, + wicket: wickets, + ); } OverSummary addBall(BallScoreModel ball, {Player? catchBy}) { @@ -354,17 +364,21 @@ extension OverSummaryMetaData on OverSummary { 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 - ? Player(id: bowler.player.id, name: bowler.player.name ?? "") - : null, - catchBy: ball.player_out_id == striker.player.id ? catchBy : null); + final configuredStriker = striker.addBall( + ball, + ballBy: ball.player_out_id == striker.player.id + ? Player(id: bowler.player.id, name: bowler.player.name ?? "") + : null, + catchBy: ball.player_out_id == striker.player.id ? catchBy : null, + ); - final configuredNonStriker = nonStriker.addBall(ball, - ballBy: ball.player_out_id == nonStriker.player.id - ? Player(id: bowler.player.id, name: bowler.player.name ?? "") - : null, - catchBy: ball.player_out_id == nonStriker.player.id ? catchBy : null); + final configuredNonStriker = nonStriker.addBall( + ball, + ballBy: ball.player_out_id == nonStriker.player.id + ? Player(id: bowler.player.id, name: bowler.player.name ?? "") + : null, + catchBy: ball.player_out_id == nonStriker.player.id ? catchBy : null, + ); final outPlayersList = outPlayers.toList(); if (ball.player_out_id == configuredStriker.player.id) { @@ -377,8 +391,10 @@ extension OverSummaryMetaData on OverSummary { totalWickets: totalWicketCount, extrasSummary: extraSummaryDetail, balls: ballScores, - bowler: bowler.addBall(ball, - isMaidenWithoutTheBall: runs == 0 && wickets == 0 && extras == 0), + bowler: bowler.addBall( + ball, + isMaidenWithoutTheBall: runs == 0 && wickets == 0 && extras == 0, + ), outPlayers: outPlayersList, striker: configuredStriker, nonStriker: configuredNonStriker, @@ -407,10 +423,12 @@ extension OverSummaryMetaData on OverSummary { final outPlayersList = outPlayers; if (ball.player_out_id == configuredStriker.player.id) { outPlayersList.removeWhere( - (element) => element.player.id == configuredStriker.player.id); + (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); + (element) => element.player.id == configuredNonStriker.player.id, + ); } final lastBall = ballScores.lastOrNull; @@ -439,8 +457,10 @@ extension BowlerSummaryMetaData on BowlerSummary { return double.parse((runsConceded / overDelivered).toStringAsFixed(1)); } - BowlerSummary addBall(BallScoreModel ball, - {required bool isMaidenWithoutTheBall}) { + BowlerSummary addBall( + BallScoreModel ball, { + required bool isMaidenWithoutTheBall, + }) { if (ball.bowler_id != player.id) { return this; } @@ -477,16 +497,19 @@ extension BowlerSummaryMetaData on BowlerSummary { : maiden; return copyWith( - wicket: wicketCount, - maiden: maidenCount, - noBalls: noBallCount, - overDelivered: overDeliverCount, - runsConceded: runCount, - wideBalls: wideBallCount); + wicket: wicketCount, + maiden: maidenCount, + noBalls: noBallCount, + overDelivered: overDeliverCount, + runsConceded: runCount, + wideBalls: wideBallCount, + ); } - BowlerSummary removeBall(BallScoreModel ball, - {required bool isMaidenIncludingBall}) { + BowlerSummary removeBall( + BallScoreModel ball, { + required bool isMaidenIncludingBall, + }) { if (ball.bowler_id != player.id) { return this; } @@ -523,12 +546,13 @@ extension BowlerSummaryMetaData on BowlerSummary { : maiden; return copyWith( - wicket: wicketCount, - maiden: maidenCount, - noBalls: noBallCount, - overDelivered: overDeliverCount, - runsConceded: runCount, - wideBalls: wideBallCount); + wicket: wicketCount, + maiden: maidenCount, + noBalls: noBallCount, + overDelivered: overDeliverCount, + runsConceded: runCount, + wideBalls: wideBallCount, + ); } } @@ -537,8 +561,11 @@ extension BatsmanSummaryMetaData on BatsmanSummary { return double.parse(((runs / ballFaced) * 100).toStringAsFixed(1)); } - BatsmanSummary addBall(BallScoreModel ball, - {Player? ballBy, Player? catchBy}) { + BatsmanSummary addBall( + BallScoreModel ball, { + Player? ballBy, + Player? catchBy, + }) { if (ball.batsman_id != player.id && ball.non_striker_id != player.id) { return this; } @@ -548,16 +575,17 @@ extension BatsmanSummaryMetaData on BatsmanSummary { ? 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); + 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) { @@ -570,14 +598,15 @@ extension BatsmanSummaryMetaData on BatsmanSummary { ? 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); + 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, + ); } } diff --git a/data/lib/api/innings/inning_model.dart b/data/lib/api/innings/inning_model.dart index a08d0855..8aeef3da 100644 --- a/data/lib/api/innings/inning_model.dart +++ b/data/lib/api/innings/inning_model.dart @@ -23,8 +23,9 @@ class InningModel with _$InningModel { _$InningModelFromJson(json); factory InningModel.fromFireStore( - DocumentSnapshot> snapshot, - SnapshotOptions? options) => + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => InningModel.fromJson(snapshot.data()!); } diff --git a/data/lib/api/match/match_model.dart b/data/lib/api/match/match_model.dart index 1fb85980..3e172e2b 100644 --- a/data/lib/api/match/match_model.dart +++ b/data/lib/api/match/match_model.dart @@ -77,10 +77,11 @@ extension DataMatchModel on MatchModel { final runDifference = firstTeam.run - secondTeam.run; return MatchResult( - teamId: firstTeam.team.id ?? "", - teamName: teamName, - difference: runDifference, - winType: WinnerByType.run); + teamId: firstTeam.team.id ?? "", + teamName: teamName, + difference: runDifference, + winType: WinnerByType.run, + ); } else if (firstTeam.run == secondTeam.run) { return MatchResult( teamId: "", @@ -172,8 +173,9 @@ class AddEditMatchRequest with _$AddEditMatchRequest { _$AddEditMatchRequestFromJson(json); factory AddEditMatchRequest.fromFireStore( - DocumentSnapshot> snapshot, - SnapshotOptions? options) => + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => AddEditMatchRequest.fromJson(snapshot.data()!); } diff --git a/data/lib/api/support/support_models.dart b/data/lib/api/support/support_models.dart index e7f5acfe..a5903659 100644 --- a/data/lib/api/support/support_models.dart +++ b/data/lib/api/support/support_models.dart @@ -20,8 +20,9 @@ class AddSupportCaseRequest with _$AddSupportCaseRequest { _$AddSupportCaseRequestFromJson(json); factory AddSupportCaseRequest.fromFireStore( - DocumentSnapshot> snapshot, - SnapshotOptions? options) => + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => AddSupportCaseRequest.fromJson(snapshot.data()!); } diff --git a/data/lib/api/user/user_models.dart b/data/lib/api/user/user_models.dart index 99aff4ee..4238fc4d 100644 --- a/data/lib/api/user/user_models.dart +++ b/data/lib/api/user/user_models.dart @@ -35,8 +35,9 @@ class UserModel with _$UserModel { _$UserModelFromJson(json); factory UserModel.fromFireStore( - DocumentSnapshot> snapshot, - SnapshotOptions? options) => + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => UserModel.fromJson(snapshot.data()!); String toJsonString() => jsonEncode(toJson()); @@ -58,7 +59,7 @@ extension ProfileCompleteExtension on UserModel { gender, player_role, batting_style, - bowling_style + bowling_style, ]; final completedFields = fields diff --git a/data/lib/service/auth/auth_service.dart b/data/lib/service/auth/auth_service.dart index 911e0d61..9a3624ba 100644 --- a/data/lib/service/auth/auth_service.dart +++ b/data/lib/service/auth/auth_service.dart @@ -1,6 +1,6 @@ -import 'package:data/errors/app_error.dart'; -import 'package:data/extensions/string_extensions.dart'; -import 'package:data/service/user/user_service.dart'; +import '../../errors/app_error.dart'; +import '../../extensions/string_extensions.dart'; +import '../user/user_service.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -53,8 +53,12 @@ class AuthService { } } - Future verifyOTP(String countryCode, String phoneNumber, - String verificationId, String otp) async { + Future verifyOTP( + String countryCode, + String phoneNumber, + String verificationId, + String otp, + ) async { try { final credential = PhoneAuthProvider.credential( verificationId: verificationId, @@ -69,17 +73,21 @@ class AuthService { } Future _onVerificationSuccess( - String countryCode, String phoneNumber, UserCredential credential) async { + String countryCode, + String phoneNumber, + UserCredential credential, + ) async { try { if (credential.additionalUserInfo?.isNewUser ?? false) { if (_auth.currentUser == null) { return; } final phone = "$countryCode ${phoneNumber.caseAndSpaceInsensitive}"; - UserModel user = UserModel( - id: _auth.currentUser!.uid, - phone: phone, - created_at: DateTime.now()); + final UserModel user = UserModel( + id: _auth.currentUser!.uid, + phone: phone, + created_at: DateTime.now(), + ); await _userService.updateUser(user); } else { final uid = credential.user?.uid; diff --git a/data/lib/service/ball_score/ball_score_service.dart b/data/lib/service/ball_score/ball_score_service.dart index 5b9ed242..abddf725 100644 --- a/data/lib/service/ball_score/ball_score_service.dart +++ b/data/lib/service/ball_score/ball_score_service.dart @@ -1,11 +1,11 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/ball_score/ball_score_model.dart'; -import 'package:data/errors/app_error.dart'; -import 'package:data/service/innings/inning_service.dart'; -import 'package:data/service/match/match_service.dart'; -import 'package:data/storage/app_preferences.dart'; -import 'package:data/utils/constant/firestore_constant.dart'; +import '../../api/ball_score/ball_score_model.dart'; +import '../../errors/app_error.dart'; +import '../innings/inning_service.dart'; +import '../match/match_service.dart'; +import '../../storage/app_preferences.dart'; +import '../../utils/constant/firestore_constant.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../api/match/match_model.dart'; @@ -29,13 +29,17 @@ class BallScoreService { String? _currentUserId; final CollectionReference _ballScoreCollection; - BallScoreService(this._firestore, this._matchService, this._inningsService, - this._currentUserId) - : _ballScoreCollection = _firestore + BallScoreService( + this._firestore, + this._matchService, + this._inningsService, + this._currentUserId, + ) : _ballScoreCollection = _firestore .collection(FireStoreConst.ballScoresCollection) .withConverter( - fromFirestore: BallScoreModel.fromFireStore, - toFirestore: (BallScoreModel score, _) => score.toJson()); + fromFirestore: BallScoreModel.fromFireStore, + toFirestore: (BallScoreModel score, _) => score.toJson(), + ); Future addBallScoreAndUpdateTeamDetails({ required BallScoreModel score, @@ -56,23 +60,27 @@ class BallScoreService { double.parse("${score.over_number - 1}.${score.ball_number}"); // update matchTeamScore and squad(if needed) - await _matchService.updateTeamScoreAndSquadViaTransaction(transaction, - matchId: matchId, - battingTeamId: battingTeamId, - totalRun: totalRuns, - over: overCount, - bowlingTeamId: bowlingTeamId, - wicket: totalWicketTaken, - runs: totalBowlingTeamRuns, - updatedMatchPlayer: updatedPlayer != null ? [updatedPlayer] : null); + await _matchService.updateTeamScoreAndSquadViaTransaction( + transaction, + matchId: matchId, + battingTeamId: battingTeamId, + totalRun: totalRuns, + over: overCount, + bowlingTeamId: bowlingTeamId, + wicket: totalWicketTaken, + runs: totalBowlingTeamRuns, + updatedMatchPlayer: updatedPlayer != null ? [updatedPlayer] : null, + ); // update innings score detail - _inningsService.updateInningScoreDetailViaTransaction(transaction, - battingTeamInningId: battingTeamInningId, - over: overCount, - totalRun: totalRuns, - bowlingTeamInningId: bowlingTeamInningId, - wicketCount: totalWicketTaken, - runs: totalBowlingTeamRuns); + _inningsService.updateInningScoreDetailViaTransaction( + transaction, + battingTeamInningId: battingTeamInningId, + over: overCount, + totalRun: totalRuns, + bowlingTeamInningId: bowlingTeamInningId, + wicketCount: totalWicketTaken, + runs: totalBowlingTeamRuns, + ); // add ball transaction.set( @@ -89,13 +97,16 @@ class BallScoreService { } Stream> getBallScoresStreamByInningIds( - List inningIds) { + List inningIds, + ) { return _ballScoreCollection .where(FireStoreConst.inningId, whereIn: inningIds) .snapshots() - .map((event) => event.docChanges - .map((score) => BallScoreChange(score.type, score.doc.data()!)) - .toList()) + .map( + (event) => event.docChanges + .map((score) => BallScoreChange(score.type, score.doc.data()!)) + .toList(), + ) .handleError((error, stack) => throw AppError.fromError(error, stack)); } @@ -105,11 +116,14 @@ class BallScoreService { } return _ballScoreCollection - .where(Filter.or( + .where( + Filter.or( Filter(FireStoreConst.bowlerId, isEqualTo: _currentUserId), Filter(FireStoreConst.batsmanId, isEqualTo: _currentUserId), Filter(FireStoreConst.wicketTakerId, isEqualTo: _currentUserId), - Filter(FireStoreConst.playerOutId, isEqualTo: _currentUserId))) + Filter(FireStoreConst.playerOutId, isEqualTo: _currentUserId), + ), + ) .snapshots() .map((event) => event.docs.map((score) => score.data()).toList()) .handleError((error, stack) => throw AppError.fromError(error, stack)); @@ -131,24 +145,28 @@ class BallScoreService { try { _firestore.runTransaction((transaction) async { // update matchTeamScore and squad(if needed) - await _matchService.updateTeamScoreAndSquadViaTransaction(transaction, - matchId: matchId, - battingTeamId: battingTeamId, - totalRun: totalRuns, - over: overCount, - bowlingTeamId: bowlingTeamId, - wicket: totalWicketTaken, - runs: totalBowlingTeamRuns, - updatedMatchPlayer: updatedPlayer); + await _matchService.updateTeamScoreAndSquadViaTransaction( + transaction, + matchId: matchId, + battingTeamId: battingTeamId, + totalRun: totalRuns, + over: overCount, + bowlingTeamId: bowlingTeamId, + wicket: totalWicketTaken, + runs: totalBowlingTeamRuns, + updatedMatchPlayer: updatedPlayer, + ); // update innings score detail - _inningsService.updateInningScoreDetailViaTransaction(transaction, - battingTeamInningId: battingTeamInningId, - over: overCount, - totalRun: totalRuns, - bowlingTeamInningId: bowlingTeamInningId, - wicketCount: totalWicketTaken, - runs: totalBowlingTeamRuns); + _inningsService.updateInningScoreDetailViaTransaction( + transaction, + battingTeamInningId: battingTeamInningId, + over: overCount, + totalRun: totalRuns, + bowlingTeamInningId: bowlingTeamInningId, + wicketCount: totalWicketTaken, + runs: totalBowlingTeamRuns, + ); // delete ball final docRef = _ballScoreCollection.doc(ballId); diff --git a/data/lib/service/device/device_service.dart b/data/lib/service/device/device_service.dart index 0c65d607..a2d9ece4 100644 --- a/data/lib/service/device/device_service.dart +++ b/data/lib/service/device/device_service.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:data/api/network/client.dart'; +import '../../api/network/client.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; diff --git a/data/lib/service/file_upload/file_upload_service.dart b/data/lib/service/file_upload/file_upload_service.dart index 63e8a768..65fb0aa7 100644 --- a/data/lib/service/file_upload/file_upload_service.dart +++ b/data/lib/service/file_upload/file_upload_service.dart @@ -1,5 +1,5 @@ import 'dart:io'; -import 'package:data/errors/app_error.dart'; +import '../../errors/app_error.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -16,12 +16,12 @@ class FileUploadService { required String filePath, required String uploadPath, }) async { - var file = File(filePath); + final file = File(filePath); if (await file.exists()) { try { - var snapshot = + final snapshot = await _firebaseStorage.ref().child(uploadPath).putFile(file); - var downloadUrl = await snapshot.ref.getDownloadURL(); + final downloadUrl = await snapshot.ref.getDownloadURL(); return downloadUrl; } catch (error, stack) { throw AppError.fromError(error, stack); diff --git a/data/lib/service/innings/inning_service.dart b/data/lib/service/innings/inning_service.dart index c34e107b..c203c3ee 100644 --- a/data/lib/service/innings/inning_service.dart +++ b/data/lib/service/innings/inning_service.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/innings/inning_model.dart'; -import 'package:data/errors/app_error.dart'; -import 'package:data/utils/constant/firestore_constant.dart'; +import '../../api/innings/inning_model.dart'; +import '../../errors/app_error.dart'; +import '../../utils/constant/firestore_constant.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; final inningServiceProvider = Provider((ref) { @@ -31,7 +31,7 @@ class InningsService { required InningStatus secondInningStatus, }) async { try { - WriteBatch batch = _firestore.batch(); + final WriteBatch batch = _firestore.batch(); final firstInningRef = _inningCollection.doc(); final secondInningRef = _inningCollection.doc(); @@ -88,14 +88,14 @@ class InningsService { final bowlInningRef = _inningCollection.doc(bowlingTeamInningId); - Map battingUpdates = { + final Map battingUpdates = { FireStoreConst.totalRuns: totalRun, }; if (over != null) battingUpdates.addAll({FireStoreConst.overs: over}); transaction.update(batInningRef, battingUpdates); - Map bowlingUpdates = { + final Map bowlingUpdates = { FireStoreConst.totalWickets: wicketCount }; if (runs != null) bowlingUpdates.addAll({FireStoreConst.totalRuns: runs}); diff --git a/data/lib/service/match/match_service.dart b/data/lib/service/match/match_service.dart index 70c3f802..16942864 100644 --- a/data/lib/service/match/match_service.dart +++ b/data/lib/service/match/match_service.dart @@ -1,13 +1,13 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/match/match_model.dart'; -import 'package:data/api/team/team_model.dart'; -import 'package:data/api/user/user_models.dart'; -import 'package:data/errors/app_error.dart'; -import 'package:data/extensions/list_extensions.dart'; -import 'package:data/service/team/team_service.dart'; -import 'package:data/service/user/user_service.dart'; -import 'package:data/utils/constant/firestore_constant.dart'; +import '../../api/match/match_model.dart'; +import '../../api/team/team_model.dart'; +import '../../api/user/user_models.dart'; +import '../../errors/app_error.dart'; +import '../../extensions/list_extensions.dart'; +import '../team/team_service.dart'; +import '../user/user_service.dart'; +import '../../utils/constant/firestore_constant.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../storage/app_preferences.dart'; @@ -39,8 +39,9 @@ class MatchService { ) : _matchCollection = _firestore .collection(FireStoreConst.matchesCollection) .withConverter( - fromFirestore: AddEditMatchRequest.fromFireStore, - toFirestore: (AddEditMatchRequest match, _) => match.toJson()); + fromFirestore: AddEditMatchRequest.fromFireStore, + toFirestore: (AddEditMatchRequest match, _) => match.toJson(), + ); Stream> getCurrentUserPlayedMatches() { if (_currentUserId == null) { @@ -56,30 +57,32 @@ class MatchService { .where(filter) .snapshots() .asyncMap((snapshot) async { - return await Future.wait(snapshot.docs.map((mainDoc) async { - final match = mainDoc.data(); - List teams = await getTeamsList(match.teams); - return MatchModel( - id: match.id, - teams: teams, - match_type: match.match_type, - number_of_over: match.number_of_over, - over_per_bowler: match.over_per_bowler, - players: match.players, - team_ids: match.team_ids, - team_creator_ids: match.team_creator_ids, - city: match.city, - ground: match.ground, - start_time: match.start_time, - created_by: match.created_by, - ball_type: match.ball_type, - pitch_type: match.pitch_type, - match_status: match.match_status, - toss_winner_id: match.toss_winner_id, - toss_decision: match.toss_decision, - current_playing_team_id: match.current_playing_team_id, - ); - }).toList()); + return await Future.wait( + snapshot.docs.map((mainDoc) async { + final match = mainDoc.data(); + final List teams = await getTeamsList(match.teams); + return MatchModel( + id: match.id, + teams: teams, + match_type: match.match_type, + number_of_over: match.number_of_over, + over_per_bowler: match.over_per_bowler, + players: match.players, + team_ids: match.team_ids, + team_creator_ids: match.team_creator_ids, + city: match.city, + ground: match.ground, + start_time: match.start_time, + created_by: match.created_by, + ball_type: match.ball_type, + pitch_type: match.pitch_type, + match_status: match.match_status, + toss_winner_id: match.toss_winner_id, + toss_decision: match.toss_decision, + current_playing_team_id: match.current_playing_team_id, + ); + }).toList(), + ); }).handleError((error, stack) => throw AppError.fromError(error, stack)); } @@ -89,38 +92,41 @@ class MatchService { } final filter = Filter.or( - Filter(FireStoreConst.createdBy, isEqualTo: _currentUserId), - Filter(FireStoreConst.players, arrayContains: _currentUserId), - Filter(FireStoreConst.teamCreatorIds, arrayContains: _currentUserId)); + Filter(FireStoreConst.createdBy, isEqualTo: _currentUserId), + Filter(FireStoreConst.players, arrayContains: _currentUserId), + Filter(FireStoreConst.teamCreatorIds, arrayContains: _currentUserId), + ); return _matchCollection .where(filter) .snapshots() .asyncMap((snapshot) async { - return await Future.wait(snapshot.docs.map((mainDoc) async { - final match = mainDoc.data(); - List teams = await getTeamsList(match.teams); - return MatchModel( - id: match.id, - teams: teams, - match_type: match.match_type, - number_of_over: match.number_of_over, - over_per_bowler: match.over_per_bowler, - city: match.city, - players: match.players, - team_ids: match.team_ids, - team_creator_ids: match.team_creator_ids, - ground: match.ground, - start_time: match.start_time, - created_by: match.created_by, - ball_type: match.ball_type, - pitch_type: match.pitch_type, - match_status: match.match_status, - toss_winner_id: match.toss_winner_id, - toss_decision: match.toss_decision, - current_playing_team_id: match.current_playing_team_id, - ); - }).toList()); + return await Future.wait( + snapshot.docs.map((mainDoc) async { + final match = mainDoc.data(); + final List teams = await getTeamsList(match.teams); + return MatchModel( + id: match.id, + teams: teams, + match_type: match.match_type, + number_of_over: match.number_of_over, + over_per_bowler: match.over_per_bowler, + city: match.city, + players: match.players, + team_ids: match.team_ids, + team_creator_ids: match.team_creator_ids, + ground: match.ground, + start_time: match.start_time, + created_by: match.created_by, + ball_type: match.ball_type, + pitch_type: match.pitch_type, + match_status: match.match_status, + toss_winner_id: match.toss_winner_id, + toss_decision: match.toss_decision, + current_playing_team_id: match.current_playing_team_id, + ); + }).toList(), + ); }).handleError((error, stack) => throw AppError.fromError(error, stack)); } @@ -129,55 +135,21 @@ class MatchService { .where(FireStoreConst.teamIds, arrayContains: teamId) .snapshots() .asyncMap((snapshot) async { - return await Future.wait(snapshot.docs.map((mainDoc) async { - final match = mainDoc.data(); - - List teams = await getTeamsList(match.teams); - return MatchModel( - id: match.id, - teams: teams, - match_type: match.match_type, - number_of_over: match.number_of_over, - over_per_bowler: match.over_per_bowler, - city: match.city, - players: match.players, - team_ids: match.team_ids, - team_creator_ids: match.team_creator_ids, - ground: match.ground, - start_time: match.start_time, - created_by: match.created_by, - ball_type: match.ball_type, - pitch_type: match.pitch_type, - match_status: match.match_status, - toss_winner_id: match.toss_winner_id, - toss_decision: match.toss_decision, - current_playing_team_id: match.current_playing_team_id, - ); - }).toList()); - }).handleError((error, stack) => throw AppError.fromError(error, stack)); - } - - Stream> getRunningMatches() { - return _matchCollection - .where(FireStoreConst.matchStatus, isEqualTo: MatchStatus.running.value) - .snapshots() - .asyncMap((snapshot) async { - List matches = []; - for (final mainDoc in snapshot.docs) { - if (mainDoc.data().match_status == MatchStatus.running) { + return await Future.wait( + snapshot.docs.map((mainDoc) async { final match = mainDoc.data(); - List teams = await getTeamsList(match.teams); - matches.add(MatchModel( + final List teams = await getTeamsList(match.teams); + return MatchModel( id: match.id, teams: teams, match_type: match.match_type, number_of_over: match.number_of_over, over_per_bowler: match.over_per_bowler, + city: match.city, players: match.players, team_ids: match.team_ids, team_creator_ids: match.team_creator_ids, - city: match.city, ground: match.ground, start_time: match.start_time, created_by: match.created_by, @@ -187,7 +159,45 @@ class MatchService { toss_winner_id: match.toss_winner_id, toss_decision: match.toss_decision, current_playing_team_id: match.current_playing_team_id, - )); + ); + }).toList(), + ); + }).handleError((error, stack) => throw AppError.fromError(error, stack)); + } + + Stream> getRunningMatches() { + return _matchCollection + .where(FireStoreConst.matchStatus, isEqualTo: MatchStatus.running.value) + .snapshots() + .asyncMap((snapshot) async { + final List matches = []; + for (final mainDoc in snapshot.docs) { + if (mainDoc.data().match_status == MatchStatus.running) { + final match = mainDoc.data(); + + final List teams = await getTeamsList(match.teams); + matches.add( + MatchModel( + id: match.id, + teams: teams, + match_type: match.match_type, + number_of_over: match.number_of_over, + over_per_bowler: match.over_per_bowler, + players: match.players, + team_ids: match.team_ids, + team_creator_ids: match.team_creator_ids, + city: match.city, + ground: match.ground, + start_time: match.start_time, + created_by: match.created_by, + ball_type: match.ball_type, + pitch_type: match.pitch_type, + match_status: match.match_status, + toss_winner_id: match.toss_winner_id, + toss_decision: match.toss_decision, + current_playing_team_id: match.current_playing_team_id, + ), + ); } } return matches; @@ -199,24 +209,27 @@ class MatchService { final match = snapshot.data(); if (match == null) { return MatchModel( - teams: [], - match_type: MatchType.limitedOvers, - number_of_over: 0, - over_per_bowler: 0, - city: '', - ground: '', - start_time: DateTime.now(), - ball_type: BallType.leather, - pitch_type: PitchType.turf, - created_by: '', - match_status: MatchStatus.running); + teams: [], + match_type: MatchType.limitedOvers, + number_of_over: 0, + over_per_bowler: 0, + city: '', + ground: '', + start_time: DateTime.now(), + ball_type: BallType.leather, + pitch_type: PitchType.turf, + created_by: '', + match_status: MatchStatus.running, + ); } - List teams = await getTeamsList(match.teams); - List? umpires = await getUserListFromUserIds(match.umpire_ids); - List? commentators = + final List teams = await getTeamsList(match.teams); + final List? umpires = + await getUserListFromUserIds(match.umpire_ids); + final List? commentators = await getUserListFromUserIds(match.commentator_ids); - List? scorers = await getUserListFromUserIds(match.scorer_ids); + final List? scorers = + await getUserListFromUserIds(match.scorer_ids); UserModel? referee; if (match.referee_id != null) { @@ -260,31 +273,34 @@ class MatchService { final match = snapshot.data(); if (match == null) { return MatchModel( - teams: [], - match_type: MatchType.limitedOvers, - number_of_over: 0, - over_per_bowler: 0, - city: '', - ground: '', - start_time: DateTime.now(), - ball_type: BallType.leather, - pitch_type: PitchType.turf, - created_by: '', - match_status: MatchStatus.running); + teams: [], + match_type: MatchType.limitedOvers, + number_of_over: 0, + over_per_bowler: 0, + city: '', + ground: '', + start_time: DateTime.now(), + ball_type: BallType.leather, + pitch_type: PitchType.turf, + created_by: '', + match_status: MatchStatus.running, + ); } - List teams = await getTeamsList(match.teams); - List? umpires = await getUserListFromUserIds(match.umpire_ids); - List? commentators = + final List teams = await getTeamsList(match.teams); + final List? umpires = + await getUserListFromUserIds(match.umpire_ids); + final List? commentators = await getUserListFromUserIds(match.commentator_ids); - List? scorers = await getUserListFromUserIds(match.scorer_ids); + final List? scorers = + await getUserListFromUserIds(match.scorer_ids); UserModel? referee; if (match.referee_id != null) { referee = await _userService.getUserById(match.referee_id!); } - var matchModel = MatchModel( + final matchModel = MatchModel( id: match.id, teams: teams, match_type: match.match_type, @@ -322,19 +338,25 @@ class MatchService { try { final matchRef = _matchCollection.doc(match.id); await matchRef.set( - match.copyWith(id: matchRef.id), SetOptions(merge: true)); + match.copyWith(id: matchRef.id), + SetOptions(merge: true), + ); return matchRef.id; } catch (error, stack) { throw AppError.fromError(error, stack); } } - Future updateTossDetails(String matchId, String tossWinnerId, - TossDecision tossDecision, String currentPlayingTeam) async { + Future updateTossDetails( + String matchId, + String tossWinnerId, + TossDecision tossDecision, + String currentPlayingTeam, + ) async { try { final matchRef = _matchCollection.doc(matchId); - Map tossDetails = { + final Map tossDetails = { FireStoreConst.tossWinnerId: tossWinnerId, FireStoreConst.tossDecision: tossDecision.value, FireStoreConst.currentPlayingTeamId: currentPlayingTeam, @@ -350,7 +372,7 @@ class MatchService { try { final matchRef = _matchCollection.doc(matchId); - Map matchStatus = { + final Map matchStatus = { FireStoreConst.matchStatus: status.value, }; @@ -378,19 +400,19 @@ class MatchService { final existingTeams = snapshot.data()?.teams ?? []; - int battingTeamIndex = + final int battingTeamIndex = existingTeams.indexWhere((team) => team.team_id == battingTeamId); - int bowlingTeamIndex = + final int bowlingTeamIndex = existingTeams.indexWhere((team) => team.team_id == bowlingTeamId); var battingTeam = existingTeams[battingTeamIndex]; var bowlingTeam = existingTeams[bowlingTeamIndex]; if (battingTeamIndex != -1 && bowlingTeamIndex != -1) { if (updatedMatchPlayer != null) { - var updatedSquad = existingTeams[battingTeamIndex].squad.toList(); + final updatedSquad = existingTeams[battingTeamIndex].squad.toList(); for (final matchPlayer in updatedMatchPlayer) { - int existingPlayerIndex = updatedSquad + final int existingPlayerIndex = updatedSquad .indexWhere((player) => player.id == matchPlayer.id); if (existingPlayerIndex != -1) { updatedSquad[existingPlayerIndex] = matchPlayer; @@ -412,15 +434,17 @@ class MatchService { } transaction.update(matchRef, { - FireStoreConst.teams: [battingTeam.toJson(), bowlingTeam.toJson()] + FireStoreConst.teams: [battingTeam.toJson(), bowlingTeam.toJson()], }); } catch (error, stack) { throw AppError.fromError(error, stack); } } - Future updateCurrentPlayingTeam( - {required String matchId, required String teamId}) async { + Future updateCurrentPlayingTeam({ + required String matchId, + required String teamId, + }) async { try { final matchRef = _matchCollection.doc(matchId); @@ -431,7 +455,9 @@ class MatchService { } Future updateTeamsSquad( - String matchId, AddMatchTeamRequest teamRequest) async { + String matchId, + AddMatchTeamRequest teamRequest, + ) async { try { final matchRef = _matchCollection.doc(matchId); @@ -440,15 +466,15 @@ class MatchService { final existingTeams = snapshot.data()?.teams ?? []; var updatedTeams = existingTeams; - int teamIndex = existingTeams + final int teamIndex = existingTeams .indexWhere((team) => team.team_id == teamRequest.team_id); if (teamIndex != -1) { var team = existingTeams[teamIndex]; - var updatedSquad = existingTeams[teamIndex].squad.toList(); + final updatedSquad = existingTeams[teamIndex].squad.toList(); for (var updatedPlayer in teamRequest.squad) { - int existingPlayerIndex = updatedSquad + final int existingPlayerIndex = updatedSquad .indexWhere((player) => player.id == updatedPlayer.id); if (existingPlayerIndex != -1) { updatedSquad[existingPlayerIndex] = updatedPlayer; @@ -459,12 +485,15 @@ class MatchService { team = team.copyWith(squad: updatedSquad); updatedTeams = updatedTeams.updateWhere( - where: (element) => element.team_id == team.team_id, - updated: (oldElement) => team); + where: (element) => element.team_id == team.team_id, + updated: (oldElement) => team, + ); } - transaction.update(matchRef, - {FireStoreConst.teams: updatedTeams.map((e) => e.toJson())}); + transaction.update( + matchRef, + {FireStoreConst.teams: updatedTeams.map((e) => e.toJson())}, + ); }); } catch (error, stack) { throw AppError.fromError(error, stack); @@ -485,7 +514,7 @@ class MatchService { return null; } try { - List users = await _userService.getUsersByIds(userIds); + final List users = await _userService.getUsersByIds(userIds); return users; } catch (error, stack) { throw AppError.fromError(error, stack); @@ -493,22 +522,26 @@ class MatchService { } Future> getTeamsList( - List teamList) async { + List teamList, + ) async { try { - List teams = []; + final List teams = []; await Future.forEach(teamList, (e) async { - TeamModel team = await _teamService.getTeamById(e.team_id); - List squad = await getPlayerListFromPlayerIds(e.squad); - teams.add(MatchTeamModel( - team: team, - squad: squad, - over: e.over, - run: e.run, - wicket: e.wicket, - captain_id: e.captain_id, - admin_id: e.admin_id, - )); + final TeamModel team = await _teamService.getTeamById(e.team_id); + final List squad = + await getPlayerListFromPlayerIds(e.squad); + teams.add( + MatchTeamModel( + team: team, + squad: squad, + over: e.over, + run: e.run, + wicket: e.wicket, + captain_id: e.captain_id, + admin_id: e.admin_id, + ), + ); }); return teams; @@ -518,13 +551,15 @@ class MatchService { } Future> getPlayerListFromPlayerIds( - List players) async { + List players, + ) async { try { - List playerIds = players.map((player) => player.id).toList(); + final List playerIds = + players.map((player) => player.id).toList(); - List users = await _userService.getUsersByIds(playerIds); + final List users = await _userService.getUsersByIds(playerIds); - List squad = users.map((user) { + final List squad = users.map((user) { final matchPlayer = players.firstWhere((element) => element.id == user.id); diff --git a/data/lib/service/support/support_service.dart b/data/lib/service/support/support_service.dart index 874d23b8..efb9e83c 100644 --- a/data/lib/service/support/support_service.dart +++ b/data/lib/service/support/support_service.dart @@ -1,5 +1,5 @@ import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/support/support_models.dart'; +import '../../api/support/support_models.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../errors/app_error.dart'; @@ -17,15 +17,18 @@ class SupportService { : _supportCollection = firestore .collection(FireStoreConst.supportCollection) .withConverter( - fromFirestore: AddSupportCaseRequest.fromFireStore, - toFirestore: (AddSupportCaseRequest support, _) => - support.toJson()); + fromFirestore: AddSupportCaseRequest.fromFireStore, + toFirestore: (AddSupportCaseRequest support, _) => + support.toJson(), + ); Future addSupportCase(AddSupportCaseRequest supportCase) async { try { final supportCaseRef = _supportCollection.doc(supportCase.id); await supportCaseRef.set( - supportCase.copyWith(id: supportCaseRef.id), SetOptions(merge: true)); + supportCase.copyWith(id: supportCaseRef.id), + SetOptions(merge: true), + ); return supportCaseRef.id; } catch (error, stack) { throw AppError.fromError(error, stack); diff --git a/data/lib/service/team/team_service.dart b/data/lib/service/team/team_service.dart index 85107cd6..0610615d 100644 --- a/data/lib/service/team/team_service.dart +++ b/data/lib/service/team/team_service.dart @@ -1,12 +1,12 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/team/team_model.dart'; -import 'package:data/api/user/user_models.dart'; -import 'package:data/errors/app_error.dart'; -import 'package:data/extensions/string_extensions.dart'; -import 'package:data/service/user/user_service.dart'; -import 'package:data/utils/constant/firestore_constant.dart'; -import 'package:data/utils/dummy_deactivated_account.dart'; +import '../../api/team/team_model.dart'; +import '../../api/user/user_models.dart'; +import '../../errors/app_error.dart'; +import '../../extensions/string_extensions.dart'; +import '../user/user_service.dart'; +import '../../utils/constant/firestore_constant.dart'; +import '../../utils/dummy_deactivated_account.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../../storage/app_preferences.dart'; @@ -32,15 +32,17 @@ class TeamService { CollectionReference get _teamsCollection => firestore.collection(FireStoreConst.teamsCollection).withConverter( - fromFirestore: TeamModel.fromFireStore, - toFirestore: (TeamModel team, _) => team.toJson()); + fromFirestore: TeamModel.fromFireStore, + toFirestore: (TeamModel team, _) => team.toJson(), + ); Future getTeamById(String teamId) async { try { final teamDoc = await _teamsCollection.doc(teamId).get(); final team = teamDoc.data(); final users = await getMemberListFromUserIds( - team?.players.map((e) => e.id).toList() ?? []); + team?.players.map((e) => e.id).toList() ?? [], + ); final players = team?.players.map((player) { final user = users.firstWhere((element) => element.id == player.id); @@ -59,7 +61,8 @@ class TeamService { final team = teamDoc.data(); final users = await getMemberListFromUserIds( - team?.players.map((e) => e.id).toList() ?? []); + team?.players.map((e) => e.id).toList() ?? [], + ); final players = team?.players.map((player) { final user = users.firstWhere((element) => element.id == player.id); @@ -76,24 +79,28 @@ class TeamService { return Stream.value([]); } return _teamsCollection.snapshots().asyncMap((snapshot) async { - final teams = await Future.wait(snapshot.docs.map((mainDoc) async { - final team = mainDoc.data(); - final isUserInTeam = - team.players.any((element) => element.id == _currentUserId); - if (isUserInTeam) { - final users = await getMemberListFromUserIds( - team.players.map((e) => e.id).toList()); - - final players = team.players.map((player) { - final user = users.firstWhere((element) => element.id == player.id); - return player.copyWith(user: user); - }).toList(); - - return team.copyWith(players: players); - } else { - return null; - } - })); + final teams = await Future.wait( + snapshot.docs.map((mainDoc) async { + final team = mainDoc.data(); + final isUserInTeam = + team.players.any((element) => element.id == _currentUserId); + if (isUserInTeam) { + final users = await getMemberListFromUserIds( + team.players.map((e) => e.id).toList(), + ); + + final players = team.players.map((player) { + final user = + users.firstWhere((element) => element.id == player.id); + return player.copyWith(user: user); + }).toList(); + + return team.copyWith(players: players); + } else { + return null; + } + }), + ); return teams.whereType().toList(); }).handleError((error, stack) => throw AppError.fromError(error, stack)); } @@ -103,19 +110,22 @@ class TeamService { .where(FireStoreConst.createdBy, isEqualTo: _currentUserId) .snapshots() .asyncMap((snapshot) async { - return await Future.wait(snapshot.docs.map((mainDoc) async { - final team = mainDoc.data(); + return await Future.wait( + snapshot.docs.map((mainDoc) async { + final team = mainDoc.data(); - final users = await getMemberListFromUserIds( - team.players.map((e) => e.id).toList()); + final users = await getMemberListFromUserIds( + team.players.map((e) => e.id).toList(), + ); - final players = team.players.map((player) { - final user = users.firstWhere((element) => element.id == player.id); - return player.copyWith(user: user); - }).toList(); + final players = team.players.map((player) { + final user = users.firstWhere((element) => element.id == player.id); + return player.copyWith(user: user); + }).toList(); - return team.copyWith(players: players); - }).toList()); + return team.copyWith(players: players); + }).toList(), + ); }).handleError((error, stack) => throw AppError.fromError(error, stack)); } @@ -144,7 +154,7 @@ class TeamService { try { await _teamsCollection.doc(teamId).update({ FireStoreConst.players: - FieldValue.arrayUnion(players.map((e) => e.toJson()).toList()) + FieldValue.arrayUnion(players.map((e) => e.toJson()).toList()), }); } catch (error, stack) { throw AppError.fromError(error, stack); @@ -152,17 +162,22 @@ class TeamService { } Future editPlayersToTeam( - String teamId, List players) async { + String teamId, + List players, + ) async { try { await _teamsCollection.doc(teamId).update( - {FireStoreConst.players: players.map((e) => e.toJson()).toList()}); + {FireStoreConst.players: players.map((e) => e.toJson()).toList()}, + ); } catch (error, stack) { throw AppError.fromError(error, stack); } } Future removePlayersFromTeam( - String teamId, List players) async { + String teamId, + List players, + ) async { try { final teamRef = _teamsCollection.doc(teamId); await teamRef @@ -174,9 +189,11 @@ class TeamService { Future isTeamNameAvailable(String teamName) async { try { - QuerySnapshot teamSnap = await _teamsCollection - .where(FireStoreConst.nameLowercase, - isEqualTo: teamName.caseAndSpaceInsensitive) + final QuerySnapshot teamSnap = await _teamsCollection + .where( + FireStoreConst.nameLowercase, + isEqualTo: teamName.caseAndSpaceInsensitive, + ) .get(); return teamSnap.docs.isEmpty; @@ -188,19 +205,24 @@ class TeamService { Future> searchTeam(String searchKey) async { try { final snapshot = await _teamsCollection - .where(FireStoreConst.nameLowercase, - isGreaterThanOrEqualTo: searchKey.caseAndSpaceInsensitive) - .where(FireStoreConst.nameLowercase, - isLessThan: '${searchKey.caseAndSpaceInsensitive}z') + .where( + FireStoreConst.nameLowercase, + isGreaterThanOrEqualTo: searchKey.caseAndSpaceInsensitive, + ) + .where( + FireStoreConst.nameLowercase, + isLessThan: '${searchKey.caseAndSpaceInsensitive}z', + ) .get(); - List teams = []; + final List teams = []; for (final mainDoc in snapshot.docs) { final team = mainDoc.data(); final users = await getMemberListFromUserIds( - team.players.map((e) => e.id).toList()); + team.players.map((e) => e.id).toList(), + ); final players = team.players.map((player) { final user = users.firstWhere((element) => element.id == player.id); diff --git a/data/lib/utils/dummy_deactivated_account.dart b/data/lib/utils/dummy_deactivated_account.dart index 5ce058e6..83becd43 100644 --- a/data/lib/utils/dummy_deactivated_account.dart +++ b/data/lib/utils/dummy_deactivated_account.dart @@ -1,20 +1,22 @@ -import 'package:data/api/team/team_model.dart'; -import 'package:data/api/user/user_models.dart'; +import '../api/team/team_model.dart'; +import '../api/user/user_models.dart'; UserModel deActiveDummyUserAccount(String id) { return UserModel( - id: id, - name: 'Deactivated User', - created_at: DateTime(1950), - location: '--', - isActive: false); + id: id, + name: 'Deactivated User', + created_at: DateTime(1950), + location: '--', + isActive: false, + ); } TeamModel deActiveDummyTeamModel(String id) { return TeamModel( - id: id, - name: 'Deactivated Team', - name_lowercase: 'deactivatedteam', - created_at: DateTime(1950), - city: '--'); + id: id, + name: 'Deactivated Team', + name_lowercase: 'deactivatedteam', + created_at: DateTime(1950), + city: '--', + ); } From 8d2a9171bbcbdca31fb0d5bc09662ea341997611 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 13 Aug 2024 17:27:40 +0530 Subject: [PATCH 06/20] Fix lint --- data/lib/api/match/match_model.dart | 4 +- data/lib/errors/app_error.dart | 54 ++++++++++------- data/lib/extensions/double_extensions.dart | 8 +-- data/lib/extensions/int_extensions.dart | 4 +- data/lib/service/innings/inning_service.dart | 7 ++- data/lib/service/user/user_service.dart | 63 ++++++++++++-------- 6 files changed, 81 insertions(+), 59 deletions(-) diff --git a/data/lib/api/match/match_model.dart b/data/lib/api/match/match_model.dart index 3e172e2b..9015b0a7 100644 --- a/data/lib/api/match/match_model.dart +++ b/data/lib/api/match/match_model.dart @@ -1,8 +1,8 @@ // ignore_for_file: non_constant_identifier_names import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/team/team_model.dart'; -import 'package:data/api/user/user_models.dart'; +import '../team/team_model.dart'; +import '../user/user_models.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'match_model.freezed.dart'; diff --git a/data/lib/errors/app_error.dart b/data/lib/errors/app_error.dart index 81059974..6af91914 100644 --- a/data/lib/errors/app_error.dart +++ b/data/lib/errors/app_error.dart @@ -1,6 +1,6 @@ import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/errors/app_error_l10n_codes.dart'; +import 'app_error_l10n_codes.dart'; import 'package:firebase_auth/firebase_auth.dart'; import '../utils/constant/firebase_error_constant.dart'; @@ -32,7 +32,9 @@ class AppError implements Exception { return _handleFirebaseError(error); } else if (error is TypeError) { return SomethingWentWrongError( - message: error.toString(), stackTrace: error.stackTrace); + message: error.toString(), + stackTrace: error.stackTrace, + ); } else if (error is LargeAttachmentUploadError) { return const LargeAttachmentUploadError(); } else { @@ -44,31 +46,35 @@ class AppError implements Exception { switch (error.code) { case errorInvalidVerificationCode: return AppError( - statusCode: error.code, - message: error.message, - l10nCode: AppErrorL10nCodes.invalidVerificationCode, - stackTrace: error.stackTrace); + statusCode: error.code, + message: error.message, + l10nCode: AppErrorL10nCodes.invalidVerificationCode, + stackTrace: error.stackTrace, + ); case errorTooManyRequest: return AppError( - statusCode: error.code, - message: error.message, - l10nCode: AppErrorL10nCodes.tooManyRequests, - stackTrace: error.stackTrace); + statusCode: error.code, + message: error.message, + l10nCode: AppErrorL10nCodes.tooManyRequests, + stackTrace: error.stackTrace, + ); case errorInvalidPhoneNumber: return AppError( - statusCode: error.code, - message: error.message, - l10nCode: AppErrorL10nCodes.invalidPhoneNumber, - stackTrace: error.stackTrace); + statusCode: error.code, + message: error.message, + l10nCode: AppErrorL10nCodes.invalidPhoneNumber, + stackTrace: error.stackTrace, + ); case errorNetworkRequestFailed: return const NoConnectionError(); case errorRequiresRecentLogin: return const RequiresRecentLoginError(); default: return SomethingWentWrongError( - statusCode: error.code, - message: error.message, - stackTrace: error.stackTrace); + statusCode: error.code, + message: error.message, + stackTrace: error.stackTrace, + ); } } } @@ -76,9 +82,10 @@ class AppError implements Exception { class NoConnectionError extends AppError { const NoConnectionError() : super( - l10nCode: AppErrorL10nCodes.noInternetConnection, - message: - "No internet connection. Please check your network and try again."); + l10nCode: AppErrorL10nCodes.noInternetConnection, + message: + "No internet connection. Please check your network and try again.", + ); } class SomethingWentWrongError extends AppError { @@ -92,9 +99,10 @@ class SomethingWentWrongError extends AppError { class LargeAttachmentUploadError extends AppError { const LargeAttachmentUploadError() : super( - l10nCode: AppErrorL10nCodes.largeAttachmentUpload, - message: - "Oops! Your file exceeds the maximum allowed size of 25 MB. Please choose a smaller file and try again."); + l10nCode: AppErrorL10nCodes.largeAttachmentUpload, + message: + "Oops! Your file exceeds the maximum allowed size of 25 MB. Please choose a smaller file and try again.", + ); } class RequiresRecentLoginError extends AppError { diff --git a/data/lib/extensions/double_extensions.dart b/data/lib/extensions/double_extensions.dart index 0feef681..86aae3d0 100644 --- a/data/lib/extensions/double_extensions.dart +++ b/data/lib/extensions/double_extensions.dart @@ -1,8 +1,8 @@ -import 'package:data/extensions/int_extensions.dart'; +import 'int_extensions.dart'; extension OverExtensionOnDouble on double { double add(int ballsToAdd) { - int totalBalls = toBalls() + ballsToAdd; + final int totalBalls = toBalls() + ballsToAdd; return totalBalls.toOvers(); } @@ -13,9 +13,9 @@ extension OverExtensionOnDouble on double { } int getBallNumberFromOver() { - String valueString = toString(); + final String valueString = toString(); - List parts = valueString.split('.'); + final List parts = valueString.split('.'); if (parts.length > 1) { return int.parse(parts[1]); diff --git a/data/lib/extensions/int_extensions.dart b/data/lib/extensions/int_extensions.dart index f81a4c29..6e2d567c 100644 --- a/data/lib/extensions/int_extensions.dart +++ b/data/lib/extensions/int_extensions.dart @@ -1,7 +1,7 @@ extension OverExtensionOnInt on int { double toOvers() { - int overs = this ~/ 6; - int additionalBalls = this % 6; + final int overs = this ~/ 6; + final int additionalBalls = this % 6; return double.parse("$overs.$additionalBalls"); } } diff --git a/data/lib/service/innings/inning_service.dart b/data/lib/service/innings/inning_service.dart index c203c3ee..7050eab3 100644 --- a/data/lib/service/innings/inning_service.dart +++ b/data/lib/service/innings/inning_service.dart @@ -20,8 +20,9 @@ class InningsService { : _inningCollection = _firestore .collection(FireStoreConst.inningsCollection) .withConverter( - fromFirestore: InningModel.fromFireStore, - toFirestore: (InningModel inning, _) => inning.toJson()); + fromFirestore: InningModel.fromFireStore, + toFirestore: (InningModel inning, _) => inning.toJson(), + ); Future createInnings({ required String matchId, @@ -96,7 +97,7 @@ class InningsService { transaction.update(batInningRef, battingUpdates); final Map bowlingUpdates = { - FireStoreConst.totalWickets: wicketCount + FireStoreConst.totalWickets: wicketCount, }; if (runs != null) bowlingUpdates.addAll({FireStoreConst.totalRuns: runs}); diff --git a/data/lib/service/user/user_service.dart b/data/lib/service/user/user_service.dart index d5e1956f..f3887833 100644 --- a/data/lib/service/user/user_service.dart +++ b/data/lib/service/user/user_service.dart @@ -1,16 +1,19 @@ import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/errors/app_error.dart'; -import 'package:data/extensions/list_extensions.dart'; -import 'package:data/utils/constant/firestore_constant.dart'; -import 'package:data/utils/dummy_deactivated_account.dart'; +import '../../errors/app_error.dart'; +import '../../extensions/list_extensions.dart'; +import '../../utils/constant/firestore_constant.dart'; +import '../../utils/dummy_deactivated_account.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../api/user/user_models.dart'; import '../../storage/app_preferences.dart'; final userServiceProvider = Provider((ref) { - final service = UserService(ref.read(currentUserPod), - ref.read(currentUserJsonPod.notifier), FirebaseFirestore.instance); + final service = UserService( + ref.read(currentUserPod), + ref.read(currentUserJsonPod.notifier), + FirebaseFirestore.instance, + ); ref.listen(currentUserPod, (_, next) => service._currentUser = next); return service; @@ -24,17 +27,19 @@ class UserService { final CollectionReference _userCollection; UserService( - this._currentUser, this._currentUserJsonController, this.firestore) - : _userCollection = firestore - .collection(FireStoreConst.usersCollection) - .withConverter( - fromFirestore: UserModel.fromFireStore, - toFirestore: (UserModel user, _) => user.toJson()); + this._currentUser, + this._currentUserJsonController, + this.firestore, + ) : _userCollection = + firestore.collection(FireStoreConst.usersCollection).withConverter( + fromFirestore: UserModel.fromFireStore, + toFirestore: (UserModel user, _) => user.toJson(), + ); Future getUser(String id) async { try { final snapshot = await _userCollection.doc(id).get(); - var userModel = snapshot.data(); + final userModel = snapshot.data(); _currentUserJsonController.state = userModel?.toJsonString(); } catch (error, stack) { throw AppError.fromError(error, stack); @@ -65,7 +70,7 @@ class UserService { Future getUserById(String id) async { try { final snapshot = await _userCollection.doc(id).get(); - var userModel = snapshot.data(); + final userModel = snapshot.data(); if (userModel == null) { return deActiveDummyUserAccount(id); } @@ -76,22 +81,26 @@ class UserService { } Future> getUsersByIds(List ids) async { - List users = []; + final List users = []; try { for (final tenIds in ids.chunked(10)) { final snapshot = await _userCollection .where(FireStoreConst.id, whereIn: tenIds) .get(); - users.addAll(snapshot.docs.map((doc) { - return doc.data(); - }).toList()); + users.addAll( + snapshot.docs.map((doc) { + return doc.data(); + }).toList(), + ); final deactivatedUserIds = tenIds.where((id) => !users.map((user) => user.id).contains(id)); - users.addAll(deactivatedUserIds.map( - (id) => deActiveDummyUserAccount(id), - )); + users.addAll( + deactivatedUserIds.map( + (id) => deActiveDummyUserAccount(id), + ), + ); } return users; @@ -103,10 +112,14 @@ class UserService { Future> searchUser(String searchKey) async { try { final snapshot = await _userCollection - .where(FireStoreConst.nameLowercase, - isGreaterThanOrEqualTo: searchKey.toLowerCase()) - .where(FireStoreConst.nameLowercase, - isLessThan: '${searchKey.toLowerCase()}z') + .where( + FireStoreConst.nameLowercase, + isGreaterThanOrEqualTo: searchKey.toLowerCase(), + ) + .where( + FireStoreConst.nameLowercase, + isLessThan: '${searchKey.toLowerCase()}z', + ) .get(); return snapshot.docs.map((doc) { From 40028c41b5ae179d7c12379adeaf03a12a6a5a8a Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 13 Aug 2024 17:33:56 +0530 Subject: [PATCH 07/20] Fix lint --- .../flow/team/detail/make_admin/make_team_admin_screen.dart | 4 ++-- .../team/detail/make_admin/make_team_admin_view_model.dart | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart index 653e7b9b..4fd4cd66 100644 --- a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart @@ -105,9 +105,9 @@ class _MakeAdminScreenState extends ConsumerState { onTap: (_) => notifier.selectAdmin(player), ), ) - : SizedBox(); + : const SizedBox(); }, - separatorBuilder: (context, index) => SizedBox(height: 16), + separatorBuilder: (context, index) => const SizedBox(height: 16), ); } } diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart index b216a149..d3f64ef6 100644 --- a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart @@ -13,7 +13,8 @@ final makeTeamAdminStateProvider = StateNotifierProvider.autoDispose< class MakeTeamAdminViewNotifier extends StateNotifier { final TeamService _teamService; - MakeTeamAdminViewNotifier(this._teamService) : super(MakeTeamAdminState()); + MakeTeamAdminViewNotifier(this._teamService) + : super(const MakeTeamAdminState()); late String _teamId; late List _players; From 9768374fe3e1d1e929b8ae762b2514c543ad9194 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 20 Aug 2024 14:23:25 +0530 Subject: [PATCH 08/20] Refactor player flow --- data/lib/api/team/team_model.dart | 2 ++ data/lib/api/team/team_model.freezed.dart | 10 +++++++--- data/lib/api/team/team_model.g.dart | 4 ++-- data/lib/service/team/team_service.dart | 4 ++-- data/lib/utils/constant/firestore_constant.dart | 1 + 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/data/lib/api/team/team_model.dart b/data/lib/api/team/team_model.dart index c86f94ab..9e70ce10 100644 --- a/data/lib/api/team/team_model.dart +++ b/data/lib/api/team/team_model.dart @@ -1,6 +1,7 @@ // ignore_for_file: non_constant_identifier_names import 'package:cloud_firestore/cloud_firestore.dart'; +import '../../utils/constant/firestore_constant.dart'; import '../user/user_models.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -19,6 +20,7 @@ abstract class TeamModel with _$TeamModel { String? profile_img_url, String? created_by, DateTime? created_at, + @JsonKey(name: FireStoreConst.teamPlayers) @Default([]) List players, }) = _TeamModel; diff --git a/data/lib/api/team/team_model.freezed.dart b/data/lib/api/team/team_model.freezed.dart index acf14ae0..05847672 100644 --- a/data/lib/api/team/team_model.freezed.dart +++ b/data/lib/api/team/team_model.freezed.dart @@ -27,6 +27,7 @@ mixin _$TeamModel { String? get profile_img_url => throw _privateConstructorUsedError; String? get created_by => throw _privateConstructorUsedError; DateTime? get created_at => throw _privateConstructorUsedError; + @JsonKey(name: FireStoreConst.teamPlayers) List get players => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -48,7 +49,7 @@ abstract class $TeamModelCopyWith<$Res> { String? profile_img_url, String? created_by, DateTime? created_at, - List players}); + @JsonKey(name: FireStoreConst.teamPlayers) List players}); } /// @nodoc @@ -126,7 +127,7 @@ abstract class _$$TeamModelImplCopyWith<$Res> String? profile_img_url, String? created_by, DateTime? created_at, - List players}); + @JsonKey(name: FireStoreConst.teamPlayers) List players}); } /// @nodoc @@ -198,6 +199,7 @@ class _$TeamModelImpl implements _TeamModel { this.profile_img_url, this.created_by, this.created_at, + @JsonKey(name: FireStoreConst.teamPlayers) final List players = const []}) : _players = players; @@ -220,7 +222,7 @@ class _$TeamModelImpl implements _TeamModel { final DateTime? created_at; final List _players; @override - @JsonKey() + @JsonKey(name: FireStoreConst.teamPlayers) List get players { if (_players is EqualUnmodifiableListView) return _players; // ignore: implicit_dynamic_type @@ -287,6 +289,7 @@ abstract class _TeamModel implements TeamModel { final String? profile_img_url, final String? created_by, final DateTime? created_at, + @JsonKey(name: FireStoreConst.teamPlayers) final List players}) = _$TeamModelImpl; factory _TeamModel.fromJson(Map json) = @@ -307,6 +310,7 @@ abstract class _TeamModel implements TeamModel { @override DateTime? get created_at; @override + @JsonKey(name: FireStoreConst.teamPlayers) List get players; @override @JsonKey(ignore: true) diff --git a/data/lib/api/team/team_model.g.dart b/data/lib/api/team/team_model.g.dart index 91f9992e..59b5570e 100644 --- a/data/lib/api/team/team_model.g.dart +++ b/data/lib/api/team/team_model.g.dart @@ -17,7 +17,7 @@ _$TeamModelImpl _$$TeamModelImplFromJson(Map json) => created_at: json['created_at'] == null ? null : DateTime.parse(json['created_at'] as String), - players: (json['players'] as List?) + players: (json['team_players'] as List?) ?.map((e) => TeamPlayer.fromJson(e as Map)) .toList() ?? const [], @@ -32,7 +32,7 @@ Map _$$TeamModelImplToJson(_$TeamModelImpl instance) => 'profile_img_url': instance.profile_img_url, 'created_by': instance.created_by, 'created_at': instance.created_at?.toIso8601String(), - 'players': instance.players.map((e) => e.toJson()).toList(), + 'team_players': instance.players.map((e) => e.toJson()).toList(), }; _$TeamPlayerImpl _$$TeamPlayerImplFromJson(Map json) => diff --git a/data/lib/service/team/team_service.dart b/data/lib/service/team/team_service.dart index 0610615d..4be80ede 100644 --- a/data/lib/service/team/team_service.dart +++ b/data/lib/service/team/team_service.dart @@ -153,7 +153,7 @@ class TeamService { Future addPlayersToTeam(String teamId, List players) async { try { await _teamsCollection.doc(teamId).update({ - FireStoreConst.players: + FireStoreConst.teamPlayers: FieldValue.arrayUnion(players.map((e) => e.toJson()).toList()), }); } catch (error, stack) { @@ -167,7 +167,7 @@ class TeamService { ) async { try { await _teamsCollection.doc(teamId).update( - {FireStoreConst.players: players.map((e) => e.toJson()).toList()}, + {FireStoreConst.teamPlayers: players.map((e) => e.toJson()).toList()}, ); } catch (error, stack) { throw AppError.fromError(error, stack); diff --git a/data/lib/utils/constant/firestore_constant.dart b/data/lib/utils/constant/firestore_constant.dart index cee197bc..45970726 100644 --- a/data/lib/utils/constant/firestore_constant.dart +++ b/data/lib/utils/constant/firestore_constant.dart @@ -38,6 +38,7 @@ class FireStoreConst { // teams field const static const String players = "players"; + static const String teamPlayers = "team_players"; static const String createdBy = "created_by"; static const String nameLowercase = "name_lowercase"; static const String profileImageUrl = "profile_img_url"; From 41e37edaecf0ae9cffc81cfe9cf4e7cb9477a185 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 20 Aug 2024 15:17:54 +0530 Subject: [PATCH 09/20] minor refactor --- data/lib/api/match/match_model.dart | 2 +- data/lib/api/match/match_model.freezed.dart | 28 ++++++++++--------- data/lib/api/match/match_model.g.dart | 5 ++-- .../matches/add_match/add_match_screen.dart | 1 + .../match_detail_highlight_view.dart | 2 ++ khelo/lib/ui/flow/team/team_list_screen.dart | 1 + 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/data/lib/api/match/match_model.dart b/data/lib/api/match/match_model.dart index 9015b0a7..049c0b82 100644 --- a/data/lib/api/match/match_model.dart +++ b/data/lib/api/match/match_model.dart @@ -129,7 +129,7 @@ class MatchResult { class MatchPlayer with _$MatchPlayer { const factory MatchPlayer({ required UserModel player, - PlayerStatus? status, + @Default(PlayerStatus.yetToPlay) PlayerStatus status, int? index, }) = _MatchPlayer; diff --git a/data/lib/api/match/match_model.freezed.dart b/data/lib/api/match/match_model.freezed.dart index e22c931a..45b2c206 100644 --- a/data/lib/api/match/match_model.freezed.dart +++ b/data/lib/api/match/match_model.freezed.dart @@ -1075,7 +1075,7 @@ MatchPlayer _$MatchPlayerFromJson(Map json) { /// @nodoc mixin _$MatchPlayer { UserModel get player => throw _privateConstructorUsedError; - PlayerStatus? get status => throw _privateConstructorUsedError; + PlayerStatus get status => throw _privateConstructorUsedError; int? get index => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -1090,7 +1090,7 @@ abstract class $MatchPlayerCopyWith<$Res> { MatchPlayer value, $Res Function(MatchPlayer) then) = _$MatchPlayerCopyWithImpl<$Res, MatchPlayer>; @useResult - $Res call({UserModel player, PlayerStatus? status, int? index}); + $Res call({UserModel player, PlayerStatus status, int? index}); $UserModelCopyWith<$Res> get player; } @@ -1109,7 +1109,7 @@ class _$MatchPlayerCopyWithImpl<$Res, $Val extends MatchPlayer> @override $Res call({ Object? player = null, - Object? status = freezed, + Object? status = null, Object? index = freezed, }) { return _then(_value.copyWith( @@ -1117,10 +1117,10 @@ class _$MatchPlayerCopyWithImpl<$Res, $Val extends MatchPlayer> ? _value.player : player // ignore: cast_nullable_to_non_nullable as UserModel, - status: freezed == status + status: null == status ? _value.status : status // ignore: cast_nullable_to_non_nullable - as PlayerStatus?, + as PlayerStatus, index: freezed == index ? _value.index : index // ignore: cast_nullable_to_non_nullable @@ -1145,7 +1145,7 @@ abstract class _$$MatchPlayerImplCopyWith<$Res> __$$MatchPlayerImplCopyWithImpl<$Res>; @override @useResult - $Res call({UserModel player, PlayerStatus? status, int? index}); + $Res call({UserModel player, PlayerStatus status, int? index}); @override $UserModelCopyWith<$Res> get player; @@ -1163,7 +1163,7 @@ class __$$MatchPlayerImplCopyWithImpl<$Res> @override $Res call({ Object? player = null, - Object? status = freezed, + Object? status = null, Object? index = freezed, }) { return _then(_$MatchPlayerImpl( @@ -1171,10 +1171,10 @@ class __$$MatchPlayerImplCopyWithImpl<$Res> ? _value.player : player // ignore: cast_nullable_to_non_nullable as UserModel, - status: freezed == status + status: null == status ? _value.status : status // ignore: cast_nullable_to_non_nullable - as PlayerStatus?, + as PlayerStatus, index: freezed == index ? _value.index : index // ignore: cast_nullable_to_non_nullable @@ -1186,7 +1186,8 @@ class __$$MatchPlayerImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$MatchPlayerImpl implements _MatchPlayer { - const _$MatchPlayerImpl({required this.player, this.status, this.index}); + const _$MatchPlayerImpl( + {required this.player, this.status = PlayerStatus.yetToPlay, this.index}); factory _$MatchPlayerImpl.fromJson(Map json) => _$$MatchPlayerImplFromJson(json); @@ -1194,7 +1195,8 @@ class _$MatchPlayerImpl implements _MatchPlayer { @override final UserModel player; @override - final PlayerStatus? status; + @JsonKey() + final PlayerStatus status; @override final int? index; @@ -1234,7 +1236,7 @@ class _$MatchPlayerImpl implements _MatchPlayer { abstract class _MatchPlayer implements MatchPlayer { const factory _MatchPlayer( {required final UserModel player, - final PlayerStatus? status, + final PlayerStatus status, final int? index}) = _$MatchPlayerImpl; factory _MatchPlayer.fromJson(Map json) = @@ -1243,7 +1245,7 @@ abstract class _MatchPlayer implements MatchPlayer { @override UserModel get player; @override - PlayerStatus? get status; + PlayerStatus get status; @override int? get index; @override diff --git a/data/lib/api/match/match_model.g.dart b/data/lib/api/match/match_model.g.dart index ce688372..0a64f336 100644 --- a/data/lib/api/match/match_model.g.dart +++ b/data/lib/api/match/match_model.g.dart @@ -156,14 +156,15 @@ Map _$$MatchTeamModelImplToJson( _$MatchPlayerImpl _$$MatchPlayerImplFromJson(Map json) => _$MatchPlayerImpl( player: UserModel.fromJson(json['player'] as Map), - status: $enumDecodeNullable(_$PlayerStatusEnumMap, json['status']), + status: $enumDecodeNullable(_$PlayerStatusEnumMap, json['status']) ?? + PlayerStatus.yetToPlay, index: (json['index'] as num?)?.toInt(), ); Map _$$MatchPlayerImplToJson(_$MatchPlayerImpl instance) => { 'player': instance.player, - 'status': _$PlayerStatusEnumMap[instance.status], + 'status': _$PlayerStatusEnumMap[instance.status]!, 'index': instance.index, }; diff --git a/khelo/lib/ui/flow/matches/add_match/add_match_screen.dart b/khelo/lib/ui/flow/matches/add_match/add_match_screen.dart index ffdee690..b8069430 100644 --- a/khelo/lib/ui/flow/matches/add_match/add_match_screen.dart +++ b/khelo/lib/ui/flow/matches/add_match/add_match_screen.dart @@ -208,6 +208,7 @@ class _AddMatchScreenState extends ConsumerState { items: MatchType.values .map((type) => BottomSheetAction( title: type.getString(context), + enabled: state.matchType != type, child: showCheckMark( context, showCheck: state.matchType == type, 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 bf0d96bd..4acaef09 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 @@ -180,6 +180,7 @@ class MatchDetailHighlightView extends ConsumerWidget { items: HighlightFilterOption.values .map((option) => BottomSheetAction( title: option.getString(context), + enabled: highlightFilterOption != option, child: _checkWidget( context, isShowCheck: highlightFilterOption == option, @@ -203,6 +204,7 @@ class MatchDetailHighlightView extends ConsumerWidget { items: teams ?.map((match) => BottomSheetAction( title: match.team.name, + enabled: highlightTeamId != match.team.id, child: _checkWidget( context, isShowCheck: highlightTeamId == match.team.id, diff --git a/khelo/lib/ui/flow/team/team_list_screen.dart b/khelo/lib/ui/flow/team/team_list_screen.dart index c445a7db..5ae76c1e 100644 --- a/khelo/lib/ui/flow/team/team_list_screen.dart +++ b/khelo/lib/ui/flow/team/team_list_screen.dart @@ -173,6 +173,7 @@ class _TeamListScreenState extends ConsumerState items: TeamFilterOption.values .map((option) => BottomSheetAction( title: option.getString(context), + enabled: selectedFilter != option, child: selectedFilter == option ? SvgPicture.asset( Assets.images.icCheck, From 86d41cca98aef886306b955d76c414d637fc7834 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Tue, 20 Aug 2024 15:29:48 +0530 Subject: [PATCH 10/20] Fix lint --- .../ui/flow/matches/add_match/add_match_view_model.dart | 8 ++------ khelo/lib/ui/flow/score_board/score_board_view_model.dart | 6 ++---- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart b/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart index 4173d9e4..e6953e28 100644 --- a/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart +++ b/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart @@ -140,16 +140,12 @@ class AddMatchViewNotifier extends StateNotifier { final firstSquad = state.squadA ?.map((e) => MatchPlayerRequest( - id: e.player.id, - status: e.status ?? PlayerStatus.yetToPlay, - index: e.index)) + id: e.player.id, status: e.status, index: e.index)) .toList() ?? []; final secondSquad = state.squadB ?.map((e) => MatchPlayerRequest( - id: e.player.id, - status: e.status ?? PlayerStatus.yetToPlay, - index: e.index)) + id: e.player.id, status: e.status, index: e.index)) .toList() ?? []; final allPlayers = firstSquad.map((e) => e.id).toList(); 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 4d77f482..1abd65ba 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 @@ -585,7 +585,7 @@ class ScoreBoardViewNotifier extends StateNotifier { return MatchPlayerRequest( id: updatedPlayer.player.id, - status: updatedPlayer.status ?? PlayerStatus.played, + status: updatedPlayer.status, index: updatedPlayer.index); } @@ -834,9 +834,7 @@ class ScoreBoardViewNotifier extends StateNotifier { team_id: team.teamId, squad: team.players .map((e) => MatchPlayerRequest( - id: e.player.id, - status: e.status ?? PlayerStatus.yetToPlay, - index: e.index)) + id: e.player.id, status: e.status, index: e.index)) .toList()); await _matchService.updateTeamsSquad( From 9dc167dcc6daf8e1b46bf9e9da96a847e683adf5 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Thu, 22 Aug 2024 12:02:27 +0530 Subject: [PATCH 11/20] Mr changes --- data/lib/api/team/team_model.dart | 7 +- data/lib/api/team/team_model.freezed.dart | 39 ++++---- data/lib/service/team/team_service.dart | 60 +++++++----- khelo/assets/locales/app_en.arb | 9 +- khelo/lib/components/user_detail_cell.dart | 71 +++++++------- khelo/lib/ui/app_route.dart | 10 +- .../add_match/add_match_view_model.dart | 7 +- .../select_squad/select_squad_screen.dart | 4 +- .../components/match_detail_squad_view.dart | 8 +- .../flow/team/add_team/add_team_screen.dart | 8 +- .../team/add_team/add_team_view_model.dart | 2 +- .../add_team_member_screen.dart | 4 +- .../team_detail_member_content.dart | 2 +- .../make_admin/make_team_admin_screen.dart | 93 +++++++++++-------- .../make_team_admin_view_model.dart | 18 ++-- .../flow/team/detail/team_detail_screen.dart | 7 +- .../components/team_member_sheet.dart | 12 +-- .../search_team/search_team_view_model.dart | 6 +- .../ui/flow/team/team_list_view_model.dart | 11 ++- 19 files changed, 205 insertions(+), 173 deletions(-) diff --git a/data/lib/api/team/team_model.dart b/data/lib/api/team/team_model.dart index 9e70ce10..e4f2d416 100644 --- a/data/lib/api/team/team_model.dart +++ b/data/lib/api/team/team_model.dart @@ -21,7 +21,8 @@ abstract class TeamModel with _$TeamModel { String? created_by, DateTime? created_at, @JsonKey(name: FireStoreConst.teamPlayers) - @Default([]) List players, + @Default([]) + List players, }) = _TeamModel; factory TeamModel.fromJson(Map json) => @@ -49,7 +50,9 @@ class TeamPlayer with _$TeamPlayer { const factory TeamPlayer({ required String id, @Default(TeamPlayerRole.player) TeamPlayerRole role, - @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user, + @JsonKey(includeToJson: false, includeFromJson: false) + @Default(UserModel(id: '')) + UserModel user, }) = _TeamPlayer; factory TeamPlayer.fromJson(Map json) => diff --git a/data/lib/api/team/team_model.freezed.dart b/data/lib/api/team/team_model.freezed.dart index 05847672..af769738 100644 --- a/data/lib/api/team/team_model.freezed.dart +++ b/data/lib/api/team/team_model.freezed.dart @@ -327,7 +327,7 @@ mixin _$TeamPlayer { String get id => throw _privateConstructorUsedError; TeamPlayerRole get role => throw _privateConstructorUsedError; @JsonKey(includeToJson: false, includeFromJson: false) - UserModel? get user => throw _privateConstructorUsedError; + UserModel get user => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -344,9 +344,9 @@ abstract class $TeamPlayerCopyWith<$Res> { $Res call( {String id, TeamPlayerRole role, - @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user}); + @JsonKey(includeToJson: false, includeFromJson: false) UserModel user}); - $UserModelCopyWith<$Res>? get user; + $UserModelCopyWith<$Res> get user; } /// @nodoc @@ -364,7 +364,7 @@ class _$TeamPlayerCopyWithImpl<$Res, $Val extends TeamPlayer> $Res call({ Object? id = null, Object? role = null, - Object? user = freezed, + Object? user = null, }) { return _then(_value.copyWith( id: null == id @@ -375,21 +375,17 @@ class _$TeamPlayerCopyWithImpl<$Res, $Val extends TeamPlayer> ? _value.role : role // ignore: cast_nullable_to_non_nullable as TeamPlayerRole, - user: freezed == user + user: null == user ? _value.user : user // ignore: cast_nullable_to_non_nullable - as UserModel?, + as UserModel, ) as $Val); } @override @pragma('vm:prefer-inline') - $UserModelCopyWith<$Res>? get user { - if (_value.user == null) { - return null; - } - - return $UserModelCopyWith<$Res>(_value.user!, (value) { + $UserModelCopyWith<$Res> get user { + return $UserModelCopyWith<$Res>(_value.user, (value) { return _then(_value.copyWith(user: value) as $Val); }); } @@ -406,10 +402,10 @@ abstract class _$$TeamPlayerImplCopyWith<$Res> $Res call( {String id, TeamPlayerRole role, - @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user}); + @JsonKey(includeToJson: false, includeFromJson: false) UserModel user}); @override - $UserModelCopyWith<$Res>? get user; + $UserModelCopyWith<$Res> get user; } /// @nodoc @@ -425,7 +421,7 @@ class __$$TeamPlayerImplCopyWithImpl<$Res> $Res call({ Object? id = null, Object? role = null, - Object? user = freezed, + Object? user = null, }) { return _then(_$TeamPlayerImpl( id: null == id @@ -436,10 +432,10 @@ class __$$TeamPlayerImplCopyWithImpl<$Res> ? _value.role : role // ignore: cast_nullable_to_non_nullable as TeamPlayerRole, - user: freezed == user + user: null == user ? _value.user : user // ignore: cast_nullable_to_non_nullable - as UserModel?, + as UserModel, )); } } @@ -451,7 +447,8 @@ class _$TeamPlayerImpl implements _TeamPlayer { const _$TeamPlayerImpl( {required this.id, this.role = TeamPlayerRole.player, - @JsonKey(includeToJson: false, includeFromJson: false) this.user}); + @JsonKey(includeToJson: false, includeFromJson: false) + this.user = const UserModel(id: '')}); factory _$TeamPlayerImpl.fromJson(Map json) => _$$TeamPlayerImplFromJson(json); @@ -463,7 +460,7 @@ class _$TeamPlayerImpl implements _TeamPlayer { final TeamPlayerRole role; @override @JsonKey(includeToJson: false, includeFromJson: false) - final UserModel? user; + final UserModel user; @override String toString() { @@ -503,7 +500,7 @@ abstract class _TeamPlayer implements TeamPlayer { {required final String id, final TeamPlayerRole role, @JsonKey(includeToJson: false, includeFromJson: false) - final UserModel? user}) = _$TeamPlayerImpl; + final UserModel user}) = _$TeamPlayerImpl; factory _TeamPlayer.fromJson(Map json) = _$TeamPlayerImpl.fromJson; @@ -514,7 +511,7 @@ abstract class _TeamPlayer implements TeamPlayer { TeamPlayerRole get role; @override @JsonKey(includeToJson: false, includeFromJson: false) - UserModel? get user; + UserModel get user; @override @JsonKey(ignore: true) _$$TeamPlayerImplCopyWith<_$TeamPlayerImpl> get copyWith => diff --git a/data/lib/service/team/team_service.dart b/data/lib/service/team/team_service.dart index 4be80ede..1e1eab19 100644 --- a/data/lib/service/team/team_service.dart +++ b/data/lib/service/team/team_service.dart @@ -78,36 +78,52 @@ class TeamService { if (_currentUserId == null) { return Stream.value([]); } - return _teamsCollection.snapshots().asyncMap((snapshot) async { - final teams = await Future.wait( + final currentPlayer = TeamPlayer(id: _currentUserId ?? 'INVALID ID'); + + final playerContains = [ + currentPlayer.copyWith(role: TeamPlayerRole.admin).toJson(), + currentPlayer.copyWith(role: TeamPlayerRole.player).toJson(), + ]; + + final filter = Filter.or( + Filter(FireStoreConst.createdBy, isEqualTo: _currentUserId), + Filter(FireStoreConst.teamPlayers, arrayContainsAny: playerContains), + ); + return _teamsCollection + .where(filter) + .snapshots() + .asyncMap((snapshot) async { + return await Future.wait( snapshot.docs.map((mainDoc) async { final team = mainDoc.data(); - final isUserInTeam = - team.players.any((element) => element.id == _currentUserId); - if (isUserInTeam) { - final users = await getMemberListFromUserIds( - team.players.map((e) => e.id).toList(), - ); - - final players = team.players.map((player) { - final user = - users.firstWhere((element) => element.id == player.id); - return player.copyWith(user: user); - }).toList(); - - return team.copyWith(players: players); - } else { - return null; - } - }), + + final users = await getMemberListFromUserIds( + team.players.map((e) => e.id).toList(), + ); + + final players = team.players.map((player) { + final user = users.firstWhere((element) => element.id == player.id); + return player.copyWith(user: user); + }).toList(); + + return team.copyWith(players: players); + }).toList(), ); - return teams.whereType().toList(); }).handleError((error, stack) => throw AppError.fromError(error, stack)); } Stream> getUserOwnedTeams() { + final currentPlayer = TeamPlayer( + id: _currentUserId ?? 'INVALID ID', + role: TeamPlayerRole.admin, + ); + + final filter = Filter.or( + Filter(FireStoreConst.createdBy, isEqualTo: _currentUserId), + Filter(FireStoreConst.teamPlayers, arrayContains: currentPlayer.toJson()), + ); return _teamsCollection - .where(FireStoreConst.createdBy, isEqualTo: _currentUserId) + .where(filter) .snapshots() .asyncMap((snapshot) async { return await Future.wait( diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index f32704b5..3d31c675 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -143,6 +143,7 @@ "team_list_all_teams_title": "All teams", "team_list_created_by_me_title": "Created by me", "team_list_me_as_member_title": "Me as member", + "team_list_me_as_admin_title": "Me as admin", "team_list_no_teams_created_title": "No teams created", "team_list_empty_list_description": "Tap on the “ + ” icon to create a team", @@ -247,7 +248,13 @@ "team_detail_empty_stat_description_text": "The players are warming up! Stay tuned for exciting stats as the team progresses.", "team_detail_add_member_title": "Add member", "team_detail_make_admin": "Make admin", - "team_detail_admin": "{count} admin", + "team_detail_admin": "{count, plural, =0{{count} admins} =1{{count} admin} other{{count} admins}}", + "@team_detail_admin": { + "placeholders": { + "count": {} + } + }, + "team_detail_make_admin_owner_title": "Owner", "team_detail_match_tab_title": "Match", "team_detail_stat_tab_title": "Stat", "team_detail_won_title": "Won({win})", diff --git a/khelo/lib/components/user_detail_cell.dart b/khelo/lib/components/user_detail_cell.dart index ae328409..84182d15 100644 --- a/khelo/lib/components/user_detail_cell.dart +++ b/khelo/lib/components/user_detail_cell.dart @@ -12,6 +12,7 @@ class UserDetailCell extends StatelessWidget { final UserModel user; final Function()? onTap; final Widget? trailing; + final EdgeInsets? padding; final bool showPhoneNumber; const UserDetailCell({ @@ -19,6 +20,7 @@ class UserDetailCell extends StatelessWidget { required this.user, this.onTap, this.trailing, + this.padding, this.showPhoneNumber = true, }); @@ -27,43 +29,46 @@ class UserDetailCell extends StatelessWidget { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: user.isActive ? onTap : null, - child: Row( - children: [ - ImageAvatar( - initial: user.nameInitial, - imageUrl: user.profile_img_url, - size: 40, - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - user.name ?? context.l10n.common_anonymous_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)), - if (user.phone != null && showPhoneNumber) ...[ - const SizedBox(height: 2), + child: Padding( + padding: padding ?? EdgeInsets.zero, + child: Row( + children: [ + ImageAvatar( + initial: user.nameInitial, + imageUrl: user.profile_img_url, + size: 40, + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ Text( - user.phone - .format(context, StringFormats.obscurePhoneNumber), - style: AppTextStyle.caption - .copyWith(color: context.colorScheme.textDisabled), + user.name ?? context.l10n.common_anonymous_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)), + if (user.phone != null && showPhoneNumber) ...[ + const SizedBox(height: 2), + Text( + user.phone + .format(context, StringFormats.obscurePhoneNumber), + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + ), + ], ], - ], + ), ), - ), - trailing ?? const SizedBox() - ], + trailing ?? const SizedBox() + ], + ), ), ); } diff --git a/khelo/lib/ui/app_route.dart b/khelo/lib/ui/app_route.dart index 78698ea9..08289152 100644 --- a/khelo/lib/ui/app_route.dart +++ b/khelo/lib/ui/app_route.dart @@ -156,15 +156,9 @@ class AppRoute { builder: (_) => AddTeamScreen(editTeam: team), ); - static AppRoute makeTeamAdmin({ - required String teamId, - required List players, - }) => + static AppRoute makeTeamAdmin({required TeamModel team}) => AppRoute(pathMakeTeamAdmin, - builder: (context) => MakeTeamAdminScreen( - teamId: teamId, - players: players, - )); + builder: (context) => MakeTeamAdminScreen(team: team)); static AppRoute searchTeam( {List? excludedIds, required bool onlyUserTeams}) => diff --git a/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart b/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart index 1fb68a22..868dc3e2 100644 --- a/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart +++ b/khelo/lib/ui/flow/matches/add_match/add_match_view_model.dart @@ -232,11 +232,8 @@ class AddMatchViewNotifier extends StateNotifier { } void onTeamSelect(TeamModel team, TeamType type) { - final matchPlayer = team.players - .take(11) - .map( - (e) => MatchPlayer(player: e.user!, status: PlayerStatus.yetToPlay)) - .toList(); + final matchPlayer = + team.players.take(11).map((e) => MatchPlayer(player: e.user)).toList(); final captainAndAdminId = matchPlayer.firstOrNull?.player.id; switch (type) { diff --git a/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart b/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart index 73af9b18..be5eb6a2 100644 --- a/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart +++ b/khelo/lib/ui/flow/matches/add_match/select_squad/select_squad_screen.dart @@ -187,8 +187,8 @@ class _SelectSquadScreenState extends ConsumerState { return state.team?.players .where((element) => !state.squad.map((e) => e.player.id).contains(element.id) && - element.user!.isActive) - .map((e) => e.user!) + element.user.isActive) + .map((e) => e.user) .toList() ?? []; } 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 367f37e4..c07f8543 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 @@ -55,16 +55,16 @@ class MatchDetailSquadView extends ConsumerWidget { final firstTeamBench = firstTeam?.team.players .where((element) => !firstTeamSquad.map((e) => e.id).contains(element.id) && - element.user!.isActive) - .map((e) => e.user!) + element.user.isActive) + .map((e) => e.user) .toList() ?? []; final secondTeamBench = secondTeam?.team.players .where((element) => !secondTeamSquad.map((e) => e.id).contains(element.id) && - element.user!.isActive) - .map((e) => e.user!) + element.user.isActive) + .map((e) => e.user) .toList() ?? []; 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 d7265cb9..887fe7e9 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 @@ -183,14 +183,14 @@ class _AddTeamScreenState extends ConsumerState { ), ], ...state.teamMembers.map((player) { - final detail = player.user!; return Padding( padding: const EdgeInsets.only(top: 16), child: UserDetailCell( - user: detail, - onTap: () => UserDetailSheet.show(context, detail), + user: player.user, + onTap: () => UserDetailSheet.show(context, player.user), trailing: actionButton(context, - onPressed: () => notifier.onRemoveUserFromTeam(detail), + onPressed: () => + notifier.onRemoveUserFromTeam(player.user), padding: const EdgeInsets.only( left: 10, top: 10, bottom: 10), icon: Icon( 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 3371390f..a3b41fff 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 @@ -94,7 +94,7 @@ class AddTeamViewNotifier extends StateNotifier { final player = TeamPlayer( id: state.currentUser!.id, role: TeamPlayerRole.admin, - user: state.currentUser); + user: state.currentUser!); players.add(player); } diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart index 2c7adf4f..80ba6e69 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart @@ -215,9 +215,9 @@ class _AddTeamMemberScreenState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 8), - _selectedProfileView(context, player.user!), + _selectedProfileView(context, player.user), const SizedBox(height: 4), - Text(player.user?.name ?? "", + Text(player.user.name ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, style: AppTextStyle.caption.copyWith( diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart index 4b11f6f5..591c1863 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart @@ -37,7 +37,7 @@ class TeamDetailMemberContent extends ConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), itemCount: state.team!.players.length, itemBuilder: (context, index) { - final member = state.team!.players[index].user!; + final member = state.team!.players[index].user; return UserDetailCell( user: member, onTap: () => UserDetailSheet.show(context, member), diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart index 4fd4cd66..6d142cab 100644 --- a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart @@ -9,6 +9,7 @@ import 'package:khelo/domain/extensions/widget_extension.dart'; import 'package:khelo/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart'; import 'package:style/button/action_button.dart'; import 'package:style/extensions/context_extensions.dart'; +import 'package:style/text/app_text_style.dart'; import 'package:style/widgets/rounded_check_box.dart'; import '../../../../../components/error_snackbar.dart'; @@ -17,13 +18,11 @@ import '../../../../../gen/assets.gen.dart'; import '../../../matches/add_match/select_squad/components/user_detail_sheet.dart'; class MakeTeamAdminScreen extends ConsumerStatefulWidget { - final String teamId; - final List players; + final TeamModel team; const MakeTeamAdminScreen({ super.key, - required this.teamId, - required this.players, + required this.team, }); @override @@ -37,10 +36,7 @@ class _MakeAdminScreenState extends ConsumerState { void initState() { super.initState(); notifier = ref.read(makeTeamAdminStateProvider.notifier); - runPostFrame(() => notifier.setData( - teamId: widget.teamId, - players: widget.players, - )); + runPostFrame(() => notifier.setData(widget.team)); } @override @@ -50,22 +46,22 @@ class _MakeAdminScreenState extends ConsumerState { final state = ref.watch(makeTeamAdminStateProvider); return AppPage( title: context.l10n.team_detail_make_admin, - actions: (state.isButtonEnabled) - ? [ - actionButton(context, - onPressed: notifier.onSave, - icon: SvgPicture.asset( - Assets.images.icCheck, - height: 24, - width: 24, - fit: BoxFit.contain, - colorFilter: ColorFilter.mode( - context.colorScheme.textPrimary, - BlendMode.srcIn, - ), - )) - ] - : null, + actions: [ + actionButton(context, + onPressed: notifier.onSave, + icon: SvgPicture.asset( + Assets.images.icCheck, + height: 24, + width: 24, + fit: BoxFit.contain, + colorFilter: ColorFilter.mode( + state.isButtonEnabled + ? context.colorScheme.primary + : context.colorScheme.textDisabled, + BlendMode.srcIn, + ), + )) + ], body: Builder(builder: (context) => _body(context, state)), ); } @@ -90,24 +86,41 @@ class _MakeAdminScreenState extends ConsumerState { Widget _body(BuildContext context, MakeTeamAdminState state) { return ListView.separated( - padding: const EdgeInsets.all(16) + context.mediaQueryPadding, - itemCount: widget.players.length, + padding: + const EdgeInsets.symmetric(vertical: 16) + context.mediaQueryPadding, + itemCount: widget.team.players.length, itemBuilder: (context, index) { - final player = widget.players[index]; - return (player.user != null) - ? UserDetailCell( - user: player.user!, - onTap: () => UserDetailSheet.show(context, player.user!), - showPhoneNumber: false, - trailing: RoundedCheckBox( - isSelected: state.selectedPlayers - .any((element) => element.user == player.user), - onTap: (_) => notifier.selectAdmin(player), - ), - ) - : const SizedBox(); + final player = widget.team.players[index]; + if (widget.team.created_by == player.id) { + return UserDetailCell( + user: player.user, + showPhoneNumber: false, + padding: EdgeInsets.symmetric(horizontal: 16), + onTap: () => UserDetailSheet.show(context, player.user), + trailing: Text(context.l10n.team_detail_make_admin_owner_title, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.primary)), + ); + } + return UserDetailCell( + user: player.user, + showPhoneNumber: false, + padding: EdgeInsets.symmetric(horizontal: 16), + onTap: () => UserDetailSheet.show(context, player.user), + trailing: RoundedCheckBox( + isSelected: state.selectedPlayers + .any((element) => element.user == player.user), + onTap: (_) => notifier.selectAdmin(player), + )); }, - separatorBuilder: (context, index) => const SizedBox(height: 16), + separatorBuilder: (context, index) => + (widget.team.created_by == widget.team.players[index].id) + ? Divider( + height: 24, + thickness: 1, + color: context.colorScheme.outline, + ) + : const SizedBox(height: 16), ); } } diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart index d3f64ef6..29269913 100644 --- a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_view_model.dart @@ -16,16 +16,11 @@ class MakeTeamAdminViewNotifier extends StateNotifier { MakeTeamAdminViewNotifier(this._teamService) : super(const MakeTeamAdminState()); - late String _teamId; - late List _players; + late TeamModel _team; - void setData({ - required String teamId, - required List players, - }) { - _teamId = teamId; - _players = players; - final admins = players + void setData(TeamModel team) { + _team = team; + final admins = _team.players .where((element) => element.role == TeamPlayerRole.admin) .toList(); state = state.copyWith(selectedPlayers: admins); @@ -39,14 +34,15 @@ class MakeTeamAdminViewNotifier extends StateNotifier { void onSave() async { try { - final players = _players.map((player) { + state = state.copyWith(actionError: null); + final players = _team.players.map((player) { final role = state.selectedPlayers.contains(player) ? TeamPlayerRole.admin : TeamPlayerRole.player; return player.copyWith(role: role); }).toList(); - await _teamService.editPlayersToTeam(_teamId, players); + await _teamService.editPlayersToTeam(_team.id ?? 'INVALID ID', players); state = state.copyWith(pop: true, actionError: null); } catch (e) { state = state.copyWith(pop: false, actionError: e); 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 065de74d..70d6c82b 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_screen.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_screen.dart @@ -213,11 +213,8 @@ class _TeamDetailScreenState extends ConsumerState { .length)), onTap: () { context.pop(); - if (state.team!.players.isNotEmpty) { - AppRoute.makeTeamAdmin( - teamId: state.team!.id ?? 'INVALID ID', - players: state.team!.players) - .push(context); + if (state.team != null) { + AppRoute.makeTeamAdmin(team: state.team!).push(context); } }, ), diff --git a/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart b/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart index b6217953..90378b1c 100644 --- a/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart +++ b/khelo/lib/ui/flow/team/search_team/components/team_member_sheet.dart @@ -64,19 +64,19 @@ class TeamMemberSheet extends StatelessWidget { runSpacing: 16, children: (team.players) .map((player) => UserDetailCell( - user: player.user!, + user: player.user, onTap: () => UserDetailSheet.show( context, - player.user!, + player.user, actionButtonTitle: - isForVerification && player.user!.isActive + isForVerification && player.user.isActive ? context.l10n.common_select_title : null, onButtonTap: () => - _onSelectButtonTap(context, player.user!), + _onSelectButtonTap(context, player.user), ), - trailing: isForVerification && player.user!.isActive - ? _selectButton(context, player.user!) + trailing: isForVerification && player.user.isActive + ? _selectButton(context, player.user) : null, )) .toList()), diff --git a/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart b/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart index bff1e1f1..236fd373 100644 --- a/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart +++ b/khelo/lib/ui/flow/team/search_team/search_team_view_model.dart @@ -90,10 +90,8 @@ class SearchTeamViewNotifier extends StateNotifier { void onTeamCellTap(TeamModel team) { state = state.copyWith(showSelectionError: false); - final playersCount = (team.players - .where((player) => player.user?.isActive ?? false) - .toList()) - .length; + final playersCount = + (team.players.where((player) => player.user.isActive).toList()).length; if (playersCount >= 2) { final isAlreadySelected = state.selectedTeam?.id == team.id; state = state.copyWith(selectedTeam: isAlreadySelected ? null : team); diff --git a/khelo/lib/ui/flow/team/team_list_view_model.dart b/khelo/lib/ui/flow/team/team_list_view_model.dart index 81ee3d9b..c31d4b23 100644 --- a/khelo/lib/ui/flow/team/team_list_view_model.dart +++ b/khelo/lib/ui/flow/team/team_list_view_model.dart @@ -69,6 +69,12 @@ class TeamListViewNotifier extends StateNotifier { .map((e) => e.id) .contains(state.currentUserId))) .toList(); + case TeamFilterOption.meAsAdmin: + filteredTeams = state.teams + .where((element) => element.players.any((player) => + player.id == state.currentUserId && + player.role == TeamPlayerRole.admin)) + .toList(); default: filteredTeams = state.teams; } @@ -113,7 +119,8 @@ class TeamListViewState with _$TeamListViewState { enum TeamFilterOption { all, createdByMe, - memberMe; + memberMe, + meAsAdmin; String getString(BuildContext context) { switch (this) { @@ -123,6 +130,8 @@ enum TeamFilterOption { return context.l10n.team_list_created_by_me_title; case TeamFilterOption.memberMe: return context.l10n.team_list_me_as_member_title; + case TeamFilterOption.meAsAdmin: + return context.l10n.team_list_me_as_admin_title; } } } From b4481db4ff2974f9860f52f9a655f214938be121 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Thu, 22 Aug 2024 12:07:15 +0530 Subject: [PATCH 12/20] Fix lint --- data/lib/errors/app_error.dart | 4 +++- .../lib/service/ball_score/ball_score_service.dart | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/data/lib/errors/app_error.dart b/data/lib/errors/app_error.dart index 112f81c9..fb62f4f8 100644 --- a/data/lib/errors/app_error.dart +++ b/data/lib/errors/app_error.dart @@ -39,7 +39,9 @@ class AppError implements Exception { return const LargeAttachmentUploadError(); } else { return SomethingWentWrongError( - message: error.toString(), stackTrace: stack); + message: error.toString(), + stackTrace: stack, + ); } } diff --git a/data/lib/service/ball_score/ball_score_service.dart b/data/lib/service/ball_score/ball_score_service.dart index d2feacee..3390a066 100644 --- a/data/lib/service/ball_score/ball_score_service.dart +++ b/data/lib/service/ball_score/ball_score_service.dart @@ -1,12 +1,12 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:data/api/ball_score/ball_score_model.dart'; -import 'package:data/errors/app_error.dart'; -import 'package:data/extensions/double_extensions.dart'; -import 'package:data/service/innings/inning_service.dart'; -import 'package:data/service/match/match_service.dart'; -import 'package:data/storage/app_preferences.dart'; -import 'package:data/utils/constant/firestore_constant.dart'; +import '../../api/ball_score/ball_score_model.dart'; +import '../../errors/app_error.dart'; +import '../../extensions/double_extensions.dart'; +import '../innings/inning_service.dart'; +import '../match/match_service.dart'; +import '../../storage/app_preferences.dart'; +import '../../utils/constant/firestore_constant.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../api/match/match_model.dart'; From f928f8d422b910ce8ee7a844762e592f0e2fb357 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Thu, 22 Aug 2024 12:09:19 +0530 Subject: [PATCH 13/20] Fix lint --- .../ball_score/ball_score_service.dart | 48 ++++++++++--------- data/lib/service/innings/inning_service.dart | 2 +- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/data/lib/service/ball_score/ball_score_service.dart b/data/lib/service/ball_score/ball_score_service.dart index 3390a066..145bd895 100644 --- a/data/lib/service/ball_score/ball_score_service.dart +++ b/data/lib/service/ball_score/ball_score_service.dart @@ -65,17 +65,19 @@ class BallScoreService { double.parse("${score.over_number - 1}.${score.ball_number}"); // update matchTeamScore and squad(if needed) - await _matchService.updateTeamScoreAndSquadViaTransaction(transaction, - matchId: matchId, - battingTeamId: battingTeamId, - totalRun: otherTotalRuns + totalRuns, - over: overCount.add(otherInningOver.toBalls()), - bowlingTeamId: bowlingTeamId, - wicket: otherTotalWicketTaken + totalWicketTaken, - runs: totalBowlingTeamRuns != null - ? otherTotalBowlingTeamRuns + totalBowlingTeamRuns - : null, - updatedMatchPlayer: updatedPlayer != null ? [updatedPlayer] : null); + await _matchService.updateTeamScoreAndSquadViaTransaction( + transaction, + matchId: matchId, + battingTeamId: battingTeamId, + totalRun: otherTotalRuns + totalRuns, + over: overCount.add(otherInningOver.toBalls()), + bowlingTeamId: bowlingTeamId, + wicket: otherTotalWicketTaken + totalWicketTaken, + runs: totalBowlingTeamRuns != null + ? otherTotalBowlingTeamRuns + totalBowlingTeamRuns + : null, + updatedMatchPlayer: updatedPlayer != null ? [updatedPlayer] : null, + ); // update innings score detail _inningsService.updateInningScoreDetailViaTransaction( transaction, @@ -154,17 +156,19 @@ class BallScoreService { try { _firestore.runTransaction((transaction) async { // update matchTeamScore and squad(if needed) - await _matchService.updateTeamScoreAndSquadViaTransaction(transaction, - matchId: matchId, - battingTeamId: battingTeamId, - totalRun: otherTotalRuns + totalRuns, - over: overCount?.add(otherInningOver.toBalls()), - bowlingTeamId: bowlingTeamId, - wicket: otherTotalWicketTaken + totalWicketTaken, - runs: totalBowlingTeamRuns != null - ? otherTotalBowlingTeamRuns + totalBowlingTeamRuns - : null, - updatedMatchPlayer: updatedPlayer); + await _matchService.updateTeamScoreAndSquadViaTransaction( + transaction, + matchId: matchId, + battingTeamId: battingTeamId, + totalRun: otherTotalRuns + totalRuns, + over: overCount?.add(otherInningOver.toBalls()), + bowlingTeamId: bowlingTeamId, + wicket: otherTotalWicketTaken + totalWicketTaken, + runs: totalBowlingTeamRuns != null + ? otherTotalBowlingTeamRuns + totalBowlingTeamRuns + : null, + updatedMatchPlayer: updatedPlayer, + ); // update innings score detail _inningsService.updateInningScoreDetailViaTransaction( diff --git a/data/lib/service/innings/inning_service.dart b/data/lib/service/innings/inning_service.dart index 39ce14af..cbf239c1 100644 --- a/data/lib/service/innings/inning_service.dart +++ b/data/lib/service/innings/inning_service.dart @@ -96,7 +96,7 @@ class InningsService { Future updateInningsStatuses(Map innings) async { try { - WriteBatch batch = _firestore.batch(); + final WriteBatch batch = _firestore.batch(); for (final inning in innings.entries) { final inningRef = _inningCollection.doc(inning.key); From ae8a8256682f4cb526ef67ef23a6e47a02df574f Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Thu, 22 Aug 2024 12:13:09 +0530 Subject: [PATCH 14/20] Fix lint --- .../flow/team/detail/make_admin/make_team_admin_screen.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart index 6d142cab..d51654a7 100644 --- a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart @@ -95,7 +95,7 @@ class _MakeAdminScreenState extends ConsumerState { return UserDetailCell( user: player.user, showPhoneNumber: false, - padding: EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.symmetric(horizontal: 16), onTap: () => UserDetailSheet.show(context, player.user), trailing: Text(context.l10n.team_detail_make_admin_owner_title, style: AppTextStyle.body2 @@ -105,7 +105,7 @@ class _MakeAdminScreenState extends ConsumerState { return UserDetailCell( user: player.user, showPhoneNumber: false, - padding: EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.symmetric(horizontal: 16), onTap: () => UserDetailSheet.show(context, player.user), trailing: RoundedCheckBox( isSelected: state.selectedPlayers From f5722b48477835083759d729a1f68e59a1dec7bb Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Thu, 22 Aug 2024 16:12:55 +0530 Subject: [PATCH 15/20] Mr changes --- .../components/team_detail_match_content.dart | 12 ++++--- .../team_detail_member_content.dart | 12 ++++--- .../make_admin/make_team_admin_screen.dart | 33 +++++++++++-------- .../flow/team/detail/team_detail_screen.dart | 32 +++++++++--------- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart index 9515eb7d..f46df9e5 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart @@ -14,6 +14,11 @@ class TeamDetailMatchContent extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(teamDetailStateProvider); + final isAdminOrOwner = state.team?.created_by == state.currentUserId || + state.team?.players.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == + true; if (state.matches != null && state.matches!.isNotEmpty) { return ListView.separated( @@ -23,7 +28,7 @@ class TeamDetailMatchContent extends ConsumerWidget { final match = state.matches![index]; return MatchDetailCell( match: match, - showActionButtons: match.created_by == state.currentUserId, + showActionButtons: isAdminOrOwner, onTap: () => AppRoute.matchDetailTab(matchId: match.id ?? "").push(context), onActionTap: () { @@ -50,10 +55,7 @@ class TeamDetailMatchContent extends ConsumerWidget { description: (state.team?.created_by == state.currentUserId) ? context.l10n.team_detail_empty_matches_description_text : context.l10n.team_detail_visitor_empty_matches_description_text, - isShowButton: state.team?.players.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == - true, + isShowButton: isAdminOrOwner, buttonTitle: context.l10n.add_match_screen_title, onTap: () async { bool? isUpdated = await AppRoute.addMatch( diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart index 591c1863..ddfe35e4 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart @@ -18,14 +18,16 @@ class TeamDetailMemberContent extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(teamDetailStateProvider); + final isAdminOrOwner = state.team?.created_by == state.currentUserId || + state.team?.players.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == + true; if (state.team?.players != null && state.team?.players.isNotEmpty == true) { return Column( children: [ - if (state.team?.players.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == - true) ...[ + if (isAdminOrOwner) ...[ _addMemberButton( context, onTap: () => @@ -54,7 +56,7 @@ class TeamDetailMemberContent extends ConsumerWidget { description: state.team!.created_by == state.currentUserId ? context.l10n.team_detail_empty_member_description_text : context.l10n.team_detail_visitor_empty_member_description_text, - isShowButton: state.team!.created_by == state.currentUserId, + isShowButton: isAdminOrOwner, buttonTitle: context.l10n.team_list_add_members_title, onTap: () => AppRoute.addTeamMember(team: state.team!).push(context), ); diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart index d51654a7..02e210f5 100644 --- a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart @@ -48,7 +48,7 @@ class _MakeAdminScreenState extends ConsumerState { title: context.l10n.team_detail_make_admin, actions: [ actionButton(context, - onPressed: notifier.onSave, + onPressed: state.isButtonEnabled ? notifier.onSave : null, icon: SvgPicture.asset( Assets.images.icCheck, height: 24, @@ -85,23 +85,29 @@ class _MakeAdminScreenState extends ConsumerState { } Widget _body(BuildContext context, MakeTeamAdminState state) { + final members = widget.team.players + .where((element) => element.id != widget.team.created_by) + .toList(); + final owner = widget.team.players + .firstWhere((element) => element.id != widget.team.created_by); + return ListView.separated( padding: const EdgeInsets.symmetric(vertical: 16) + context.mediaQueryPadding, - itemCount: widget.team.players.length, + itemCount: members.length + 1, itemBuilder: (context, index) { - final player = widget.team.players[index]; - if (widget.team.created_by == player.id) { + if (index == 0) { return UserDetailCell( - user: player.user, + user: owner.user, showPhoneNumber: false, padding: const EdgeInsets.symmetric(horizontal: 16), - onTap: () => UserDetailSheet.show(context, player.user), + onTap: () => UserDetailSheet.show(context, owner.user), trailing: Text(context.l10n.team_detail_make_admin_owner_title, style: AppTextStyle.body2 .copyWith(color: context.colorScheme.primary)), ); } + final player = members[index - 1]; return UserDetailCell( user: player.user, showPhoneNumber: false, @@ -113,14 +119,13 @@ class _MakeAdminScreenState extends ConsumerState { onTap: (_) => notifier.selectAdmin(player), )); }, - separatorBuilder: (context, index) => - (widget.team.created_by == widget.team.players[index].id) - ? Divider( - height: 24, - thickness: 1, - color: context.colorScheme.outline, - ) - : const SizedBox(height: 16), + separatorBuilder: (context, index) => (index == 0) + ? Divider( + height: 24, + thickness: 1, + color: context.colorScheme.outline, + ) + : const SizedBox(height: 16), ); } } 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 70d6c82b..4f9dbb45 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_screen.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_screen.dart @@ -71,10 +71,11 @@ class _TeamDetailScreenState extends ConsumerState { size: 24, color: context.colorScheme.textPrimary, )), - actions: (state.team?.players.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == - true) + actions: (state.team?.created_by == state.currentUserId || + state.team?.players.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == + true) ? [ moreOptionButton( context, @@ -205,19 +206,18 @@ class _TeamDetailScreenState extends ConsumerState { .push(context); }, ), - BottomSheetAction( - title: context.l10n.team_detail_make_admin, - child: Text(context.l10n.team_detail_admin(state.team!.players - .where((element) => element.role == TeamPlayerRole.admin) - .toList() - .length)), - onTap: () { - context.pop(); - if (state.team != null) { + if (state.team?.players.isNotEmpty ?? false) + BottomSheetAction( + title: context.l10n.team_detail_make_admin, + child: Text(context.l10n.team_detail_admin(state.team!.players + .where((element) => element.role == TeamPlayerRole.admin) + .toList() + .length)), + onTap: () { + context.pop(); AppRoute.makeTeamAdmin(team: state.team!).push(context); - } - }, - ), + }, + ), ]); } From a55de3fff4408f39a3f8d5a55dfaedd2d2502162 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Fri, 23 Aug 2024 10:41:46 +0530 Subject: [PATCH 16/20] Mr changes --- data/lib/service/team/team_service.dart | 6 ++-- .../add_team_member_screen.dart | 4 ++- .../add_team_member_view_model.dart | 32 +++++++++++++----- .../make_admin/make_team_admin_screen.dart | 33 +++++++++++-------- khelo/lib/ui/flow/team/team_list_screen.dart | 9 ++--- 5 files changed, 55 insertions(+), 29 deletions(-) diff --git a/data/lib/service/team/team_service.dart b/data/lib/service/team/team_service.dart index 1e1eab19..a010a5ce 100644 --- a/data/lib/service/team/team_service.dart +++ b/data/lib/service/team/team_service.dart @@ -196,8 +196,10 @@ class TeamService { ) async { try { final teamRef = _teamsCollection.doc(teamId); - await teamRef - .update({FireStoreConst.players: FieldValue.arrayRemove(players)}); + await teamRef.update({ + FireStoreConst.teamPlayers: + FieldValue.arrayRemove(players.map((e) => e.toJson()).toList()) + }); } catch (error, stack) { throw AppError.fromError(error, stack); } diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart index 80ba6e69..b1962515 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_screen.dart @@ -11,6 +11,7 @@ import 'package:khelo/components/error_snackbar.dart'; import 'package:khelo/components/image_avatar.dart'; import 'package:khelo/components/user_detail_cell.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/widget_extension.dart'; import 'package:khelo/ui/flow/matches/add_match/select_squad/components/user_detail_sheet.dart'; import 'package:khelo/ui/flow/team/add_team_member/add_team_member_view_model.dart'; import 'package:khelo/ui/flow/team/add_team_member/components/verify_team_member_sheet.dart'; @@ -41,6 +42,7 @@ class _AddTeamMemberScreenState extends ConsumerState { void initState() { super.initState(); notifier = ref.read(addTeamMemberStateProvider.notifier); + runPostFrame(() => notifier.setData(widget.team)); } @override @@ -56,7 +58,7 @@ class _AddTeamMemberScreenState extends ConsumerState { ? const AppProgressIndicator(size: AppProgressIndicatorSize.small) : actionButton( context, - onPressed: () => notifier.addPlayersToTeam(widget.team.id), + onPressed: () => notifier.addPlayersToTeam(), icon: SvgPicture.asset( Assets.images.icCheck, colorFilter: ColorFilter.mode( diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart index 27d41e08..66ba60ef 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart @@ -4,6 +4,7 @@ import 'package:data/api/team/team_model.dart'; import 'package:data/api/user/user_models.dart'; import 'package:data/service/team/team_service.dart'; import 'package:data/service/user/user_service.dart'; +import 'package:data/storage/app_preferences.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -15,6 +16,7 @@ final addTeamMemberStateProvider = StateNotifierProvider.autoDispose< return AddTeamMemberViewNotifier( ref.read(userServiceProvider), ref.read(teamServiceProvider), + ref.read(currentUserPod)?.id, ); }); @@ -22,9 +24,19 @@ class AddTeamMemberViewNotifier extends StateNotifier { final UserService _userService; final TeamService _teamService; Timer? _debounce; + final String? currantUserId; - AddTeamMemberViewNotifier(this._userService, this._teamService) - : super(AddTeamMemberState(searchController: TextEditingController())); + AddTeamMemberViewNotifier( + this._userService, + this._teamService, + this.currantUserId, + ) : super(AddTeamMemberState(searchController: TextEditingController())); + + late TeamModel _team; + + void setData(TeamModel team) { + _team = team; + } Future search(String searchKey) async { try { @@ -51,8 +63,12 @@ class AddTeamMemberViewNotifier extends StateNotifier { } void selectUser(UserModel user) { - final player = - TeamPlayer(id: user.id, role: TeamPlayerRole.player, user: user); + final player = TeamPlayer( + id: user.id, + role: (_team.created_by == currantUserId) + ? TeamPlayerRole.admin + : TeamPlayerRole.player, + user: user); state = state.copyWith(selectedUsers: [...state.selectedUsers, player]); } @@ -62,14 +78,12 @@ class AddTeamMemberViewNotifier extends StateNotifier { state = state.copyWith(selectedUsers: updatedList); } - Future addPlayersToTeam(String? id) async { - if (id == null) { - return; - } + Future addPlayersToTeam() async { + if (_team.id == null) return; state = state.copyWith(isAddInProgress: true, actionError: null); try { - await _teamService.addPlayersToTeam(id, state.selectedUsers); + await _teamService.addPlayersToTeam(_team.id!, state.selectedUsers); state = state.copyWith(isAddInProgress: false, isAdded: true); } catch (e) { state = state.copyWith(isAddInProgress: false, actionError: e); diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart index 02e210f5..c1158279 100644 --- a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart @@ -88,8 +88,10 @@ class _MakeAdminScreenState extends ConsumerState { final members = widget.team.players .where((element) => element.id != widget.team.created_by) .toList(); - final owner = widget.team.players - .firstWhere((element) => element.id != widget.team.created_by); + + final TeamPlayer owner = widget.team.players.firstWhere( + (element) => element.id == widget.team.created_by, + orElse: () => TeamPlayer(id: '')); return ListView.separated( padding: @@ -97,21 +99,26 @@ class _MakeAdminScreenState extends ConsumerState { itemCount: members.length + 1, itemBuilder: (context, index) { if (index == 0) { - return UserDetailCell( - user: owner.user, - showPhoneNumber: false, - padding: const EdgeInsets.symmetric(horizontal: 16), - onTap: () => UserDetailSheet.show(context, owner.user), - trailing: Text(context.l10n.team_detail_make_admin_owner_title, - style: AppTextStyle.body2 - .copyWith(color: context.colorScheme.primary)), - ); + return (owner.id.isNotEmpty) + ? UserDetailCell( + user: owner.user, + showPhoneNumber: false, + padding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + onTap: () => UserDetailSheet.show(context, owner.user), + trailing: Text( + context.l10n.team_detail_make_admin_owner_title, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.primary)), + ) + : SizedBox(); } + final player = members[index - 1]; return UserDetailCell( user: player.user, showPhoneNumber: false, - padding: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), onTap: () => UserDetailSheet.show(context, player.user), trailing: RoundedCheckBox( isSelected: state.selectedPlayers @@ -119,7 +126,7 @@ class _MakeAdminScreenState extends ConsumerState { onTap: (_) => notifier.selectAdmin(player), )); }, - separatorBuilder: (context, index) => (index == 0) + separatorBuilder: (context, index) => (index == 0 && owner.id.isNotEmpty) ? Divider( height: 24, thickness: 1, diff --git a/khelo/lib/ui/flow/team/team_list_screen.dart b/khelo/lib/ui/flow/team/team_list_screen.dart index 5ae76c1e..3ca9e50d 100644 --- a/khelo/lib/ui/flow/team/team_list_screen.dart +++ b/khelo/lib/ui/flow/team/team_list_screen.dart @@ -88,10 +88,11 @@ class _TeamListScreenState extends ConsumerState return _teamListCell( context, team: team, - showMoreOptionButton: team.players.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == - true, + showMoreOptionButton: team.created_by == state.currentUserId || + team.players.any((element) => + element.id == state.currentUserId && + element.role == TeamPlayerRole.admin) == + true, ); }, ) From 2ed67e4e4894954bccc10a0af3a8b36e1342aae5 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Fri, 23 Aug 2024 10:46:45 +0530 Subject: [PATCH 17/20] Fix lint --- data/lib/service/team/team_service.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/lib/service/team/team_service.dart b/data/lib/service/team/team_service.dart index a010a5ce..9957f9a3 100644 --- a/data/lib/service/team/team_service.dart +++ b/data/lib/service/team/team_service.dart @@ -198,7 +198,7 @@ class TeamService { final teamRef = _teamsCollection.doc(teamId); await teamRef.update({ FireStoreConst.teamPlayers: - FieldValue.arrayRemove(players.map((e) => e.toJson()).toList()) + FieldValue.arrayRemove(players.map((e) => e.toJson()).toList()), }); } catch (error, stack) { throw AppError.fromError(error, stack); From 2622664af237f0c253e6f47c74de0c765008ebaa Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Fri, 23 Aug 2024 10:49:22 +0530 Subject: [PATCH 18/20] Fix lint --- .../flow/team/detail/make_admin/make_team_admin_screen.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart index c1158279..4288971b 100644 --- a/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart +++ b/khelo/lib/ui/flow/team/detail/make_admin/make_team_admin_screen.dart @@ -91,7 +91,7 @@ class _MakeAdminScreenState extends ConsumerState { final TeamPlayer owner = widget.team.players.firstWhere( (element) => element.id == widget.team.created_by, - orElse: () => TeamPlayer(id: '')); + orElse: () => const TeamPlayer(id: '')); return ListView.separated( padding: @@ -111,7 +111,7 @@ class _MakeAdminScreenState extends ConsumerState { style: AppTextStyle.body2 .copyWith(color: context.colorScheme.primary)), ) - : SizedBox(); + : const SizedBox(); } final player = members[index - 1]; From 888e6b4049bf0fba8579a1624c9fb0b1768e30f9 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Fri, 23 Aug 2024 11:09:36 +0530 Subject: [PATCH 19/20] Mr changes --- data/lib/api/team/team_model.dart | 9 +++++++++ .../team/add_team_member/add_team_member_view_model.dart | 6 +++--- .../detail/components/team_detail_match_content.dart | 8 ++------ .../detail/components/team_detail_member_content.dart | 8 ++------ khelo/lib/ui/flow/team/detail/team_detail_screen.dart | 6 +----- khelo/lib/ui/flow/team/team_list_screen.dart | 6 +----- 6 files changed, 18 insertions(+), 25 deletions(-) diff --git a/data/lib/api/team/team_model.dart b/data/lib/api/team/team_model.dart index e4f2d416..c5e4149c 100644 --- a/data/lib/api/team/team_model.dart +++ b/data/lib/api/team/team_model.dart @@ -25,6 +25,15 @@ abstract class TeamModel with _$TeamModel { List players, }) = _TeamModel; + bool isAdminOrOwner(String? currentUserId) { + return created_by == currentUserId || + players.any( + (element) => + element.id == currentUserId && + element.role == TeamPlayerRole.admin, + ); + } + factory TeamModel.fromJson(Map json) => _$TeamModelFromJson(json); diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart index 66ba60ef..66a00edd 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart @@ -24,12 +24,12 @@ class AddTeamMemberViewNotifier extends StateNotifier { final UserService _userService; final TeamService _teamService; Timer? _debounce; - final String? currantUserId; + final String? currentUserId; AddTeamMemberViewNotifier( this._userService, this._teamService, - this.currantUserId, + this.currentUserId, ) : super(AddTeamMemberState(searchController: TextEditingController())); late TeamModel _team; @@ -65,7 +65,7 @@ class AddTeamMemberViewNotifier extends StateNotifier { void selectUser(UserModel user) { final player = TeamPlayer( id: user.id, - role: (_team.created_by == currantUserId) + role: (_team.created_by == currentUserId) ? TeamPlayerRole.admin : TeamPlayerRole.player, user: user); diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart index f46df9e5..c43d37a8 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart @@ -1,5 +1,4 @@ import 'package:data/api/match/match_model.dart'; -import 'package:data/api/team/team_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/empty_screen.dart'; @@ -14,11 +13,8 @@ class TeamDetailMatchContent extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(teamDetailStateProvider); - final isAdminOrOwner = state.team?.created_by == state.currentUserId || - state.team?.players.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == - true; + final isAdminOrOwner = + state.team?.isAdminOrOwner(state.currentUserId) ?? false; if (state.matches != null && state.matches!.isNotEmpty) { return ListView.separated( diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart index ddfe35e4..d005cb4e 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart @@ -1,4 +1,3 @@ -import 'package:data/api/team/team_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/empty_screen.dart'; @@ -18,11 +17,8 @@ class TeamDetailMemberContent extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(teamDetailStateProvider); - final isAdminOrOwner = state.team?.created_by == state.currentUserId || - state.team?.players.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == - true; + final isAdminOrOwner = + state.team?.isAdminOrOwner(state.currentUserId) ?? false; if (state.team?.players != null && state.team?.players.isNotEmpty == true) { return Column( 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 4f9dbb45..017fd815 100644 --- a/khelo/lib/ui/flow/team/detail/team_detail_screen.dart +++ b/khelo/lib/ui/flow/team/detail/team_detail_screen.dart @@ -71,11 +71,7 @@ class _TeamDetailScreenState extends ConsumerState { size: 24, color: context.colorScheme.textPrimary, )), - actions: (state.team?.created_by == state.currentUserId || - state.team?.players.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == - true) + actions: (state.team?.isAdminOrOwner(state.currentUserId) ?? false) ? [ moreOptionButton( context, diff --git a/khelo/lib/ui/flow/team/team_list_screen.dart b/khelo/lib/ui/flow/team/team_list_screen.dart index 3ca9e50d..bb8d4375 100644 --- a/khelo/lib/ui/flow/team/team_list_screen.dart +++ b/khelo/lib/ui/flow/team/team_list_screen.dart @@ -88,11 +88,7 @@ class _TeamListScreenState extends ConsumerState return _teamListCell( context, team: team, - showMoreOptionButton: team.created_by == state.currentUserId || - team.players.any((element) => - element.id == state.currentUserId && - element.role == TeamPlayerRole.admin) == - true, + showMoreOptionButton: team.isAdminOrOwner(state.currentUserId), ); }, ) From 36d8ca046685849be58eb55dea514b0c7ba5edc0 Mon Sep 17 00:00:00 2001 From: cp-mayank-v Date: Fri, 23 Aug 2024 11:53:45 +0530 Subject: [PATCH 20/20] Minor changes --- data/lib/api/team/team_model.dart | 20 ++++++++++--------- .../add_team_member_view_model.dart | 14 ++++--------- .../components/team_detail_match_content.dart | 1 + .../team_detail_member_content.dart | 1 + 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/data/lib/api/team/team_model.dart b/data/lib/api/team/team_model.dart index c5e4149c..9ed4b99f 100644 --- a/data/lib/api/team/team_model.dart +++ b/data/lib/api/team/team_model.dart @@ -25,15 +25,6 @@ abstract class TeamModel with _$TeamModel { List players, }) = _TeamModel; - bool isAdminOrOwner(String? currentUserId) { - return created_by == currentUserId || - players.any( - (element) => - element.id == currentUserId && - element.role == TeamPlayerRole.admin, - ); - } - factory TeamModel.fromJson(Map json) => _$TeamModelFromJson(json); @@ -44,6 +35,17 @@ abstract class TeamModel with _$TeamModel { TeamModel.fromJson(snapshot.data()!); } +extension TeamModelExtension on TeamModel { + bool isAdminOrOwner(String? currentUserId) { + return created_by == currentUserId || + players.any( + (element) => + element.id == currentUserId && + element.role == TeamPlayerRole.admin, + ); + } +} + enum TeamPlayerRole { admin, player; diff --git a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart index 66a00edd..ef6e8e16 100644 --- a/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart +++ b/khelo/lib/ui/flow/team/add_team_member/add_team_member_view_model.dart @@ -4,7 +4,6 @@ import 'package:data/api/team/team_model.dart'; import 'package:data/api/user/user_models.dart'; import 'package:data/service/team/team_service.dart'; import 'package:data/service/user/user_service.dart'; -import 'package:data/storage/app_preferences.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -16,7 +15,6 @@ final addTeamMemberStateProvider = StateNotifierProvider.autoDispose< return AddTeamMemberViewNotifier( ref.read(userServiceProvider), ref.read(teamServiceProvider), - ref.read(currentUserPod)?.id, ); }); @@ -24,12 +22,10 @@ class AddTeamMemberViewNotifier extends StateNotifier { final UserService _userService; final TeamService _teamService; Timer? _debounce; - final String? currentUserId; AddTeamMemberViewNotifier( this._userService, this._teamService, - this.currentUserId, ) : super(AddTeamMemberState(searchController: TextEditingController())); late TeamModel _team; @@ -63,12 +59,10 @@ class AddTeamMemberViewNotifier extends StateNotifier { } void selectUser(UserModel user) { - final player = TeamPlayer( - id: user.id, - role: (_team.created_by == currentUserId) - ? TeamPlayerRole.admin - : TeamPlayerRole.player, - user: user); + final role = (_team.created_by == user.id) + ? TeamPlayerRole.admin + : TeamPlayerRole.player; + final player = TeamPlayer(id: user.id, role: role, user: user); state = state.copyWith(selectedUsers: [...state.selectedUsers, player]); } diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart index c43d37a8..03bbe95a 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_match_content.dart @@ -1,4 +1,5 @@ import 'package:data/api/match/match_model.dart'; +import 'package:data/api/team/team_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/empty_screen.dart'; diff --git a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart index d005cb4e..f7fc1f27 100644 --- a/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart +++ b/khelo/lib/ui/flow/team/detail/components/team_detail_member_content.dart @@ -1,3 +1,4 @@ +import 'package:data/api/team/team_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/components/empty_screen.dart';