feat(app): экраны импорта отчётов, целей, доходов, ребалансировки, налогов и бенчмарков
Импорт (/imports, /instruments/pending) и фаза 4 (/goals, /income, /rebalance, /tax, аналитика-хаб с benchmarks_card) — по docs/ai/import-contract.md и docs/ai/phase4-contract.md. file_picker для загрузки отчёта.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
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('.', ',')} %';
|
||||
}
|
||||
Reference in New Issue
Block a user