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
+136 -56
View File
@@ -1,4 +1,7 @@
import 'package:flutter/material.dart';
import '../../core/widgets/help_tip.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
@@ -67,9 +70,12 @@ class _TaxLotsTabState extends ConsumerState<TaxLotsTab> {
color: Theme.of(context).colorScheme.tertiaryContainer,
child: ListTile(
leading: const Icon(Icons.schedule),
title: Text('До ЛДВ меньше полугода: ${near.length} лот(ов)'),
title: Text(
'До ЛДВ меньше полугода: ${near.length} лот(ов)',
),
subtitle: const Text(
'Продажа до этой даты облагается налогом на весь прирост.'),
'Продажа до этой даты облагается налогом на весь прирост.',
),
trailing: FilterChip(
label: const Text('только они'),
selected: _onlyNearLdv,
@@ -80,7 +86,8 @@ class _TaxLotsTabState extends ConsumerState<TaxLotsTab> {
const SizedBox(height: 12),
SectionCard(
title: 'Открытые лоты',
subtitle: 'налог при продаже сегодня — оценка по ставке из сводки',
subtitle:
'налог при продаже сегодня — оценка по ставке из сводки',
child: _LotsTable(rows: rows),
),
],
@@ -104,71 +111,144 @@ class _LotsTable extends StatelessWidget {
scrollDirection: Axis.horizontal,
child: DataTable(
columns: [
DataColumn(label: Text('Бумага', style: headerStyle)),
DataColumn(label: Text('Куплен', style: headerStyle)),
DataColumn(label: Text('Кол-во', style: headerStyle), numeric: true),
DataColumn(label: Text('Стоимость', style: headerStyle), numeric: true),
DataColumn(label: Text('Рынок', style: headerStyle), numeric: true),
DataColumn(label: Text('Нереализ.', style: headerStyle), numeric: true),
DataColumn(label: Text('Дата ЛДВ', style: headerStyle)),
DataColumn(label: Text('Дней до ЛДВ', style: headerStyle), numeric: true),
DataColumn(label: Text('Налог при продаже', style: headerStyle), numeric: true),
DataColumn(label: TermLabel('Бумага', style: headerStyle)),
DataColumn(label: TermLabel('Куплен', style: headerStyle)),
DataColumn(
label: TermLabel(
'Кол-во',
style: headerStyle,
alignment: MainAxisAlignment.end,
),
numeric: true,
),
DataColumn(
label: TermLabel(
'Стоимость',
style: headerStyle,
alignment: MainAxisAlignment.end,
),
numeric: true,
),
DataColumn(
label: TermLabel(
'Рынок',
style: headerStyle,
alignment: MainAxisAlignment.end,
),
numeric: true,
),
DataColumn(
label: TermLabel(
'Нереализ.',
style: headerStyle,
alignment: MainAxisAlignment.end,
),
numeric: true,
),
DataColumn(label: TermLabel('Дата ЛДВ', style: headerStyle)),
DataColumn(
label: TermLabel(
'Дней до ЛДВ',
style: headerStyle,
alignment: MainAxisAlignment.end,
),
numeric: true,
),
DataColumn(
label: TermLabel(
'Налог при продаже',
style: headerStyle,
alignment: MainAxisAlignment.end,
),
numeric: true,
),
],
rows: [
for (final l in rows)
DataRow(
color: l.nearLdv
? WidgetStatePropertyAll(
theme.colorScheme.tertiaryContainer.withValues(alpha: 0.5))
theme.colorScheme.tertiaryContainer.withValues(
alpha: 0.5,
),
)
: null,
onSelectChanged: l.instrumentId == null
? null
: (_) => context.push('/portfolio/instrument/${l.instrumentId}'),
: (_) =>
context.push('/portfolio/instrument/${l.instrumentId}'),
cells: [
DataCell(Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(l.title),
if (l.nearLdv) ...[
const SizedBox(width: 6),
Tooltip(
message: 'До ЛДВ осталось ${l.daysToLdv} дн. — '
'продажа сейчас облагается налогом полностью',
child: Icon(Icons.schedule, size: 16, color: theme.colorScheme.error),
),
DataCell(
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(l.title),
if (l.nearLdv) ...[
const SizedBox(width: 6),
Tooltip(
message:
'До ЛДВ осталось ${l.daysToLdv} дн. — '
'продажа сейчас облагается налогом полностью',
child: Icon(
Icons.schedule,
size: 16,
color: theme.colorScheme.error,
),
),
],
],
],
)),
),
),
DataCell(Text(l.openDate == null ? '' : ruDate(l.openDate!))),
DataCell(Text(l.qtyRemaining == null ? '' : formatQty(l.qtyRemaining!))),
DataCell(l.costRub == null
? const Text('')
: MoneyText(l.costRub!, currency: 'RUB')),
DataCell(l.marketValueRub == null
? const Text('')
: MoneyText(l.marketValueRub!, currency: 'RUB')),
DataCell(l.unrealizedGainRub == null
? const Text('')
: MoneyText(
l.unrealizedGainRub!,
currency: 'RUB',
style: TextStyle(color: signColor(context, l.unrealizedGainRub)),
)),
DataCell(l.ldvEligible
? const Text('уже действует')
: Text(l.ldvDate == null ? '' : ruDate(l.ldvDate!))),
DataCell(l.ldvEligible
? const Text('')
: Text(
l.daysToLdv == null ? '' : '${l.daysToLdv}',
style: l.nearLdv
? TextStyle(
color: theme.colorScheme.error, fontWeight: FontWeight.w600)
: null,
)),
DataCell(l.taxIfSoldNowRub == null
? const Text('')
: MoneyText(l.taxIfSoldNowRub!, currency: 'RUB')),
DataCell(
Text(
l.qtyRemaining == null ? '' : formatQty(l.qtyRemaining!),
),
),
DataCell(
l.costRub == null
? const Text('')
: MoneyText(l.costRub!, currency: 'RUB'),
),
DataCell(
l.marketValueRub == null
? const Text('')
: MoneyText(l.marketValueRub!, currency: 'RUB'),
),
DataCell(
l.unrealizedGainRub == null
? const Text('')
: MoneyText(
l.unrealizedGainRub!,
currency: 'RUB',
style: TextStyle(
color: signColor(context, l.unrealizedGainRub),
),
),
),
DataCell(
l.ldvEligible
? const Text('уже действует')
: Text(l.ldvDate == null ? '' : ruDate(l.ldvDate!)),
),
DataCell(
l.ldvEligible
? const Text('')
: Text(
l.daysToLdv == null ? '' : '${l.daysToLdv}',
style: l.nearLdv
? TextStyle(
color: theme.colorScheme.error,
fontWeight: FontWeight.w600,
)
: null,
),
),
DataCell(
l.taxIfSoldNowRub == null
? const Text('')
: MoneyText(l.taxIfSoldNowRub!, currency: 'RUB'),
),
],
),
],