Closed OnyemaAnthony closed 3 years ago
Hello @OnyemaAnthony π
Here's the code properly formatted - more readable:
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:todo_list/models/todo_list_model.dart';
import 'package:todo_list/repository/database_repository.dart';
part 'task_event.dart';
part 'task_state.dart';
class TaskBloc extends Bloc<TaskEvent, TaskState> {
DatabaseRepository _repository;
TaskBloc({@required DatabaseRepository repository})
: assert(repository != null),
_repository = repository,
super(TaskInitial());
@override
TaskState get initialState => TaskInitial();
@override
Stream mapEventToState(
TaskEvent event,
) async* {
if (event is FetchAllTaskEvent) {
yield* _mapFetchAllTAskEventToState(event);
} else if (event is SaveTaskEvent) {
_mapSaveTaskEventToState(event);
}
}
Stream _mapFetchAllTAskEventToState(FetchAllTaskEvent event) async* {
yield TaskLoadingState();
TodoListModel task;
try {
List tasks = await _repository.geAllTask();
for (int i = 0; i < tasks.length; i++) {
task = TodoListModel.map(tasks[i]);
}
yield TaskLoadedState(task);
} catch (e) {
yield TaskErrorState(e.toString());
}
}
Stream _mapSaveTaskEventToState(SaveTaskEvent event) async* {
yield TaskLoadingState();
try {
int result = await _repository.saveTask(event.task);
yield TaskAddedState(result);
} catch (e) {
yield TaskErrorState(e.toString());
}
}
}
Do you have Equatable
implemented in the TaskEvent
class and subclasses? Could you debug the following, and see whether the app stops or not?
@override
Stream mapEventToState(
TaskEvent event,
) async* {
assert(event is SaveTaskEvent);
if (event is FetchAllTaskEvent) {
yield* _mapFetchAllTAskEventToState(event);
} else if (event is SaveTaskEvent) {
_mapSaveTaskEventToState(event);
}
}
We would need a bit more of information in order to guess where the error may be π
@mikededo thanks for your reply, what more information do you need,I created a class where I performed CRUD with sqflite DB,I used the class as the repository of the bloc then I tried adding an item to the DB from the UI and it's working well but when I migrate it to bloc and trigger the SaveTaskEvent it's shows on the log that the event was trigger but the Bloc is not being called
Are you using a BlocObserver
which prints when onEvent
is called? (Check this link from the docs).
Yea i used Bloc observer,am comfortable using Bloc with firebase Firestore as the repository, this is my first time of using sqflite and that is the first time am experiencing this error
With this:
I tried adding an item to the DB from the UI and it's working well
Do you mean that your databse reflectes the changes? Or no new item is added? π€
No new item was added, the function that adds the item is in the repository and the function was never called
The function that adds the item is called from the mapSaveTaskToState function,due to the Bloc was not called the item was not saved
The function that adds the item is called from the mapSaveTaskToState function,due to the Bloc was not called the item was not saved.
Yes, I expected that. It kind of strange, ngl. Could you attach some code, for instance, where do you call add the event? π
here is the code i use as my repository that is the sqflite file
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; import 'package:todo_list/models/todo_list_model.dart'; import 'package:todo_list/utility/utilities.dart';
class DatabaseRepository { static final DatabaseRepository _instance = DatabaseRepository.internal();
factory DatabaseRepository() => _instance;
static Database _db;
DatabaseRepository.internal();
Future
initDb() async { Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, 'tododb.db');
var dataBase = await openDatabase(path, version: 1, onCreate: _onCreate);
}
void _onCreate(Database db, int newVersion) async { await db.execute( "CREATE TABLE ${Utility.todoTable}(${Utility.id} INTEGER PRIMARY KEY, ${Utility.task} TEXT,${Utility.deadline}TEXT})"); }
Future
int result =
await dbClient.insert(Utility.todoTable, todoListModel.toMap());
return result;
}
Future geAllTask() async {
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM ${Utility.todoTable}");
return result.toList();
}
Future
return Sqflite.firstIntValue(
await dbClient.rawQuery("SELECT COUNT(*) FROM ${Utility.todoTable}"));
}
Future
var result = await dbClient.rawQuery(
"SELECT * FROM ${Utility.todoTable} WHERE ${Utility.id} = $id");
if (result.length == 0) {
return null;
} else {
return TodoListModel.fromMap(result.first);
}
}
Future
return await dbClient
.delete(Utility.todoTable, where: "${Utility.id} = ?", whereArgs: [id]);
}
Future
Future close()async{ var dbClient = await db; return dbClient.close(); } }
here is the ui part where am calling the event, am adding the event in the saveTask function
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:todo_list/bloc/task/task_bloc.dart';
import 'package:todo_list/models/todo_list_model.dart';
import 'package:todo_list/repository/database_repository.dart';
import 'package:todo_list/utility/utilities.dart';
class AddTaskScreen extends StatefulWidget {
@override
_AddTaskScreenState createState() => _AddTaskScreenState();
}
class _AddTaskScreenState extends State<AddTaskScreen> {
TaskBloc taskBloc;
TextEditingController taskController = TextEditingController();
TextEditingController dateController = TextEditingController();
TextEditingController timeController = TextEditingController();
final DateFormat formatter = DateFormat('dd, MMMM, yyyy');
// TodoListModel task = TodoListModel(deadLine: '', task: '');
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) =>
TaskBloc(repository: DatabaseRepository()),
child: Builder(builder: (BuildContext ctx) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Add a new Task'),
actions: [
GestureDetector(
onTap:** () {
saveTask(ctx);
},
child: Container(
margin: EdgeInsets.only(right: 20),
child: Icon(
Icons.check,
size: 30,
)),
)
],
),
body: buildTask(ctx));
}
),
);
}
Widget buildTaskForm(BuildContext ctx) { return Container( margin: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("What need to be done?"), Row( children: [ Expanded( child: Container( width: 400, child: TextFormField( controller: taskController, textInputAction: TextInputAction.newline, keyboardType: TextInputType.multiline, maxLines: null, decoration: InputDecoration( hintText: 'Enter Task Here', //border: OutlineInputBorder(), ), ), ), ), SizedBox( width: 10, ), Icon( Icons.keyboard_voice, color: Theme.of(context).primaryColor, size: 28, ), ], ), SizedBox( height: 40, ), Center( child: Text( "Dead line", style: TextStyle(fontSize: 19), )), SizedBox( height: 10, ), Row( children: [ Expanded( child: Container( width: 400, child: TextFormField( onTap: () { _showDatePicker(context); }, controller: dateController, textInputAction: TextInputAction.newline, keyboardType: TextInputType.multiline, maxLines: null, decoration: InputDecoration( hintText: 'Enter Date', //border: OutlineInputBorder(), ), ), ), ), SizedBox( width: 10, ),
Icon(
Icons.date_range,
color: Theme.of(context).primaryColor,
size: 28,
),
// SizedBox(height: 10,),
dateController.text.isEmpty
? Container()
: Expanded(child: buildTime()),
],
),
],
),
);
}
Row buildTime() { return Row( children: [ Expanded( child: Container( width: 400, child: TextFormField( onTap: () { _selectTime(context); }, controller: timeController, textInputAction: TextInputAction.newline, keyboardType: TextInputType.multiline, decoration: InputDecoration( hintText: 'Enter Time', //border: OutlineInputBorder(), ), ), ), ), SizedBox( width: 10, ), Icon( Icons.timer, color: Theme.of(context).primaryColor, size: 28, ), ], ); }
Future
void _showDatePicker(BuildContext context) { showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(3000)) .then((pickedDate) { if (pickedDate == null) { return; } setState(() { dateController.text = formatter.format(pickedDate).toString(); //task.deadLine = dateController.text; }); }); }
saveTask(BuildContext ctx) async {
taskBloc = BlocProvider.of
Widget buildTask(BuildContext context) { return BlocBuilder<TaskBloc, TaskState>( builder: (ctx, state) { if (state is TaskInitial) { return buildTaskForm(ctx); } else if (state is TaskLoadingState) { return Utility.showCirclarLoader(); } else if (state is TaskAddedState) { return buildTaskForm(ctx); } else if (state is TaskErrorState) { //return Utility.showLongErrorToast(state.message); } return Container(); }, ); } }```
@mikededo sir please i dont know how to format code this is my first time of reporting an issue here
i think the problem is coming from the repository because i did everything right in the bloc file and also the ui the same way i use to do when am using firebase the only thing different is the data base please if there is any other thing i need to do to connect bloc and sqflite db that i did not do you can tell me
Here you have an explanation from the GitHub docs on how to write codeblocks in Markdown. Try editing your comments! π
In the function saveTask
, you are calling BlocProvider.of(ctx)
without specifying the BLoC type. As you can see in the documentation, you should be using BlocProvider.of<BlocA>(context)
. However, it is strange that your app does not show any error and that, as you say, the BlocObserver
is called.
Could you try adding what I propsed before here? Aside from this, do you have a public repository of the project? Therefore I could fork it, try it and help you finding the issue (it's easier for me to debug if I can compile and run the app myself :wink:).
i have added the type of bloc but still the same thing is happening https://github.com/OnyemaAnthony/todo_list.git is the link to the repository you can clone it and switch to develop branch
I have found the issue. I will provide a pull request explaining you the why! π―
okay thank you sir i really appreciate
It is a pleasure π
If everything works as expected, merge the pr and close both the issue and the pr π
Okay I will do just that but I haven't seen the pull request
its working thank you sir God bless you,but i did not know the cause of the error
As I have stated in the pr, the issue was not yielding the function inside mapEventToState
.
Instead of:
@override
Stream<TaskState> mapEventToState(
TaskEvent event,
) async* {
if (event is FetchAllTaskEvent) {
yield* _mapFetchAllTAskEventToState(event);
} else if (event is SaveTaskEvent) {
yield* _mapSaveTaskEventToState(event);
}
}
You were doing:
@override
Stream<TaskState> mapEventToState(
TaskEvent event,
) async* {
if (event is FetchAllTaskEvent) {
yield* _mapFetchAllTAskEventToState(event);
} else if (event is SaveTaskEvent) {
_mapSaveTaskEventToState(event); // <- Here's the issue
}
}
You were not yielding _mapSaveTaskToState
, which would not call the function.
ohhhh now i get that is a very stupid mistake and i was not able to figure it out thanks anyways
here is my bloc class, when i trigger the SaveTaskEvent the event is called but the bloc and the repository is not called,am using Sqflite db as my repository
import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/cupertino.dart'; import 'package:todo_list/models/todo_list_model.dart'; import 'package:todo_list/repository/database_repository.dart';
part 'task_event.dart';
part 'task_state.dart';
class TaskBloc extends Bloc<TaskEvent, TaskState> { DatabaseRepository _repository;
TaskBloc({@required DatabaseRepository repository}) : assert (repository != null), _repository = repository, super(TaskInitial());
@override TaskState get initialState => TaskInitial();
@override Stream mapEventToState(TaskEvent event,) async {
if (event is FetchAllTaskEvent) {
yield _mapFetchAllTAskEventToState(event);
} else if (event is SaveTaskEvent) {
_mapSaveTaskEventToState(event);
}
}
Stream _mapFetchAllTAskEventToState(
FetchAllTaskEvent event) async* {
yield TaskLoadingState();
TodoListModel task;
} Stream _mapSaveTaskEventToState(SaveTaskEvent event) async* {
yield TaskLoadingState();
} }