11. Develop an application that tracks our daily Expenses and get a report chart.
Step to Run
- Open your Flutter project in VS Code.
- Open
lib/main.dart. - Delete the existing code.
- Paste the program code given below.
- Save the file.
- Run the program using
flutter runcmd
PROGRAM:
import 'package:flutter/material.dart';
void main() {
runApp(const ExpenseTrackerApp());
}
class ExpenseTrackerApp extends StatelessWidget {
const ExpenseTrackerApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Lab Program 11',
debugShowCheckedModeBanner: false,
home: const ExpenseTrackerScreen(),
);
}
}
class ExpenseTrackerScreen extends StatefulWidget {
const ExpenseTrackerScreen({super.key});
@override
State<ExpenseTrackerScreen> createState() => _ExpenseTrackerScreenState();
}
class _ExpenseTrackerScreenState extends State<ExpenseTrackerScreen> {
final TextEditingController titleController = TextEditingController();
final TextEditingController amountController = TextEditingController();
String selectedCategory = 'Food';
final List<String> categories = [
'Food',
'Travel',
'Shopping',
'Bills',
'Others',
];
final List<Map<String, dynamic>> expenses = [];
void addExpense() {
String title = titleController.text.trim();
double amount = double.tryParse(amountController.text) ?? 0;
if (title.isNotEmpty && amount > 0) {
setState(() {
expenses.add({
'title': title,
'amount': amount,
'category': selectedCategory,
});
titleController.clear();
amountController.clear();
selectedCategory = 'Food';
});
}
}
void deleteExpense(int index) {
setState(() {
expenses.removeAt(index);
});
}
double getTotalExpense() {
double total = 0;
for (var expense in expenses) {
total += expense['amount'];
}
return total;
}
Map<String, double> getCategoryTotals() {
Map<String, double> totals = {
'Food': 0,
'Travel': 0,
'Shopping': 0,
'Bills': 0,
'Others': 0,
};
for (var expense in expenses) {
totals[expense['category']] =
totals[expense['category']]! + expense['amount'];
}
return totals;
}
@override
void dispose() {
titleController.dispose();
amountController.dispose();
super.dispose();
}
Widget buildReportChart() {
Map<String, double> totals = getCategoryTotals();
double maxAmount = 1;
for (var amount in totals.values) {
if (amount > maxAmount) {
maxAmount = amount;
}
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: totals.entries.map((entry) {
double barWidth = entry.value / maxAmount;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
SizedBox(
width: 75,
child: Text(
entry.key,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(
child: Stack(
children: [
Container(
height: 24,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(12),
),
),
FractionallySizedBox(
widthFactor: barWidth,
child: Container(
height: 24,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(12),
),
),
),
],
),
),
const SizedBox(width: 8),
Text(
'₹${entry.value.toStringAsFixed(0)}',
style: const TextStyle(fontWeight: FontWeight.bold),
),
],
),
);
}).toList(),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Program 11: Expense Tracker'),
centerTitle: true,
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
TextField(
controller: titleController,
decoration: const InputDecoration(
labelText: 'Expense Title',
hintText: 'Example: Lunch',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.edit),
),
),
const SizedBox(height: 15),
TextField(
controller: amountController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Amount',
hintText: 'Example: 100',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.currency_rupee),
),
),
const SizedBox(height: 15),
DropdownButtonFormField<String>(
value: selectedCategory,
decoration: const InputDecoration(
labelText: 'Category',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.category),
),
items: categories.map((category) {
return DropdownMenuItem(
value: category,
child: Text(category),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedCategory = value!;
});
},
),
const SizedBox(height: 15),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: addExpense,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
),
child: const Text(
'Add Expense',
style: TextStyle(fontSize: 18),
),
),
),
const SizedBox(height: 20),
Card(
color: Colors.blue.shade50,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const Text(
'Total Expense',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
'₹${getTotalExpense().toStringAsFixed(2)}',
style: const TextStyle(
fontSize: 28,
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
const SizedBox(height: 20),
const Align(
alignment: Alignment.centerLeft,
child: Text(
'Expense Report Chart',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 10),
buildReportChart(),
const SizedBox(height: 20),
const Align(
alignment: Alignment.centerLeft,
child: Text(
'Expense List',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 10),
expenses.isEmpty
? const Text(
'No expenses added yet',
style: TextStyle(fontSize: 16),
)
: ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: expenses.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
child: Text('${index + 1}'),
),
title: Text(expenses[index]['title']),
subtitle: Text(expenses[index]['category']),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'₹${expenses[index]['amount'].toStringAsFixed(0)}',
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
IconButton(
icon: const Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
deleteExpense(index);
},
),
],
),
),
);
},
),
],
),
),
);
}
}OUTPUT:

