feat(app): экраны импорта отчётов, целей, доходов, ребалансировки, налогов и бенчмарков

Импорт (/imports, /instruments/pending) и фаза 4 (/goals, /income,
/rebalance, /tax, аналитика-хаб с benchmarks_card) — по
docs/ai/import-contract.md и docs/ai/phase4-contract.md. file_picker для
загрузки отчёта.
This commit is contained in:
Dmitry
2026-09-19 10:44:38 +03:00
parent 15f5812ea4
commit b69bb4a0c9
52 changed files with 7404 additions and 13 deletions
+56
View File
@@ -0,0 +1,56 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/api/api_client.dart';
import '../portfolio/providers.dart' show scopeProvider;
import 'data/income_api.dart';
final incomeApiProvider = Provider<IncomeApi>((ref) => IncomeApi(ref.watch(apiProvider).dio));
/// How far the calendar looks ahead, in months. 12 is the contract default.
final calendarMonthsProvider = StateProvider<int>((ref) => 12);
final calendarIncludePaidProvider = StateProvider<bool>((ref) => false);
/// Доходы shares the portfolio-wide [scopeProvider]: switching the scope on Портфель must
/// not leave the income calendar showing a different portfolio.
final incomeCalendarProvider = FutureProvider.autoDispose<IncomeCalendar>((ref) async {
final scope = ref.watch(scopeProvider);
final months = ref.watch(calendarMonthsProvider);
final includePaid = ref.watch(calendarIncludePaidProvider);
final now = DateTime.now();
return ref.watch(incomeApiProvider).calendar(
scope: scope,
dateFrom: DateTime(now.year, now.month, now.day),
dateTo: DateTime(now.year, now.month + months, now.day),
includePaid: includePaid,
);
});
/// How far the history goes back, in months.
final historyMonthsProvider = StateProvider<int>((ref) => 24);
final incomeHistoryProvider = FutureProvider.autoDispose<IncomeHistory>((ref) async {
final scope = ref.watch(scopeProvider);
final months = ref.watch(historyMonthsProvider);
final now = DateTime.now();
return ref.watch(incomeApiProvider).history(
scope: scope,
dateFrom: DateTime(now.year, now.month - months + 1, 1),
dateTo: DateTime(now.year, now.month + 1, 0),
);
});
final forecastMonthsProvider = StateProvider<int>((ref) => 12);
final incomeForecastProvider = FutureProvider.autoDispose<IncomeForecast>((ref) async {
final scope = ref.watch(scopeProvider);
return ref
.watch(incomeApiProvider)
.forecast(scope: scope, months: ref.watch(forecastMonthsProvider));
});
void invalidateIncomeProviders(WidgetRef ref) {
ref.invalidate(incomeCalendarProvider);
ref.invalidate(incomeHistoryProvider);
ref.invalidate(incomeForecastProvider);
}