diff --git a/lib/screens/home_screen/pages/DevelopersPage/developers.dart b/lib/screens/home_screen/pages/DevelopersPage/developers.dart index 263ece7..9bc31d7 100644 --- a/lib/screens/home_screen/pages/DevelopersPage/developers.dart +++ b/lib/screens/home_screen/pages/DevelopersPage/developers.dart @@ -15,7 +15,7 @@ class Developers extends StatefulWidget { } class _DevelopersState extends State { - Session selectedSession = Session.session_22_23; + Session selectedSession = Session.session_23_24; Map members = {}; Widget positionHeading(BuildContext ctx, String title) { diff --git a/lib/screens/home_screen/pages/EventsPage/events_page.dart b/lib/screens/home_screen/pages/EventsPage/events_page.dart index 62ea888..e245d67 100644 --- a/lib/screens/home_screen/pages/EventsPage/events_page.dart +++ b/lib/screens/home_screen/pages/EventsPage/events_page.dart @@ -79,11 +79,6 @@ class _EventsPageState extends State { builder: (context) => const EnigmaPage(), ), ); - // Navigator.push( - // context, - // MaterialPageRoute( - // builder: (context) => engima_page(), - // )); }, child: Card( shape: RoundedRectangleBorder( diff --git a/lib/screens/home_screen/pages/EventsPage/widgets/enigma_event_widget.dart b/lib/screens/home_screen/pages/EventsPage/widgets/enigma_event_widget.dart index 0b66087..ad4fab9 100644 --- a/lib/screens/home_screen/pages/EventsPage/widgets/enigma_event_widget.dart +++ b/lib/screens/home_screen/pages/EventsPage/widgets/enigma_event_widget.dart @@ -46,8 +46,7 @@ class _EnigmaEventState extends State { final now = DateTime.now(); for (final event in events) { - final startDate = DateTime.parse(event?["startDate"] ?? - ''); + final startDate = DateTime.parse(event?["startDate"] ?? ''); final durationInHrs = event?["durationInHrs"] as int?; if (durationInHrs != null) { @@ -72,7 +71,7 @@ class _EnigmaEventState extends State { Widget _buildSection(String title, List? events) { if (events == null || events.isEmpty) { - return SizedBox(); + return const SizedBox(); } return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -91,7 +90,7 @@ class _EnigmaEventState extends State { itemCount: eventdetails.length, itemBuilder: (context, int index) { if (eventdetails[index] == null || eventdetails.isEmpty) { - return SizedBox(); + return const SizedBox(); } return Container( width: MediaQuery.of(context).size.width * 0.6, @@ -145,35 +144,12 @@ class _EnigmaEventState extends State { msg: "Contest link copied to clipboard"); } }, - onPressed: () async { - if (!Provider.of(context, - listen: false) - .user! - .registeredEnigmas - .contains( - eventdetails[index]!['_id'].toString())) { - setState(() { - isLoading = true; - }); - Response res = await Provider.of( - context, - listen: false) - .registerEnigma(eventdetails[index]['_id']); - - if ((res.statusCode ?? 400) >= 200 && - (res.statusCode ?? 400) < 300) { - Fluttertoast.showToast( - msg: res.data['error'] ?? 'Unknown Error'); - } - } else { - launchUrl( - Uri.parse( - eventdetails[index]!["cfContestLink"]), - mode: LaunchMode.externalApplication); - } - setState(() { - isLoading = false; - }); + onPressed: () { + launchUrl( + Uri.parse(eventdetails[index]!["cfContestLink"]), + //If you want to launch in external app and not in CSS + // mode: LaunchMode.externalApplication + ); }, child: Text( Provider.of(context) @@ -185,6 +161,64 @@ class _EnigmaEventState extends State { : "Register Here", ), ), + Provider.of(context) + .user! + .registeredEnigmas + .contains( + eventdetails[index]!['_id'].toString()) + ? const Padding( + padding: EdgeInsets.all(8.0), + child: Text("Already registered"), + ) + : Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Flexible( + child: Text("Have you registered?")), + Flexible( + child: ElevatedButton( + onPressed: () async { + if (!Provider.of(context, + listen: false) + .user! + .registeredEnigmas + .contains( + eventdetails[index]!['_id'] + .toString())) { + setState(() { + isLoading = true; + }); + Response res = await Provider.of< + UserHandler>(context, + listen: false) + .registerEnigma( + eventdetails[index]['_id']); + + if ((res.statusCode ?? 400) >= + 200 && + (res.statusCode ?? 400) < 300) { + Fluttertoast.showToast( + msg: res.data['error'] ?? + 'Unknown Error'); + } + } + setState(() { + isLoading = false; + }); + }, + child: const Text("Yes")), + ), + Flexible( + child: ElevatedButton( + onPressed: () { + Fluttertoast.showToast( + msg: + "Please register for the contest"); + }, + child: const Text("No")), + ) + ], + ), ], ), ); @@ -202,7 +236,7 @@ class _EnigmaEventState extends State { eventdetails = snapshot.data; if (eventdetails.isEmpty) { - return Center( + return const Center( child: Text( 'No events available')); // Handle null or empty eventdetails } @@ -229,19 +263,19 @@ class _EnigmaEventState extends State { Tab( child: SizedBox( width: MediaQuery.of(context).size.width * 0.33, - child: Center(child: Text('Live')), + child: const Center(child: Text('Live')), ), ), Tab( child: SizedBox( width: MediaQuery.of(context).size.width * 0.33, - child: Center(child: Text('Upcoming')), + child: const Center(child: Text('Upcoming')), ), ), Tab( child: SizedBox( width: MediaQuery.of(context).size.width * 0.33, - child: Center(child: Text('Past')), + child: const Center(child: Text('Past')), ), ), ], diff --git a/lib/splash.dart b/lib/splash.dart index 30dac27..5ee0091 100644 --- a/lib/splash.dart +++ b/lib/splash.dart @@ -34,6 +34,10 @@ class _SplashState extends State { } else { Provider.of(context, listen: false).isOnline = false; Fluttertoast.showToast(msg: "Couldn't connect to the internet"); + // Fetching user from local storage in case of no internet + if (await NetworkEngine.doesCookieDirExists()) { + await Provider.of(context, listen: false).fetchUser(); + } } Widget page = const AuthScreen(); if (Provider.of(context, listen: false).user != null) { diff --git a/lib/state_handlers/user/user_handler.dart b/lib/state_handlers/user/user_handler.dart index 276aaca..1d6e940 100644 --- a/lib/state_handlers/user/user_handler.dart +++ b/lib/state_handlers/user/user_handler.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'user_model.dart'; import 'package:cssapp/utils/network_engine.dart'; +import 'package:cssapp/utils/storage_handler.dart'; class UserHandler extends ChangeNotifier { UserModel? user; @@ -54,6 +55,8 @@ class UserHandler extends ChangeNotifier { if ((res.statusCode ?? 400) >= 200 && (res.statusCode ?? 400) < 300) { user = UserModel.read(res.data); + // Storing user details in local storage on successful login + StorageHandler().saveUserToLocalStorage(user!); } return res; } @@ -66,6 +69,9 @@ class UserHandler extends ChangeNotifier { (res.statusCode ?? 400) < 300 && res.data?['user'] != null) { user = UserModel.read(res.data); + } else { + // Loading user from local storage + user = await StorageHandler().loadUserFromLocalStorage(); } return res; } diff --git a/lib/state_handlers/user/user_model.dart b/lib/state_handlers/user/user_model.dart index e51ec14..e04cfa2 100644 --- a/lib/state_handlers/user/user_model.dart +++ b/lib/state_handlers/user/user_model.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + class UserModel { String name; String email; @@ -29,4 +31,37 @@ class UserModel { List.from(data['registeredAbacusEvents']), registeredEnigmas: List.from(data['registeredEnigmas'])); } + + // Convert UserModel to a Map + Map toMap() { + return { + 'name': name, + 'email': email, + 'scholarID': scholarID, + 'codeforcesHandle': codeforcesHandle, + 'githubHandle': githubHandle, + 'registeredAbacusEvents': registeredAbacusEvents, + 'registeredEnigmas': registeredEnigmas, + }; + } + + // Create a UserModel from a Map + factory UserModel.fromMap(Map map) { + return UserModel( + name: map['name'], + email: map['email'], + scholarID: map['scholarID'], + codeforcesHandle: map['codeforcesHandle'], + githubHandle: map['githubHandle'], + registeredAbacusEvents: List.from(map['registeredAbacusEvents']), + registeredEnigmas: List.from(map['registeredEnigmas']), + ); + } + + // Convert UserModel to a JSON string + String toJson() => json.encode(toMap()); + + // Create a UserModel from a JSON string + factory UserModel.fromJson(String source) => + UserModel.fromMap(json.decode(source)); } diff --git a/lib/utils/network_engine.dart b/lib/utils/network_engine.dart index fc76a10..00f491f 100644 --- a/lib/utils/network_engine.dart +++ b/lib/utils/network_engine.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:cssapp/utils/storage_handler.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:dio_cookie_manager/dio_cookie_manager.dart'; @@ -26,6 +27,8 @@ class NetworkEngine { } static Future signOut() async { + // Delete all user data from local storage on logout + StorageHandler().clearAllData(); final Directory appDocDir = await getApplicationDocumentsDirectory(); Directory cookiesDir = Directory(appDocDir.path + _cookieDirName); if (await cookiesDir.exists()) { diff --git a/lib/utils/storage_handler.dart b/lib/utils/storage_handler.dart index a4a64e2..80820da 100644 --- a/lib/utils/storage_handler.dart +++ b/lib/utils/storage_handler.dart @@ -1,6 +1,7 @@ // ignore_for_file: avoid_print import 'dart:ui'; +import 'package:cssapp/state_handlers/user/user_model.dart'; import 'package:shared_preferences/shared_preferences.dart'; class StorageHandler { @@ -12,11 +13,28 @@ class StorageHandler { PlatformDispatcher.instance.platformBrightness == Brightness.dark; } + Future loadUserFromLocalStorage() async { + final jsonString = _preferences?.getString('user'); + if (jsonString != null) { + return UserModel.fromJson(jsonString); + } else { + return null; + } + } + // ----------------------------- Setter Methods ----------------------------- Future toggleDarkTheme() async { await _preferences?.setBool('isDarkTheme', !isDarkTheme()); } + Future saveUserToLocalStorage(UserModel user) async { + await _preferences?.setString('user', user.toJson()); + } + + Future clearAllData() async { + await _preferences?.clear(); +} + Future initPreferences() async { _preferences = await SharedPreferences.getInstance(); } diff --git a/pubspec.lock b/pubspec.lock index ba4e753..2d4cfaf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: archive - sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b" + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" url: "https://pub.dev" source: hosted - version: "3.4.9" + version: "3.4.10" args: dependency: transitive description: @@ -37,26 +37,26 @@ packages: dependency: "direct main" description: name: cached_network_image - sha256: f98972704692ba679db144261172a8e20feb145636c617af0eb4022132a6797f + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: "56aa42a7a01e3c9db8456d9f3f999931f1e05535b5a424271e9a38cabf066613" + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: "759b9a9f8f6ccbb66c185df805fac107f05730b1dab9c64626d1008cca532257" + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" carousel_slider: dependency: "direct main" description: @@ -93,12 +93,7 @@ packages: dependency: transitive description: name: collection - - source: hosted - version: "1.18.0" - - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 - + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted version: "1.18.0" @@ -393,26 +388,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -425,10 +420,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -489,26 +484,26 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" pointycastle: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" provider: dependency: "direct main" description: @@ -545,10 +540,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7" + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" shared_preferences_linux: dependency: transitive description: @@ -561,10 +556,10 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_web: dependency: transitive description: @@ -702,10 +697,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -718,17 +713,10 @@ packages: dependency: transitive description: name: test_api - - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted version: "0.6.1" - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" - typed_data: dependency: transitive description: @@ -749,26 +737,26 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86 + sha256: d25bb0ca00432a5e1ee40e69c36c85863addf7cc45e433769d61bed3fe81fd96 url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.2.3" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def" + sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.2.2" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3 + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.4" url_launcher_linux: dependency: transitive description: @@ -789,18 +777,18 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" + sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.1" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9" + sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" url_launcher_windows: dependency: transitive description: @@ -837,50 +825,50 @@ packages: dependency: transitive description: name: webview_flutter - sha256: "42393b4492e629aa3a88618530a4a00de8bb46e50e7b3993fedbfdc5352f0dbf" + sha256: "71e1bfaef41016c8d5954291df5e9f8c6172f1f6ff3af01b5656456ddb11f94c" url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "4.4.4" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: e313dcdf45d4c95bcb8960351ef2389b7f0687b90bc92483f7f7983ae5758456 + sha256: "161af93c2abaf94ef2192bffb53a3658b2d721a3bf99b69aa1e47814ee18cc96" url: "https://pub.dev" source: hosted - version: "3.13.0" + version: "3.13.2" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "68e86162aa8fc646ae859e1585995c096c95fc2476881fa0c4a8d10f56013a5a" + sha256: "80b40ae4fb959957eef9fa8970b6c9accda9f49fc45c2b75154696a8e8996cfe" url: "https://pub.dev" source: hosted - version: "2.8.0" + version: "2.9.1" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: accdaaa49a2aca2dc3c3230907988954cdd23fed0a19525d6c9789d380f4dc76 + sha256: b99ca8d8bae9c6b43d568218691aa537fb0aeae1d7d34eadf112a6aa36d26506 url: "https://pub.dev" source: hosted - version: "3.9.4" + version: "3.11.0" win32: dependency: transitive description: name: win32 - sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.2.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" xml: dependency: transitive description: @@ -914,5 +902,5 @@ packages: source: hosted version: "2.0.2" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.2.3 <4.0.0" + flutter: ">=3.16.6"