From b951af1eece8214407d654638393520f1c621329 Mon Sep 17 00:00:00 2001 From: pahmiudahgede Date: Sat, 17 May 2025 15:54:38 +0700 Subject: [PATCH] refact: improve counter logic in cart --- .../cart/presentation/cart_screen.dart | 345 ++++++++++-------- lib/widget/button.dart | 0 lib/widget/card_withicon_two.dart | 4 +- lib/widget/counter_dialog.dart | 84 +++++ lib/widget/counter_inpput.dart | 80 ++++ pubspec.lock | 16 +- pubspec.yaml | 2 +- 7 files changed, 376 insertions(+), 155 deletions(-) delete mode 100644 lib/widget/button.dart create mode 100644 lib/widget/counter_dialog.dart create mode 100644 lib/widget/counter_inpput.dart diff --git a/lib/features/cart/presentation/cart_screen.dart b/lib/features/cart/presentation/cart_screen.dart index a6034a4..7366c17 100644 --- a/lib/features/cart/presentation/cart_screen.dart +++ b/lib/features/cart/presentation/cart_screen.dart @@ -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 { + 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"); + }, + ), + ), + ], + ), ), ), ), diff --git a/lib/widget/button.dart b/lib/widget/button.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/widget/card_withicon_two.dart b/lib/widget/card_withicon_two.dart index 0945854..d5d0d0e 100644 --- a/lib/widget/card_withicon_two.dart +++ b/lib/widget/card_withicon_two.dart @@ -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, diff --git a/lib/widget/counter_dialog.dart b/lib/widget/counter_dialog.dart new file mode 100644 index 0000000..9604bbf --- /dev/null +++ b/lib/widget/counter_dialog.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; + +class EditAmountDialog extends StatefulWidget { + final double initialAmount; + final String itemName; + final double pricePerKg; + final ValueChanged 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 { + 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"), + ), + ], + ); + } +} diff --git a/lib/widget/counter_inpput.dart b/lib/widget/counter_inpput.dart new file mode 100644 index 0000000..50ae38e --- /dev/null +++ b/lib/widget/counter_inpput.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +class CounterInput extends StatefulWidget { + final double initialValue; + final ValueChanged onChanged; + + const CounterInput({ + super.key, + this.initialValue = 0, + required this.onChanged, + }); + + @override + CounterInputState createState() => CounterInputState(); +} + +class CounterInputState extends State { + 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, + ), + ], + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index eddb120..1f369d6 100644 --- a/pubspec.lock +++ b/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: diff --git a/pubspec.yaml b/pubspec.yaml index b548dea..ddb0d29 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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