style(app): остальные экраны под новый визуальный язык и форматирование

Доходы, ребалансировка, налоги, импорт, цели, здоровье данных, правила, транзакции, категории, cashflow, pending: новые виджеты и токены темы, dart format. Тесты подстроены под новые модели.
This commit is contained in:
Dmitry
2026-09-19 22:14:27 +03:00
parent 62d36aa3e8
commit 322c60a359
55 changed files with 2158 additions and 1080 deletions
+46 -14
View File
@@ -16,12 +16,16 @@ import 'data_quality_list.dart';
final _dateFmt = DateFormat('dd.MM.yyyy HH:mm');
final syncStatusProvider = FutureProvider.autoDispose<List<SourceStatus>>((ref) async {
final syncStatusProvider = FutureProvider.autoDispose<List<SourceStatus>>((
ref,
) async {
final r = await ref.watch(apiProvider).getSyncApi().syncStatus();
return r.data ?? const [];
});
final syncRunsProvider = FutureProvider.autoDispose<List<SyncRunOut>>((ref) async {
final syncRunsProvider = FutureProvider.autoDispose<List<SyncRunOut>>((
ref,
) async {
final r = await ref.watch(apiProvider).getSyncApi().syncRuns(limit: 20);
return r.data ?? const [];
});
@@ -74,7 +78,8 @@ class _HealthPageState extends ConsumerState<HealthPage> {
await ref.read(apiProvider).getSyncApi().syncTrigger(source_: source);
} on DioException catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(problemMessage(e))));
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(problemMessage(e))));
} finally {
ref.invalidate(syncStatusProvider);
ref.invalidate(syncRunsProvider);
@@ -114,7 +119,10 @@ class _HealthPageState extends ConsumerState<HealthPage> {
body: TabBarView(
children: [
_SourcesTab(onRefresh: _refreshAll, onTrigger: _trigger),
_QualityTab(dataQuality: dataQuality, onRefresh: () async => ref.invalidate(dataQualityProvider)),
_QualityTab(
dataQuality: dataQuality,
onRefresh: () async => ref.invalidate(dataQualityProvider),
),
],
),
),
@@ -149,17 +157,26 @@ class _SourcesTab extends ConsumerWidget {
message: 'Источники данных ещё не подключены (фаза 1: ZenMoney, ЦБ).',
)
: Column(
children: [for (final s in rows) _SourceCard(source: s, onTrigger: onTrigger)],
children: [
for (final s in rows)
_SourceCard(source: s, onTrigger: onTrigger),
],
),
),
const SizedBox(height: 24),
Text('Последние запуски', style: Theme.of(context).textTheme.titleMedium),
Text(
'Последние запуски',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
AsyncValueView(
value: runs,
onRetry: () => ref.invalidate(syncRunsProvider),
data: (rows) => rows.isEmpty
? const EmptyState(icon: Icons.history, message: 'Запусков ещё не было.')
? const EmptyState(
icon: Icons.history,
message: 'Запусков ещё не было.',
)
: Column(children: [for (final r in rows) _RunTile(run: r)]),
),
],
@@ -217,10 +234,14 @@ class _SourceCard extends StatelessWidget {
),
subtitle: Padding(
padding: const EdgeInsets.only(top: 4),
child: Text([
if (source.lastRunAt != null) 'запуск ${_dateFmt.format(source.lastRunAt!.toLocal())}',
if (source.cursor != null) 'курсор ${_shortCursor(source.cursor!)}',
].join(' · ')),
child: Text(
[
if (source.lastRunAt != null)
'запуск ${_dateFmt.format(source.lastRunAt!.toLocal())}',
if (source.cursor != null)
'курсор ${_shortCursor(source.cursor!)}',
].join(' · '),
),
),
trailing: IconButton(
tooltip: 'Запустить синхронизацию',
@@ -277,7 +298,12 @@ class _RunTile extends StatelessWidget {
children: [
content,
const SizedBox(height: 8),
Text(run.error!, style: TextStyle(color: Theme.of(context).colorScheme.error)),
Text(
run.error!,
style: TextStyle(
color: Theme.of(context).colorScheme.error,
),
),
],
),
),
@@ -295,7 +321,10 @@ class _RunTile extends StatelessWidget {
_runTitle(context),
Padding(
padding: const EdgeInsets.only(top: 2, bottom: 6),
child: Text(subtitle, style: Theme.of(context).textTheme.bodySmall),
child: Text(
subtitle,
style: Theme.of(context).textTheme.bodySmall,
),
),
content,
],
@@ -317,7 +346,10 @@ class _RunTile extends StatelessWidget {
Widget _statusChip(BuildContext context, RunStatus? status) {
if (status == null) {
return const Chip(visualDensity: VisualDensity.compact, label: Text('нет данных'));
return const Chip(
visualDensity: VisualDensity.compact,
label: Text('нет данных'),
);
}
final scheme = Theme.of(context).colorScheme;
final (label, color) = switch (status) {