import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'numpad_nominal_widget.dart'; import 'target_celengan_picker.dart'; class EditTargetModal extends StatefulWidget { final TextEditingController nominalController; final TextEditingController targetController; final VoidCallback onSimpan; final void Function(String key) onNominalKey; const EditTargetModal({ super.key, required this.nominalController, required this.targetController, required this.onSimpan, required this.onNominalKey, }); static void show( BuildContext context, { required TextEditingController nominalController, required TextEditingController targetController, required VoidCallback onSimpan, required void Function(String key) onNominalKey, }) { showModalBottomSheet( context: context, backgroundColor: Colors.white, isScrollControlled: true, isDismissible: false, enableDrag: false, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24)), ), builder: (_) => EditTargetModal( nominalController: nominalController, targetController: targetController, onSimpan: onSimpan, onNominalKey: onNominalKey, ), ); } @override State createState() => _EditTargetModalState(); } class _EditTargetModalState extends State { bool _showPicker = false; bool get _isFormValid => widget.targetController.text.isNotEmpty && widget.nominalController.text.isNotEmpty && widget.nominalController.text != '0'; @override void initState() { super.initState(); widget.targetController.addListener(_onFieldChanged); widget.nominalController.addListener(_onFieldChanged); } void _onFieldChanged() => setState(() {}); @override void dispose() { widget.targetController.removeListener(_onFieldChanged); widget.nominalController.removeListener(_onFieldChanged); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedSize( duration: const Duration(milliseconds: 250), curve: Curves.easeInOut, child: Padding( padding: EdgeInsets.fromLTRB( 24, 16, 24, MediaQuery.of(context).viewInsets.bottom + 32, ), child: _showPicker ? _buildPicker() : _buildForm(), ), ); } Widget _buildForm() { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Drag handle Center( child: Container( width: 40, height: 4, margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: Colors.grey.shade300, borderRadius: BorderRadius.circular(2), ), ), ), // Header kontekstual Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16), margin: const EdgeInsets.only(bottom: 24), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF5B9BD5), Color(0xFF7BB8F0)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( '🎉 Target Tercapai!', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), SizedBox(height: 4), Text( 'Selamat, tabunganmu berhasil! Yuk, set target baru untuk mulai menabung lagi.', style: TextStyle( fontSize: 13, color: Colors.white70, height: 1.4, ), ), ], ), ), const Text( 'Target Celengan', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: Colors.black54, ), ), const SizedBox(height: 8), _buildTapField( controller: widget.targetController, hint: 'Pilih target celengan', icon: Icons.savings_outlined, suffixIcon: const Icon( Icons.keyboard_arrow_down_rounded, color: Colors.grey, ), onTap: () => setState(() => _showPicker = true), ), const SizedBox(height: 16), const Text( 'Nominal Target', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: Colors.black54, ), ), const SizedBox(height: 8), _buildTapField( controller: widget.nominalController, hint: 'Masukkan nominal target', icon: Icons.attach_money_outlined, onTap: () => NumpadNominalWidget.show( context, controller: widget.nominalController, onKey: widget.onNominalKey, onSimpan: () => Get.back(), ), ), const SizedBox(height: 28), // Tombol Simpan — disabled kalau form belum lengkap GestureDetector( onTap: _isFormValid ? widget.onSimpan : null, child: AnimatedContainer( duration: const Duration(milliseconds: 200), width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( color: _isFormValid ? const Color(0xFF5B9BD5) : Colors.grey.shade300, borderRadius: BorderRadius.circular(12), ), child: Center( child: Text( 'Simpan Target Baru', style: TextStyle( color: _isFormValid ? Colors.white : Colors.grey.shade500, fontWeight: FontWeight.bold, fontSize: 16, ), ), ), ), ), ], ); } Widget _buildPicker() { return Column( mainAxisSize: MainAxisSize.min, children: [ Row( children: [ GestureDetector( onTap: () => setState(() => _showPicker = false), child: const Icon( Icons.arrow_back_ios_new_rounded, size: 18, color: Colors.black87, ), ), const SizedBox(width: 12), const Text( 'Pilih Target Celengan', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ], ), const SizedBox(height: 4), const Padding( padding: EdgeInsets.only(left: 30), child: Align( alignment: Alignment.centerLeft, child: Text( 'Pilih tujuan tabunganmu', style: TextStyle(fontSize: 13, color: Colors.grey), ), ), ), const SizedBox(height: 16), TargetCelenganPicker( selected: widget.targetController.text.isEmpty ? null : widget.targetController.text, onSelected: (label) { widget.targetController.text = label; setState(() => _showPicker = false); }, hideHeader: true, ), ], ); } Widget _buildTapField({ required TextEditingController controller, required String hint, required IconData icon, Widget? suffixIcon, required VoidCallback onTap, }) { return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), decoration: BoxDecoration( color: const Color(0xFFF2F2F2), borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Icon(icon, color: Colors.grey, size: 20), const SizedBox(width: 12), Expanded( child: ValueListenableBuilder( valueListenable: controller, builder: (_, value, __) { return Text( value.text.isEmpty ? hint : value.text, style: TextStyle( fontSize: 14, color: value.text.isEmpty ? Colors.grey : Colors.black87, ), ); }, ), ), if (suffixIcon != null) suffixIcon, ], ), ), ); } }