I'm new to flutter. I am trying to set up an authentication flow. if the user is not logged in, I plan to build a MaterialApp with certain routes (eg Facebook Auth, Google Auth and Email Auth). If the user is logged in, they ll see another MaterialApp with routes such as HomePage, ListPage, CreatePage etc.
I tried but below codes fail. Anyone with experience can advise? thanks in advance
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import './pages/email.dart';
import './pages/auth.dart';
import './pages/home.dart';
import './pages/list.dart';
import './pages/create.dart';
import './scoped-models/main.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
final MainModel _model = MainModel();
bool _isAuthenticated = false;
#override
void initState() {
_model.autoAuthenticate();
_model.userSubject.listen((bool isAuthenticated) {
setState(() {
_isAuthenticated = isAuthenticated;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
print(_isAuthenticated);
return ScopedModel<MainModel>(
model: _model,
child: !_isAuthenticated == true
? MaterialApp(
theme: ThemeData(
primaryColor: Colors.lime, buttonColor: Colors.teal),
routes: {
'/': (BuildContext context) => AuthPage(),
'/email': (BuildContext context) => EmailPage(),
},
)
: MaterialApp(
theme: ThemeData(
primaryColor: Colors.lime, buttonColor: Colors.teal),
routes: {
'/': (BuildContext context) => HomePage(),
'/list': (BuildContext context) => ListPage(),
'/create': (BuildContext context) => CreatePage()
},
),
);
}
Related
When app is open,the first_screen widget must display until 3seconds and after the time passed home_page widget must show that I expect.But,after over 3seconds,home_page is not appear.State changing is notified from provider to Router.Which part is error?Please!!
My router app_route.dart is
import 'package:flutter/material.dart';
import 'package:navigator_2/keys/screen_keys.dart';
import 'package:navigator_2/provider/tab_provider.dart';
import 'package:navigator_2/root_screen.dart';
import 'package:navigator_2/screens/first_screen.dart';
class AppRoute extends RouterDelegate<AppKey> with ChangeNotifier,PopNavigatorRouterDelegateMixin{
#override
late final GlobalKey<NavigatorState> navigatorKeys;
final TabManager _tabManager;
AppRoute(this._tabManager) : navigatorKeys = GlobalKey<NavigatorState>(){
_tabManager.addListener(() {notifyListeners();});
}
#override
Widget build(BuildContext context) {
print("${_tabManager.isInitialPage}");
print("${_tabManager.currentTab}");
return Navigator(
key: navigatorKeys,
onPopPage: _handlePopPage,
pages: [
if(!_tabManager.isInitialPage) FirstScreen.page(),
if(_tabManager.isInitialPage == true)...{
RootScreen.page(_tabManager.currentTab)
},
],
);
}
#override
Future<void> setNewRoutePath(configuration) {
// TODO: implement setNewRoutePath
throw UnimplementedError();
}
bool _handlePopPage(Route<dynamic> route, result) {
if(!route.didPop(result)){
return false;
}
return true;
}
#override
// TODO: implement navigatorKey
GlobalKey<NavigatorState>? get navigatorKey => navigatorKeys;
}`
--------------------------------------------------------------------------------------------------
main.dart is
import 'package:flutter/material.dart';
import 'package:navigator_2/provider/tab_provider.dart';
import 'package:navigator_2/router_api/app_route.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
// This widget is the root of your application.
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late AppRoute _appRoute;
TabManager tabManager = TabManager();
#override
void initState() {
super.initState();
_appRoute = AppRoute(tabManager);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => TabManager())
],
child: Router(routerDelegate: _appRoute),
),
);
}
}
I have some error in the Flutter code main.dart file .I create AuthService class,I create Provider method in the main.dart file, but it has some error at the call up the Provider method . i need solve this error.
enter image description here
import 'package:flutter/material.dart';
import 'package:trip/screen/first_screen.dart';
import 'package:trip/screen/sign_up_screen.dart';
import 'package:trip/services/auth_service.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return Provider(
auth: AuthService,
child: MaterialApp(
title: 'Test FireBase',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: FirstScreen(),
routes: <String, WidgetBuilder>{
'/signUp': (BuildContext context) => SignUpScreen(),
'/home': (BuildContext context) => FirstScreen(),
},
),
);
}
}
class Provider extends InheritedWidget {
final AuthService auth;
Provider(Key key, Widget child, this.auth) : super(key: key, child: child);
#override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static Provider of(BuildContext context) =>
(context.dependOnInheritedWidgetOfExactType<Provider>() as Provider);
}
You are getting the error because the Provider constructor you made is working with positional parameters, not with named. For more information on named and positional parameters check out this post.
You can either change your constructor to work with named parameters like this:
Provider({Key? key, required Widget child, required this.auth}) : super(key: key, child: child);
or you can remove namings of your parameters in the cosntructor call like this:
return Provider(
UniqueKey(),
MaterialApp(
...
),
AuthService(),
);
I would prefer the first solution.
When I run this I keep getting the same error , kindly assist.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(App());
}
class App extends StatelessWidget {
final Color primaryColor = Color(0xff18203d);
#override
Widget build(BuildContext context) {
// ignore: todo
// TODO: implement build
return MultiProvider(
providers: [
Provider<AuthenticationService>(
create: (_) => AuthenticationService(FirebaseAuth.instance),
),
StreamProvider(
create: (_context) =>
_context.read<AuthenticationService>().authStateChanges,
initialData: null,
),
],
child: MaterialApp(
title: 'Mboka Horticulture',
theme: ThemeData(
primaryColor: primaryColor,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: AuthenticationWrapper(),
));
}
}
class AuthenticationWrapper extends StatelessWidget {
const AuthenticationWrapper({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
// ignore: todo
// TODO: implement build
final firebaseuser = context.watch<User>();
if (firebaseuser != null) {
return Dashboard();
}
return Login();
}
}
This is the error I keep getting and I don't understand.
**Providers are "scoped". So if you insert of provider inside a
route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that AuthenticationWrapper is under your MultiProvider/Provider<User>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:**
I'm using Provider v4.0.0 and when I hot reload the app I lose state from Provider class.
I know provider preserves it's state so obviously my code has some flaw. But I'm unable to find out what's wrong with my code.
Following is my main.dart file :
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:scapperapp/provider/auth.dart';
import 'package:scapperapp/screens/authenticated.dart';
import 'package:scapperapp/screens/homepage.dart';
import 'package:scapperapp/screens/login.dart';
import 'package:scapperapp/screens/started.dart';
void main() {
HttpOverrides.global = new MyHttpOverrides();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [ChangeNotifierProvider(create: (context) => User())],
child: Consumer<User>(
builder: (context, User user, _) => MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.deepPurple,
primaryColor: Color(0xFF5B5A92),
accentColor: Color(0xFFadacdf),
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: user.isAuthorised
? HomeScreen()
: FutureBuilder(
future: user.tryAutoLogin(),
builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState ==
ConnectionState.waiting
? HomePage()
: HomePage(),
),
routes: {
SignupChoice.routeName: (context) => SignupChoice(),
LoginPage.routeName: (context) => LoginPage(),
HomeScreen.routeName: (context) => HomeScreen()
},
),
));
}
}
class MyHttpOverrides extends HttpOverrides {
#override
HttpClient createHttpClient(SecurityContext context) {
return super.createHttpClient(context)
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
}
I have a scenario wherein I check the value of SharePreferences based on the value it will redirect the user to HomePage or LandingPage. I am not sure where did I got wrong? but I am getting this error below: I guess its not getting the context right any idea how do I get it?.
Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
E/flutter (11533): The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
Here is my code:
import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<MyApp> {
#override
void initState() {
super.initState();
getUserStatus().then((userStatus) {
if (userStatus == null) {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return LandingPage();
}));
} else {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return HomePage();
}));
}
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: CircularProgressIndicator(),
));
}
}
Future<String> getUserStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String userStatus = prefs.getString('userstatus');
print("==On Load Check ==");
print(userStatus);
return userStatus;
}
When you call Navigator.of(context) framework goes up in widget tree attached to provided context and tries to find the closest Navigator.
The widget tree you showed does not have one, so you need to include Navigator in the widget tree.
Easiest option is to use MaterialApp with your widget passed as home. MaterialApp is creating navigator inside itself. (CupertinoApp does it too)
Updated code from original example:
import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: LoadingPage(),
);
}
}
class LoadingPage extends StatefulWidget {
LoadingPage({Key key}) : super(key: key);
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<LoadingPage> { // note type update
#override
void initState() {
super.initState();
getUserStatus().then((userStatus) {
if (userStatus == null) {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return LandingPage();
}));
} else {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return HomePage();
}));
}
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: CircularProgressIndicator(),
));
}
}
Future<String> getUserStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String userStatus = prefs.getString('userstatus');
print("==On Load Check ==");
print(userStatus);
return userStatus;
}
I have changed my code from
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo App',
theme: ThemeData(
primarySwatch: white,
scaffoldBackgroundColor: Colors.white,
),
home: Scaffold(
appBar: AppBar(
title: Text('Demo App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
HomeScreen(title: 'Demo Home')));
},
child: Text('Open Home Screen'))
],
),
),
),
);
}
To
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo App',
theme: ThemeData(
primarySwatch: white,
scaffoldBackgroundColor: Colors.white,
),
home: InitScreen());
}
}
class InitScreen extends StatelessWidget {
const InitScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
HomeScreen(title: 'Demo Home')));
},
child: Text('Open Home Screen'))
],
),
),
);
}
What changed?
Create a separate widget for home code in MyApp with InitScreen
What was the issue?
When we try to push Route by using Navigator.of(context), flutter will
try to find Navigator in the widget tree of the given context. In the
initial code, there was no widget that has Navigator. So, create a
separate widget for home code. And the MaterialApp widget in MyApp
will have Navigator.