refact: improve counter logic in cart

This commit is contained in:
pahmiudahgede 2025-05-17 15:54:38 +07:00
parent e1f62103b9
commit b951af1eec
7 changed files with 376 additions and 155 deletions

View File

@ -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");
},
),
),
],
),
),
),
),

View File

View File

@ -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,

View File

@ -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"),
),
],
);
}
}

View File

@ -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,
),
],
);
}
}

View File

@ -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:

View File

@ -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