I have built a todo app with flutter, getx and firebase. I have a login page, signup page and the todo page where I show a list of todos. I am using firebase_auth package for authentication and cloud_firestore package for saving and retrieving data from firestore. I have 2 models - one for user and other for todo.
For saving the todo in firestore I have the below method -
Future<void> addTodo(String content, String uid) async {
try {
await firebaseFirestore
.collection("users")
.doc(uid)
.collection("todos")
.add({
"content": content,
"dateCreated": Timestamp.now(),
"done": false,
});
} catch (e) {
print(e.toString());
rethrow;
}
}
To retrieve the list of todos from firestore I am using the below method which is returning a stream of todos
Stream<List<TodoModel>> todoStream(String uid) {
return firebaseFirestore
.collection("users")
.doc(uid)
.collection("todos")
.orderBy("dateCreated", descending: true)
.snapshots()
.map((event) {
List<TodoModel> retVal = List.empty(growable: true);
event.docs.forEach((element) {
TodoModel todo = TodoModel();
todo.todoId = element.id;
todo.content = element['content'];
todo.dateCreated = element['dateCreated'];
todo.done = element['done'];
print(todo.toString());
retVal.add(todo);
});
return retVal;
});
}
As you can see todo for a particular user is tied to their id.
Now in my todo controller's onInit method I am calling the above function to get the stream of todos
@override
void onInit() {
String uid = Get.find<AuthController>().user;
todoList.bindStream(DatabaseService().todoStream(uid));
super.onInit();
}
Auth controller returns the user's id which is then fed to the todoStream function to get the todos
In the main page of the app inside the build method I am injecting the Todo controller like so
Get.put(TodoController());
In the body of the Scaffold widget I am displaying the todos using Obx like so
Obx(
() {
if (Get.find<TodoController>().todos.length > 0) {
return Expanded(
child: ListView.builder(
itemCount: Get.find<TodoController>().todos.length,
itemBuilder: (_, index) {
TodoModel todo = Get.find<TodoController>().todos[index];
return Card(
margin:
EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
children: [
Expanded(
child: Text(
todo.content,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
Checkbox(
value: todo.done,
onChanged: (newValue) {
print(newValue);
}),
],
),
),
);
},
),
);
} else {
return Text(
"Loading....",
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
);
}
},
)
The issue I am facing is when the app starts and the first user logs in, I can see that the todo controller is created and initialized and the list of his todos is displayed on the page. However when he logs out and another user logs in the page is able to display his name correctly which means the user is identified correctly, but still the list of todos of the first user are showing.
This tells me that when the second user logs in the onInit method of the todo controller is not called.
Anyone know how to fix this?
Below is my TodoController -
class TodoController extends GetxController {
Rxn<List<TodoModel>> todoList = Rxn<List<TodoModel>>();
List<TodoModel> get todos => todoList.value ?? [];
void clear() => todoList = Rxn<List<TodoModel>>();
@override
void onInit() {
String uid = Get.find<AuthController>().user;
print("onInit called=====================" + uid);
todoList.bindStream(DatabaseService().todoStream(uid));
print("todo bind stream done=========================");
super.onInit();
}
}