Добрый день!
Как я могу использовать поставщика для MaterialApp? У меня есть MultiProvider и абстрактный класс. Необходимо передать авторизацию на LandingPage
Вот что я хотел бы получить:
Widget build(BuildContext context) {
return Provider<AuthBase>(
create: (context) => Auth(),
child: MaterialApp(
title: "Bloc Test",
theme: ThemeData(primarySwatch: Colors.indigo),
home: LandingPage(),
),
);
}
Вот мой рабочий код:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<ToDoProvider>(
create: (ctx) => ToDoProvider(),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Ultimative ToDo',
theme: ThemeData(
scaffoldBackgroundColor: myListMainColor,
textTheme:
GoogleFonts.sourceSansProTextTheme(Theme.of(context).textTheme),
visualDensity: VisualDensity.adaptivePlatformDensity,
),
initialRoute: '/',
routes: {
'/': (context) => LandingPage(auth: Auth()),
OpenedToDo.routeName: (context) => OpenedToDo(),
},
),
У меня есть абстрактный класс AuthBase, но я не могу смешивать его с ChangeNotifier. Вот почему я не могу поместить новую строку кода в MultiProvider.
abstract class AuthBase {
User get currentUser;
Future<User> signInAnonymously();
Stream<User> authStateChanges();
Future<void> singOut(BuildContext context);
Future<User> singInWithGoogle();
Future<User> createUserWithEmailAndPassword(String email, String password);
Future<User> signInWithEmailAndPassword(String email, String password);
}
class Auth implements AuthBase {
final _firebaseAuth = FirebaseAuth.instance;
@override
Stream<User> authStateChanges() => _firebaseAuth.authStateChanges();
@override
User get currentUser => _firebaseAuth.currentUser;
@override
Future<User> signInAnonymously() async {
}
@override
Future<User> signInWithEmailAndPassword(String email, String password) async {
}
@override
Future<User> createUserWithEmailAndPassword(
}
@override
Future<User> singInWithGoogle() async {
}
@override
Future<void> singOut(BuildContext context) async {
}
}
Ошибка:
Ошибка: не удалось найти правильный поставщик над этим виджетом StreamBuilder.
Скорее всего, это происходит из-за того, что вы использовали
BuildContext
, в котором отсутствует выбранный вами поставщик. Есть несколько распространенных сценариев:
Провайдер, которого вы пытаетесь прочитать, находится на другом маршруте.
Провайдеры ограничены. Поэтому, если вы вставите поставщика внутри маршрута, другие маршруты не смогут получить доступ к этому поставщику.
Вы использовали
BuildContext
, который является предком провайдера, которого вы пытаетесь прочитать.Убедитесь, что StreamBuilder находится под вашим MultiProvider / Provider. Обычно это происходит, когда вы создаете провайдера и пытаетесь его сразу же прочитать.
Например, вместо:
return Provider<Example>( create: (_) => Example(), // Will throw a ProviderNotFoundError, because `context` is associated // to the widget that is the parent of `Provider<Example>` child: Text(context.watch<Example>()), ), } ``` consider using `builder` like so: ``` Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // we use `builder` to obtain a new `BuildContext` that has access to the provider builder: (context) { // No longer throws return Text(context.watch<Example>()), } ), } ```
LandingPage:
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: auth.authStateChanges(),
builder: (context, snapshot) {
//* если подключился к данным
if (snapshot.connectionState == ConnectionState.active) {
//* получаем данные о пользователе
final User user = snapshot.data;
print('~ uid is ${user?.uid}');
if (user == null) {
//Navigator.of(context).pushNamed(SignInPage.routeName, arguments: auth);
return SignInPage.create(context);
} else {
// Navigator.of(context).pushNamed(HomeScreen.routeName);
return HomeScreen();
}
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
},
);
}
SignInPage имеет эту часть кода:
static Widget create(BuildContext context) {
final auth = Provider.of<AuthBase>(context, listen: false);
return Provider<SignInBloc>(
create: (_) => SignInBloc(auth: auth),
//* обязательно должен быть dispose
dispose: (_, bloc) => bloc.dispose(),
//* consumer помогает прокинуть данные в конструктор
child: Consumer<SignInBloc>(
child: SignInPage(),
builder: (_, bloc, __) => SignInPage(bloc: bloc),
),
);
}