You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			253 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Dart
		
	
			
		
		
	
	
			253 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Dart
		
	
| import 'package:flutter/gestures.dart';
 | |
| import 'package:flutter/material.dart';
 | |
| import 'package:fluttertoast/fluttertoast.dart';
 | |
| import 'package:provider/provider.dart';
 | |
| import 'package:shared_preferences/shared_preferences.dart';
 | |
| import 'package:test_sa/app_strings/app_asset.dart';
 | |
| import 'package:test_sa/controllers/notification/firebase_notification_manger.dart';
 | |
| import 'package:test_sa/controllers/providers/settings/app_settings.dart';
 | |
| import 'package:test_sa/extensions/context_extension.dart';
 | |
| import 'package:test_sa/extensions/int_extensions.dart';
 | |
| import 'package:test_sa/extensions/string_extensions.dart';
 | |
| import 'package:test_sa/extensions/text_extensions.dart';
 | |
| import 'package:test_sa/extensions/widget_extensions.dart';
 | |
| import 'package:test_sa/models/new_models/general_response_model.dart';
 | |
| import 'package:test_sa/new_views/app_style/app_color.dart';
 | |
| import 'package:test_sa/new_views/forget_password_module/forget_passwod_verify_otp.dart';
 | |
| import 'package:test_sa/new_views/pages/land_page/land_page.dart';
 | |
| import 'package:url_launcher/url_launcher.dart';
 | |
| 
 | |
| import '../../controllers/providers/api/user_provider.dart';
 | |
| import '../../controllers/providers/settings/setting_provider.dart';
 | |
| import '../../controllers/validator/validator.dart';
 | |
| import '../../models/user.dart';
 | |
| import '../common_widgets/app_filled_button.dart';
 | |
| import '../common_widgets/app_text_form_field.dart';
 | |
| 
 | |
| class LoginPage extends StatefulWidget {
 | |
|   static const String routeName = "/login_page";
 | |
| 
 | |
|   const LoginPage({Key? key}) : super(key: key);
 | |
| 
 | |
|   @override
 | |
|   State<LoginPage> createState() => _LoginPageState();
 | |
| }
 | |
| 
 | |
