Part 1
Use Provider to get data across the app
1 - Install Provider in .yaml file and get packages
2 - Build mindmap of a simple Provider implementation
3 - Build mindmap for Todoey app and Provider implementation
- How to use Provider with ListView and its tiles(parts 3 and 4)
- Buttons updating state (part 2) 4 - Start writing code ###Create TaskData class Properties tasks = []; (lift from tasks list)
Getter for taskCount
int get taskCount {
return tasks.length;
}
Void addNewTasks() { // addTask to list ; notifyListeners(); }
void addNewTasks(String newTaskTitle) {
final task = Task(name: newTaskTitle);
tasks.add(task);
notifyListeners();
}
Update root to access data at highest level
Got an error The argument type 'Widget Function(BuildContext)' can't be assigned to the parameter type 'Widget Function(BuildContext, Widget).
Turns out using builder is deprecated and we must use create instead. (April 16/ 2021).
Tasks Screen
Update Text widget to provide number of tasks
'${Provider.of<TaskData>(context).tasks.length}',
Comment out SetState in AddTaskScreen
Convert to stateless widget since we are no longer using setState
Update TaskListobject to not need any property constructors
Tasks List
Import provider and task_data
Delete tasks property, won’t be needed anymore, the constructor is not needed either
Replace ToDoItem constructor data, depending on which property you are trying to access
Provider.of<TaskData>(context).tasks[index].name
Also comment out setState
Convert to stateless widget since we are no longer using setState
The Consumer Widget from Provider
To not have to repeat all the places where Provider.of<TaskData>(context).tasks[index].name
is going to be accessed.
Wrap highest level widget where these will be used
In our case in Tasks List is the List View widget
End up with this
return Consumer<TaskData>(
builder: (context, taskData, child) {
Return ListView….;
},
child: ListView.builder(
Now taskData can replace Provider.of<TaskData>(context)
Part 2
Add Tasks to list functionality
AddTasks Screen
Button
onPressed: () {
//newValue comes from textfield input
Provider.of<TaskData>(context, listen: false)
.addNewTasks(newTaskTitle);
Navigator.pop(context);
},
Part 3
Functionality for tile’s state
Task Data
void updateTask(Task task) {
task.toggleDone();
}
Task Tile
Tasks List (nothing specific to Provider, except for the use of updateTask)
final task = taskData.tasks[index];
return TodoItem(
newTodoItem: task.name,
tapped: task.isDone,
iconCallBack: (bool checkBoxState) {
TaskData().updateTask(task);
});
With current setup, it should work, but Tasks Screen only updated when the button is pressed in the Add Tasks Screen. I think it is related to changes / updates in Provider. Related to that I had to set the listen: false . .. Maybe it is because we are using Consumer
SUCCESS! Because of changes made to the newer versions of Provider package, where we need to set the listen property to false. Even though we are inside Consumer, we still need to access updateTask calling through explicitly calling Provider to be able to set the listen property to false. This way the widget can rerender.
final task = taskData.tasks[index];
return TodoItem(
newTodoItem: task.name,
tapped: task.isDone,
iconCallBack: (checkBoxState) {
Provider.of<TaskData>(context, listen: false)
.updateTask(task);
});
Part 4
Delete Tasks
1 create new method in TaskData model to delete the task
void deleteTask(Task task) {
_tasks.remove(task);
notifyListeners();
}
2 - create a new callback in the TodoItem constructor
final Function longPressCallBack;
TodoItem({this.newTodoItem, this.tapped, this.iconCallBack, this.longPressCallBack});
3 - ListTile has a property - onLongPress, which is where we’ll call the new property in the constructor
return ListTile(
onLongPress: longPressCallBack,
4 - Update TodoItem constructor in the TasksList Widget
longPressCallBack: () {
Provider.of<TaskData>(context, listen: false)
.deleteTask(task);
},);
5 - The TaskScreen creates a new TasksList Widget as a child, so it should get all this information and update. DONE!