style(app): остальные экраны под новый визуальный язык и форматирование

Доходы, ребалансировка, налоги, импорт, цели, здоровье данных, правила, транзакции, категории, cashflow, pending: новые виджеты и токены темы, dart format. Тесты подстроены под новые модели.
This commit is contained in:
Dmitry
2026-09-19 22:14:27 +03:00
parent 62d36aa3e8
commit 322c60a359
55 changed files with 2158 additions and 1080 deletions
+41 -16
View File
@@ -50,7 +50,9 @@ class IncomeForecastTab extends ConsumerWidget {
StatTile(
label: 'Доходность к стоимости',
// null means "нет оценки стоимости" and must not read as 0 %
value: Text(formatPercent(data.annualYieldOnValue, signed: false)),
value: Text(
formatPercent(data.annualYieldOnValue, signed: false),
),
note: data.annualYieldOnValue == null
? 'нет оценки текущей стоимости'
: 'ожидаемый доход / стоимость портфеля',
@@ -58,7 +60,10 @@ class IncomeForecastTab extends ConsumerWidget {
for (final b in bases)
StatTile(
label: 'Основание: ${basisLabel(b)}',
value: MoneyText(_basisTotal(data, b).toString(), currency: 'RUB'),
value: MoneyText(
_basisTotal(data, b).toString(),
currency: 'RUB',
),
note: basisDescription(b),
width: 220,
),
@@ -91,8 +96,14 @@ class IncomeForecastTab extends ConsumerWidget {
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: (data.months.length * 52).toDouble().clamp(320, double.infinity),
child: _ForecastChart(months: data.months, bases: bases),
width: (data.months.length * 52).toDouble().clamp(
320,
double.infinity,
),
child: _ForecastChart(
months: data.months,
bases: bases,
),
),
),
),
@@ -130,7 +141,8 @@ class _HorizonChips extends ConsumerWidget {
ChoiceChip(
label: Text('$m мес'),
selected: months == m,
onSelected: (_) => ref.read(forecastMonthsProvider.notifier).state = m,
onSelected: (_) =>
ref.read(forecastMonthsProvider.notifier).state = m,
),
],
);
@@ -191,10 +203,16 @@ class _BasisLegend extends StatelessWidget {
Container(
width: 10,
height: 10,
decoration: BoxDecoration(color: basisColor(b), shape: BoxShape.circle),
decoration: BoxDecoration(
color: basisColor(b),
shape: BoxShape.circle,
),
),
const SizedBox(width: 6),
Text(basisLabel(b), style: Theme.of(context).textTheme.bodySmall),
Text(
basisLabel(b),
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
@@ -235,7 +253,8 @@ class _ForecastChart extends StatelessWidget {
getTitlesWidget: (value, meta) {
final i = value.round();
if (i < 0 || i >= months.length) return const SizedBox.shrink();
if (months.length > 14 && i.isOdd) return const SizedBox.shrink();
if (months.length > 14 && i.isOdd)
return const SizedBox.shrink();
final m = months[i].month;
return Text(
m == null ? '' : ruMonthYearShort(m),
@@ -251,7 +270,8 @@ class _ForecastChart extends StatelessWidget {
final m = months[group.x];
final parts = [
for (final b in bases)
if ((Decimal.tryParse(m.byBasis[b] ?? '0') ?? Decimal.zero) > Decimal.zero)
if ((Decimal.tryParse(m.byBasis[b] ?? '0') ?? Decimal.zero) >
Decimal.zero)
'${basisLabel(b)}: ${MoneyText.format(m.byBasis[b]!, 'RUB')}',
];
return BarTooltipItem(
@@ -277,7 +297,8 @@ class _ForecastChart extends StatelessWidget {
final stack = <BarChartRodStackItem>[];
var from = 0.0;
for (final b in bases) {
final v = (Decimal.tryParse(m.byBasis[b] ?? '0') ?? Decimal.zero).toDouble();
final v = (Decimal.tryParse(m.byBasis[b] ?? '0') ?? Decimal.zero)
.toDouble();
if (v <= 0) continue;
stack.add(BarChartRodStackItem(from, from + v, basisColor(b)));
from += v;
@@ -321,14 +342,18 @@ class _ForecastTable extends StatelessWidget {
for (final m in months)
DataRow(
cells: [
DataCell(Text(m.month == null ? '' : ruMonthYearShort(m.month!))),
DataCell(
Text(m.month == null ? '' : ruMonthYearShort(m.month!)),
),
for (final b in bases)
DataCell(MoneyText(m.byBasis[b] ?? '0', currency: 'RUB')),
DataCell(MoneyText(
m.amountRub,
currency: 'RUB',
style: Theme.of(context).textTheme.titleSmall,
)),
DataCell(
MoneyText(
m.amountRub,
currency: 'RUB',
style: Theme.of(context).textTheme.titleSmall,
),
),
],
),
],