import 'package:flutter/cupertino.dart'; import 'package:please_pay_me/core/format/formatters.dart'; import 'package:please_pay_me/features/budgets/budgets_controller.dart'; import 'package:please_pay_me/features/expenses/expense_actions.dart'; import 'package:please_pay_me/features/journal/journal_controller.dart'; import 'package:please_pay_me/theme/theme.dart'; import 'package:please_pay_me/ui/ui.dart'; import 'package:provider/provider.dart'; /// Operations grouped by day, with current-budget / all-budgets scope. class JournalScreen extends StatelessWidget { const JournalScreen({super.key}); @override Widget build(BuildContext context) { final journal = context.watch(); final budgets = context.watch(); return CupertinoPageScaffold( backgroundColor: AppColors.of(context, AppColors.groupedBackground), child: CustomScrollView( physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), slivers: [ AppLargeNavBar( title: 'Журнал', trailing: CupertinoButton( padding: EdgeInsets.zero, minimumSize: Size.zero, onPressed: budgets.hasBudgets ? () => showExpenseFormSheet(context: context, controller: budgets) : null, child: const AppIcon(CupertinoIcons.add_circled, color: AppColors.accent), ), ), CupertinoSliverRefreshControl(onRefresh: () => journal.load(silent: true)), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.only(top: AppSpacing.s2, bottom: AppSpacing.s4), child: AppSegmentedControl( labels: JournalScope.values.map((scope) => scope.label).toList(), index: JournalScope.values.indexOf(journal.scope), onChanged: (index) => journal.setScope(JournalScope.values[index]), ), ), ), SliverToBoxAdapter( child: journal.state.map( loading: () => AppListSection( children: List.generate(4, (_) => const AppSkeletonRow(hasLeading: false)), ), error: (message) => AppErrorView(message: message, onRetry: journal.load), data: (_) => _JournalBody(journal: journal), ), ), const SliverToBoxAdapter(child: SizedBox(height: AppSpacing.s7)), ], ), ); } } class _JournalBody extends StatelessWidget { const _JournalBody({required this.journal}); final JournalController journal; @override Widget build(BuildContext context) { final groups = journal.groups; if (groups.isEmpty) { final budgets = context.read(); return AppEmptyState( icon: CupertinoIcons.doc_text, title: 'Операций пока нет', message: journal.scope == JournalScope.all ? 'Как только появится первая трата, она появится здесь.' : 'В текущем бюджете ещё ничего не потрачено.', actionLabel: budgets.hasBudgets ? 'Добавить трату' : null, onAction: budgets.hasBudgets ? () => showExpenseFormSheet(context: context, controller: budgets) : null, ); } return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ AppCard( child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const AppText.footnote('Всего операций'), AppText.title('${journal.state.valueOrNull?.totalCount ?? 0}'), ], ), ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const AppText.footnote('Сумма'), AppText.title(formatMoney(journal.totalSum)), ], ), ), ], ), ), const SizedBox(height: AppSpacing.s5), for (final group in groups) ...[ AppListSection( header: formatRelativeDay(group.day), footer: 'Итого за день: ${formatMoney(group.total)}', children: [ for (final expense in group.items) AppListTile( title: expenseTitle(expense.note), subtitle: formatWeekday(expense.spentAt), value: expenseAmount(expense.amount), showChevron: false, ), ], ), const SizedBox(height: AppSpacing.s5), ], if (journal.hasMore) Padding( padding: const EdgeInsets.symmetric(horizontal: AppSpacing.gutter), child: AppButton( label: 'Показать ещё', style: AppButtonStyle.gray, loading: journal.isLoadingMore, onPressed: journal.loadMore, ), ), ], ); } }