refact: improve counter logic in cart
This commit is contained in:
parent
e1f62103b9
commit
b951af1eec
|
@ -3,6 +3,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|||
import 'package:gap/gap.dart';
|
||||
import 'package:rijig_mobile/core/utils/guide.dart';
|
||||
import 'package:rijig_mobile/widget/buttoncard.dart';
|
||||
import 'package:rijig_mobile/widget/counter_dialog.dart';
|
||||
|
||||
class CartScreen extends StatefulWidget {
|
||||
const CartScreen({super.key});
|
||||
|
@ -12,165 +13,221 @@ class CartScreen extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _CartScreenState extends State<CartScreen> {
|
||||
double totalWeight = 1.0;
|
||||
double pricePerKg = 700;
|
||||
|
||||
void _openEditAmountDialog(String itemName) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return EditAmountDialog(
|
||||
initialAmount: totalWeight,
|
||||
itemName: itemName,
|
||||
pricePerKg: pricePerKg,
|
||||
onSave: (newAmount) {
|
||||
setState(() {
|
||||
totalWeight = newAmount;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _increment() {
|
||||
setState(() {
|
||||
totalWeight += 0.25;
|
||||
});
|
||||
}
|
||||
|
||||
void _decrement() {
|
||||
if (totalWeight > 0.25) {
|
||||
setState(() {
|
||||
totalWeight -= 0.25;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
String formatAmount(double value) {
|
||||
String formattedValue = value.toStringAsFixed(2);
|
||||
|
||||
if (formattedValue.endsWith('.00')) {
|
||||
return formattedValue.split('.').first;
|
||||
}
|
||||
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: whiteColor,
|
||||
appBar: AppBar(
|
||||
title: Text('Keranjang', style: Tulisan.subheading()),
|
||||
backgroundColor: whiteColor,
|
||||
title: Text(
|
||||
'Keranjang Sampah',
|
||||
style: Tulisan.subheading(color: blackNavyColor),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withValues(alpha: 0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 8,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Lokasi Penjemputan',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
child: Padding(
|
||||
padding: PaddingCustom().paddingHorizontal(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withValues(alpha: 0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 8,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
'Lokasi harus di Jember',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
|
||||
Gap(15),
|
||||
CardButtonOne(
|
||||
textButton: "Pilih Alamat",
|
||||
fontSized: 16.sp,
|
||||
color: primaryColor,
|
||||
colorText: whiteColor,
|
||||
borderRadius: 9,
|
||||
horizontal: double.infinity,
|
||||
vertical: 40,
|
||||
onTap: () {
|
||||
debugPrint("lanjutkan tapped");
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 20),
|
||||
|
||||
Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withValues(alpha: 0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 8,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Jenis Sampah',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.delete, color: Colors.blue),
|
||||
SizedBox(width: 8),
|
||||
Text('Plastik', style: TextStyle(fontSize: 14)),
|
||||
Spacer(),
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: Icon(Icons.remove),
|
||||
),
|
||||
Text('4.75 kg'),
|
||||
IconButton(onPressed: () {}, icon: Icon(Icons.add)),
|
||||
],
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Lokasi Penjemputan',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
'Dijumlahkan: 4.75 kg',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
'Lokasi harus di Jember',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
|
||||
Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withValues(alpha: 0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 8,
|
||||
),
|
||||
],
|
||||
Gap(15),
|
||||
CardButtonOne(
|
||||
textButton: "Pilih Alamat",
|
||||
fontSized: 16.sp,
|
||||
color: primaryColor,
|
||||
colorText: whiteColor,
|
||||
borderRadius: 9,
|
||||
horizontal: double.infinity,
|
||||
vertical: 40,
|
||||
onTap: () {
|
||||
debugPrint("pilih alamat tapped");
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Berat Total',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text('4.75 kg', style: TextStyle(fontSize: 18)),
|
||||
],
|
||||
Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withValues(alpha: 0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 8,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Jenis Sampah',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.delete, color: Colors.blue),
|
||||
SizedBox(width: 8),
|
||||
Text('Kertas Campur'),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_openEditAmountDialog('Kertas Campur');
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Text("${formatAmount(totalWeight)} kg"),
|
||||
Icon(Icons.edit, color: Colors.blue),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: _decrement,
|
||||
icon: Icon(Icons.remove),
|
||||
color: Colors.red,
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
IconButton(
|
||||
onPressed: _increment,
|
||||
icon: Icon(Icons.add),
|
||||
color: Colors.green,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
SizedBox(height: 20),
|
||||
|
||||
Center(
|
||||
child: CardButtonOne(
|
||||
textButton: "Lanjutkan",
|
||||
fontSized: 16.sp,
|
||||
color: primaryColor,
|
||||
colorText: whiteColor,
|
||||
borderRadius: 9,
|
||||
horizontal: double.infinity,
|
||||
vertical: 60,
|
||||
onTap: () {
|
||||
debugPrint("lanjutkan tapped");
|
||||
},
|
||||
Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withValues(alpha: 0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 8,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Estimasi Total Berat',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
"${formatAmount(totalWeight)} kg",
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
SizedBox(height: 20),
|
||||
|
||||
Center(
|
||||
child: CardButtonOne(
|
||||
textButton: "Lanjutkan",
|
||||
fontSized: 16.sp,
|
||||
color: primaryColor,
|
||||
colorText: whiteColor,
|
||||
borderRadius: 9,
|
||||
horizontal: double.infinity,
|
||||
vertical: 60,
|
||||
onTap: () {
|
||||
debugPrint("lanjutkan tapped");
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class PaymentItem extends StatelessWidget {
|
||||
class ButtonWIthIcon extends StatelessWidget {
|
||||
final String title;
|
||||
final String? category;
|
||||
final IconData iconData;
|
||||
final String amount;
|
||||
|
||||
const PaymentItem({
|
||||
const ButtonWIthIcon({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.category,
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class EditAmountDialog extends StatefulWidget {
|
||||
final double initialAmount;
|
||||
final String itemName;
|
||||
final double pricePerKg;
|
||||
final ValueChanged<double> onSave;
|
||||
|
||||
const EditAmountDialog({
|
||||
super.key,
|
||||
required this.initialAmount,
|
||||
required this.itemName,
|
||||
required this.pricePerKg,
|
||||
required this.onSave,
|
||||
});
|
||||
|
||||
@override
|
||||
EditAmountDialogState createState() => EditAmountDialogState();
|
||||
}
|
||||
|
||||
class EditAmountDialogState extends State<EditAmountDialog> {
|
||||
late double _currentAmount;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_currentAmount = widget.initialAmount;
|
||||
}
|
||||
|
||||
String formatAmount(double value) {
|
||||
String formattedValue = value.toStringAsFixed(2);
|
||||
|
||||
if (formattedValue.endsWith('.00')) {
|
||||
return formattedValue.split('.').first;
|
||||
}
|
||||
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text("Edit Jumlah ${widget.itemName}"),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
initialValue: formatAmount(_currentAmount),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_currentAmount = double.tryParse(value) ?? 0.0;
|
||||
});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: "Jumlah (kg)",
|
||||
border: OutlineInputBorder(),
|
||||
suffixText: 'kg',
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
|
||||
Text(
|
||||
"Estimasi Harga: Rp ${(widget.pricePerKg * _currentAmount).toStringAsFixed(0)}",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text("Batal"),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
widget.onSave(_currentAmount);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text("Simpan"),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class CounterInput extends StatefulWidget {
|
||||
final double initialValue;
|
||||
final ValueChanged<double> onChanged;
|
||||
|
||||
const CounterInput({
|
||||
super.key,
|
||||
this.initialValue = 0,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
CounterInputState createState() => CounterInputState();
|
||||
}
|
||||
|
||||
class CounterInputState extends State<CounterInput> {
|
||||
late double _value;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_value = widget.initialValue;
|
||||
}
|
||||
|
||||
void _increment() {
|
||||
setState(() {
|
||||
_value += 0.25;
|
||||
});
|
||||
widget.onChanged(_value);
|
||||
}
|
||||
|
||||
void _decrement() {
|
||||
if (_value > 0.25) {
|
||||
setState(() {
|
||||
_value -= 0.25;
|
||||
});
|
||||
widget.onChanged(_value);
|
||||
}
|
||||
}
|
||||
|
||||
void _onChanged(String text) {
|
||||
double? parsedValue = double.tryParse(text);
|
||||
if (parsedValue != null && parsedValue >= 0) {
|
||||
setState(() {
|
||||
_value = parsedValue;
|
||||
});
|
||||
widget.onChanged(_value);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: _decrement,
|
||||
icon: Icon(Icons.remove),
|
||||
color: Colors.red,
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
width: 60,
|
||||
child: TextField(
|
||||
onChanged: _onChanged,
|
||||
controller: TextEditingController(text: _value.toStringAsFixed(2)),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
textAlign: TextAlign.center,
|
||||
decoration: InputDecoration(border: OutlineInputBorder()),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: _increment,
|
||||
icon: Icon(Icons.add),
|
||||
color: Colors.green,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
16
pubspec.lock
16
pubspec.lock
|
@ -121,6 +121,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
custom_refresh_indicator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: custom_refresh_indicator
|
||||
sha256: c34dd1dfb1f6b9ee2db9c5972586dba5e4445d79f8431f6ab098a6e963ccd39c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
dbus:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -821,14 +829,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
wolt_modal_sheet:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: wolt_modal_sheet
|
||||
sha256: "03e28e39dd4de44dc58a7c623877488a89ca3b41a62fc3e70bfc86b64be067d6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -12,6 +12,7 @@ dependencies:
|
|||
concentric_transition: ^1.0.3
|
||||
connectivity_plus: ^6.1.4
|
||||
cupertino_icons: ^1.0.8
|
||||
custom_refresh_indicator: ^4.0.1
|
||||
device_info_plus: ^11.4.0
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
@ -38,7 +39,6 @@ dependencies:
|
|||
smooth_page_indicator: ^1.2.1
|
||||
toastification: ^3.0.2
|
||||
uuid: ^4.5.1
|
||||
wolt_modal_sheet: ^0.11.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^5.0.0
|
||||
|
|
Loading…
Reference in New Issue