153 lines
4.9 KiB
Dart
153 lines
4.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:intl/intl.dart';
|
|
import '../providers/db_provider.dart';
|
|
import '../theme/app_theme.dart';
|
|
|
|
class DashboardScreen extends ConsumerWidget {
|
|
const DashboardScreen({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final totalBalance = ref.watch(totalBalanceProvider);
|
|
final accounts = ref.watch(openAccountsProvider);
|
|
final recentTxs = ref.watch(recentTransactionsProvider);
|
|
|
|
return ListView(
|
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 90),
|
|
children: [
|
|
// Total Balance
|
|
_BalanceCard(balance: totalBalance),
|
|
const SizedBox(height: 16),
|
|
|
|
// By accounts
|
|
Text('Comptes', style: Theme.of(context).textTheme.titleMedium),
|
|
const SizedBox(height: 8),
|
|
...accounts.map((a) => _AccountMiniCard(account: a)),
|
|
const SizedBox(height: 24),
|
|
|
|
// Recent transactions
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text('Transactions récentes', style: Theme.of(context).textTheme.titleMedium),
|
|
TextButton.icon(
|
|
onPressed: () {},
|
|
icon: const Icon(Icons.arrow_forward_ios, size: 14),
|
|
label: const Text('Voir tout'),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
if (recentTxs.isEmpty)
|
|
Card(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(32),
|
|
child: Center(child: Text('Aucune transaction', style: Theme.of(context).textTheme.bodyMedium)),
|
|
),
|
|
)
|
|
else
|
|
...recentTxs.map((t) => _TxItem(transaction: t)),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _BalanceCard extends StatelessWidget {
|
|
final double balance;
|
|
const _BalanceCard({required this.balance});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Card(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text('Solde total', style: Theme.of(context).textTheme.bodyMedium),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
formatCurrency(balance),
|
|
style: Theme.of(context).textTheme.headlineLarge?.copyWith(
|
|
fontSize: 36,
|
|
fontWeight: FontWeight.w700,
|
|
color: balance >= 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _AccountMiniCard extends StatelessWidget {
|
|
final Account account;
|
|
const _AccountMiniCard({required this.account});
|
|
|
|
IconData _icon() {
|
|
switch (account.type) {
|
|
case 'savings': return Icons.savings_outlined;
|
|
case 'credit': return Icons.credit_card_outlined;
|
|
case 'cash': return Icons.money_outlined;
|
|
default: return Icons.account_balance_outlined;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Card(
|
|
margin: const EdgeInsets.only(bottom: 6),
|
|
child: ListTile(
|
|
dense: true,
|
|
leading: Icon(_icon(), color: Theme.of(context).colorScheme.onSurfaceVariant),
|
|
title: Text(account.name, style: Theme.of(context).textTheme.bodyMedium),
|
|
trailing: Text(
|
|
formatCurrency(account.balance),
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
fontWeight: FontWeight.w600,
|
|
color: account.balance >= 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _TxItem extends StatelessWidget {
|
|
final Transaction transaction;
|
|
const _TxItem({required this.transaction});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Card(
|
|
margin: const EdgeInsets.only(bottom: 4),
|
|
child: ListTile(
|
|
dense: true,
|
|
leading: CircleAvatar(
|
|
radius: 18,
|
|
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
|
|
child: Icon(
|
|
transaction.amount >= 0 ? Icons.arrow_downward : Icons.arrow_upward,
|
|
size: 16,
|
|
color: transaction.amount >= 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error,
|
|
),
|
|
),
|
|
title: Text(transaction.payee, style: Theme.of(context).textTheme.bodyMedium),
|
|
subtitle: Text(
|
|
DateFormat('dd/MM/yy').format(transaction.date),
|
|
style: Theme.of(context).textTheme.bodySmall,
|
|
),
|
|
trailing: Text(
|
|
formatCurrency(transaction.amount),
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
fontWeight: FontWeight.w600,
|
|
color: transaction.amount >= 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|