feat: Enhance documentation for AddExpenseDialog, BalancesTab, and ExpenseDetailDialog with detailed comments and usage examples

This commit is contained in:
Dayron
2025-10-31 17:04:28 +01:00
parent 2faf37f145
commit 48be18460c
3 changed files with 176 additions and 11 deletions

View File

@@ -1,3 +1,11 @@
/// This file defines the `ExpenseDetailDialog` widget, which provides a detailed view of a specific expense
/// within a group. It allows users to view expense details, such as the amount, payer, date, and splits, and
/// perform actions like editing, deleting, or archiving the expense.
///
/// The dialog is highly interactive and adapts its UI based on the current user's permissions and the state
/// of the expense. It also integrates with BLoC for state management and supports features like receipt display
/// and split payment marking.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
@@ -10,10 +18,20 @@ import '../../models/expense.dart';
import '../../models/group.dart';
import 'add_expense_dialog.dart';
/// A stateless widget that displays detailed information about a specific expense.
///
/// The `ExpenseDetailDialog` widget shows the expense's amount, payer, date, splits, and receipt. It also
/// provides actions for editing, deleting, or archiving the expense, depending on the current user's permissions.
class ExpenseDetailDialog extends StatelessWidget {
/// The expense to display details for.
final Expense expense;
/// The group to which the expense belongs.
final Group group;
/// Creates an `ExpenseDetailDialog` widget.
///
/// The [expense] and [group] parameters must not be null.
const ExpenseDetailDialog({
super.key,
required this.expense,
@@ -22,11 +40,13 @@ class ExpenseDetailDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Formatters for displaying dates and times.
final dateFormat = DateFormat('dd MMMM yyyy');
final timeFormat = DateFormat('HH:mm');
return BlocBuilder<UserBloc, user_state.UserState>(
builder: (context, userState) {
// Determine the current user and their permissions.
final currentUser = userState is user_state.UserLoaded ? userState.user : null;
final canEdit = currentUser?.id == expense.paidById;
@@ -39,6 +59,7 @@ class ExpenseDetailDialog extends StatelessWidget {
automaticallyImplyLeading: false,
actions: [
if (canEdit) ...[
// Edit button.
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
@@ -46,11 +67,13 @@ class ExpenseDetailDialog extends StatelessWidget {
_showEditDialog(context, currentUser!);
},
),
// Delete button.
IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => _confirmDelete(context),
),
],
// Close button.
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
@@ -60,7 +83,7 @@ class ExpenseDetailDialog extends StatelessWidget {
body: ListView(
padding: const EdgeInsets.all(16),
children: [
// En-tête avec icône
// Header with icon and description.
Center(
child: Column(
children: [
@@ -99,7 +122,7 @@ class ExpenseDetailDialog extends StatelessWidget {
),
const SizedBox(height: 24),
// Montant
// Amount card.
Card(
child: Padding(
padding: const EdgeInsets.all(16),
@@ -127,11 +150,11 @@ class ExpenseDetailDialog extends StatelessWidget {
),
const SizedBox(height: 16),
// Informations
// Information rows.
_buildInfoRow(Icons.person, 'Payé par', expense.paidByName),
_buildInfoRow(Icons.calendar_today, 'Date', dateFormat.format(expense.date)),
_buildInfoRow(Icons.access_time, 'Heure', timeFormat.format(expense.createdAt)),
if (expense.isEdited && expense.editedAt != null)
_buildInfoRow(
Icons.edit,
@@ -143,7 +166,7 @@ class ExpenseDetailDialog extends StatelessWidget {
const Divider(),
const SizedBox(height: 8),
// Divisions
// Splits section.
const Text(
'Répartition',
style: TextStyle(
@@ -156,7 +179,7 @@ class ExpenseDetailDialog extends StatelessWidget {
const SizedBox(height: 16),
// Reçu
// Receipt section.
if (expense.receiptUrl != null) ...[
const Divider(),
const SizedBox(height: 8),
@@ -188,7 +211,7 @@ class ExpenseDetailDialog extends StatelessWidget {
const SizedBox(height: 16),
// Bouton archiver
// Archive button.
if (!expense.isArchived && canEdit)
OutlinedButton.icon(
onPressed: () => _confirmArchive(context),
@@ -204,6 +227,7 @@ class ExpenseDetailDialog extends StatelessWidget {
);
}
/// Builds a row displaying an icon, a label, and a value.
Widget _buildInfoRow(IconData icon, String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
@@ -231,6 +255,10 @@ class ExpenseDetailDialog extends StatelessWidget {
);
}
/// Builds a tile displaying details about a split in the expense.
///
/// The tile shows the user's name, the split amount, and whether the split is paid. If the current user
/// is responsible for the split and it is unpaid, a button is provided to mark it as paid.
Widget _buildSplitTile(BuildContext context, ExpenseSplit split) {
return BlocBuilder<UserBloc, user_state.UserState>(
builder: (context, userState) {
@@ -283,6 +311,7 @@ class ExpenseDetailDialog extends StatelessWidget {
);
}
/// Shows a dialog for editing the expense.
void _showEditDialog(BuildContext context, user_state.UserModel currentUser) {
showDialog(
context: context,
@@ -297,6 +326,7 @@ class ExpenseDetailDialog extends StatelessWidget {
);
}
/// Shows a confirmation dialog for deleting the expense.
void _confirmDelete(BuildContext context) {
showDialog(
context: context,
@@ -324,6 +354,7 @@ class ExpenseDetailDialog extends StatelessWidget {
);
}
/// Shows a confirmation dialog for archiving the expense.
void _confirmArchive(BuildContext context) {
showDialog(
context: context,