322 lines
9.5 KiB
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),
|
|
),
|
|
);
|
|
}),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
} |