Files
TravelMate/lib/components/account/expenses_tab.dart
Van Leemput Dayron 13933fc56c Resolve map problem.
2025-12-06 15:50:19 +01:00

209 lines
6.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../models/expense.dart';
import '../../models/group.dart';
import 'expense_detail_dialog.dart';
class ExpensesTab extends StatelessWidget {
final List<Expense> expenses;
final Group group;
final String currentUserId;
const ExpensesTab({
super.key,
required this.expenses,
required this.group,
required this.currentUserId,
});
@override
Widget build(BuildContext context) {
if (expenses.isEmpty) {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.receipt_long, size: 80, color: Colors.grey),
SizedBox(height: 16),
Text(
'Aucune dépense',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text(
'Ajoutez votre première dépense',
style: TextStyle(fontSize: 14, color: Colors.grey),
),
],
),
);
}
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: expenses.length,
itemBuilder: (context, index) {
final expense = expenses[index];
return _buildExpenseCard(context, expense);
},
);
}
Widget _buildExpenseCard(BuildContext context, Expense expense) {
final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
final dateFormat = DateFormat('dd/MM');
// Logique pour déterminer l'impact sur l'utilisateur
bool isPayer = expense.paidById == currentUserId;
double amountToDisplay = expense.amount;
bool isPositive = isPayer;
// Si je suis le payeur, je suis en positif (on me doit de l'argent)
// Si je ne suis pas le payeur, je suis en négatif (je dois de l'argent)
// Note: Pour être précis, il faudrait calculer ma part exacte, mais pour l'instant
// on affiche le total avec la couleur indiquant si j'ai payé ou non.
final amountColor = isPositive ? Colors.green : Colors.red;
final prefix = isPositive ? '+' : '-';
return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: isDark ? theme.cardColor : Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.05),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _showExpenseDetail(context, expense),
borderRadius: BorderRadius.circular(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
// Icone circulaire
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: _getCategoryColor(
expense.category,
).withValues(alpha: 0.2),
shape: BoxShape.circle,
),
child: Icon(
expense.category.icon,
color: _getCategoryColor(expense.category),
size: 24,
),
),
const SizedBox(width: 16),
// Détails
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
expense.description,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Row(
children: [
Text(
isPayer
? 'Payé par vous'
: 'Payé par ${expense.paidByName}',
style: TextStyle(
fontSize: 13,
color: isDark
? Colors.grey[400]
: Colors.grey[600],
),
),
Text(
'${dateFormat.format(expense.date)}',
style: TextStyle(
fontSize: 13,
color: isDark
? Colors.grey[500]
: Colors.grey[500],
),
),
],
),
],
),
),
// Montant
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'$prefix${amountToDisplay.toStringAsFixed(2)} ${expense.currency.symbol}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: amountColor,
),
),
if (expense.currency != ExpenseCurrency.eur)
Text(
'Total ${expense.amountInEur.toStringAsFixed(2)}',
style: TextStyle(
fontSize: 11,
color: isDark ? Colors.grey[500] : Colors.grey[400],
),
),
],
),
],
),
),
),
),
);
}
Color _getCategoryColor(ExpenseCategory category) {
switch (category) {
case ExpenseCategory.restaurant:
return Colors.orange;
case ExpenseCategory.transport:
return Colors.blue;
case ExpenseCategory.accommodation:
return Colors.purple;
case ExpenseCategory.entertainment:
return Colors.pink;
case ExpenseCategory.shopping:
return Colors.teal;
case ExpenseCategory.other:
return Colors.grey;
case ExpenseCategory.reimbursement:
return Colors.green;
}
}
void _showExpenseDetail(BuildContext context, Expense expense) {
showDialog(
context: context,
builder: (context) => ExpenseDetailDialog(expense: expense, group: group),
);
}
}