TKK_E32230211/lib/app/widgets/numpad_nominal_widget.dart

173 lines
5.4 KiB
Dart

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