149 lines
5.7 KiB
Dart
149 lines
5.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart'; // For date formatting
|
|
|
|
import '../models/transaction_record.dart'; // Use the model class
|
|
|
|
class TransactionListItem extends StatelessWidget {
|
|
final TransactionRecord transaction; // Use the model class
|
|
final VoidCallback? onEdit; // Callback for edit action
|
|
final VoidCallback? onDelete; // Callback for delete action
|
|
|
|
const TransactionListItem({
|
|
Key? key,
|
|
required this.transaction,
|
|
this.onEdit, // Make callbacks optional
|
|
this.onDelete,
|
|
}) : super(key: key);
|
|
|
|
// Function to show the options menu
|
|
void _showOptionsMenu(BuildContext context) {
|
|
showModalBottomSheet(
|
|
context: context,
|
|
builder: (context) {
|
|
return SafeArea( // Use SafeArea to avoid system UI
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min, // Take minimum space
|
|
children: <Widget>[
|
|
ListTile(
|
|
leading: const Icon(Icons.edit_outlined),
|
|
title: const Text('Редактировать'),
|
|
onTap: () {
|
|
Navigator.pop(context); // Close the bottom sheet
|
|
onEdit?.call(); // Call the edit callback if it exists
|
|
},
|
|
),
|
|
ListTile(
|
|
leading: const Icon(Icons.delete_outline, color: Colors.red),
|
|
title: const Text('Удалить', style: TextStyle(color: Colors.red)),
|
|
onTap: () {
|
|
Navigator.pop(context); // Close the bottom sheet
|
|
onDelete?.call(); // Call the delete callback if it exists
|
|
},
|
|
),
|
|
// Optional: Add a Cancel button
|
|
ListTile(
|
|
leading: const Icon(Icons.cancel_outlined),
|
|
title: const Text('Отмена'),
|
|
onTap: () => Navigator.pop(context),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final isExpense = transaction.type == 'expense';
|
|
final theme = Theme.of(context);
|
|
|
|
// Wrap the ListTile in an InkWell to handle long press
|
|
return InkWell(
|
|
onLongPress: () => _showOptionsMenu(context), // Show menu on long press
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), // Adjusted padding
|
|
child: Row(
|
|
children: [
|
|
// Category Icon (only for expenses)
|
|
if (isExpense && transaction.category != null)
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: transaction.category!.colorCode.withOpacity(0.1), // Use category color
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(
|
|
transaction.category!.iconCode, // Use category icon
|
|
color: transaction.category!.colorCode,
|
|
size: 20,
|
|
),
|
|
)
|
|
else if (!isExpense) // Icon for Income
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.green.shade100, // Specific color for income icon background
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(
|
|
Icons.attach_money_outlined, // Specific icon for income
|
|
color: Colors.green.shade700,
|
|
size: 20,
|
|
),
|
|
),
|
|
const SizedBox(width: 16), // Space between icon and text
|
|
|
|
// Transaction Details (Category/Merchant, Date)
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
isExpense ? transaction.merchant : transaction.merchant, // Display merchant for both for now
|
|
style: theme.textTheme.titleMedium?.copyWith(
|
|
fontWeight: FontWeight.w500, // Medium weight
|
|
),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis, // Prevent overflow
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
// Display category name for expense, or 'Income' for income
|
|
isExpense ? transaction.category?.name ?? 'Unknown Category' : 'Income',
|
|
style: theme.textTheme.bodySmall?.copyWith(
|
|
color: theme.textTheme.bodySmall?.color?.withOpacity(0.7), // Subtle color
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
// Amount and Date
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
children: [
|
|
Text(
|
|
'${isExpense ? '-' : '+'} \$${NumberFormat.currency(symbol: '', decimalDigits: 2).format(transaction.amount)}', // Format amount with sign
|
|
style: theme.textTheme.titleMedium?.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
color: isExpense ? Colors.red.shade600 : Colors.green.shade600, // Color based on type
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
DateFormat('MMM d, yyyy').format(transaction.date), // Format date
|
|
style: theme.textTheme.bodySmall?.copyWith(
|
|
color: theme.textTheme.bodySmall?.color?.withOpacity(0.7), // Subtle color
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|