From d087c10ca5b30af2c8f43ee9908223fd40906083 Mon Sep 17 00:00:00 2001 From: gitadmin Date: Mon, 2 Mar 2026 12:53:42 +0530 Subject: [PATCH] login and signup --- lib/login/login.dart | 315 ++++++++++++--------- lib/profile/employees.dart | 185 ++++++++---- lib/profile/source_location.dart | 46 ++- lib/resources/resources_drivers.dart | 126 +++++---- lib/signup/signup_mobilenumber_screen.dart | 129 ++++++--- 5 files changed, 528 insertions(+), 273 deletions(-) diff --git a/lib/login/login.dart b/lib/login/login.dart index 1cdc85c..5baa8be 100644 --- a/lib/login/login.dart +++ b/lib/login/login.dart @@ -26,7 +26,7 @@ class _LoginState extends State { bool isObscureText=true; TextEditingController mobileNumberController = TextEditingController(); TextEditingController passwordController = TextEditingController(); - + final _formKey = GlobalKey(); @override void initState() { @@ -51,172 +51,229 @@ class _LoginState extends State { FocusManager.instance.primaryFocus?.unfocus(); }, child: SafeArea( - child: SingleChildScrollView( - child: Padding( + child: SingleChildScrollView( + child: Padding( padding: const EdgeInsets.fromLTRB(24, 0, 24, 0), - child: Column( + child: Form( + key: _formKey, + child: Column( - children: [ - SizedBox(height: MediaQuery.of(context).size.height * .2), - CircleAvatar(radius: 80, backgroundColor: Color(0XFFF3F1FB)), - SizedBox(height: MediaQuery.of(context).size.height * .05), + children: [ + SizedBox(height: MediaQuery.of(context).size.height * .2), + CircleAvatar(radius: 80, backgroundColor: Color(0XFFF3F1FB)), + SizedBox(height: MediaQuery.of(context).size.height * .05), - SizedBox(height:MediaQuery.of(context).size.height * .024,), - Container( - child: TextFormField( + SizedBox(height:MediaQuery.of(context).size.height * .024,), + TextFormField( controller: mobileNumberController, keyboardType: TextInputType.number, - textCapitalization: TextCapitalization.sentences, maxLength: 10, + autovalidateMode: AutovalidateMode.onUserInteraction, + decoration: textFormFieldDecoration(Icons.phone,'Mobile Number'), - style:fontTextStyle(14,Color(0XFF2A2A2A),FontWeight.w400), + + style: fontTextStyle(14, Color(0XFF2A2A2A), FontWeight.w400), cursorColor: Color(0XFF8270DB), - //TextStyle(color: Colors.black,fontWeight: FontWeight.bold), + inputFormatters: [ + + // Allow only numbers + FilteringTextInputFormatter.digitsOnly, + + // Restrict first digit 6-9 + TextInputFormatter.withFunction( + (oldValue, newValue) { + + if (newValue.text.isEmpty) { + return newValue; + } + + // First digit must be 6-9 + if (!RegExp(r'^[6-9]').hasMatch(newValue.text)) { + return oldValue; + } + + return newValue; + }, + ), + ], + + validator: (value) { + + if (value == null || value.isEmpty) { + return "Please enter mobile number"; + } + + if (!RegExp(r'^[6-9]').hasMatch(value)) { + return "Please enter digits 6,7,8,9"; + } + + if (value.length != 10) { + return "Enter valid 10 digit number"; + } + + return null; + }, ), - ), - SizedBox(height:MediaQuery.of(context).size.height * .016,), - - Container( - child: TextFormField( - cursorColor:Color(0XFF8270DB), - obscureText: isObscureText, - obscuringCharacter: '*', - controller: passwordController, - decoration: InputDecoration( - filled: false, - fillColor: Colors.white, - labelText: 'Password', - //prefixIcon: const Icon(Icons.lock, color: Colors.white,), - labelStyle: fontTextStyle(14,Color(0XFF7E7F80),FontWeight.w400), - border: OutlineInputBorder( + SizedBox(height:MediaQuery.of(context).size.height * .016,), + + Container( + child: TextFormField( + cursorColor:Color(0XFF8270DB), + obscureText: isObscureText, + obscuringCharacter: '*', + controller: passwordController, + decoration: InputDecoration( + filled: false, + fillColor: Colors.white, + labelText: 'Password', + //prefixIcon: const Icon(Icons.lock, color: Colors.white,), + labelStyle: fontTextStyle(14,Color(0XFF7E7F80),FontWeight.w400), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(4.0), + borderSide: BorderSide(color: greyColor, + width: 1, )), + focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.0), - borderSide: BorderSide(color: greyColor, - width: 1, )), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(4.0), - borderSide: BorderSide(color: Color(0XFF8270DB),width: 2,), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(4.0), - borderSide: BorderSide(color: greyColor), - ), + borderSide: BorderSide(color: Color(0XFF8270DB),width: 2,), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(4.0), + borderSide: BorderSide(color: greyColor), + ), - suffixIcon: IconButton( - icon: isObscureText==true?Image.asset('images/eye_icon.png',color: Color(0XFF7E7F80),width: 30,height: 30,):Image.asset('images/open_eye.png',color:Color(0XFF7E7F80),width: 30,height: 30,), - /* Icon( + suffixIcon: IconButton( + icon: isObscureText==true?Image.asset('images/eye_icon.png',color: Color(0XFF7E7F80),width: 30,height: 30,):Image.asset('images/open_eye.png',color:Color(0XFF7E7F80),width: 30,height: 30,), + /* Icon( icon:Image.asset('assets/your_image.png'), color: isObscureText==true?greyColor:primaryColor, ),*/ - onPressed: () { + onPressed: () { - print("show password"); - setState(() { - isObscureText = !isObscureText; - }); - }, - ), + print("show password"); + setState(() { + isObscureText = !isObscureText; + }); + }, + ), + ), + style: fontTextStyle(14,Color(0XFF2A2A2A),FontWeight.w400), + validator: (value) { + if (value == null || value.isEmpty) { + return "Please enter password"; + } + return null; + }, ), - style: fontTextStyle(14,Color(0XFF2A2A2A),FontWeight.w400), - ), - ), - - SizedBox(height:MediaQuery.of(context).size.height * .016,), - Align( - alignment: Alignment.bottomLeft, - child:GestureDetector( - onTap: (){ - /* Navigator.push( + + SizedBox(height:MediaQuery.of(context).size.height * .016,), + Align( + alignment: Alignment.bottomLeft, + child:GestureDetector( + onTap: (){ + /* Navigator.push( context, MaterialPageRoute(builder: (context) => ForgotpasswordNew()), );*/ - }, - child: Text( - 'Forgot Password?', - style: fontTextStyle(12,Color(0XFF1D7AFC),FontWeight.w600), + }, + child: Text( + 'Forgot Password?', + style: fontTextStyle(12,Color(0XFF1D7AFC),FontWeight.w600), - ), - ) - ), - SizedBox(height:MediaQuery.of(context).size.height * .024,), - Container( - width:double.infinity, - height: MediaQuery.of(context).size.height * .06, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, - backgroundColor: primaryColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0), // Customize the radius ), - ), - onPressed: () async{ + ) + ), + SizedBox(height:MediaQuery.of(context).size.height * .024,), + Container( + width:double.infinity, + height: MediaQuery.of(context).size.height * .06, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0), // Customize the radius + ), + ), + onPressed: () async { + + // 🔥 THIS MAKES VALIDATION WORK + if (!_formKey.currentState!.validate()) { + return; + } - if (mobileNumberController.text != ''&& - passwordController.text != '') { AppSettings.preLoaderDialog(context); bool isOnline = await AppSettings.internetConnectivity(); if(isOnline){ - SharedPreferences prefs = await SharedPreferences.getInstance(); + + SharedPreferences prefs = + await SharedPreferences.getInstance(); + String? fcmToken = prefs.getString('fcmToken'); - var payload = new Map(); - payload["phone"] = mobileNumberController.text.toString(); - payload["password"] = passwordController.text.toString(); - payload["fcmIds"] = [fcmToken]; - - bool signinStatus = await AppSettings.login(payload); - - try{ - if (signinStatus) { - Navigator.of(context,rootNavigator: true).pop(); - String token = AppSettings.accessToken; - await storage.write(key: 'authToken', value: token); - - print('Token saved: $token'); - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const DashboardScreen()), - ); - AppSettings.longSuccessToast("Logged in Successfully"); - mobileNumberController.text=''; - passwordController.text=''; - - } else { - Navigator.of(context,rootNavigator: true).pop(); - AppSettings.longFailedToast("Invalid details"); - } - } - catch(exception){ - Navigator.of(context,rootNavigator: true).pop(); - print(exception); + + var payload = { + "phone": mobileNumberController.text.trim(), + "password": passwordController.text.trim(), + "fcmIds": [fcmToken] + }; + + bool signinStatus = + await AppSettings.login(payload); + + Navigator.of(context,rootNavigator: true).pop(); + + if (signinStatus) { + + String token = AppSettings.accessToken; + + await storage.write( + key: 'authToken', + value: token); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const DashboardScreen()), + ); + + AppSettings.longSuccessToast( + "Logged in Successfully"); + + mobileNumberController.clear(); + passwordController.clear(); + + } else { + + AppSettings.longFailedToast( + "Invalid details"); + } + } else{ - Navigator.of(context,rootNavigator: true).pop(); - AppSettings.longFailedToast("Please Check internet"); - } + Navigator.of(context, + rootNavigator: true).pop(); - } - else{ + AppSettings.longFailedToast( + "Please Check internet"); - AppSettings.longFailedToast("Please enter valid details"); - } + } - }, - child: Text('Login',style: fontTextStyle(12,Colors.white,FontWeight.w600),), - )), - ], - ), - ) - )), - ), - ], + }, + child: Text('Login',style: fontTextStyle(12,Colors.white,FontWeight.w600),), + )), + ], + ), + ) + )), + ), + ), ], ) ); } diff --git a/lib/profile/employees.dart b/lib/profile/employees.dart index d5f464b..8f7415d 100644 --- a/lib/profile/employees.dart +++ b/lib/profile/employees.dart @@ -26,6 +26,9 @@ class _FleetEmployeesState extends State { final _mobileCtrl = TextEditingController(); final _altMobileCtrl = TextEditingController(); final _locationCtrl = TextEditingController(); + final _experienceController = TextEditingController(); + final _licenseController = TextEditingController(); + final List licenseNumbers = [ "UP3220050012345", @@ -91,10 +94,7 @@ class _FleetEmployeesState extends State { Future _addDriver() async { if (!(_formKey.currentState?.validate() ?? false)) return; - if (selectedLicense == null || selectedExperience == null) { - AppSettings.longFailedToast("Select License & Experience"); - return; - } + var payload = { "Name": _nameCtrl.text.trim(), @@ -373,6 +373,7 @@ class _FleetEmployeesState extends State { controller: _nameCtrl, validator: (v) => _required(v, field: "Driver Name"), textCapitalization: TextCapitalization.none, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: const [ FirstCharUppercaseFormatter(), // << live first-letter caps ], @@ -386,81 +387,105 @@ class _FleetEmployeesState extends State { ), _LabeledField( label: "Driver License Number *", - child: DropdownButtonFormField( - value: selectedLicense, - dropdownColor: Colors.white, - items: licenseNumbers - .map((t) => - DropdownMenuItem(value: t, child: Text(t))) - .toList(), - onChanged: (v) => setState(() => selectedLicense = v), - validator: (v) => v == null || v.isEmpty - ? "Driver License required" - : null, - isExpanded: true, - alignment: Alignment.centerLeft, - hint: Text( - "Select License Number", - style: fontTextStyle( - 14, const Color(0xFF939495), FontWeight.w400), - ), - icon: Image.asset('images/downarrow.png', - width: 16, height: 16), + child: TextFormField( + controller: _licenseController, // create controller decoration: const InputDecoration( border: OutlineInputBorder(), - isDense: false, - contentPadding: EdgeInsets.symmetric( - horizontal: 12, vertical: 14), + hintText: "Enter License Number", + + contentPadding: + EdgeInsets.symmetric(horizontal: 12, vertical: 14), ), + autovalidateMode: AutovalidateMode.onUserInteraction, + style: fontTextStyle( + 14, const Color(0xFF2A2A2A), FontWeight.w400), + + validator: (value) { + if (value == null || value.trim().isEmpty) { + return "Driver License required"; + } + return null; + }, ), ), _LabeledField( label: "Years of Experience *", - child: DropdownButtonFormField( - value: selectedExperience, - dropdownColor: Colors.white, - items: yearOptions - .map((t) => - DropdownMenuItem(value: t, child: Text(t))) - .toList(), - onChanged: (v) => - setState(() => selectedExperience = v), - validator: (v) => v == null || v.isEmpty - ? "Experience is required" - : null, - isExpanded: true, - alignment: Alignment.centerLeft, - hint: Text( - "Years", - style: fontTextStyle( - 14, const Color(0xFF939495), FontWeight.w400), - ), - icon: Image.asset('images/downarrow.png', - width: 16, height: 16), + child: TextFormField( + controller: _experienceController, // create controller + keyboardType: TextInputType.number, + autovalidateMode: AutovalidateMode.onUserInteraction, decoration: const InputDecoration( border: OutlineInputBorder(), - isDense: false, - contentPadding: EdgeInsets.symmetric( - horizontal: 12, vertical: 14), + hintText: "Enter Years", + contentPadding: + EdgeInsets.symmetric(horizontal: 12, vertical: 14), ), + + style: fontTextStyle( + 14, const Color(0xFF2A2A2A), FontWeight.w400), + + validator: (value) { + if (value == null || value.trim().isEmpty) { + return "Experience is required"; + } + return null; + }, ), ), _LabeledField( label: "Phone Number *", child: TextFormField( controller: _mobileCtrl, - validator: (v) => _validatePhone(v), keyboardType: TextInputType.phone, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), + + // Restrict first digit 6-9 + TextInputFormatter.withFunction( + (oldValue, newValue) { + + if (newValue.text.isEmpty) { + return newValue; + } + + // First digit must be 6-9 + if (!RegExp(r'^[6-9]').hasMatch(newValue.text)) { + return oldValue; + } + + return newValue; + }, + ), ], - decoration: InputDecoration( + + validator: (value) { + + if (value == null || value.isEmpty) { + return "Phone Number required"; + } + + if (!RegExp(r'^[6-9]').hasMatch(value)) { + return "Enter digits starting 6,7,8,9"; + } + + if (value.length != 10) { + return "Enter valid 10 digit number"; + } + + return null; + }, + + decoration: InputDecoration( hintText: "Mobile Number", - hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), - border: OutlineInputBorder(), + hintStyle: fontTextStyle( + 14, const Color(0xFF939495), FontWeight.w400), + border: const OutlineInputBorder(), isDense: true, ), + + textInputAction: TextInputAction.next, ), ), _LabeledField( @@ -468,9 +493,27 @@ class _FleetEmployeesState extends State { child: TextFormField( controller: _altMobileCtrl, keyboardType: TextInputType.phone, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), + + // Restrict first digit 6-9 + TextInputFormatter.withFunction( + (oldValue, newValue) { + + if (newValue.text.isEmpty) { + return newValue; + } + + // First digit must be 6-9 + if (!RegExp(r'^[6-9]').hasMatch(newValue.text)) { + return oldValue; + } + + return newValue; + }, + ), ], decoration: InputDecoration( hintText: "Mobile Number", @@ -486,6 +529,7 @@ class _FleetEmployeesState extends State { controller: _locationCtrl, validator: (v) => _required(v, field: "Location"), textCapitalization: TextCapitalization.none, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: const [ FirstCharUppercaseFormatter(), // << live first-letter caps ], @@ -511,6 +555,7 @@ class _FleetEmployeesState extends State { validator: (v) => v == null || v.isEmpty ? "Status is required" : null, isExpanded: true, alignment: Alignment.centerLeft, + autovalidateMode: AutovalidateMode.onUserInteraction, hint: Text( "Select status", style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), @@ -525,12 +570,36 @@ class _FleetEmployeesState extends State { ), const SizedBox(height: 16), ElevatedButton( - onPressed: _addDriver, + onPressed: () { + + if (_formKey.currentState!.validate()) { + + _addDriver(); + + // Reset form validation + _formKey.currentState!.reset(); + + // ✅ Clear TextFields + _mobileCtrl.clear(); + _licenseController.clear(); // Driver License + _experienceController.clear(); + _locationCtrl.clear(); // Location field + _nameCtrl.clear(); + + // ✅ Reset variables (if any) + selectedLicense = null; + selectedExperience = null; + + setState(() {}); + } + + }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF8270DB), foregroundColor: Colors.white, - minimumSize: const Size(343, 41), // Width & Height - padding: const EdgeInsets.fromLTRB(24, 12, 24, 12),), + minimumSize: const Size(343, 41), + padding: const EdgeInsets.fromLTRB(24, 12, 24, 12), + ), child: const Text("Add Driver"), ), ], diff --git a/lib/profile/source_location.dart b/lib/profile/source_location.dart index b5d88f5..fe86616 100644 --- a/lib/profile/source_location.dart +++ b/lib/profile/source_location.dart @@ -172,6 +172,7 @@ class _SourceLocationState extends State { controller: _nameCtrl, validator: (v) => _required(v, field: "Location Name"), textCapitalization: TextCapitalization.none, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: const [ FirstCharUppercaseFormatter(), // << live first-letter caps ], @@ -186,21 +187,58 @@ class _SourceLocationState extends State { ), _LabeledField( - label: "Mobile Number *", + label: "Phone Number *", child: TextFormField( controller: _mobileCtrl, - validator: (v) => _validatePhone(v, label: "Mobile Number"), keyboardType: TextInputType.phone, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), + + // Restrict first digit 6-9 + TextInputFormatter.withFunction( + (oldValue, newValue) { + + if (newValue.text.isEmpty) { + return newValue; + } + + // First digit must be 6-9 + if (!RegExp(r'^[6-9]').hasMatch(newValue.text)) { + return oldValue; + } + + return newValue; + }, + ), ], + + validator: (value) { + + if (value == null || value.isEmpty) { + return "Phone Number required"; + } + + if (!RegExp(r'^[6-9]').hasMatch(value)) { + return "Enter digits starting 6,7,8,9"; + } + + if (value.length != 10) { + return "Enter valid 10 digit number"; + } + + return null; + }, + decoration: InputDecoration( hintText: "Mobile Number", - hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + hintStyle: fontTextStyle( + 14, const Color(0xFF939495), FontWeight.w400), border: const OutlineInputBorder(), isDense: true, ), + textInputAction: TextInputAction.next, ), ), @@ -324,7 +362,9 @@ class _SourceLocationState extends State { hint: Text( "Select Water Type", style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + ), + autovalidateMode: AutovalidateMode.onUserInteraction, icon: Image.asset('images/downarrow.png', width: 16, height: 16), decoration: const InputDecoration( border: OutlineInputBorder(), diff --git a/lib/resources/resources_drivers.dart b/lib/resources/resources_drivers.dart index aa47eab..2f05598 100644 --- a/lib/resources/resources_drivers.dart +++ b/lib/resources/resources_drivers.dart @@ -56,6 +56,8 @@ class _ResourcesDriverScreenState extends State { final _mobileCtrl = TextEditingController(); final _altMobileCtrl = TextEditingController(); final _locationCtrl = TextEditingController(); + final _licenseController = TextEditingController(); + final _experienceController = TextEditingController(); // Unused in UI but kept if you later need them final _commissionCtrl = TextEditingController(); @@ -256,6 +258,7 @@ class _ResourcesDriverScreenState extends State { controller: _nameCtrl, validator: (v) => _required(v, field: "Driver Name"), textCapitalization: TextCapitalization.none, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: const [ FirstCharUppercaseFormatter(), // << live first-letter caps ], @@ -272,64 +275,49 @@ class _ResourcesDriverScreenState extends State { _LabeledField( label: "Driver License Number *", - child: DropdownButtonFormField( - value: selectedLicense, - dropdownColor: Colors.white, - items: licenseNumbers - .map((t) => - DropdownMenuItem(value: t, child: Text(t))) - .toList(), - onChanged: (v) => setState(() => selectedLicense = v), - validator: (v) => v == null || v.isEmpty - ? "Driver License required" - : null, - isExpanded: true, - alignment: Alignment.centerLeft, - hint: Text( - "Select License Number", - style: fontTextStyle( - 14, const Color(0xFF939495), FontWeight.w400), - ), - icon: Image.asset('images/downarrow.png', - width: 16, height: 16), + child: TextFormField( + controller: _licenseController, // create controller decoration: const InputDecoration( border: OutlineInputBorder(), - isDense: false, - contentPadding: EdgeInsets.symmetric( - horizontal: 12, vertical: 14), + hintText: "Enter License Number", + contentPadding: + EdgeInsets.symmetric(horizontal: 12, vertical: 14), ), + + style: fontTextStyle( + 14, const Color(0xFF2A2A2A), FontWeight.w400), + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return "Driver License required"; + } + return null; + }, ), ), _LabeledField( label: "Years of Experience *", - child: DropdownButtonFormField( - value: selectedExperience, - dropdownColor: Colors.white, - items: yearOptions - .map((t) => - DropdownMenuItem(value: t, child: Text(t))) - .toList(), - onChanged: (v) => - setState(() => selectedExperience = v), - validator: (v) => v == null || v.isEmpty - ? "Experience is required" - : null, - isExpanded: true, - alignment: Alignment.centerLeft, - hint: Text( - "Years", - style: fontTextStyle( - 14, const Color(0xFF939495), FontWeight.w400), - ), - icon: Image.asset('images/downarrow.png', - width: 16, height: 16), + child: TextFormField( + controller: _experienceController, // create controller + keyboardType: TextInputType.number, + autovalidateMode: AutovalidateMode.onUserInteraction, decoration: const InputDecoration( border: OutlineInputBorder(), - isDense: false, - contentPadding: EdgeInsets.symmetric( - horizontal: 12, vertical: 14), + hintText: "Enter Years", + contentPadding: + EdgeInsets.symmetric(horizontal: 12, vertical: 14), ), + + style: fontTextStyle( + 14, const Color(0xFF2A2A2A), FontWeight.w400), + + validator: (value) { + if (value == null || value.trim().isEmpty) { + return "Experience is required"; + } + return null; + }, ), ), @@ -337,13 +325,47 @@ class _ResourcesDriverScreenState extends State { label: "Phone Number *", child: TextFormField( controller: _mobileCtrl, - validator: (v) => - _validatePhone(v, label: "Phone Number"), keyboardType: TextInputType.phone, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), + + // Restrict first digit 6-9 + TextInputFormatter.withFunction( + (oldValue, newValue) { + + if (newValue.text.isEmpty) { + return newValue; + } + + // First digit must be 6-9 + if (!RegExp(r'^[6-9]').hasMatch(newValue.text)) { + return oldValue; + } + + return newValue; + }, + ), ], + + validator: (value) { + + if (value == null || value.isEmpty) { + return "Phone Number required"; + } + + if (!RegExp(r'^[6-9]').hasMatch(value)) { + return "Enter digits starting 6,7,8,9"; + } + + if (value.length != 10) { + return "Enter valid 10 digit number"; + } + + return null; + }, + decoration: InputDecoration( hintText: "Mobile Number", hintStyle: fontTextStyle( @@ -351,6 +373,7 @@ class _ResourcesDriverScreenState extends State { border: const OutlineInputBorder(), isDense: true, ), + textInputAction: TextInputAction.next, ), ), @@ -366,6 +389,7 @@ class _ResourcesDriverScreenState extends State { label: "Alternate Phone Number"); }, keyboardType: TextInputType.phone, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), @@ -387,6 +411,7 @@ class _ResourcesDriverScreenState extends State { controller: _locationCtrl, validator: (v) => _required(v, field: "Location"), textCapitalization: TextCapitalization.none, + autovalidateMode: AutovalidateMode.onUserInteraction, inputFormatters: const [ FirstCharUppercaseFormatter(), // << live first-letter caps ], @@ -418,9 +443,12 @@ class _ResourcesDriverScreenState extends State { alignment: Alignment.centerLeft, hint: Text( "Select status", + style: fontTextStyle( 14, const Color(0xFF939495), FontWeight.w400), + ), + autovalidateMode: AutovalidateMode.onUserInteraction, icon: const Icon(Icons.keyboard_arrow_down_rounded), decoration: const InputDecoration( border: OutlineInputBorder(), diff --git a/lib/signup/signup_mobilenumber_screen.dart b/lib/signup/signup_mobilenumber_screen.dart index fe2b6ab..d0ed280 100644 --- a/lib/signup/signup_mobilenumber_screen.dart +++ b/lib/signup/signup_mobilenumber_screen.dart @@ -14,7 +14,7 @@ class SignUpMobileNumberScreen extends StatefulWidget { class _SignUpMobileNumberScreenState extends State { TextEditingController mobileNumberController = TextEditingController(); - + final _formKey = GlobalKey(); @override Widget build(BuildContext context) { @@ -48,17 +48,62 @@ class _SignUpMobileNumberScreenState extends State { ), ), SizedBox(height:MediaQuery.of(context).size.height * .016,), - Container( - child: TextFormField( - controller: mobileNumberController, - keyboardType: TextInputType.number, - textCapitalization: TextCapitalization.sentences, - maxLength: 10, - decoration: textFormFieldDecoration(Icons.phone,'Mobile Number'), - style:fontTextStyle(14,Color(0XFF2A2A2A),FontWeight.w400), - cursorColor: Color(0XFF8270DB), - - //TextStyle(color: Colors.black,fontWeight: FontWeight.bold), + + Form( + key: _formKey, + child: Column( + children: [ + + TextFormField( + controller: mobileNumberController, + keyboardType: TextInputType.number, + maxLength: 10, + autovalidateMode: AutovalidateMode.onUserInteraction, + + decoration: textFormFieldDecoration(Icons.phone,'Mobile Number'), + + style: fontTextStyle(14, Color(0XFF2A2A2A), FontWeight.w400), + cursorColor: Color(0XFF8270DB), + + inputFormatters: [ + + FilteringTextInputFormatter.digitsOnly, + TextInputFormatter.withFunction( + (oldValue, newValue) { + + if (newValue.text.isEmpty) { + return newValue; + } + + // First digit must be 6-9 + if (!RegExp(r'^[6-9]').hasMatch(newValue.text)) { + return oldValue; + } + + return newValue; + }, + ), + ], + + validator: (value) { + + if (value == null || value.isEmpty) { + return "Please enter mobile number"; + } + + if (!RegExp(r'^[6-9]').hasMatch(value)) { + return "Please enter digits 6,7,8,9"; + } + + if (value.length != 10) { + return "Enter valid 10 digit number"; + } + + return null; + }, + ), + + ], ), ), @@ -75,41 +120,57 @@ class _SignUpMobileNumberScreenState extends State { BorderRadius.circular(24.0), // Customize the radius ), ), - onPressed: () async{ - if(mobileNumberController.text.length>=10){ + onPressed: () async { + + if (!_formKey.currentState!.validate()) { + return; + } + + AppSettings.preLoaderDialog(context); - AppSettings.preLoaderDialog(context); + bool isOnline = + await AppSettings.internetConnectivity(); - bool isOnline = await AppSettings.internetConnectivity(); - if(isOnline){ + if(isOnline){ - var payload = new Map(); - payload["phone"] = mobileNumberController.text.toString(); + var payload = { + "phone": + mobileNumberController.text.trim() + }; - bool forgotPwd = await AppSettings.getOtp(payload); + bool forgotPwd = + await AppSettings.getOtp(payload); - if(forgotPwd){ - Navigator.of(context,rootNavigator: true).pop(); - Navigator.push( - context, - new MaterialPageRoute( - builder: (__) => new Otpscreen(mobileNumber:mobileNumberController.text.toString()))); + Navigator.of(context, + rootNavigator: true).pop(); + + if(forgotPwd){ + + Navigator.push( + context, + MaterialPageRoute( + builder: (__)=>Otpscreen( + mobileNumber: + mobileNumberController.text.trim(), + ))); - } - else{ - AppSettings.longFailedToast('Please enter valid registered mobile number'); - } } else{ - Navigator.of(context,rootNavigator: true).pop(); - AppSettings.longFailedToast("Please Check internet"); - } + AppSettings.longFailedToast( + 'Please enter valid registered mobile number'); + } } else{ - AppSettings.longFailedToast('Please enter 10 digits of mobile number'); + + Navigator.of(context, + rootNavigator: true).pop(); + + AppSettings.longFailedToast( + "Please Check internet"); + } },