import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/widgets/async_value_view.dart'; import '../../core/widgets/empty_state.dart'; import '../portfolio/labels.dart' show dimensionLabels; import 'data/rebalance_api.dart'; import 'plan_tab.dart'; import 'providers.dart'; import 'targets_tab.dart'; /// Ребалансировка: the target weights on one tab, the resulting recommendations on the /// other. Both are per portfolio and per dimension, so the pickers live in the app bar and /// drive both tabs at once. class RebalancePage extends ConsumerWidget { const RebalancePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final portfolios = ref.watch(portfoliosProvider); return DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title: const Text('Ребалансировка'), actions: [ const _PortfolioSelector(), const _DimensionSelector(), IconButton( tooltip: 'Обновить', icon: const Icon(Icons.refresh), onPressed: () => invalidateRebalanceProviders(ref), ), ], bottom: const TabBar( tabs: [Tab(text: 'Целевые веса'), Tab(text: 'Рекомендации')], ), ), body: AsyncValueView( value: portfolios, onRetry: () => ref.invalidate(portfoliosProvider), data: (list) { if (list.isEmpty) { return const EmptyState( icon: Icons.pie_chart_outline, message: 'Портфелей пока нет.\n' 'Ребалансировка считается по портфелю: заведите его в настройках счетов.', ); } 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; }); return const Center(child: CircularProgressIndicator()); } return const TabBarView(children: [TargetsTab(), RebalancePlanTab()]); }, ), ), ); } } class _PortfolioSelector extends ConsumerWidget { const _PortfolioSelector(); @override Widget build(BuildContext context, WidgetRef ref) { final portfolios = ref.watch(portfoliosProvider).valueOrNull ?? const []; final selected = ref.watch(selectedPortfolioProvider); if (portfolios.length < 2 || selected == null) return const SizedBox.shrink(); return DropdownButtonHideUnderline( child: DropdownButton( 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)), ], onChanged: (v) { if (v != null) ref.read(selectedPortfolioProvider.notifier).state = v; }, ), ); } } class _DimensionSelector extends ConsumerWidget { const _DimensionSelector(); @override Widget build(BuildContext context, WidgetRef ref) { final current = ref.watch(targetDimensionProvider); return Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: DropdownButtonHideUnderline( child: DropdownButton( value: current, borderRadius: BorderRadius.circular(8), items: [ for (final d in targetDimensions) DropdownMenuItem(value: d, child: Text(dimensionLabels[d] ?? d)), ], onChanged: (v) { if (v != null) ref.read(targetDimensionProvider.notifier).state = v; }, ), ), ); } }