diff --git a/build_watch b/build_watch index cf7c5a96..624c789b 100755 --- a/build_watch +++ b/build_watch @@ -16,7 +16,7 @@ function keep_running { } # Navigate to each project directory and run the watcher in the background -(cd app && keep_running) & +(cd khelo && keep_running) & (cd data && keep_running) & # Wait for all background processes to finish diff --git a/data/.flutter-plugins b/data/.flutter-plugins index eb8d0f3e..89ba6518 100644 --- a/data/.flutter-plugins +++ b/data/.flutter-plugins @@ -1,5 +1,13 @@ # This is a generated file; do not edit or check into version control. +cloud_firestore=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-4.14.0/ +cloud_firestore_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.9.0/ device_info_plus=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/ +firebase_auth=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-4.16.0/ +firebase_auth_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth_web-5.8.13/ +firebase_core=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-2.24.2/ +firebase_core_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core_web-2.10.0/ +firebase_storage=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-11.6.0/ +firebase_storage_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage_web-3.6.17/ flutter_timezone=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/ package_info_plus=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/ path_provider_linux=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 6c20de1a..22f52b23 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":true,"dependencies":[]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.3.5/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":true,"dependencies":[]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.1/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":true,"dependencies":[]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.3.5/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","dependencies":[]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_web-2.2.2/","dependencies":[]}]},"dependencyGraph":[{"name":"device_info_plus","dependencies":[]},{"name":"flutter_timezone","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-01-23 10:49:28.245095","version":"3.16.8"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-4.14.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-4.16.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-2.24.2/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-11.6.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.3.5/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-4.14.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-4.16.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-2.24.2/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-11.6.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.1/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-4.14.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-4.16.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-2.24.2/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-11.6.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.3.5/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-4.14.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-4.16.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-2.24.2/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-11.6.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.9.0/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-9.1.1/","dependencies":[]},{"name":"firebase_auth_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth_web-5.8.13/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core_web-2.10.0/","dependencies":[]},{"name":"firebase_storage_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage_web-3.6.17/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-5.0.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_web-2.2.2/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-01-29 11:39:02.318944","version":"3.16.8"} \ No newline at end of file diff --git a/data/lib/api/user/user_models.dart b/data/lib/api/user/user_models.dart index a1a65dff..0e3a9dd7 100644 --- a/data/lib/api/user/user_models.dart +++ b/data/lib/api/user/user_models.dart @@ -9,39 +9,42 @@ part 'user_models.freezed.dart'; part 'user_models.g.dart'; @freezed -class User with _$User { - const User._(); +class UserModel with _$UserModel { + const UserModel._(); - const factory User({ - required int id, + const factory UserModel({ + required String id, String? name, String? location, String? phone, - String? dob, + DateTime? dob, String? email, String? profile_img_url, UserGender? gender, DateTime? created_at, DateTime? updated_at, - String? player_role, - String? batting_style, - String? bowling_style, - }) = _User; + PlayerRole? player_role, + BattingStyle? batting_style, + BowlingStyle? bowling_style, + }) = _UserModel; - factory User.fromJson(Map json) => - _$UserFromJson(json); + factory UserModel.fromJson(Map json) => + _$UserModelFromJson(json); String toJsonString() => jsonEncode(toJson()); - static User? fromJsonString(String json) => - User.fromJson(jsonDecode(json)); + String get nameInitial => name?[0].toUpperCase() ?? '?'; + + static UserModel? fromJsonString(String json) => + UserModel.fromJson(jsonDecode(json)); } @JsonEnum(valueField: "value") enum UserGender { unknown(0), male(1), - female(2); + female(2), + other(3); final int value; @@ -50,7 +53,6 @@ enum UserGender { @JsonEnum(valueField: "value") enum PlayerRole { - unknown(0), topOrderBatter(1), middleOrderBatter(2), wickerKeeperBatter(3), @@ -68,7 +70,6 @@ enum PlayerRole { @JsonEnum(valueField: "value") enum BattingStyle { - unknown(0), rightHandBat(1), leftHandBat(2); @@ -79,9 +80,15 @@ enum BattingStyle { @JsonEnum(valueField: "value") enum BowlingStyle { - unknown(0), - male(1), - female(2); + rightArmFast(0), + rightArmMedium(1), + leftArmFast(2), + leftArmMedium(3), + slowLeftArmOrthodox(4), + slowLeftArmChinaMan(5), + rightArmOffBreak(6), + rightArmLegBreak(7), + none(8); final int value; diff --git a/data/lib/api/user/user_models.freezed.dart b/data/lib/api/user/user_models.freezed.dart index 9a9a77cb..acb93601 100644 --- a/data/lib/api/user/user_models.freezed.dart +++ b/data/lib/api/user/user_models.freezed.dart @@ -14,56 +14,57 @@ 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#custom-getters-and-methods'); -User _$UserFromJson(Map json) { - return _User.fromJson(json); +UserModel _$UserModelFromJson(Map json) { + return _UserModel.fromJson(json); } /// @nodoc -mixin _$User { - int get id => throw _privateConstructorUsedError; +mixin _$UserModel { + String get id => throw _privateConstructorUsedError; String? get name => throw _privateConstructorUsedError; String? get location => throw _privateConstructorUsedError; String? get phone => throw _privateConstructorUsedError; - String? get dob => throw _privateConstructorUsedError; + DateTime? get dob => throw _privateConstructorUsedError; String? get email => throw _privateConstructorUsedError; String? get profile_img_url => throw _privateConstructorUsedError; UserGender? get gender => throw _privateConstructorUsedError; DateTime? get created_at => throw _privateConstructorUsedError; DateTime? get updated_at => throw _privateConstructorUsedError; - String? get player_role => throw _privateConstructorUsedError; - String? get batting_style => throw _privateConstructorUsedError; - String? get bowling_style => throw _privateConstructorUsedError; + PlayerRole? get player_role => throw _privateConstructorUsedError; + BattingStyle? get batting_style => throw _privateConstructorUsedError; + BowlingStyle? get bowling_style => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) - $UserCopyWith get copyWith => throw _privateConstructorUsedError; + $UserModelCopyWith get copyWith => + throw _privateConstructorUsedError; } /// @nodoc -abstract class $UserCopyWith<$Res> { - factory $UserCopyWith(User value, $Res Function(User) then) = - _$UserCopyWithImpl<$Res, User>; +abstract class $UserModelCopyWith<$Res> { + factory $UserModelCopyWith(UserModel value, $Res Function(UserModel) then) = + _$UserModelCopyWithImpl<$Res, UserModel>; @useResult $Res call( - {int id, + {String id, String? name, String? location, String? phone, - String? dob, + DateTime? dob, String? email, String? profile_img_url, UserGender? gender, DateTime? created_at, DateTime? updated_at, - String? player_role, - String? batting_style, - String? bowling_style}); + PlayerRole? player_role, + BattingStyle? batting_style, + BowlingStyle? bowling_style}); } /// @nodoc -class _$UserCopyWithImpl<$Res, $Val extends User> - implements $UserCopyWith<$Res> { - _$UserCopyWithImpl(this._value, this._then); +class _$UserModelCopyWithImpl<$Res, $Val extends UserModel> + implements $UserModelCopyWith<$Res> { + _$UserModelCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; @@ -91,7 +92,7 @@ class _$UserCopyWithImpl<$Res, $Val extends User> id: null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable - as int, + as String, name: freezed == name ? _value.name : name // ignore: cast_nullable_to_non_nullable @@ -107,7 +108,7 @@ class _$UserCopyWithImpl<$Res, $Val extends User> dob: freezed == dob ? _value.dob : dob // ignore: cast_nullable_to_non_nullable - as String?, + as DateTime?, email: freezed == email ? _value.email : email // ignore: cast_nullable_to_non_nullable @@ -131,47 +132,49 @@ class _$UserCopyWithImpl<$Res, $Val extends User> player_role: freezed == player_role ? _value.player_role : player_role // ignore: cast_nullable_to_non_nullable - as String?, + as PlayerRole?, batting_style: freezed == batting_style ? _value.batting_style : batting_style // ignore: cast_nullable_to_non_nullable - as String?, + as BattingStyle?, bowling_style: freezed == bowling_style ? _value.bowling_style : bowling_style // ignore: cast_nullable_to_non_nullable - as String?, + as BowlingStyle?, ) as $Val); } } /// @nodoc -abstract class _$$UserImplCopyWith<$Res> implements $UserCopyWith<$Res> { - factory _$$UserImplCopyWith( - _$UserImpl value, $Res Function(_$UserImpl) then) = - __$$UserImplCopyWithImpl<$Res>; +abstract class _$$UserModelImplCopyWith<$Res> + implements $UserModelCopyWith<$Res> { + factory _$$UserModelImplCopyWith( + _$UserModelImpl value, $Res Function(_$UserModelImpl) then) = + __$$UserModelImplCopyWithImpl<$Res>; @override @useResult $Res call( - {int id, + {String id, String? name, String? location, String? phone, - String? dob, + DateTime? dob, String? email, String? profile_img_url, UserGender? gender, DateTime? created_at, DateTime? updated_at, - String? player_role, - String? batting_style, - String? bowling_style}); + PlayerRole? player_role, + BattingStyle? batting_style, + BowlingStyle? bowling_style}); } /// @nodoc -class __$$UserImplCopyWithImpl<$Res> - extends _$UserCopyWithImpl<$Res, _$UserImpl> - implements _$$UserImplCopyWith<$Res> { - __$$UserImplCopyWithImpl(_$UserImpl _value, $Res Function(_$UserImpl) _then) +class __$$UserModelImplCopyWithImpl<$Res> + extends _$UserModelCopyWithImpl<$Res, _$UserModelImpl> + implements _$$UserModelImplCopyWith<$Res> { + __$$UserModelImplCopyWithImpl( + _$UserModelImpl _value, $Res Function(_$UserModelImpl) _then) : super(_value, _then); @pragma('vm:prefer-inline') @@ -191,11 +194,11 @@ class __$$UserImplCopyWithImpl<$Res> Object? batting_style = freezed, Object? bowling_style = freezed, }) { - return _then(_$UserImpl( + return _then(_$UserModelImpl( id: null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable - as int, + as String, name: freezed == name ? _value.name : name // ignore: cast_nullable_to_non_nullable @@ -211,7 +214,7 @@ class __$$UserImplCopyWithImpl<$Res> dob: freezed == dob ? _value.dob : dob // ignore: cast_nullable_to_non_nullable - as String?, + as DateTime?, email: freezed == email ? _value.email : email // ignore: cast_nullable_to_non_nullable @@ -235,23 +238,23 @@ class __$$UserImplCopyWithImpl<$Res> player_role: freezed == player_role ? _value.player_role : player_role // ignore: cast_nullable_to_non_nullable - as String?, + as PlayerRole?, batting_style: freezed == batting_style ? _value.batting_style : batting_style // ignore: cast_nullable_to_non_nullable - as String?, + as BattingStyle?, bowling_style: freezed == bowling_style ? _value.bowling_style : bowling_style // ignore: cast_nullable_to_non_nullable - as String?, + as BowlingStyle?, )); } } /// @nodoc @JsonSerializable() -class _$UserImpl extends _User { - const _$UserImpl( +class _$UserModelImpl extends _UserModel { + const _$UserModelImpl( {required this.id, this.name, this.location, @@ -267,11 +270,11 @@ class _$UserImpl extends _User { this.bowling_style}) : super._(); - factory _$UserImpl.fromJson(Map json) => - _$$UserImplFromJson(json); + factory _$UserModelImpl.fromJson(Map json) => + _$$UserModelImplFromJson(json); @override - final int id; + final String id; @override final String? name; @override @@ -279,7 +282,7 @@ class _$UserImpl extends _User { @override final String? phone; @override - final String? dob; + final DateTime? dob; @override final String? email; @override @@ -291,22 +294,22 @@ class _$UserImpl extends _User { @override final DateTime? updated_at; @override - final String? player_role; + final PlayerRole? player_role; @override - final String? batting_style; + final BattingStyle? batting_style; @override - final String? bowling_style; + final BowlingStyle? bowling_style; @override String toString() { - return 'User(id: $id, name: $name, location: $location, phone: $phone, dob: $dob, email: $email, profile_img_url: $profile_img_url, gender: $gender, created_at: $created_at, updated_at: $updated_at, player_role: $player_role, batting_style: $batting_style, bowling_style: $bowling_style)'; + return 'UserModel(id: $id, name: $name, location: $location, phone: $phone, dob: $dob, email: $email, profile_img_url: $profile_img_url, gender: $gender, created_at: $created_at, updated_at: $updated_at, player_role: $player_role, batting_style: $batting_style, bowling_style: $bowling_style)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$UserImpl && + other is _$UserModelImpl && (identical(other.id, id) || other.id == id) && (identical(other.name, name) || other.name == name) && (identical(other.location, location) || @@ -350,38 +353,39 @@ class _$UserImpl extends _User { @JsonKey(ignore: true) @override @pragma('vm:prefer-inline') - _$$UserImplCopyWith<_$UserImpl> get copyWith => - __$$UserImplCopyWithImpl<_$UserImpl>(this, _$identity); + _$$UserModelImplCopyWith<_$UserModelImpl> get copyWith => + __$$UserModelImplCopyWithImpl<_$UserModelImpl>(this, _$identity); @override Map toJson() { - return _$$UserImplToJson( + return _$$UserModelImplToJson( this, ); } } -abstract class _User extends User { - const factory _User( - {required final int id, +abstract class _UserModel extends UserModel { + const factory _UserModel( + {required final String id, final String? name, final String? location, final String? phone, - final String? dob, + final DateTime? dob, final String? email, final String? profile_img_url, final UserGender? gender, final DateTime? created_at, final DateTime? updated_at, - final String? player_role, - final String? batting_style, - final String? bowling_style}) = _$UserImpl; - const _User._() : super._(); + final PlayerRole? player_role, + final BattingStyle? batting_style, + final BowlingStyle? bowling_style}) = _$UserModelImpl; + const _UserModel._() : super._(); - factory _User.fromJson(Map json) = _$UserImpl.fromJson; + factory _UserModel.fromJson(Map json) = + _$UserModelImpl.fromJson; @override - int get id; + String get id; @override String? get name; @override @@ -389,7 +393,7 @@ abstract class _User extends User { @override String? get phone; @override - String? get dob; + DateTime? get dob; @override String? get email; @override @@ -401,13 +405,13 @@ abstract class _User extends User { @override DateTime? get updated_at; @override - String? get player_role; + PlayerRole? get player_role; @override - String? get batting_style; + BattingStyle? get batting_style; @override - String? get bowling_style; + BowlingStyle? get bowling_style; @override @JsonKey(ignore: true) - _$$UserImplCopyWith<_$UserImpl> get copyWith => + _$$UserModelImplCopyWith<_$UserModelImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/data/lib/api/user/user_models.g.dart b/data/lib/api/user/user_models.g.dart index 8fadfad9..8bfb5963 100644 --- a/data/lib/api/user/user_models.g.dart +++ b/data/lib/api/user/user_models.g.dart @@ -6,12 +6,13 @@ part of 'user_models.dart'; // JsonSerializableGenerator // ************************************************************************** -_$UserImpl _$$UserImplFromJson(Map json) => _$UserImpl( - id: json['id'] as int, +_$UserModelImpl _$$UserModelImplFromJson(Map json) => + _$UserModelImpl( + id: json['id'] as String, name: json['name'] as String?, location: json['location'] as String?, phone: json['phone'] as String?, - dob: json['dob'] as String?, + dob: json['dob'] == null ? null : DateTime.parse(json['dob'] as String), email: json['email'] as String?, profile_img_url: json['profile_img_url'] as String?, gender: $enumDecodeNullable(_$UserGenderEnumMap, json['gender']), @@ -21,30 +22,63 @@ _$UserImpl _$$UserImplFromJson(Map json) => _$UserImpl( updated_at: json['updated_at'] == null ? null : DateTime.parse(json['updated_at'] as String), - player_role: json['player_role'] as String?, - batting_style: json['batting_style'] as String?, - bowling_style: json['bowling_style'] as String?, + player_role: + $enumDecodeNullable(_$PlayerRoleEnumMap, json['player_role']), + batting_style: + $enumDecodeNullable(_$BattingStyleEnumMap, json['batting_style']), + bowling_style: + $enumDecodeNullable(_$BowlingStyleEnumMap, json['bowling_style']), ); -Map _$$UserImplToJson(_$UserImpl instance) => +Map _$$UserModelImplToJson(_$UserModelImpl instance) => { 'id': instance.id, 'name': instance.name, 'location': instance.location, 'phone': instance.phone, - 'dob': instance.dob, + 'dob': instance.dob?.toIso8601String(), 'email': instance.email, 'profile_img_url': instance.profile_img_url, 'gender': _$UserGenderEnumMap[instance.gender], 'created_at': instance.created_at?.toIso8601String(), 'updated_at': instance.updated_at?.toIso8601String(), - 'player_role': instance.player_role, - 'batting_style': instance.batting_style, - 'bowling_style': instance.bowling_style, + 'player_role': _$PlayerRoleEnumMap[instance.player_role], + 'batting_style': _$BattingStyleEnumMap[instance.batting_style], + 'bowling_style': _$BowlingStyleEnumMap[instance.bowling_style], }; const _$UserGenderEnumMap = { UserGender.unknown: 0, UserGender.male: 1, UserGender.female: 2, + UserGender.other: 3, +}; + +const _$PlayerRoleEnumMap = { + PlayerRole.topOrderBatter: 1, + PlayerRole.middleOrderBatter: 2, + PlayerRole.wickerKeeperBatter: 3, + PlayerRole.wicketKeeper: 4, + PlayerRole.bowler: 5, + PlayerRole.allRounder: 6, + PlayerRole.lowerOrderBatter: 7, + PlayerRole.openingBatter: 8, + PlayerRole.none: 9, +}; + +const _$BattingStyleEnumMap = { + BattingStyle.rightHandBat: 1, + BattingStyle.leftHandBat: 2, +}; + +const _$BowlingStyleEnumMap = { + BowlingStyle.rightArmFast: 0, + BowlingStyle.rightArmMedium: 1, + BowlingStyle.leftArmFast: 2, + BowlingStyle.leftArmMedium: 3, + BowlingStyle.slowLeftArmOrthodox: 4, + BowlingStyle.slowLeftArmChinaMan: 5, + BowlingStyle.rightArmOffBreak: 6, + BowlingStyle.rightArmLegBreak: 7, + BowlingStyle.none: 8, }; diff --git a/data/lib/service/auth/auth_service.dart b/data/lib/service/auth/auth_service.dart new file mode 100644 index 00000000..83c04f2c --- /dev/null +++ b/data/lib/service/auth/auth_service.dart @@ -0,0 +1,69 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final authServiceProvider = Provider((ref) { + return AuthService(FirebaseAuth.instance); +}); + +class AuthService { + final FirebaseAuth _auth; + + AuthService(this._auth); + + Stream get user => _auth.authStateChanges(); + + // Future signInWithPhoneNumber( + // String verificationId, String smsCode) async { + // AuthCredential credential = PhoneAuthProvider.credential( + // verificationId: verificationId, + // smsCode: smsCode, + // ); + // await _auth.signInWithCredential(credential); + // // Update user details in Fire-store after successful sign-in + // // await _updateUserData(); + // } + // + // Future signUpWithPhoneNumber( + // String verificationId, String smsCode, String additionalDetails) async { + // AuthCredential credential = PhoneAuthProvider.credential( + // verificationId: verificationId, + // smsCode: smsCode, + // ); + // await _auth.signInWithCredential(credential); + // // Update user details in Fire-store after successful sign-up + // // await _updateUserData(additionalDetails); + // } + + Future verifyPhoneNumber({ + required String phoneNumber, + Function(String, int?)? onCodeSent, + Function(PhoneAuthCredential)? onVerificationCompleted, + Function(FirebaseAuthException)? onVerificationFailed, + Function(String)? onCodeAutoRetrievalTimeout, + }) async { + await _auth.verifyPhoneNumber( + phoneNumber: phoneNumber, + verificationCompleted: (PhoneAuthCredential credential) async { + // Automatically sign in the user if verification is successful + await _auth.signInWithCredential(credential); + // whole process here and then call + onVerificationCompleted != null + ? onVerificationCompleted(credential) + : null; + }, + verificationFailed: (FirebaseAuthException e) => + onVerificationFailed != null ? onVerificationFailed(e) : null, + codeSent: (String verificationId, int? resendToken) => + onCodeSent != null ? onCodeSent(verificationId, resendToken) : null, + codeAutoRetrievalTimeout: (verificationId) => + onCodeAutoRetrievalTimeout != null + ? onCodeAutoRetrievalTimeout(verificationId) + : null, + ); + } + + Future signOut() async { + await _auth.signOut(); + // make user null here + } +} diff --git a/data/lib/service/file_upload/file_upload_service.dart b/data/lib/service/file_upload/file_upload_service.dart new file mode 100644 index 00000000..760b9cd7 --- /dev/null +++ b/data/lib/service/file_upload/file_upload_service.dart @@ -0,0 +1,37 @@ +import 'dart:io'; + +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:path/path.dart' as path; + +final fileUploadServiceProvider = Provider( + (ref) => FileUploadService(FirebaseStorage.instance), +); + +class FileUploadService { + final FirebaseStorage _firebaseStorage; + + FileUploadService(this._firebaseStorage); + + Future uploadProfileImage(String imagePath) async { + var file = File(imagePath); + if (await file.exists()) { + String fileExtension = path.extension(file.path); + DateTime currentDate = DateTime.now(); + String imgName = + "IMG_${currentDate.year}${currentDate.month}${currentDate.day}${currentDate.hour}${currentDate.minute}${currentDate.second}${currentDate.millisecond}$fileExtension"; + var snapshot = await _firebaseStorage + .ref() + .child('UserProfileImages/$imgName') + .putFile(file); // TODO: resolve rules of firebase storage and fireStore + var downloadUrl = await snapshot.ref.getDownloadURL(); + return downloadUrl; + } else { + throw Exception("UploadProfileImage: file doesn't exist"); + } + } + + Future deleteUploadedProfileImage(String imgUrl) async { + await _firebaseStorage.refFromURL(imgUrl).delete(); + } +} diff --git a/data/lib/service/user/user_service.dart b/data/lib/service/user/user_service.dart index 41fef06e..0af93d6c 100644 --- a/data/lib/service/user/user_service.dart +++ b/data/lib/service/user/user_service.dart @@ -1,22 +1,53 @@ +import 'package:cloud_firestore/cloud_firestore.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(); + final service = UserService(ref.read(currentUserPod), + ref.read(currentUserJsonPod.notifier), FirebaseFirestore.instance); + ref.listen(currentUserPod, (_, next) => service.currentUser = next); return service; }); class UserService { - User? currentUser; -/* -// caller function here - func callerFunctionCalledFromNotifier(){ - var response = await funcThatInternallyDoTheseStuff(); - parse the response - return the response - } -*/ -} \ No newline at end of file + UserModel? currentUser; + final StateController currentUserJsonController; + final FirebaseFirestore _firestore; + final String collectionName = 'users'; + + UserService( + this.currentUser, this.currentUserJsonController, this._firestore); + + Future addUser(UserModel user) async { + await _firestore.collection(collectionName).add(user.toJson()); + } + + Future deleteUser() async { + await _firestore.collection(collectionName).doc(currentUser?.id).delete(); + currentUserJsonController.state = null; + } + + Future updateUser(UserModel user) async { + DocumentReference userRef = + _firestore.collection(collectionName).doc(user.id); + + await userRef.set(user.toJson(), SetOptions(merge: true)); + + currentUserJsonController.state = user.toJsonString(); + } + + Future getUser(String id) async { + DocumentReference userRef = _firestore.collection(collectionName).doc(id); + DocumentSnapshot snapshot = await userRef.get(); + Map userData = snapshot.data() as Map; + var tempUser = UserModel.fromJson(userData); + currentUserJsonController.state = tempUser.toJsonString(); + } + + void signOutUser() { + currentUserJsonController.state = null; + } +} diff --git a/data/lib/storage/app_preferences.dart b/data/lib/storage/app_preferences.dart index 878f64a9..b4b5a78c 100644 --- a/data/lib/storage/app_preferences.dart +++ b/data/lib/storage/app_preferences.dart @@ -8,9 +8,9 @@ final currentUserJsonPod = createPrefProvider( defaultValue: null, ); -final currentUserPod = Provider((ref) { +final currentUserPod = Provider((ref) { final json = ref.watch(currentUserJsonPod); - return json == null ? null : User.fromJsonString(json); + return json == null ? null : UserModel.fromJsonString(json); }); final hasUserSession = Provider((ref) => ref.watch(currentUserPod) != null); diff --git a/data/pubspec.yaml b/data/pubspec.yaml index 8a874d60..f3a10a9a 100644 --- a/data/pubspec.yaml +++ b/data/pubspec.yaml @@ -13,6 +13,14 @@ dependencies: shared_preferences: ^2.0.18 + # storage + firebase_storage: ^11.6.0 + cloud_firestore: ^4.14.0 + + # auth + firebase_core: ^2.24.2 + firebase_auth: ^4.16.0 + # io dio: ^5.0.2 json_annotation: ^4.8.1 @@ -23,10 +31,11 @@ dependencies: device_info_plus: ^9.1.1 package_info_plus: ^5.0.1 flutter_timezone: ^1.0.8 + path: ^1.8.3 # state management - flutter_riverpod: ^2.3.1 - hooks_riverpod: ^2.3.1 + flutter_riverpod: ^2.4.9 + hooks_riverpod: ^2.4.9 dev_dependencies: flutter_test: diff --git a/khelo/android/app/build.gradle b/khelo/android/app/build.gradle index 9e415127..3fc7abe3 100644 --- a/khelo/android/app/build.gradle +++ b/khelo/android/app/build.gradle @@ -49,6 +49,7 @@ android { targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } buildTypes { diff --git a/khelo/assets/images/ic_camera.png b/khelo/assets/images/ic_camera.png new file mode 100644 index 00000000..c82fffb0 Binary files /dev/null and b/khelo/assets/images/ic_camera.png differ diff --git a/khelo/assets/images/ic_gallery.png b/khelo/assets/images/ic_gallery.png new file mode 100644 index 00000000..20fe2132 Binary files /dev/null and b/khelo/assets/images/ic_gallery.png differ diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index 23c939de..4228d629 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -5,6 +5,23 @@ "tab_stats_title": "stats", "tab_profile_title": "profile", + "common_none_title":"None", + "common_anonymous_title":"Anonymous", + "common_delete_title":"Delete", + "common_cancel_title":"Cancel", + "common_sign_out_title":"Sign out", + + "alert_confirm_default_title": "Are you sure?", + "alert_confirm_default_message": "Are you sure you want to {deleteText}?", + "@alert_confirm_default_message": { + "description": "Are you sure you want to {deleteText}?", + "placeholders": { + "deleteText": { + "type": "String" + } + } + }, + "intro_sign_in_btn_text": "Sign in", "intro_get_start_text": "Getting started with us", "intro_description_text": "get started with Khelo, create your team, start the match, score your match, get your stats and much more.\nEmbark on a journey beyond imagination, where every move is a new adventure!\nPlay. Thrive. Conquer.", @@ -17,5 +34,46 @@ "otp_verification_enter_otp_text": "Enter OTP you received", "otp_verification_resend_code_text": "Resend Code", - "edit_profile_screen_title": "Edit profile" + "edit_profile_screen_title": "Edit profile", + "edit_profile_select_birth_date_placeholder": "Select your date of birth", + "edit_profile_name_placeholder": "NAME", + "edit_profile_email_placeholder": "EMAIL", + "edit_profile_location_placeholder": "LOCATION", + "edit_profile_dob_placeholder": "DOB", + "edit_profile_gender_placeholder": "GENDER", + "edit_profile_player_role_placeholder": "PLAYER ROLE", + "edit_profile_batting_style_placeholder": "BATTING STYLE", + "edit_profile_bowling_style_placeholder": "BOWLING STYLE", + "edit_profile_gender_male_title": "Male", + "edit_profile_gender_female_title": "Female", + "edit_profile_gender_other_title": "Other", + "edit_profile_save_title": "SAVE", + "edit_profile_choose_option_title": "Choose an option.", + "edit_profile_crop_image_title": "Crop Image", + + + "batting_style_right_hand_bat_title": "Right hand bat", + "batting_style_left_hand_bat_title": "Left hand bat", + + "bowling_style_right_arm_fast_title": "Right arm fast", + "bowling_style_right_arm_medium_title": "Right arm medium", + "bowling_style_left_arm_fast_title": "Left arm fast", + "bowling_style_left_arm_medium_title": "Left arm medium", + "bowling_style_slow_left_arm_orthodox_title": "Slow left arm orthodox", + "bowling_style_slow_left_arm_chinaman_title": "Slow left arm chinaman", + "bowling_style_right_arm_off_break_title": "Right arm off break", + "bowling_style_right_arm_leg_break_title": "Right arm leg break", + + "player_role_top_order_batter_title": "Top order batter", + "player_role_middle_order_batter_title": "Middle order batter", + "player_role_wicket_keeper_batter_title": "Wicket keeper batter", + "player_role_wicket_keeper_title": "Wicket keeper", + "player_role_bowler_title": "Bowler", + "player_role_all_rounder_title": "All rounder", + "player_role_lower_order_batter_title": "Lower order batter", + "player_role_opening_batter_title": "Opening batter", + + "profile_complete_your_profile_title": "Complete Your Profile", + "profile_complete_profile_description_title": "Enhance your profile by filling in the remaining details. Let's make it more comprehensive and appealing.", + "profile_complete_profile_btn_title": "Complete Profile" } \ No newline at end of file diff --git a/khelo/ios/Podfile.lock b/khelo/ios/Podfile.lock index 31d8035f..d46fca1e 100644 --- a/khelo/ios/Podfile.lock +++ b/khelo/ios/Podfile.lock @@ -1,4 +1,644 @@ PODS: + - abseil/algorithm (1.20220623.0): + - abseil/algorithm/algorithm (= 1.20220623.0) + - abseil/algorithm/container (= 1.20220623.0) + - abseil/algorithm/algorithm (1.20220623.0): + - abseil/base/config + - abseil/algorithm/container (1.20220623.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/base (1.20220623.0): + - abseil/base/atomic_hook (= 1.20220623.0) + - abseil/base/base (= 1.20220623.0) + - abseil/base/base_internal (= 1.20220623.0) + - abseil/base/config (= 1.20220623.0) + - abseil/base/core_headers (= 1.20220623.0) + - abseil/base/dynamic_annotations (= 1.20220623.0) + - abseil/base/endian (= 1.20220623.0) + - abseil/base/errno_saver (= 1.20220623.0) + - abseil/base/fast_type_id (= 1.20220623.0) + - abseil/base/log_severity (= 1.20220623.0) + - abseil/base/malloc_internal (= 1.20220623.0) + - abseil/base/prefetch (= 1.20220623.0) + - abseil/base/pretty_function (= 1.20220623.0) + - abseil/base/raw_logging_internal (= 1.20220623.0) + - abseil/base/spinlock_wait (= 1.20220623.0) + - abseil/base/strerror (= 1.20220623.0) + - abseil/base/throw_delegate (= 1.20220623.0) + - abseil/base/atomic_hook (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/base (1.20220623.0): + - abseil/base/atomic_hook + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/log_severity + - abseil/base/raw_logging_internal + - abseil/base/spinlock_wait + - abseil/meta/type_traits + - abseil/base/base_internal (1.20220623.0): + - abseil/base/config + - abseil/meta/type_traits + - abseil/base/config (1.20220623.0) + - abseil/base/core_headers (1.20220623.0): + - abseil/base/config + - abseil/base/dynamic_annotations (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/base/errno_saver (1.20220623.0): + - abseil/base/config + - abseil/base/fast_type_id (1.20220623.0): + - abseil/base/config + - abseil/base/log_severity (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/malloc_internal (1.20220623.0): + - abseil/base/base + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/raw_logging_internal + - abseil/base/prefetch (1.20220623.0): + - abseil/base/config + - abseil/base/pretty_function (1.20220623.0) + - abseil/base/raw_logging_internal (1.20220623.0): + - abseil/base/atomic_hook + - abseil/base/config + - abseil/base/core_headers + - abseil/base/errno_saver + - abseil/base/log_severity + - abseil/base/spinlock_wait (1.20220623.0): + - abseil/base/base_internal + - abseil/base/core_headers + - abseil/base/errno_saver + - abseil/base/strerror (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/errno_saver + - abseil/base/throw_delegate (1.20220623.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/cleanup/cleanup (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/cleanup/cleanup_internal + - abseil/cleanup/cleanup_internal (1.20220623.0): + - abseil/base/base_internal + - abseil/base/core_headers + - abseil/utility/utility + - abseil/container/common (1.20220623.0): + - abseil/meta/type_traits + - abseil/types/optional + - abseil/container/compressed_tuple (1.20220623.0): + - abseil/utility/utility + - abseil/container/container_memory (1.20220623.0): + - abseil/base/config + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/utility/utility + - abseil/container/fixed_array (1.20220623.0): + - abseil/algorithm/algorithm + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/throw_delegate + - abseil/container/compressed_tuple + - abseil/memory/memory + - abseil/container/flat_hash_map (1.20220623.0): + - abseil/algorithm/container + - abseil/base/core_headers + - abseil/container/container_memory + - abseil/container/hash_function_defaults + - abseil/container/raw_hash_map + - abseil/memory/memory + - abseil/container/flat_hash_set (1.20220623.0): + - abseil/algorithm/container + - abseil/base/core_headers + - abseil/container/container_memory + - abseil/container/hash_function_defaults + - abseil/container/raw_hash_set + - abseil/memory/memory + - abseil/container/hash_function_defaults (1.20220623.0): + - abseil/base/config + - abseil/hash/hash + - abseil/strings/cord + - abseil/strings/strings + - abseil/container/hash_policy_traits (1.20220623.0): + - abseil/meta/type_traits + - abseil/container/hashtable_debug_hooks (1.20220623.0): + - abseil/base/config + - abseil/container/hashtablez_sampler (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/debugging/stacktrace + - abseil/memory/memory + - abseil/profiling/exponential_biased + - abseil/profiling/sample_recorder + - abseil/synchronization/synchronization + - abseil/utility/utility + - abseil/container/inlined_vector (1.20220623.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/base/throw_delegate + - abseil/container/inlined_vector_internal + - abseil/memory/memory + - abseil/container/inlined_vector_internal (1.20220623.0): + - abseil/base/core_headers + - abseil/container/compressed_tuple + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/types/span + - abseil/container/layout (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/strings/strings + - abseil/types/span + - abseil/utility/utility + - abseil/container/raw_hash_map (1.20220623.0): + - abseil/base/throw_delegate + - abseil/container/container_memory + - abseil/container/raw_hash_set + - abseil/container/raw_hash_set (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/prefetch + - abseil/container/common + - abseil/container/compressed_tuple + - abseil/container/container_memory + - abseil/container/hash_policy_traits + - abseil/container/hashtable_debug_hooks + - abseil/container/hashtablez_sampler + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/numeric/bits + - abseil/utility/utility + - abseil/debugging/debugging_internal (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/errno_saver + - abseil/base/raw_logging_internal + - abseil/debugging/demangle_internal (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/debugging/stacktrace (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/debugging/debugging_internal + - abseil/debugging/symbolize (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/malloc_internal + - abseil/base/raw_logging_internal + - abseil/debugging/debugging_internal + - abseil/debugging/demangle_internal + - abseil/strings/strings + - abseil/functional/any_invocable (1.20220623.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/utility/utility + - abseil/functional/bind_front (1.20220623.0): + - abseil/base/base_internal + - abseil/container/compressed_tuple + - abseil/meta/type_traits + - abseil/utility/utility + - abseil/functional/function_ref (1.20220623.0): + - abseil/base/base_internal + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/hash/city (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/hash/hash (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/container/fixed_array + - abseil/functional/function_ref + - abseil/hash/city + - abseil/hash/low_level_hash + - abseil/meta/type_traits + - abseil/numeric/int128 + - abseil/strings/strings + - abseil/types/optional + - abseil/types/variant + - abseil/utility/utility + - abseil/hash/low_level_hash (1.20220623.0): + - abseil/base/config + - abseil/base/endian + - abseil/numeric/bits + - abseil/numeric/int128 + - abseil/memory (1.20220623.0): + - abseil/memory/memory (= 1.20220623.0) + - abseil/memory/memory (1.20220623.0): + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/meta (1.20220623.0): + - abseil/meta/type_traits (= 1.20220623.0) + - abseil/meta/type_traits (1.20220623.0): + - abseil/base/config + - abseil/numeric/bits (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/numeric/int128 (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/numeric/bits + - abseil/numeric/representation (1.20220623.0): + - abseil/base/config + - abseil/profiling/exponential_biased (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/profiling/sample_recorder (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/synchronization/synchronization + - abseil/time/time + - abseil/random/distributions (1.20220623.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/numeric/bits + - abseil/random/internal/distribution_caller + - abseil/random/internal/fast_uniform_bits + - abseil/random/internal/fastmath + - abseil/random/internal/generate_real + - abseil/random/internal/iostream_state_saver + - abseil/random/internal/traits + - abseil/random/internal/uniform_helper + - abseil/random/internal/wide_multiply + - abseil/strings/strings + - abseil/random/internal/distribution_caller (1.20220623.0): + - abseil/base/config + - abseil/base/fast_type_id + - abseil/utility/utility + - abseil/random/internal/fast_uniform_bits (1.20220623.0): + - abseil/base/config + - abseil/meta/type_traits + - abseil/random/internal/traits + - abseil/random/internal/fastmath (1.20220623.0): + - abseil/numeric/bits + - abseil/random/internal/generate_real (1.20220623.0): + - abseil/meta/type_traits + - abseil/numeric/bits + - abseil/random/internal/fastmath + - abseil/random/internal/traits + - abseil/random/internal/iostream_state_saver (1.20220623.0): + - abseil/meta/type_traits + - abseil/numeric/int128 + - abseil/random/internal/nonsecure_base (1.20220623.0): + - abseil/base/core_headers + - abseil/container/inlined_vector + - abseil/meta/type_traits + - abseil/random/internal/pool_urbg + - abseil/random/internal/salted_seed_seq + - abseil/random/internal/seed_material + - abseil/types/span + - abseil/random/internal/pcg_engine (1.20220623.0): + - abseil/base/config + - abseil/meta/type_traits + - abseil/numeric/bits + - abseil/numeric/int128 + - abseil/random/internal/fastmath + - abseil/random/internal/iostream_state_saver + - abseil/random/internal/platform (1.20220623.0): + - abseil/base/config + - abseil/random/internal/pool_urbg (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/random/internal/randen + - abseil/random/internal/seed_material + - abseil/random/internal/traits + - abseil/random/seed_gen_exception + - abseil/types/span + - abseil/random/internal/randen (1.20220623.0): + - abseil/base/raw_logging_internal + - abseil/random/internal/platform + - abseil/random/internal/randen_hwaes + - abseil/random/internal/randen_slow + - abseil/random/internal/randen_engine (1.20220623.0): + - abseil/base/endian + - abseil/meta/type_traits + - abseil/random/internal/iostream_state_saver + - abseil/random/internal/randen + - abseil/random/internal/randen_hwaes (1.20220623.0): + - abseil/base/config + - abseil/random/internal/platform + - abseil/random/internal/randen_hwaes_impl + - abseil/random/internal/randen_hwaes_impl (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/numeric/int128 + - abseil/random/internal/platform + - abseil/random/internal/randen_slow (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/numeric/int128 + - abseil/random/internal/platform + - abseil/random/internal/salted_seed_seq (1.20220623.0): + - abseil/container/inlined_vector + - abseil/meta/type_traits + - abseil/random/internal/seed_material + - abseil/types/optional + - abseil/types/span + - abseil/random/internal/seed_material (1.20220623.0): + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/raw_logging_internal + - abseil/random/internal/fast_uniform_bits + - abseil/strings/strings + - abseil/types/optional + - abseil/types/span + - abseil/random/internal/traits (1.20220623.0): + - abseil/base/config + - abseil/numeric/bits + - abseil/numeric/int128 + - abseil/random/internal/uniform_helper (1.20220623.0): + - abseil/base/config + - abseil/meta/type_traits + - abseil/numeric/int128 + - abseil/random/internal/traits + - abseil/random/internal/wide_multiply (1.20220623.0): + - abseil/base/config + - abseil/numeric/bits + - abseil/numeric/int128 + - abseil/random/internal/traits + - abseil/random/random (1.20220623.0): + - abseil/random/distributions + - abseil/random/internal/nonsecure_base + - abseil/random/internal/pcg_engine + - abseil/random/internal/pool_urbg + - abseil/random/internal/randen_engine + - abseil/random/seed_sequences + - abseil/random/seed_gen_exception (1.20220623.0): + - abseil/base/config + - abseil/random/seed_sequences (1.20220623.0): + - abseil/base/config + - abseil/random/internal/pool_urbg + - abseil/random/internal/salted_seed_seq + - abseil/random/internal/seed_material + - abseil/random/seed_gen_exception + - abseil/types/span + - abseil/status/status (1.20220623.0): + - abseil/base/atomic_hook + - abseil/base/core_headers + - abseil/base/raw_logging_internal + - abseil/base/strerror + - abseil/container/inlined_vector + - abseil/debugging/stacktrace + - abseil/debugging/symbolize + - abseil/functional/function_ref + - abseil/strings/cord + - abseil/strings/str_format + - abseil/strings/strings + - abseil/types/optional + - abseil/status/statusor (1.20220623.0): + - abseil/base/base + - abseil/base/core_headers + - abseil/base/raw_logging_internal + - abseil/meta/type_traits + - abseil/status/status + - abseil/strings/strings + - abseil/types/variant + - abseil/utility/utility + - abseil/strings/cord (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/container/fixed_array + - abseil/container/inlined_vector + - abseil/functional/function_ref + - abseil/meta/type_traits + - abseil/numeric/bits + - abseil/strings/cord_internal + - abseil/strings/cordz_functions + - abseil/strings/cordz_info + - abseil/strings/cordz_statistics + - abseil/strings/cordz_update_scope + - abseil/strings/cordz_update_tracker + - abseil/strings/internal + - abseil/strings/str_format + - abseil/strings/strings + - abseil/types/optional + - abseil/types/span + - abseil/strings/cord_internal (1.20220623.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/base/throw_delegate + - abseil/container/compressed_tuple + - abseil/container/inlined_vector + - abseil/container/layout + - abseil/functional/function_ref + - abseil/meta/type_traits + - abseil/strings/strings + - abseil/types/span + - abseil/strings/cordz_functions (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/raw_logging_internal + - abseil/profiling/exponential_biased + - abseil/strings/cordz_handle (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/synchronization/synchronization + - abseil/strings/cordz_info (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/base/raw_logging_internal + - abseil/container/inlined_vector + - abseil/debugging/stacktrace + - abseil/strings/cord_internal + - abseil/strings/cordz_functions + - abseil/strings/cordz_handle + - abseil/strings/cordz_statistics + - abseil/strings/cordz_update_tracker + - abseil/synchronization/synchronization + - abseil/types/span + - abseil/strings/cordz_statistics (1.20220623.0): + - abseil/base/config + - abseil/strings/cordz_update_tracker + - abseil/strings/cordz_update_scope (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/strings/cord_internal + - abseil/strings/cordz_info + - abseil/strings/cordz_update_tracker + - abseil/strings/cordz_update_tracker (1.20220623.0): + - abseil/base/config + - abseil/strings/internal (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/meta/type_traits + - abseil/strings/str_format (1.20220623.0): + - abseil/strings/str_format_internal + - abseil/strings/str_format_internal (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/functional/function_ref + - abseil/meta/type_traits + - abseil/numeric/bits + - abseil/numeric/int128 + - abseil/numeric/representation + - abseil/strings/strings + - abseil/types/optional + - abseil/types/span + - abseil/utility/utility + - abseil/strings/strings (1.20220623.0): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/base/throw_delegate + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/numeric/bits + - abseil/numeric/int128 + - abseil/strings/internal + - abseil/synchronization/graphcycles_internal (1.20220623.0): + - abseil/base/base + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/malloc_internal + - abseil/base/raw_logging_internal + - abseil/synchronization/kernel_timeout_internal (1.20220623.0): + - abseil/base/core_headers + - abseil/base/raw_logging_internal + - abseil/time/time + - abseil/synchronization/synchronization (1.20220623.0): + - abseil/base/atomic_hook + - abseil/base/base + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/malloc_internal + - abseil/base/raw_logging_internal + - abseil/debugging/stacktrace + - abseil/debugging/symbolize + - abseil/synchronization/graphcycles_internal + - abseil/synchronization/kernel_timeout_internal + - abseil/time/time + - abseil/time (1.20220623.0): + - abseil/time/internal (= 1.20220623.0) + - abseil/time/time (= 1.20220623.0) + - abseil/time/internal (1.20220623.0): + - abseil/time/internal/cctz (= 1.20220623.0) + - abseil/time/internal/cctz (1.20220623.0): + - abseil/time/internal/cctz/civil_time (= 1.20220623.0) + - abseil/time/internal/cctz/time_zone (= 1.20220623.0) + - abseil/time/internal/cctz/civil_time (1.20220623.0): + - abseil/base/config + - abseil/time/internal/cctz/time_zone (1.20220623.0): + - abseil/base/config + - abseil/time/internal/cctz/civil_time + - abseil/time/time (1.20220623.0): + - abseil/base/base + - abseil/base/core_headers + - abseil/base/raw_logging_internal + - abseil/numeric/int128 + - abseil/strings/strings + - abseil/time/internal/cctz/civil_time + - abseil/time/internal/cctz/time_zone + - abseil/types (1.20220623.0): + - abseil/types/any (= 1.20220623.0) + - abseil/types/bad_any_cast (= 1.20220623.0) + - abseil/types/bad_any_cast_impl (= 1.20220623.0) + - abseil/types/bad_optional_access (= 1.20220623.0) + - abseil/types/bad_variant_access (= 1.20220623.0) + - abseil/types/compare (= 1.20220623.0) + - abseil/types/optional (= 1.20220623.0) + - abseil/types/span (= 1.20220623.0) + - abseil/types/variant (= 1.20220623.0) + - abseil/types/any (1.20220623.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/fast_type_id + - abseil/meta/type_traits + - abseil/types/bad_any_cast + - abseil/utility/utility + - abseil/types/bad_any_cast (1.20220623.0): + - abseil/base/config + - abseil/types/bad_any_cast_impl + - abseil/types/bad_any_cast_impl (1.20220623.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/bad_optional_access (1.20220623.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/bad_variant_access (1.20220623.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/compare (1.20220623.0): + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/optional (1.20220623.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/types/bad_optional_access + - abseil/utility/utility + - abseil/types/span (1.20220623.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/base/throw_delegate + - abseil/meta/type_traits + - abseil/types/variant (1.20220623.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/bad_variant_access + - abseil/utility/utility + - abseil/utility/utility (1.20220623.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/meta/type_traits + - BoringSSL-GRPC (0.0.24): + - BoringSSL-GRPC/Implementation (= 0.0.24) + - BoringSSL-GRPC/Interface (= 0.0.24) + - BoringSSL-GRPC/Implementation (0.0.24): + - BoringSSL-GRPC/Interface (= 0.0.24) + - BoringSSL-GRPC/Interface (0.0.24) + - cloud_firestore (4.14.0): + - Firebase/Firestore (= 10.18.0) + - firebase_core + - Flutter + - nanopb (< 2.30910.0, >= 2.30908.0) - device_info_plus (0.0.1): - Flutter - Firebase/Auth (10.18.0): @@ -6,6 +646,12 @@ PODS: - FirebaseAuth (~> 10.18.0) - Firebase/CoreOnly (10.18.0): - FirebaseCore (= 10.18.0) + - Firebase/Firestore (10.18.0): + - Firebase/CoreOnly + - FirebaseFirestore (~> 10.18.0) + - Firebase/Storage (10.18.0): + - Firebase/CoreOnly + - FirebaseStorage (~> 10.18.0) - firebase_auth (4.16.0): - Firebase/Auth (= 10.18.0) - firebase_core @@ -13,6 +659,10 @@ PODS: - firebase_core (2.24.2): - Firebase/CoreOnly (= 10.18.0) - Flutter + - firebase_storage (11.6.0): + - Firebase/Storage (= 10.18.0) + - firebase_core + - Flutter - FirebaseAppCheckInterop (10.19.0) - FirebaseAuth (10.18.0): - FirebaseAppCheckInterop (~> 10.17) @@ -21,15 +671,47 @@ PODS: - GoogleUtilities/Environment (~> 7.8) - GTMSessionFetcher/Core (< 4.0, >= 2.1) - RecaptchaInterop (~> 100.0) + - FirebaseAuthInterop (10.19.0) - FirebaseCore (10.18.0): - FirebaseCoreInternal (~> 10.0) - GoogleUtilities/Environment (~> 7.12) - GoogleUtilities/Logger (~> 7.12) + - FirebaseCoreExtension (10.19.0): + - FirebaseCore (~> 10.0) - FirebaseCoreInternal (10.19.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseFirestore (10.18.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreExtension (~> 10.0) + - FirebaseFirestoreInternal (~> 10.17) + - FirebaseSharedSwift (~> 10.0) + - FirebaseFirestoreInternal (10.19.0): + - abseil/algorithm (~> 1.20220623.0) + - abseil/base (~> 1.20220623.0) + - abseil/container/flat_hash_map (~> 1.20220623.0) + - abseil/memory (~> 1.20220623.0) + - abseil/meta (~> 1.20220623.0) + - abseil/strings/strings (~> 1.20220623.0) + - abseil/time (~> 1.20220623.0) + - abseil/types (~> 1.20220623.0) + - FirebaseAppCheckInterop (~> 10.17) + - FirebaseCore (~> 10.0) + - "gRPC-C++ (~> 1.49.1)" + - leveldb-library (~> 1.22) + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseSharedSwift (10.19.0) + - FirebaseStorage (10.18.0): + - FirebaseAppCheckInterop (~> 10.0) + - FirebaseAuthInterop (~> 10.0) + - FirebaseCore (~> 10.0) + - FirebaseCoreExtension (~> 10.0) + - GTMSessionFetcher/Core (< 4.0, >= 2.1) - Flutter (1.0.0) - flutter_timezone (0.0.1): - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) - GoogleUtilities/AppDelegateSwizzler (7.12.0): - GoogleUtilities/Environment - GoogleUtilities/Logger @@ -45,69 +727,200 @@ PODS: - "GoogleUtilities/NSData+zlib (7.12.0)" - GoogleUtilities/Reachability (7.12.0): - GoogleUtilities/Logger + - "gRPC-C++ (1.49.1)": + - "gRPC-C++/Implementation (= 1.49.1)" + - "gRPC-C++/Interface (= 1.49.1)" + - "gRPC-C++/Implementation (1.49.1)": + - abseil/base/base (= 1.20220623.0) + - abseil/base/core_headers (= 1.20220623.0) + - abseil/cleanup/cleanup (= 1.20220623.0) + - abseil/container/flat_hash_map (= 1.20220623.0) + - abseil/container/flat_hash_set (= 1.20220623.0) + - abseil/container/inlined_vector (= 1.20220623.0) + - abseil/functional/any_invocable (= 1.20220623.0) + - abseil/functional/bind_front (= 1.20220623.0) + - abseil/functional/function_ref (= 1.20220623.0) + - abseil/hash/hash (= 1.20220623.0) + - abseil/memory/memory (= 1.20220623.0) + - abseil/meta/type_traits (= 1.20220623.0) + - abseil/random/random (= 1.20220623.0) + - abseil/status/status (= 1.20220623.0) + - abseil/status/statusor (= 1.20220623.0) + - abseil/strings/cord (= 1.20220623.0) + - abseil/strings/str_format (= 1.20220623.0) + - abseil/strings/strings (= 1.20220623.0) + - abseil/synchronization/synchronization (= 1.20220623.0) + - abseil/time/time (= 1.20220623.0) + - abseil/types/optional (= 1.20220623.0) + - abseil/types/span (= 1.20220623.0) + - abseil/types/variant (= 1.20220623.0) + - abseil/utility/utility (= 1.20220623.0) + - "gRPC-C++/Interface (= 1.49.1)" + - gRPC-Core (= 1.49.1) + - "gRPC-C++/Interface (1.49.1)" + - gRPC-Core (1.49.1): + - gRPC-Core/Implementation (= 1.49.1) + - gRPC-Core/Interface (= 1.49.1) + - gRPC-Core/Implementation (1.49.1): + - abseil/base/base (= 1.20220623.0) + - abseil/base/core_headers (= 1.20220623.0) + - abseil/container/flat_hash_map (= 1.20220623.0) + - abseil/container/flat_hash_set (= 1.20220623.0) + - abseil/container/inlined_vector (= 1.20220623.0) + - abseil/functional/any_invocable (= 1.20220623.0) + - abseil/functional/bind_front (= 1.20220623.0) + - abseil/functional/function_ref (= 1.20220623.0) + - abseil/hash/hash (= 1.20220623.0) + - abseil/memory/memory (= 1.20220623.0) + - abseil/meta/type_traits (= 1.20220623.0) + - abseil/random/random (= 1.20220623.0) + - abseil/status/status (= 1.20220623.0) + - abseil/status/statusor (= 1.20220623.0) + - abseil/strings/cord (= 1.20220623.0) + - abseil/strings/str_format (= 1.20220623.0) + - abseil/strings/strings (= 1.20220623.0) + - abseil/synchronization/synchronization (= 1.20220623.0) + - abseil/time/time (= 1.20220623.0) + - abseil/types/optional (= 1.20220623.0) + - abseil/types/span (= 1.20220623.0) + - abseil/types/variant (= 1.20220623.0) + - abseil/utility/utility (= 1.20220623.0) + - BoringSSL-GRPC (= 0.0.24) + - gRPC-Core/Interface (= 1.49.1) + - gRPC-Core/Interface (1.49.1) - GTMSessionFetcher/Core (3.2.0) + - image_cropper (0.0.4): + - Flutter + - TOCropViewController (~> 2.6.1) + - image_picker_ios (0.0.1): + - Flutter + - leveldb-library (1.22.2) + - nanopb (2.30909.1): + - nanopb/decode (= 2.30909.1) + - nanopb/encode (= 2.30909.1) + - nanopb/decode (2.30909.1) + - nanopb/encode (2.30909.1) - package_info_plus (0.4.5): - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS - PromisesObjC (2.3.1) - RecaptchaInterop (100.0.0) - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS + - sqflite (0.0.3): + - Flutter + - FMDB (>= 2.7.5) + - TOCropViewController (2.6.1) DEPENDENCIES: + - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_storage (from `.symlinks/plugins/firebase_storage/ios`) - Flutter (from `Flutter`) - flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`) + - image_cropper (from `.symlinks/plugins/image_cropper/ios`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) SPEC REPOS: trunk: + - abseil + - BoringSSL-GRPC - Firebase - FirebaseAppCheckInterop - FirebaseAuth + - FirebaseAuthInterop - FirebaseCore + - FirebaseCoreExtension - FirebaseCoreInternal + - FirebaseFirestore + - FirebaseFirestoreInternal + - FirebaseSharedSwift + - FirebaseStorage + - FMDB - GoogleUtilities + - "gRPC-C++" + - gRPC-Core - GTMSessionFetcher + - leveldb-library + - nanopb - PromisesObjC - RecaptchaInterop + - TOCropViewController EXTERNAL SOURCES: + cloud_firestore: + :path: ".symlinks/plugins/cloud_firestore/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" firebase_auth: :path: ".symlinks/plugins/firebase_auth/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" + firebase_storage: + :path: ".symlinks/plugins/firebase_storage/ios" Flutter: :path: Flutter flutter_timezone: :path: ".symlinks/plugins/flutter_timezone/ios" + image_cropper: + :path: ".symlinks/plugins/image_cropper/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" SPEC CHECKSUMS: + abseil: 926fb7a82dc6d2b8e1f2ed7f3a718bce691d1e46 + BoringSSL-GRPC: 3175b25143e648463a56daeaaa499c6cb86dad33 + cloud_firestore: 73eece22ce25a0565238c283ee9990f1618d8063 device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 Firebase: 414ad272f8d02dfbf12662a9d43f4bba9bec2a06 firebase_auth: 8e9ec02991ca4659111cc671c84d0c010b6bfb26 firebase_core: 0af4a2b24f62071f9bf283691c0ee41556dcb3f5 + firebase_storage: 2b932fa5461f4efac36a2dcfbe240898b190b5b1 FirebaseAppCheckInterop: 37884781f3e16a1ba47e7ec80a1e805f987788e3 FirebaseAuth: 12314b438fa76048540c8fb86d6cfc9e08595176 + FirebaseAuthInterop: f90d6820bf6ecf44753b9f13ba941902d00b525a FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f + FirebaseCoreExtension: c08d14c7b22e07994e876d837e6f58642f340087 FirebaseCoreInternal: b444828ea7cfd594fca83046b95db98a2be4f290 + FirebaseFirestore: 171bcbb57a1a348dd171a0d5e382c03ef85a77bb + FirebaseFirestoreInternal: a15405fb607dfd14edd568bba77028f4c7a69688 + FirebaseSharedSwift: f34eeb7d3ea87a34497629b6ca41657beadef76a + FirebaseStorage: 8333c4b183764cdd170d9539a61322b71c23adff Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_timezone: ffb07bdad3c6276af8dada0f11978d8a1f8a20bb + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34 + "gRPC-C++": 2df8cba576898bdacd29f0266d5236fa0e26ba6a + gRPC-Core: a21a60aefc08c68c247b439a9ef97174b0c54f96 GTMSessionFetcher: 41b9ef0b4c08a6db4b7eb51a21ae5183ec99a2c8 + image_cropper: a3291c624a953049bc6a02e1f8c8ceb162a24b25 + image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425 + leveldb-library: f03246171cce0484482ec291f88b6d563699ee06 + nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 + sqflite: 50a33e1d72bd59ee092a519a35d107502757ebed + TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863 PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 diff --git a/khelo/ios/Runner/Info.plist b/khelo/ios/Runner/Info.plist index 3499970e..c3c997bd 100644 --- a/khelo/ios/Runner/Info.plist +++ b/khelo/ios/Runner/Info.plist @@ -56,5 +56,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSCameraUsageDescription + Capture a new profile image using your device's camera for a personalized and up-to-date appearance. + NSPhotoLibraryUsageDescription + Select a profile image from your device's gallery to showcase your preferred photo in moments of your choice. diff --git a/khelo/lib/components/app_page.dart b/khelo/lib/components/app_page.dart index 09212975..508720be 100644 --- a/khelo/lib/components/app_page.dart +++ b/khelo/lib/components/app_page.dart @@ -33,7 +33,8 @@ class AppPage extends StatelessWidget { } } - Widget _cupertino(BuildContext context) => CupertinoPageScaffold( + Widget _cupertino(BuildContext context) => + CupertinoPageScaffold( navigationBar: (title == null && titleWidget == null) && actions == null && leading == null diff --git a/khelo/lib/domain/extensions/string_extensions.dart b/khelo/lib/domain/extensions/string_extensions.dart new file mode 100644 index 00000000..3574dfa3 --- /dev/null +++ b/khelo/lib/domain/extensions/string_extensions.dart @@ -0,0 +1,8 @@ +extension EmailValidator on String { + bool isValidEmail() { + // TODO: wrong result in case of 'special!chars@email.com' + return RegExp( + r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$') + .hasMatch(this); + } +} diff --git a/khelo/lib/main.dart b/khelo/lib/main.dart index c8bc697f..8bfdd17e 100644 --- a/khelo/lib/main.dart +++ b/khelo/lib/main.dart @@ -1,15 +1,29 @@ +import 'package:data/storage/provider/preferences_provider.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:khelo/ui/app.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'firebase_options.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + final container = await _initContainer(); + runApp(UncontrolledProviderScope(container: container, child: const App())); +} + +Future _initContainer() async { await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); - runApp(const ProviderScope(child: App())); -} \ No newline at end of file + final prefs = await SharedPreferences.getInstance(); + + final container = ProviderContainer( + overrides: [ + sharedPreferencesProvider.overrideWithValue(prefs), + ], + ); + return container; +} diff --git a/khelo/lib/ui/app.dart b/khelo/lib/ui/app.dart index 1d162cf6..4c4de1eb 100644 --- a/khelo/lib/ui/app.dart +++ b/khelo/lib/ui/app.dart @@ -26,7 +26,7 @@ class _AppState extends ConsumerState { super.initState(); final AppRoute initialRoute; - initialRoute = AppRoute.main; + initialRoute = AppRoute.intro; // if (ref.read(hasUserSession)) { // initialRoute = AppRoute.main; // } else { diff --git a/khelo/lib/ui/app_route.dart b/khelo/lib/ui/app_route.dart index f7b1a2a9..e4acb288 100644 --- a/khelo/lib/ui/app_route.dart +++ b/khelo/lib/ui/app_route.dart @@ -104,8 +104,8 @@ class AppRoute { verificationId: verificationId, )); - static AppRoute get editProfile => - AppRoute(pathEditProfile, builder: (_) => const EditProfileScreen()); + static AppRoute editProfile({bool isToCreateAccount = false}) => + AppRoute(pathEditProfile, builder: (_) => EditProfileScreen(isToCreateAccount: isToCreateAccount)); static final routes = [ GoRoute( @@ -122,13 +122,17 @@ class AppRoute { : state.widget(context); }, ), - phoneLogin.goRoute(), GoRoute( - path: pathPhoneNumberVerification, - builder: (context, state) => state.widget(context), + path: pathEditProfile, + builder: (context, state) { + return state.extra == null + ? EditProfileScreen(isToCreateAccount: true,) + : state.widget(context); + }, ), + phoneLogin.goRoute(), GoRoute( - path: pathEditProfile, + path: pathPhoneNumberVerification, builder: (context, state) => state.widget(context), ), ]; diff --git a/khelo/lib/ui/flow/intro/intro_screen.dart b/khelo/lib/ui/flow/intro/intro_screen.dart index 4c82a240..5a43e112 100644 --- a/khelo/lib/ui/flow/intro/intro_screen.dart +++ b/khelo/lib/ui/flow/intro/intro_screen.dart @@ -49,8 +49,8 @@ class _IntroScreenState extends ConsumerState { ), PrimaryButton( context.l10n.intro_sign_in_btn_text, - onPressed: () { - AppRoute.phoneLogin.push(context); + onPressed: () async { + await AppRoute.phoneLogin.push(context); }, ), ], diff --git a/khelo/lib/ui/flow/profile/profile_screen.dart b/khelo/lib/ui/flow/profile/profile_screen.dart index a612997d..4c7edab9 100644 --- a/khelo/lib/ui/flow/profile/profile_screen.dart +++ b/khelo/lib/ui/flow/profile/profile_screen.dart @@ -1,29 +1,196 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:data/api/user/user_models.dart'; +import 'package:data/storage/app_preferences.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.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/ui/app_route.dart'; +import 'package:khelo/ui/flow/profile/profile_view_model.dart'; +import 'package:style/animations/on_tap_scale.dart'; +import 'package:style/button/primary_button.dart'; +import 'package:style/extensions/context_extensions.dart'; +import 'package:style/text/app_text_style.dart'; -class ProfileScreen extends StatefulWidget { +class ProfileScreen extends ConsumerWidget { const ProfileScreen({super.key}); - @override - State createState() => _ProfileScreenState(); -} + _observeUserSession(BuildContext context, WidgetRef ref) { + ref.listen(hasUserSession, (previous, next) { + if (!next) { + AppRoute.intro.go(context); + } + }); + } -class _ProfileScreenState extends State { @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final notifier = ref.watch(profileStateProvider.notifier); + final state = ref.watch(profileStateProvider); + + _observeUserSession(context, ref); return AppPage( title: context.l10n.tab_profile_title, + actions: [ + TextButton( + onPressed: () { + _showSignOutAlert(context, () { + notifier.onSignOutTap(); + }); + }, + child: Text( + context.l10n.common_sign_out_title, + style: AppTextStyle.button + .copyWith(color: context.colorScheme.primary), + )) + ], body: Builder( builder: (context) { - return Center( - child: TextButton(onPressed: () { - AppRoute.editProfile.push(context); - }, child: const Text("go to profile >>")), + return ListView( + padding: context.mediaQueryPadding + + const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + children: [ + _userProfileView(context, state), + if (state.currentUser != null) ...[ + const SizedBox( + height: 24, + ), + _inCompleteProfileView(context, state.currentUser!) + ], + // const SizedBox( + // height: 24, + // ), + // Text(context.l10n.edit_profile_sign_out_title, style: AppTextStyle.header2.copyWith(color: context.colorScheme.textSecondary),) + ], ); }, ), ); } + + Widget _userProfileView(BuildContext context, ProfileState state) { + return OnTapScale( + onTap: () => AppRoute.editProfile().push(context), + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all(color: context.colorScheme.containerHigh), + borderRadius: BorderRadius.circular(12)), + child: Row( + children: [ + Container( + height: 90, + width: 90, + alignment: Alignment.center, + decoration: BoxDecoration( + color: context.colorScheme.containerLow, + shape: BoxShape.circle, + // image: state.currentUser?.profile_img_url != null + // ? DecorationImage( + // image: CachedNetworkImageProvider( + // state.currentUser!.profile_img_url!), + // fit: BoxFit.cover) + // : null, + image: state.currentUser?.profile_img_url != null + ? DecorationImage( + image: CachedNetworkImageProvider( + state.currentUser!.profile_img_url!), + fit: BoxFit.cover) + : null, + border: Border.all(color: context.colorScheme.containerHigh)), + child: state.currentUser?.profile_img_url == null + ? Text(state.currentUser?.nameInitial ?? '?', + style: AppTextStyle.header1.copyWith( + color: context.colorScheme.secondary, fontSize: 40)) + : null, + ), + const SizedBox( + width: 16, + ), + Expanded( + child: Text( + state.currentUser?.name ?? context.l10n.common_anonymous_title, + style: AppTextStyle.header3 + .copyWith(color: context.colorScheme.textPrimary), + ), + ) + ], + ), + ), + ); + } + + Widget _inCompleteProfileView(BuildContext context, UserModel currentUser) { + if (currentUser.profile_img_url == null || + currentUser.batting_style == null || + currentUser.bowling_style == null) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all(color: context.colorScheme.containerHigh), + borderRadius: BorderRadius.circular(12)), + child: Column( + children: [ + Text( + context.l10n.profile_complete_your_profile_title, + style: AppTextStyle.header1 + .copyWith(color: context.colorScheme.textPrimary), + ), + const SizedBox( + height: 8, + ), + Text( + context.l10n.profile_complete_profile_description_title, + style: AppTextStyle.subtitle1 + .copyWith(color: context.colorScheme.textSecondary), + textAlign: TextAlign.center, + ), + const SizedBox( + height: 24, + ), + PrimaryButton( + onPressed: () => AppRoute.editProfile().push(context), + context.l10n.profile_complete_profile_btn_title) + ], + ), + ); + } else { + return const SizedBox(); + } + } + + void _showSignOutAlert(BuildContext context, Function() onSignOut) { + showAdaptiveDialog( + context: context, + builder: (context) { + return AlertDialog.adaptive( + title: Text(context.l10n.common_sign_out_title), + content: Text(context.l10n.alert_confirm_default_message( + context.l10n.common_sign_out_title.toLowerCase())), + actions: [ + TextButton( + onPressed: () { + context.pop(); + }, + child: Text( + context.l10n.common_cancel_title, + style: TextStyle(color: context.colorScheme.textSecondary), + ), + ), + TextButton( + onPressed: () { + context.pop(); + onSignOut(); + }, + child: Text( + context.l10n.common_sign_out_title, + style: TextStyle(color: context.colorScheme.alert), + ), + ), + ], + ); + }, + ); + } } diff --git a/khelo/lib/ui/flow/profile/profile_view_model.dart b/khelo/lib/ui/flow/profile/profile_view_model.dart new file mode 100644 index 00000000..285a725c --- /dev/null +++ b/khelo/lib/ui/flow/profile/profile_view_model.dart @@ -0,0 +1,48 @@ +import 'package:data/api/user/user_models.dart'; +import 'package:data/service/user/user_service.dart'; +import 'package:data/storage/app_preferences.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'profile_view_model.freezed.dart'; + +final profileStateProvider = + StateNotifierProvider.autoDispose((ref) { + final notifier = ProfileViewNotifier( + FirebaseAuth.instance, + ref.read(userServiceProvider), + ref.read(currentUserPod), + ); + ref.listen(currentUserPod, (_, next) => notifier._updateUser(next)); + return notifier; +}); + +class ProfileViewNotifier extends StateNotifier { + final FirebaseAuth _auth; + final UserService _userService; + + ProfileViewNotifier(this._auth, this._userService, UserModel? user) + : super(ProfileState(currentUser: user)); + + void _updateUser(UserModel? user) { + state = state.copyWith(currentUser: user); + } + + void onSignOutTap() { + // signOut from firebase auth + try { + _auth.signOut(); + _userService.signOutUser(); + // clear preference and show intro + } catch (e) { + debugPrint("ProfileViewNotifier: error while sign Out -> $e"); + } + } +} + +@freezed +class ProfileState with _$ProfileState { + const factory ProfileState({UserModel? currentUser}) = _ProfileState; +} diff --git a/khelo/lib/ui/flow/profile/profile_view_model.freezed.dart b/khelo/lib/ui/flow/profile/profile_view_model.freezed.dart new file mode 100644 index 00000000..ce5d8c81 --- /dev/null +++ b/khelo/lib/ui/flow/profile/profile_view_model.freezed.dart @@ -0,0 +1,151 @@ +// 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 'profile_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#custom-getters-and-methods'); + +/// @nodoc +mixin _$ProfileState { + UserModel? get currentUser => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ProfileStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProfileStateCopyWith<$Res> { + factory $ProfileStateCopyWith( + ProfileState value, $Res Function(ProfileState) then) = + _$ProfileStateCopyWithImpl<$Res, ProfileState>; + @useResult + $Res call({UserModel? currentUser}); + + $UserModelCopyWith<$Res>? get currentUser; +} + +/// @nodoc +class _$ProfileStateCopyWithImpl<$Res, $Val extends ProfileState> + implements $ProfileStateCopyWith<$Res> { + _$ProfileStateCopyWithImpl(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? currentUser = freezed, + }) { + return _then(_value.copyWith( + currentUser: freezed == currentUser + ? _value.currentUser + : currentUser // ignore: cast_nullable_to_non_nullable + as UserModel?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UserModelCopyWith<$Res>? get currentUser { + if (_value.currentUser == null) { + return null; + } + + return $UserModelCopyWith<$Res>(_value.currentUser!, (value) { + return _then(_value.copyWith(currentUser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ProfileStateImplCopyWith<$Res> + implements $ProfileStateCopyWith<$Res> { + factory _$$ProfileStateImplCopyWith( + _$ProfileStateImpl value, $Res Function(_$ProfileStateImpl) then) = + __$$ProfileStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({UserModel? currentUser}); + + @override + $UserModelCopyWith<$Res>? get currentUser; +} + +/// @nodoc +class __$$ProfileStateImplCopyWithImpl<$Res> + extends _$ProfileStateCopyWithImpl<$Res, _$ProfileStateImpl> + implements _$$ProfileStateImplCopyWith<$Res> { + __$$ProfileStateImplCopyWithImpl( + _$ProfileStateImpl _value, $Res Function(_$ProfileStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? currentUser = freezed, + }) { + return _then(_$ProfileStateImpl( + currentUser: freezed == currentUser + ? _value.currentUser + : currentUser // ignore: cast_nullable_to_non_nullable + as UserModel?, + )); + } +} + +/// @nodoc + +class _$ProfileStateImpl implements _ProfileState { + const _$ProfileStateImpl({this.currentUser}); + + @override + final UserModel? currentUser; + + @override + String toString() { + return 'ProfileState(currentUser: $currentUser)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProfileStateImpl && + (identical(other.currentUser, currentUser) || + other.currentUser == currentUser)); + } + + @override + int get hashCode => Object.hash(runtimeType, currentUser); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ProfileStateImplCopyWith<_$ProfileStateImpl> get copyWith => + __$$ProfileStateImplCopyWithImpl<_$ProfileStateImpl>(this, _$identity); +} + +abstract class _ProfileState implements ProfileState { + const factory _ProfileState({final UserModel? currentUser}) = + _$ProfileStateImpl; + + @override + UserModel? get currentUser; + @override + @JsonKey(ignore: true) + _$$ProfileStateImplCopyWith<_$ProfileStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/khelo/lib/ui/flow/settings/profile/edit_profile_screen.dart b/khelo/lib/ui/flow/settings/profile/edit_profile_screen.dart index 529d4643..3c3f89dd 100644 --- a/khelo/lib/ui/flow/settings/profile/edit_profile_screen.dart +++ b/khelo/lib/ui/flow/settings/profile/edit_profile_screen.dart @@ -1,44 +1,542 @@ -import 'package:flutter/cupertino.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:data/api/user/user_models.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:image_cropper/image_cropper.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:intl/intl.dart'; import 'package:khelo/components/app_page.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/ui/app_route.dart'; +import 'package:khelo/ui/flow/settings/profile/edit_profile_view_model.dart'; +import 'package:style/animations/on_tap_scale.dart'; +import 'package:style/button/primary_button.dart'; import 'package:style/extensions/context_extensions.dart'; +import 'package:style/text/app_text_style.dart'; class EditProfileScreen extends ConsumerWidget { - const EditProfileScreen({super.key}); + final bool isToCreateAccount; + + EditProfileScreen({super.key, required this.isToCreateAccount}); + + final double profileViewHeight = 130; + final ImagePicker _picker = ImagePicker(); + + _observeIsSaved(BuildContext context, WidgetRef ref) { + ref.listen(editProfileStateProfile.select((state) => state.isSaved), + (previous, next) { + if (next) { + if (isToCreateAccount) { + AppRoute.main.go(context); + } else { + context.pop(); + } + } + }); + } @override Widget build(BuildContext context, WidgetRef ref) { - return AppPage( - title: context.l10n.edit_profile_screen_title, - body: Builder( - builder: (context) { - return ListView( - padding: context.mediaQueryPadding + - const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), - - children: const [ - // center pick profile image from camera or gallery - CupertinoTextField( - placeholder: "name", - ), - SizedBox(height: 16,), - CupertinoTextField( - placeholder: "email", + final notifier = ref.watch(editProfileStateProfile.notifier); + final state = ref.watch(editProfileStateProfile); + + _observeIsSaved(context, ref); + + return PopScope( + canPop: !state.isButtonEnable, + onPopInvoked: (didPop) { + notifier.onBackBtnPressed(); + context.pop(); + }, + child: AppPage( + title: context.l10n.edit_profile_screen_title, + actions: [ + if (!isToCreateAccount) ...[ + IconButton( + onPressed: () => + _showDeleteAlert(context, () => notifier.onDeleteTap()), + icon: const Icon(Icons.delete_outline)) + ] + ], + body: Material( + child: Builder( + builder: (context) { + return ListView( + padding: context.mediaQueryPadding + + const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + children: [ + _profileImageView(context, notifier, state), + const SizedBox( + height: 16, + ), + _textInputField( + context, + notifier, + state, + context.l10n.edit_profile_name_placeholder, + state.nameController), + const SizedBox( + height: 16, + ), + _textInputField( + context, + notifier, + state, + context.l10n.edit_profile_email_placeholder, + state.emailController), + const SizedBox( + height: 16, + ), + _textInputField( + context, + notifier, + state, + context.l10n.edit_profile_location_placeholder, + state.locationController), + _sectionTitle( + context, context.l10n.edit_profile_dob_placeholder), + OnTapScale( + onTap: () => _selectDate(context, notifier, state), + child: Text.rich(TextSpan(children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Icon(Icons.calendar_today, + color: context.colorScheme.textPrimary), + )), + TextSpan( + text: DateFormat.yMMMMd().format(state.dob), + style: AppTextStyle.subtitle1.copyWith( + color: context.colorScheme.textSecondary)), + ])), + ), + _sectionTitle( + context, context.l10n.edit_profile_gender_placeholder), + _genderOptionView(context, notifier, state), + const SizedBox( + height: 16, + ), + DropdownButton( + alignment: Alignment.center, + value: state.playerRole, + hint: Text( + context.l10n.edit_profile_player_role_placeholder), + items: PlayerRole.values.map((PlayerRole items) { + return DropdownMenuItem( + value: items, + child: Text(_getPlayerRoleString(context, items)), + ); + }).toList(), + onChanged: (PlayerRole? newValue) { + if (newValue != null && newValue != state.playerRole) { + notifier.onPlayerRoleChange(newValue); + } + }), + const SizedBox( + height: 16, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + DropdownButton( + value: state.battingStyle, + hint: Text(context + .l10n.edit_profile_batting_style_placeholder), + items: BattingStyle.values.map((BattingStyle items) { + return DropdownMenuItem( + value: items, + child: + Text(_getBattingStyleString(context, items)), + ); + }).toList(), + onChanged: (BattingStyle? newValue) { + if (newValue != null && + newValue != state.battingStyle) { + notifier.onBattingStyleChange(newValue); + } + }), + DropdownButton( + value: state.bowlingStyle, + hint: Text(context + .l10n.edit_profile_bowling_style_placeholder), + items: BowlingStyle.values.map((BowlingStyle items) { + return DropdownMenuItem( + value: items, + child: + Text(_getBowlingStyleString(context, items)), + ); + }).toList(), + onChanged: (BowlingStyle? newValue) { + if (newValue != null && + newValue != state.bowlingStyle) { + notifier.onBowlingStyleChange(newValue); + } + }) + ], + ), + const SizedBox( + height: 24, + ), + PrimaryButton( + context.l10n.edit_profile_save_title, + expanded: false, + progress: state.isSaveInProgress, + enabled: state.isButtonEnable, + onPressed: () => notifier.onSubmitTap(), + ) + ], + ); + }, + ), + ), + ), + ); + } + + Widget _profileImageView(BuildContext context, + EditProfileViewNotifier notifier, EditProfileState state) { + return Center( + child: SizedBox( + height: profileViewHeight, + width: profileViewHeight, + child: Stack( + children: [ + Container( + height: profileViewHeight, + width: profileViewHeight, + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: state.imageUrl != null + ? DecorationImage( + image: CachedNetworkImageProvider(state.imageUrl!), + fit: BoxFit.cover) + : null, + color: context.colorScheme.primary), + child: state.imageUrl == null + ? Icon( + Icons.person, + size: profileViewHeight / 2, + color: context.colorScheme.textSecondary, + ) + : null, + ), + OnTapScale( + onTap: () { + _onEditProfileButtonTap(context, notifier); + }, + child: Align( + alignment: Alignment.bottomRight, + child: Container( + height: profileViewHeight / 3, + width: profileViewHeight / 3, + decoration: BoxDecoration( + color: context.colorScheme.surface, + border: + Border.all(color: context.colorScheme.textSecondary), + shape: BoxShape.circle), + child: Icon( + Icons.edit, + size: profileViewHeight / 5, + color: context.colorScheme.textSecondary, + ), + ), ), - SizedBox(height: 16,), - SizedBox(height: 16,), - CupertinoTextField( - placeholder: "location", + ), + ], + ), + ), + ); + } + + void _onEditProfileButtonTap( + BuildContext context, EditProfileViewNotifier notifier) { + showModalBottomSheet( + context: context, + showDragHandle: true, + backgroundColor: context.colorScheme.surface, + builder: (sheetContext) { + return Container( + padding: sheetContext.mediaQueryPadding + + const EdgeInsets.only(left: 16, right: 16, bottom: 24), + child: Wrap( + children: [ + Text( + context.l10n.edit_profile_choose_option_title, + style: AppTextStyle.header2 + .copyWith(color: context.colorScheme.textSecondary), ), - CupertinoTextField( - placeholder: "dob", + const SizedBox( + height: 34, ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + //Light Line Png vectors by Lovepik.com GRAPHIC IMAGE LINK : camera + _sheetOptionCell( + context, + notifier, + "assets/images/ic_camera.png", + () async { + sheetContext.pop(); + final image = await _picker.pickImage( + source: ImageSource.camera, + requestFullMetadata: false, + ); + if (context.mounted && image != null) { + _openCropImage(context, notifier, image); + } + }, + ), + + _sheetOptionCell( + context, + notifier, + "assets/images/ic_gallery.png", + () async { + sheetContext.pop(); + final image = await _picker.pickImage( + source: ImageSource.gallery, + requestFullMetadata: false, + ); + if (context.mounted && image != null) { + _openCropImage(context, notifier, image); + } + }, + ), + ], + ) ], - ); - }, + ), + ); + }, + ); + } + + Widget _sheetOptionCell(BuildContext context, + EditProfileViewNotifier notifier, String imagePath, VoidCallback onTap) { + return OnTapScale( + onTap: () => onTap(), + child: Container( + height: 80, + width: 80, + decoration: BoxDecoration( + image: DecorationImage(image: AssetImage(imagePath)), + shape: BoxShape.circle, + border: Border.all(color: context.colorScheme.containerHigh), + color: context.colorScheme.containerLow), + ), + ); + } + + void _openCropImage(BuildContext context, EditProfileViewNotifier notifier, + XFile image) async { + final croppedImage = await ImageCropper().cropImage( + sourcePath: image.path, + aspectRatioPresets: [CropAspectRatioPreset.square], + uiSettings: [ + AndroidUiSettings( + toolbarTitle: context.l10n.edit_profile_crop_image_title, + toolbarColor: context.colorScheme.primary, + toolbarWidgetColor: context.colorScheme.onPrimary, + initAspectRatio: CropAspectRatioPreset.square, + lockAspectRatio: true, + ), + IOSUiSettings( + title: context.l10n.edit_profile_crop_image_title, + ), + WebUiSettings( + context: context, + ), + ], + ); + + if (croppedImage != null) notifier.onImageChange(croppedImage.path); + } + + Widget _textInputField(BuildContext context, EditProfileViewNotifier notifier, + EditProfileState state, String label, TextEditingController controller) { + return TextField( + controller: controller, + onChanged: (value) => notifier.onValueChange(), + decoration: InputDecoration( + labelText: label, + border: const OutlineInputBorder(), + ), + ); + } + + Widget _sectionTitle(BuildContext context, String title) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 16, + ), + Text( + title, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textSecondary), + ), + const SizedBox( + height: 8, + ), + ], + ); + } + + Future _selectDate(BuildContext context, + EditProfileViewNotifier notifier, EditProfileState state) async { + final DateTime? picked = await showDatePicker( + context: context, + helpText: context.l10n.edit_profile_select_birth_date_placeholder, + initialDate: state.dob, + firstDate: DateTime(1920), + lastDate: DateTime.now()); + if (picked != null && picked != state.dob) { + notifier.onDateSelect(selectedDate: picked); + } + } + + Widget _genderOptionView(BuildContext context, + EditProfileViewNotifier notifier, EditProfileState state) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _radioBtnCell(context, notifier, state, UserGender.male), + _radioBtnCell(context, notifier, state, UserGender.female), + _radioBtnCell(context, notifier, state, UserGender.other), + ], + ); + } + + Widget _radioBtnCell(BuildContext context, EditProfileViewNotifier notifier, + EditProfileState state, UserGender gender) { + return OnTapScale( + onTap: () => notifier.onGenderSelect(gender: gender), + child: Wrap( + direction: Axis.horizontal, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Radio( + value: gender, + groupValue: state.gender, + activeColor: context.colorScheme.primary, + onChanged: (value) { + if (value != null) { + notifier.onGenderSelect(gender: value); + } + }), + Text( + _getGenderString(context, gender), + style: AppTextStyle.button.copyWith( + color: context.colorScheme.textSecondary, fontSize: 16), + ), + ], ), ); } + + String _getGenderString(BuildContext context, UserGender gender) { + switch (gender) { + case UserGender.male: + return context.l10n.edit_profile_gender_male_title; + case UserGender.female: + return context.l10n.edit_profile_gender_female_title; + case UserGender.other: + return context.l10n.edit_profile_gender_other_title; + default: + return ""; + } + } + + String _getBattingStyleString(BuildContext context, BattingStyle style) { + switch (style) { + case BattingStyle.rightHandBat: + return context.l10n.batting_style_right_hand_bat_title; + case BattingStyle.leftHandBat: + return context.l10n.batting_style_left_hand_bat_title; + } + } + + String _getBowlingStyleString(BuildContext context, BowlingStyle style) { + switch (style) { + case BowlingStyle.rightArmFast: + return context.l10n.bowling_style_right_arm_fast_title; + case BowlingStyle.rightArmMedium: + return context.l10n.bowling_style_right_arm_medium_title; + case BowlingStyle.leftArmFast: + return context.l10n.bowling_style_left_arm_fast_title; + case BowlingStyle.leftArmMedium: + return context.l10n.bowling_style_left_arm_medium_title; + case BowlingStyle.slowLeftArmOrthodox: + return context.l10n.bowling_style_slow_left_arm_orthodox_title; + case BowlingStyle.slowLeftArmChinaMan: + return context.l10n.bowling_style_slow_left_arm_chinaman_title; + case BowlingStyle.rightArmOffBreak: + return context.l10n.bowling_style_right_arm_off_break_title; + case BowlingStyle.rightArmLegBreak: + return context.l10n.bowling_style_right_arm_leg_break_title; + case BowlingStyle.none: + return context.l10n.common_none_title; + } + } + + String _getPlayerRoleString(BuildContext context, PlayerRole role) { + switch (role) { + case PlayerRole.topOrderBatter: + return context.l10n.player_role_top_order_batter_title; + case PlayerRole.middleOrderBatter: + return context.l10n.player_role_middle_order_batter_title; + case PlayerRole.wickerKeeperBatter: + return context.l10n.player_role_wicket_keeper_batter_title; + case PlayerRole.wicketKeeper: + return context.l10n.player_role_wicket_keeper_title; + case PlayerRole.bowler: + return context.l10n.player_role_bowler_title; + case PlayerRole.allRounder: + return context.l10n.player_role_all_rounder_title; + case PlayerRole.lowerOrderBatter: + return context.l10n.player_role_lower_order_batter_title; + case PlayerRole.openingBatter: + return context.l10n.player_role_opening_batter_title; + case PlayerRole.none: + return context.l10n.common_none_title; + } + } + + void _showDeleteAlert(BuildContext context, Function() onDelete) { + showAdaptiveDialog( + context: context, + builder: (context) { + return AlertDialog.adaptive( + title: Text(context.l10n.common_delete_title), + content: Text(context.l10n.alert_confirm_default_message( + context.l10n.common_delete_title.toLowerCase())), + actions: [ + TextButton( + onPressed: () { + context.pop(); + }, + child: Text( + context.l10n.common_cancel_title, + style: TextStyle(color: context.colorScheme.textSecondary), + ), + ), + TextButton( + onPressed: () { + context.pop(); + onDelete(); + }, + child: Text( + context.l10n.common_delete_title, + style: TextStyle(color: context.colorScheme.alert), + ), + ), + ], + ); + }, + ); + } } diff --git a/khelo/lib/ui/flow/settings/profile/edit_profile_view_model.dart b/khelo/lib/ui/flow/settings/profile/edit_profile_view_model.dart new file mode 100644 index 00000000..d5d119fd --- /dev/null +++ b/khelo/lib/ui/flow/settings/profile/edit_profile_view_model.dart @@ -0,0 +1,210 @@ +import 'package:data/api/user/user_models.dart'; +import 'package:data/service/file_upload/file_upload_service.dart'; +import 'package:data/service/user/user_service.dart'; +import 'package:data/storage/app_preferences.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:khelo/domain/extensions/string_extensions.dart'; + +part 'edit_profile_view_model.freezed.dart'; + +final editProfileStateProfile = StateNotifierProvider.autoDispose< + EditProfileViewNotifier, EditProfileState>((ref) { + final notifier = EditProfileViewNotifier( + ref.read(fileUploadServiceProvider), + ref.read(userServiceProvider), + FirebaseAuth.instance, + ref.read(currentUserPod), + ); + ref.listen(currentUserPod, (_, next) => notifier._updateUser(next)); + return notifier; +}); + +class EditProfileViewNotifier extends StateNotifier { + final FileUploadService fileUploadService; + final UserService userService; + final FirebaseAuth auth; + + EditProfileViewNotifier( + this.fileUploadService, this.userService, this.auth, UserModel? user) + : super(EditProfileState( + dob: user?.dob ?? DateTime.now(), + imageUrl: user?.profile_img_url, + battingStyle: user?.batting_style, + bowlingStyle: user?.bowling_style, + gender: user?.gender, + playerRole: user?.player_role, + nameController: TextEditingController(text: user?.name), + emailController: TextEditingController(text: user?.email), + currentUser: user, + locationController: TextEditingController(text: user?.location))); + + void _updateUser(UserModel? user) { + state = state.copyWith(currentUser: user); + } + + void onDateSelect({required DateTime selectedDate}) { + state = state.copyWith(dob: selectedDate); + onValueChange(); + } + + void onGenderSelect({required UserGender gender}) { + state = state.copyWith(gender: gender); + onValueChange(); + } + + void onBattingStyleChange(BattingStyle style) { + state = state.copyWith(battingStyle: style); + onValueChange(); + } + + void onBowlingStyleChange(BowlingStyle style) { + state = state.copyWith(bowlingStyle: style); + onValueChange(); + } + + void onPlayerRoleChange(PlayerRole role) { + state = state.copyWith(playerRole: role); + onValueChange(); + } + + void onValueChange() { + final bool isEnable = state.nameController.text.trim().length >= 3 && + state.emailController.text.trim().isValidEmail() && + state.locationController.text.trim().length >= 3; + + state = state.copyWith(isButtonEnable: isEnable); + } + + Future onImageChange(String path) async { + try { + final imageUrl = await fileUploadService.uploadProfileImage(path); + final prevUrl = state.imageUrl; + + if (prevUrl != null && prevUrl != state.currentUser?.profile_img_url) { + await fileUploadService.deleteUploadedProfileImage(prevUrl); + } + state = state.copyWith(imageUrl: imageUrl); + onValueChange(); + } catch (e) { + debugPrint("EditProfileViewNotifier: error while image upload -> $e"); + } + } + + Future onSubmitTap() async { + if (state.currentUser == null) { + return; + } + + try { + state = state.copyWith(isSaveInProgress: true); + if (state.currentUser?.profile_img_url != null && + state.imageUrl != state.currentUser?.profile_img_url) { + fileUploadService + .deleteUploadedProfileImage(state.currentUser!.profile_img_url!); + } + + final name = state.nameController.text.trim(); + final email = state.emailController.text.trim(); + final location = state.locationController.text.trim(); + + UserModel user = UserModel( + id: state.currentUser!.id, + name: name, + email: email, + location: location, + batting_style: state.battingStyle, + bowling_style: state.bowlingStyle, + player_role: state.playerRole, + gender: state.gender, + profile_img_url: state.imageUrl, + dob: state.dob, + updated_at: DateTime.now()); + + await userService.updateUser(user); + state = state.copyWith(isSaveInProgress: false, isSaved: true); + } catch (e) { + state = state.copyWith(isSaveInProgress: false); + debugPrint( + "EditProfileViewNotifier: error while edit profile details -> $e"); + } + } + + Future onDeleteTap() async { + try { + if (state.imageUrl != null) { + if (state.imageUrl != state.currentUser?.profile_img_url && + state.currentUser?.profile_img_url != null) { + fileUploadService + .deleteUploadedProfileImage(state.currentUser!.profile_img_url!); + } + fileUploadService.deleteUploadedProfileImage(state.imageUrl!); + } else { + if (state.currentUser?.profile_img_url != null) { + fileUploadService + .deleteUploadedProfileImage(state.currentUser!.profile_img_url!); + } + } + + await auth.currentUser?.delete(); + userService.deleteUser(); + } on FirebaseAuthException catch (e) { + if (e.code == "requires-recent-login") { + await _reAuthenticateAndDelete(); + } + } catch (e) { + debugPrint("EditProfileViewNotifier: error while delete account -> $e"); + } + } + + Future _reAuthenticateAndDelete() async { + try { + final providerData = auth.currentUser?.providerData.first; + if (PhoneAuthProvider().providerId == providerData?.providerId) { + await auth.currentUser?.reauthenticateWithProvider(PhoneAuthProvider()); + await auth.currentUser?.delete(); + } + } on FirebaseAuthException catch (e) { + if (e.code == "web-user-interaction-failure") { + debugPrint( + "EditProfileViewNotifier: error in _reAuthenticateAndDelete -> $e"); + } + } catch (e) { + debugPrint( + "EditProfileViewNotifier: error in reAuthenticate And Delete -> $e"); + } + } + + void onBackBtnPressed() { + try { + if (state.imageUrl != state.currentUser?.profile_img_url && + state.imageUrl != null) { + fileUploadService.deleteUploadedProfileImage(state.imageUrl!); + } + } catch (e) { + debugPrint( + "EditProfileViewNotifier: error while delete image on back btn press -> $e"); + } + } +} + +@freezed +class EditProfileState with _$EditProfileState { + const factory EditProfileState({ + required DateTime dob, + required TextEditingController nameController, + required TextEditingController emailController, + required TextEditingController locationController, + @Default(null) String? imageUrl, + @Default(null) UserGender? gender, + @Default(null) BattingStyle? battingStyle, + @Default(null) BowlingStyle? bowlingStyle, + @Default(null) PlayerRole? playerRole, + @Default(false) bool isButtonEnable, + @Default(false) bool isSaved, + @Default(false) bool isSaveInProgress, + UserModel? currentUser, + }) = _EditProfileState; +} diff --git a/khelo/lib/ui/flow/settings/profile/edit_profile_view_model.freezed.dart b/khelo/lib/ui/flow/settings/profile/edit_profile_view_model.freezed.dart new file mode 100644 index 00000000..17a04629 --- /dev/null +++ b/khelo/lib/ui/flow/settings/profile/edit_profile_view_model.freezed.dart @@ -0,0 +1,429 @@ +// 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 'edit_profile_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#custom-getters-and-methods'); + +/// @nodoc +mixin _$EditProfileState { + DateTime get dob => throw _privateConstructorUsedError; + TextEditingController get nameController => + throw _privateConstructorUsedError; + TextEditingController get emailController => + throw _privateConstructorUsedError; + TextEditingController get locationController => + throw _privateConstructorUsedError; + String? get imageUrl => throw _privateConstructorUsedError; + UserGender? get gender => throw _privateConstructorUsedError; + BattingStyle? get battingStyle => throw _privateConstructorUsedError; + BowlingStyle? get bowlingStyle => throw _privateConstructorUsedError; + PlayerRole? get playerRole => throw _privateConstructorUsedError; + bool get isButtonEnable => throw _privateConstructorUsedError; + bool get isSaved => throw _privateConstructorUsedError; + bool get isSaveInProgress => throw _privateConstructorUsedError; + UserModel? get currentUser => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $EditProfileStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $EditProfileStateCopyWith<$Res> { + factory $EditProfileStateCopyWith( + EditProfileState value, $Res Function(EditProfileState) then) = + _$EditProfileStateCopyWithImpl<$Res, EditProfileState>; + @useResult + $Res call( + {DateTime dob, + TextEditingController nameController, + TextEditingController emailController, + TextEditingController locationController, + String? imageUrl, + UserGender? gender, + BattingStyle? battingStyle, + BowlingStyle? bowlingStyle, + PlayerRole? playerRole, + bool isButtonEnable, + bool isSaved, + bool isSaveInProgress, + UserModel? currentUser}); + + $UserModelCopyWith<$Res>? get currentUser; +} + +/// @nodoc +class _$EditProfileStateCopyWithImpl<$Res, $Val extends EditProfileState> + implements $EditProfileStateCopyWith<$Res> { + _$EditProfileStateCopyWithImpl(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? dob = null, + Object? nameController = null, + Object? emailController = null, + Object? locationController = null, + Object? imageUrl = freezed, + Object? gender = freezed, + Object? battingStyle = freezed, + Object? bowlingStyle = freezed, + Object? playerRole = freezed, + Object? isButtonEnable = null, + Object? isSaved = null, + Object? isSaveInProgress = null, + Object? currentUser = freezed, + }) { + return _then(_value.copyWith( + dob: null == dob + ? _value.dob + : dob // ignore: cast_nullable_to_non_nullable + as DateTime, + nameController: null == nameController + ? _value.nameController + : nameController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + emailController: null == emailController + ? _value.emailController + : emailController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + locationController: null == locationController + ? _value.locationController + : locationController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + imageUrl: freezed == imageUrl + ? _value.imageUrl + : imageUrl // ignore: cast_nullable_to_non_nullable + as String?, + gender: freezed == gender + ? _value.gender + : gender // ignore: cast_nullable_to_non_nullable + as UserGender?, + battingStyle: freezed == battingStyle + ? _value.battingStyle + : battingStyle // ignore: cast_nullable_to_non_nullable + as BattingStyle?, + bowlingStyle: freezed == bowlingStyle + ? _value.bowlingStyle + : bowlingStyle // ignore: cast_nullable_to_non_nullable + as BowlingStyle?, + playerRole: freezed == playerRole + ? _value.playerRole + : playerRole // ignore: cast_nullable_to_non_nullable + as PlayerRole?, + isButtonEnable: null == isButtonEnable + ? _value.isButtonEnable + : isButtonEnable // ignore: cast_nullable_to_non_nullable + as bool, + isSaved: null == isSaved + ? _value.isSaved + : isSaved // ignore: cast_nullable_to_non_nullable + as bool, + isSaveInProgress: null == isSaveInProgress + ? _value.isSaveInProgress + : isSaveInProgress // ignore: cast_nullable_to_non_nullable + as bool, + currentUser: freezed == currentUser + ? _value.currentUser + : currentUser // ignore: cast_nullable_to_non_nullable + as UserModel?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UserModelCopyWith<$Res>? get currentUser { + if (_value.currentUser == null) { + return null; + } + + return $UserModelCopyWith<$Res>(_value.currentUser!, (value) { + return _then(_value.copyWith(currentUser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$EditProfileStateImplCopyWith<$Res> + implements $EditProfileStateCopyWith<$Res> { + factory _$$EditProfileStateImplCopyWith(_$EditProfileStateImpl value, + $Res Function(_$EditProfileStateImpl) then) = + __$$EditProfileStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {DateTime dob, + TextEditingController nameController, + TextEditingController emailController, + TextEditingController locationController, + String? imageUrl, + UserGender? gender, + BattingStyle? battingStyle, + BowlingStyle? bowlingStyle, + PlayerRole? playerRole, + bool isButtonEnable, + bool isSaved, + bool isSaveInProgress, + UserModel? currentUser}); + + @override + $UserModelCopyWith<$Res>? get currentUser; +} + +/// @nodoc +class __$$EditProfileStateImplCopyWithImpl<$Res> + extends _$EditProfileStateCopyWithImpl<$Res, _$EditProfileStateImpl> + implements _$$EditProfileStateImplCopyWith<$Res> { + __$$EditProfileStateImplCopyWithImpl(_$EditProfileStateImpl _value, + $Res Function(_$EditProfileStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? dob = null, + Object? nameController = null, + Object? emailController = null, + Object? locationController = null, + Object? imageUrl = freezed, + Object? gender = freezed, + Object? battingStyle = freezed, + Object? bowlingStyle = freezed, + Object? playerRole = freezed, + Object? isButtonEnable = null, + Object? isSaved = null, + Object? isSaveInProgress = null, + Object? currentUser = freezed, + }) { + return _then(_$EditProfileStateImpl( + dob: null == dob + ? _value.dob + : dob // ignore: cast_nullable_to_non_nullable + as DateTime, + nameController: null == nameController + ? _value.nameController + : nameController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + emailController: null == emailController + ? _value.emailController + : emailController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + locationController: null == locationController + ? _value.locationController + : locationController // ignore: cast_nullable_to_non_nullable + as TextEditingController, + imageUrl: freezed == imageUrl + ? _value.imageUrl + : imageUrl // ignore: cast_nullable_to_non_nullable + as String?, + gender: freezed == gender + ? _value.gender + : gender // ignore: cast_nullable_to_non_nullable + as UserGender?, + battingStyle: freezed == battingStyle + ? _value.battingStyle + : battingStyle // ignore: cast_nullable_to_non_nullable + as BattingStyle?, + bowlingStyle: freezed == bowlingStyle + ? _value.bowlingStyle + : bowlingStyle // ignore: cast_nullable_to_non_nullable + as BowlingStyle?, + playerRole: freezed == playerRole + ? _value.playerRole + : playerRole // ignore: cast_nullable_to_non_nullable + as PlayerRole?, + isButtonEnable: null == isButtonEnable + ? _value.isButtonEnable + : isButtonEnable // ignore: cast_nullable_to_non_nullable + as bool, + isSaved: null == isSaved + ? _value.isSaved + : isSaved // ignore: cast_nullable_to_non_nullable + as bool, + isSaveInProgress: null == isSaveInProgress + ? _value.isSaveInProgress + : isSaveInProgress // ignore: cast_nullable_to_non_nullable + as bool, + currentUser: freezed == currentUser + ? _value.currentUser + : currentUser // ignore: cast_nullable_to_non_nullable + as UserModel?, + )); + } +} + +/// @nodoc + +class _$EditProfileStateImpl implements _EditProfileState { + const _$EditProfileStateImpl( + {required this.dob, + required this.nameController, + required this.emailController, + required this.locationController, + this.imageUrl = null, + this.gender = null, + this.battingStyle = null, + this.bowlingStyle = null, + this.playerRole = null, + this.isButtonEnable = false, + this.isSaved = false, + this.isSaveInProgress = false, + this.currentUser}); + + @override + final DateTime dob; + @override + final TextEditingController nameController; + @override + final TextEditingController emailController; + @override + final TextEditingController locationController; + @override + @JsonKey() + final String? imageUrl; + @override + @JsonKey() + final UserGender? gender; + @override + @JsonKey() + final BattingStyle? battingStyle; + @override + @JsonKey() + final BowlingStyle? bowlingStyle; + @override + @JsonKey() + final PlayerRole? playerRole; + @override + @JsonKey() + final bool isButtonEnable; + @override + @JsonKey() + final bool isSaved; + @override + @JsonKey() + final bool isSaveInProgress; + @override + final UserModel? currentUser; + + @override + String toString() { + return 'EditProfileState(dob: $dob, nameController: $nameController, emailController: $emailController, locationController: $locationController, imageUrl: $imageUrl, gender: $gender, battingStyle: $battingStyle, bowlingStyle: $bowlingStyle, playerRole: $playerRole, isButtonEnable: $isButtonEnable, isSaved: $isSaved, isSaveInProgress: $isSaveInProgress, currentUser: $currentUser)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$EditProfileStateImpl && + (identical(other.dob, dob) || other.dob == dob) && + (identical(other.nameController, nameController) || + other.nameController == nameController) && + (identical(other.emailController, emailController) || + other.emailController == emailController) && + (identical(other.locationController, locationController) || + other.locationController == locationController) && + (identical(other.imageUrl, imageUrl) || + other.imageUrl == imageUrl) && + (identical(other.gender, gender) || other.gender == gender) && + (identical(other.battingStyle, battingStyle) || + other.battingStyle == battingStyle) && + (identical(other.bowlingStyle, bowlingStyle) || + other.bowlingStyle == bowlingStyle) && + (identical(other.playerRole, playerRole) || + other.playerRole == playerRole) && + (identical(other.isButtonEnable, isButtonEnable) || + other.isButtonEnable == isButtonEnable) && + (identical(other.isSaved, isSaved) || other.isSaved == isSaved) && + (identical(other.isSaveInProgress, isSaveInProgress) || + other.isSaveInProgress == isSaveInProgress) && + (identical(other.currentUser, currentUser) || + other.currentUser == currentUser)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + dob, + nameController, + emailController, + locationController, + imageUrl, + gender, + battingStyle, + bowlingStyle, + playerRole, + isButtonEnable, + isSaved, + isSaveInProgress, + currentUser); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$EditProfileStateImplCopyWith<_$EditProfileStateImpl> get copyWith => + __$$EditProfileStateImplCopyWithImpl<_$EditProfileStateImpl>( + this, _$identity); +} + +abstract class _EditProfileState implements EditProfileState { + const factory _EditProfileState( + {required final DateTime dob, + required final TextEditingController nameController, + required final TextEditingController emailController, + required final TextEditingController locationController, + final String? imageUrl, + final UserGender? gender, + final BattingStyle? battingStyle, + final BowlingStyle? bowlingStyle, + final PlayerRole? playerRole, + final bool isButtonEnable, + final bool isSaved, + final bool isSaveInProgress, + final UserModel? currentUser}) = _$EditProfileStateImpl; + + @override + DateTime get dob; + @override + TextEditingController get nameController; + @override + TextEditingController get emailController; + @override + TextEditingController get locationController; + @override + String? get imageUrl; + @override + UserGender? get gender; + @override + BattingStyle? get battingStyle; + @override + BowlingStyle? get bowlingStyle; + @override + PlayerRole? get playerRole; + @override + bool get isButtonEnable; + @override + bool get isSaved; + @override + bool get isSaveInProgress; + @override + UserModel? get currentUser; + @override + @JsonKey(ignore: true) + _$$EditProfileStateImplCopyWith<_$EditProfileStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_screen.dart b/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_screen.dart index 2dce7b07..9b5d55c7 100644 --- a/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_screen.dart +++ b/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_screen.dart @@ -44,9 +44,9 @@ class _PhoneVerificationScreenState void _observeVerificationComplete() { ref.listen( phoneVerificationStateProvider - .select((value) => value.verificationComplete), (previous, next) { - if (next) { - context.pop(true); + .select((value) => value.credential), (previous, next) { + if (next != null) { + context.pop(next); } }); } diff --git a/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_view_model.dart b/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_view_model.dart index f3472401..e4f44d91 100644 --- a/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_view_model.dart +++ b/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_view_model.dart @@ -1,5 +1,8 @@ import 'dart:async'; +import 'package:data/api/user/user_models.dart'; +import 'package:data/service/user/user_service.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -8,21 +11,20 @@ part 'phone_verification_view_model.freezed.dart'; final phoneVerificationStateProvider = StateNotifierProvider.autoDispose< PhoneVerificationViewNotifier, PhoneVerificationState>((ref) { return PhoneVerificationViewNotifier( - FirebaseAuth.instance, - ); + FirebaseAuth.instance, ref.read(userServiceProvider)); }); class PhoneVerificationViewNotifier extends StateNotifier { final FirebaseAuth firebaseAuth; + final UserService userService; late Timer timer; late String phoneNumber; bool firstAutoVerificationComplete = false; - PhoneVerificationViewNotifier( - this.firebaseAuth, - ) : super(const PhoneVerificationState()) { + PhoneVerificationViewNotifier(this.firebaseAuth, this.userService) + : super(const PhoneVerificationState()) { updateResendCodeTimerDuration(); } @@ -60,33 +62,51 @@ class PhoneVerificationViewNotifier } Future resendCode({required String phone}) async { - state = state.copyWith(error: null); - updateResendCodeTimerDuration(); - await firebaseAuth.verifyPhoneNumber( - phoneNumber: phone, - verificationCompleted: (phoneAuthCredential) async { - try { - final userCredential = - await firebaseAuth.signInWithCredential(phoneAuthCredential); - onVerificationSuccess(userCredential); - } catch (error) { + try { + state = state.copyWith(error: null); + updateResendCodeTimerDuration(); + await firebaseAuth.verifyPhoneNumber( + phoneNumber: phone, + verificationCompleted: (phoneAuthCredential) async { + try { + final userCredential = + await firebaseAuth.signInWithCredential(phoneAuthCredential); + onVerificationSuccess(userCredential); + } catch (error) { + state = state.copyWith(error: error); + } + }, + verificationFailed: (error) { state = state.copyWith(error: error); - } - }, - verificationFailed: (error) { - state = state.copyWith(error: error); - }, - codeSent: (verificationId, forceResendingToken) { - state = state.copyWith(verificationId: verificationId); - }, - codeAutoRetrievalTimeout: (verificationId) {}, - ); + }, + codeSent: (verificationId, forceResendingToken) { + state = state.copyWith(verificationId: verificationId); + }, + codeAutoRetrievalTimeout: (verificationId) {}, + ); + } catch (e) { + debugPrint("PhoneVerificationViewNotifier: error in resend otp -> $e"); + } } - void onVerificationSuccess(UserCredential credential) { - // do something with cred - // return cred info to prev screen to push from edit screen - state = state.copyWith(verifying: false, verificationComplete: true); + Future onVerificationSuccess(UserCredential credential) async { + try { + if (credential.additionalUserInfo?.isNewUser ?? false) { + UserModel user = UserModel( + id: firebaseAuth.currentUser?.uid ?? "INVALID ID", + phone: firebaseAuth.currentUser?.phoneNumber, + created_at: DateTime.now()); + await userService.updateUser(user); + state = state.copyWith(verifying: false, credential: credential); + } else { + // get user + await userService.getUser(credential.user?.uid ?? "INVALID ID"); + state = state.copyWith(verifying: false, credential: credential); + } + } catch (e) { + debugPrint( + "PhoneVerificationViewNotifier: error in onVerificationSuccess -> $e"); + } } Future verifyOTP() async { @@ -101,8 +121,9 @@ class PhoneVerificationViewNotifier final userCredential = await firebaseAuth.signInWithCredential(credential); onVerificationSuccess(userCredential); - } catch (error) { - state = state.copyWith(verifying: false, error: error); + } catch (e) { + state = state.copyWith(verifying: false, error: e); + debugPrint("PhoneVerificationViewNotifier: error in verifyOTP -> $e"); } } @@ -118,7 +139,7 @@ class PhoneVerificationState with _$PhoneVerificationState { const factory PhoneVerificationState({ @Default(false) bool verifying, @Default(false) bool enableVerify, - @Default(false) bool verificationComplete, + @Default(null) UserCredential? credential, String? verificationId, @Default('') String otp, @Default(Duration(seconds: 30)) Duration activeResendDuration, diff --git a/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_view_model.freezed.dart b/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_view_model.freezed.dart index 8d372feb..d7e6915f 100644 --- a/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_view_model.freezed.dart +++ b/khelo/lib/ui/flow/sign_in/phone_verification/phone_verification_view_model.freezed.dart @@ -18,7 +18,7 @@ final _privateConstructorUsedError = UnsupportedError( mixin _$PhoneVerificationState { bool get verifying => throw _privateConstructorUsedError; bool get enableVerify => throw _privateConstructorUsedError; - bool get verificationComplete => throw _privateConstructorUsedError; + UserCredential? get credential => throw _privateConstructorUsedError; String? get verificationId => throw _privateConstructorUsedError; String get otp => throw _privateConstructorUsedError; Duration get activeResendDuration => throw _privateConstructorUsedError; @@ -38,7 +38,7 @@ abstract class $PhoneVerificationStateCopyWith<$Res> { $Res call( {bool verifying, bool enableVerify, - bool verificationComplete, + UserCredential? credential, String? verificationId, String otp, Duration activeResendDuration, @@ -61,7 +61,7 @@ class _$PhoneVerificationStateCopyWithImpl<$Res, $Res call({ Object? verifying = null, Object? enableVerify = null, - Object? verificationComplete = null, + Object? credential = freezed, Object? verificationId = freezed, Object? otp = null, Object? activeResendDuration = null, @@ -76,10 +76,10 @@ class _$PhoneVerificationStateCopyWithImpl<$Res, ? _value.enableVerify : enableVerify // ignore: cast_nullable_to_non_nullable as bool, - verificationComplete: null == verificationComplete - ? _value.verificationComplete - : verificationComplete // ignore: cast_nullable_to_non_nullable - as bool, + credential: freezed == credential + ? _value.credential + : credential // ignore: cast_nullable_to_non_nullable + as UserCredential?, verificationId: freezed == verificationId ? _value.verificationId : verificationId // ignore: cast_nullable_to_non_nullable @@ -109,7 +109,7 @@ abstract class _$$PhoneVerificationStateImplCopyWith<$Res> $Res call( {bool verifying, bool enableVerify, - bool verificationComplete, + UserCredential? credential, String? verificationId, String otp, Duration activeResendDuration, @@ -131,7 +131,7 @@ class __$$PhoneVerificationStateImplCopyWithImpl<$Res> $Res call({ Object? verifying = null, Object? enableVerify = null, - Object? verificationComplete = null, + Object? credential = freezed, Object? verificationId = freezed, Object? otp = null, Object? activeResendDuration = null, @@ -146,10 +146,10 @@ class __$$PhoneVerificationStateImplCopyWithImpl<$Res> ? _value.enableVerify : enableVerify // ignore: cast_nullable_to_non_nullable as bool, - verificationComplete: null == verificationComplete - ? _value.verificationComplete - : verificationComplete // ignore: cast_nullable_to_non_nullable - as bool, + credential: freezed == credential + ? _value.credential + : credential // ignore: cast_nullable_to_non_nullable + as UserCredential?, verificationId: freezed == verificationId ? _value.verificationId : verificationId // ignore: cast_nullable_to_non_nullable @@ -173,7 +173,7 @@ class _$PhoneVerificationStateImpl implements _PhoneVerificationState { const _$PhoneVerificationStateImpl( {this.verifying = false, this.enableVerify = false, - this.verificationComplete = false, + this.credential = null, this.verificationId, this.otp = '', this.activeResendDuration = const Duration(seconds: 30), @@ -187,7 +187,7 @@ class _$PhoneVerificationStateImpl implements _PhoneVerificationState { final bool enableVerify; @override @JsonKey() - final bool verificationComplete; + final UserCredential? credential; @override final String? verificationId; @override @@ -201,7 +201,7 @@ class _$PhoneVerificationStateImpl implements _PhoneVerificationState { @override String toString() { - return 'PhoneVerificationState(verifying: $verifying, enableVerify: $enableVerify, verificationComplete: $verificationComplete, verificationId: $verificationId, otp: $otp, activeResendDuration: $activeResendDuration, error: $error)'; + return 'PhoneVerificationState(verifying: $verifying, enableVerify: $enableVerify, credential: $credential, verificationId: $verificationId, otp: $otp, activeResendDuration: $activeResendDuration, error: $error)'; } @override @@ -213,8 +213,8 @@ class _$PhoneVerificationStateImpl implements _PhoneVerificationState { other.verifying == verifying) && (identical(other.enableVerify, enableVerify) || other.enableVerify == enableVerify) && - (identical(other.verificationComplete, verificationComplete) || - other.verificationComplete == verificationComplete) && + (identical(other.credential, credential) || + other.credential == credential) && (identical(other.verificationId, verificationId) || other.verificationId == verificationId) && (identical(other.otp, otp) || other.otp == otp) && @@ -228,7 +228,7 @@ class _$PhoneVerificationStateImpl implements _PhoneVerificationState { runtimeType, verifying, enableVerify, - verificationComplete, + credential, verificationId, otp, activeResendDuration, @@ -246,7 +246,7 @@ abstract class _PhoneVerificationState implements PhoneVerificationState { const factory _PhoneVerificationState( {final bool verifying, final bool enableVerify, - final bool verificationComplete, + final UserCredential? credential, final String? verificationId, final String otp, final Duration activeResendDuration, @@ -257,7 +257,7 @@ abstract class _PhoneVerificationState implements PhoneVerificationState { @override bool get enableVerify; @override - bool get verificationComplete; + UserCredential? get credential; @override String? get verificationId; @override diff --git a/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_screen.dart b/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_screen.dart index f9ba0816..4d5316c4 100644 --- a/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_screen.dart +++ b/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_screen.dart @@ -1,9 +1,9 @@ import 'package:data/storage/app_preferences.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.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/ui/app_route.dart'; @@ -30,12 +30,13 @@ class _SignInWithPhoneScreenState extends ConsumerState { (previous, current) async { if (current != null) { final state = ref.read(signInWithPhoneStateProvider); - final bool? success = await AppRoute.verifyOTP( + final UserCredential? success = await AppRoute.verifyOTP( phoneNumber: state.code.dialCode + state.phone, verificationId: current, - ).push(context); - if (success == true && context.mounted) context.pop(true); + ).push(context); + if (success != null && context.mounted) onSignInSuccess(success); + //context.pop(true); //onSignInSuccess(); // in place of context.pop } }, @@ -46,9 +47,9 @@ class _SignInWithPhoneScreenState extends ConsumerState { ref.listen( signInWithPhoneStateProvider.select((value) => value.signInSuccess), (previous, current) async { - if (current && context.mounted) { - context.pop(true); - //onSignInSuccess(); // in place of context.pop + if (current != null && context.mounted) { + // context.pop(true); + onSignInSuccess(current); // in place of context.pop } }, ); @@ -137,12 +138,12 @@ class _SignInWithPhoneScreenState extends ConsumerState { ); } - void onSignInSuccess() async { + void onSignInSuccess(UserCredential credential) async { final user = ref.read(currentUserPod); if (user?.name == null || user!.name!.isEmpty) { - // await AppRoute.editProfile(blockBackButton: true).push(context); - await AppRoute.editProfile.push(context); + AppRoute.editProfile(isToCreateAccount: true).go(context); + } else { + AppRoute.main.go(context); } - if (mounted) context.pop(true); } } diff --git a/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_view_model.dart b/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_view_model.dart index cfb443fe..792efc49 100644 --- a/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_view_model.dart +++ b/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_view_model.dart @@ -1,5 +1,7 @@ import 'package:canopas_country_picker/canopas_country_picker.dart'; +import 'package:data/api/user/user_models.dart'; import 'package:data/service/device/device_service.dart'; +import 'package:data/service/user/user_service.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -9,15 +11,17 @@ part 'sign_in_with_phone_view_model.freezed.dart'; final signInWithPhoneStateProvider = StateNotifierProvider.autoDispose< SignInWithPhoneViewNotifier, SignInWithPhoneState>((ref) { - return SignInWithPhoneViewNotifier( - FirebaseAuth.instance, ref.read(deviceServiceProvider)); + return SignInWithPhoneViewNotifier(FirebaseAuth.instance, + ref.read(userServiceProvider), ref.read(deviceServiceProvider)); }); class SignInWithPhoneViewNotifier extends StateNotifier { final FirebaseAuth firebaseAuth; + final UserService userService; final DeviceService deviceService; - SignInWithPhoneViewNotifier(this.firebaseAuth, this.deviceService) + SignInWithPhoneViewNotifier( + this.firebaseAuth, this.userService, this.deviceService) : super( SignInWithPhoneState( code: CountryCode.getCountryCodeByAlpha2( @@ -40,7 +44,8 @@ class SignInWithPhoneViewNotifier extends StateNotifier { ); } } catch (e) { - //Error: couldn't get country code + debugPrint( + "SignInWithPhoneViewNotifier: error in fetchCountryCode -> $e"); } } @@ -58,24 +63,34 @@ class SignInWithPhoneViewNotifier extends StateNotifier { Future verifyPhoneNumber() async { state = state.copyWith(verifying: true, error: null); - await firebaseAuth.verifyPhoneNumber( - phoneNumber: state.code.dialCode + state.phone, - verificationCompleted: (phoneAuthCredential) async { - // automated sign in handled in android - await firebaseAuth.signInWithCredential(phoneAuthCredential); - // return cred info to prev screen to push from edit screen + try { + await firebaseAuth.verifyPhoneNumber( + phoneNumber: state.code.dialCode + state.phone, + verificationCompleted: (phoneAuthCredential) async { + final credential = + await firebaseAuth.signInWithCredential(phoneAuthCredential); - state = state.copyWith(verifying: false, signInSuccess: true); - }, - verificationFailed: (error) { - state = state.copyWith(verifying: false, error: error); - }, - codeSent: (verificationId, forceResendingToken) { - state = - state.copyWith(verificationId: verificationId, verifying: false); - }, - codeAutoRetrievalTimeout: (verificationId) {}, - ); + // call update function and update user in db + UserModel user = UserModel( + id: firebaseAuth.currentUser?.uid ?? "INVALID ID", + phone: firebaseAuth.currentUser?.phoneNumber); + await userService.updateUser(user); + state = state.copyWith(verifying: false, signInSuccess: credential); + }, + verificationFailed: (error) { + state = state.copyWith(verifying: false, error: error); + }, + codeSent: (verificationId, forceResendingToken) { + state = + state.copyWith(verificationId: verificationId, verifying: false); + }, + codeAutoRetrievalTimeout: (verificationId) {}, + ); + } catch (e) { + state = state.copyWith(verifying: false, error: e); + debugPrint( + "SignInWithPhoneViewNotifier: error in verifyPhoneNumber -> $e"); + } } } @@ -84,7 +99,7 @@ class SignInWithPhoneState with _$SignInWithPhoneState { const factory SignInWithPhoneState({ required CountryCode code, @Default(false) bool verifying, - @Default(false) bool signInSuccess, + @Default(null) UserCredential? signInSuccess, String? verificationId, @Default(false) bool enableNext, Object? error, diff --git a/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_view_model.freezed.dart b/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_view_model.freezed.dart index 147bdac2..354c427a 100644 --- a/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_view_model.freezed.dart +++ b/khelo/lib/ui/flow/sign_in/sign_in_with_phone/sign_in_with_phone_view_model.freezed.dart @@ -18,7 +18,7 @@ final _privateConstructorUsedError = UnsupportedError( mixin _$SignInWithPhoneState { CountryCode get code => throw _privateConstructorUsedError; bool get verifying => throw _privateConstructorUsedError; - bool get signInSuccess => throw _privateConstructorUsedError; + UserCredential? get signInSuccess => throw _privateConstructorUsedError; String? get verificationId => throw _privateConstructorUsedError; bool get enableNext => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; @@ -38,7 +38,7 @@ abstract class $SignInWithPhoneStateCopyWith<$Res> { $Res call( {CountryCode code, bool verifying, - bool signInSuccess, + UserCredential? signInSuccess, String? verificationId, bool enableNext, Object? error, @@ -61,7 +61,7 @@ class _$SignInWithPhoneStateCopyWithImpl<$Res, $Res call({ Object? code = null, Object? verifying = null, - Object? signInSuccess = null, + Object? signInSuccess = freezed, Object? verificationId = freezed, Object? enableNext = null, Object? error = freezed, @@ -76,10 +76,10 @@ class _$SignInWithPhoneStateCopyWithImpl<$Res, ? _value.verifying : verifying // ignore: cast_nullable_to_non_nullable as bool, - signInSuccess: null == signInSuccess + signInSuccess: freezed == signInSuccess ? _value.signInSuccess : signInSuccess // ignore: cast_nullable_to_non_nullable - as bool, + as UserCredential?, verificationId: freezed == verificationId ? _value.verificationId : verificationId // ignore: cast_nullable_to_non_nullable @@ -108,7 +108,7 @@ abstract class _$$SignInWithPhoneStateImplCopyWith<$Res> $Res call( {CountryCode code, bool verifying, - bool signInSuccess, + UserCredential? signInSuccess, String? verificationId, bool enableNext, Object? error, @@ -128,7 +128,7 @@ class __$$SignInWithPhoneStateImplCopyWithImpl<$Res> $Res call({ Object? code = null, Object? verifying = null, - Object? signInSuccess = null, + Object? signInSuccess = freezed, Object? verificationId = freezed, Object? enableNext = null, Object? error = freezed, @@ -143,10 +143,10 @@ class __$$SignInWithPhoneStateImplCopyWithImpl<$Res> ? _value.verifying : verifying // ignore: cast_nullable_to_non_nullable as bool, - signInSuccess: null == signInSuccess + signInSuccess: freezed == signInSuccess ? _value.signInSuccess : signInSuccess // ignore: cast_nullable_to_non_nullable - as bool, + as UserCredential?, verificationId: freezed == verificationId ? _value.verificationId : verificationId // ignore: cast_nullable_to_non_nullable @@ -170,7 +170,7 @@ class _$SignInWithPhoneStateImpl implements _SignInWithPhoneState { const _$SignInWithPhoneStateImpl( {required this.code, this.verifying = false, - this.signInSuccess = false, + this.signInSuccess = null, this.verificationId, this.enableNext = false, this.error, @@ -183,7 +183,7 @@ class _$SignInWithPhoneStateImpl implements _SignInWithPhoneState { final bool verifying; @override @JsonKey() - final bool signInSuccess; + final UserCredential? signInSuccess; @override final String? verificationId; @override @@ -242,7 +242,7 @@ abstract class _SignInWithPhoneState implements SignInWithPhoneState { const factory _SignInWithPhoneState( {required final CountryCode code, final bool verifying, - final bool signInSuccess, + final UserCredential? signInSuccess, final String? verificationId, final bool enableNext, final Object? error, @@ -253,7 +253,7 @@ abstract class _SignInWithPhoneState implements SignInWithPhoneState { @override bool get verifying; @override - bool get signInSuccess; + UserCredential? get signInSuccess; @override String? get verificationId; @override diff --git a/khelo/linux/flutter/generated_plugin_registrant.cc b/khelo/linux/flutter/generated_plugin_registrant.cc index e71a16d2..64a0ecea 100644 --- a/khelo/linux/flutter/generated_plugin_registrant.cc +++ b/khelo/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); } diff --git a/khelo/linux/flutter/generated_plugins.cmake b/khelo/linux/flutter/generated_plugins.cmake index 2e1de87a..2db3c22a 100644 --- a/khelo/linux/flutter/generated_plugins.cmake +++ b/khelo/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/khelo/macos/Flutter/GeneratedPluginRegistrant.swift b/khelo/macos/Flutter/GeneratedPluginRegistrant.swift index d531019e..481fc0b5 100644 --- a/khelo/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/khelo/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,18 +5,28 @@ import FlutterMacOS import Foundation +import cloud_firestore import device_info_plus +import file_selector_macos import firebase_auth import firebase_core +import firebase_storage import flutter_timezone import package_info_plus +import path_provider_foundation import shared_preferences_foundation +import sqflite func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/khelo/pubspec.lock b/khelo/pubspec.lock index bed12be7..98e2e308 100644 --- a/khelo/pubspec.lock +++ b/khelo/pubspec.lock @@ -129,6 +129,30 @@ packages: url: "https://pub.dev" source: hosted version: "8.8.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" + url: "https://pub.dev" + source: hosted + version: "1.1.1" canopas_country_picker: dependency: "direct main" description: @@ -177,6 +201,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + cloud_firestore: + dependency: "direct main" + description: + name: cloud_firestore + sha256: "8bfbb5a2edbc6052452326d60de0113fea2bcbf081d34a3f8e45c8b38307b31c" + url: "https://pub.dev" + source: hosted + version: "4.14.0" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + sha256: "73ff438fe46028f0e19f55da18b6ddc6906ab750562cd7d9ffab77ff8c0c4307" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + sha256: "232e45e95970d3a6baab8f50f9c3a6e2838d145d9d91ec9a7392837c44296397" + url: "https://pub.dev" + source: hosted + version: "3.9.0" code_builder: dependency: transitive description: @@ -209,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.7.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + url: "https://pub.dev" + source: hosted + version: "0.3.3+8" crypto: dependency: transitive description: @@ -312,6 +368,38 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + url: "https://pub.dev" + source: hosted + version: "0.9.2+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" firebase_auth: dependency: "direct main" description: @@ -360,6 +448,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.10.0" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + sha256: "75e6cb6bed65138b5bbd86bfd7cf9bc9a175fb0c31aacc400e9203df117ffbe6" + url: "https://pub.dev" + source: hosted + version: "11.6.0" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + sha256: "545a3a8edf337850403bb0fa03c8074a53deb87c0107d19755c77a82ce07919e" + url: "https://pub.dev" + source: hosted + version: "5.1.3" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + sha256: ee6870ff79aa304b8996ba18a4aefe1e8b3fc31fd385eab6574180267aa8d393 + url: "https://pub.dev" + source: hosted + version: "3.6.17" fixnum: dependency: transitive description: @@ -373,6 +485,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.dev" + source: hosted + version: "3.3.1" flutter_hooks: dependency: transitive description: @@ -385,15 +505,23 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "3.0.1" flutter_localizations: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + url: "https://pub.dev" + source: hosted + version: "2.0.17" flutter_riverpod: dependency: "direct main" description: @@ -456,10 +584,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: c5fa45fa502ee880839e3b2152d987c44abae26d064a2376d4aad434cf0f7b15 + sha256: "3b40e751eaaa855179b416974d59d29669e750d2e50fcdb2b37f1cb0ca8c803a" url: "https://pub.dev" source: hosted - version: "12.1.3" + version: "13.0.1" go_router_builder: dependency: "direct dev" description: @@ -516,6 +644,94 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image_cropper: + dependency: "direct main" + description: + name: image_cropper + sha256: f4bad5ed2dfff5a7ce0dfbad545b46a945c702bb6182a921488ef01ba7693111 + url: "https://pub.dev" + source: hosted + version: "5.0.1" + image_cropper_for_web: + dependency: transitive + description: + name: image_cropper_for_web + sha256: "865d798b5c9d826f1185b32e5d0018c4183ddb77b7b82a931e1a06aa3b74974e" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + image_cropper_platform_interface: + dependency: transitive + description: + name: image_cropper_platform_interface + sha256: ee160d686422272aa306125f3b6fb1c1894d9b87a5e20ed33fa008e7285da11e + url: "https://pub.dev" + source: hosted + version: "5.0.0" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "26222b01a0c9a2c8fe02fc90b8208bd3325da5ed1f4a2acabf75939031ac0bdd" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" + url: "https://pub.dev" + source: hosted + version: "0.8.9+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3 + url: "https://pub.dev" + source: hosted + version: "3.0.2" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3 + url: "https://pub.dev" + source: hosted + version: "0.8.9+1" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b + url: "https://pub.dev" + source: hosted + version: "2.9.3" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" intl: dependency: "direct main" description: @@ -560,10 +776,10 @@ packages: dependency: transitive description: name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "3.0.0" logging: dependency: transitive description: @@ -612,6 +828,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + url: "https://pub.dev" + source: hosted + version: "2.0.0" package_config: dependency: transitive description: @@ -644,6 +868,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -741,7 +989,7 @@ packages: source: hosted version: "0.27.7" shared_preferences: - dependency: transitive + dependency: "direct main" description: name: shared_preferences sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" @@ -881,6 +1129,22 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: c2c32eb0c74021d987336522acc3b6bf0082fbd0c540c36a9cf4ddb8ba891ddc + url: "https://pub.dev" + source: hosted + version: "2.3.1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" stack_trace: dependency: transitive description: @@ -928,6 +1192,14 @@ packages: relative: true source: path version: "0.0.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" term_glyph: dependency: transitive description: diff --git a/khelo/pubspec.yaml b/khelo/pubspec.yaml index b0be5b7d..10ffc613 100644 --- a/khelo/pubspec.yaml +++ b/khelo/pubspec.yaml @@ -39,11 +39,16 @@ dependencies: data: path: ../data + shared_preferences: ^2.0.18 + # UI cupertino_icons: ^1.0.2 + image_cropper: ^5.0.1 + cached_network_image: ^3.3.1 # picker canopas_country_picker: ^0.0.4 + image_picker: ^1.0.7 # io freezed_annotation: ^2.4.1 @@ -51,18 +56,20 @@ dependencies: # auth firebase_core: ^2.24.2 firebase_auth: ^4.16.0 + firebase_storage: ^11.6.0 + cloud_firestore: ^4.14.0 # state management - flutter_riverpod: ^2.3.1 - hooks_riverpod: ^2.3.1 + flutter_riverpod: ^2.4.9 + hooks_riverpod: ^2.4.9 # navigation - go_router: ^12.0.1 + go_router: ^13.0.1 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_lints: ^3.0.1 riverpod_lint: ^2.1.1 # code generation @@ -79,6 +86,9 @@ flutter: generate: true uses-material-design: true + assets: + - assets/images/. + # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg diff --git a/khelo/windows/flutter/generated_plugin_registrant.cc b/khelo/windows/flutter/generated_plugin_registrant.cc index d141b74f..ec1e463e 100644 --- a/khelo/windows/flutter/generated_plugin_registrant.cc +++ b/khelo/windows/flutter/generated_plugin_registrant.cc @@ -6,12 +6,21 @@ #include "generated_plugin_registrant.h" +#include +#include #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + CloudFirestorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("CloudFirestorePluginCApi")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); FirebaseAuthPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi")); FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FirebaseStoragePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi")); } diff --git a/khelo/windows/flutter/generated_plugins.cmake b/khelo/windows/flutter/generated_plugins.cmake index 29944d5b..767b5286 100644 --- a/khelo/windows/flutter/generated_plugins.cmake +++ b/khelo/windows/flutter/generated_plugins.cmake @@ -3,8 +3,11 @@ # list(APPEND FLUTTER_PLUGIN_LIST + cloud_firestore + file_selector_windows firebase_auth firebase_core + firebase_storage ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/run_lint b/run_lint index cde3a6b9..d2f9c8e3 100755 --- a/run_lint +++ b/run_lint @@ -2,4 +2,4 @@ cd data && flutter analyze --fatal-infos || true cd ../style && flutter analyze --fatal-infos || true -cd ../app && flutter analyze --fatal-infos || true +cd ../khelo && flutter analyze --fatal-infos || true diff --git a/style/lib/extensions/date_extensions.dart b/style/lib/extensions/date_extensions.dart new file mode 100644 index 00000000..6317fa18 --- /dev/null +++ b/style/lib/extensions/date_extensions.dart @@ -0,0 +1,3 @@ +extension DateTimeExtensions on DateTime { + DateTime get startOfDay => DateTime(year, month, day); +} \ No newline at end of file