英文:
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'),
),
],
);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论