This commit is contained in:
2025-01-24 19:00:27 +05:30
parent 26aaa8c4e8
commit d9ddf69827
47 changed files with 3291 additions and 108 deletions

View File

@@ -1,6 +1,8 @@
// ignore_for_file: library_private_types_in_public_api
import 'package:flutter/material.dart';
import 'package:grocery_app/src/ui/cart/cartview_screen.dart';
import 'package:grocery_app/src/ui/favourite/favourite_screen.dart';
import 'package:grocery_app/src/ui/home/home_screen.dart';
import 'package:grocery_app/src/ui/profilepage/profile_screen.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
@@ -25,7 +27,8 @@ class _BottomBarState extends State<BottomBarWidget> {
});
if (bottomWidgetPageController.hasClients) {
bottomWidgetPageController.animateToPage(index, duration: const Duration(milliseconds: 100), curve: Curves.ease);
bottomWidgetPageController.animateToPage(index,
duration: const Duration(milliseconds: 100), curve: Curves.ease);
}
}
@@ -47,10 +50,10 @@ class _BottomBarState extends State<BottomBarWidget> {
body: PageView(
controller: bottomWidgetPageController,
physics: const NeverScrollableScrollPhysics(),
children: const <Widget>[
children: <Widget>[
HomeScreen(),
Text('1'),
Text('2'),
FavouriteScreen(),
Mycart(),
ProfileScreen(),
],
),

View File

@@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/svg.dart';
import 'package:grocery_app/src/common_widget/network_image.dart';
import 'package:grocery_app/src/ui/widgets/custom_icon_button.dart';
import 'package:grocery_app/utils/constants/assets_constant.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
import 'package:grocery_app/utils/extensions/uicontext.dart';
class CartItem extends StatelessWidget {
// final ProductModel product;
const CartItem({
Key? key,
// required this.product,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// final theme = context.theme;
return Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
color: Colors.greenAccent.withOpacity(0.1),
borderRadius: BorderRadius.circular(5),
),
child: AppNetworkImage(
width: 50.w,
height: 40.h,
imageUrl:
'https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png',
backGroundColor: APPCOLOR.bgGrey,
radius: 10,
),
),
// Image.asset(product.image, width: 50.w, height: 40.h),
16.horizontalSpace,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Vegitables and Fruits",
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: context.customMedium(APPCOLOR.balck1A1A1A, 14),
),
5.verticalSpace,
Text(
'1kg, 10\$',
style: context.customMedium(APPCOLOR.balck1A1A1A, 14),
),
],
),
const Spacer(),
Row(
children: [
CustomIconButton(
width: 20.w,
height: 20.h,
onPressed: () {},
icon: SvgPicture.asset(
APPASSETS.removeIcon,
fit: BoxFit.none,
),
backgroundColor: APPCOLOR.appGreen,
),
16.horizontalSpace,
Text(
"10",
style: context.customMedium(APPCOLOR.balck1A1A1A, 14),
),
16.horizontalSpace,
CustomIconButton(
width: 20.w,
height: 20.h,
onPressed: () {},
icon: SvgPicture.asset(
APPASSETS.addIcon,
fit: BoxFit.none,
),
backgroundColor: APPCOLOR.appGreen,
),
],
)
],
),
);
}
}

View File

