62 lines
2.1 KiB
Dart
62 lines
2.1 KiB
Dart
import 'package:flutter/services.dart';
|
|
|
|
String formatWithThousands(dynamic value, {int? decimalPlaces}) {
|
|
if (value == null) return '-';
|
|
num? n;
|
|
if (value is num) {
|
|
n = value;
|
|
} else if (value is String) {
|
|
n = num.tryParse(value);
|
|
}
|
|
if (n == null) return value.toString();
|
|
|
|
// Determine effective decimal digits
|
|
int effectiveDecimalDigits = decimalPlaces ?? (n is int ? 0 : 2);
|
|
if (decimalPlaces != null && decimalPlaces > 0) {
|
|
final fixed = n.toStringAsFixed(decimalPlaces);
|
|
final parts = fixed.split('.');
|
|
if (parts.length == 2) {
|
|
final fractional = parts[1];
|
|
final isAllZeros = fractional.replaceAll('0', '').isEmpty;
|
|
if (isAllZeros) {
|
|
effectiveDecimalDigits = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
final parts = n.toStringAsFixed(effectiveDecimalDigits).split('.');
|
|
final intPart = parts[0];
|
|
final decPart = parts.length > 1 ? parts[1] : null;
|
|
final reg = RegExp(r'\B(?=(\d{3})+(?!\d))');
|
|
final grouped = intPart.replaceAllMapped(reg, (m) => ',');
|
|
return decPart == null || decPart.isEmpty ? grouped : '$grouped.$decPart';
|
|
}
|
|
|
|
class ThousandsSeparatorInputFormatter extends TextInputFormatter {
|
|
@override
|
|
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
|
final text = newValue.text;
|
|
if (text.isEmpty) return newValue;
|
|
final selectionIndexFromTheRight = text.length - newValue.selection.end;
|
|
String cleaned = text.replaceAll(',', '');
|
|
// Keep decimal part
|
|
String integerPart = cleaned;
|
|
String decimalPart = '';
|
|
final dotIndex = cleaned.indexOf('.');
|
|
if (dotIndex >= 0) {
|
|
integerPart = cleaned.substring(0, dotIndex);
|
|
decimalPart = cleaned.substring(dotIndex); // includes '.'
|
|
}
|
|
final reg = RegExp(r'\B(?=(\d{3})+(?!\d))');
|
|
final formattedInt = integerPart.replaceAllMapped(reg, (m) => ',');
|
|
final formatted = formattedInt + decimalPart;
|
|
final newSelectionIndex = formatted.length - selectionIndexFromTheRight;
|
|
return TextEditingValue(
|
|
text: formatted,
|
|
selection: TextSelection.collapsed(offset: newSelectionIndex.clamp(0, formatted.length)),
|
|
);
|
|
}
|
|
}
|
|
|
|
|