This commit is contained in:
2026-03-25 14:04:43 +03:00
parent a1476a3abb
commit daa2346370
2 changed files with 161 additions and 57 deletions
+10
View File
@@ -174,5 +174,15 @@ class AppStrings {
String get reset => _ru ? 'Сброс' : 'Reset'; String get reset => _ru ? 'Сброс' : 'Reset';
String get apply => _ru ? 'Применить' : 'Apply'; 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'; String get dateLocale => _ru ? 'ru_RU' : 'en_US';
} }
+151 -57
View File
@@ -264,6 +264,12 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
) )
: globalCurrencyInfo; : 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( return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar( appBar: AppBar(
@@ -307,19 +313,21 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
), ),
], ],
), ),
floatingActionButton: FloatingActionButton.extended( floatingActionButton: isOnAddAccountPage
onPressed: () { ? null
HapticService.medium(); : FloatingActionButton.extended(
context.push('/add'); onPressed: () {
}, HapticService.medium();
backgroundColor: const Color(0xFF7C6DED), context.push('/add');
foregroundColor: Colors.white, },
icon: const Icon(Icons.add), backgroundColor: const Color(0xFF7C6DED),
label: Text( foregroundColor: Colors.white,
s.addTransactionDashboard, icon: const Icon(Icons.add),
style: const TextStyle(fontWeight: FontWeight.w600), label: Text(
), s.addTransactionDashboard,
), style: const TextStyle(fontWeight: FontWeight.w600),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
body: SafeArea( body: SafeArea(
child: CustomScrollView( child: CustomScrollView(
@@ -345,62 +353,72 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
: null, : null,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
SummaryRow( if (!isOnAddAccountPage) ...[
income: income, SummaryRow(
expense: expense, income: income,
currencyInfo: currencyInfo, expense: expense,
strings: s,
),
if (budget != null) ...[
const SizedBox(height: 16),
BudgetProgress(
spent: monthExpense,
budget: budget,
currencyInfo: currencyInfo, currencyInfo: currencyInfo,
strings: s, strings: s,
), ),
], if (budget != null) ...[
const SizedBox(height: 24), const SizedBox(height: 16),
custom.SearchBar( BudgetProgress(
controller: _searchController, spent: monthExpense,
focusNode: _searchFocusNode, budget: budget,
onTap: _scrollToSearch, currencyInfo: currencyInfo,
ref: ref, strings: s,
strings: s, ),
), ],
const SizedBox(height: 12), const SizedBox(height: 24),
FilterChips(strings: s), custom.SearchBar(
const SizedBox(height: 20), controller: _searchController,
Text( focusNode: _searchFocusNode,
s.transactions, onTap: _scrollToSearch,
style: Theme.of(context).textTheme.titleMedium?.copyWith( ref: ref,
fontWeight: FontWeight.w600, strings: s,
color: Theme.of(context).colorScheme.onSurface,
), ),
), 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) if (isOnAddAccountPage) ...[
SliverFillRemaining( const SliverFillRemaining(
hasScrollBody: false, hasScrollBody: false,
child: EmptyState(strings: s), child: Center(child: _AccountsInfoBlock()),
) ),
else ] else ...[
SliverPadding( if (recent.isEmpty)
padding: const EdgeInsets.fromLTRB(20, 0, 20, 100), SliverFillRemaining(
sliver: SliverList.builder( hasScrollBody: false,
itemCount: recent.length, child: EmptyState(strings: s),
itemBuilder: (context, i) => Padding( )
padding: const EdgeInsets.only(bottom: 10), else
child: RepaintBoundary( SliverPadding(
child: TransactionTile(transaction: recent[i]), 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)), const SliverPadding(padding: EdgeInsets.only(bottom: 80)),
], ],
), ),
@@ -408,3 +426,79 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
); );
} }
} }
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),
),
),
),
],
);
}
}