| class _LoginPageState extends State<LoginPage> {
 | |
|   final User _user = User();
 | |
|   late UserProvider _userProvider;
 | |
|   SettingProvider? _settingProvider;
 | |
|   final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
 | |
|   TextEditingController userNameController = TextEditingController();
 | |
|   bool _passwordVisible = false;
 | |
|   bool rememberMe = false;
 | |
|   bool privacyPolicyChecked = false;
 | |
| 
 | |
|   @override
 | |
|   void initState() {
 | |
|     super.initState();
 | |
|     if (FirebaseNotificationManger.token == null) FirebaseNotificationManger.getToken();
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     _userProvider = Provider.of<UserProvider>(context);
 | |
|     if (_settingProvider == null) {
 | |
|       _settingProvider = Provider.of<SettingProvider>(context);
 | |
|       rememberMe = _settingProvider!.rememberMe;
 | |
|       if (rememberMe) {
 | |
|         _user.userName = _settingProvider!.username;
 | |
|         userNameController.text = _user.userName ?? '';
 | |
|         _user.password = _settingProvider!.password;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return Form(
 | |
|       key: _formKey,
 | |
|       child: Scaffold(
 | |
|           backgroundColor: AppColor.background(context),
 | |
|           body: SingleChildScrollView(
 | |
|             child: Column(
 | |
|               mainAxisSize: MainAxisSize.min,
 | |
|               children: [
 | |
|                 Container(
 | |
|                   width: double.infinity,
 | |
|                   height: 293.toScreenHeight,
 | |
|                   padding: EdgeInsets.only(left: 16.toScreenWidth),
 | |
|                   decoration: BoxDecoration(
 | |
|                     image: DecorationImage(
 | |
|                       image: AssetImage(AppAsset.loginTopBg),
 | |
|                       fit: BoxFit.cover, // Adjusts the image to cover the entire container
 | |
|                     ),
 | |
|                   ),
 | |
|                   child: Column(
 | |
|                     crossAxisAlignment: CrossAxisAlignment.start,
 | |
|                     mainAxisAlignment: MainAxisAlignment.start,
 | |
|                     children: [
 | |
|                       SizedBox(
 | |
|                         height: 100.toScreenHeight,
 | |
|                       ),
 | |
|                       "logo_white".toPngAsset(width: 110),
 | |
|                       25.height,
 | |
|                       context.translation.signInToYour.customHeadingText(context).custom(color: Colors.white, fontSize: 27, fontWeight: FontWeight.w500),
 | |
|                       context.translation.account.customHeadingText(context).custom(color: Colors.white, fontSize: 27, fontWeight: FontWeight.w500),
 | |
|                       15.height,
 | |
|                     ],
 | |
|                   ),
 | |
|                 ),
 | |
|                 SizedBox(
 | |
|                   height: 47.toScreenHeight,
 | |
|                 ),
 | |
|                 Padding(
 | |
|                   padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
 | |
|                   child: Column(
 | |
|                     mainAxisAlignment: MainAxisAlignment.center,
 | |
|                     crossAxisAlignment: CrossAxisAlignment.start,
 | |
|                     children: [
 | |
|                       AppTextFormField(
 | |
|                         initialValue: _user.userName ?? "",
 | |
|                         controller: userNameController,
 | |
|                         backgroundColor: AppColor.fieldBgColor(context),
 | |
|                         validator: (value) => Validator.hasValue(value!) ? null : context.translation.requiredField,
 | |
|                         labelText: context.translation.username,
 | |
|                         style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
 | |
|                         floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
 | |
|                         labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)),
 | |
|                         textInputType: TextInputType.text,
 | |
|                         showWithoutDecoration: true,
 | |
|                         contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight),
 | |
|                         onSaved: (value) {
 | |
|                           _user.userName = value;
 | |
|                         },
 | |
|                       ),
 | |
|                       16.height,
 | |
|                       AppTextFormField(
 | |
|                         initialValue: _user.password ?? "",
 | |
|                         showWithoutDecoration: true,
 | |
|                         labelText: context.translation.password,
 | |
|                         backgroundColor: AppColor.fieldBgColor(context),
 | |
|                         style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
 | |
|                         labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)),
 | |
|                         floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
 | |
|                         contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight),
 | |
|                         obscureText: !_passwordVisible,
 | |
|                         suffixIcon: Icon(
 | |
|                           // Based on passwordVisible state choose the icon
 | |
|                           _passwordVisible ? Icons.visibility : Icons.visibility_off,
 | |
|                           color: context.isDark ? AppColor.neutral10 : AppColor.neutral20,
 | |
|                         ).paddingOnly(end: 12).onPress(() {
 | |
|                           setState(() {
 | |
|                             _passwordVisible = !_passwordVisible;
 | |
|                           });
 | |
|                         }),
 | |
|                         validator: (value) => Validator.isValidPassword(value!)
 | |
|                             ? null
 | |
|                             : value.isEmpty
 | |
|                                 ? context.translation.requiredField
 | |
|                                 : context.translation.passwordLengthMessage,
 | |
|                         onSaved: (value) {
 | |
|                           _user.password = value;
 | |
|                         },
 | |
|                       ),
 | |
|                       16.height,
 | |
|                       Align(
 | |
|                         alignment: AlignmentDirectional.centerEnd,
 | |
|                         child: context.translation.forgotPassword.bodyText(context).custom(color: AppColor.primary10, fontWeight: FontWeight.w500).onPress(() async {
 | |
|                           if (userNameController.text.isNotEmpty) {
 | |
|                             GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(context: context, employeeId: userNameController.text);
 | |
|                             if (response.isSuccess == true) {
 | |
|                               Navigator.push(
 | |
|                                   context,
 | |
|                                   MaterialPageRoute(
 | |
|                                       builder: (context) => ForgetPasswordVerifyOtpView(
 | |
|                                             data: {'employeeId': userNameController.text, 'phoneNumber': response.data},
 | |
|                                           )));
 | |
|                               // Navigator.push(context, ForgetPasswordVerifyOtpView.routeName);
 | |
|                             } else {
 | |
|                               context.showConfirmDialog(response.message ?? context.translation.failedToCompleteRequest);
 | |
|                             }
 | |
|                           } else {
 | |
|                             Fluttertoast.showToast(msg: context.translation.employeeIdIsRequired);
 | |
|                           }
 | |
|                         }),
 | |
|                       ),
 | |
|                       Row(
 | |
|                         children: [
 | |
|                           Checkbox(
 | |
|                               value: rememberMe,
 | |
|                               activeColor: AppColor.blueStatus(context),
 | |
|                               materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
 | |
|                               onChanged: (value) {
 | |
|                                 setState(() {
 | |
|                                   rememberMe = value!;
 | |
|                                 });
 | |
|                               }),
 | |
|                           "Remember Me".bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral50).expanded,
 | |
|                         ],
 | |
|                       ),
 | |
|                       Row(
 | |
|                         crossAxisAlignment: CrossAxisAlignment.center,
 | |
|                         children: [
 | |
|                           Checkbox(
 | |
|                               value: privacyPolicyChecked,
 | |
|                               activeColor: AppColor.blueStatus(context),
 | |
|                               materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
 | |
|                               onChanged: (value) {
 | |
|                                 if (value == null) return;
 | |
|                                 privacyPolicyChecked = value;
 | |
|                                 setState(() {});
 | |
|                               }),
 | |
|                           RichText(
 | |
|                             text: TextSpan(text: "I have read and agree to ", style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.primary50 : AppColor.neutral50), children: [
 | |
|                               TextSpan(
 | |
|                                   text: "Privacy Policy",
 | |
|                                   style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context), decoration: TextDecoration.underline),
 | |
|                                   recognizer: TapGestureRecognizer()
 | |
|                                     ..onTap = () async {
 | |
|                                       Uri uri = Uri.parse("https://cloudsolutions.com.sa/en/privacy-policy");
 | |
|                                       try {
 | |
|                                         launchUrl(uri);
 | |
|                                       } catch (ex) {}
 | |
|                                     }),
 | |
|                             ]),
 | |
|                           ).expanded,
 | |
|                         ],
 | |
|                       ),
 | |
|                       16.height,
 | |
|                       AppFilledButton(label: context.translation.signIn, buttonColor: AppColor.primary10, maxWidth: true, onPressed: _login),
 | |
|                     ],
 | |
|                   ),
 | |
