Init
This commit is contained in:
commit
295625c70f
151 files changed
+10677
No files matched your search
@@ -0,0 +1,148 @@
|
||||
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
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user