Data is not initialized in Stream provider after login or registration

Viewed 42

Data in the provider is not loaded after registration or login to the application (I use firebase). They appear only after restarting the application. Here is the provider structure.

if (FirebaseAuth.instance.currentUser?.uid != null) {
    setState(() {
      uid = FirebaseAuth.instance.currentUser?.uid;
    });
  }

  return MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => UserProvider()),
      StreamProvider<List<Project>>(
        create: (context) => ProjectsActions().getAllProjects(uid),
        initialData: const [],
        catchError: (_, __) => const [],
      ),
      StreamProvider<List<Task>>(
        create: (context) => TasksActions().getAllTasks(uid),
        initialData: const [],
        catchError: (_, __) => const [],
      ),
      StreamProvider<List<Note>>(
        create: (context) => NotesActions().getAllNotes(uid),
        initialData: const [],
        catchError: (_, __) => const [],
      ),
    ],
    child: MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'App',
      locale: _locale,
      navigatorKey: NavigationService.navigatorKey,
      onGenerateRoute: RouterGenerator.generateRoute,
      home: StreamBuilder(
        stream: FirebaseAuth.instance.authStateChanges(),
        builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
          if (snapshot.connectionState == ConnectionState.active) {
            if (snapshot.hasData) {
              return const InitPage();
            } else if (snapshot.hasError) {
              return Center(
                child: Text('${snapshot.error}'),
              );
            }
          }

          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }

          return const AuthorizationPage();
        },
      ),
      supportedLocales: const [
        Locale('en', 'US'),
        Locale('ru', 'RU'),
      ],
      localizationsDelegates: const [
        IkiteoLocalization.delegate,
        SfGlobalLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      localeResolutionCallback: (locale, supportedLocales) {
        for (var supportedLocale in supportedLocales) {
          if (supportedLocale.languageCode == locale?.languageCode &&
              supportedLocale.countryCode == locale?.countryCode) {

            return supportedLocale;
          }
        }

        return supportedLocales.first;
      },
    ),
  );

I am trying to find a way to solve this problem. In the application I use registration and login using a login and password, as well as Google registration (firebase)

Streams used in providers:
  Stream<List<Project>> getAllProjects(String? uid) => FirebaseFirestore.instance
  .collection('projectus')
  .where('creator', isEqualTo: uid)
  .snapshots()
  .map((snapshots) => snapshots.docs.map((doc) => Project.fromJSON(doc.data(), doc)).toList());


Stream<List<Task>> getAllTasks(String? uid) async* {
try {
  yield* FirebaseFirestore.instance
    .collection('tasks')
    .where('creator', isEqualTo: uid)
    .snapshots()
    .map((snapshots) => snapshots.docs.map((doc) => Task.fromJSON(doc.data(), doc.id)).toList());
} on FirebaseException catch(e) {
  print('getAllTasks fn error has been detected. [ERROR] $e');
}

}

Stream<List<Note>> getAllNotes(String? uid) async* {
try {
  yield* FirebaseFirestore.instance
    .collection('notes')
    .where('creator', isEqualTo: uid)
    .snapshots()
    .map((snapshots) => snapshots.docs.map((doc) => Note.fromJSON(doc.data(), doc.id)).toList());
} on FirebaseException catch(e) {
  print('getAllNotes fn error has been detected. [ERROR] $e');
}

}

If i delete catchError from StreamProvider I've got this error:

An exception was throw by _MapStream<QuerySnapshot<Map<String, dynamic>>, List> listened by

StreamProvider<List>, but no catchError was provided.

Exception: [cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.

1 Answers

Finally I was able to solve this problem. The problem was that there was an incorrect order of the widgets. For everything to work correctly, you need to do the following order of the main widgets: StreamBuilder -> MultiProvider -> MaterialApp. Аfter I used switch case inside MaterialApp for checking connectionState. And for reloading providers I used inside StreamBuilder.

      if (snapshot.hasData) {
        uid = FirebaseAuth.instance.currentUser?.uid;
      }

It's not the cleanest solution in my opinion, but it worked for me now.

Related