Merge branch 'dev_aamir' of http://34.17.52.180/Haroon6138/HMG_Patient_App_New into dev_sultan

pull/36/head
Sultan khan 2 months ago
commit 009fa1859e

@ -1,5 +1,6 @@
import 'dart:developer';
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
@ -33,7 +34,7 @@ class ValidationUtils {
if (nationalId != null && nationalId.isNotEmpty && selectedCountry != null) {
if (selectedCountry == CountryEnum.saudiArabia) {
if (!validateIqama(nationalId)) {
_dialogService.showExceptionBottomSheet(message: "Please enter a valid national ID", onOkPressed: onOkPress);
_dialogService.showExceptionBottomSheet(message: "Please enter a valid Iqama ID", onOkPressed: onOkPress);
return false;
}
}
@ -98,4 +99,44 @@ class ValidationUtils {
final regex = RegExp(r'^784\d{4}\d{7}\d{1}$');
return regex.hasMatch(id);
}
static bool validateUaeRegistration({String? name, GenderTypeEnum? gender, NationalityCountries? country, MaritalStatusTypeEnum? maritalStatus, required Function() onOkPress}) {
if (name == null || name.isEmpty) {
_dialogService.showExceptionBottomSheet(message: "Please enter a valid name", onOkPressed: onOkPress);
return false;
}
if (gender == null) {
_dialogService.showExceptionBottomSheet(message: "Please select a gender", onOkPressed: onOkPress);
return false;
}
if (maritalStatus == null) {
_dialogService.showExceptionBottomSheet(message: "Please select a marital status", onOkPressed: onOkPress);
return false;
}
if (country == null) {
_dialogService.showExceptionBottomSheet(message: "Please select a country", onOkPressed: onOkPress);
return false;
}
return true;
}
static bool isValidateEmail({String? email, required Function() onOkPress}) {
if (email == null || email.isEmpty) {
_dialogService.showExceptionBottomSheet(message: "Please enter email", onOkPressed: onOkPress);
return false;
}
final bool emailIsValid = RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,}$").hasMatch(email);
if (!emailIsValid) {
_dialogService.showExceptionBottomSheet(message: "Please enter a valid email format", onOkPressed: onOkPress);
return false;
}
return true;
}
}

