feat(app): новый визуальный язык, верхняя навигация, портфели, создание счетов и ручные события

Тема и общие виджеты (AssetIcon, ServiceMark, HelpTip, глоссарий), верхняя панель TopNav и вкладки Аналитики вместо NavSidebar, иконки PWA. Экраны: портфели, создание брокерского счёта, ручное событие, правка инструмента, Обзор карточками по скоупам и таблица активов, пересчёт метрик с опросом /metrics/status. design-system.md обновлён.
This commit is contained in:
Dmitry
2026-09-19 22:14:21 +03:00
parent a559d6de3e
commit 62d36aa3e8
73 changed files with 6406 additions and 1192 deletions
+26 -10
View File
@@ -75,21 +75,24 @@ class _DimensionCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final onlyUnknown = buckets.every((b) => b.bucket == 'unknown' || b.bucket == 'cash');
final onlyUnknown = buckets.every(
(b) => b.bucket == 'unknown' || b.bucket == 'cash',
);
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(dimensionLabel(dimension), style: Theme.of(context).textTheme.titleMedium),
Text(
dimensionLabel(dimension),
style: Theme.of(context).textTheme.titleMedium,
),
if (onlyUnknown) ...[
const SizedBox(height: 4),
Text(
'Атрибут не заполнен у инструментов — разрез пустой, а не нулевой.',
style: Theme.of(context)
.textTheme
.bodySmall
style: Theme.of(context).textTheme.bodySmall
?.copyWith(color: Theme.of(context).hintColor),
),
],
@@ -111,7 +114,9 @@ class _DimensionCard extends StatelessWidget {
],
);
}
return Column(children: [donut, const SizedBox(height: 12), legend]);
return Column(
children: [donut, const SizedBox(height: 12), legend],
);
},
),
],
@@ -133,7 +138,10 @@ class _Donut extends StatelessWidget {
// and the legend still lists it with its real value
final positive = buckets.where((b) => _d(b.valueRub) > 0).toList();
if (positive.isEmpty) {
return const EmptyState(icon: Icons.donut_large_outlined, message: 'Нечего показать.');
return const EmptyState(
icon: Icons.donut_large_outlined,
message: 'Нечего показать.',
);
}
return PieChart(
PieChartData(
@@ -194,10 +202,18 @@ class _Legend extends StatelessWidget {
if (buckets[i].holdingCount > 0)
Padding(
padding: const EdgeInsets.only(right: 8),
child: Text('${buckets[i].holdingCount}',
style: theme.textTheme.bodySmall?.copyWith(color: theme.hintColor)),
child: Text(
'${buckets[i].holdingCount}',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.hintColor,
),
),
),
MoneyText(buckets[i].valueRub, currency: 'RUB', style: theme.textTheme.bodyMedium),
MoneyText(
buckets[i].valueRub,
currency: 'RUB',
style: theme.textTheme.bodyMedium,
),
const SizedBox(width: 12),
SizedBox(
width: 56,