Files
fin-tracker/app/lib/features/income/income_page.dart
T
Dmitry 7b419f4188 feat(app): offline-кэш на остальных экранах — фаза 5
accounts, cashflow, categories, goals, income, portfolio (+instrument),
rebalance, tax, rules переведены на Cached<T> по контракту
docs/ai/offline-cache.md. Общие/второстепенные селекторы (scopesProvider,
categoriesListProvider и т.п.) оставлены как есть — не основной контент
экрана. sync_page.dart и settings_page.dart не тронуты (первый — заменён
health-page отдельно, второй — чистые действия без списка для баннера).
2026-09-19 14:00:13 +03:00

64 lines
2.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/cache/cached.dart';
import '../../core/widgets/scope_selector.dart';
import '../../core/widgets/stale_banner.dart';
import 'calendar_tab.dart';
import 'forecast_tab.dart';
import 'history_tab.dart';
import 'providers.dart';
/// Доходы: the dividend/coupon calendar, the paid history and the forecast — three views of
/// one question, so three tabs of one screen rather than three navigation destinations.
///
/// One offline banner covers all three tabs (`docs/ai/offline-cache.md`): they share a
/// scope and `TabBarView` builds all of them eagerly anyway, so watching all three
/// providers here to compute it costs nothing extra.
class IncomePage extends ConsumerWidget {
const IncomePage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final stale = oldestFetch([
ref.watch(incomeCalendarProvider).valueOrNull?.fetchedAt,
ref.watch(incomeHistoryProvider).valueOrNull?.fetchedAt,
ref.watch(incomeForecastProvider).valueOrNull?.fetchedAt,
]);
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
title: const Text('Доходы'),
actions: [
const ScopeSelector(),
IconButton(
tooltip: 'Обновить',
icon: const Icon(Icons.refresh),
onPressed: () => invalidateIncomeProviders(ref),
),
],
bottom: const TabBar(
tabs: [Tab(text: 'Календарь'), Tab(text: 'История'), Tab(text: 'Прогноз')],
),
),
body: Column(
children: [
if (stale != null)
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 0),
child: StaleBanner(fetchedAt: stale),
),
const Expanded(
child: TabBarView(
children: [IncomeCalendarTab(), IncomeHistoryTab(), IncomeForecastTab()],
),
),
],
),
),
);
}
}