From daa2346370b611dc379a91ce529172608af1b1aa Mon Sep 17 00:00:00 2001 From: kolo Date: Wed, 25 Mar 2026 14:04:43 +0300 Subject: [PATCH] update --- lib/core/l10n/app_strings.dart | 10 ++ lib/features/dashboard/screen.dart | 208 +++++++++++++++++++++-------- 2 files changed, 161 insertions(+), 57 deletions(-) diff --git a/lib/core/l10n/app_strings.dart b/lib/core/l10n/app_strings.dart index 97dc35a..23318aa 100644 --- a/lib/core/l10n/app_strings.dart +++ b/lib/core/l10n/app_strings.dart @@ -174,5 +174,15 @@ class AppStrings { String get reset => _ru ? 'Сброс' : 'Reset'; String get apply => _ru ? 'Применить' : 'Apply'; + String get accountsInfoTitle => _ru ? 'Счета' : 'Accounts'; + String get accountsInfoBalance => _ru + ? 'У каждого счёта свой баланс, валюта и цвет карточки.' + : 'Each account has its own balance, currency and card color.'; + String get accountsInfoCustomize => _ru + ? 'Удерживайте карточку для настройки градиента, названия и валюты.' + : 'Long-press any card to customize its gradient, name and currency.'; + String get accountsInfoLimit => + _ru ? 'Максимум 5 счетов.' : 'Maximum 5 accounts.'; + String get dateLocale => _ru ? 'ru_RU' : 'en_US'; } diff --git a/lib/features/dashboard/screen.dart b/lib/features/dashboard/screen.dart index 5564783..70d45be 100644 --- a/lib/features/dashboard/screen.dart +++ b/lib/features/dashboard/screen.dart @@ -264,6 +264,12 @@ class _DashboardScreenState extends ConsumerState { ) : globalCurrencyInfo; + final activeIndex = ref.watch(activeAccountIndexProvider); + final accountsAsync = ref.watch(accountsProvider); + final accountCount = accountsAsync.valueOrNull?.length ?? 0; + final isOnAddAccountPage = + accountCount < 5 && activeIndex == accountCount + 1; + return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: AppBar( @@ -307,19 +313,21 @@ class _DashboardScreenState extends ConsumerState { ), ], ), - floatingActionButton: FloatingActionButton.extended( - onPressed: () { - HapticService.medium(); - context.push('/add'); - }, - backgroundColor: const Color(0xFF7C6DED), - foregroundColor: Colors.white, - icon: const Icon(Icons.add), - label: Text( - s.addTransactionDashboard, - style: const TextStyle(fontWeight: FontWeight.w600), - ), - ), + floatingActionButton: isOnAddAccountPage + ? null + : FloatingActionButton.extended( + onPressed: () { + HapticService.medium(); + context.push('/add'); + }, + backgroundColor: const Color(0xFF7C6DED), + foregroundColor: Colors.white, + icon: const Icon(Icons.add), + label: Text( + s.addTransactionDashboard, + style: const TextStyle(fontWeight: FontWeight.w600), + ), + ), floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, body: SafeArea( child: CustomScrollView( @@ -345,62 +353,72 @@ class _DashboardScreenState extends ConsumerState { : null, ), const SizedBox(height: 16), - SummaryRow( - income: income, - expense: expense, - currencyInfo: currencyInfo, - strings: s, - ), - if (budget != null) ...[ - const SizedBox(height: 16), - BudgetProgress( - spent: monthExpense, - budget: budget, + if (!isOnAddAccountPage) ...[ + SummaryRow( + income: income, + expense: expense, currencyInfo: currencyInfo, strings: s, ), - ], - const SizedBox(height: 24), - custom.SearchBar( - controller: _searchController, - focusNode: _searchFocusNode, - onTap: _scrollToSearch, - ref: ref, - strings: s, - ), - const SizedBox(height: 12), - FilterChips(strings: s), - const SizedBox(height: 20), - Text( - s.transactions, - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w600, - color: Theme.of(context).colorScheme.onSurface, + if (budget != null) ...[ + const SizedBox(height: 16), + BudgetProgress( + spent: monthExpense, + budget: budget, + currencyInfo: currencyInfo, + strings: s, + ), + ], + const SizedBox(height: 24), + custom.SearchBar( + controller: _searchController, + focusNode: _searchFocusNode, + onTap: _scrollToSearch, + ref: ref, + strings: s, ), - ), - const SizedBox(height: 12), + const SizedBox(height: 12), + FilterChips(strings: s), + const SizedBox(height: 20), + Text( + s.transactions, + style: Theme.of(context).textTheme.titleMedium + ?.copyWith( + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.onSurface, + ), + ), + const SizedBox(height: 12), + ], ], ), ), ), - if (recent.isEmpty) - SliverFillRemaining( + if (isOnAddAccountPage) ...[ + const SliverFillRemaining( hasScrollBody: false, - child: EmptyState(strings: s), - ) - else - SliverPadding( - padding: const EdgeInsets.fromLTRB(20, 0, 20, 100), - sliver: SliverList.builder( - itemCount: recent.length, - itemBuilder: (context, i) => Padding( - padding: const EdgeInsets.only(bottom: 10), - child: RepaintBoundary( - child: TransactionTile(transaction: recent[i]), + child: Center(child: _AccountsInfoBlock()), + ), + ] else ...[ + if (recent.isEmpty) + SliverFillRemaining( + hasScrollBody: false, + child: EmptyState(strings: s), + ) + else + SliverPadding( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 100), + sliver: SliverList.builder( + itemCount: recent.length, + itemBuilder: (context, i) => Padding( + padding: const EdgeInsets.only(bottom: 10), + child: RepaintBoundary( + child: TransactionTile(transaction: recent[i]), + ), ), ), ), - ), + ], const SliverPadding(padding: EdgeInsets.only(bottom: 80)), ], ), @@ -408,3 +426,79 @@ class _DashboardScreenState extends ConsumerState { ); } } + +class _AccountsInfoBlock extends ConsumerWidget { + const _AccountsInfoBlock(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final s = ref.watch(stringsProvider); + final onSurface = Theme.of(context).colorScheme.onSurface; + return Padding( + padding: const EdgeInsets.only(bottom: 60), + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 260), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.account_balance_wallet_rounded, + size: 18, + color: Color(0xFF7C6DED), + ), + const SizedBox(width: 8), + Text( + s.accountsInfoTitle, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w700, + color: onSurface, + ), + ), + ], + ), + const SizedBox(height: 12), + _InfoRow(icon: Icons.swap_horiz_rounded, text: s.accountsInfoBalance), + const SizedBox(height: 8), + _InfoRow(icon: Icons.touch_app_rounded, text: s.accountsInfoCustomize), + const SizedBox(height: 8), + _InfoRow(icon: Icons.lock_outline_rounded, text: s.accountsInfoLimit), + ], + ), + ), + ); + } + } + +class _InfoRow extends StatelessWidget { + final IconData icon; + final String text; + + const _InfoRow({required this.icon, required this.text}); + + @override + Widget build(BuildContext context) { + final onSurface = Theme.of(context).colorScheme.onSurface; + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(icon, size: 15, color: onSurface.withOpacity(0.4)), + const SizedBox(width: 8), + Expanded( + child: Text( + text, + style: TextStyle( + fontSize: 13, + height: 1.4, + color: onSurface.withOpacity(0.5), + ), + ), + ), + ], + ); + } +}