feat: implement product name normalization to Title Case with smart rules

This commit is contained in:
Nils-Johan Gynther
2026-05-01 23:33:33 +02:00
parent e4f1aae047
commit 51e654c592
@@ -86,6 +86,19 @@ String _formatSwedishNumber(double value) {
return _formatCompactNumber(value).replaceAll('.', ',');
}
/// Konverterar VERSALER-produktnamn till Title Case med smarta regler:
/// - Token med `/` (förkortningar) lämnas i versaler: KY/KAL/LE/TO
/// - Token som börjar med siffra (mängd/storlek) görs till gemener: 284g, 12x85g
/// - Övriga token: första bokstav versal, resten gemen: Aprikosmarmelad
String _normalizeProductName(String raw) {
return raw.trim().split(' ').map((token) {
if (token.isEmpty) return token;
if (token.contains('/')) return token;
if (RegExp(r'^\d').hasMatch(token)) return token.toLowerCase();
return token[0].toUpperCase() + token.substring(1).toLowerCase();
}).join(' ');
}
// ── Redigeringstillstånd per rad ─────────────────────────────────────────────
typedef _ItemEdit = ItemEdit;
@@ -153,7 +166,7 @@ class _EditDialogState extends State<_EditDialog> {
text: widget.current.unit ?? widget.item.unit ?? '',
);
_newProductNameCtrl = TextEditingController(
text: widget.current.productName ?? widget.item.rawName,
text: _normalizeProductName(widget.current.productName ?? widget.item.rawName),
);
}
@@ -314,7 +327,11 @@ class _EditDialogState extends State<_EditDialog> {
final aiPath = item.categorySuggestionPath;
final aiLabel = (aiPath != null && aiPath.isNotEmpty)
? aiPath
: ((aiCategory != null && aiCategory.isNotEmpty) ? aiCategory : null);
: ((aiCategory != null && aiCategory.isNotEmpty)
? aiCategory
: (item.suggestedProductName?.isNotEmpty == true
? item.suggestedProductName
: null));
final currentQuantity =
double.tryParse(_quantityCtrl.text.replaceAll(',', '.')) ?? widget.item.quantity;
final currentUnit = _unitCtrl.text.trim().isEmpty ? widget.item.unit : _unitCtrl.text.trim();