Firebase Firestore query with GetX and Firebase Auth

Viewed 1595

I have a small flutter application that uses Firebase Auth to login and then uses bindStream to query a list of documents from Firestore. It works from a fresh start/hot restart, but as soon as I logout I get a firebase/firestore permission error and subsequent login's don't refresh the stream. I thought that a GetxController disposes streams created via bindStream when the view that uses the controller is disposed. In this case, when I logout I pop off all routes via Get.offAll, but it appears the stream is still active and that's when the permissions error happens. But I'm not actually sure what is happening.

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp();

  Get.put(LoginController());
  Get.put(AuthController(), permanent: true);

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'GetX Firebase Firestore',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SplashScreen(),
    );
  }
}

auth_controller.dart

class AuthController extends GetxController {
  final AuthService _authService = AuthService();
  AuthService get authService => _authService;

  final LoginController _loginController = Get.find<LoginController>();
  LoginController get loginController => _loginController;

  Rxn<User> _user = Rxn<User>();
  User? get user => _user.value;

  @override
  void onReady() async {
    // bind auth state to _firebaesUser, but also give an initial value
    _user = Rxn<User>(_authService.currentUser);
    _user.bindStream(_authService.authState);

    //run every time auth state changes
    ever<User?>(_user, handleAuthChanged);

    super.onReady();
  }

  handleAuthChanged(User? user) {
    print("handleAuthChanged - ${user?.uid}");
    if (user == null) {
      Get.offAll(() => LoginScreen());
    } else {
      Get.offAll(() => HomeScreen(), binding: HomeBinding());
    }
  }
}

user_controller.dart

class UserController extends GetxController {
  final UserRepository _userRepository = UserRepository();

  final repository = UserRepository();
  final users = Rx<List<FirestoreUser>>([]);

  late Rx<FirestoreUser> _firestoreUser;
  FirestoreUser get firestoreUser => _firestoreUser.value;

  @override
  void onInit() {
    super.onInit();
    final user = FirebaseAuth.instance.currentUser;

    if (user == null) return;

    _firestoreUser = Rx<FirestoreUser>(FirestoreUser.fromAuth(user));
    // get user data from firestore

    _firestoreUser.bindStream(_userRepository.getUserById(user.uid));

    // query user collection
    getAllUsers();
  }

  void getAllUsers() {
    users.bindStream(repository.getAllUsers());
  }
}

home_screen.dart

class HomeScreen extends GetView<UserController> {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("All Sample Users"),
        actions: [
          IconButton(
            onPressed: () => Get.to(ProfileScreen()),
            icon: Icon(Icons.person),
          ),
        ],
      ),
      body: Obx(
        () => ListView.builder(
          itemCount: controller.users.value.length,
          itemBuilder: (context, index) {
            final user = controller.users.value[index];
            return ListTile(
              leading: CircleAvatar(
                backgroundImage: NetworkImage(user.photoURL),
              ),
              title: Text(user.displayName),
            );
          },
        ),
      ),
    );
  }
}

home_binding.dart

class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<UserController>(() => UserController(), fenix: true);
  }
}
0 Answers
Related