0

I have some mistakes with flutter and firebase, if someone can help would be great here is my auth controller

class AuthController extends GetxController {
  final FirebaseAuth auth = FirebaseAuth.instance;
  final Rxn<User> _firebaseUser = Rxn<User>();
  Rx<XFile>? _pickedImage;

  XFile? get profilePhoto => _pickedImage?.value;
  // final user = FirebaseAuth.instance.currentUser.obs;

  Rxn<User> get user => _firebaseUser;
  // final user = FirebaseAuth.instance.currentUser;

  @override
  onInit() {
    _firebaseUser.bindStream(auth.authStateChanges());
    super.onInit();
  }

  // void register(
  //     String name, String email, String password, XFile? image) async {
  //   try {
  //     UserCredential _authResult = await auth.createUserWithEmailAndPassword(
  //         email: email.trim(), password: password);

  //     //create user in database.dart

  //     String downloadUrl = await uploadToStorage(image!);

  //     UserModel _user = UserModel(
  //       id: _authResult.user?.uid,
  //       name: name,
  //       email: _authResult.user?.email,
  //       profilePic: downloadUrl,
  //     );

  //     if (await Database().createNewUser(_user)) {
  //       Get.find<UserController>().user = _user;
  //     }
  //   } catch (e) {
  //     Get.snackbar(
  //       "Error creating Account",
  //       e.toString(),
  //       snackPosition: SnackPosition.BOTTOM,
  //     );
  //   }
  // }
  void register(
      String name, String email, String password, XFile? image) async {
    try {
      if (name.isNotEmpty &&
          email.isNotEmpty &&
          password.isNotEmpty &&
          image != null) {
        // save out user to our ath and firebase firestore
        UserCredential _authResult = await auth.createUserWithEmailAndPassword(
          email: email,
          password: password,
        );
        String downloadUrl = await uploadToStorage(image);
        UserModel _user = UserModel(
          id: _authResult.user?.uid,
          name: name,
          email: _authResult.user?.email,
          profilePic: downloadUrl,
        );
        if (await Database().createNewUser(_user)) {
          Get.find<UserController>().user = _user;
        } else {
          Get.snackbar(
            'Error Creating Account',
            'Please enter all the fields',
          );
        }
      }
    } catch (e) {
      Get.snackbar(
        'Error Creating Account',
        e.toString(),
      );
    }
  }

  void login(String email, password) async {
    try {
      UserCredential _authResult = await auth.signInWithEmailAndPassword(
          email: email.trim(), password: password);
      Get.find<UserController>().user =
          await Database().getUser(_authResult.user?.uid ?? '');
    } catch (e) {
      Get.snackbar("About User", "User message",
          snackPosition: SnackPosition.BOTTOM,
          titleText: Text("Acount creation failed"),
          messageText:
              Text(e.toString(), style: TextStyle(color: Colors.white)));
    }
  }

  Future<void> signOut() async {
    await auth.signOut();
    Get.find<UserController>().clear();
  }

  Future pickImage() async {
    print("call on click add photo icon");
    final ImagePicker _picker = ImagePicker();
    final XFile? pickedImage =
        await _picker.pickImage(source: ImageSource.gallery);
    print('picked image filled with image from gallery'); //This doesnt print at

    if (pickedImage != null) {
      Get.snackbar('Profile Picture',
          'You have successfully selected your profile picture!');

      // print(pickedImage.path);
    }
    _pickedImage = Rx<XFile>(pickedImage!);
    // print(_pickedImage);
    // print(profilePhoto);
  }

  // upload to firebase storage
  Future<String> uploadToStorage(XFile? image) async {
    Reference ref = FirebaseStorage.instance
        .ref('')
        .child('profilePics')
        .child(auth.currentUser!.uid);

    // print(ref);

    UploadTask uploadTask = ref.putFile(File(image?.path ?? 'idemo'));
    print(uploadTask);
    // TaskSnapshot snap = await uploadTask;
    String downloadUrl = await (await uploadTask).ref.getDownloadURL();
    print(downloadUrl);
    return downloadUrl;
  }
}

Here is my function to createNewUser

class Database {
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;

  Future<bool> createNewUser(UserModel user) async {
    try {
      await _firestore.collection("users").doc(user.id).set({
        "name": user.name,
        "email": user.email,
        "profilePhoto": user.profilePic
      });
      return true;
    } catch (e) {
      print(e);
      return false;
    }
  }

Here is HomeController

class HomeController extends GetxController {
  final Rxn<List<TodoModel>> todoList = Rxn<List<TodoModel>>([]);

  var selectedDate = DateTime.now().obs;

  List<TodoModel>? get todos => todoList.value;

  @override
  void onInit() {
    super.onInit();
    String? uid = Get.find<AuthController>().auth.currentUser?.uid ?? '';
    print(uid);
    todoList.bindStream(Database().todoStream(uid));
  }

  chooseDate() async {
    DateTime? pickedDate = await showDatePicker(
      context: Get.context!,
      initialDate: selectedDate.value,
      firstDate: DateTime(2000),
      lastDate: DateTime(2024),
      //initialEntryMode: DatePickerEntryMode.input,
      // initialDatePickerMode: DatePickerMode.year,
    );
    if (pickedDate != null && pickedDate != selectedDate.value) {
      selectedDate.value = pickedDate;
    }
  }
}

and here is View page

GetX<HomeController>(
  init: Get.put<HomeController>(HomeController()),
  builder: (HomeController todoController) {
    if (todoController.todos != null) {
      // print(todoController.todos?.done ?? false);
      return Expanded(
        child: ListView.builder(
          itemCount: todoController.todos?.length,
          itemBuilder: (_, index) {
            return TodoCard(
              uid: controller.user.value?.uid ?? '',
              todo: todoController.todos![index],
            );
          },
        ),
      );
    } else {
      return Text("loading...");
    }
  },
),

So, I have an error when I register a new user I got this error:

The following assertion was thrown building Builder(dirty): a document path must be a non-empty string Failed assertion: line 116 pos 14: ‘path.isNotEmpty’

And here is output from terminal:

The relevant error-causing widget was
GetMaterialApp
lib/main.dart:23
When the exception was thrown, this was the stack
#2      _JsonCollectionReference.doc
#3      Database.todoStream
#4      HomeController.onInit
#5      GetLifeCycleBase._onStart
#6      InternalFinalCallback.call
#7      GetInstance._startController
#8      GetInstance._initDependencies
#9      GetInstance.find
#10     GetInstance.put
#11     Inst.put

So a problem is with this path, and when I reload from the visual studio I god the right user with the right data. So the problem is when I register a user for the first time.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Vesko_dev
  • 356
  • 6
  • 18

1 Answers1

0

It looks like uid is empty, which you should also be able to see from looking up print(uid); in your output.

When your application or web page loads, Firebase automatically tries to restore the previously signed in user from its local state. This requires that it makes a call to the server however (for example to check if the account has been disabled) and while that call is going on, your main code continues to execute and the currentUser variable is going to be null.

Your code needs to take this into account. The easiest way to do this is to not depend on currentUser, but instead to use an reactively respond to changes in the authentication state as shown in the first example in the documentation on getting the current user:

FirebaseAuth.instance
  .authStateChanges()
  .listen((User? user) {
    if (user != null) {
      print(user.uid);
    }
  });

The authStateChange method here returns a stream that fires an event whenever the authentication state changes, so when the user signs in or signs out. The common way to use this stream is to either set the user to the state of your widget, or to use the stream directly in a StreamBuilder.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807