diff --git a/lib/core/routes/route_name.dart b/lib/core/routes/route_name.dart index b8b5540..bb275bd 100644 --- a/lib/core/routes/route_name.dart +++ b/lib/core/routes/route_name.dart @@ -52,4 +52,7 @@ class RouteName { //language change static const String languageChangeScreen = 'languageChangeScreen'; + + //delete Account + static const String deleteAccountScreen = 'deleteAccountScreen'; } diff --git a/lib/core/routes/routes.dart b/lib/core/routes/routes.dart index 9698747..cbb9df7 100644 --- a/lib/core/routes/routes.dart +++ b/lib/core/routes/routes.dart @@ -10,6 +10,7 @@ import 'package:tanami_app/features/biometric/presentation/pages/biometric_scree import 'package:tanami_app/features/contactAdmin/presentation/pages/contact_admin_screen.dart'; import 'package:tanami_app/features/countrySelection/presentation/pages/choose_country_screen.dart'; +import 'package:tanami_app/features/deleteAccount/presentation/pages/delete_account_screen.dart'; import 'package:tanami_app/features/forgotPassword/presentation/pages/restore_password_screen.dart'; import 'package:tanami_app/features/languageChange/presentation/pages/language_change_screen.dart'; import 'package:tanami_app/features/otpVerification/presentation/pages/otp_screen.dart'; @@ -168,6 +169,13 @@ final goRouter = GoRouter( return const LanguageChaneScreen(); }, ), + GoRoute( + name: RouteName.deleteAccountScreen, + path: RouteName.deleteAccountScreen, + builder: (context, state) { + return const DeleteAccountScreen(); + }, + ), ], ), // GoRoute( diff --git a/lib/core/styles/app_color.dart b/lib/core/styles/app_color.dart index 201e717..8a54af0 100644 --- a/lib/core/styles/app_color.dart +++ b/lib/core/styles/app_color.dart @@ -80,4 +80,7 @@ class AppColor { //Language Color static const Color languageTextColor = Color(0xFF015698); + + //Delete Account Color + static const Color descriptionText = Color(0xFFC6C6C6); } diff --git a/lib/core/styles/app_text.dart b/lib/core/styles/app_text.dart index d6d5870..49e241c 100644 --- a/lib/core/styles/app_text.dart +++ b/lib/core/styles/app_text.dart @@ -162,4 +162,21 @@ class AppText { static const String chooseTheLanguageText = "Choose the language"; static const String changingTheLanguageWillReloadApp = "Changing the language will reload the application"; + + //Delete Screen + static const String weAreSadToSeeYouGo = "We're sad to see you go :("; + static const String enterAdescription = "Enter a description..."; + static const String toHelpUsImprovePleaseLetusKnowWhyYouWantToDeleteAccount = + "To help us improve, please let us know why you want to delete your account"; + static const String charactersLeft = "characters left"; + static const String iUnderstandAndAgreeThatmyDataWillBeDeleted = + "I understand and agree that my data will be deleted"; + static const String noIWantToStay = "No, i want to stay"; + static const String pleaseEnteraDescription = "Please enter a description"; + static const String pleaseCheckThisField = "Please check this field"; + static const String weHaveReceivedYourRequestToDeleteAccount = + "We have received your request to delete your account"; + static const String theRequestWillBeProcessed = + "The request will be processed within 72 hours"; + static const closeText = "Close"; } diff --git a/lib/features/MainScreens/Settings/presentation/widgets/settings_bottom_section.dart b/lib/features/MainScreens/Settings/presentation/widgets/settings_bottom_section.dart index 869f8e0..0ed36b8 100644 --- a/lib/features/MainScreens/Settings/presentation/widgets/settings_bottom_section.dart +++ b/lib/features/MainScreens/Settings/presentation/widgets/settings_bottom_section.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:gap/gap.dart'; +import 'package:tanami_app/core/routes/route_name.dart'; +import 'package:tanami_app/core/routes/routes.dart'; import '../../../../../core/styles/app_color.dart'; import '../../../../../core/styles/app_text.dart'; @@ -24,14 +26,20 @@ class SettingsBottomSection extends StatelessWidget { height: 56.h, child: ButtonWidget().elevatedBtn( txtClr: AppColor.plainWhite, - function: () {}, + function: () { + goRouter.goNamed(RouteName.loginScreen, pathParameters: { + "fromScreen": "registerStep", + }); + }, text: AppText.logoutText, clr: AppColor.primaryColor2, ), ), const Gap(5), ButtonWidget().textBtn( - function: () {}, + function: () { + goRouter.pushNamed(RouteName.deleteAccountScreen); + }, text: TextWidget().text14W700( AppText.deleteAccountText, clr: AppColor.hintTextColor, diff --git a/lib/features/deleteAccount/presentation/bloc/delete_account_bloc.dart b/lib/features/deleteAccount/presentation/bloc/delete_account_bloc.dart new file mode 100644 index 0000000..a8bd515 --- /dev/null +++ b/lib/features/deleteAccount/presentation/bloc/delete_account_bloc.dart @@ -0,0 +1,65 @@ +import 'package:bloc/bloc.dart'; +import 'package:flutter/material.dart'; +import 'package:tanami_app/features/deleteAccount/presentation/bloc/delete_account_event.dart'; +import 'package:tanami_app/features/deleteAccount/presentation/bloc/delete_account_state.dart'; + +class DeleteAccountBloc extends Bloc { + final GlobalKey formKey = GlobalKey(); + final TextEditingController descriptionTextField = TextEditingController(); + + GlobalKey getFormKey() { + return formKey; + } + + DeleteAccountBloc() : super(DeleteAccountInitial()) { + descriptionTextField.addListener(_onFormFieldChanged); + + on(_onLoginFormChanged); + on((event, emit) async { + if (!formKey.currentState!.validate()) { + return; + } + emit(DeleteAccountLoading()); + try { + // Simulate API call + await Future.delayed(const Duration(seconds: 2)); + // Replace the next line with actual API call + final isSuccess = _mockApiCheck(); + if (isSuccess) { + emit(DeleteAccountSuccess()); + } else { + emit(const DeleteAccountFailure("Failed.")); + } + } catch (e) { + emit(DeleteAccountFailure(e.toString())); + } + }); + } + + bool _mockApiCheck() { + return true; + } + + void _onFormFieldChanged() { + add(DeleteAccountFormChanged( + descriptionTextField.text, + )); + } + + void _onLoginFormChanged( + DeleteAccountFormChanged event, Emitter emit) { + final areFieldsFilled = event.description.isNotEmpty; + emit(DeleteAccountFieldsState(areFieldsFilled)); + } + + // Method to reset text fields + void resetFields() { + descriptionTextField.clear(); + } + + @override + Future close() { + descriptionTextField.dispose(); + return super.close(); + } +} diff --git a/lib/features/deleteAccount/presentation/bloc/delete_account_event.dart b/lib/features/deleteAccount/presentation/bloc/delete_account_event.dart new file mode 100644 index 0000000..0db45bf --- /dev/null +++ b/lib/features/deleteAccount/presentation/bloc/delete_account_event.dart @@ -0,0 +1,30 @@ +import 'package:equatable/equatable.dart'; + +abstract class DeleteAccountEvent extends Equatable { + const DeleteAccountEvent(); + + @override + List get props => []; +} + +class DeleteAccountSubmitted extends DeleteAccountEvent { + final String description; + + const DeleteAccountSubmitted( + this.description, + ); + + @override + List get props => [description]; +} + +class DeleteAccountFormChanged extends DeleteAccountEvent { + final String description; + + const DeleteAccountFormChanged( + this.description, + ); + + @override + List get props => [description]; +} diff --git a/lib/features/deleteAccount/presentation/bloc/delete_account_state.dart b/lib/features/deleteAccount/presentation/bloc/delete_account_state.dart new file mode 100644 index 0000000..e4700a3 --- /dev/null +++ b/lib/features/deleteAccount/presentation/bloc/delete_account_state.dart @@ -0,0 +1,32 @@ +import 'package:equatable/equatable.dart'; + +abstract class DeleteAccountState extends Equatable { + const DeleteAccountState(); + + @override + List get props => []; +} + +class DeleteAccountInitial extends DeleteAccountState {} + +class DeleteAccountLoading extends DeleteAccountState {} + +class DeleteAccountSuccess extends DeleteAccountState {} + +class DeleteAccountFailure extends DeleteAccountState { + final String error; + + const DeleteAccountFailure(this.error); + + @override + List get props => [error]; +} + +class DeleteAccountFieldsState extends DeleteAccountState { + final bool areFieldsFilled; + + const DeleteAccountFieldsState(this.areFieldsFilled); + + @override + List get props => [areFieldsFilled]; +} diff --git a/lib/features/deleteAccount/presentation/bloc/text_bloc.dart b/lib/features/deleteAccount/presentation/bloc/text_bloc.dart new file mode 100644 index 0000000..ff759eb --- /dev/null +++ b/lib/features/deleteAccount/presentation/bloc/text_bloc.dart @@ -0,0 +1,16 @@ +import 'package:bloc/bloc.dart'; +import 'text_event.dart'; +import 'text_state.dart'; + +class TextBloc extends Bloc { + final int maxCharacters; + + TextBloc(this.maxCharacters) : super(TextInitial()) { + on(_onTextChanged); + } + + void _onTextChanged(TextChanged event, Emitter emit) { + final charactersLeft = maxCharacters - event.text.length; + emit(TextUpdated(event.text, charactersLeft)); + } +} diff --git a/lib/features/deleteAccount/presentation/bloc/text_event.dart b/lib/features/deleteAccount/presentation/bloc/text_event.dart new file mode 100644 index 0000000..0c8f637 --- /dev/null +++ b/lib/features/deleteAccount/presentation/bloc/text_event.dart @@ -0,0 +1,15 @@ +import 'package:equatable/equatable.dart'; + +abstract class TextEvent extends Equatable { + @override + List get props => []; +} + +class TextChanged extends TextEvent { + final String text; + + TextChanged(this.text); + + @override + List get props => [text]; +} diff --git a/lib/features/deleteAccount/presentation/bloc/text_state.dart b/lib/features/deleteAccount/presentation/bloc/text_state.dart new file mode 100644 index 0000000..1a18af2 --- /dev/null +++ b/lib/features/deleteAccount/presentation/bloc/text_state.dart @@ -0,0 +1,18 @@ +import 'package:equatable/equatable.dart'; + +abstract class TextState extends Equatable { + @override + List get props => []; +} + +class TextInitial extends TextState {} + +class TextUpdated extends TextState { + final String text; + final int charactersLeft; + + TextUpdated(this.text, this.charactersLeft); + + @override + List get props => [text, charactersLeft]; +} diff --git a/lib/features/deleteAccount/presentation/pages/delete_account_layout.dart b/lib/features/deleteAccount/presentation/pages/delete_account_layout.dart new file mode 100644 index 0000000..991896d --- /dev/null +++ b/lib/features/deleteAccount/presentation/pages/delete_account_layout.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/features/deleteAccount/presentation/widgets/top_section.dart'; + +import '../widgets/bottom_section.dart'; +import '../widgets/form_section.dart'; + +class DeleteAccountLayout extends StatelessWidget { + const DeleteAccountLayout({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: true, + body: SingleChildScrollView( + child: Column( + children: [ + const TopSection(), + const FormSection(), + const Gap(30), + bottomSection(context), + ], + ), + )); + } +} diff --git a/lib/features/deleteAccount/presentation/pages/delete_account_screen.dart b/lib/features/deleteAccount/presentation/pages/delete_account_screen.dart new file mode 100644 index 0000000..2975ff0 --- /dev/null +++ b/lib/features/deleteAccount/presentation/pages/delete_account_screen.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:tanami_app/features/deleteAccount/presentation/bloc/text_bloc.dart'; +import 'package:tanami_app/features/deleteAccount/presentation/pages/delete_account_layout.dart'; + +import '../../../../core/styles/app_text.dart'; +import '../../../../shared/components/appbar_widget.dart'; +import '../../../../shared/components/bloc/checkbox/checkbox_bloc.dart'; +import '../bloc/delete_account_bloc.dart'; + +class DeleteAccountScreen extends StatelessWidget { + const DeleteAccountScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const AppBarWidget( + height: 75, + titleTxt: AppText.deleteAccountText, + ), + body: MultiBlocProvider( + providers: [ + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => DeleteAccountBloc(), + ), + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => CheckboxBloc(), + ), + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => TextBloc(350), + ), + ], + child: const DeleteAccountLayout(), + ), + ); + } +} diff --git a/lib/features/deleteAccount/presentation/widgets/bottom_section.dart b/lib/features/deleteAccount/presentation/widgets/bottom_section.dart new file mode 100644 index 0000000..2462071 --- /dev/null +++ b/lib/features/deleteAccount/presentation/widgets/bottom_section.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gap/gap.dart'; + +import '../../../../core/routes/routes.dart'; +import '../../../../core/styles/app_color.dart'; +import '../../../../core/styles/app_text.dart'; +import '../../../../shared/components/bloc/checkbox/checkbox_bloc.dart'; +import '../../../../shared/components/bloc/checkbox/checkbox_event.dart'; +import '../../../../shared/components/bloc/checkbox/checkbox_state.dart'; +import '../../../../shared/components/button_widget.dart'; +import '../../../../shared/components/loader.dart'; +import '../../../../shared/components/text_widget.dart'; +import '../../../../shared/components/toast_message.dart'; +import '../bloc/delete_account_bloc.dart'; +import '../bloc/delete_account_event.dart'; +import '../bloc/delete_account_state.dart'; + +Widget bottomSection(BuildContext context) { + final deleteAccountBloc = context.read(); + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 10, + ), + width: 1.sw, + height: 56.h, + child: ButtonWidget().elevatedBtn( + txtClr: AppColor.plainWhite, + function: () { + goRouter.pop(); + }, + text: AppText.noIWantToStay, + clr: AppColor.primaryColor2, + ), + ), + BlocConsumer( + listener: (context, state) { + if (state is DeleteAccountLoading) { + Loader.loader(context); + } else if (state is DeleteAccountSuccess) { + goRouter.pop(); + } else if (state is DeleteAccountFailure) { + goRouter.pop(); + errorToastMessage( + context, + state.error, + ); + } + }, + builder: (context, state) { + return ButtonWidget().textBtn( + function: () { + if (deleteAccountBloc.formKey.currentState!.validate()) { + context.read().add(ValidateCheckbox()); + if (context.read().state is CheckboxChecked) { + context.read().add( + DeleteAccountSubmitted( + context + .read() + .descriptionTextField + .text, + ), + ); + } + } + }, + text: TextWidget().text14W700(AppText.deleteAccountText, + clr: AppColor.hintTextColor, + textDecoration: TextDecoration.underline)); + }, + ), + const Gap(20), + ], + ); +} diff --git a/lib/features/deleteAccount/presentation/widgets/form_section.dart b/lib/features/deleteAccount/presentation/widgets/form_section.dart new file mode 100644 index 0000000..f803543 --- /dev/null +++ b/lib/features/deleteAccount/presentation/widgets/form_section.dart @@ -0,0 +1,114 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +import '../../../../shared/components/bloc/checkbox/checkbox_bloc.dart'; +import '../../../../shared/components/bloc/checkbox/checkbox_state.dart'; +import '../../../../shared/components/checkbox_widget.dart'; +import '../../../../shared/components/form_label_textfield.dart'; +import '../bloc/delete_account_bloc.dart'; +import '../bloc/text_bloc.dart'; +import '../bloc/text_event.dart'; +import '../bloc/text_state.dart'; + +class FormSection extends StatelessWidget { + const FormSection({super.key}); + + @override + Widget build(BuildContext context) { + final deleteAccountBloc = context.read(); + return Form( + key: deleteAccountBloc.formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 16.0, + right: 16, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Gap(40), + BlocBuilder( + builder: (context, state) { + return FormLabelTextField( + onChangeFun: (p0) { + context.read().add(TextChanged( + deleteAccountBloc.descriptionTextField.text, + )); + }, + hintText: AppText.enterAdescription, + textEditingController: + deleteAccountBloc.descriptionTextField, + title: AppText + .toHelpUsImprovePleaseLetusKnowWhyYouWantToDeleteAccount, + type: "description", + ); + }, + ), + const Gap(8), + BlocBuilder( + builder: (context, state) { + if (state is TextUpdated) { + return TextWidget().text14W400( + "${state.charactersLeft} ${AppText.charactersLeft}", + clr: AppColor.descriptionText); + } + return const Text('350 characters left'); + }, + ), + ], + ), + ), + Stack( + children: [ + SizedBox( + width: 1.sw, + height: 70.h, + ), + const CheckBoxWidget(), + Positioned( + left: 45, + top: 14, + child: SizedBox( + width: 0.75.sw, + child: TextWidget().text14W500( + AppText.iUnderstandAndAgreeThatmyDataWillBeDeleted, + clr: AppColor.charcoalColor, + txtAlign: TextAlign.start, + ), + ), + ), + BlocBuilder( + builder: (context, state) { + if (state is CheckboxError) { + return Positioned( + left: 45, + top: 55, + child: SizedBox( + width: 0.75.sw, + child: TextWidget().text14W500( + AppText.pleaseCheckThisField, + clr: AppColor.txtErrorColor, + txtAlign: TextAlign.start, + ), + ), + ); + } + return const SizedBox.shrink(); + }, + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/features/deleteAccount/presentation/widgets/top_section.dart b/lib/features/deleteAccount/presentation/widgets/top_section.dart new file mode 100644 index 0000000..e89df2d --- /dev/null +++ b/lib/features/deleteAccount/presentation/widgets/top_section.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +class TopSection extends StatelessWidget { + const TopSection({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Gap(85), + Center( + child: SvgPicture.asset( + AppImages.weclomeLogo, + ), + ), + const Gap(30), + TextWidget().text20W700( + AppText.weAreSadToSeeYouGo, + clr: AppColor.charcoalColor, + ), + ], + ); + } +} diff --git a/lib/features/login/presentation/bloc/login_bloc.dart b/lib/features/login/presentation/bloc/login_bloc.dart index 1ae720f..a753d11 100644 --- a/lib/features/login/presentation/bloc/login_bloc.dart +++ b/lib/features/login/presentation/bloc/login_bloc.dart @@ -21,6 +21,8 @@ class LoginBloc extends Bloc { on(_onLoginFormChanged); on((event, emit) async { if (!formKey.currentState!.validate()) { + emit( + const LoginFailure("Login failed. Please check your credentials.")); return; } emit(LoginLoading()); diff --git a/lib/features/welcome/presentation/widgets/login_signup_button.dart b/lib/features/welcome/presentation/widgets/login_signup_button.dart index 6887eb8..7bddd2b 100644 --- a/lib/features/welcome/presentation/widgets/login_signup_button.dart +++ b/lib/features/welcome/presentation/widgets/login_signup_button.dart @@ -15,7 +15,7 @@ class LoginSignUpButton extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric(vertical: 40.0), + padding: const EdgeInsets.symmetric(vertical: 20.0), child: Column( children: [ Container( diff --git a/lib/shared/components/bloc/checkbox/checkbox_bloc.dart b/lib/shared/components/bloc/checkbox/checkbox_bloc.dart index 90e68d4..1f897e8 100644 --- a/lib/shared/components/bloc/checkbox/checkbox_bloc.dart +++ b/lib/shared/components/bloc/checkbox/checkbox_bloc.dart @@ -1,4 +1,5 @@ import 'package:bloc/bloc.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; import 'checkbox_event.dart'; import 'checkbox_state.dart'; @@ -6,6 +7,7 @@ import 'checkbox_state.dart'; class CheckboxBloc extends Bloc { CheckboxBloc() : super(CheckboxUnchecked()) { on(_onToggleCheckbox); + on(_onValidateCheckbox); } void _onToggleCheckbox(ToggleCheckbox event, Emitter emit) { @@ -15,4 +17,11 @@ class CheckboxBloc extends Bloc { emit(CheckboxUnchecked()); } } + + void _onValidateCheckbox( + ValidateCheckbox event, Emitter emit) { + if (state is! CheckboxChecked) { + emit(const CheckboxError(AppText.pleaseCheckThisField)); + } + } } diff --git a/lib/shared/components/bloc/checkbox/checkbox_event.dart b/lib/shared/components/bloc/checkbox/checkbox_event.dart index 346cbbc..f17b4de 100644 --- a/lib/shared/components/bloc/checkbox/checkbox_event.dart +++ b/lib/shared/components/bloc/checkbox/checkbox_event.dart @@ -8,3 +8,5 @@ abstract class CheckboxEvent extends Equatable { } class ToggleCheckbox extends CheckboxEvent {} + +class ValidateCheckbox extends CheckboxEvent {} diff --git a/lib/shared/components/bloc/checkbox/checkbox_state.dart b/lib/shared/components/bloc/checkbox/checkbox_state.dart index a40b36b..c444957 100644 --- a/lib/shared/components/bloc/checkbox/checkbox_state.dart +++ b/lib/shared/components/bloc/checkbox/checkbox_state.dart @@ -10,3 +10,12 @@ abstract class CheckBoxState extends Equatable { class CheckboxUnchecked extends CheckBoxState {} class CheckboxChecked extends CheckBoxState {} + +class CheckboxError extends CheckBoxState { + final String message; + + const CheckboxError(this.message); + + @override + List get props => [message]; +} diff --git a/lib/shared/components/button_widget.dart b/lib/shared/components/button_widget.dart index 29ee744..c40420a 100644 --- a/lib/shared/components/button_widget.dart +++ b/lib/shared/components/button_widget.dart @@ -1,16 +1,32 @@ import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:tanami_app/core/styles/app_color.dart'; import 'package:tanami_app/shared/components/text_widget.dart'; class ButtonWidget { - //Text Button Widget textBtn({ required Widget text, + Color? clr, required VoidCallback function, }) { - return TextButton( - onPressed: function, - child: text, + return InkWell( + onTap: function, + child: Container( + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + shape: RoundedRectangleBorder( + side: const BorderSide(width: 1, color: AppColor.txtBorderColor), + borderRadius: BorderRadius.circular(30), + ), + ), + margin: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 10, + ), + width: 1.sw, + height: 56.h, + child: Center(child: text), + ), ); } diff --git a/lib/shared/components/form_label_textfield.dart b/lib/shared/components/form_label_textfield.dart index 0dd53b7..64c42b2 100644 --- a/lib/shared/components/form_label_textfield.dart +++ b/lib/shared/components/form_label_textfield.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:gap/gap.dart'; import 'package:tanami_app/core/styles/app_color.dart'; import 'package:tanami_app/core/styles/app_text.dart'; @@ -17,12 +18,14 @@ class FormLabelTextField extends StatelessWidget { required this.textEditingController, required this.hintText, this.prefixWidget, + this.onChangeFun, }); final String title; final String type; final String hintText; final TextEditingController textEditingController; final Widget? prefixWidget; + final Function(String)? onChangeFun; @override Widget build(BuildContext context) { @@ -32,6 +35,7 @@ class FormLabelTextField extends StatelessWidget { TextWidget().text14W500( title, clr: AppColor.textLabelColor, + txtAlign: type == "description" ? TextAlign.start : TextAlign.center, ), const Gap(10), type == "password" @@ -39,6 +43,7 @@ class FormLabelTextField extends StatelessWidget { controller: textEditingController, ) : textFormField( + onInput: onChangeFun, validator: (value) { if (type == "phone number") { if (value != null && value.isEmpty) { @@ -50,10 +55,19 @@ class FormLabelTextField extends StatelessWidget { return AppText.chooseCountry; } return null; + } else if (type == "description") { + if (textEditingController.text.isEmpty) { + return AppText.pleaseEnteraDescription; + } + return null; } else { return null; } }, + inputFormatters: [ + LengthLimitingTextInputFormatter(350), + ], + maxlines: type == "description" ? 6 : 1, texttype: type == "phone number" ? TextInputType.phone : TextInputType.name, diff --git a/lib/shared/components/text_from_field_widget.dart b/lib/shared/components/text_from_field_widget.dart index d77f243..2045593 100644 --- a/lib/shared/components/text_from_field_widget.dart +++ b/lib/shared/components/text_from_field_widget.dart @@ -24,13 +24,11 @@ Widget textFormField({ return TextFormField( validator: validator, textAlignVertical: TextAlignVertical.center, - // cursorColor: AppColor.txtBorderShadowColor, + cursorColor: AppColor.primaryColor2, initialValue: value, readOnly: readonly!, onTap: onTap, - enabled: enabled, - enableInteractiveSelection: false, maxLines: maxlines, autovalidateMode: AutovalidateMode.onUserInteraction, controller: textEditingController,