main.
dart
```
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:personal_life_manager/todo_list.dart';
import 'package:hive_flutter/adapters.dart';
import 'expense_tracker.dart';
import 'food_tracker.dart';
// TODO: edit option, future list, past list
void main() async {
await Hive.initFlutter();
ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Error'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.error_outline_outlined,
color: Colors.red,
size: 100,
),
Text(
kReleaseMode
? 'Oops... something went wrong'
: errorDetails.exception.toString(),
),
],
),
),
),
);
};
runApp(
const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
)
);
}
class HomePage extends StatefulWidget {
final int initialPageIndex;
const HomePage({super.key, this.initialPageIndex = 0});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _selectedIndex = 0;
static final List<Widget> _widgetOptions = <Widget>[
const TodoListPage(),
const FoodTrackerPage(),
const ExpenseTrackerPage(),
];
void pageChanged(int index) {
setState(() {
_selectedIndex = index;
});
}
Widget buildPageView() {
return PageView(
controller: pageController,
onPageChanged: (index) {
pageChanged(index);
},
children: _widgetOptions);
}
PageController pageController = PageController(
initialPage: 0,
keepPage: true,
);
void bottomTapped(int index) {
setState(() {
_selectedIndex = index;
pageController.animateToPage(index,
duration: const Duration(milliseconds: 500), curve: Curves.ease);
});
}
@override
void initState() {
_selectedIndex = widget.initialPageIndex;
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PopScope(
onPopInvoked: (val) async {
final confirmed = await showExitDialog(context);
if (confirmed) {
// Perform exit logic here
}
},
child: Center(
child: buildPageView(),
),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.checklist),
label: 'Todo',
),
BottomNavigationBarItem(
icon: Icon(Icons.food_bank_rounded),
label: 'Food',
),
BottomNavigationBarItem(
icon: Icon(Icons.currency_rupee),
label: 'Expenses',
),
],
currentIndex: _selectedIndex,
unselectedItemColor: Colors.black.withAlpha(127),
selectedItemColor: Colors.black,
onTap: (index) => bottomTapped(index),
iconSize: 24,
selectedFontSize: 12.0,
unselectedFontSize: 12.0,
backgroundColor: Colors.grey.shade50,
selectedLabelStyle: const TextStyle(
fontWeight: FontWeight.w900),
unselectedLabelStyle: const TextStyle(
fontWeight: FontWeight.w900,
),
),
);
}
}
getDateAndTime() {
List<String> Month = ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'];
List<String> WeekDay = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday", "Sunday"];
var now = DateTime.now();
var date =
'${now.day} ${Month[now.month-1]} ${now.year}';
var weekday = now.weekday;
return '${WeekDay[weekday-1]}, $date';
}
Future<bool> showExitDialog(BuildContext context) async {
final result = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Confirmation'),
content: const Text('Are you sure you want to exit?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('Exit'),
),
],
),
);
return result ?? false;
}
```
todo_list.dart
```
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'main.dart';
var box;
List _todoListItems = [];
class TodoListPage extends StatefulWidget {
const TodoListPage({super.key});
@override
State<TodoListPage> createState() => _TodoListPageState();
}
class _TodoListPageState extends State<TodoListPage> {
Widget editTextBottom = const SizedBox(
height: 0,
width: 0,
);
Widget floatingButton = const SizedBox(
height: 0,
width: 0,
);
Widget initialFloatingButton() {
return ElevatedButton(
onPressed: () => takeInput(addTodo, ""),
child: const Icon(
Icons.add,
size: 50,
),
);
}
@override
void initState() {
getListItems();
setState(() {
floatingButton = initialFloatingButton();
});
super.initState();
}
closeTextBox() {
setState(() {
editTextBottom = const SizedBox(
height: 0,
width: 0,
);
floatingButton = initialFloatingButton();
});
}
getListItems() async {
box = await Hive.openBox('myBox');
List forToday = [];
List allItems = box.get('todoList') ?? [];
String dateToday = getDateAndTime();
for (var item in allItems) {
if(item['createdOnString'] == null) {
forToday.add(item);
} else if (item['createdOnString'] == dateToday) {
forToday.add(item);
}
}
_todoListItems = forToday;
setState(() {});
}
addTodo(String value) async {
_todoListItems
.add({
'title': value,
'val': false,
'createdOnString': getDateAndTime(),
'createdOn' : DateTime.now()
});
box ??= await Hive.openBox('myBox');
box.put('todoList', _todoListItems);
closeTextBox();
}
takeInput(Function afterInput, String initVal) {
setState(() {
// hiding floating action button
floatingButton = const SizedBox(
height: 0,
width: 0,
);
editTextBottom = SizedBox(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextFormField(
initialValue: initVal,
autofocus: true,
// onFieldSubmitted: (value) => afterInput(value),
// onTapOutside: (e) => closeTextBox(),
decoration: InputDecoration(
labelText: initVal == "" ? 'Add your ToDo' : 'Edit your ToDo',
border: const OutlineInputBorder(),
),
),
SizedBox(height: 50,),
ElevatedButton(
style: ElevatedButton.styleFrom(
fixedSize: const Size(500.0, 50.0),
),
onPressed: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2100),
);
},
child: Text('Pick Date'),
),
SizedBox(height: 50,),
DropdownButtonFormField<String>(
// value: todoItem.repeatFrequency,
onChanged: (newValue) {
setState(() {
// todoItem.repeatFrequency = newValue!;
});
},
items: <String>['Daily', 'Weekly', 'Monthly',
'Yearly'].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
],
),
),
);
});
}
int _indexToEdit = 0;
editTodoHelper(String value) {
_todoListItems[_indexToEdit]['title'] = value;
box.put('todoList', _todoListItems);
setState(() {
closeTextBox();
});
}
editTodo(int index) {
_indexToEdit = index;
takeInput(editTodoHelper, _todoListItems[index]['title']);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 10,
// centerTitle: true,
title: Text(getDateAndTime()),
actions: [
PopupMenuButton(
onSelected: (value) async {
switch(value){
case 'Scheduled Tasks':
break;
case 'Today':
break;
case 'Previous Tasks':
break;
}
},
icon: const Icon(Icons.menu),
offset: const Offset(-1, 50),
itemBuilder: (context) => [
const PopupMenuItem(
value: 'Scheduled Tasks',
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Icon(Icons.more_time_rounded),
),
Text('Scheduled Tasks'),
],
),
),
const PopupMenuItem(
value: 'Today',
child: Row(
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Icon(Icons.access_time),
),
Text('Today'),
],
),
),
const PopupMenuItem(
value: 'Previous Tasks',
child: Row(
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Icon(Icons.timer_off_outlined),
),
Text('Previous Tasks'),
],
),
),
]),
],
),
floatingActionButton: floatingButton,
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
bottomSheet: BottomSheet(
onClosing: () {
const SizedBox(
height: 0,
width: 0,
);
},
builder: (BuildContext context) {
return editTextBottom;
},
),
body: SizedBox(
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: Column(
children: [
if (_todoListItems.isEmpty)
Center(
child: SizedBox(
height: 300,
child: Column(
children: [
Icon(
Icons.add,
size: 200,
color: Colors.grey.shade500,
),
const Text('Add some items to start your Journey!')
],
),
),
)
else
SizedBox(
height: 0.085 *
_todoListItems.length *
MediaQuery.of(context).size.height,
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 25),
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
String title = _todoListItems[index]['title'];
bool isChecked = _todoListItems[index]['val'];
String createdOnString = _todoListItems[index]
['createdOnString'] ??
getDateAndTime();
return Dismissible(
key: ValueKey<String>(title),
background: SizedBox(
height: 10,
child: Container(
color: Colors.red,
alignment: Alignment.centerLeft,
child: const Padding(
padding:
EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.delete),
),
)),
direction: DismissDirection.startToEnd,
onDismissed: (DismissDirection direction) {
Map? toRemove;
for (var element in _todoListItems) {
if (element['title'] == title) {
toRemove = element;
}
}
_todoListItems.remove(toRemove);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Item removed'),
duration: Duration(seconds: 1),
),
);
box.put('todoList', _todoListItems);
},
child: InkWell(
onLongPress: () => editTodo(index),
child: CheckboxListTile(
value: _todoListItems[index]['val'],
title: Text(
title,
style: TextStyle(
fontSize: 20,
decoration: isChecked
? TextDecoration.lineThrough
: TextDecoration.none),
),
onChanged: (bool? val) => setState(() {
_todoListItems[index]['val'] =
!_todoListItems[index]['val'];
box.put('todoList', _todoListItems);
}),
),
),
);
},
itemCount: _todoListItems.length,
),
),
),
],
),
)),
);
}
}
```