@@ -0,0 +1,244 @@
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/svg.dart';
import 'package:grocery_app/src/common_widget/network_image.dart';
import 'package:grocery_app/src/ui/bestdeal/bestdeal_screen.dart';
import 'package:grocery_app/src/ui/cart/cart_item.dart';
import 'package:grocery_app/src/ui/widgets/custom_icon_button.dart';
import 'package:grocery_app/utils/constants/assets_constant.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
import 'package:grocery_app/utils/extensions/uicontext.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
class Mycart extends StatefulWidget {
const Mycart({super.key});
@override
State<Mycart> createState() => _MycartState();
}
class _MycartState extends State<Mycart> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
// leading: Center(
// child: SizedBox(
// height: 20,
// width: 20,
// child: InkWell(
// onTap: () {
// Navigator.of(context).pop();
// },
// child: SvgPicture.asset(
// APPASSETS.back,
// height: 20,
// width: 20,
// )),
// ),
// ),
title: Center(
child: const Text(
'Cart 🛒',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
),
),
),
// actions: [
// InkWell(
// onTap: () {},
// child: Icon(
// MdiIcons.magnify,
// size: 35,
// ),
// )
// ],
),
body: Column(
children: [
Expanded(
child: ListView.separated(
separatorBuilder: (_, index) => Padding(
padding: EdgeInsets.only(top: 12.h, bottom: 24.h),
child: const Divider(thickness: 1),
),
itemCount: 10,
itemBuilder: (context, index) => CartItem(
//product: controller.products[index],
)
.animate(delay: (100 * index).ms)
.fade()
.slideX(
duration: 300.ms,
begin: -1,
curve: Curves.easeInSine,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Text(
"Best Deal",
style: context.customExtraBold(Colors.black, 18),
),
),
InkWell(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) {
return const BestDealScreen();
},
));
},
child: Text(
"See All",
style: context.customMedium(APPCOLOR.lightGreen, 16),
),
),
],
),
const SizedBox(
height: 15,
),
SizedBox(
height: 222,
child: ListView.builder(
itemCount: 5,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(right: 10, bottom: 5, top: 5),
child: Container(
height: 215,
width: 150,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 1,
offset: const Offset(5, 5),
),
]),
child: Padding(
padding: const EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 100,
width: 150,
decoration: BoxDecoration(
color: APPCOLOR.bgGrey,
borderRadius: BorderRadius.circular(15)),
child: const Stack(
alignment: Alignment.center,
children: [
AppNetworkImage(
height: 70,
width: 70,
imageUrl:
"https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg",
backGroundColor: Colors.transparent),
Positioned(
right: 5,
top: 5,
child: Icon(Icons.favorite_border))
],
),
),
Text(
"Fortune Arhar Dal (Toor Dal)",
textAlign: TextAlign.left,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style:
context.customMedium(APPCOLOR.balck1A1A1A, 14),
),
const SizedBox(
height: 5,
),
Text(
"500 ML",
textAlign: TextAlign.left,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: context.customMedium(
Colors.grey.withOpacity(0.8), 12),
),
const SizedBox(
height: 3,
),
Row(
children: [
Expanded(
child: Row(
children: [
Text(
"\$12",
textAlign: TextAlign.left,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: context.customSemiBold(
Colors.black, 12),
),
const SizedBox(
width: 5,
),
Text(
"\$14",
textAlign: TextAlign.left,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: context
.customMedium(
Colors.grey.withOpacity(0.8), 12)
.copyWith(
decoration:
TextDecoration.lineThrough,
),
),
],
)),
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Container(
height: 30,
width: 50,
decoration: BoxDecoration(
color: APPCOLOR.lightGreen,
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: Text(
'Add',
style: context.customRegular(
Colors.white, 12),
)),
),
),
)
],
),
],
),
),
),
);
},
),
),
],
),
);
}
}

View File

@@ -3,12 +3,14 @@ import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:grocery_app/src/common_widget/textfield_widget.dart';
import 'package:grocery_app/src/core/routes/routes.dart';
import 'package:grocery_app/src/logic/provider/auth_provider.dart';
import 'package:grocery_app/src/ui/bottomnavigation/bottom_bar_widget.dart';
import 'package:grocery_app/utils/constants/assets_constant.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
import 'package:grocery_app/utils/constants/string_constant.dart';
import 'package:grocery_app/utils/extensions/extensions.dart';
import 'package:grocery_app/utils/extensions/uicontext.dart';
import 'package:provider/provider.dart';
class EnterFullNameScreen extends StatefulWidget {
const EnterFullNameScreen({super.key});
@@ -23,6 +25,9 @@ class _EnterFullNameScreenState extends State<EnterFullNameScreen> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
final pageNotifier = Provider.of<AuthProvider>(context, listen: false);
return Scaffold(
body: Container(
width: MediaQuery.sizeOf(context).width,
@@ -53,7 +58,7 @@ class _EnterFullNameScreenState extends State<EnterFullNameScreen> {
child: Column(
children: [
AppTextFieldWidget(
controller: TextEditingController(),
controller: pageNotifier.name,
hintText: APPSTRING.firstNameHint,
onValidate: (value){
if (value == null || value.isEmpty) {
@@ -63,7 +68,7 @@ class _EnterFullNameScreenState extends State<EnterFullNameScreen> {
},
),
AppTextFieldWidget(
controller: TextEditingController(),
controller: pageNotifier.lastName,
hintText: APPSTRING.lastNameHint,
onValidate: (value){
if (value == null || value.isEmpty) {
@@ -72,6 +77,28 @@ class _EnterFullNameScreenState extends State<EnterFullNameScreen> {
return null;
},
),
AppTextFieldWidget(
controller: pageNotifier.email,
hintText: APPSTRING.emailHint,
onValidate: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter eamil-id';
}
return null;
},
),
AppTextFieldWidget(
controller: pageNotifier.address,
hintText: APPSTRING.addressHint,
onValidate: (value) {
if (value == null || value.isEmpty)
{
return 'Please Enter address';
}
return null;
},
),
],
),
)
@@ -88,11 +115,13 @@ class _EnterFullNameScreenState extends State<EnterFullNameScreen> {
padding: context.bodyAllPadding.copyWith(bottom: 20),
child: Center(
child: InkWell(
onTap: () {
onTap: ()
{
if (_formKey.currentState?.validate() ?? false) {
context.clearAndPush( routePath: MyRoutes.BOTTOMNAV);
}
if (_formKey.currentState?.validate() ?? false)
{
context.clearAndPush( routePath: MyRoutes.BOTTOMNAV);
}

View File

@@ -0,0 +1,153 @@
import 'package:flutter/material.dart';
import 'package:grocery_app/src/common_widget/network_image.dart';
import 'package:grocery_app/src/data/product_model.dart';
import 'package:grocery_app/src/ui/widgets/custom_title.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
class FavouriteScreen extends StatefulWidget {
@override
_FavouriteScreenState createState() => _FavouriteScreenState();
}
class _FavouriteScreenState extends State<FavouriteScreen>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _animation;
List<ProductModel> _favProducts = [
ProductModel("", 'Bell pepper red', '7pcs', '\$4.99'),
ProductModel("", 'Ginger', '1kg', '\$4.99'),
ProductModel("", 'Egg pasta', '30gm', '\$15.9'),
];
@override
void initState() {
_animationController = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
super.initState();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
CustomTitle(title: 'Favourite'),
Expanded(
child: ListView.separated(
itemCount: _favProducts.length,
shrinkWrap: true,
padding: const EdgeInsets.all(16),
itemBuilder: (_, index)
{
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _animationController,
curve: Interval(
(0.5 / _favProducts.length) * index,
1,
curve: Curves.easeOut,
),
),
);
_animationController.forward(from: 0);
return AnimatedBuilder(
animation: _animationController,
builder: (_, child) {
return FadeTransition(
opacity: _animation,
child: Transform(
transform: Matrix4.translationValues(
0.0,
50 * (1.0 - _animation.value),
0.0,
),
child: child,
),
);
},
child: ListTile(
onTap: () {},
leading: Container(
decoration: BoxDecoration(
color: Colors.greenAccent.withOpacity(0.1),
borderRadius: BorderRadius.circular(5),
),
child: AppNetworkImage(
height: 80,
width: 80,
imageUrl:
'https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png',
backGroundColor: APPCOLOR.bgGrey,
radius: 10,
),
),
// Image.asset(_favProducts[index].productImage),
title: Text(_favProducts[index].productName),
subtitle: Text(_favProducts[index].quantity),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(_favProducts[index].amount),
Icon(
Icons.navigate_next_rounded,
size: 32,
color: APPCOLOR.gray,
)
],
),
),
);
},
separatorBuilder: (_, index) {
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _animationController,
curve: Interval(
(0.5 / _favProducts.length) * index,
1,
curve: Curves.easeOut,
),
),
);
_animationController.forward(from: 0);
return AnimatedBuilder(
animation: _animationController,
builder: (_, child) {
return FadeTransition(
opacity: _animation,
child: Transform(
transform: Matrix4.translationValues(
0.0,
50 * (1.0 - _animation.value),
0.0,
),
child: child,
),
);
},
child: Divider(),
);
},
),
),
// Padding(
// padding:
// const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 78),
// child: NectarButton(
// onPressed: () {},
// text: 'Add All To Cart',
// ),
// ),
],
);
}
}

View File

@@ -2,10 +2,12 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:grocery_app/src/common_widget/textfield_widget.dart';
import 'package:grocery_app/src/core/routes/routes.dart';
import 'package:grocery_app/src/logic/provider/auth_provider.dart';
import 'package:grocery_app/src/ui/otp/otp_screen.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
import 'package:grocery_app/utils/constants/string_constant.dart';
import 'package:grocery_app/utils/extensions/uicontext.dart';
import 'package:provider/provider.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@@ -15,6 +17,8 @@ class LoginScreen extends StatefulWidget {
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController phoneController = TextEditingController();
String? validatePhoneNumber(String? value) {
if (value == null || value.isEmpty) {
return 'Phone number cannot be empty';
@@ -27,6 +31,8 @@ class _LoginScreenState extends State<LoginScreen> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
final pageNotifier = Provider.of<AuthProvider>(context, listen: false);
return Scaffold(
body: Container(
width: MediaQuery.sizeOf(context).width,
@@ -62,7 +68,7 @@ class _LoginScreenState extends State<LoginScreen> {
key: _formKey,
child: AppTextFieldWidget(
length: 10,
controller: TextEditingController(),
controller: phoneController,
hintText: APPSTRING.phoneNumberHint,
onValidate: (value) => validatePhoneNumber(value),
),
@@ -80,18 +86,26 @@ class _LoginScreenState extends State<LoginScreen> {
padding: context.bodyAllPadding.copyWith(bottom: 20),
child: Center(
child: InkWell(
onTap: () {
print("djkhfjdgf ${_formKey.currentState?.validate()}");
if (_formKey.currentState?.validate() ?? false)
{
context.push(MyRoutes.OTPSCREEN);
onTap: () async {
if (_formKey.currentState?.validate() ?? false) {
final success =
await pageNotifier.sendOtp(phoneController.text, context);
// Navigator.of(context).push(MaterialPageRoute(
// builder: (context)
// {
// return const OtpScreen();
// },
// ));
if (success) {
context.push(MyRoutes.OTPSCREEN);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Failed to send OTP. Please try again."),
),
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Enter a valid 10-digit phone number."),
),
);
}
},
child: Container(

View File

@@ -32,7 +32,8 @@ class _MapScreenState extends State<MapScreen> {
APPASSETS.back,
height: 20,
width: 20,
)),
)
),
),
),
title: const Text(

View File

@@ -25,10 +25,9 @@ class _OnBoardingScreenState extends State<OnBoardingScreen> {
_pageController.nextPage(duration: _kDuration, curve: _kCurve);
}
skipFunction()
{
skipFunction() {
SharedPrefUtils.setFreshInstall(isFresh: false).then(
(value) => context.clearAndPush(routePath: MyRoutes.LOGIN, args: 0),
(value) => context.clearAndPush(routePath: MyRoutes.BOTTOMNAV, args: 0),
);
// Navigator.pushReplacement(context, MaterialPageRoute(
@@ -79,12 +78,12 @@ class _OnBoardingScreenState extends State<OnBoardingScreen> {
children: <Widget>[
Stack(
children: [
Image.asset(APPASSETS.onBoardMan),
Positioned(
top: 10,
top: 20,
right: 0,
child: InkWell(
child: GestureDetector(
onTap: () {
print("djfhgk");
skipFunction();
},
child: Row(
@@ -95,15 +94,14 @@ class _OnBoardingScreenState extends State<OnBoardingScreen> {
style:
context.customMedium(APPCOLOR.appGreen, 14),
),
const SizedBox(
width: 10,
),
const SizedBox(width: 10),
Container(
height: 35,
width: 35,
decoration: BoxDecoration(
color: APPCOLOR.appGreen,
borderRadius: BorderRadius.circular(90)),
color: APPCOLOR.appGreen,
borderRadius: BorderRadius.circular(90),
),
child: const Center(
child: Icon(
Icons.arrow_forward,
@@ -116,7 +114,6 @@ class _OnBoardingScreenState extends State<OnBoardingScreen> {
),
),
),
Image.asset(APPASSETS.onBoardMan),
Positioned(
bottom: 100,
right: 0,

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:grocery_app/src/logic/provider/auth_provider.dart';
import 'package:grocery_app/src/ui/entername/enter_fullname_screen.dart';
import 'package:grocery_app/utils/constants/assets_constant.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
@@ -9,6 +10,7 @@ import 'package:grocery_app/utils/extensions/color_ex.dart';
import 'package:grocery_app/utils/extensions/uicontext.dart';
import 'package:otp_text_field/otp_text_field.dart';
import 'package:otp_text_field/style.dart';
import 'package:provider/provider.dart';
import '../../core/routes/routes.dart';
@@ -20,8 +22,22 @@ class OtpScreen extends StatefulWidget {
}
class _OtpScreenState extends State<OtpScreen> {
String maskNumber(String number) {
// Ensure the input has at least 4 digits to avoid errors
if (number.length < 4) {
throw Exception('Number is too short to mask');
}
// Replace all characters except the last 4 with '*'
String maskedPart = '*' * (number.length - 4);
String visiblePart = number.substring(number.length - 4);
return maskedPart + visiblePart;
}
@override
Widget build(BuildContext context) {
final pageNotifier = Provider.of<AuthProvider>(context, listen: false);
return Scaffold(
body: Container(
width: MediaQuery.sizeOf(context).width,
@@ -49,7 +65,7 @@ class _OtpScreenState extends State<OtpScreen> {
SizedBox(
width: 300,
child: Text(
APPSTRING.enterCode,
"Enter the 6-digit code sent to you at ${maskNumber(pageNotifier.numberwithCode)}",
style: context.customRegular(APPCOLOR.grey666666, 16),
),
),
@@ -57,16 +73,12 @@ class _OtpScreenState extends State<OtpScreen> {
OTPTextField(
length: 6,
onChanged: (c) {
if (c.length == 6)
{
context.push(MyRoutes.FULLNAME);
// Navigator.push(context, MaterialPageRoute(
// builder: (context)
// {
// return const EnterFullNameScreen();
// },
// ));
if (c.length == 6) {
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return const EnterFullNameScreen();
},
));
}
},
width: MediaQuery.of(context).size.width,
@@ -77,7 +89,20 @@ class _OtpScreenState extends State<OtpScreen> {
style: const TextStyle(fontSize: 17),
textFieldAlignment: MainAxisAlignment.spaceBetween,
fieldStyle: FieldStyle.box,
onCompleted: (pin) {},
onCompleted: (pin) async {
final success = await pageNotifier.verifiOtp(pin, context);
if (success) {
context.push(MyRoutes.FULLNAME);
} else {
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// backgroundColor: Colors.grey,
// content: Text("Failed to send OTP. Please try again."),
// ),
// );
}
},
),
const SizedBox(
height: 10,

View File

@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
class CustomIconButton extends StatelessWidget {
final Function()? onPressed;
final Widget? icon;
final Color? backgroundColor;
final Color? borderColor;
final double? width;
final double? height;
const CustomIconButton({
Key? key,
required this.onPressed,
required this.icon,
this.backgroundColor,
this.borderColor,
this.width,
this.height,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: width ?? 44.w,
height: height ?? 44.h,
child: Material(
color: backgroundColor,
shape: borderColor == null
? const CircleBorder()
: CircleBorder(
side: BorderSide(color: borderColor!),
),
child: InkWell(
onTap: onPressed,
child: icon,
highlightColor: Colors.red,
customBorder: const CircleBorder(),
),
),
);
}
}

View File

@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:grocery_app/utils/extensions/uicontext.dart';
class CustomTitle extends StatelessWidget {
final String title;
const CustomTitle({
Key? key,
required this.title,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SafeArea(
bottom: false,
child: Column(
children: [
const SizedBox(height: 8),
Text(
title,
style: context.customExtraBold(Colors.black, 18),
),
const SizedBox(height: 24),
Divider(),
],
),
);
}
}