Files
Dmitry 322c60a359 style(app): остальные экраны под новый визуальный язык и форматирование
Доходы, ребалансировка, налоги, импорт, цели, здоровье данных, правила, транзакции, категории, cashflow, pending: новые виджеты и токены темы, dart format. Тесты подстроены под новые модели.
2026-09-19 22:14:27 +03:00

114 lines
3.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/cache/cached.dart';
import '../../core/widgets/stale_banner.dart';
import 'data/tax_api.dart';
import 'lots_tab.dart';
import 'providers.dart';
import 'summary_tab.dart';
/// Налоги: the year summary and the open-lot list with ЛДВ dates.
///
/// The word «оценка» is on the screen itself, not in a tooltip: the tax agent is the
/// broker, and these numbers exist so that the broker's statement can be checked against
/// something — not to replace it.
class TaxPage extends ConsumerWidget {
const TaxPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final stale = oldestFetch([
ref.watch(taxSummaryProvider).valueOrNull?.fetchedAt,
ref.watch(taxLotsProvider).valueOrNull?.fetchedAt,
]);
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Text('Налоги (оценка)'),
actions: [
const _YearSelector(),
IconButton(
tooltip: 'Обновить',
icon: const Icon(Icons.refresh),
onPressed: () => invalidateTaxProviders(ref),
),
],
bottom: const TabBar(
tabs: [
Tab(text: 'Сводка за год'),
Tab(text: 'Лоты и ЛДВ'),
],
),
),
body: Column(
children: [
const EstimateBanner(),
if (stale != null)
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 12),
child: StaleBanner(fetchedAt: stale),
),
const Expanded(
child: TabBarView(children: [TaxSummaryTab(), TaxLotsTab()]),
),
],
),
),
);
}
}
/// The disclaimer, always visible above both tabs.
class EstimateBanner extends ConsumerWidget {
const EstimateBanner({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final summary = ref.watch(taxSummaryProvider).valueOrNull?.data;
final scheme = Theme.of(context).colorScheme;
final text = summary?.disclaimer ?? TaxSummary.defaultDisclaimer;
return Material(
color: scheme.tertiaryContainer,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Row(
children: [
const Icon(Icons.info_outline, size: 18),
const SizedBox(width: 8),
Expanded(
child: Text(text, style: Theme.of(context).textTheme.bodySmall),
),
],
),
),
);
}
}
class _YearSelector extends ConsumerWidget {
const _YearSelector();
@override
Widget build(BuildContext context, WidgetRef ref) {
final year = ref.watch(taxYearProvider);
final now = DateTime.now().year;
return DropdownButtonHideUnderline(
child: DropdownButton<int>(
value: year,
borderRadius: BorderRadius.circular(8),
items: [
for (var y = now; y >= now - 6; y--)
DropdownMenuItem(value: y, child: Text('$y')),
],
onChanged: (v) {
if (v != null) ref.read(taxYearProvider.notifier).state = v;
},
),
);
}
}