156 lines
5.7 KiB
Dart
156 lines
5.7 KiB
Dart
import 'package:drift/drift.dart' show Value;
|
|
import '../data/db.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../providers/db_provider.dart';
|
|
import '../theme/app_theme.dart';
|
|
|
|
class AccountsScreen extends ConsumerWidget {
|
|
const AccountsScreen({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final all = ref.watch(openAccountsProvider);
|
|
final query = ref.watch(searchQueryProvider).toLowerCase();
|
|
final accounts = query.isEmpty
|
|
? all
|
|
: all.where((a) => a.name.toLowerCase().contains(query)).toList();
|
|
|
|
return ListView(
|
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 90),
|
|
children: [
|
|
...accounts.map((a) => _AccountCard(account: a)),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _AccountCard extends ConsumerWidget {
|
|
final Account account;
|
|
const _AccountCard({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;
|
|
}
|
|
}
|
|
|
|
String _label() {
|
|
switch (account.type) {
|
|
case 'checking': return 'Compte courant';
|
|
case 'savings': return 'Épargne';
|
|
case 'credit': return 'Carte de crédit';
|
|
case 'cash': return 'Espèces';
|
|
default: return account.type;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
return Card(
|
|
margin: const EdgeInsets.only(bottom: 8),
|
|
child: ListTile(
|
|
leading: CircleAvatar(
|
|
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
|
|
child: Icon(_icon(), color: Theme.of(context).colorScheme.onSurfaceVariant, size: 22),
|
|
),
|
|
title: Text(account.name, style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600)),
|
|
subtitle: Text(_label(), style: Theme.of(context).textTheme.bodySmall),
|
|
trailing: Text(
|
|
formatCurrency(account.balance),
|
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
fontWeight: FontWeight.w700,
|
|
color: account.balance >= 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error,
|
|
),
|
|
),
|
|
onTap: () => _editAccount(context, ref, account),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _editAccount(BuildContext context, WidgetRef ref, Account account) async {
|
|
final db = ref.read(dbProvider);
|
|
final nameCtrl = TextEditingController(text: account.name);
|
|
final balanceCtrl = TextEditingController(text: account.balance.toStringAsFixed(2));
|
|
String type = account.type;
|
|
|
|
await showDialog(
|
|
context: context,
|
|
builder: (ctx) => StatefulBuilder(
|
|
builder: (context, setDialogState) => AlertDialog(
|
|
title: const Text('Modifier le compte'),
|
|
content: SingleChildScrollView(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
TextField(
|
|
controller: nameCtrl,
|
|
decoration: const InputDecoration(labelText: 'Nom', hintText: 'Ex: Compte courant'),
|
|
),
|
|
const SizedBox(height: 12),
|
|
TextField(
|
|
controller: balanceCtrl,
|
|
decoration: const InputDecoration(labelText: 'Solde', hintText: '0,00'),
|
|
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
|
),
|
|
const SizedBox(height: 12),
|
|
DropdownButtonFormField<String>(
|
|
initialValue: type,
|
|
decoration: const InputDecoration(labelText: 'Type'),
|
|
items: const [
|
|
DropdownMenuItem(value: 'checking', child: Text('Compte courant')),
|
|
DropdownMenuItem(value: 'savings', child: Text('Épargne')),
|
|
DropdownMenuItem(value: 'credit', child: Text('Carte de crédit')),
|
|
DropdownMenuItem(value: 'cash', child: Text('Espèces')),
|
|
],
|
|
onChanged: (v) {
|
|
if (v != null) {
|
|
type = v;
|
|
setDialogState(() {});
|
|
}
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () async {
|
|
await (db.delete(db.accounts)..where((t) => t.id.equals(account.id))).go();
|
|
if (ctx.mounted) Navigator.pop(ctx);
|
|
},
|
|
style: TextButton.styleFrom(foregroundColor: Theme.of(context).colorScheme.error),
|
|
child: const Text('Supprimer'),
|
|
),
|
|
const SizedBox(width: 8),
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(ctx),
|
|
child: const Text('Annuler'),
|
|
),
|
|
FilledButton(
|
|
onPressed: () async {
|
|
final name = nameCtrl.text.trim();
|
|
final balanceStr = balanceCtrl.text.trim().replaceAll(',', '.');
|
|
final balance = double.tryParse(balanceStr);
|
|
if (name.isEmpty || balance == null) return;
|
|
await (db.update(db.accounts)..where((t) => t.id.equals(account.id))).write(AccountsCompanion(
|
|
name: Value(name),
|
|
type: Value(type),
|
|
balance: Value(balance),
|
|
));
|
|
if (ctx.mounted) Navigator.pop(ctx);
|
|
},
|
|
child: const Text('Enregistrer'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
nameCtrl.dispose();
|
|
balanceCtrl.dispose();
|
|
}
|
|
}
|