style(app): остальные экраны под новый визуальный язык и форматирование
Доходы, ребалансировка, налоги, импорт, цели, здоровье данных, правила, транзакции, категории, cashflow, pending: новые виджеты и токены темы, dart format. Тесты подстроены под новые модели.
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../core/cache/cached.dart';
|
||||
import '../../core/widgets/async_value_view.dart';
|
||||
import '../../core/widgets/empty_state.dart';
|
||||
import '../../core/widgets/stale_banner.dart';
|
||||
import '../portfolio/labels.dart' show dimensionLabels;
|
||||
import '../portfolios/providers.dart' show portfolioListProvider;
|
||||
import 'data/rebalance_api.dart';
|
||||
import 'plan_tab.dart';
|
||||
import 'providers.dart';
|
||||
@@ -45,7 +47,10 @@ class RebalancePage extends ConsumerWidget {
|
||||
),
|
||||
],
|
||||
bottom: const TabBar(
|
||||
tabs: [Tab(text: 'Целевые веса'), Tab(text: 'Рекомендации')],
|
||||
tabs: [
|
||||
Tab(text: 'Целевые веса'),
|
||||
Tab(text: 'Рекомендации'),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
@@ -61,21 +66,48 @@ class RebalancePage extends ConsumerWidget {
|
||||
onRetry: () => ref.invalidate(portfoliosProvider),
|
||||
data: (list) {
|
||||
if (list.isEmpty) {
|
||||
return const EmptyState(
|
||||
icon: Icons.pie_chart_outline,
|
||||
message: 'Портфелей пока нет.\n'
|
||||
'Ребалансировка считается по портфелю: заведите его в настройках счетов.',
|
||||
// A portfolio can exist yet be absent here: this list comes from the
|
||||
// analytics scopes, which only cover accounts that have ledger events.
|
||||
final created =
|
||||
ref
|
||||
.watch(portfolioListProvider)
|
||||
.valueOrNull
|
||||
?.isNotEmpty ??
|
||||
false;
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
EmptyState(
|
||||
icon: Icons.pie_chart_outline,
|
||||
message: created
|
||||
? 'Портфели есть, но в них нет счетов с бумагами.\n'
|
||||
'Добавьте брокерские счета: у счетов ZenMoney нет сделок, '
|
||||
'считать по ним нечего.'
|
||||
: 'Портфелей пока нет.\n'
|
||||
'Ребалансировка считается по портфелю — набору счетов.',
|
||||
),
|
||||
FilledButton.icon(
|
||||
onPressed: () => context.go('/portfolios'),
|
||||
icon: Icon(created ? Icons.edit_outlined : Icons.add),
|
||||
label: Text(
|
||||
created ? 'Изменить портфели' : 'Создать портфель',
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
final selected = ref.watch(selectedPortfolioProvider);
|
||||
if (selected == null || !list.any((p) => p.id == selected)) {
|
||||
// pick the first portfolio once, after the list is known
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(selectedPortfolioProvider.notifier).state = list.first.id;
|
||||
ref.read(selectedPortfolioProvider.notifier).state =
|
||||
list.first.id;
|
||||
});
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return const TabBarView(children: [TargetsTab(), RebalancePlanTab()]);
|
||||
return const TabBarView(
|
||||
children: [TargetsTab(), RebalancePlanTab()],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
@@ -91,16 +123,23 @@ class _PortfolioSelector extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final portfolios = ref.watch(portfoliosProvider).valueOrNull ?? const <PortfolioRef>[];
|
||||
final portfolios =
|
||||
ref.watch(portfoliosProvider).valueOrNull ?? const <PortfolioRef>[];
|
||||
final selected = ref.watch(selectedPortfolioProvider);
|
||||
if (portfolios.length < 2 || selected == null) return const SizedBox.shrink();
|
||||
if (portfolios.length < 2 || selected == null)
|
||||
return const SizedBox.shrink();
|
||||
return DropdownButtonHideUnderline(
|
||||
child: DropdownButton<int>(
|
||||
value: portfolios.any((p) => p.id == selected) ? selected : portfolios.first.id,
|
||||
value: portfolios.any((p) => p.id == selected)
|
||||
? selected
|
||||
: portfolios.first.id,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
items: [
|
||||
for (final p in portfolios)
|
||||
DropdownMenuItem(value: p.id, child: Text(p.name, overflow: TextOverflow.ellipsis)),
|
||||
DropdownMenuItem(
|
||||
value: p.id,
|
||||
child: Text(p.name, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
],
|
||||
onChanged: (v) {
|
||||
if (v != null) ref.read(selectedPortfolioProvider.notifier).state = v;
|
||||
|
||||
Reference in New Issue
Block a user