budget screen: dynamic month display, editable budget amounts (tap to set)

This commit is contained in:
alexis 2026-07-11 22:13:51 +02:00
parent e3baad4dfa
commit da74308bad

View file

@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../providers/db_provider.dart';
import '../theme/app_theme.dart';
import 'package:drift/drift.dart' show Value;
import '../data/db.dart';
class BudgetScreen extends ConsumerWidget {
const BudgetScreen({super.key});
@ -10,6 +12,9 @@ class BudgetScreen extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final groups = ref.watch(categoryGroupsProvider).valueOrNull ?? [];
final catsByGroup = ref.watch(categoriesByGroupProvider);
final now = DateTime.now();
final months = ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
final monthLabel = '${months[now.month]} ${now.year}';
return ListView(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 90),
@ -22,7 +27,7 @@ class BudgetScreen extends ConsumerWidget {
children: [
Text('Budget du mois', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 4),
Text('Juillet 2026', style: Theme.of(context).textTheme.bodySmall),
Text(monthLabel, style: Theme.of(context).textTheme.bodySmall),
],
),
),
@ -106,6 +111,51 @@ class _CategoryRow extends ConsumerWidget {
final remaining = ref.watch(categoryRemainingProvider(categoryId));
final pct = budgeted > 0 ? ((budgeted + spent) / budgeted).clamp(0.0, 1.0) : 0.0;
void _editBudget() async {
final month = ref.read(currentMonthProvider);
final db = ref.read(dbProvider);
final ctrl = TextEditingController(text: budgeted > 0 ? budgeted.toStringAsFixed(2) : '');
final newAmount = await showDialog<double>(
context: context,
builder: (ctx) => AlertDialog(
title: Text('Budget : ${category.name}'),
content: TextField(
controller: ctrl,
decoration: const InputDecoration(labelText: 'Montant', hintText: '0,00'),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
autofocus: true,
),
actions: [
TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Annuler')),
FilledButton(
onPressed: () {
final v = double.tryParse(ctrl.text.trim().replaceAll(',', '.'));
if (v != null) Navigator.pop(ctx, v);
},
child: const Text('Enregistrer'),
),
],
),
);
ctrl.dispose();
if (newAmount == null) return;
final existing = await (db.select(db.budgets)
..where((b) => b.categoryId.equals(categoryId))
..where((b) => b.month.equals(month)))
.get();
if (existing.isNotEmpty) {
await db.update(db.budgets).replace(existing.first.copyWith(budgeted: newAmount));
} else {
await db.into(db.budgets).insert(BudgetsCompanion.insert(
categoryId: categoryId,
month: month,
budgeted: Value(newAmount),
));
}
}
return Padding(
padding: const EdgeInsets.only(left: 8, bottom: 4),
child: Card(
@ -144,8 +194,14 @@ class _CategoryRow extends ConsumerWidget {
const SizedBox(height: 2),
Row(
children: [
Text('Budget: ${formatCurrency(budgeted)}',
style: Theme.of(context).textTheme.bodySmall),
GestureDetector(
onTap: _editBudget,
child: Text('Budget: ${formatCurrency(budgeted)}',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
decoration: TextDecoration.underline,
color: Theme.of(context).colorScheme.primary,
)),
),
const SizedBox(width: 12),
Text('Dépensé: ${formatCurrency(spent.abs())}',
style: Theme.of(context).textTheme.bodySmall),