-2

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)));

}
Gary Gan
  • 37
  • 1
  • 4

1 Answers1

1

Change this part of your code to look like this:

return MultiProvider(
      providers: [
        ChangeNotifierProvider<TodosProvider >(
          create: (_) => TodosProvider(),
        ),          
      ],
      builder: (context, child) {
        return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'todolist',
      theme: ThemeData(
        primarySwatch: Colors.pink,
        scaffoldBackgroundColor: Color(0xFFf6f5ee),
      ),
      home: hompage(),
    );
   });
  }
}

Add all other providers you intend to use inside the multiprovider also. Read up on providers, and how they are scoped, and that providers need to be inserted above children widgets who are going to use. We put it now above material because it's the very top of your widget tree.

Huthaifa Muayyad
  • 11,321
  • 3
  • 17
  • 49