Невозможно использовать провайдера во флаттере для обработки потока аутентификации
Если кто-то не может понять мою проблему, сообщите
Я использовал пакет Provider для обработки потока аутентификации. Что я делаю: Main.dart -> Виджет обработчика Auth (который содержит построитель потока для проверки onAuthChange) -> Обработчик страницы (здесь, если пользователь новый, он приведет пользователя к экрану адаптации, оттуда он будет передан в Login страница с использованием push-замены) После входа в систему выполняется проверка пользователя, существуют ли данные или нет -> если они существуют, он попадает на главный экран -> Главный экран содержит 3 вкладки. На главной вкладке есть кнопка выхода, но когда я нажимаю, она не работает. Помогите мне в этом.
Main.dart
Provider<AuthBase>(
create: (context)=>Auth(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Rapport',
theme: ThemeData(
primaryColor: Color(0xFFE3F2FD),
visualDensity: VisualDensity.adaptivePlatformDensity,
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: CustomPageTransitionsBuilder(),
TargetPlatform.iOS: CustomPageTransitionsBuilder(),
},
),
),
/*This is the routes table. Add all the route names used inside the app here
Add the route name where the route is made as static const String, so as to you don't need to remember anything.
*/
routes: {
//the route name / stands for home / first route in the app.
'/': (ctx) {
return SplashScreen.navigate(
name: 'assets/splash.flr',
next: (context) {
print(isLogin.toString());
return AuthWidgetBuilder(dataExists: myData.length==0,isLogin: isLogin,builder: (context, userSnapshot,isLogin,dataExist) {
return Scaffold(
body: AuthWidget(userSnapshot: userSnapshot,dataExists: myData.length==0,isLogin: isLogin,),
);
});
},
startAnimation: 'Untitled',
until: () => Future.delayed(Duration(seconds: 4)),
backgroundColor: Colors.white,
);
},
LoginScreen.loginRoute: (ctx) => LoginScreen(),
CheckUser.checkRoute: (ctx) => CheckUser(),
OnboardingScreen.onBoardRoute: (ctx) => OnboardingScreen(),
StudentInfo.studentRoute: (ctx) => StudentInfo(),
PersonalDetails.routeName:(ctx) => PersonalDetails(),
ProfessionalDetails.routeName:(ctx) => ProfessionalDetails(),
AddressDetails.routeName: (ctx) => AddressDetails(),
TeacherHomeScreen.routeName:(ctx)=>TeacherHomeScreen(),
TeacherVerification.routeName:(ctx)=>TeacherVerification(),
StudentHomeScreen.routeName : (ctx)=>StudentHomeScreen(),
},
),
);
Auth_Widget_Builder
class AuthWidgetBuilder extends StatelessWidget {
const AuthWidgetBuilder({Key key, @required this.builder,@required this.isLogin,@required this.dataExists}) : super(key: key);
final Widget Function(BuildContext, AsyncSnapshot<User>,String,bool) builder;
final String isLogin;
final bool dataExists;
@override
Widget build(BuildContext context) {
print('AuthWidgetBuilder rebuild');
print(dataExists);
final authService =
Provider.of<AuthBase>(context, listen: false);
return StreamBuilder<User>(
stream: authService.onAuthStateChanged,
builder: (context, snapshot) {
print('StreamBuilder: ${snapshot.connectionState}');
final User user = snapshot.data;
if (user != null) {
SharedPrefFunction().saveLoginPreference();
return MultiProvider(
providers: [
Provider<User>.value(value: user),
],
child: builder(context, snapshot,'true',dataExists),
);
}
return builder(context, snapshot,isLogin,dataExists);
},
);
}
}
Auth.Widget
class AuthWidget extends StatelessWidget {
const AuthWidget({Key key, @required this.userSnapshot,this.dataExists,this.isLogin}) : super(key: key);
final AsyncSnapshot<User> userSnapshot;
final String isLogin;
final bool dataExists;
@override
Widget build(BuildContext context) {
if (userSnapshot.connectionState == ConnectionState.active) {
if(isLogin == null){
return OnboardingScreen();
}
else{
return userSnapshot.hasData ? CheckUser(dataExist: dataExists,) : LoginScreen();
}
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
}
В checkUser.dart, если данные существуют
homePage(BuildContext context) {
print('checkUser');
if (dataExists) {
return Scaffold(
body: SafeArea(
child: Container(
child: Column(
children: <Widget>[
Text(
'Welcome',
style: kTextStyle,
),
FlatButton.icon(
onPressed: () {
setState(() {
Navigator.of(context).pushReplacementNamed(
StudentHomeScreen.routeName, //This line is changed by me. This code is not correct and needs to be changed.
);
});
},
icon: Icon(Icons.home),
label: Text('Home'),
),
],
),
),
),
);
} else {
return getInfoPage();
}
}
Student_Home_Screen.dart
class _StudentHomeState extends State<StudentHomeScreen> {
bool _isProfilePicSet = false;
int _currentTabIndex = 1;
var _tabs = [
Center(
child: Text('Search Tab'),
),
HomeTab(),
Center(
child: Text('Profile Tab'),
),
];
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.white,
body: _tabs[_currentTabIndex],
bottomNavigationBar: BottomNavigationBar(
// type: BottomNavigationBarType.shifting,
backgroundColor: Colors.white,
// fixedColor: Colors.black,
iconSize: 24,
selectedIconTheme: IconThemeData(
color: themeColor,
opacity: 1,
),
unselectedIconTheme: IconThemeData(
color: themeColor,
opacity: 0.6,
),
showUnselectedLabels: false,
showSelectedLabels: true,
elevation: 10,
currentIndex: _currentTabIndex,
onTap: (index) {
setState(() {
_currentTabIndex = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text(
'Search',
style: subhead2.copyWith(color: themeColor),
),
),
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text(
'Home',
style: subhead2.copyWith(color: themeColor),
),
),
BottomNavigationBarItem(
icon: CircleAvatar(
backgroundImage: _isProfilePicSet
? NetworkImage('set link here')
: AssetImage('assets/images/default.png'),
maxRadius: 12,
),
title: Text(
'Profile',
style: subhead2.copyWith(color: themeColor),
),
),
],
),
);
}
}
В Hometab функция кнопки выхода
Future<void> _signOut(BuildContext context) async {
try {
final auth = Provider.of<AuthBase>(context, listen: false);
await auth.signOut();
} catch (e) {
print(e);
}
}
2 ответа
Это может вам помочь. Я не уверен, но это работает для меня
Выход из системы
Future _signOut() async {
try {
return await auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
Использование функции
IconButton(
onPressed: () async {
await _auth.signOut();
MaterialPageRoute(
builder: (context) => Login(),
);
},
icon: Icon(Icons.exit_to_app),
),
Вам необходимо иметь AuthWidgetBuilder как виджет верхнего уровня (в идеале выше MaterialApp), чтобы все дерево виджетов перестраивалось при событиях входа / выхода.
Вы можете сделать SplashScreen дочерним и иметь некоторую условную логику, чтобы решить, следует ли вам его представлять.
Кстати, если ваш экран-заставка не содержит анимации, вам вообще не нужен виджет, и вы можете использовать экран запуска на iOS или аналогичный на Android (в Интернете есть руководства по этому поводу). Автор: @bizz84