MultiProvider with AbstractClass notifier

huangapple go评论73阅读模式
英文:

MultiProvider with AbstractClass notifier

问题

我正在尝试创建一个用于Google和Facebook登录的单一界面,我的`SignInProvider`看起来像这样:
```dart
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 { ... }

我的首页页面:

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 // 显示加载器
              } else if (snapshot.hasData) {
                return // 显示已登录的界面
              } else {
                // 提供通过Google和Facebook登录的选项
                return Row(children: [
                TextButton(
                  onPressed: () {
                    final provider = Provider.of<SignInProvider>(
                      context,
                      listen: false,
                    );
                    provider.login();
                  },
                  child: const Text('使用Google登录'),
                ),
                TextButton(
                  onPressed: () {
                    final provider = Provider.of<SignInProvider>(
                      context,
                      listen: false,
                    );
                    provider.login();
                  },
                  child: const Text('使用Facebook登录'),
                ),
              ],
            );
          }
        }),
      ),
    );
  }
}

在此界面中,单击“使用Google登录”和“使用Facebook登录”都引用了FacebookSignInProvider,因为它是提供者列表中的最后一个。如何使其分别作用于相应的提供者?

当我将onPressed 定义更改为Provider.of<GoogleSignInProvider>Provider.of<FacebookSignInProvider>时,它会导致崩溃。


<details>
<summary>英文:</summary>

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&lt;GoogleSignInProvider&gt;` or `Provider.of&lt;FacebookSignInProvider&gt;` it crashes.

</details>


# 答案1
**得分**: 1

尝试这个解决方案

创建一个带有ChangeNotifier的单个通用SignInProvider,以及SignInType枚举

```dart
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() {}
}

创建如下的_HomeState类

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'),
                  ),
                ],
                );
              }
            }),
      ),
    );
  }
}

这样,你将拥有一个更通用的提供程序,可以处理多种登录提供程序。
你还可以按照上述模式创建单独的抽象类。
希望对你有帮助。
谢谢 MultiProvider with AbstractClass notifier

英文:

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&lt;Home&gt; {

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

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

答案2

得分: 0

替换 ChangeNotifierProvider&lt;SignInProvider&gt;ChangeNotifierProvider&lt;FacebookSignInProvider&gt;ChangeNotifierProvider&lt;GoogleSignInProvider&gt;

英文:

Replace ChangeNotifierProvider&lt;SignInProvider&gt; with ChangeNotifierProvider&lt; FacebookSignInProvider&gt; and ChangeNotifierProvider&lt;GoogleSignInProvider&gt;

答案3

得分: 0

// 在你的 main() 函数中
void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<FacebookSignInProvider>.value(
          value: FacebookSignInProvider(),
        ),
        ChangeNotifierProvider<GoogleSignInProvider>.value(
          value: GoogleSignInProvider(),
        ),
      ],
      child: const MyApp()
    )
  );
}

// 你的按钮
return Row(
    children: [
        TextButton(
            onPressed: () {
                final provider = Provider.of<GoogleSignInProvider>(context, listen: false);
                provider.login();
            },
            child: const Text('用Google登录'),
         ),
         TextButton(
             onPressed: () {
                 final provider = Provider.of<FacebookSignInProvider>(context, listen: false);
                 provider.login();
             },
             child: const Text('用Facebook登录'),
         ),
     ],
);
英文:

Link to the output

  • In your main() function
void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider&lt;FacebookSignInProvider&gt;.value(
          value: FacebookSignInProvider(),
        ),
        ChangeNotifierProvider&lt;GoogleSignInProvider&gt;.value(
          value: GoogleSignInProvider(),
        ),
      ],
     child: const MyApp()
    )
  );
}
  • Your buttons
return Row(
    children: [
        TextButton(
            onPressed: () {
                final provider = Provider.of&lt;GoogleSignInProvider&gt;(context, listen: false);
                provider.login();
            },
            child: const Text(&#39;Login with Google&#39;),
         ),
         TextButton(
             onPressed: () {
                 final provider = Provider.of&lt;FacebookSignInProvider&gt;(context, listen: false);
                 provider.login();
             },
             child: const Text(&#39;Login with Facebook&#39;),
         ),
     ],
);

huangapple
  • 本文由 发表于 2023年6月5日 14:16:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76403906.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定