skip to Main Content

I am trying to create a single interface for Google and Facebook login, my SignInProvider looks like:

abstract class SignInProvider with ChangeNotifier {
  bool get isSigningIn;
  set isSigningIn(bool isSigningIn);
  void login();
  void logout();
}

class FacebookSignInProvider with ChangeNotifier implements SignInProvider { ... }
class GoogleSignInProvider with ChangeNotifier implements SignInProvider { ... }

My Landing page:

class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<SignInProvider>(create: (context) => GoogleSignInProvider()),
        ChangeNotifierProvider<SignInProvider>(create: (context) => FacebookSignInProvider())
      ],
      child: Scaffold(
        body: StreamBuilder(
            stream: FirebaseAuth.instance.authStateChanges(),
            builder: (context, snapshot) {
              final provider =
                  Provider.of<SignInProvider>(context, listen: true);
              if (provider.isSigningIn) {
                return // Show loader
              } else if (snapshot.hasData) {
                return // Show logged-in UI
              } else {
                // Give option to login via Google and Facebook
                return Row(children: [
                TextButton(
                  onPressed: () {
                    final provider = Provider.of<SignInProvider>(
                      context,
                      listen: false,
                    );
                    provider.login();
                  },
                  child: const Text('Login with Google'),
                ),
                TextButton(
                  onPressed: () {
                    final provider = Provider.of<SignInProvider>(
                      context,
                      listen: false,
                    );
                    provider.login();
                  },
                  child: const Text('Login with Facebook'),
                ),
              ],
            );
          }
        }),
      ),
    );
  }
}

In this UI, clicking on Login with Google and Login with Facebook both are referring to FacebookSignInProvider, since that is provided last in the list of providers. How can I make it act on respective provider?

When I change the onPressed definition to Provider.of<GoogleSignInProvider> or Provider.of<FacebookSignInProvider> it crashes.

3

Answers


  1. Replace ChangeNotifierProvider<SignInProvider> with ChangeNotifierProvider< FacebookSignInProvider> and ChangeNotifierProvider<GoogleSignInProvider>

    Login or Signup to reply.
  2. Link to the output

    • In your main() function
    void main() {
      runApp(
        MultiProvider(
          providers: [
            ChangeNotifierProvider<FacebookSignInProvider>.value(
              value: FacebookSignInProvider(),
            ),
            ChangeNotifierProvider<GoogleSignInProvider>.value(
              value: GoogleSignInProvider(),
            ),
          ],
         child: const MyApp()
        )
      );
    }
    
    • Your buttons
    return Row(
        children: [
            TextButton(
                onPressed: () {
                    final provider = Provider.of<GoogleSignInProvider>(context, listen: false);
                    provider.login();
                },
                child: const Text('Login with Google'),
             ),
             TextButton(
                 onPressed: () {
                     final provider = Provider.of<FacebookSignInProvider>(context, listen: false);
                     provider.login();
                 },
                 child: const Text('Login with Facebook'),
             ),
         ],
    );
    
    Login or Signup to reply.
  3. Try this solution

    Create a single generic SignInProvider with ChangeNotifier along with SignInType enum

    enum SignInType {
      none,
      facebook,
      google
    }
    
    class SignInProvider with ChangeNotifier {
      bool _isSigningIn = false;
      SignInType _signInType = SignInType.none;
    
      set signInType(SignInType signType) {
        _signInType = signType;
      }
    
      SignInType get signInType {
        return _signInType;
      }
    
    
      set signingIn(bool signingIn) {
        _isSigningIn = signingIn;
      }
    
      bool get signingIn {
        return _isSigningIn;
      }
    
      void login() {
        switch (signInType) {
          case SignInType.none:
          case SignInType.facebook:
          case SignInType.google:
        }
      }
    
      void logout() {}
    }
    

    Create _HomeState class as follows

    class _HomeState extends State<Home> {
    
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
            ChangeNotifierProvider<SignInProvider>(create: (context) => SignInProvider()),
          ],
          child: Scaffold(
            body: StreamBuilder(
                stream: FirebaseAuth.instance.authStateChanges(),
                builder: (context, snapshot) {
                  final provider =
                  Provider.of<SignInProvider>(context, listen: true);
                  if (provider._isSigningIn) {
                    return const Text("loader");
                  } else if (snapshot.hasData) {
                    return const Text("loader");
                  } else {
                    // Give option to login via Google and Facebook
                    return Row(children: [
                      TextButton(
                        onPressed: () {
                          final provider = Provider.of<SignInProvider>(
                            context,
                            listen: false,
                          );
                          provider.signInType = SignInType.google;
                          provider.login();
                        },
                        child: const Text('Login with Google'),
                      ),
                      TextButton(
                        onPressed: () {
                          final provider = Provider.of<SignInProvider>(
                            context,
                            listen: false,
                          );
                          provider.signInType = SignInType.facebook;
                          provider.login();
                        },
                        child: const Text('Login with Facebook'),
                      ),
                    ],
                    );
                  }
                }),
          ),
        );
      }
    }
    

    This way you will have a more generic provider that can handle multiple type of login providers.
    You can also create separate abstract class following the above pattern.
    Hope it helps.
    Thanks 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search