英文:
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<GoogleSignInProvider>` or `Provider.of<FacebookSignInProvider>` 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'),
                  ),
                ],
                );
              }
            }),
      ),
    );
  }
}
这样,你将拥有一个更通用的提供程序,可以处理多种登录提供程序。
你还可以按照上述模式创建单独的抽象类。
希望对你有帮助。
谢谢 ![]()
英文:
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.<br>
You can also create separate abstract class following the above pattern. <br>
Hope it helps.
Thanks ![]()
答案2
得分: 0
替换 ChangeNotifierProvider<SignInProvider> 为 ChangeNotifierProvider<FacebookSignInProvider> 和 ChangeNotifierProvider<GoogleSignInProvider>
英文:
Replace ChangeNotifierProvider<SignInProvider> with ChangeNotifierProvider< FacebookSignInProvider> and ChangeNotifierProvider<GoogleSignInProvider>
答案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登录'),
         ),
     ],
);
英文:
- 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'),
         ),
     ],
);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论