diff --git a/data/.flutter-plugins b/data/.flutter-plugins index 2f20d04d..76ffe17c 100644 --- a/data/.flutter-plugins +++ b/data/.flutter-plugins @@ -1,24 +1,24 @@ # This is a generated file; do not edit or check into version control. -cloud_firestore=/home/mayank/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/ -cloud_firestore_web=/home/mayank/.pub-cache/hosted/pub.dev/cloud_firestore_web-4.3.2/ -cloud_functions=/home/mayank/.pub-cache/hosted/pub.dev/cloud_functions-5.1.3/ -cloud_functions_web=/home/mayank/.pub-cache/hosted/pub.dev/cloud_functions_web-4.10.2/ -device_info_plus=/home/mayank/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/ -firebase_auth=/home/mayank/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/ -firebase_auth_web=/home/mayank/.pub-cache/hosted/pub.dev/firebase_auth_web-5.13.2/ -firebase_core=/home/mayank/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/ -firebase_core_web=/home/mayank/.pub-cache/hosted/pub.dev/firebase_core_web-2.18.1/ -firebase_messaging=/home/mayank/.pub-cache/hosted/pub.dev/firebase_messaging-15.1.3/ -firebase_messaging_web=/home/mayank/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.9.2/ -firebase_storage=/home/mayank/.pub-cache/hosted/pub.dev/firebase_storage-12.3.2/ -firebase_storage_web=/home/mayank/.pub-cache/hosted/pub.dev/firebase_storage_web-3.10.2/ -flutter_timezone=/home/mayank/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/ -package_info_plus=/home/mayank/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/ -path_provider_linux=/home/mayank/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/home/mayank/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/ -shared_preferences=/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences-2.3.2/ -shared_preferences_android=/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_android-2.3.3/ -shared_preferences_foundation=/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/ -shared_preferences_linux=/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/ -shared_preferences_web=/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.2/ -shared_preferences_windows=/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/ +cloud_firestore=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/ +cloud_firestore_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore_web-4.3.2/ +cloud_functions=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_functions-5.1.3/ +cloud_functions_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_functions_web-4.10.2/ +device_info_plus=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/ +firebase_auth=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/ +firebase_auth_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth_web-5.13.2/ +firebase_core=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/ +firebase_core_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core_web-2.18.1/ +firebase_messaging=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_messaging-15.0.2/ +firebase_messaging_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.9.0/ +firebase_storage=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-12.3.3/ +firebase_storage_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage_web-3.10.3/ +flutter_timezone=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/ +package_info_plus=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/ +path_provider_linux=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ +shared_preferences=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences-2.3.2/ +shared_preferences_android=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_android-2.3.3/ +shared_preferences_foundation=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/ +shared_preferences_linux=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/ +shared_preferences_web=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.2/ +shared_preferences_windows=/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/ diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index a3d8252f..c32d1774 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":"cloud_firestore","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_functions-5.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_messaging-15.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_storage","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_storage-12.3.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/mayank/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_functions-5.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_messaging-15.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_storage","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_storage-12.3.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/mayank/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_android-2.3.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_functions-5.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_messaging-15.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_storage","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_storage-12.3.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/mayank/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/mayank/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_storage-12.3.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/mayank/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/mayank/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_firestore_web-4.3.2/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/mayank/.pub-cache/hosted/pub.dev/cloud_functions_web-4.10.2/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_auth_web-5.13.2/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_core_web-2.18.1/","dependencies":[]},{"name":"firebase_messaging_web","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.9.2/","dependencies":["firebase_core_web"]},{"name":"firebase_storage_web","path":"/home/mayank/.pub-cache/hosted/pub.dev/firebase_storage_web-3.10.2/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/mayank/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","dependencies":[]},{"name":"package_info_plus","path":"/home/mayank/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/mayank/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.2/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_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_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"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-11-25 14:43:28.651480","version":"3.24.3","swift_package_manager_enabled":false} \ 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-5.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_functions-5.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_messaging-15.0.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_storage","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-12.3.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_functions-5.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_messaging-15.0.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_storage","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-12.3.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_android-2.3.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_functions-5.1.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_messaging-15.0.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_storage","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-12.3.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","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-10.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","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.4.1/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore-5.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth-5.3.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core-3.6.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage-12.3.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","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.4.1/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_firestore_web-4.3.2/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/cloud_functions_web-4.10.2/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/device_info_plus-10.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_auth_web-5.13.2/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_core_web-2.18.1/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.9.0/","dependencies":["firebase_core_web"]},{"name":"firebase_storage_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/firebase_storage_web-3.10.3/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/flutter_timezone-3.0.1/","dependencies":[]},{"name":"package_info_plus","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/package_info_plus-8.0.2/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/sidhdhi.p/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.2/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_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_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"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-12-12 12:49:06.125107","version":"3.24.3","swift_package_manager_enabled":false} \ No newline at end of file diff --git a/data/lib/api/leaderboard/leaderboard_model.dart b/data/lib/api/leaderboard/leaderboard_model.dart new file mode 100644 index 00000000..d72c5995 --- /dev/null +++ b/data/lib/api/leaderboard/leaderboard_model.dart @@ -0,0 +1,82 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../../converter/timestamp_json_converter.dart'; +import '../../utils/constant/firestore_constant.dart'; +import '../user/user_models.dart'; + +part 'leaderboard_model.freezed.dart'; + +part 'leaderboard_model.g.dart'; + +@freezed +class LeaderboardModel with _$LeaderboardModel { + const factory LeaderboardModel({ + required LeaderboardField type, + @Default([]) List players, + }) = _LeaderboardModel; + + factory LeaderboardModel.fromJson(Map json) => + _$LeaderboardModelFromJson(json); + + factory LeaderboardModel.fromFireStore( + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => + LeaderboardModel.fromJson(snapshot.data()!); +} + +@freezed +class LeaderboardPlayer with _$LeaderboardPlayer { + const factory LeaderboardPlayer({ + @TimeStampJsonConverter() required DateTime date, + required String id, + @Default(0) int runs, + @Default(0) int wickets, + @Default(0) int catches, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user, + }) = _LeaderboardPlayer; + + factory LeaderboardPlayer.fromJson(Map json) => + _$LeaderboardPlayerFromJson(json); + + factory LeaderboardPlayer.fromFireStore( + DocumentSnapshot> snapshot, + SnapshotOptions? options, + ) => + LeaderboardPlayer.fromJson(snapshot.data()!); +} + +enum LeaderboardType { + weekly, + monthly, + allTime; + + String getDatabaseConst() { + switch (this) { + case LeaderboardType.weekly: + return FireStoreConst.weeklyDocument; + case LeaderboardType.monthly: + return FireStoreConst.monthlyDocument; + case LeaderboardType.allTime: + return FireStoreConst.allTimeDocument; + } + } +} + +enum LeaderboardField { + batting, + bowling, + fielding; + + String getDatabaseConst() { + switch (this) { + case LeaderboardField.batting: + return FireStoreConst.runs; + case LeaderboardField.bowling: + return FireStoreConst.wickets; + case LeaderboardField.fielding: + return FireStoreConst.catches; + } + } +} diff --git a/data/lib/api/leaderboard/leaderboard_model.freezed.dart b/data/lib/api/leaderboard/leaderboard_model.freezed.dart new file mode 100644 index 00000000..f931eeb9 --- /dev/null +++ b/data/lib/api/leaderboard/leaderboard_model.freezed.dart @@ -0,0 +1,476 @@ +// 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 'leaderboard_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +LeaderboardModel _$LeaderboardModelFromJson(Map json) { + return _LeaderboardModel.fromJson(json); +} + +/// @nodoc +mixin _$LeaderboardModel { + LeaderboardField get type => throw _privateConstructorUsedError; + List get players => throw _privateConstructorUsedError; + + /// Serializes this LeaderboardModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of LeaderboardModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $LeaderboardModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LeaderboardModelCopyWith<$Res> { + factory $LeaderboardModelCopyWith( + LeaderboardModel value, $Res Function(LeaderboardModel) then) = + _$LeaderboardModelCopyWithImpl<$Res, LeaderboardModel>; + @useResult + $Res call({LeaderboardField type, List players}); +} + +/// @nodoc +class _$LeaderboardModelCopyWithImpl<$Res, $Val extends LeaderboardModel> + implements $LeaderboardModelCopyWith<$Res> { + _$LeaderboardModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of LeaderboardModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? type = null, + Object? players = null, + }) { + return _then(_value.copyWith( + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as LeaderboardField, + players: null == players + ? _value.players + : players // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LeaderboardModelImplCopyWith<$Res> + implements $LeaderboardModelCopyWith<$Res> { + factory _$$LeaderboardModelImplCopyWith(_$LeaderboardModelImpl value, + $Res Function(_$LeaderboardModelImpl) then) = + __$$LeaderboardModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({LeaderboardField type, List players}); +} + +/// @nodoc +class __$$LeaderboardModelImplCopyWithImpl<$Res> + extends _$LeaderboardModelCopyWithImpl<$Res, _$LeaderboardModelImpl> + implements _$$LeaderboardModelImplCopyWith<$Res> { + __$$LeaderboardModelImplCopyWithImpl(_$LeaderboardModelImpl _value, + $Res Function(_$LeaderboardModelImpl) _then) + : super(_value, _then); + + /// Create a copy of LeaderboardModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? type = null, + Object? players = null, + }) { + return _then(_$LeaderboardModelImpl( + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as LeaderboardField, + players: null == players + ? _value._players + : players // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$LeaderboardModelImpl implements _LeaderboardModel { + const _$LeaderboardModelImpl( + {required this.type, final List players = const []}) + : _players = players; + + factory _$LeaderboardModelImpl.fromJson(Map json) => + _$$LeaderboardModelImplFromJson(json); + + @override + final LeaderboardField type; + final List _players; + @override + @JsonKey() + List get players { + if (_players is EqualUnmodifiableListView) return _players; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_players); + } + + @override + String toString() { + return 'LeaderboardModel(type: $type, players: $players)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LeaderboardModelImpl && + (identical(other.type, type) || other.type == type) && + const DeepCollectionEquality().equals(other._players, _players)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, type, const DeepCollectionEquality().hash(_players)); + + /// Create a copy of LeaderboardModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$LeaderboardModelImplCopyWith<_$LeaderboardModelImpl> get copyWith => + __$$LeaderboardModelImplCopyWithImpl<_$LeaderboardModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$LeaderboardModelImplToJson( + this, + ); + } +} + +abstract class _LeaderboardModel implements LeaderboardModel { + const factory _LeaderboardModel( + {required final LeaderboardField type, + final List players}) = _$LeaderboardModelImpl; + + factory _LeaderboardModel.fromJson(Map json) = + _$LeaderboardModelImpl.fromJson; + + @override + LeaderboardField get type; + @override + List get players; + + /// Create a copy of LeaderboardModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$LeaderboardModelImplCopyWith<_$LeaderboardModelImpl> get copyWith => + throw _privateConstructorUsedError; +} + +LeaderboardPlayer _$LeaderboardPlayerFromJson(Map json) { + return _LeaderboardPlayer.fromJson(json); +} + +/// @nodoc +mixin _$LeaderboardPlayer { + @TimeStampJsonConverter() + DateTime get date => throw _privateConstructorUsedError; + String get id => throw _privateConstructorUsedError; + int get runs => throw _privateConstructorUsedError; + int get wickets => throw _privateConstructorUsedError; + int get catches => throw _privateConstructorUsedError; + @JsonKey(includeToJson: false, includeFromJson: false) + UserModel? get user => throw _privateConstructorUsedError; + + /// Serializes this LeaderboardPlayer to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of LeaderboardPlayer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $LeaderboardPlayerCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LeaderboardPlayerCopyWith<$Res> { + factory $LeaderboardPlayerCopyWith( + LeaderboardPlayer value, $Res Function(LeaderboardPlayer) then) = + _$LeaderboardPlayerCopyWithImpl<$Res, LeaderboardPlayer>; + @useResult + $Res call( + {@TimeStampJsonConverter() DateTime date, + String id, + int runs, + int wickets, + int catches, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user}); + + $UserModelCopyWith<$Res>? get user; +} + +/// @nodoc +class _$LeaderboardPlayerCopyWithImpl<$Res, $Val extends LeaderboardPlayer> + implements $LeaderboardPlayerCopyWith<$Res> { + _$LeaderboardPlayerCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of LeaderboardPlayer + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = null, + Object? id = null, + Object? runs = null, + Object? wickets = null, + Object? catches = null, + Object? user = freezed, + }) { + return _then(_value.copyWith( + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as DateTime, + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + runs: null == runs + ? _value.runs + : runs // ignore: cast_nullable_to_non_nullable + as int, + wickets: null == wickets + ? _value.wickets + : wickets // ignore: cast_nullable_to_non_nullable + as int, + catches: null == catches + ? _value.catches + : catches // ignore: cast_nullable_to_non_nullable + as int, + user: freezed == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as UserModel?, + ) as $Val); + } + + /// Create a copy of LeaderboardPlayer + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $UserModelCopyWith<$Res>? get user { + if (_value.user == null) { + return null; + } + + return $UserModelCopyWith<$Res>(_value.user!, (value) { + return _then(_value.copyWith(user: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$LeaderboardPlayerImplCopyWith<$Res> + implements $LeaderboardPlayerCopyWith<$Res> { + factory _$$LeaderboardPlayerImplCopyWith(_$LeaderboardPlayerImpl value, + $Res Function(_$LeaderboardPlayerImpl) then) = + __$$LeaderboardPlayerImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@TimeStampJsonConverter() DateTime date, + String id, + int runs, + int wickets, + int catches, + @JsonKey(includeToJson: false, includeFromJson: false) UserModel? user}); + + @override + $UserModelCopyWith<$Res>? get user; +} + +/// @nodoc +class __$$LeaderboardPlayerImplCopyWithImpl<$Res> + extends _$LeaderboardPlayerCopyWithImpl<$Res, _$LeaderboardPlayerImpl> + implements _$$LeaderboardPlayerImplCopyWith<$Res> { + __$$LeaderboardPlayerImplCopyWithImpl(_$LeaderboardPlayerImpl _value, + $Res Function(_$LeaderboardPlayerImpl) _then) + : super(_value, _then); + + /// Create a copy of LeaderboardPlayer + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = null, + Object? id = null, + Object? runs = null, + Object? wickets = null, + Object? catches = null, + Object? user = freezed, + }) { + return _then(_$LeaderboardPlayerImpl( + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as DateTime, + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + runs: null == runs + ? _value.runs + : runs // ignore: cast_nullable_to_non_nullable + as int, + wickets: null == wickets + ? _value.wickets + : wickets // ignore: cast_nullable_to_non_nullable + as int, + catches: null == catches + ? _value.catches + : catches // ignore: cast_nullable_to_non_nullable + as int, + user: freezed == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as UserModel?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$LeaderboardPlayerImpl implements _LeaderboardPlayer { + const _$LeaderboardPlayerImpl( + {@TimeStampJsonConverter() required this.date, + required this.id, + this.runs = 0, + this.wickets = 0, + this.catches = 0, + @JsonKey(includeToJson: false, includeFromJson: false) this.user}); + + factory _$LeaderboardPlayerImpl.fromJson(Map json) => + _$$LeaderboardPlayerImplFromJson(json); + + @override + @TimeStampJsonConverter() + final DateTime date; + @override + final String id; + @override + @JsonKey() + final int runs; + @override + @JsonKey() + final int wickets; + @override + @JsonKey() + final int catches; + @override + @JsonKey(includeToJson: false, includeFromJson: false) + final UserModel? user; + + @override + String toString() { + return 'LeaderboardPlayer(date: $date, id: $id, runs: $runs, wickets: $wickets, catches: $catches, user: $user)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LeaderboardPlayerImpl && + (identical(other.date, date) || other.date == date) && + (identical(other.id, id) || other.id == id) && + (identical(other.runs, runs) || other.runs == runs) && + (identical(other.wickets, wickets) || other.wickets == wickets) && + (identical(other.catches, catches) || other.catches == catches) && + (identical(other.user, user) || other.user == user)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => + Object.hash(runtimeType, date, id, runs, wickets, catches, user); + + /// Create a copy of LeaderboardPlayer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$LeaderboardPlayerImplCopyWith<_$LeaderboardPlayerImpl> get copyWith => + __$$LeaderboardPlayerImplCopyWithImpl<_$LeaderboardPlayerImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$LeaderboardPlayerImplToJson( + this, + ); + } +} + +abstract class _LeaderboardPlayer implements LeaderboardPlayer { + const factory _LeaderboardPlayer( + {@TimeStampJsonConverter() required final DateTime date, + required final String id, + final int runs, + final int wickets, + final int catches, + @JsonKey(includeToJson: false, includeFromJson: false) + final UserModel? user}) = _$LeaderboardPlayerImpl; + + factory _LeaderboardPlayer.fromJson(Map json) = + _$LeaderboardPlayerImpl.fromJson; + + @override + @TimeStampJsonConverter() + DateTime get date; + @override + String get id; + @override + int get runs; + @override + int get wickets; + @override + int get catches; + @override + @JsonKey(includeToJson: false, includeFromJson: false) + UserModel? get user; + + /// Create a copy of LeaderboardPlayer + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$LeaderboardPlayerImplCopyWith<_$LeaderboardPlayerImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/data/lib/api/leaderboard/leaderboard_model.g.dart b/data/lib/api/leaderboard/leaderboard_model.g.dart new file mode 100644 index 00000000..868f0642 --- /dev/null +++ b/data/lib/api/leaderboard/leaderboard_model.g.dart @@ -0,0 +1,51 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'leaderboard_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$LeaderboardModelImpl _$$LeaderboardModelImplFromJson( + Map json) => + _$LeaderboardModelImpl( + type: $enumDecode(_$LeaderboardFieldEnumMap, json['type']), + players: (json['players'] as List?) + ?.map( + (e) => LeaderboardPlayer.fromJson(e as Map)) + .toList() ?? + const [], + ); + +Map _$$LeaderboardModelImplToJson( + _$LeaderboardModelImpl instance) => + { + 'type': _$LeaderboardFieldEnumMap[instance.type]!, + 'players': instance.players, + }; + +const _$LeaderboardFieldEnumMap = { + LeaderboardField.batting: 'batting', + LeaderboardField.bowling: 'bowling', + LeaderboardField.fielding: 'fielding', +}; + +_$LeaderboardPlayerImpl _$$LeaderboardPlayerImplFromJson( + Map json) => + _$LeaderboardPlayerImpl( + date: const TimeStampJsonConverter().fromJson(json['date'] as Object), + id: json['id'] as String, + runs: (json['runs'] as num?)?.toInt() ?? 0, + wickets: (json['wickets'] as num?)?.toInt() ?? 0, + catches: (json['catches'] as num?)?.toInt() ?? 0, + ); + +Map _$$LeaderboardPlayerImplToJson( + _$LeaderboardPlayerImpl instance) => + { + 'date': const TimeStampJsonConverter().toJson(instance.date), + 'id': instance.id, + 'runs': instance.runs, + 'wickets': instance.wickets, + 'catches': instance.catches, + }; diff --git a/data/lib/extensions/date_extension.dart b/data/lib/extensions/date_extension.dart new file mode 100644 index 00000000..82fde9e2 --- /dev/null +++ b/data/lib/extensions/date_extension.dart @@ -0,0 +1,22 @@ +extension DateExtension on DateTime { + DateTime get getStartOfMonth { + return DateTime(year, month, 1); + } + + DateTime get getEndOfMonth { + final nextMonth = month == 12 + ? DateTime(year + 1, 1, 1) + : DateTime(year, month + 1, 1); + return nextMonth.subtract(const Duration(days: 1)); + } + + DateTime get getStartOfWeek { + final startOfWeek = subtract(Duration(days: weekday - 1)); + return DateTime(startOfWeek.year, startOfWeek.month, startOfWeek.day); + } + + DateTime get getEndOfWeek { + final endOfWeek = add(Duration(days: 7 - weekday)); + return DateTime(endOfWeek.year, endOfWeek.month, endOfWeek.day, 23, 59, 59); + } +} \ No newline at end of file diff --git a/data/lib/service/leaderboard/leaderboard_service.dart b/data/lib/service/leaderboard/leaderboard_service.dart new file mode 100644 index 00000000..f00b4a46 --- /dev/null +++ b/data/lib/service/leaderboard/leaderboard_service.dart @@ -0,0 +1,138 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../api/leaderboard/leaderboard_model.dart'; +import '../../api/user/user_models.dart'; +import '../../errors/app_error.dart'; +import '../../extensions/date_extension.dart'; +import '../../utils/combine_latest.dart'; +import '../../utils/constant/firestore_constant.dart'; +import '../user/user_service.dart'; + +final leaderboardServiceProvider = Provider( + (ref) => LeaderboardService( + FirebaseFirestore.instance, + ref.read(userServiceProvider), + ), +); + +class LeaderboardService { + final FirebaseFirestore _firestore; + final UserService _userService; + + LeaderboardService( + this._firestore, + this._userService, + ); + + CollectionReference _leaderboardCollection( + LeaderboardType type, + ) => + _firestore + .collection(FireStoreConst.leaderboardCollection) + .doc(type.getDatabaseConst()) + .collection(FireStoreConst.dataCollection) + .withConverter( + fromFirestore: LeaderboardPlayer.fromFireStore, + toFirestore: (LeaderboardPlayer leaderboard, _) => + leaderboard.toJson(), + ); + + Stream> streamLeaderboardByField({ + LeaderboardType type = LeaderboardType.allTime, + int limit = 20, + LeaderboardField field = LeaderboardField.batting, + }) { + var query = _leaderboardCollection(type) + .orderBy(field.getDatabaseConst(), descending: true) + .where(field.getDatabaseConst(), isGreaterThan: 0); + + if(type == LeaderboardType.weekly || type == LeaderboardType.monthly){ + final now = DateTime.now(); + final startTime = type == LeaderboardType.weekly ? now.getStartOfWeek : now.getStartOfMonth; + final endTime = type == LeaderboardType.weekly ? now.getEndOfWeek : now.getEndOfMonth; + + final timeFilter = Filter.and( + Filter(FireStoreConst.date, isGreaterThanOrEqualTo: startTime), + Filter(FireStoreConst.date, isLessThanOrEqualTo: endTime), + ); + + query = query.where(timeFilter); + } + + query = query.limit(limit); + return query + .snapshots() + .asyncMap((snapshot) async { + final docs = snapshot.docs.map((e) => e.data()).toList(); + final players = + await getUserListFromUserIds(docs.map((e) => e.id).toList()); + return docs.map((e) { + final player = players.firstWhere((element) => element.id == e.id); + return e.copyWith(user: player); + }).toList(); + }).handleError((error, stack) => throw AppError.fromError(error, stack)); + } + + Stream> streamLeaderboard({ + LeaderboardType type = LeaderboardType.allTime, + int limit = 20, + }) { + return combineLatest3( + streamLeaderboardByField( + type: type, + limit: limit, + field: LeaderboardField.batting, + ), + streamLeaderboardByField( + type: type, + limit: limit, + field: LeaderboardField.bowling, + ), + streamLeaderboardByField( + type: type, + limit: limit, + field: LeaderboardField.fielding, + ), + ).map( + (event) { + final List leaderboard = []; + if (event.$1.isNotEmpty) { + leaderboard.add( + LeaderboardModel( + type: LeaderboardField.batting, + players: event.$1, + ), + ); + } + if (event.$2.isNotEmpty) { + leaderboard.add( + LeaderboardModel( + type: LeaderboardField.bowling, + players: event.$2, + ), + ); + } + if (event.$3.isNotEmpty) { + leaderboard.add( + LeaderboardModel( + type: LeaderboardField.fielding, + players: event.$3, + ), + ); + } + return leaderboard; + }, + ).handleError((error, stack) => throw AppError.fromError(error, stack)); + } + + // Helper Methods + Future> getUserListFromUserIds(List users) async { + try { + final userList = await _userService.getUsersByIds(users); + return userList; + } catch (error, stack) { + throw AppError.fromError(error, stack); + } + } +} diff --git a/data/lib/service/user/user_service.dart b/data/lib/service/user/user_service.dart index 79b83701..e0486637 100644 --- a/data/lib/service/user/user_service.dart +++ b/data/lib/service/user/user_service.dart @@ -1,15 +1,15 @@ import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:http/http.dart' as http; + +import '../../api/network/client.dart'; +import '../../api/user/user_models.dart'; import '../../errors/app_error.dart'; import '../../extensions/list_extensions.dart'; -import '../../api/network/client.dart'; -import '../device/device_service.dart'; +import '../../storage/app_preferences.dart'; import '../../utils/constant/firestore_constant.dart'; import '../../utils/dummy_deactivated_account.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -import '../../api/user/user_models.dart'; -import '../../storage/app_preferences.dart'; +import '../device/device_service.dart'; import 'user_endpoint.dart'; final userServiceProvider = Provider((ref) { diff --git a/data/lib/utils/combine_latest.dart b/data/lib/utils/combine_latest.dart index 582e07c6..758fb281 100644 --- a/data/lib/utils/combine_latest.dart +++ b/data/lib/utils/combine_latest.dart @@ -26,4 +26,17 @@ Stream<(T1, T2, T3, T4)> combineLatest4( final firstThree = combineLatest3(stream1, stream2, stream3); return combineLatest2(firstThree, stream4) .map((tuple) => (tuple.$1.$1, tuple.$1.$2, tuple.$1.$3, tuple.$2)); +} + +Stream<(T1, T2, T3, T4, T5)> combineLatest5( + Stream stream1, + Stream stream2, + Stream stream3, + Stream stream4, + Stream stream5, + ) { + final firstFour = combineLatest4(stream1, stream2, stream3, stream4); + return combineLatest2(firstFour, stream5).map( + (tuple) => (tuple.$1.$1, tuple.$1.$2, tuple.$1.$3, tuple.$1.$4, tuple.$2), + ); } \ No newline at end of file diff --git a/data/lib/utils/constant/firestore_constant.dart b/data/lib/utils/constant/firestore_constant.dart index d4805559..1f697d7c 100644 --- a/data/lib/utils/constant/firestore_constant.dart +++ b/data/lib/utils/constant/firestore_constant.dart @@ -11,6 +11,7 @@ class FireStoreConst { static const String userStatCollection = "user_stat"; static const String supportCollection = "contact_support"; static const String tournamentCollection = "tournaments"; + static const String leaderboardCollection = "leaderboard"; // matches field const static const String id = "id"; @@ -63,6 +64,16 @@ class FireStoreConst { static const String matchIds = "match_ids"; static const String endDate = "end_date"; static const String startDate = "start_date"; + + // leaderboard field const + static const String weeklyDocument = "weekly"; + static const String monthlyDocument = "monthly"; + static const String allTimeDocument = "all_time"; + static const String dataCollection = "data"; + static const String runs = "runs"; + static const String wickets = "wickets"; + static const String catches = "catches"; + static const String date = "date"; } class DataConfig { diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index fc68af72..2de4bef5 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -82,6 +82,10 @@ "common_remove_admin": "Remove admin", "common_transfer_ownership": "Transfer ownership", "common_tournaments": "Tournaments", + "common_leaderboard": "Leaderboard", + "common_batting": "Batting", + "common_bowling": "Bowling", + "common_fielding": "Fielding", "common_obscure_phone_number_text": "{countryCode} ***** ***{lastDigits}", "@common_obscure_phone_number_text": { "description": "+{countryCode} ***** ***{lastDigits}", @@ -155,6 +159,17 @@ "home_match_list_empty_search_title": "No match results", "home_match_list_empty_search_message": "No results found. Make sure the team name is correct or try again later.", + "@_LEADERBOARD": { + }, + "leaderboard_empty_title": "Nothing to Show Yet", + "leaderboard_empty_description": "No scores available yet. Make your move and take the lead!", + "leaderboard_catches_title": "{count, plural, =0{{count} catches} =1{{count} catch} other{{count} catches}}", + "@leaderboard_catches_title": { + "placeholders": { + "count": {} + } + }, + "@_NOTIFICATION_POPUP": { }, "notification_popup_title": "Turn on notifications?", @@ -447,8 +462,6 @@ "add_toss_detail_screen_title": "Add Toss Detail", "add_toss_detail_who_won_toss_text": "Who won the toss?", "add_toss_detail_winner_elected_to_text": "Toss-winner elected to - ?", - "add_toss_detail_bat_text": "Batting", - "add_toss_detail_bowl_text": "Bowling", "add_substitute_search_substitute_title": "Who’s ready to step in?", "add_substitute_search_substitute_description": "Search and assign a substitute fielder to maintain your fielding edge.", @@ -517,9 +530,6 @@ "team_detail_run_rate_title": "Run Rate", "user_detail_info_title": "Info", - "user_detail_batting_title": "Batting", - "user_detail_bowling_title": "Bowling", - "user_detail_fielding_title": "Fielding", "user_detail_personal_information_title": "Personal information", "user_detail_participation_title": "Participation", "user_detail_role_title": "Role", diff --git a/khelo/lib/domain/extensions/enum_extensions.dart b/khelo/lib/domain/extensions/enum_extensions.dart index e1a8d9a2..97065ddd 100644 --- a/khelo/lib/domain/extensions/enum_extensions.dart +++ b/khelo/lib/domain/extensions/enum_extensions.dart @@ -1,4 +1,5 @@ import 'package:data/api/ball_score/ball_score_model.dart'; +import 'package:data/api/leaderboard/leaderboard_model.dart'; import 'package:data/api/match/match_model.dart'; import 'package:data/api/tournament/tournament_model.dart'; import 'package:data/api/user/user_models.dart'; @@ -167,9 +168,9 @@ extension TossDecisionString on TossDecision { String getString(BuildContext context) { switch (this) { case TossDecision.bat: - return context.l10n.add_toss_detail_bat_text; + return context.l10n.common_batting; case TossDecision.bowl: - return context.l10n.add_toss_detail_bowl_text; + return context.l10n.common_bowling; } } } @@ -320,7 +321,8 @@ extension TournamentTypeString on TournamentType { case TournamentType.doubleOut: return context.l10n.tournament_type_double_out_description(minTeamReq); case TournamentType.bestOfThree: - return context.l10n.tournament_type_best_of_three_description(minTeamReq); + return context.l10n + .tournament_type_best_of_three_description(minTeamReq); case TournamentType.custom: return context.l10n.tournament_type_custom_description(minTeamReq); } @@ -356,3 +358,16 @@ extension TournamentKeyStatString on KeyStatTag { } } } + +extension LeaderboardFieldTypeString on LeaderboardField { + String getString(BuildContext context) { + switch (this) { + case LeaderboardField.batting: + return context.l10n.common_batting; + case LeaderboardField.bowling: + return context.l10n.common_bowling; + case LeaderboardField.fielding: + return context.l10n.common_fielding; + } + } +} diff --git a/khelo/lib/ui/app_route.dart b/khelo/lib/ui/app_route.dart index 34a93ca3..44ca0958 100644 --- a/khelo/lib/ui/app_route.dart +++ b/khelo/lib/ui/app_route.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:data/api/leaderboard/leaderboard_model.dart'; import 'package:data/api/match/match_model.dart'; import 'package:data/api/team/team_model.dart'; import 'package:data/api/tournament/tournament_model.dart'; @@ -9,6 +10,7 @@ import 'package:go_router/go_router.dart'; import 'package:khelo/ui/flow/home/home_view_model.dart'; import 'package:khelo/ui/flow/home/search/search_screen.dart'; import 'package:khelo/ui/flow/intro/intro_screen.dart'; +import 'package:khelo/ui/flow/leaderboard/leaderboard_screen.dart'; import 'package:khelo/ui/flow/matches/add_match/add_match_screen.dart'; import 'package:khelo/ui/flow/matches/add_match/match_officials/add_match_officials_screen.dart'; import 'package:khelo/ui/flow/matches/add_match/match_officials/add_match_officials_view_model.dart'; @@ -66,6 +68,7 @@ class AppRoute { static const pathMatchSelection = "/match-selection"; static const pathTournamentDetail = "/tournament-detail"; static const pathMemberSelection = "/member-selection"; + static const pathLeaderboard = "/leaderboard"; final String path; final String? name; @@ -234,6 +237,12 @@ class AppRoute { AppRoute(pathMakeTeamAdmin, builder: (context) => MakeTeamAdminScreen(team: team)); + static AppRoute leaderboard({ + LeaderboardField selectedField = LeaderboardField.batting, + }) => + AppRoute(pathLeaderboard, + builder: (context) => LeaderboardScreen(selectedField: selectedField)); + static AppRoute searchTeam({ List? excludedIds, required bool onlyUserTeams, @@ -449,6 +458,10 @@ class AppRoute { path: pathMakeTeamAdmin, builder: (context, state) => state.widget(context), ), + GoRoute( + path: pathLeaderboard, + builder: (context, state) => state.widget(context), + ), GoRoute( path: pathAddTeam, pageBuilder: (context, state) => adaptivePage( diff --git a/khelo/lib/ui/flow/home/home_screen.dart b/khelo/lib/ui/flow/home/home_screen.dart index 3c677fbc..8f641f03 100644 --- a/khelo/lib/ui/flow/home/home_screen.dart +++ b/khelo/lib/ui/flow/home/home_screen.dart @@ -1,11 +1,15 @@ +import 'package:data/api/leaderboard/leaderboard_model.dart'; import 'package:data/api/tournament/tournament_model.dart'; +import 'package:data/api/user/user_models.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:khelo/components/app_page.dart'; import 'package:khelo/components/empty_screen.dart'; import 'package:khelo/components/error_screen.dart'; +import 'package:khelo/components/image_avatar.dart'; import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/enum_extensions.dart'; import 'package:khelo/ui/app_route.dart'; import 'package:khelo/ui/flow/home/components/match_item.dart'; import 'package:khelo/ui/flow/home/components/tournament_item.dart'; @@ -91,6 +95,10 @@ class _HomeScreenState extends ConsumerState { _tournamentList(context, state.tournaments), const SizedBox(height: 8), ], + if (state.leaderboard.isNotEmpty) ...[ + _leaderboardList(context, state.leaderboard), + const SizedBox(height: 8), + ], (state.matches.isNotEmpty) ? _content(context, state) : SizedBox( @@ -173,6 +181,133 @@ class _HomeScreenState extends ConsumerState { ); } + Widget _leaderboardList( + BuildContext context, + List leaderboard, + ) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _header( + context, + header: context.l10n.common_leaderboard, + isViewAllShow: false, + onViewAll: () {}, + ), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: leaderboard + .map((data) => _leaderboardCell(context, data)) + .toList(), + ), + ), + ), + ], + ); + } + + Widget _leaderboardCell(BuildContext context, LeaderboardModel leaderboard) { + return OnTapScale( + onTap: () => + AppRoute.leaderboard(selectedField: leaderboard.type).push(context), + child: Container( + width: Size.fromWidth(360).width, + padding: EdgeInsets.only(left: 16, right: 8, top: 16, bottom: 16), + margin: EdgeInsets.only(left: 8, right: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + border: Border.all(color: context.colorScheme.outline)), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Text( + leaderboard.type.getString(context), + style: AppTextStyle.caption.copyWith( + color: context.colorScheme.textDisabled, + ), + ), + ), + SvgPicture.asset( + Assets.images.icArrowForward, + width: 16, + height: 16, + colorFilter: ColorFilter.mode( + context.colorScheme.textDisabled, + BlendMode.srcIn, + ), + ), + ], + ), + SizedBox(height: 16), + _leaderboardPlayerListView(leaderboard.players), + ], + ), + ), + ); + } + + Widget _leaderboardPlayerListView(List players) { + return Row( + children: [ + for (int rank = 0; rank < players.length; rank++) + Expanded( + child: Container( + padding: EdgeInsets.all(8), + margin: EdgeInsets.only(right: 8), + decoration: BoxDecoration( + color: context.colorScheme.containerLow, + borderRadius: BorderRadius.circular(6), + border: Border.all(color: context.colorScheme.outline)), + child: _leaderboardPlayerProfileView( + players.elementAt(rank).user, rank <= 2 ? rank + 1 : null), + ), + ), + ], + ); + } + + Widget _leaderboardPlayerProfileView(UserModel? user, int? rank) { + return Column( + children: [ + Stack( + children: [ + ImageAvatar( + initial: user?.nameInitial ?? "?", + imageUrl: user?.profile_img_url, + size: 48, + ), + if (rank != null) + Positioned( + right: 0, + bottom: 0, + child: CircleAvatar( + backgroundColor: context.colorScheme.primary, + radius: 9, + child: Text( + rank.toString(), + style: AppTextStyle.caption.copyWith( + color: context.colorScheme.onPrimary, fontSize: 10), + ), + ), + ) + ], + ), + Text( + user?.name ?? "Deactivated User", + overflow: TextOverflow.ellipsis, + style: AppTextStyle.body1 + .copyWith(color: context.colorScheme.textPrimary), + ), + ], + ); + } + Widget _content( BuildContext context, HomeViewState state, diff --git a/khelo/lib/ui/flow/home/home_view_model.dart b/khelo/lib/ui/flow/home/home_view_model.dart index 3a0a92a9..9e36cb22 100644 --- a/khelo/lib/ui/flow/home/home_view_model.dart +++ b/khelo/lib/ui/flow/home/home_view_model.dart @@ -1,7 +1,9 @@ import 'dart:async'; +import 'package:data/api/leaderboard/leaderboard_model.dart'; import 'package:data/api/match/match_model.dart'; import 'package:data/api/tournament/tournament_model.dart'; +import 'package:data/service/leaderboard/leaderboard_service.dart'; import 'package:data/service/match/match_service.dart'; import 'package:data/service/tournament/tournament_service.dart'; import 'package:data/storage/app_preferences.dart'; @@ -19,6 +21,7 @@ final homeViewStateProvider = final notifier = HomeViewNotifier( ref.read(matchServiceProvider), ref.read(tournamentServiceProvider), + ref.read(leaderboardServiceProvider), ); ref.listen( hasUserSession, (_, next) => notifier._onUserSessionUpdate(next)); @@ -29,11 +32,13 @@ final homeViewStateProvider = class HomeViewNotifier extends StateNotifier { final MatchService _matchService; final TournamentService _tournamentService; + final LeaderboardService _leaderboardService; StreamSubscription? _streamSubscription; HomeViewNotifier( this._matchService, this._tournamentService, + this._leaderboardService, ) : super(const HomeViewState()) { loadData(); } @@ -48,11 +53,12 @@ class HomeViewNotifier extends StateNotifier { _streamSubscription?.cancel(); state = state.copyWith(loading: state.matches.isEmpty); - final combineFutures = combineLatest4( + final combineFutures = combineLatest5( _matchService.streamActiveRunningMatches(), _matchService.streamUpcomingMatches(), _matchService.streamFinishedMatches(), _tournamentService.streamActiveTournaments(), + _leaderboardService.streamLeaderboard(limit: 4), ); _streamSubscription = combineFutures.listen( @@ -65,6 +71,7 @@ class HomeViewNotifier extends StateNotifier { MatchStatusLabel.finished: results.$3, }, tournaments: results.$4, + leaderboard: results.$5, loading: false, error: null, ); @@ -90,6 +97,7 @@ class HomeViewState with _$HomeViewState { @Default(false) bool loading, @Default([]) List matches, @Default([]) List tournaments, + @Default([]) List leaderboard, @Default({}) Map> groupMatches, }) = _HomeViewState; } diff --git a/khelo/lib/ui/flow/home/home_view_model.freezed.dart b/khelo/lib/ui/flow/home/home_view_model.freezed.dart index b42c1145..7dcb5525 100644 --- a/khelo/lib/ui/flow/home/home_view_model.freezed.dart +++ b/khelo/lib/ui/flow/home/home_view_model.freezed.dart @@ -20,6 +20,7 @@ mixin _$HomeViewState { bool get loading => throw _privateConstructorUsedError; List get matches => throw _privateConstructorUsedError; List get tournaments => throw _privateConstructorUsedError; + List get leaderboard => throw _privateConstructorUsedError; Map> get groupMatches => throw _privateConstructorUsedError; @@ -41,6 +42,7 @@ abstract class $HomeViewStateCopyWith<$Res> { bool loading, List matches, List tournaments, + List leaderboard, Map> groupMatches}); } @@ -63,6 +65,7 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> Object? loading = null, Object? matches = null, Object? tournaments = null, + Object? leaderboard = null, Object? groupMatches = null, }) { return _then(_value.copyWith( @@ -79,6 +82,10 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> ? _value.tournaments : tournaments // ignore: cast_nullable_to_non_nullable as List, + leaderboard: null == leaderboard + ? _value.leaderboard + : leaderboard // ignore: cast_nullable_to_non_nullable + as List, groupMatches: null == groupMatches ? _value.groupMatches : groupMatches // ignore: cast_nullable_to_non_nullable @@ -100,6 +107,7 @@ abstract class _$$HomeViewStateImplCopyWith<$Res> bool loading, List matches, List tournaments, + List leaderboard, Map> groupMatches}); } @@ -120,6 +128,7 @@ class __$$HomeViewStateImplCopyWithImpl<$Res> Object? loading = null, Object? matches = null, Object? tournaments = null, + Object? leaderboard = null, Object? groupMatches = null, }) { return _then(_$HomeViewStateImpl( @@ -136,6 +145,10 @@ class __$$HomeViewStateImplCopyWithImpl<$Res> ? _value._tournaments : tournaments // ignore: cast_nullable_to_non_nullable as List, + leaderboard: null == leaderboard + ? _value._leaderboard + : leaderboard // ignore: cast_nullable_to_non_nullable + as List, groupMatches: null == groupMatches ? _value._groupMatches : groupMatches // ignore: cast_nullable_to_non_nullable @@ -152,9 +165,11 @@ class _$HomeViewStateImpl implements _HomeViewState { this.loading = false, final List matches = const [], final List tournaments = const [], + final List leaderboard = const [], final Map> groupMatches = const {}}) : _matches = matches, _tournaments = tournaments, + _leaderboard = leaderboard, _groupMatches = groupMatches; @override @@ -180,6 +195,15 @@ class _$HomeViewStateImpl implements _HomeViewState { return EqualUnmodifiableListView(_tournaments); } + final List _leaderboard; + @override + @JsonKey() + List get leaderboard { + if (_leaderboard is EqualUnmodifiableListView) return _leaderboard; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_leaderboard); + } + final Map> _groupMatches; @override @JsonKey() @@ -191,7 +215,7 @@ class _$HomeViewStateImpl implements _HomeViewState { @override String toString() { - return 'HomeViewState(error: $error, loading: $loading, matches: $matches, tournaments: $tournaments, groupMatches: $groupMatches)'; + return 'HomeViewState(error: $error, loading: $loading, matches: $matches, tournaments: $tournaments, leaderboard: $leaderboard, groupMatches: $groupMatches)'; } @override @@ -204,6 +228,8 @@ class _$HomeViewStateImpl implements _HomeViewState { const DeepCollectionEquality().equals(other._matches, _matches) && const DeepCollectionEquality() .equals(other._tournaments, _tournaments) && + const DeepCollectionEquality() + .equals(other._leaderboard, _leaderboard) && const DeepCollectionEquality() .equals(other._groupMatches, _groupMatches)); } @@ -215,6 +241,7 @@ class _$HomeViewStateImpl implements _HomeViewState { loading, const DeepCollectionEquality().hash(_matches), const DeepCollectionEquality().hash(_tournaments), + const DeepCollectionEquality().hash(_leaderboard), const DeepCollectionEquality().hash(_groupMatches)); /// Create a copy of HomeViewState @@ -232,6 +259,7 @@ abstract class _HomeViewState implements HomeViewState { final bool loading, final List matches, final List tournaments, + final List leaderboard, final Map> groupMatches}) = _$HomeViewStateImpl; @@ -244,6 +272,8 @@ abstract class _HomeViewState implements HomeViewState { @override List get tournaments; @override + List get leaderboard; + @override Map> get groupMatches; /// Create a copy of HomeViewState diff --git a/khelo/lib/ui/flow/leaderboard/leaderboard_screen.dart b/khelo/lib/ui/flow/leaderboard/leaderboard_screen.dart new file mode 100644 index 00000000..c670fb50 --- /dev/null +++ b/khelo/lib/ui/flow/leaderboard/leaderboard_screen.dart @@ -0,0 +1,225 @@ +import 'package:collection/collection.dart'; +import 'package:data/api/leaderboard/leaderboard_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:khelo/components/app_page.dart'; +import 'package:khelo/components/image_avatar.dart'; +import 'package:khelo/domain/extensions/context_extensions.dart'; +import 'package:khelo/domain/extensions/enum_extensions.dart'; +import 'package:khelo/ui/flow/leaderboard/leaderboard_view_model.dart'; +import 'package:style/button/tab_button.dart'; +import 'package:style/extensions/context_extensions.dart'; +import 'package:style/indicator/progress_indicator.dart'; +import 'package:style/text/app_text_style.dart'; + +import '../../../components/empty_screen.dart'; +import '../../../components/error_screen.dart'; +import '../../../domain/extensions/widget_extension.dart'; + +class LeaderboardScreen extends ConsumerStatefulWidget { + final LeaderboardField selectedField; + + const LeaderboardScreen({ + super.key, + required this.selectedField, + }); + + @override + ConsumerState createState() => _LeaderboardScreenState(); +} + +class _LeaderboardScreenState extends ConsumerState { + late PageController _controller; + late LeaderboardViewNotifier notifier; + + int get _selectedTab => _controller.hasClients + ? _controller.page?.round() ?? 0 + : _controller.initialPage; + + @override + void initState() { + super.initState(); + notifier = ref.read(leaderboardStateProvider.notifier); + + runPostFrame(() => notifier.onTabChange(widget.selectedField.index)); + _controller = PageController( + initialPage: widget.selectedField.index, + ); + } + + @override + Widget build(BuildContext context) { + final state = ref.watch(leaderboardStateProvider); + + return AppPage( + title: context.l10n.common_leaderboard, + body: Builder( + builder: (context) => _body(context, state), + ), + ); + } + + Widget _body(BuildContext context, LeaderboardViewState state) { + if (state.loading) { + return const Center(child: AppProgressIndicator()); + } else if (state.error != null) { + return ErrorScreen( + error: state.error, + onRetryTap: notifier.loadLeaderboard, + ); + } else if (state.leaderboard.isEmpty) { + return _emptyLeaderboard(context); + } + + return Padding( + padding: context.mediaQueryPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + _tabView(context), + _content(context, state), + ], + ), + ); + } + + Widget _emptyLeaderboard(BuildContext context) { + return EmptyScreen( + title: context.l10n.leaderboard_empty_title, + description: context.l10n.leaderboard_empty_description, + isShowButton: false, + ); + } + + Widget _tabView(BuildContext context) { + final tabs = LeaderboardField.values; + + return SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9), + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: List.generate( + tabs.length, + (index) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: TabButton( + tabs[index].getString(context), + onTap: () => _controller.jumpToPage(index), + selected: index == _selectedTab, + ), + ), + ), + ), + ); + } + + Widget _content(BuildContext context, LeaderboardViewState state) { + return Expanded( + child: PageView( + controller: _controller, + onPageChanged: notifier.onTabChange, + children: LeaderboardField.values + .map((field) => _playerListView(context, state, field)) + .toList(), + ), + ); + } + + Widget _playerListView(BuildContext context, LeaderboardViewState state, + LeaderboardField field) { + final players = state.leaderboard + .firstWhereOrNull((data) => data.type == field) + ?.players ?? + []; + + if (players.isEmpty) { + return _emptyLeaderboard(context); + } + return ListView.separated( + padding: EdgeInsets.all(16), + itemBuilder: (context, index) { + final player = players[index]; + return _leaderboardCell( + player: player, + field: field, + rank: index + 1, + ); + }, + separatorBuilder: (context, index) => SizedBox(height: 16), + itemCount: players.length, + ); + } + + Widget _leaderboardCell({ + required LeaderboardPlayer player, + required LeaderboardField field, + required int rank, + }) { + return Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all(color: context.colorScheme.outline), + ), + child: Row( + children: [ + Text( + rank.toString().padLeft(2, '0'), + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + SizedBox(width: 16), + ImageAvatar( + initial: player.user?.nameInitial ?? "?", + imageUrl: player.user?.profile_img_url, + size: 42, + ), + SizedBox(width: 16), + Expanded( + child: Text( + player.user?.name ?? "Deactivated User", + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + ), + SizedBox(width: 8), + Material( + type: MaterialType.transparency, + child: Chip( + label: Text( + _getCountAsPerField(context, player, field), + style: AppTextStyle.body2.copyWith( + color: rank <= 2 + ? context.colorScheme.onPrimary + : context.colorScheme.primary, + ), + ), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + side: const BorderSide(color: Colors.transparent), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + backgroundColor: rank <= 2 + ? context.colorScheme.primary + : context.colorScheme.containerLowOnSurface, + ), + ), + ], + ), + ); + } + + String _getCountAsPerField( + BuildContext context, LeaderboardPlayer player, LeaderboardField field) { + switch (field) { + case LeaderboardField.batting: + return context.l10n.common_runs_title(player.runs); + case LeaderboardField.bowling: + return context.l10n.common_wickets_title(player.wickets); + case LeaderboardField.fielding: + return context.l10n.leaderboard_catches_title(player.catches); + } + } +} diff --git a/khelo/lib/ui/flow/leaderboard/leaderboard_view_model.dart b/khelo/lib/ui/flow/leaderboard/leaderboard_view_model.dart new file mode 100644 index 00000000..d011e674 --- /dev/null +++ b/khelo/lib/ui/flow/leaderboard/leaderboard_view_model.dart @@ -0,0 +1,66 @@ +import 'dart:async'; + +import 'package:data/api/leaderboard/leaderboard_model.dart'; +import 'package:data/service/leaderboard/leaderboard_service.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'leaderboard_view_model.freezed.dart'; + +final leaderboardStateProvider = StateNotifierProvider.autoDispose< + LeaderboardViewNotifier, LeaderboardViewState>((ref) { + return LeaderboardViewNotifier(ref.read(leaderboardServiceProvider)); +}); + +class LeaderboardViewNotifier extends StateNotifier { + final LeaderboardService _leaderboardService; + StreamSubscription? _streamSubscription; + + LeaderboardViewNotifier(this._leaderboardService) + : super(LeaderboardViewState()) { + loadLeaderboard(); + } + + void onTabChange(int tab) { + if (state.selectedTab != tab) { + state = state.copyWith(selectedTab: tab); + } + } + + void loadLeaderboard() { + _streamSubscription?.cancel(); + state = state.copyWith(loading: state.leaderboard.isNotEmpty); + + _streamSubscription = + _leaderboardService.streamLeaderboard().listen( + (results) { + state = state.copyWith( + leaderboard: results, + loading: false, + error: null, + ); + }, + onError: (e) { + state = state.copyWith(error: e, loading: false); + debugPrint("LeaderboardViewNotifier: error while loading leaderboard -> $e"); + }, + ); + } + + @override + void dispose() { + _streamSubscription?.cancel(); + super.dispose(); + } +} + +@freezed +class LeaderboardViewState with _$LeaderboardViewState { + const factory LeaderboardViewState({ + Object? error, + @Default([]) List leaderboard, + @Default(false) bool loading, + @Default(0) int selectedTab, + }) = _LeaderboardViewState; +} diff --git a/khelo/lib/ui/flow/leaderboard/leaderboard_view_model.freezed.dart b/khelo/lib/ui/flow/leaderboard/leaderboard_view_model.freezed.dart new file mode 100644 index 00000000..f01d62ba --- /dev/null +++ b/khelo/lib/ui/flow/leaderboard/leaderboard_view_model.freezed.dart @@ -0,0 +1,221 @@ +// 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 'leaderboard_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$LeaderboardViewState { + Object? get error => throw _privateConstructorUsedError; + List get leaderboard => throw _privateConstructorUsedError; + bool get loading => throw _privateConstructorUsedError; + int get selectedTab => throw _privateConstructorUsedError; + + /// Create a copy of LeaderboardViewState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $LeaderboardViewStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LeaderboardViewStateCopyWith<$Res> { + factory $LeaderboardViewStateCopyWith(LeaderboardViewState value, + $Res Function(LeaderboardViewState) then) = + _$LeaderboardViewStateCopyWithImpl<$Res, LeaderboardViewState>; + @useResult + $Res call( + {Object? error, + List leaderboard, + bool loading, + int selectedTab}); +} + +/// @nodoc +class _$LeaderboardViewStateCopyWithImpl<$Res, + $Val extends LeaderboardViewState> + implements $LeaderboardViewStateCopyWith<$Res> { + _$LeaderboardViewStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of LeaderboardViewState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? error = freezed, + Object? leaderboard = null, + Object? loading = null, + Object? selectedTab = null, + }) { + return _then(_value.copyWith( + error: freezed == error ? _value.error : error, + leaderboard: null == leaderboard + ? _value.leaderboard + : leaderboard // ignore: cast_nullable_to_non_nullable + as List, + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + selectedTab: null == selectedTab + ? _value.selectedTab + : selectedTab // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LeaderboardViewStateImplCopyWith<$Res> + implements $LeaderboardViewStateCopyWith<$Res> { + factory _$$LeaderboardViewStateImplCopyWith(_$LeaderboardViewStateImpl value, + $Res Function(_$LeaderboardViewStateImpl) then) = + __$$LeaderboardViewStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {Object? error, + List leaderboard, + bool loading, + int selectedTab}); +} + +/// @nodoc +class __$$LeaderboardViewStateImplCopyWithImpl<$Res> + extends _$LeaderboardViewStateCopyWithImpl<$Res, _$LeaderboardViewStateImpl> + implements _$$LeaderboardViewStateImplCopyWith<$Res> { + __$$LeaderboardViewStateImplCopyWithImpl(_$LeaderboardViewStateImpl _value, + $Res Function(_$LeaderboardViewStateImpl) _then) + : super(_value, _then); + + /// Create a copy of LeaderboardViewState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? error = freezed, + Object? leaderboard = null, + Object? loading = null, + Object? selectedTab = null, + }) { + return _then(_$LeaderboardViewStateImpl( + error: freezed == error ? _value.error : error, + leaderboard: null == leaderboard + ? _value._leaderboard + : leaderboard // ignore: cast_nullable_to_non_nullable + as List, + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + selectedTab: null == selectedTab + ? _value.selectedTab + : selectedTab // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$LeaderboardViewStateImpl implements _LeaderboardViewState { + const _$LeaderboardViewStateImpl( + {this.error, + final List leaderboard = const [], + this.loading = false, + this.selectedTab = 0}) + : _leaderboard = leaderboard; + + @override + final Object? error; + final List _leaderboard; + @override + @JsonKey() + List get leaderboard { + if (_leaderboard is EqualUnmodifiableListView) return _leaderboard; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_leaderboard); + } + + @override + @JsonKey() + final bool loading; + @override + @JsonKey() + final int selectedTab; + + @override + String toString() { + return 'LeaderboardViewState(error: $error, leaderboard: $leaderboard, loading: $loading, selectedTab: $selectedTab)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LeaderboardViewStateImpl && + const DeepCollectionEquality().equals(other.error, error) && + const DeepCollectionEquality() + .equals(other._leaderboard, _leaderboard) && + (identical(other.loading, loading) || other.loading == loading) && + (identical(other.selectedTab, selectedTab) || + other.selectedTab == selectedTab)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(error), + const DeepCollectionEquality().hash(_leaderboard), + loading, + selectedTab); + + /// Create a copy of LeaderboardViewState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$LeaderboardViewStateImplCopyWith<_$LeaderboardViewStateImpl> + get copyWith => + __$$LeaderboardViewStateImplCopyWithImpl<_$LeaderboardViewStateImpl>( + this, _$identity); +} + +abstract class _LeaderboardViewState implements LeaderboardViewState { + const factory _LeaderboardViewState( + {final Object? error, + final List leaderboard, + final bool loading, + final int selectedTab}) = _$LeaderboardViewStateImpl; + + @override + Object? get error; + @override + List get leaderboard; + @override + bool get loading; + @override + int get selectedTab; + + /// Create a copy of LeaderboardViewState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$LeaderboardViewStateImplCopyWith<_$LeaderboardViewStateImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/khelo/lib/ui/flow/score_board/score_board_view_model.dart b/khelo/lib/ui/flow/score_board/score_board_view_model.dart index 18d3bd5f..0adfb324 100644 --- a/khelo/lib/ui/flow/score_board/score_board_view_model.dart +++ b/khelo/lib/ui/flow/score_board/score_board_view_model.dart @@ -772,7 +772,7 @@ class ScoreBoardViewNotifier extends StateNotifier { } } - void _addPlayerStats({bool isMatchComplete = false}) async { + void _addPlayerStats() async { try { final userStatType = state.match?.match_type == MatchType.testMatch ? UserStatType.test @@ -1203,7 +1203,7 @@ class ScoreBoardViewNotifier extends StateNotifier { } try { state = state.copyWith(actionError: null, isActionInProgress: true); - _addPlayerStats(isMatchComplete: true); + _addPlayerStats(); List batsMan = []; if (state.batsMans?.isNotEmpty ?? false) { batsMan = state.batsMans! diff --git a/khelo/lib/ui/flow/stats/user_stat/user_stat_screen.dart b/khelo/lib/ui/flow/stats/user_stat/user_stat_screen.dart index 920c5f06..9e2526f2 100644 --- a/khelo/lib/ui/flow/stats/user_stat/user_stat_screen.dart +++ b/khelo/lib/ui/flow/stats/user_stat/user_stat_screen.dart @@ -84,9 +84,9 @@ class _UserStatScreenState extends ConsumerState Widget _tabView(BuildContext context) { final tabs = [ - context.l10n.user_detail_batting_title, - context.l10n.user_detail_bowling_title, - context.l10n.user_detail_fielding_title + context.l10n.common_batting, + context.l10n.common_bowling, + context.l10n.common_fielding ]; return SingleChildScrollView( diff --git a/khelo/lib/ui/flow/team/user_detail/component/user_detail_batting_content.dart b/khelo/lib/ui/flow/team/user_detail/component/user_detail_batting_content.dart index 8b3ad8bb..438fb5c3 100644 --- a/khelo/lib/ui/flow/team/user_detail/component/user_detail_batting_content.dart +++ b/khelo/lib/ui/flow/team/user_detail/component/user_detail_batting_content.dart @@ -27,7 +27,7 @@ class UserDetailBattingContent extends ConsumerWidget { context, isHeader: true, showDivider: false, - title: context.l10n.user_detail_batting_title, + title: context.l10n.common_batting, subtitle1: context.l10n.user_detail_test_title, subtitle2: context.l10n.common_other_title, ), diff --git a/khelo/lib/ui/flow/team/user_detail/component/user_detail_bowling_content.dart b/khelo/lib/ui/flow/team/user_detail/component/user_detail_bowling_content.dart index 0e54fc1e..522030c8 100644 --- a/khelo/lib/ui/flow/team/user_detail/component/user_detail_bowling_content.dart +++ b/khelo/lib/ui/flow/team/user_detail/component/user_detail_bowling_content.dart @@ -28,7 +28,7 @@ class UserDetailBowlingContent extends ConsumerWidget { context, isHeader: true, showDivider: false, - title: context.l10n.user_detail_bowling_title, + title: context.l10n.common_bowling, subtitle1: context.l10n.user_detail_test_title, subtitle2: context.l10n.common_other_title, ), diff --git a/khelo/lib/ui/flow/team/user_detail/component/user_detail_fielding_content.dart b/khelo/lib/ui/flow/team/user_detail/component/user_detail_fielding_content.dart index f620b833..dbeb8550 100644 --- a/khelo/lib/ui/flow/team/user_detail/component/user_detail_fielding_content.dart +++ b/khelo/lib/ui/flow/team/user_detail/component/user_detail_fielding_content.dart @@ -27,7 +27,7 @@ class UserDetailFieldingContent extends ConsumerWidget { context, isHeader: true, showDivider: false, - title: context.l10n.user_detail_fielding_title, + title: context.l10n.common_fielding, subtitle1: context.l10n.user_detail_test_title, subtitle2: context.l10n.common_other_title, ), diff --git a/khelo/lib/ui/flow/team/user_detail/user_detail_screen.dart b/khelo/lib/ui/flow/team/user_detail/user_detail_screen.dart index dd4e4c9b..d6d644f1 100644 --- a/khelo/lib/ui/flow/team/user_detail/user_detail_screen.dart +++ b/khelo/lib/ui/flow/team/user_detail/user_detail_screen.dart @@ -140,8 +140,8 @@ class _UserDetailScreenState extends ConsumerState { Widget _tabView(BuildContext context) { final tabs = [ context.l10n.user_detail_info_title, - context.l10n.user_detail_batting_title, - context.l10n.user_detail_bowling_title + context.l10n.common_batting, + context.l10n.common_bowling ]; return SingleChildScrollView(