@ -109,6 +109,7 @@ class AuthenticationViewModel extends ChangeNotifier {
nationalIdController.clear();
phoneNumberController.clear();
emailController.clear();
dobController.clear();
maritalStatus = null;
genderType = null;
@ -325,7 +326,8 @@ class AuthenticationViewModel extends ChangeNotifier {
);
}
Future<void> sendActivationCode({required OTPTypeEnum otpTypeEnum, required String nationalIdOrFileNumber, required String phoneNumber, required bool isForRegister, dynamic payload}) async {
Future<void> sendActivationCode(
{required OTPTypeEnum otpTypeEnum, required String nationalIdOrFileNumber, required String phoneNumber, required bool isForRegister, dynamic payload, bool isComingFromResendOTP = false}) async {
var request = RequestUtils.getCommonRequestSendActivationCode(
otpTypeEnum: otpTypeEnum,
mobileNumber: phoneNumber,
@ -365,7 +367,7 @@ class AuthenticationViewModel extends ChangeNotifier {
} else {
if (apiResponse.data != null && apiResponse.data['isSMSSent'] == true) {
LoaderBottomSheet.hideLoader();
navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
if (!isComingFromResendOTP) navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber, isComingFromRegister: checkIsUserComingForRegister(request: payload), payload: payload);
} else {
// TODO: Handle isSMSSent false
// navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
@ -387,8 +389,9 @@ class AuthenticationViewModel extends ChangeNotifier {
required String? activationCode,
required OTPTypeEnum otpTypeEnum,
required Function(String? message) onWrongActivationCode,
Function()? onResendActivation,
}) async {
bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true);
bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true || _appState.getUserRegistrationPayload.patientOutSa == 1);
final request = RequestUtils.getCommonRequestWelcome(
phoneNumber: phoneNumberController.text,
@ -554,20 +557,27 @@ class AuthenticationViewModel extends ChangeNotifier {
_navigationService.pushAndReplace(AppRoutes.landingScreen);
}
Future<void> navigateToOTPScreen({required OTPTypeEnum otpTypeEnum, required String phoneNumber}) async {
Future<void> navigateToOTPScreen({required OTPTypeEnum otpTypeEnum, required String phoneNumber, required bool isComingFromRegister, dynamic payload}) async {
_navigationService.pushToOtpScreen(
phoneNumber: phoneNumber,
checkActivationCode: (int activationCode) async {
await checkActivationCode(
activationCode: activationCode.toString(),
activationCode: activationCode.toString(),
otpTypeEnum: otpTypeEnum,
onWrongActivationCode: (String? value) {
onWrongActivationCode(message: value);
},
);
},
onResendOTPPressed: (String phoneNumber) async {
await sendActivationCode(
otpTypeEnum: otpTypeEnum,
onWrongActivationCode: (String? value) {
onWrongActivationCode(message: value);
});
// Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => RegisterNewStep2(null, {"nationalID": "12345678654321"})));
phoneNumber: phoneNumberController.text,
nationalIdOrFileNumber: nationalIdController.text,
isForRegister: isComingFromRegister,
isComingFromResendOTP: true,
payload: payload);
},
onResendOTPPressed: (String phoneNumber) {},
);
}
@ -654,19 +664,18 @@ class AuthenticationViewModel extends ChangeNotifier {
}
Future<void> onRegistrationComplete() async {
LoaderBottomSheet.showLoader();
var request = RequestUtils.getUserSignupCompletionRequest(fullName: nameController.text, emailAddress: emailController.text, gender: genderType, maritalStatus: maritalStatus);
//
print("============= Final Payload ===============");
print(request);
print("=================== ====================");
final resultEither = await _authenticationRepo.registerUser(registrationPayloadDataModelRequest: request);
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
if (apiResponse.data is String) {
//TODO: This Section Need to Be Testing.
_dialogService.showExceptionBottomSheet(message: apiResponse.data, onOkPressed: () {}, onCancelPressed: () {});
//TODO: Here We Need to Show a Dialog Of Something in the case of Fail With OK and Cancel and the Display Variable WIll be result.
} else {
print(apiResponse.data as Map<String, dynamic>);
if (apiResponse.data["MessageStatus"] == 1) {
LoaderBottomSheet.hideLoader();
//TODO: Here We Need to Show a Dialog Of Something in the case of Success.
await clearDefaultInputValues(); // This will Clear All Default Values Of User.
_navigationService.pushAndReplace(AppRoutes.loginScreen);
@ -727,8 +736,6 @@ class AuthenticationViewModel extends ChangeNotifier {
} else {
isOutSideSa = false;
}
print(isOutSideSa);
return isOutSideSa;
}

@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
@ -50,12 +51,12 @@ class OTPWidget extends StatefulWidget {
final TextInputType keyboardType;
final EdgeInsets pinBoxOuterPadding;
OTPWidget({
const OTPWidget({
Key? key,
this.maxLength = 4,
this.controller,
this.pinBoxWidth = 70.0,
this.pinBoxHeight = 100.0,
this.pinBoxHeight = 70.0,
this.pinTextStyle,
this.onDone,
this.defaultBorderColor = Colors.black,
@ -127,7 +128,9 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
_highlightAnimationController = AnimationController(vsync: this);
_initTextController();
_calculateStrList();
widget.controller!.addListener(_controllerListener);
if (widget.controller != null) {
widget.controller!.addListener(_controllerListener);
}
focusNode.addListener(_focusListener);
}
@ -190,7 +193,9 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
focusNode.removeListener(_focusListener);
}
_highlightAnimationController.dispose();
widget.controller?.removeListener(_controllerListener);
if (widget.controller != null) {
widget.controller!.removeListener(_controllerListener);
}
super.dispose();
}
@ -231,7 +236,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
width: 0.0,
),
);
return SizedBox(
return Container(
width: _width,
height: widget.pinBoxHeight,
child: TextField(
@ -241,8 +246,6 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
controller: widget.controller,
keyboardType: widget.keyboardType,
inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null,
// Enable SMS autofill
autofillHints: const [AutofillHints.oneTimeCode],
style: TextStyle(
height: 0.1,
color: Colors.transparent,
@ -301,33 +304,28 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
return _buildPinCode(i, context);
});
return Row(
children: pinCodes,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: pinCodes,
);
}
Widget _buildPinCode(int i, BuildContext context) {
Color borderColor;
Color pinBoxColor;
// Determine if OTP is complete
bool isComplete = text.length == widget.maxLength;
Color pinBoxColor = widget.pinBoxColor;
if (widget.hasError) {
borderColor = widget.errorBorderColor;
pinBoxColor = widget.pinBoxColor;
} else if (isComplete) {
borderColor = Colors.transparent;
pinBoxColor = AppColors.successColor;
pinBoxColor = widget.errorBorderColor;
} else if (i < text.length) {
borderColor = Colors.transparent;
pinBoxColor = AppColors.blackBgColor;
pinBoxColor = AppColors.blackBgColor; // Custom color for filled boxes
} else {
borderColor = Colors.transparent;
pinBoxColor = widget.pinBoxColor;
}
// Change color to success when all fields are complete
if (text.length == widget.maxLength) {
pinBoxColor = AppColors.successColor;
}
EdgeInsets insets;
if (i == 0) {
insets = EdgeInsets.only(
@ -346,22 +344,21 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
} else {
insets = widget.pinBoxOuterPadding;
}
return Container(
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
key: ValueKey<String>("container$i"),
alignment: Alignment.center,
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0),
margin: insets,
decoration: BoxDecoration(
border: Border.all(
color: borderColor,
width: widget.pinBoxBorderWidth,
),
child: _animatedTextBox(strList[i], i),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: pinBoxColor,
borderRadius: BorderRadius.circular(widget.pinBoxRadius),
borderRadius: widget.pinBoxRadius,
),
width: widget.pinBoxWidth,
height: widget.pinBoxHeight,
child: _animatedTextBox(strList[i], i),
);
}
@ -407,10 +404,12 @@ class OTPVerificationScreen extends StatefulWidget {
class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
final int _otpLength = 4;
late TextEditingController _otpController;
late final TextEditingController _otpController;
Timer? _resendTimer;
int _resendTime = 60;
int _resendTime = 120;
bool _isOtpComplete = false;
bool _isVerifying = false; // Flag to prevent multiple verification calls
@override
void initState() {
@ -437,29 +436,27 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
}
void _onOtpChanged(String value) {
// Handle clipboard paste or programmatic input
if (value.length > 1) {
String? otp = _extractOtpFromText(value);
if (otp != null) {
autoFillOtp(otp);
return;
}
}
// The OTPWidget will automatically call onDone when complete
// This method can be used for any additional logic on text change
}
setState(() {
_isOtpComplete = value.length == _otpLength;
});
void _onOtpCompleted(String otp) {
debugPrint('OTP Completed: $otp');
widget.checkActivationCode(int.parse(otp));
if (_isOtpComplete && !_isVerifying) {
_isVerifying = true;
_verifyOtp(value);
} else if (!_isOtpComplete) {
// Reset the flag when OTP is incomplete (user is editing)
_isVerifying = false;
}
}
void _resendOtp() {
if (_resendTime == 0) {
setState(() => _resendTime = 60);
setState(() {
_resendTime = 120;
_isVerifying = false; // Reset verification flag
});
_startResendTimer();
autoFillOtp("1234");
// autoFillOtp("1234");
widget.onResendOTPPressed(widget.phoneNumber);
}
}
@ -469,68 +466,6 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
return phone.length > 4 ? '05xxxxxx${phone.substring(phone.length - 2)}' : phone;
}
/// Extract OTP from text using multiple patterns
String? _extractOtpFromText(String text) {
// Pattern 1: Find 4-6 consecutive digits
RegExp digitPattern = RegExp(r'\b\d{4,6}\b');
Match? match = digitPattern.firstMatch(text);
if (match != null) {
String digits = match.group(0)!;
if (digits.length >= _otpLength) {
return digits.substring(0, _otpLength);
}
}
// Pattern 2: Find digits separated by spaces or special characters
String cleanedText = text.replaceAll(RegExp(r'[^\d]'), '');
if (cleanedText.length >= _otpLength) {
return cleanedText.substring(0, _otpLength);
}
return null;
}
/// Paste OTP from clipboard
Future<void> _pasteFromClipboard() async {
try {
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null && data.text != null) {
String clipboardText = data.text!;
String? otp = _extractOtpFromText(clipboardText);
if (otp != null) {
autoFillOtp(otp);
// Show feedback to user
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('OTP pasted: $otp'),
duration: const Duration(seconds: 2),
backgroundColor: AppColors.successColor,
),
);
} else {
// Show error if no valid OTP found
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('No valid OTP found in clipboard'),
duration: Duration(seconds: 2),
),
);
}
}
} catch (e) {
debugPrint('Error pasting from clipboard: $e');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to paste from clipboard'),
duration: Duration(seconds: 2),
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -560,35 +495,30 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
),
SizedBox(height: 40.h),
// OTP Input Fields using new OTPWidget
// OTP Input Fields using new OTP Widget
Center(
child: AutofillGroup(
child: OTPWidget(
maxLength: _otpLength,
controller: _otpController,
pinBoxWidth: 75.h,
pinBoxHeight: 100.h,
autoFocus: true,
pinBoxRadius: 16,
pinBoxBorderWidth: 0,
pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h),
defaultBorderColor: Colors.transparent,
textBorderColor: Colors.transparent,
errorBorderColor: AppColors.primaryRedColor,
pinBoxColor: AppColors.whiteColor,
pinTextStyle: TextStyle(
fontSize: 50.fSize,
fontWeight: FontWeight.bold,
color: AppColors.whiteColor,
),
onTextChanged: _onOtpChanged,
onDone: _onOtpCompleted,
child: OTPWidget(
maxLength: _otpLength,
controller: _otpController,
pinBoxWidth: 70.h,
pinBoxHeight: 100,
pinBoxRadius: 16,
pinBoxBorderWidth: 0,
pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h),
defaultBorderColor: Colors.transparent,
textBorderColor: Colors.transparent,
pinBoxColor: AppColors.whiteColor,
autoFocus: true,
onTextChanged: _onOtpChanged,
pinTextStyle: TextStyle(
fontSize: 40.fSize,
fontWeight: FontWeight.bold,
color: AppColors.whiteColor,
),
),
),
const SizedBox(height: 16),
const SizedBox(height: 32),
// Resend OTP
Row(
@ -596,9 +526,18 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
children: [
const Text("Didn't receive it? "),
if (_resendTime > 0)
Text(
'resend in (${_resendTime.toString().padLeft(2, '0')}:00). ',
style: const TextStyle(color: Colors.grey),
Builder(
// Use a Builder to easily calculate minutes and seconds inline
builder: (context) {
final minutes = (_resendTime ~/ 60)
.toString()
.padLeft(2, '0'); // Integer division for minutes final seconds = (_resendTime % 60).toString().padLeft(2, '0'); // Modulo for remaining seconds
final seconds = (_resendTime % 60).toString().padLeft(2, '0'); // Modulo for remaining seconds // <--- HERE IT IS
return Text(
'resend in ($minutes:$seconds). ',
style: const TextStyle(color: Colors.grey),
);
},
)
else
GestureDetector(
@ -620,50 +559,15 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
);
}
void _verifyOtp(String otp) {
debugPrint('Verifying OTP: $otp');
widget.checkActivationCode(int.parse(otp));
}
/// Auto fill OTP into text fields
void autoFillOtp(String otp) {
if (otp.length != _otpLength) return;
// Clear any existing text first
_otpController.clear();
// Add a small delay to ensure the UI is updated
Future.delayed(const Duration(milliseconds: 50), () {
_otpController.text = otp;
// Move cursor to the end
_otpController.selection = TextSelection.fromPosition(
TextPosition(offset: otp.length),
);
});
}
/// Clear OTP fields
void clearOtp() {
_otpController.clear();
}
/// Get current OTP value
String getCurrentOtp() {
return _otpController.text;
}
/// Check if OTP is complete
bool isOtpComplete() {
return _otpController.text.length == _otpLength;
}
/// Simulate SMS received with OTP (for testing purposes)
void simulateSMSReceived(String otp) {
if (otp.length == _otpLength && RegExp(r'^\d+$').hasMatch(otp)) {
autoFillOtp(otp);
// Show a brief indicator that SMS was detected
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('OTP detected from SMS: $otp'),
duration: const Duration(seconds: 2),
backgroundColor: AppColors.successColor,
),
);
}
_isVerifying = false;
_otpController.text = otp;
}
}

@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/common_models/nationality_country_model
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
@ -66,7 +67,7 @@ class _RegisterNew extends State<RegisterNewStep2> {
children: [
TextInputWidget(
labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr() : LocaleKeys.name.tr(),
hintText: authVM!.isUserFromUAE() ? "" : ("${appState.getNHICUserData.firstNameEn!.toUpperCase()} ${appState.getNHICUserData.lastNameEn!.toUpperCase()}"),
hintText: authVM!.isUserFromUAE() ? "Enter your full name" : ("${appState.getNHICUserData.firstNameEn!.toUpperCase()} ${appState.getNHICUserData.lastNameEn!.toUpperCase()}"),
controller: authVM!.isUserFromUAE() ? authVM!.nameController : null,
isEnable: true,
prefix: null,
@ -275,6 +276,20 @@ class _RegisterNew extends State<RegisterNewStep2> {
icon: AppAssets.confirm,
iconColor: AppColors.textGreenColor,
onPressed: () {
if (appState.getUserRegistrationPayload.zipCode != CountryEnum.saudiArabia.countryCode) {
if (ValidationUtils.validateUaeRegistration(
name: authVM!.nameController.text,
gender: authVM!.genderType,
country: authVM!.pickedCountryByUAEUser,
maritalStatus: authVM!.maritalStatus,
onOkPress: () {
Navigator.of(context).pop();
})) {
showModel(context: context);
}
} else {
showModel(context: context);
}
// if (isFromDubai) {
// if (name == null) {
// AppToast.showErrorToast(message: LocaleKeys.enterFullName);
@ -293,8 +308,6 @@ class _RegisterNew extends State<RegisterNewStep2> {
// return;
// }
// }
showModel(context: context);
},
),
)
@ -324,7 +337,13 @@ class _RegisterNew extends State<RegisterNewStep2> {
child: CustomButton(
text: LocaleKeys.submit,
onPressed: () {
authVM!.onRegistrationComplete();
if (ValidationUtils.isValidateEmail(
email: authVM!.emailController.text,
onOkPress: () {
Navigator.of(context).pop();
})) {
authVM!.onRegistrationComplete();
}
},
backgroundColor: AppColors.bgGreenColor,
borderColor: AppColors.bgGreenColor,

@ -152,6 +152,7 @@ class _GenericBottomSheetState extends State<GenericBottomSheet> {
prefix: widget.isForEmail ? null : widget.countryCode,
isBorderAllowed: false,
isAllowLeadingIcon: true,
fontSize: 12.h,
isCountryDropDown: widget.isEnableCountryDropdown,
leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone,
)

@ -69,16 +69,21 @@ class _CustomCountryDropdownState extends State<CustomCountryDropdown> {
child: Row(
children: [
GestureDetector(
onTap: () {
if (_isDropdownOpen) {
_closeDropdown();
} else {
_openDropdown();
}
},
child: Utils.buildSvgWithAssets(icon: selectedCountry != null ? selectedCountry!.iconPath : AppAssets.ksa, width: 40.h, height: 40.h)),
SizedBox(width: 8.h),
Utils.buildSvgWithAssets(icon: _isDropdownOpen ? AppAssets.dropdow_icon : AppAssets.dropdow_icon),
onTap: () {
if (_isDropdownOpen) {
_closeDropdown();
} else {
_openDropdown();
}
},
child: Row(
children: [
Utils.buildSvgWithAssets(icon: selectedCountry != null ? selectedCountry!.iconPath : AppAssets.ksa, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Utils.buildSvgWithAssets(icon: _isDropdownOpen ? AppAssets.dropdow_icon : AppAssets.dropdow_icon),
],
),
),
SizedBox(width: 4.h),
if (widget.isFromBottomSheet)
GestureDetector(
@ -100,19 +105,23 @@ class _CustomCountryDropdownState extends State<CustomCountryDropdown> {
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
selectedCountry!.countryCode,
style: TextStyle(fontSize: 12.fSize, height: 21 / 18, fontWeight: FontWeight.w600, letterSpacing: -0.2),
style: TextStyle(fontSize: 12.fSize, height: 23 / 18, fontWeight: FontWeight.w600, letterSpacing: -1),
),
SizedBox(width: 4.h),
if (widget.isEnableTextField)
SizedBox(
height: 18,
height: 20,
width: 200,
// color: Colors.red,
child: TextField(
focusNode: textFocusNode,
decoration: InputDecoration(hintText: "", isDense: true, border: InputBorder.none),
style: TextStyle(fontSize: 12.fSize, height: 23 / 18, fontWeight: FontWeight.w600, letterSpacing: -1),
decoration: InputDecoration(hintText: "", isDense: false, border: InputBorder.none),
keyboardType: TextInputType.phone,
onChanged: widget.onPhoneNumberChanged),
),
@ -146,7 +155,6 @@ class _CustomCountryDropdownState extends State<CustomCountryDropdown> {
_overlayEntry = OverlayEntry(
builder: (context) => Stack(
children: [
// Dismiss dropdown when tapping outside
Positioned.fill(
child: GestureDetector(
onTap: _closeDropdown,
@ -157,7 +165,7 @@ class _CustomCountryDropdownState extends State<CustomCountryDropdown> {
Positioned(
top: offset.dy + renderBox.size.height,
left: widget.isRtl ? offset.dx + 6.h : offset.dx - 6.h,
width: renderBox.size.width,
width: !widget.isFromBottomSheet ? renderBox.size.width : 60.h,
child: Material(
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: Colors.white, borderRadius: 12),
@ -165,27 +173,26 @@ class _CustomCountryDropdownState extends State<CustomCountryDropdown> {
children: widget.countryList
.map(
(country) => GestureDetector(
onTap: () {
setState(() {
selectedCountry = country;
});
widget.onCountryChange?.call(country);
_closeDropdown();
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 16.h),
child: Row(
children: [
Utils.buildSvgWithAssets(icon: country.iconPath, width: 38.h, height: 38.h),
if (!widget.isFromBottomSheet) SizedBox(width: 12.h),
if (!widget.isFromBottomSheet)
Text(appState.getLanguageCode() == "ar" ? country.nameArabic : country.displayName,
style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, letterSpacing: -0.2)),
],
),
),
),
onTap: () {
setState(() {
selectedCountry = country;
});
widget.onCountryChange?.call(country);
_closeDropdown();
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 16.h),
child: Row(
children: [
Utils.buildSvgWithAssets(icon: country.iconPath, width: 38.h, height: 38.h),
if (!widget.isFromBottomSheet) SizedBox(width: 12.h),
if (!widget.isFromBottomSheet)
Text(appState.getLanguageCode() == "ar" ? country.nameArabic : country.displayName,
style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, letterSpacing: -0.2)),
],
),
)),
)
.toList(),
),

@ -223,32 +223,21 @@ class TextInputWidget extends StatelessWidget {
keyboardType: keyboardType,
controller: controller,
readOnly: isReadOnly,
textAlignVertical: TextAlignVertical.top,
textAlignVertical: TextAlignVertical.center,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
onChanged: onChange,
focusNode: focusNode ?? _focusNode,
autofocus: autoFocus,
textInputAction: TextInputAction.done,
cursorHeight: isWalletAmountInput! ? 40.h : 18.h,
style: TextStyle(fontSize: fontSize!.fSize, height: isWalletAmountInput! ? 1 / 4 : 21 / 14, fontWeight: FontWeight.w500, color: AppColors.textColor, letterSpacing: -0.2),
cursorHeight: isWalletAmountInput! ? 40.h : 20.h,
style: TextStyle(fontSize: fontSize!.fSize, height: isWalletAmountInput! ? 1 / 4 : 16 / 14, fontWeight: FontWeight.w500, color: AppColors.textColor, letterSpacing: -1),
decoration: InputDecoration(
isDense: true,
hintText: hintText,
hintStyle: TextStyle(fontSize: 14.fSize, height: 21 / 16, fontWeight: FontWeight.w500, color: Color(0xff898A8D), letterSpacing: -0.2),
prefixIconConstraints: BoxConstraints(minWidth: 45.h),
prefixIcon: prefix == null
? null
: Text(
"+" + prefix!,
style: TextStyle(
fontSize: 14.fSize,
height: 21 / 14,
fontWeight: FontWeight.w500,
color: Color(0xff2E303A),
letterSpacing: -0.2,
),
),
hintStyle: TextStyle(fontSize: 14.fSize, height: 21 / 16, fontWeight: FontWeight.w500, color: Color(0xff898A8D), letterSpacing: -1),
prefixIconConstraints: BoxConstraints(minWidth: 30.h),
prefixIcon: prefix == null ? null : "+${prefix!}".toText14(letterSpacing: -1, color: AppColors.textColor, weight: FontWeight.w500),
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,

Loading…
Cancel
Save