简体   繁体   中英

Flutter/Firebase: Dynamic homepage depending on user loginStatus using MultiProvider issues

I want to check if the user is already logged in and show him page depending on that.

Here is my main.dart :

...
import 'firebase/authentication_service.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        Provider<AuthenticationService>(
          create: (_) => AuthenticationService(FirebaseAuth.instance),
        ),
        StreamProvider(
          create: (context) =>
              context.read<AuthenticationService>().authStateChanges,
          initialData: null,
        ),
      ],
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
            backgroundColor: Colors.transparent,
            primaryColor: Color(0xff4d629f),
            buttonBarTheme:
                ButtonBarThemeData(alignment: MainAxisAlignment.center)),
        home: AuthenticationWrapper(),
      ),
    );
  }
}

class AuthenticationWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final firebaseUser = context.watch<User>();

    if (firebaseUser != null) {
      //If the user is successfully Logged-In.
      return HomePage();
    } else {
      //If the user is not Logged-In.
      return LoginPage();
    }
  }
}

And here is my Authentication_service.dart :

class AuthenticationService {
  final FirebaseAuth _firebaseAuth;
  UserModel userModel = UserModel.empty();
  final userRef = FirebaseFirestore.instance.collection('users');

  AuthenticationService(this._firebaseAuth);

  Stream<User?> get authStateChanges => _firebaseAuth.authStateChanges();

  Future<String> signIn(
      {required String email, required String password}) async {
    try {
      await _firebaseAuth.signInWithEmailAndPassword(
          email: email, password: password);
      return "Signed in";
    } on FirebaseAuthException catch (e) {
      if (e.code == 'user-not-found')
        return "There is no user for that e-mail";
      else if (e.code == 'wrong-password')
        return "Entered wrong Password";
      else
        return "Something went wrong: $e";
    }
  }
...

And there are errors:

The following ProviderNotFoundException was thrown building AuthenticationWrapper(dirty): Error: Could not find the correct Provider above this AuthenticationWrapper Widget This happens because you used a BuildContext that does not include the provider of your choice. There are a few common scenarios:

  • You added a new provider in your main.dart and performed a hot-reload. To fix, perform a hot-restart.
  • The provider you are trying to read is in a different route.
  • Providers are "scoped". So if you insert of provider inside a route, then other routes will not be able to access that provider.
  • You used a BuildContext that is an ancestor of the provider you are trying to read. Make sure that AuthenticationWrapper is under your MultiProvider/Provider. This usually happens when you are creating a provider and trying to read it immediately. For example, instead of:
Widget build(BuildContext context) {
  return Provider<Example>(
    create: (_) => Example(),
    // Will throw a ProviderNotFoundError, because `context` is associated
    // to the widget that is the parent of `Provider<Example>`
    child: Text(context.watch<Example>()),
  ),
}

consider using builder like so:

Widget build(BuildContext context) {
  return Provider<Example>(
    create: (_) => Example(),
    // we use `builder` to obtain a new `BuildContext` that has access to the provider
    builder: (context) {
      // No longer throws
      return Text(context.watch<Example>()),
    }
  ),
}

Unfortunately it didn't help or i just can't implement it in a right way.

@SumerSingh solution worked, i just changed it a bit for my use.

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _initialized = false;
  bool _error = false;
  void initializeFlutterFire() async {
    try {
      await Firebase.initializeApp();
      setState(() {
        _initialized = true;
      });
    } catch (e) {
      setState(() {
        _error = true;
      });
    }
  }

  @override
  void initState() {
    initializeFlutterFire();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'App',
        debugShowCheckedModeBanner: false,
        home: Scaffold(
            body: _error
                ? splashScreen()
                : !_initialized
                    ? splashScreen()
                    : SplashScreen()));
  }
}

class SplashScreen extends StatefulWidget {
  SplashScreen({Key? key}) : super(key: key);

  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  var currentUser;
  AuthenticationService _authService =
      new AuthenticationService(FirebaseAuth.instance);
  late final UserModel userModel;
  bool isAuthinticated = false;

  _isUserSignedin() async {
    currentUser = _auth.currentUser;
    userModel = await _authService.getUserFromDB(uid: _auth.currentUser!.uid);
    setState(() {
      currentUser != null ? isAuthinticated = true : isAuthinticated = false;
    });
  }

  @override
  void initState() {
    super.initState();
    _isUserSignedin();
    startTime();
  }

  startTime() async {
    var _duration = new Duration(seconds: 4);
    return new Timer(_duration, navigationPage);
  }

  Widget userAuthState() {
    if (!isAuthinticated)
      return LoginPage();
    else if (userModel.type == 'Attendant')
      return AttendantMainPage();
    else
      return SeniorMainPage();
  }

  void navigationPage() {
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(builder: (BuildContext context) => userAuthState()),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(body: splashScreen());
  }
}

Widget splashScreen() {
  return Container(
    height: double.maxFinite,
    width: double.maxFinite,
    child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: [
          CircleAvatar(
              radius: 80.0, child: Image.asset('assets/logo.png')),
          Text("APP NAME",
              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
          CircularProgressIndicator()
        ]),
  );
}

It works well, thank you for help!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM