diff --git a/android/app/build.gradle b/android/app/build.gradle index e2ee37a..fe59029 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,5 +1,9 @@ plugins { id "com.android.application" + // START: FlutterFire Configuration + id 'com.google.gms.google-services' + id 'com.google.firebase.crashlytics' + // END: FlutterFire Configuration id "kotlin-android" // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id "dev.flutter.flutter-gradle-plugin" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 7c7f3d0..34a1df6 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -24,6 +24,12 @@ android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> + + diff --git a/lib/controller/home_controller.dart b/lib/controller/home_controller.dart index 26f243c..bfe9375 100644 --- a/lib/controller/home_controller.dart +++ b/lib/controller/home_controller.dart @@ -3,21 +3,113 @@ import 'package:cheminova/models/user_model.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../notification_service.dart'; + class HomeController extends GetxController { final HomeService homeService = HomeService(); + NotificationServices notificationServices = NotificationServices(); - var user = Rxn(); + UserModel? user; + // var userModel = UserModel( + // id: '', + // uniqueId: '', + // name: '', + // email: '', + // phone: '', + // role: '', + // sbu: '', + // createdAt: '', + // updatedAt: '', + // ).obs; // Observable for UserModel @override void onInit() { getUser(); super.onInit(); + notificationServices.requestNotificationPermission(); + notificationServices.getDeviceToken().then((value) { + print('Device Token: $value'); + fcmToken(); + }); } - Future getUser() async - { + Future fcmToken() async { SharedPreferences prefs = await SharedPreferences.getInstance(); String? token = prefs.getString('token'); - user.value = (await homeService.getUser(token: token)) as UserModel? ; + final fcmToken = await NotificationServices().getDeviceToken(); + print('fcmToken: $fcmToken'); + homeService.fcmToken({"fcmToken": fcmToken}, token!); + } + + Future getUser() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? token = prefs.getString('token'); + + HomeService homeService = HomeService(); + user = await homeService.getUser(token: token); + + if (user != null) { + print(user); // For debugging, prints the user details + } else { + print('Failed to fetch user data'); + } } } + + + + + + +// import 'package:cheminova/controller/home_service.dart'; +// import 'package:cheminova/models/user_model.dart'; +// import 'package:get/get.dart'; +// import 'package:shared_preferences/shared_preferences.dart'; +// +// import '../notification_service.dart'; +// +// class HomeController extends GetxController { +// final HomeService homeService = HomeService(); +// NotificationServices notificationServices = NotificationServices(); +// +// +// +// var userModel = UserModel(id: '', uniqueId: '', name: '', email: '', phone: '', role: '', sbu: '', createdAt: '', updatedAt: '' +// +// ).obs; // Observable for UserModel +// +// @override +// void onInit() { +// getUser(); +// super.onInit(); +// notificationServices.requestNotificationPermission(); +// notificationServices.getDeviceToken().then((value) { +// print('Device Token: $value'); +// fcmToken(); +// }); +// } +// +// Future fcmToken() async { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// String? token = prefs.getString('token'); +// final fcmToken = await NotificationServices().getDeviceToken(); +// print('fcmToken: $fcmToken'); +// homeService.fcmToken({"fcmToken": fcmToken}, token!); +// } +// +// Future getUser() async { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// +// String? token = prefs.getString('token'); +// +// userModel = (await homeService.getUser(token: token)) as dynamic; +// +// +// // if (userModel != null) { +// // if (userModel != null) {ddddd +// // userModel.value = userResponse as UserModel; // Update the userModel with API response +// // update(); // Notify GetX to rebuild widgets using GetBuilder/Obx +// // } +// } +// } +// diff --git a/lib/controller/home_service.dart b/lib/controller/home_service.dart index ba5ed41..06190d4 100644 --- a/lib/controller/home_service.dart +++ b/lib/controller/home_service.dart @@ -1,25 +1,58 @@ import 'package:cheminova/models/user_model.dart'; +import 'package:cheminova/utils/api_urls.dart'; import 'package:cheminova/utils/common_api_service.dart'; import 'package:cheminova/utils/show_snackbar.dart'; class HomeService { - Future?> getUser({String? token}) async { + Future getUser({String? token}) async { try { - final response = await commonApiService>( + final response = await commonApiService( method: "GET", - url: "api/v1/user/details", - fromJson: (json) => json, + url: ApiUrls.profileUrl, additionalHeaders: { // Pass the token here 'Authorization': 'Bearer $token', }, + fromJson: (json) { + if (json['user'] != null) { + // Parse the user data from the API response + return UserModel.fromJson(json['user']); + } + return json as UserModel; + }, + ); + return response; + } catch (e) { + print(e.toString()); + showSnackbar(e.toString()); // Optional: show error using a Snackbar + return null; + } + } + + + Future?> fcmToken(Map data, + String? token) async { + try { + final response = await commonApiService( + url: ApiUrls.fcmUrl, + method: 'POST', + body: data, + fromJson: (json) => json as String, + // Just return the string response + additionalHeaders: { // Pass the token here + 'Authorization': 'Bearer $token', + }, ); - return response; + if (response != null) { + // Since the response is a string, wrap it in a Map to avoid type issues + return { + 'message': response + }; // Return the response in a map with 'message' as the key + } + return null; } catch (e) { - showSnackbar(e.toString()); + showSnackbar(e.toString()); // Handle any errors + return null; } - return null; } - - } diff --git a/lib/models/user_model.dart b/lib/models/user_model.dart index b079da9..8413f5f 100644 --- a/lib/models/user_model.dart +++ b/lib/models/user_model.dart @@ -1,43 +1,99 @@ class UserModel { - String id; - String name; - String uniqueId; - String email; - bool isVerified; + final String id; + final String uniqueId; + final String name; + final String email; + final String phone; + final String role; + final String sbu; + final String createdAt; + final String updatedAt; + final String? fcmToken; + final Avatar? avatar; UserModel({ required this.id, - required this.name, required this.uniqueId, + required this.name, required this.email, - required this.isVerified, + required this.phone, + required this.role, + required this.sbu, + required this.createdAt, + required this.updatedAt, + this.fcmToken, + this.avatar, }); - // Factory constructor to create an instance of UserModel from a JSON map + // Factory constructor for converting JSON to UserModel factory UserModel.fromJson(Map json) { return UserModel( - id: json['_id'] ??"", - name: json['name'] ??"Sarita", - uniqueId: json['uniqueId'] ??"1234", - email: json['email'] ??"", - isVerified: json['isVerified'] as bool? ??false, + id: json['_id'], + uniqueId: json['uniqueId'], + name: json['name'], + email: json['email'], + phone: json['phone'], + role: json['role'], + sbu: json['SBU'], + createdAt: json['createdAt'], + updatedAt: json['updatedAt'], + fcmToken: json['fcm_token'], + avatar: json['avatar'] != null ? Avatar.fromJson(json['avatar']) : null, ); } - // Method to convert an instance of UserModel to a JSON map + // Method to convert UserModel to JSON Map toJson() { return { '_id': id, - 'name': name, 'uniqueId': uniqueId, + 'name': name, 'email': email, - 'isVerified': isVerified, + 'phone': phone, + 'role': role, + 'SBU': sbu, + 'createdAt': createdAt, + 'updatedAt': updatedAt, + 'fcm_token': fcmToken, + 'avatar': avatar?.toJson(), }; } - // Override toString() to provide a readable output + // Overriding toString to get a readable output for debugging @override String toString() { - return 'UserModel{id: $id, name: $name, uniqueId: $uniqueId, email: $email, isVerified: $isVerified}'; + return 'UserModel{id: $id, uniqueId: $uniqueId, name: $name, email: $email, phone: $phone, role: $role, sbu: $sbu, createdAt: $createdAt, updatedAt: $updatedAt, fcmToken: $fcmToken, avatar: $avatar}'; + } +} + +// Avatar model to handle avatar data +class Avatar { + final String publicId; + final String url; + + Avatar({ + required this.publicId, + required this.url, + }); + + // Factory constructor for converting JSON to Avatar + factory Avatar.fromJson(Map json) { + return Avatar( + publicId: json['public_id'] ?? '', + url: json['url'] ?? '', + ); + } + + // Method to convert Avatar to JSON + Map toJson() { + return { + 'public_id': publicId, + 'url': url, + }; + } + + @override + String toString() { + return 'Avatar{publicId: $publicId, url: $url}'; } } diff --git a/lib/screens/authentication/controller/auth_controller.dart b/lib/screens/authentication/controller/auth_controller.dart index ab08871..ab473ab 100644 --- a/lib/screens/authentication/controller/auth_controller.dart +++ b/lib/screens/authentication/controller/auth_controller.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; + +import 'package:cheminova/controller/home_controller.dart'; import 'package:cheminova/screens/authentication/controller/auth_service.dart'; import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/utils/show_snackbar.dart'; @@ -5,18 +8,31 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../../../notification_service.dart'; +import '../../../utils/api_client.dart'; +import '../../../utils/api_urls.dart'; +import '../../../utils/secure__storage_service.dart'; + class AuthController extends GetxController { final authService = AuthService(); + final _apiClient = ApiClient(); + final _storageService = SecureStorageService(); + TextEditingController emailController = TextEditingController(); TextEditingController passwordController = TextEditingController(); - TextEditingController phoneController = TextEditingController(); + //TextEditingController phoneController = TextEditingController(); TextEditingController currentpassController = TextEditingController(); TextEditingController newpassController = TextEditingController(); TextEditingController confirmpassController = TextEditingController(); + final HomeController _homeController = Get.put(HomeController()); RxBool isLoading = false.obs; - + @override + void onInit(){ + super.onInit(); + NotificationServices().requestNotificationPermission(); + } Future login() async { isLoading.value = true; final response = await authService.login({ @@ -26,7 +42,9 @@ class AuthController extends GetxController { isLoading.value = false; update(); if (response != null) { + _homeController.fcmToken(); showSnackbar("Your Successfully logged In!"); + Get.offAll(() => const HomeScreen()); } else if(response == null){ @@ -34,7 +52,54 @@ class AuthController extends GetxController { } } - Future forgotpass() async{ + // Future<(bool, String)> login() async { + // isLoading(true); + // try { + // Response response = (await _apiClient.post( + // ApiUrls.loginUrl, + // data: { + // 'email': emailController.text, + // 'password': passwordController.text + // }, + // )) as Response; + // + // isLoading(false); + // + // // Check if the response status code is 200 + // if (response.statusCode == 200) { + // // Access the data field from the response + // final responseData = jsonDecode(response.body) as Map; + // final token = responseData['token']; + // final message = responseData['message']; + // + // await _storageService.write( + // key: 'access_token', + // value: token, + // ); + // + // final fcmToken = await NotificationServices().getDeviceToken(); + // print('fcmToken: $fcmToken'); + // + // await _apiClient.post( + // ApiUrls.fcmUrl, + // data: {'fcmToken': fcmToken}, + // ); + // + // return (true, message.toString()); + // } else { + // // Handle the error based on status code + // final responseData = jsonDecode(response.body) as Map; + // return (false, responseData['message'].toString()); + // } + // } catch (e) { + // isLoading(false); + // return (false, 'Something went wrong'); + // } + // } + + + +Future forgotpass() async{ isLoading.value = true; final response = await authService.forgotPassword( { diff --git a/lib/screens/authentication/controller/auth_service.dart b/lib/screens/authentication/controller/auth_service.dart index 8d20668..64cc3b8 100644 --- a/lib/screens/authentication/controller/auth_service.dart +++ b/lib/screens/authentication/controller/auth_service.dart @@ -1,11 +1,15 @@ +import 'package:cheminova/utils/api_urls.dart'; import 'package:cheminova/utils/common_api_service.dart'; import 'package:cheminova/utils/show_snackbar.dart'; +import '../../../utils/api_client.dart'; + class AuthService { + Future?> login(Map data) async { try { final response = await commonApiService>( - url: '/api/v1/user/login/', + url: ApiUrls.loginUrl, method: 'POST', body: data, fromJson: (json) => json, // Simply return the JSON map as is @@ -21,7 +25,7 @@ class AuthService { Future?> forgotPassword(Map data) async { try { final response = await commonApiService>( - url: '/api/v1/user/password/forgot', + url: ApiUrls.forgetPasswordUrl, method: 'POST', body: data, fromJson: (json) => json, // Simply return the JSON map as is @@ -37,7 +41,7 @@ class AuthService { Future?> changePassword(Map data, {required String token}) async { try { final response = await commonApiService>( - url: '/api/v1/user/password/update', + url: ApiUrls.changePasswordUrl, method: 'PUT', body: data, fromJson: (json) => json, // Simply return the JSON map as is diff --git a/lib/screens/authentication/profile_screen.dart b/lib/screens/authentication/profile_screen.dart new file mode 100644 index 0000000..8fc3f70 --- /dev/null +++ b/lib/screens/authentication/profile_screen.dart @@ -0,0 +1,117 @@ +import 'package:cheminova/controller/home_controller.dart'; +import 'package:cheminova/widgets/my_drawer.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:get/get.dart'; + + +import '../../widgets/comman_background.dart'; +import '../../widgets/common_appbar.dart'; + +class ProfileScreen extends StatefulWidget { + // String? name; + // final String uniqueId; + // final String email; + // final String mobileNumber; + // final String designation; + + const ProfileScreen({ + Key? key, + + }) : super(key: key); + + @override + State createState() => _ProfileScreenState(); +} + +class _ProfileScreenState extends State { + + final homecontroller = Get.put(HomeController()); + @override + Widget build(BuildContext context) { + final user = homecontroller!.user; + return Stack( + children: [ + CommonBackground( + isFullWidth: true, + child: Scaffold( + drawer: MyDrawer(), + backgroundColor: Colors.transparent, + appBar: CommonAppBar( + title: const Text('Profile'), + backgroundColor: Colors.transparent, + elevation: 0, + actions: [ + IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: SvgPicture.asset( + 'assets/svg/back_arrow.svg', + ), + padding: const EdgeInsets.only(right: 20), + ), + ], + ), + body: SingleChildScrollView( + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(20.0) + .copyWith(top: 15, bottom: 30), + margin: const EdgeInsets.symmetric( + horizontal: 30.0, vertical: 20.0), + decoration: BoxDecoration( + border: Border.all(color: Colors.white), + color: const Color(0xffB4D1E5).withOpacity(0.9), + borderRadius: BorderRadius.circular(26.0), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + _buildProfileItem('Name', user!.name), + _buildProfileItem('ID', user.uniqueId), + _buildProfileItem('Email ID', user.email), + _buildProfileItem('Mobile Number', user.phone), + _buildProfileItem('Designation', user.role), + ], + ), + ), + ], + ), + ), + ), + ), + ], + ); + } + + Widget _buildProfileItem(String label, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xff004791), + ), + ), + const SizedBox(height: 5), + Text( + value, + style: const TextStyle( + fontSize: 18, + color: Colors.black, + ), + ), + const Divider(color: Colors.grey), + ], + ), + ); + } +} diff --git a/lib/utils/api_client.dart b/lib/utils/api_client.dart new file mode 100644 index 0000000..e62166e --- /dev/null +++ b/lib/utils/api_client.dart @@ -0,0 +1,60 @@ + +import 'package:cheminova/utils/secure__storage_service.dart'; +import 'package:dio/dio.dart'; +import 'package:pretty_dio_logger/pretty_dio_logger.dart'; + +import 'api_urls.dart'; + + +class ApiClient { + final Dio _dio; + final SecureStorageService _storageService = SecureStorageService(); + + ApiClient({String? baseUrl}) + : _dio = Dio(BaseOptions( + baseUrl: baseUrl ?? ApiUrls.baseUrl, + connectTimeout: const Duration(seconds: 120), + receiveTimeout: const Duration(seconds: 120))) { + _dio.interceptors + .add(LogInterceptor(responseBody: true, requestBody: true)); + _dio.interceptors + .add(InterceptorsWrapper(onRequest: (options, handler) async { + String? token = await _storageService.read(key: 'access_token'); + if (token != null) { + options.headers['Authorization'] = 'Bearer $token'; + } + _dio.interceptors + .add(LogInterceptor(responseBody: true, requestBody: true)); + _dio.interceptors.add(PrettyDioLogger( + requestHeader: true, + requestBody: true, + responseBody: true, + responseHeader: false, + error: true, + compact: true, + maxWidth: 90, + )); + return handler.next(options); + }, onResponse: (response, handler) { + return handler.next(response); + }, onError: (DioException e, handler) { + return handler.next(e); + })); + } + + Future get(String path, {Map? queryParameters}) { + return _dio.get(path, queryParameters: queryParameters); + } + + Future post(String path, {dynamic data}) { + return _dio.post(path, data: data); + } + + Future put(String path, {Map? data}) { + return _dio.put(path, data: data); + } + + Future delete(String path, {Map? data}) { + return _dio.delete(path, data: data); + } +} diff --git a/lib/utils/api_urls.dart b/lib/utils/api_urls.dart new file mode 100644 index 0000000..ee535fd --- /dev/null +++ b/lib/utils/api_urls.dart @@ -0,0 +1,18 @@ +class ApiUrls { + // static const String baseUrl = 'https://cheminova-api-2.onrender.com/api/'; + static const String baseUrl = 'https://api.cnapp.co.in'; + static const String loginUrl = '/api/v1/user/login/'; + static const String profileUrl = '/api/v1/user/details'; + static const String forgetPasswordUrl = '/api/v1/user/password/forgot'; + static const String changePasswordUrl = '/api/v1/user/password/update'; + static const String fcmUrl = '/api/v1/user/fcm-token'; + static const String getCategoryUrl = '/api/category/getCategories'; + static const String getProductUrl = '/api/category/getCategories'; + static const String getProductManualUrl = '/api/productmanual/getall'; + static const String getKycUrl = '/api/kyc/getAll'; + static const String getNotificationUrl = '/api/get-notification-pd'; + static const String getPlacedOrderUrl ='/api/get-placed-order-pd'; + static const String getSinglePlacedOrderUrl ='/api/get-single-placed-order-pd'; + static const String placedOrderUrl ='${baseUrl}/api/order-place'; + +} diff --git a/lib/utils/upper_case_format.dart b/lib/utils/upper_case_format.dart new file mode 100644 index 0000000..909139a --- /dev/null +++ b/lib/utils/upper_case_format.dart @@ -0,0 +1,11 @@ +import 'package:flutter/services.dart'; + +class UpperCaseTextFormatter extends TextInputFormatter { + @override + TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + return newValue.copyWith( + text: newValue.text.toUpperCase(), + selection: newValue.selection, + ); + } +} \ No newline at end of file diff --git a/lib/widgets/my_drawer.dart b/lib/widgets/my_drawer.dart index 7dcdc48..9ad4389 100644 --- a/lib/widgets/my_drawer.dart +++ b/lib/widgets/my_drawer.dart @@ -1,83 +1,185 @@ import 'package:cheminova/controller/home_controller.dart'; +import 'package:cheminova/models/user_model.dart'; import 'package:cheminova/screens/authentication/change_password_screen.dart'; import 'package:cheminova/screens/authentication/login_screen.dart'; +import 'package:cheminova/screens/authentication/profile_screen.dart'; import 'package:cheminova/screens/home_screen.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; class MyDrawer extends StatefulWidget { - const MyDrawer({super.key}); + final UserModel? userModel; + + MyDrawer({super.key, this.userModel}); @override State createState() => _MyDrawerState(); } class _MyDrawerState extends State { - final homeController = Get.put(HomeController()); + final homecontroller = Get.put(HomeController()); @override Widget build(BuildContext context) { + final user = homecontroller.user; return Drawer( child: ListView( padding: EdgeInsets.zero, children: [ SizedBox( height: 150, - child: Obx( - (){ - return DrawerHeader( - decoration: const BoxDecoration( - color: Colors.black87, + child: DrawerHeader( + decoration: const BoxDecoration( + color: Colors.black87, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + user!.name ?? "username", + style: const TextStyle( + color: Colors.white, + fontSize: 18, + ), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - homeController.user.value?.name?? "username", - style: const TextStyle( - color: Colors.white, - fontSize: 18, - ), - ), - Text( - homeController.user.value?.uniqueId?? 'Employee ID', - style: const TextStyle( - color: Colors.white, - fontSize: 20, - ), - ), - ], + Text( + user!.uniqueId ?? 'Employee ID', + style: const TextStyle( + color: Colors.white, + fontSize: 20, + ), ), - ); - }, + ], + ), ), ), ListTile( leading: const Icon(Icons.home), title: const Text('Home'), - onTap: () => Get.offAll(() => const HomeScreen()), + onTap: () { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => const HomeScreen()), + (route) => false, + ); + }, ), ListTile( leading: const Icon(Icons.account_circle), title: const Text('Profile'), onTap: () { - Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ProfileScreen()), + ); }, ), ListTile( leading: const Icon(Icons.settings), title: const Text('Change Password'), onTap: () { - Get.to(ChangePasswordScreen()); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ChangePasswordScreen()), + ); }, ), ListTile( leading: const Icon(Icons.exit_to_app), title: const Text('Logout'), - onTap: () => Get.offAll(() => const LoginScreen()), + onTap: () { + logoutBox(context); + }, ), ], ), ); } } + +Future logoutBox(BuildContext context) { + Size size = MediaQuery.of(context).size; + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0), + ), + backgroundColor: Colors.white, + alignment: Alignment.center, + title: const Text('Are you sure you want to log out?'), + titleTextStyle: const TextStyle( + fontSize: 20, fontWeight: FontWeight.w400, color: Colors.black), + actionsAlignment: MainAxisAlignment.center, + actionsPadding: const EdgeInsets.only(left: 10, right: 10, bottom: 20), + actions: [ + Row( + children: [ + Expanded( + child: SizedBox( + height: (size.height / 50.52) * 2, + child: ElevatedButton( + style: ButtonStyle( + elevation: MaterialStateProperty.all(0), + backgroundColor: MaterialStateProperty.all( + Colors.black), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0), + )), + ), + onPressed: () async { + Navigator.pop(context); + }, + child: const Text( + "No", + style: TextStyle( + fontSize: 17, + color: Colors.white, + fontWeight: FontWeight.w500), + ), + ), + ), + ), + const SizedBox(width: 5), + Expanded( + child: SizedBox( + height: (size.height / 50.52) * 2, + child: ElevatedButton( + style: ButtonStyle( + elevation: MaterialStateProperty.all(0), + backgroundColor: + MaterialStateProperty.all(Colors.white), + shape: + MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0), + side: const BorderSide( + color: Colors.purple, width: 1))), + ), + onPressed: () async { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (context) => LoginScreen()), + (route) => false, + ); + }, + child: const Text( + "Yes", + style: TextStyle( + fontSize: 17, + color: Colors.purple, + fontWeight: FontWeight.w500), + ), + ), + ), + ), + ], + ) + ], + ); + }, + ); +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 7299b5c..0a1f571 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,12 +7,16 @@ #include "generated_plugin_registrant.h" #include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStoragePlugin"); + flutter_secure_storage_plugin_register_with_registrar(flutter_secure_storage_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 786ff5c..1107468 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_linux + flutter_secure_storage url_launcher_linux ) diff --git a/pubspec.lock b/pubspec.lock index 80a9be6..4f0272f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -342,6 +342,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.22" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + sha256: "9f3dd2ac3b6875b0fde5b04734789c3ef35ba3965c18e99dd564a7a2f8056df6" + url: "https://pub.dev" + source: hosted + version: "4.2.1" flutter_svg: dependency: "direct main" description: @@ -664,6 +672,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pretty_dio_logger: + dependency: "direct main" + description: + name: pretty_dio_logger + sha256: "36f2101299786d567869493e2f5731de61ce130faa14679473b26905a92b6407" + url: "https://pub.dev" + source: hosted + version: "1.4.0" shared_preferences: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 623e98d..6c71145 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,6 +54,8 @@ dependencies: flutter_local_notifications: ^17.2.1+2 firebase_crashlytics: ^4.0.4 firebase_analytics: ^11.2.1 + flutter_secure_storage: ^4.2.1 + pretty_dio_logger: ^1.4.0 dev_dependencies: flutter_test: