Files
karvon_market/app_code/lib/screens/check_out.dart
jahongireshonqulov 9fbdabafb4 Initial commit
2025-10-17 19:42:02 +05:00

913 lines
34 KiB
Dart

import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/Image_view.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
// import 'package:grostore/custom_ui/loading.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/models/payment_types_response.dart';
import 'package:grostore/models/time_slote_response.dart';
import 'package:grostore/presenters/check_out_presenter.dart';
import 'package:grostore/screens/address/addresses.dart';
// import 'package:grostore/presenters/user_presenter.dart';
// import 'package:grostore/screens/main.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class CheckOut extends StatefulWidget {
const CheckOut({Key? key}) : super(key: key);
@override
State<CheckOut> createState() => _CheckOutState();
}
class _CheckOutState extends State<CheckOut> {
bool pay = false;
String dostavka = '';
@override
void initState() {
Provider.of<CheckOutPresenter>(context, listen: false)
.init(context);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: AppLang.local(context).check_out_ucf, context: context),
body: SingleChildScrollView(
child: Consumer<CheckOutPresenter>(builder: (context, data, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 24),
/// #build shipping address
buildShippingAddress(context, data),
const SizedBox(height: 24),
/// #Billing address
// buildBillingAddress(context, data),
// const SizedBox(
// height: 24
// ),
/// #Build Logistics
if (data.logistics.isNotEmpty)
buildLogistic(context, data)
else
Container(
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: const EdgeInsets.all(8),
decoration: BoxDecorations.shadow(radius: 8).copyWith(color: ThemeConfig.red),
child: Text(AppLang.local(context).we_are_not_shipping_to_your_city_now,style: StyleConfig.fs14cWhitefwNormal,)),
const SizedBox(height: 24),
/// #Prefer Delivery time text
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).preferred_delivery_time,
style: StyleConfig.fs16fwBold,
),
),
/// #Prefer Delivery time
data.isFetchTimeSlot?buildDeliveryTime(context, data):timeSlotShimmer(),
const SizedBox(height: 24),
/// #Personal info
buildPersonalInfo(context,data),
const SizedBox(height: 24),
/// #Payment Method text
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).payment_method,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(height: 10),
/// #Payment Method Button
Container(
height: 100,
decoration: BoxDecorations.shadow(radius: 8),
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding,vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: InkWell(
onTap: (){
pay = !pay;
data.peyMethod("Karta");
},
child: Container(
height: MediaQuery.sizeOf(context).height,
width: MediaQuery.sizeOf(context).width,
padding: EdgeInsets.all(5),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: Border.all(
width: 1.5,
color:pay ?ThemeConfig.red:ThemeConfig.xxlightGrey
)
),
child: Column(
children: [
Icon(Icons.add_card,color:pay?ThemeConfig.red :ThemeConfig.xlightGrey),
Text(AppLang.local(context).when_receiving_by_card,style:pay? StyleConfig.fs12Red :StyleConfig.fs12cGrey,textAlign: TextAlign.center,),
],
),
),
),
),
),
const SizedBox(width: 20),
Expanded(
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: InkWell(
onTap: (){
pay = !pay;
data.peyMethod("Naqd pul");
},
child: Container(
height: MediaQuery.sizeOf(context).height,
width: MediaQuery.sizeOf(context).width,
alignment: Alignment.center,
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: Border.all(
width: 1.5,
color:pay?ThemeConfig.xxlightGrey :ThemeConfig.red
)
),
child: Column(
children: [
Icon(Icons.payments_outlined,color:pay ?ThemeConfig.xxlightGrey :ThemeConfig.red,),
Text(AppLang.local(context).when_receiving_by_cash,style:pay? StyleConfig.fs12cGrey:StyleConfig.fs12Red ,textAlign: TextAlign.center,),
],
),
),
),
),
),
],
),
),
const SizedBox(height: 24),
/// #Tips title
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).add_tips_for_deliveryman,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(
height: 10
),
/// #tips
Container(
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
decoration: BoxDecorations.shadow(radius: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLang.local(context).tips,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 10,
),
TextField(
controller: data.tipsTxt,
keyboardType: TextInputType.phone,
decoration: InputDecorations.phone(hint_text: AppLang.local(context).tips),
),
],
),
),
const SizedBox(height: 24),
/// #Order Summary
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).order_summary,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(
height: 10,
),
Container(
width: getWidth(context),
decoration: BoxDecorations.shadow(radius: 8),
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding14,
vertical: StyleConfig.padding14),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).subtotal} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice(data.orderSummeryResponse.subTotal),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).delivery_fee_ucf} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice("${data.orderSummeryResponse.shippingCharge}"),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).tax} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice(data.orderSummeryResponse.tax),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).coupon_discount_ucf} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice(data.orderSummeryResponse.couponDiscount),
style: StyleConfig.fs14fwNormal,
),
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: DottedLine(
direction: Axis.horizontal,
lineLength: double.infinity,
lineThickness: 1.0,
dashLength: 4.0,
dashColor: ThemeConfig.grey,
//dashGradient: [Colors.red, Colors.blue],
dashRadius: 0.0,
dashGapLength: 4.0,
dashGapColor: Colors.transparent,
//dashGapGradient: [Colors.red, Colors.blue],
dashGapRadius: 0.0,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).total} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice("${data.orderSummeryResponse.total} so'm} "),
style: StyleConfig.fs14fwNormal,
),
],
),
],
),
),
const SizedBox( height: 24 ),
/// #Order contract button
Button(
minWidth: getWidth(context),
color: ThemeConfig.red,
onPressed: (){
data.placeOrder(context);
},
padding: const EdgeInsets.symmetric(vertical: 20),
child: Text(
AppLang.local(context).place_order,
// "Place Order",
style: StyleConfig.fs16cWhitefwBold,
),
)
],
);
}),
),
);
}
// int subster(String text){
// final a = text.substring(0,6);
// final b = a.split(",");
// final c = "${b[0]}${b[1]}";
// print("-----------");
// print("heloH :: $c ::");
// print("-----------");
// final e = int.parse(c);
// return e;
// }
/// #tieslot timer
Widget timeSlotShimmer(){
return Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding,vertical: 5),
child: Column(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecorations.shadow(radius: 8),
child: Shimmers(
height: 40,
width: getWidth(context),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecorations.shadow(radius: 8),
child: Shimmers(
height: 40,
width: getWidth(context),
),
)
],
),
);
}
/// #Delivery Time
Column buildDeliveryTime(BuildContext context, CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 10,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Button(
minWidth: getWidth(context),
onPressed: () {
data.onChangeDeliveryType("regular");
},
child:Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: data.shipping_delivery_type == "regular"
? Border.all(color: ThemeConfig.red, width: 2)
: null),
child: Row(
children: [
Icon(
Icons.local_shipping_outlined,
size: 45,
color: ThemeConfig.grey,
),
const SizedBox(
width: 10,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
AppLang.local(context).reg_delivery,
style: StyleConfig.fs14fwNormal,
),
SizedBox(
width: 200,
child: Text(
AppLang.local(context).we_will_deliver_your_products_soon,
style: StyleConfig.fs14fwNormal,
overflow: TextOverflow.ellipsis,
),
),
],
),
],
),
)
,
),
),
Button(
minWidth: getWidth(context),
onPressed: () {
data.onChangeDeliveryType("scheduled");
setState(() {});
},
child: Container(
margin: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: data.shipping_delivery_type == "scheduled"
? Border.all(color: ThemeConfig.red, width: 2)
: null),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: getWidth(context) * 0.35,
child: Button(
minWidth: getWidth(context) * 0.35,
alignment: Alignment.centerLeft,
child: Text(
DateFormat("d MMM").format(data.selectedDate!),
style: StyleConfig.fs14fwNormal,
),
onPressed: () async {
DateTime date = await chooseDate(data);
data.onChangeDate(date);
data.onChangeDeliveryType("scheduled");
setState(() { });
},
),
),
SizedBox(
width: getWidth(context) * 0.35,
child: Button(
minWidth: getWidth(context),
child: SizedBox(
width: getWidth(context) * 0.35,
child: buildTimeDropDown(data),
),
),
),
],
),
),
),
],
);
}
/// #Date Picker
chooseDate(CheckOutPresenter data) async {
return await showDatePicker(
initialEntryMode: DatePickerEntryMode.calendar,
initialDate: data.selectedDate!,
firstDate: data.firstDate,
lastDate: data.lastDate,
context: context,
);
}
/// #Personal information
Column buildPersonalInfo(BuildContext context,CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).personal_information,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
decoration: BoxDecorations.shadow(radius: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLang.local(context).phone,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 10,
),
TextField(
controller:data.phoneTxt ,
keyboardType: TextInputType.phone,
decoration: InputDecorations.phone(hint_text: "Phone"),
),
const SizedBox(
height: 10,
),
Text(
AppLang.local(context).alternative_phone_ucf,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 10,
),
TextField(
controller: data.additionalPhoneTxt,
keyboardType: TextInputType.phone,
decoration: InputDecorations.phone(
hint_text: AppLang.local(context).alternative_phone_ucf),
),
const SizedBox(
height: 10,
),
Text(
AppLang.local(context).additional_info_ucf,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 10,
),
Container(
padding: const EdgeInsets.all(8),
constraints: const BoxConstraints(minHeight: 80),
width: getWidth(context),
decoration: BoxDecorations.basic().copyWith(
border: Border.all(color: ThemeConfig.grey, width: 1)),
child: TextField(
controller: data.additionalInfoTxt,
decoration: InputDecoration.collapsed(
hintText: AppLang.local(context).additional_info_ucf),
),
)
],
),
),
],
);
}
/// #build shipping address
Column buildShippingAddress(BuildContext context, CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppLang.local(context).delivery_address_ucf,
style: StyleConfig.fs16fwBold,
),
Material(
clipBehavior: Clip.antiAlias,
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: InkWell(
onTap: (){
MakeRoute.go(context, const Addresses());
},
child: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: Border.all(
width: 1,
color: ThemeConfig.red,
)
),
child: const Text("Manzil qo'shish"),
),
),
)
],
),
),
SizedBox(
//color: Colors.red,
height: 150,
width: getWidth(context),
child: data.isFetchDeliveryAddress?ListView.separated(
itemCount: data.addresses.length,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: Border.all(
width: 2,
color:
data.selectedShippingAddress.id == data.addresses[index].id
? ThemeConfig.red
: ThemeConfig.grey)),
child: Button(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
shape: StyleConfig.buttonRadius(8),
minWidth: getWidth(context) * 0.5,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.addresses[index].countryName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].stateName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].cityName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].address,
style: StyleConfig.fs14fwNormal,
maxLines: 1,
),
],
),
onPressed: () {
data.onChangeShippingAddress(data.addresses[index]);
},
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 10,
);
},
):Shimmers.horizontalList(10, getWidth(context) * 0.5, 100),
)
],
);
}
/// #Build billing address
Column buildBillingAddress(BuildContext context, CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).billing_address_ucf,
style: StyleConfig.fs16fwBold,
),
),
SizedBox(
//color: Colors.red,
height: 150,
width: getWidth(context),
child: data.isFetchDeliveryAddress?ListView.separated(
itemCount: data.addresses.length,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: Border.all(
width: 2,
color: data.billingAddressId == data.addresses[index].id
? ThemeConfig.red
: ThemeConfig.grey)),
child: Button(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
shape: StyleConfig.buttonRadius(8),
minWidth: getWidth(context) * 0.5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
data.addresses[index].countryName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].stateName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].cityName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].address,
style: StyleConfig.fs14fwNormal,
),
],
),
onPressed: () {
data.onChangeBillingAddress(data.addresses[index].id);
},
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 10,
);
},
):Shimmers.horizontalList(10, getWidth(context) * 0.5, 100),
),
],
);
}
/// #Build logistics
Column buildLogistic(BuildContext context, CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).available_logistics_ucf,
style: StyleConfig.fs16fwBold,
),
),
SizedBox(
//color: Colors.red,
height: 150,
width: getWidth(context),
child:ListView.separated(
itemCount: data.logistics.length,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: Border.all(
width: 2,
color:
data.selectedLogistic.id == data.logistics[index].id
? ThemeConfig.red
: ThemeConfig.grey)),
child: Button(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
shape: StyleConfig.buttonRadius(8),
minWidth: getWidth(context) * 0.5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
data.logistics[index].name,
style: StyleConfig.fs14fwNormal,
),
ImageView(
url: data.logistics[index].image,
height: 40,
width: getWidth(context) * 0.4,
),
Text(
showPrice(data.logistics[index].price),
style: StyleConfig.fs12,
),
],
),
onPressed: () {
data.onChangeLogistic(data.logistics[index]);
},
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 10,
);
},
),
),
],
);
}
/// #Build time dropdown
Widget buildTimeDropDown(CheckOutPresenter data) {
return DropdownButton<TimeSlot>(
menuMaxHeight: 300,
isDense: true,
underline: Container(),
isExpanded: true,
onChanged: (TimeSlot? value) {
data.onChangeTimeSlot(value!);
},
icon: const Icon(Icons.arrow_drop_down),
value: data.selectedTimeslot,
items: data.timeSlots
.map(
(value) => DropdownMenuItem<TimeSlot>(
value: value,
child: Text(
value.timeline,
),
),
)
.toList(),
);
}
/// #Payment Method
Future<PaymentTypesResponse?> showPaymentMethods(CheckOutPresenter data)async{
return showDialog<PaymentTypesResponse>(context: context, builder: (context){
return AlertDialog(
titlePadding: EdgeInsets.zero,
title: Container(
alignment: Alignment.center,
color: ThemeConfig.accentColor,
padding: const EdgeInsets.symmetric(horizontal: 14,vertical: 24),
child: Text("Choose Payment Method",style: StyleConfig.fs16cWhitefwBold,),
),
content:Column(
children: List.generate(data.paymentTypes.length, (index) {
return Column(
children: [
Button(
minWidth: getWidth(context),
onPressed: (){
Navigator.pop(context,data.paymentTypes[index]);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: getWidth(context)*0.3,
child: Text(data.paymentTypes[index].name,style: StyleConfig.fs14fwBold,)),
Container(
width: getWidth(context)*0.3,
padding: const EdgeInsets.all(8),
child: ImageView.svg(url: data.paymentTypes[index].image,height:50,width: 50),
),
],
))
],
);
}),
) ,
actions: [
Button(
minWidth:getWidth(context),
padding: const EdgeInsets.symmetric(vertical: 20),
color: ThemeConfig.red,
onPressed: (){
Navigator.pop(context);
},
child: Text("Close",style: StyleConfig.fs14cWhitefwNormal,),
)
],
);
});
}
}