Files
fin-tracker/app/lib/features/rebalance/weights.dart
T
Dmitry 322c60a359 style(app): остальные экраны под новый визуальный язык и форматирование
Доходы, ребалансировка, налоги, импорт, цели, здоровье данных, правила, транзакции, категории, cashflow, pending: новые виджеты и токены темы, dart format. Тесты подстроены под новые модели.
2026-09-19 22:14:27 +03:00

40 lines
1.5 KiB
Dart

import 'package:decimal/decimal.dart';
/// Weights travel as shares (`"0.60"` = 60 %) and are edited as percents. The conversion is
/// exact on both sides: `Decimal`, never `double`, so 33,33 % round-trips unchanged and a
/// set that sums to exactly 1 does not fail validation because of binary floating point.
final _hundred = Decimal.fromInt(100);
/// `"0.605"` → `"60,5"`; empty for anything unparseable.
String shareToPercentText(String? share) {
final d = share == null ? null : Decimal.tryParse(share);
if (d == null) return '';
final p = d * _hundred;
final text = p == p.truncate() ? p.truncate().toString() : p.toString();
return text.replaceAll('.', ',');
}
/// `"60,5"` → `"0.605"`; null when the text is not a number.
String? percentTextToShare(String text) {
final normalized = text.trim().replaceAll(',', '.').replaceAll(' ', '');
if (normalized.isEmpty) return null;
final d = Decimal.tryParse(normalized);
if (d == null) return null;
return (d / _hundred).toDecimal(scaleOnInfinitePrecision: 10).toString();
}
/// `"0.032"` → `"3,20 %"`, signed. Kept local to the rebalance screen because drift is a
/// share, not a return, and the portfolio helper would sign it the same way by accident.
String formatShareAsPercent(
String? share, {
bool signed = false,
int digits = 2,
}) {
final d = share == null ? null : Decimal.tryParse(share);
if (d == null) return '—';
final p = (d * _hundred).toDouble();
final sign = signed && p > 0 ? '+' : '';
return '$sign${p.toStringAsFixed(digits).replaceAll('.', ',')} %';
}