|                 ),
 | |
|               ],
 | |
|             ),
 | |
|           )),
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   Future<void> _login() async {
 | |
|     if (!_formKey.currentState!.validate()) return;
 | |
| 
 | |
|     if (privacyPolicyChecked == false) {
 | |
|       "You must agree privacy policy".showToast;
 | |
|       return;
 | |
|     }
 | |
|     _formKey.currentState!.save();
 | |
|     int status = await _userProvider.login(context: context, user: _user);
 | |
|     if (status >= 200 && status < 300 && _userProvider.user!.isAuthenticated! ?? false) {
 | |
|       await _settingProvider!.setUser(_userProvider.user!);
 | |
| 
 | |
|       // (await SharedPreferences.getInstance()).remove(ASettings.localAuth);
 | |
|       await _settingProvider!.setRememberMe(_user.userName!, _user.password!, rememberMe);
 | |
|       //TODO need to verify this here...
 | |
|       if (_userProvider.user?.isEnabledFaceId == true) {
 | |
|         await _settingProvider!.setAuth(_userProvider.user!.isEnabledFaceId!);
 | |
|       } else {
 | |
|         (await SharedPreferences.getInstance()).remove(ASettings.localAuth);
 | |
|       }
 | |
|       Navigator.pushReplacementNamed(context, LandPage.routeName);
 | |
|     } else {
 | |
|       Fluttertoast.showToast(msg: _userProvider.user?.message ?? context.translation.failedToCompleteRequest);
 | |
|     }
 | |
|   }
 | |
| }
 |