import 'package:flutter/material.dart'; import 'package:get/get.dart'; class NumpadNominalWidget extends StatelessWidget { final void Function(String key) onKey; final VoidCallback onSimpan; final TextEditingController displayController; const NumpadNominalWidget({ super.key, required this.onKey, required this.onSimpan, required this.displayController, }); static void show( BuildContext context, { required TextEditingController controller, required void Function(String key) onKey, required VoidCallback onSimpan, }) { showModalBottomSheet( context: context, backgroundColor: Colors.white, isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24)), ), builder: (_) => NumpadNominalWidget( displayController: controller, onKey: onKey, onSimpan: onSimpan, ), ); } String _formatDisplay(String raw) { if (raw.isEmpty) return 'Rp. 0'; return 'Rp. $raw'; } @override Widget build(BuildContext context) { final keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', 'del']; return SingleChildScrollView( padding: EdgeInsets.fromLTRB( 16, 12, 16, MediaQuery.of(context).viewInsets.bottom + 24, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 40, height: 4, margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: Colors.grey.shade300, borderRadius: BorderRadius.circular(2), ), ), ValueListenableBuilder( valueListenable: displayController, builder: (_, value, __) { return Container( width: double.infinity, padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: const Color(0xFFF2F2F2), borderRadius: BorderRadius.circular(12), ), child: RichText( textAlign: TextAlign.center, text: TextSpan( children: [ const TextSpan( text: 'Rp. ', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black87, letterSpacing: 1, ), ), TextSpan( text: value.text.isEmpty ? '0' : value.text, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black87, letterSpacing: 2, ), ), ], ), ), ); }, ), GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: keys.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, mainAxisSpacing: 8, crossAxisSpacing: 8, childAspectRatio: 1.6, ), itemBuilder: (_, i) { final key = keys[i]; return GestureDetector( onTap: () => onKey(key), child: Container( decoration: const BoxDecoration( color: Color(0xFFF2F2F2), shape: BoxShape.circle, ), child: Center( child: key == 'del' ? const Icon( Icons.backspace_outlined, color: Colors.black87, size: 20, ) : Text( key, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.w600, color: Colors.black87, ), ), ), ), ); }, ), const SizedBox(height: 12), GestureDetector( onTap: onSimpan, child: Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 14), decoration: BoxDecoration( color: const Color(0xFF5B9BD5), borderRadius: BorderRadius.circular(12), ), child: const Center( child: Text( 'Simpan', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ), ), ), ), ), ], ), ); } }