I am building a flutter app and passing data from addTaskScreen to the homeScreen using navigation. But when I am pressing the back button from homeScreen, the app is going to the previous state and shows previous un-updated data. How to prevent it.
Here is the code of my two screens,
home screen:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:todo/database/database.dart';
import 'package:todo/hidden_screen.dart';
import 'package:todo/models/task_model.dart';
// import 'package:sqflite/sqflite.dart';
import 'add_todo_screen.dart';
// ignore: use_key_in_widget_constructors
class HomeScreen extends StatefulWidget {
// const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
late Future<List<Task>> _taskList;
final DateFormat _dateFormatter = DateFormat('MMM dd, yyyy');
// ignore: unused_field
final DatabaseHelper _databaseHelper = DatabaseHelper.instance;
@override
void initState() {
super.initState();
_updateTaskList();
}
_updateTaskList() {
_taskList = DatabaseHelper.instance.getTaskList();
}
Widget _buildTask(Task task) {
return Column(
children: [
ListTile(
title: Text(
task.title!,
style: TextStyle(
fontFamily: 'Mordred',
color: task.status == 0 ? Colors.black87 : Colors.black12,
decoration: task.status == 0
? TextDecoration.none
: TextDecoration.lineThrough,
),
),
subtitle: Text(
'${_dateFormatter.format(task.date!)} - ${task.priority}',
style: TextStyle(
fontFamily: 'Mordred',
color: task.status == 0 ? Colors.black87 : Colors.black12,
decoration: task.status == 0
? TextDecoration.none
: TextDecoration.lineThrough,
),
),
trailing: Checkbox(
checkColor: Colors.black,
tristate: false,
onChanged: (value) {
// print(value);
task.status = value! ? 1 : 0;
DatabaseHelper.instance.updateTask(task);
_updateTaskList();
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => HomeScreen(),
),
);
},
activeColor: Theme.of(context).primaryColor,
value: task.status == 1 ? true : false,
),
onTap: () => Navigator.push(
context,
CupertinoPageRoute(
builder: (_) => AddToDoScreen(
updateTaskList: _updateTaskList(),
task: task,
),
),
),
),
const Divider(
height: 20,
thickness: 20,
)
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lime[100],
appBar: AppBar(
leading: GestureDetector(
onLongPress: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (_) => const HiddenScreen(),
),
);
},
child: const Padding(
padding: EdgeInsets.fromLTRB(10, 10, 0, 5),
// child: Icon(
// Icons.tornado_rounded,
// color: Colors.lime[100],
// size: 30,
// ),
// child: Image.asset(
// 'assets/images/box.gif',
// fit: BoxFit.cover,
// ),
child: CircleAvatar(
backgroundImage: AssetImage(
'assets/images/box.gif',
),
),
),
),
title: const Text(
'Things To Do',
style: TextStyle(fontFamily: 'Binary X CHR', fontSize: 36),
),
elevation: 60,
),
floatingActionButton: FloatingActionButton(
backgroundColor: Theme.of(context).primaryColor,
onPressed: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (_) => AddToDoScreen(
updateTaskList: _updateTaskList,
),
),
);
},
child: const Icon(Icons.ac_unit_rounded),
),
body: FutureBuilder(
future: _taskList,
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
final int completedTaskCount = snapshot.data!
.where((Task task) => task.status == 1)
.toList()
.length;
return ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 20.0),
itemCount: int.parse(snapshot.data!.length.toString()) + 1,
itemBuilder: (BuildContext conntext, int index) {
if (index == 0) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 40,
vertical: 30,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text(
'MY TASK',
style: TextStyle(
color: Colors.black38,
fontFamily: 'Binary X CHR',
fontSize: 40,
// fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 10,
),
Text(
'$completedTaskCount out of ${snapshot.data.length} Completed',
style: const TextStyle(
color: Colors.black38,
fontFamily: 'Binary X CHR',
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
],
),
);
}
return _buildTask(snapshot.data![index - 1]);
},
);
},
),
);
}
}
add task screen:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:todo/database/database.dart';
import 'package:todo/home_screen.dart';
import 'models/task_model.dart';
class AddToDoScreen extends StatefulWidget {
// const AddToDoScreen({super.key});
final Task? task;
final Function? updateTaskList;
const AddToDoScreen({super.key, this.task, this.updateTaskList});
@override
State<AddToDoScreen> createState() => _AddToDoScreenState();
}
class _AddToDoScreenState extends State<AddToDoScreen> {
final _formKey = GlobalKey<FormState>();
String _title = '';
String _priority = 'Low';
DateTime _date = DateTime.now();
String btnText = "Add Task";
String titleText = "Add Title";
final TextEditingController _dateController = TextEditingController();
final DateFormat _dateFormatter = DateFormat('MMM dd, yyyy');
final List<String> _priorities = ['Low', 'Medium', 'High'];
@override
void initState() {
super.initState();
if (widget.task != null) {
_title = widget.task!.title!;
_date = widget.task!.date!;
_priority = widget.task!.priority!;
setState(() {
btnText = "Update Task";
titleText = "Update Task";
});
} else {
setState(() {
btnText = "Add Task";
titleText = "Add Task";
});
}
_dateController.text = _dateFormatter.format(_date);
}
@override
void dispose() {
_dateController.dispose();
super.dispose();
}
_handleDatePicker() async {
final DateTime? date = await showDatePicker(
context: context,
initialDate: _date,
firstDate: DateTime(1900),
lastDate: DateTime(2100),
);
if (date != null && date != _date) {
setState(() {
_date = date;
});
_dateController.text = _dateFormatter.format(date);
}
}
_delete() {
DatabaseHelper.instance.deleteTask(widget.task!.id!);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => HomeScreen(),
),
);
widget.updateTaskList!();
}
_submit() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
// print to check if the data is saving to database or not
// print('$_title, $_date, $_priority');
Task task = Task(title: _title, date: _date, priority: _priority);
if (widget.task == null) {
task.status = 0;
DatabaseHelper.instance.insertTask(task);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => HomeScreen(),
),
);
} else {
task.id = widget.task!.id;
task.status = widget.task!.status;
DatabaseHelper.instance.updateTask(task);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => HomeScreen(),
),
);
Navigator.pop(
context,
MaterialPageRoute(
builder: (_) => HomeScreen(),
),
);
}
widget.updateTaskList!();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lime[100],
body: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: SingleChildScrollView(
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
GestureDetector(
onTap: () => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => HomeScreen(),
),
),
child: Icon(
Icons.arrow_back_ios_new_rounded,
size: 30.0,
color: Theme.of(context).primaryColor,
),
),
const SizedBox(
height: 20.0,
),
Text(
titleText,
style: const TextStyle(
fontSize: 40,
fontFamily: 'Mordred',
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 10,
),
Form(
key: _formKey,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
),
child: TextFormField(
style: const TextStyle(
fontSize: 18.0,
fontFamily: 'Mordred',
),
decoration: InputDecoration(
labelText: 'Title',
labelStyle: const TextStyle(
// color: Colors.black,
fontSize: 18,
fontFamily: 'Mordred',
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
validator: (input) => input!.trim().isEmpty
? 'Please enter a task title'
: null,
onSaved: (input) => _title = input!,
initialValue: _title,
),
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
),
child: TextFormField(
readOnly: true,
controller: _dateController,
onTap: _handleDatePicker,
style: const TextStyle(
fontSize: 18.0,
fontFamily: 'Mordred',
),
decoration: InputDecoration(
labelText: 'Date',
labelStyle: const TextStyle(
fontSize: 18,
fontFamily: 'Mordred',
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: DropdownButtonFormField(
isDense: true,
icon: const Icon(Icons.double_arrow_rounded),
iconSize: 20,
iconEnabledColor: Theme.of(context).primaryColor,
iconDisabledColor: Colors.black54,
items: _priorities.map((String priority) {
return DropdownMenuItem(
value: priority,
child: Text(
priority,
style: const TextStyle(
color: Colors.black54,
fontSize: 18,
fontFamily: 'Mordred'),
),
);
}).toList(),
style: const TextStyle(fontSize: 18),
decoration: InputDecoration(
labelText: 'Priority',
labelStyle: const TextStyle(
fontSize: 18,
fontFamily: 'Mordred',
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
value: _priority,
// ignore: unnecessary_null_comparison
validator: (input) => _priority == null
? 'Please select a priority level'
: null,
onChanged: (value) {
setState(
() {
_priority = value.toString();
},
);
},
),
),
Container(
margin: const EdgeInsets.fromLTRB(0, 10, 0, 10),
height: 60.0,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.lime),
),
onPressed: _submit,
child: Text(
btnText,
style: TextStyle(
color: Colors.lime[100],
fontSize: 20,
fontFamily: 'Mordred',
),
),
),
),
widget.task != null
? Container(
margin: const EdgeInsets.fromLTRB(0, 20, 0, 0),
height: 60.0,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.lime),
),
onPressed: _delete,
child: Text(
'Delete Task',
style: TextStyle(
color: Colors.lime[100],
fontSize: 20,
fontFamily: 'Mordred',
),
),
),
)
: const SizedBox.shrink(),
],
),
),
],
),
),
),
),
);
}
}
3
Answers
Thanks, everyone for the answers. And I have found the solution and it helped me to solve the problem. I have just used pushAndRemoveUntil instead of pushReplacement.
Here is my code with problem part:
And here is the solution:
You have the following section in your code:
This might make it go to the home screen and then pop to a previous state again?
Maybe take the pop out.
If you are still struggling with the data not updating, you might need to just add a
setState(() {})
around your update call.Instead of using pop, you should push the user to the page. Much like onions, apps have (previously loaded)layers. Try this in the AppBar: