Merge pull request #24 from WDI-Ideas/jayeshjain25
delete account ui screen
This commit is contained in:
@@ -52,4 +52,7 @@ class RouteName {
|
||||
|
||||
//language change
|
||||
static const String languageChangeScreen = 'languageChangeScreen';
|
||||
|
||||
//delete Account
|
||||
static const String deleteAccountScreen = 'deleteAccountScreen';
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -80,4 +80,7 @@ class AppColor {
|
||||
|
||||
//Language Color
|
||||
static const Color languageTextColor = Color(0xFF015698);
|
||||
|
||||
//Delete Account Color
|
||||
static const Color descriptionText = Color(0xFFC6C6C6);
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<DeleteAccountEvent, DeleteAccountState> {
|
||||
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
final TextEditingController descriptionTextField = TextEditingController();
|
||||
|
||||
GlobalKey<FormState> getFormKey() {
|
||||
return formKey;
|
||||
}
|
||||
|
||||
DeleteAccountBloc() : super(DeleteAccountInitial()) {
|
||||
descriptionTextField.addListener(_onFormFieldChanged);
|
||||
|
||||
on<DeleteAccountFormChanged>(_onLoginFormChanged);
|
||||
on<DeleteAccountSubmitted>((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<DeleteAccountState> emit) {
|
||||
final areFieldsFilled = event.description.isNotEmpty;
|
||||
emit(DeleteAccountFieldsState(areFieldsFilled));
|
||||
}
|
||||
|
||||
// Method to reset text fields
|
||||
void resetFields() {
|
||||
descriptionTextField.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
descriptionTextField.dispose();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class DeleteAccountEvent extends Equatable {
|
||||
const DeleteAccountEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class DeleteAccountSubmitted extends DeleteAccountEvent {
|
||||
final String description;
|
||||
|
||||
const DeleteAccountSubmitted(
|
||||
this.description,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object> get props => [description];
|
||||
}
|
||||
|
||||
class DeleteAccountFormChanged extends DeleteAccountEvent {
|
||||
final String description;
|
||||
|
||||
const DeleteAccountFormChanged(
|
||||
this.description,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object> get props => [description];
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class DeleteAccountState extends Equatable {
|
||||
const DeleteAccountState();
|
||||
|
||||
@override
|
||||
List<Object> 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<Object> get props => [error];
|
||||
}
|
||||
|
||||
class DeleteAccountFieldsState extends DeleteAccountState {
|
||||
final bool areFieldsFilled;
|
||||
|
||||
const DeleteAccountFieldsState(this.areFieldsFilled);
|
||||
|
||||
@override
|
||||
List<Object> get props => [areFieldsFilled];
|
||||
}
|
||||
16
lib/features/deleteAccount/presentation/bloc/text_bloc.dart
Normal file
16
lib/features/deleteAccount/presentation/bloc/text_bloc.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'text_event.dart';
|
||||
import 'text_state.dart';
|
||||
|
||||
class TextBloc extends Bloc<TextEvent, TextState> {
|
||||
final int maxCharacters;
|
||||
|
||||
TextBloc(this.maxCharacters) : super(TextInitial()) {
|
||||
on<TextChanged>(_onTextChanged);
|
||||
}
|
||||
|
||||
void _onTextChanged(TextChanged event, Emitter<TextState> emit) {
|
||||
final charactersLeft = maxCharacters - event.text.length;
|
||||
emit(TextUpdated(event.text, charactersLeft));
|
||||
}
|
||||
}
|
||||
15
lib/features/deleteAccount/presentation/bloc/text_event.dart
Normal file
15
lib/features/deleteAccount/presentation/bloc/text_event.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class TextEvent extends Equatable {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class TextChanged extends TextEvent {
|
||||
final String text;
|
||||
|
||||
TextChanged(this.text);
|
||||
|
||||
@override
|
||||
List<Object> get props => [text];
|
||||
}
|
||||
18
lib/features/deleteAccount/presentation/bloc/text_state.dart
Normal file
18
lib/features/deleteAccount/presentation/bloc/text_state.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class TextState extends Equatable {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class TextInitial extends TextState {}
|
||||
|
||||
class TextUpdated extends TextState {
|
||||
final String text;
|
||||
final int charactersLeft;
|
||||
|
||||
TextUpdated(this.text, this.charactersLeft);
|
||||
|
||||
@override
|
||||
List<Object> get props => [text, charactersLeft];
|
||||
}
|
||||
@@ -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),
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<DeleteAccountBloc>();
|
||||
|
||||
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<DeleteAccountBloc, DeleteAccountState>(
|
||||
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<CheckboxBloc>().add(ValidateCheckbox());
|
||||
if (context.read<CheckboxBloc>().state is CheckboxChecked) {
|
||||
context.read<DeleteAccountBloc>().add(
|
||||
DeleteAccountSubmitted(
|
||||
context
|
||||
.read<DeleteAccountBloc>()
|
||||
.descriptionTextField
|
||||
.text,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
text: TextWidget().text14W700(AppText.deleteAccountText,
|
||||
clr: AppColor.hintTextColor,
|
||||
textDecoration: TextDecoration.underline));
|
||||
},
|
||||
),
|
||||
const Gap(20),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -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<DeleteAccountBloc>();
|
||||
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<TextBloc, TextState>(
|
||||
builder: (context, state) {
|
||||
return FormLabelTextField(
|
||||
onChangeFun: (p0) {
|
||||
context.read<TextBloc>().add(TextChanged(
|
||||
deleteAccountBloc.descriptionTextField.text,
|
||||
));
|
||||
},
|
||||
hintText: AppText.enterAdescription,
|
||||
textEditingController:
|
||||
deleteAccountBloc.descriptionTextField,
|
||||
title: AppText
|
||||
.toHelpUsImprovePleaseLetusKnowWhyYouWantToDeleteAccount,
|
||||
type: "description",
|
||||
);
|
||||
},
|
||||
),
|
||||
const Gap(8),
|
||||
BlocBuilder<TextBloc, TextState>(
|
||||
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<CheckboxBloc, CheckBoxState>(
|
||||
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();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> {
|
||||
on<LoginFormChanged>(_onLoginFormChanged);
|
||||
on<LoginSubmitted>((event, emit) async {
|
||||
if (!formKey.currentState!.validate()) {
|
||||
emit(
|
||||
const LoginFailure("Login failed. Please check your credentials."));
|
||||
return;
|
||||
}
|
||||
emit(LoginLoading());
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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<CheckboxEvent, CheckBoxState> {
|
||||
CheckboxBloc() : super(CheckboxUnchecked()) {
|
||||
on<ToggleCheckbox>(_onToggleCheckbox);
|
||||
on<ValidateCheckbox>(_onValidateCheckbox);
|
||||
}
|
||||
|
||||
void _onToggleCheckbox(ToggleCheckbox event, Emitter<CheckBoxState> emit) {
|
||||
@@ -15,4 +17,11 @@ class CheckboxBloc extends Bloc<CheckboxEvent, CheckBoxState> {
|
||||
emit(CheckboxUnchecked());
|
||||
}
|
||||
}
|
||||
|
||||
void _onValidateCheckbox(
|
||||
ValidateCheckbox event, Emitter<CheckBoxState> emit) {
|
||||
if (state is! CheckboxChecked) {
|
||||
emit(const CheckboxError(AppText.pleaseCheckThisField));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,5 @@ abstract class CheckboxEvent extends Equatable {
|
||||
}
|
||||
|
||||
class ToggleCheckbox extends CheckboxEvent {}
|
||||
|
||||
class ValidateCheckbox extends CheckboxEvent {}
|
||||
|
||||
@@ -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<Object> get props => [message];
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user