ok hi guys i need your help. i am creating a todolist app right now and then the todolist widget which is the main page of the todo list (basically showing the todo) is not working when I run the code it give me this error The following ProviderNotFoundException was thrown building TodoListWdiget(dirty): Error: Could not find the correct Provider above this TodoListWdiget Widget
This happens because you used a BuildContext
that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your
main.dart
and performed a hot-reload. To fix, perform a hot-restart.The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then other routes will not be able to access that provider.
You used a
BuildContext
that is an ancestor of the provider you are trying to read.Make sure that TodoListWdiget is under your MultiProvider/Provider. This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // Will throw a ProviderNotFoundError, because `context` is associated // to the widget that is the parent of `Provider<Example>` child: Text(context.watch<Example>()), ), }
consider using
builder
like so:Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // we use `builder` to obtain a new `BuildContext` that has access to the provider builder: (context) { // No longer throws return Text(context.watch<Example>()), } ), }
i try all the solution given but cannot help. so guys please help me. this my code for the TodoListWdiget
class TodoListWdiget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final provider = Provider.of<TodosProvider>(context);
///get things in todos provider from all the context
final todos = provider.todos;
///this means we will get provider and provider is
///things in the todosprovider and there is a variable call todos and store inside final todos here
return todos.isEmpty
? Center(
child: Text(
'no todos',
style: TextStyle(fontSize: 20),
))
:
ListView.separated(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(16),
itemBuilder: (context, index) {
final todo = todos[index];
return TodoWidget(
todo:
todo); //it means all the things in the todo that we have written
},
separatorBuilder: (context, index) => SizedBox(height: 8),
itemCount: todos.length);
}
}
whole code of this todo list app
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'utils.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'todolist',
theme: ThemeData(
primarySwatch: Colors.pink,
scaffoldBackgroundColor: Color(0xFFf6f5ee),
),
home: hompage(),
);
}
}
class hompage extends StatefulWidget {
@override
_hompageState createState() => _hompageState();
}
class _hompageState extends State<hompage> {
int selectedindex = 0;
final tabs = [
TodoListWdiget(),
Completedtodolist(),
];
final _formKey = GlobalKey<FormState>();
String title = '';
String description = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('todolist'),
),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.white.withOpacity(1.0),
selectedItemColor: Colors.white,
currentIndex: selectedindex,
onTap: (index) => setState(() {
selectedindex = index;
}),
items: [
BottomNavigationBarItem(
icon: Icon(Icons.fact_check_outlined),
label: 'todo',
),
BottomNavigationBarItem(
icon: Icon(
Icons.done,
size: 28,
),
label: 'done',
),
],
),
body: tabs[selectedindex],
floatingActionButton: FloatingActionButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
backgroundColor: Colors.black,
onPressed: () {
showtextfield();
},
child: Icon(Icons.add),
),
);
}
///after press show the dialog
showtextfield() {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
content: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'add todo',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
),
const SizedBox(height: 8),
todoformwidget(
onChangedTitle: (title) =>
setState(() => this.title = title),
onChangeDescription: (description) =>
setState(() => this.description = description),
onSavedTodo: addTodo,
),
],
),
),
);
});
}
void addTodo() {
final isValid = _formKey.currentState!.validate();
if (isValid) {
final todo = Todo(
id: DateTime.now().toString(),
title: title,
description: description,
createdTime: DateTime.now(),
);
final provider = Provider.of<TodosProvider>(context, listen: false);
provider.addTodo(todo);
Navigator.of(context).pop();
} else {
return;
}
}
}
class todoformwidget extends StatelessWidget {
final String title;
final String description;
final ValueChanged<String> onChangedTitle;
final ValueChanged<String> onChangeDescription;
final VoidCallback onSavedTodo;
const todoformwidget({
this.title = '',
this.description = '',
required this.onChangeDescription,
required this.onChangedTitle,
required this.onSavedTodo,
});
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
buildTitle(),
SizedBox(height: 8),
buildDescription(),
SizedBox(height: 8),
buildButton(),
],
),
);
}
Widget buildTitle() => TextFormField(
autofocus: true,
initialValue: title,
validator: (title) {
if (title != null) {
title.isEmpty ? 'Enter an email' : null;
}
},
decoration: InputDecoration(
border: UnderlineInputBorder(),
labelText: 'title',
),
onChanged: onChangedTitle,
);
Widget buildDescription() => TextFormField(
autofocus: true,
initialValue: description,
decoration: InputDecoration(
border: UnderlineInputBorder(),
labelText: 'Description',
),
onChanged: onChangeDescription,
);
Widget buildButton() => SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black),
),
onPressed: onSavedTodo,
child: Text('Save'),
),
);
}
class TodosProvider extends ChangeNotifier {
// all the task is going to be here
List<Todo> _todos = [
Todo(
createdTime: DateTime.now(),
title: 'Buy Food ',
description: '''- Eggs
- Milk
- Bread
- Water''',
),
Todo(
createdTime: DateTime.now(),
title: 'Plan family trip to Norway',
description: '''- Rent some hotels
- Rent a car
- Pack suitcase''',
),
Todo(
createdTime: DateTime.now(),
title: 'Walk the Dog ',
),
Todo(
createdTime: DateTime.now(),
title: 'Plan Jacobs birthday party ',
),
];
List<Todo> get todos => _todos.where((todo) => todo.isDone == false).toList();
///add todo function is the todo thing that requried name todo here and then
void addTodo(Todo todo) {
_todos.add(todo);
notifyListeners();
}
void updateTodo(Todo todo, String title, String description) {
todo.title = title;
todo.description = description;
notifyListeners();
}
void removeTodo(Todo todo) {
_todos.remove(todo);
notifyListeners();
}
bool toggleTodoStatus(Todo todo) {
todo.isDone = !todo.isDone;
notifyListeners();
return todo.isDone;
}
List<Todo> get todosCompleted =>
_todos.where((todo) => todo.isDone == true).toList();
}
/// this list of todo and we want to get it public where the todo here that is only
/// false will be in this public todos list
///things required for the todo widget means the todo box
class TodoField {
static const createdTime = 'createdTime';
}
class Todo {
DateTime createdTime;
String title;
String id;
String description;
bool isDone;
Todo({
required this.createdTime,
required this.title,
this.description = '',
this.id = '',
this.isDone = false,
});
}
///this is the whole box thing
class TodoListWdiget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final provider = Provider.of<TodosProvider>(context);
///get things in todos provider from all the context
final todos = provider.todos;
///this means we will get provider and provider is
///things in the todosprovider and there is a variable call todos and store inside final todos here
return todos.isEmpty
? Center(
child: Text(
'no todos',
style: TextStyle(fontSize: 20),
))
:
ListView.separated(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(16),
itemBuilder: (context, index) {
final todo = todos[index];
return TodoWidget(
todo:
todo); //it means all the things in the todo that we have written
},
separatorBuilder: (context, index) => SizedBox(height: 8),
itemCount: todos.length);
}
}
///create the box thing of a todolist
class TodoWidget extends StatelessWidget {
const TodoWidget({required this.todo, Key? key}) : super(key: key);
final Todo todo;
@override
Widget build(BuildContext context) => ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Slidable(
child: buildTodo(context),
actionPane: SlidableDrawerActionPane(),
key: Key(todo.id),
// show text
actionExtentRatio: 0.30,
actions: [
IconSlideAction(
color: Colors.green,
onTap: editTodo(context, todo),
caption: 'edit',
icon: Icons.edit),
],
secondaryActions: [
IconSlideAction(
color: Colors.red,
onTap: deletetodo(context, todo),
caption: 'delete',
icon: Icons.delete,
),
],
));
Widget buildTodo(BuildContext context) => Container(
padding: EdgeInsets.all(20),
color: Colors.white,
child: Row(
children: [
Checkbox(
activeColor: Theme.of(context).primaryColor,
value: todo.isDone,
onChanged: (_) {
final provider =
Provider.of<TodosProvider>(context, listen: false);
final isDone = provider.toggleTodoStatus(todo);
Utils.showSnackBar(context,
isDone ? 'task completed' : 'task marked incomplete');
},
checkColor: Colors.white,
),
SizedBox(
width: 20,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
todo.title,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor,
fontSize: 22,
),
),
if (todo.description.isNotEmpty)
Container(
margin: EdgeInsets.only(top: 4),
child: Text(
todo.description,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor,
fontSize: 22,
),
),
)
],
))
],
),
);
deletetodo(BuildContext context, Todo todo) {
final provider = Provider.of<TodosProvider>(context, listen: false);
provider.removeTodo(todo);
///showsnackbar(context);
Utils.showSnackBar(context, 'delete the task');
}
///void showsnackbar(BuildContext context,Todo todo){
/// final snackbar =SnackBar(
///content:Text(context,'has been delete',style:TextStyle(fontSize:16)
/// );
/// Scaffold.of(context)..showSnackBar(snackbar);
/// }
editTodo(BuildContext context, Todo todo) => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => EditTodoPage(todo: todo),
),
);
}
class EditTodoPage extends StatefulWidget {
final Todo todo;
const EditTodoPage({
Key? key,
required this.todo,
}) : super(key: key);
@override
_EditTodoPageState createState() => _EditTodoPageState();
}
class _EditTodoPageState extends State<EditTodoPage> {
final _formKey = GlobalKey<FormState>();
String title = '';
String description = '';
@override
void initState() {
// TODO: implement initState
super.initState();
title = widget.todo.title;
description = widget.todo.description;
}
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text('Edit Todo'),
actions: [
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
final provider =
Provider.of<TodosProvider>(context, listen: false);
provider.removeTodo(widget.todo);
Navigator.of(context).pop();
},
)
],
),
body: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: todoformwidget(
title: title,
description: description,
onChangedTitle: (title) => setState(() => this.title = title),
onChangeDescription: (description) =>
setState(() => this.description = description),
onSavedTodo: saveTodo,
),
),
),
);
void saveTodo() {
final isValid = _formKey.currentState!.validate();
if (!isValid) {
return;
} else {
final provider = Provider.of<TodosProvider>(context, listen: false);
provider.updateTodo(widget.todo, title, description);
Navigator.of(context).pop();
}
}
}
class Completedtodolist extends StatelessWidget {
const Completedtodolist({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final provider = Provider.of<TodosProvider>(context);
final todos = provider.todosCompleted;
return todos.isEmpty ?Center(
child: Text(
'No completed tasks.',
style: TextStyle(fontSize: 20),
),
):ListView.separated(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(40),
itemBuilder:(context, index) {
final todo = todos[index];
return TodoWidget(todo: todo);
},
separatorBuilder: (context, index) => SizedBox(height: 8),
itemCount: todos.length,);
}
}
class Utils{
static late BuildContext context;
static void showSnackBar(BuildContext,String text)=>
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content:Text(text)));
}