Импорт (/imports, /instruments/pending) и фаза 4 (/goals, /income, /rebalance, /tax, аналитика-хаб с benchmarks_card) — по docs/ai/import-contract.md и docs/ai/phase4-contract.md. file_picker для загрузки отчёта.
70 lines
2.6 KiB
Dart
70 lines
2.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
/// Аналитика: a hub for the phase-4 screens.
|
|
///
|
|
/// Why a hub instead of four more destinations: the shell already carried eleven, which on
|
|
/// a phone leaves ~36 px per label in the bottom bar. Доходы, Ребалансировка, Цели and
|
|
/// Налоги are all "what do I do with the portfolio next" questions, so they live behind one
|
|
/// entry that highlights for all four (see `alsoMatches` in `app_shell.dart`), while each
|
|
/// keeps its own top-level route from the contract (`/income`, `/rebalance`, `/goals`,
|
|
/// `/tax`) and is deep-linkable.
|
|
class AnalyticsHubPage extends StatelessWidget {
|
|
const AnalyticsHubPage({super.key});
|
|
|
|
static const _entries = [
|
|
(
|
|
path: '/income',
|
|
icon: Icons.payments_outlined,
|
|
title: 'Доходы',
|
|
subtitle: 'Календарь дивидендов и купонов, история выплат, прогноз на 12 месяцев',
|
|
),
|
|
(
|
|
path: '/rebalance',
|
|
icon: Icons.balance,
|
|
title: 'Ребалансировка',
|
|
subtitle: 'Целевые веса портфеля и рекомендации, что докупить или продать',
|
|
),
|
|
(
|
|
path: '/goals',
|
|
icon: Icons.flag_outlined,
|
|
title: 'Цели',
|
|
subtitle: 'Накопительные цели и прогноз их достижения по текущему тренду',
|
|
),
|
|
(
|
|
path: '/tax',
|
|
icon: Icons.receipt_long_outlined,
|
|
title: 'Налоги',
|
|
subtitle: 'Оценка налога за год и лоты с датой ЛДВ — для сверки со справкой брокера',
|
|
),
|
|
];
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('Аналитика')),
|
|
body: ListView(
|
|
padding: const EdgeInsets.all(16),
|
|
children: [
|
|
for (final e in _entries)
|
|
Card(
|
|
child: ListTile(
|
|
leading: Icon(e.icon),
|
|
title: Text(e.title),
|
|
subtitle: Text(e.subtitle),
|
|
trailing: const Icon(Icons.chevron_right),
|
|
onTap: () => context.go(e.path),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
Text(
|
|
'Сравнение с бенчмарками живёт на экране «Портфель»: обгон индекса — '
|
|
'свойство портфеля, а не отдельная тема.',
|
|
style: Theme.of(context).textTheme.bodySmall,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|