proxybuy-flutter/lib/widgets/reserve_bottom_sheet.dart

322 lines
9.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/res/colors.dart';
import 'package:lba/screens/product/checkout.dart';
class ReserveBottomSheet extends StatefulWidget {
const ReserveBottomSheet({super.key});
@override
State<ReserveBottomSheet> createState() => _ReserveBottomSheetState();
}
class _ReserveBottomSheetState extends State<ReserveBottomSheet> {
int _quantity = 1;
final double _pricePerItem = 27.900;
final bool _isHotDeal = false;
void _incrementQuantity() {
if (_isHotDeal) return;
setState(() {
_quantity++;
});
}
void _decrementQuantity() {
if (_quantity <= 1) return;
setState(() {
_quantity--;
});
}
@override
Widget build(BuildContext context) {
final subtotal = _pricePerItem * _quantity;
const salesTax = 0.000;
final total = subtotal + salesTax;
return Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20.0)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40,
height: 4,
margin: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(10),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 234, 247, 238),
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(),
const SizedBox(height: 16),
Divider(color: Colors.grey.shade300, thickness: 1),
const SizedBox(height: 16),
_buildPriceDetails(subtotal, salesTax, total),
const SizedBox(height: 24),
_buildFooter(),
],
),
),
),
],
),
);
}
Widget _buildHeader() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
SvgPicture.asset(Assets.icons.shop.path,
height: 22, color: Colors.grey.shade700),
const SizedBox(width: 10),
const Text(
"Al Rawabi Dairy Company L.L.C",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
],
),
const SizedBox(height: 8),
const Padding(
padding: EdgeInsets.only(left: 4.0),
child: Text(
"Philadelphia Honey Pecan Cream Cheese Spread,\n7.5 oz Tub",
style:
TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
),
),
const SizedBox(height: 6),
const Padding(
padding: EdgeInsets.only(left: 4.0),
child: Text(
"Pickup Now - 10:00 PM Today",
style: TextStyle(fontSize: 13, color: Colors.grey),
),
),
],
);
}
Widget _buildPriceDetails(double subtotal, double salesTax, double total) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Price Details",
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 16),
),
Text(
"$_quantity Item",
style: const TextStyle(fontSize: 14, color: Colors.grey),
),
],
),
const SizedBox(height: 12),
const DashedLine(),
const SizedBox(height: 12),
_priceRow("Subtotal", subtotal.toStringAsFixed(3)),
const SizedBox(height: 10),
_priceRow("Sales tax", salesTax.toStringAsFixed(3)),
const SizedBox(height: 12),
const DashedLine(),
const SizedBox(height: 12),
_priceRow("Total", total.toStringAsFixed(3), isTotal: true),
],
);
}
Widget _buildFooter() {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildQuantitySelector(),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const CheckoutPage(),
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.easeInOut;
final tween = Tween(begin: begin, end: end)
.chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: LightAppColors.offerTimer,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
padding:
const EdgeInsets.symmetric(horizontal: 65, vertical: 10),
),
child: const Text(
'Reserve',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
],
),
if (_isHotDeal) ...[
const SizedBox(height: 16),
_buildWarningMessage(),
]
],
);
}
Widget _priceRow(String label, String amount, {bool isTotal = false}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: TextStyle(
fontSize: 15,
fontWeight: isTotal ? FontWeight.bold : FontWeight.normal,
color: Colors.grey.shade700,
),
),
Text(
"AED $amount",
style: TextStyle(
fontSize: 15,
fontWeight: isTotal ? FontWeight.bold : FontWeight.w500,
color: Colors.black,
),
),
],
);
}
Widget _buildQuantitySelector() {
final bool canDecrement = _quantity > 1;
final bool canIncrement = !_isHotDeal;
return Container(
height: 45,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: [
IconButton(
icon: Icon(Icons.remove,
color: canDecrement ? Colors.red : Colors.grey),
onPressed: _decrementQuantity,
splashRadius: 20,
),
Text(
_quantity.toString(),
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
IconButton(
icon: Icon(Icons.add,
color: canIncrement ? Colors.red : Colors.grey),
onPressed: _incrementQuantity,
splashRadius: 20,
),
],
),
);
}
Widget _buildWarningMessage() {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Icons.error, color: Colors.orangeAccent, size: 20),
const SizedBox(width: 10),
Expanded(
child: RichText(
text: TextSpan(
style: TextStyle(
fontSize: 12.5,
color: Colors.grey.shade800,
fontFamily: 'Roboto'),
children: const [
TextSpan(text: "Due to the "),
TextSpan(
text: "Hot",
style: TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(
text:
" label discount, you can only purchase or reserve one item."),
],
),
),
),
],
);
}
}
class DashedLine extends StatelessWidget {
const DashedLine({super.key, this.height = 1, this.color = Colors.grey});
final double height;
final Color color;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final boxWidth = constraints.constrainWidth();
const dashWidth = 5.0;
final dashHeight = height;
final dashCount = (boxWidth / (2 * dashWidth)).floor();
return Flex(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
direction: Axis.horizontal,
children: List.generate(dashCount, (_) {
return SizedBox(
width: dashWidth,
height: dashHeight,
child: DecoratedBox(
decoration: BoxDecoration(color: color),
),
);
}),
);
},
);
}
}