i want to implement conditional routing with auto route package
isLoggedIn returns true but
autoroute redirects to login page,
how can i resolve this problem
import 'package:animated_splash_screen/animated_splash_screen.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:expense/config/routes/app_router.dart';
import 'package:expense/config/themes/theme_config.dart';
import 'package:expense/constants/assets_path_constants.dart';
import 'package:expense/constants/constants.dart';
import 'package:expense/core/auth/login/bloc/cubit/auth_cubit.dart';
import 'package:expense/core/auth/login/repository/mongodb/mongo_auth_repository.dart';
import 'package:expense/utils/services/lang/language_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'core/splash_screen.dart';
Future<void> main() async {
statusBar();
await _init();
runApp(
EasyLocalization(
supportedLocales: LanguageService.instance.supportedLocales,
path: AssetsPath.langAssetPath,
child: const Expense(),
),
);
}
void statusBar() {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: ColorConstants.backgroundColor,
systemNavigationBarIconBrightness: Brightness.dark,
),
);
}
Future<void> _init() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
}
class Expense extends StatefulWidget {
const Expense({Key? key}) : super(key: key);
#override
State<Expense> createState() => _ExpenseState();
}
class _ExpenseState extends State<Expense> {
final _appRouter = AppRouter();
bool isLoggedIn = false;
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => AuthCubit(MongoAuthRepository()),
child: BlocConsumer<AuthCubit, AuthState>(
builder: (context, state) {
context.read<AuthCubit>().isValid();
return _buildMaterialApp(context, state);
},
listener: (context, state) {
if (state is TokenIsValid) {
isLoggedIn = state.isValid;
}
},
),
);
}
MaterialApp _buildMaterialApp(BuildContext context, AuthState state) {
print(isLoggedIn);
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Gider',
// Tost Mesajı Init
builder: BotToastInit(),
theme: CustomTheme.primaryTheme,
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
home: AnimatedSplashScreen(
splash: const SplashPage(),
animationDuration: const Duration(seconds: 2),
nextScreen: MaterialApp.router(
debugShowCheckedModeBanner: false,
theme: CustomTheme.primaryTheme,
routeInformationParser: _appRouter.defaultRouteParser(includePrefixMatches: true),
routerDelegate: _appRouter.delegate(
initialRoutes: [
if (isLoggedIn) HomeRoute(response: null) else const LoginRoute(),
],
),
),
),
);
}
}
Related
I have this error while trying to change language locally using the flutter provider here is the error Exception caught by widgets library
The following LateError was thrown building Builder(dirty, dependencies: [_InheritedProviderScope<LocaleProvider?>]):
LateInitializationError: Field '_locale#49012749' has not been initialized.
The relevant error-causing widget was
ChangeNotifierProvider
When the exception was thrown, this was the stack
my code:
`
import 'package:flutter/material.dart';
import '../l10n/l10n.dart';
class LocaleProvider extends ChangeNotifier {
late Locale? _locale;
Locale get locale => _locale!;
void setLocale(Locale locale) {
if (!L10n.all.contains(locale)) return;
_locale = locale;
notifyListeners();
}
void clearlocale() {
_locale = null;
notifyListeners();
}
}
final provider = Provider.of<LocaleProvider>(context);
final locale = provider.locale;
DropdownButtonHideUnderline(
child: DropdownButton(
value: locale,
icon: Container(width: 12),
items: L10n.all.map(
(locale) {
final flag = L10n.getFlag(locale.languageCode);
return DropdownMenuItem(
child: Center(
child: Text(flag),
),
value: locale,
onTap: () {
final provider = Provider.of<LocaleProvider>(context,
listen: false);
provider.setLocale(locale);
},
);
},
).toList(),
onChanged: (Locale? value) {
// value=locale
},
)),
import 'package:flutter/material.dart';
class L10n {
static final all = [
const Locale('en'),
const Locale('ar'),
];
static getFlag(String code) {
switch (code) {
case 'ar':
return '🇱🇧';
case 'en':
default:
return 'en';
}
}
}
`
main:
`
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:thrifty/constants/utils.dart';
import 'package:thrifty/provider/locale_provider.dart';
import 'l10n/l10n.dart';
import 'screens/splash_screen.dart';
import 'package:flutter_gen/gen_l10n/app_localization.dart';
import 'package:provider/provider.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
final navigatorKey = GlobalKey<NavigatorState>();
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) => ChangeNotifierProvider(
create: (context) => LocaleProvider(),
builder: (context, child) {
final provider = Provider.of<LocaleProvider>(context);
return MaterialApp(
scaffoldMessengerKey: Utils.messengerKey,
navigatorKey: navigatorKey,
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
supportedLocales: L10n.all,
// ignore: prefer_const_literals_to_create_immutables
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
locale: provider.locale,
home: SplashScreen(),
);
});
}
`
language only can change when I change language in my phone, but I am trying to do it locally.
This happens because access to the _local property happens before initialisation.
Add initialisation with default value or pass it via constructor:
class LocaleProvider extends ChangeNotifier {
Locale? _locale;
Locale get locale => _locale!;
LocaleProvider(Locale locale): _locale = locale;
void setLocale(Locale locale) {
if (!L10n.all.contains(locale)) return;
_locale = locale;
notifyListeners();
}
void clearlocale() {
_locale = null;
notifyListeners();
}
}
Update
Add to your pubspec.yaml dependency flutter_localisation
dependencies:
flutter:
sdk: flutter
flutter_localizations: # Add this line
sdk: flutter # Add this line
In your main.dart file add import
import 'package:flutter_localizations/flutter_localizations.dart';
Wrap your MyApp widget with MaterialApp
void main() {
runApp(
const MaterialApp(
title: 'Application title',
localizationsDelegates: <LocalizationsDelegate<dynamic>>[
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: <Locale>[
// Your supported locales
Locale('de'),
Locale('en'),
Locale('es')
],
home: MyApp(), // All Localized Widgets must be placed inside home widget.
)
);
}
And your main will look like:
final navigatorKey = GlobalKey<NavigatorState>();
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MaterialApp(
title: 'Application title',
localizationsDelegates: <LocalizationsDelegate<dynamic>>[
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: <Locale>[
// Your supported locales
Locale('de'),
Locale('en'),
Locale('es')
],
home: MyApp(), // All Localized Widgets must be placed inside home widget.
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) => ChangeNotifierProvider(
create: (context) => LocaleProvider(Localizations.localeOf(context)),
builder: (context, child) {
final provider = Provider.of<LocaleProvider>(context);
return MaterialApp(
scaffoldMessengerKey: Utils.messengerKey,
navigatorKey: navigatorKey,
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
supportedLocales: L10n.all,
// ignore: prefer_const_literals_to_create_immutables
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
locale: provider.locale,
home: SplashScreen(),
);
});
}
I am working on a social media app which contains a home screen with bottom navbar and 5 pages .
Although i am able to change the bool value to show or hide navbar under provider but the changes are not reflecting in widget .
main.dart -
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) =>
ScrollProvider(),
),
],
child : MyApp()
My provider class -
class ScrollProvider with ChangeNotifier{
bool isVisible = true;
void show() {
isVisible = true;
print("in Provider $isVisible");
notifyListeners();
}
void hide() {
isVisible = false;
print("in Provider $isVisible");
notifyListeners();
}
}
Page which has the value scrollcontroller
ScrollController _scrollController =
ScrollController();
_scrollController.addListener(() {
final direction =
_scrollController.position.userScrollDirection;
if (direction == ScrollDirection.forward) {
ScrollProvider().show();
}
if (direction == ScrollDirection.reverse) {
ScrollProvider().hide();
}
});
And my homescreen which which has body and navbar contains this code
‘’’
bottomNavigationBar: Consumer<BottomBarVisibilityProvider>(
builder: (context, bottomBarVisibilityProvider, child) =>
AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: bottomBarVisibilityProvider.isVisible
? Wrap(
children: const [BottomBar()],
)
: Wrap(),
),
),
I have initialised the provider inside main.dart
Can someone tell me why its not working .. and what should i do
here is the full code of homepage
class _HomeState extends State<Home> {
List<Widget> _pages ;
#override
void initState() {
super.initState();
_pages = [
MemeTabView(scrollController: scrollToHide),
TempTab(),
null,
NotificationScreen(),
ProfileScreen(uid: FirebaseAuth.instance.currentUser.uid,showAppBar: false),
];
}
#override
Widget build(BuildContext context) {
if (widget.selectedIndex == null) {
widget.selectedIndex = 0;
}
return
Scaffold(
appBar: AppBar(
title: brandName(),
),
extendBody: true,
bottomNavigationBar:
Consumer<ScrollProvider>(
builder: (_,scrollProvider,__){
return Container(
child: scrollProvider.isVisible == true
?
bottomNav()
: Container(),
);
},
),
drawer: MyDrawer(),
body:PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
children: _pages,
),
);
}
You need to read provider like
context.read<BottomBarVisibilityProvider>();
void main() {
runApp(
/// Providers are above [MyApp] instead of inside it, so that tests
/// can use [MyApp] while mocking the providers
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => BottomBarVisibilityProvider()),
],
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.\
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: const SCCR(),
);
}
}
class SCCR extends StatefulWidget {
const SCCR({Key? key}) : super(key: key);
#override
State<SCCR> createState() => _SCCRState();
}
class _SCCRState extends State<SCCR> {
//just for test purpose
late final bottomBarVisibilityProvider =
context.read<BottomBarVisibilityProvider>();
late final ScrollController scrollController = ScrollController()
..addListener(() {
final direction = scrollController.position.userScrollDirection;
if (direction == ScrollDirection.forward) {
if (!bottomBarVisibilityProvider.isVisible) {
bottomBarVisibilityProvider.show();
}
} else if (direction == ScrollDirection.reverse) {
if (bottomBarVisibilityProvider.isVisible) {
bottomBarVisibilityProvider.hide();
}
}
});
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
controller: scrollController,
child: Container(
height: 3333,
),
),
bottomNavigationBar: Consumer<BottomBarVisibilityProvider>(
builder: (context, bottomBarVisibilityProvider, child) =>
AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: bottomBarVisibilityProvider.isVisible
? Wrap(
children: [
Container(
height: 100,
color: Colors.red,
width: 100,
)
],
)
: null,
),
),
);
}
}
I will suggest to follow documentation
This is how I use my providers:
I have 3 different providers here, MyThemeClass, NewMsgListener and FirebaseProvider. All of them extend ChangeNotifierProvider. And this is my main:
import 'package:my_app/my_firebase.dart';
import 'package:my_app/global.dart';
import 'package:provider/provider.dart';
import 'package:navigation_history_observer/navigation_history_observer.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:my_app/firebase_options.dart';
import 'package:my_app/screens/welcome_screen.dart';
import 'package:my_app/new_msg_listener.dart';
import 'package:my_app/provider_updates.dart';
import 'package:my_app/theme.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
MyFirebase.myFutureFirebaseApp =
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
final NewMsgListener newMsgListener = NewMsgListener();
final MyThemeClass myThemeClass = MyThemeClass();
await myThemeClass.getMyTheme();
print('getMyTheme() is ready');
await MyFirebase.myFutureFirebaseApp;
runApp(MyApp(myThemeClass, newMsgListener));
}
class MyApp extends StatelessWidget {
const MyApp(this.myThemeClass, this.newMsgListener, {Key? key})
: super(key: key);
final MyThemeClass myThemeClass;
final NewMsgListener newMsgListener;
#override
Widget build(BuildContext context) {
print('Building $runtimeType');
FirebaseProvider firebaseProvider = FirebaseProvider();
firebaseProvider.initialize(GlobalVariable.navState);
return MultiProvider(
providers: [
ChangeNotifierProvider<FirebaseProvider>(
create: (context) => firebaseProvider),
ChangeNotifierProvider(create: (context) => myThemeClass),
ChangeNotifierProvider(create: (context) => newMsgListener),
],
builder: (context, child) {
return MaterialApp(
theme: Provider.of<MyThemeClass>(context).currentTheme,
home: WelcomeScreen(myThemeClass),
debugShowCheckedModeBanner: false,
navigatorObservers: [NavigationHistoryObserver()],
navigatorKey: GlobalVariable.navState,
);
});
}
}
Not that it's important, but my my_firebase.dart file looks like this (just so you don't need to wonder!):
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:my_app/firebase_labels.dart';
class MyFirebase {
static Future<FirebaseApp>? myFutureFirebaseApp; //Initialized from main()
static FirebaseFirestore storeObject = FirebaseFirestore.instance;
static auth.FirebaseAuth authObject = auth.FirebaseAuth.instance;
}
Does that provider management work for you?
the following error occurs after I tried adding the provider feature to my app:
Error: Could not find the correct Provider above this Consumer Widget
This is my code for the ChangeNotifier:
import 'package:flutter/material.dart';
class AppStateNotifier extends ChangeNotifier {
bool isDarkMode = false;
void updateTheme(bool isDarkMode) {
this.isDarkMode = isDarkMode;
notifyListeners();
}
}
And there is my main class:
import 'package:wilson/src/config/theme_data.dart';
import 'package:wilson/src/routes/index.dart';
import 'package:wilson/src/utils/app_state_notifier.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Wilson extends StatelessWidget {
const Wilson({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Consumer<AppStateNotifier>(builder: (context, appState, child) {
return MaterialApp(
title: 'App-Name',
theme: ThemeConfig.lightTheme,
darkTheme: ThemeConfig.darkTheme,
themeMode: appState.isDarkMode ? ThemeMode.dark : ThemeMode.light,
onGenerateRoute: routes,
);
});
}
}
Maybe someone can help me with that, because I believe it's just a stupid little mistake.
You have to initialize this into your main.dart like this.
You can use multi provider if you have more than one provider files.
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: Doctorss()),
ChangeNotifierProvider.value(value: Categoriess()),
ChangeNotifierProvider.value(value: TopDoctors()),
ChangeNotifierProvider.value(value: Appointments()),
ChangeNotifierProvider.value(value: TopArticlesProvider()),
],
child: MaterialApp(
theme: ThemeData(
appBarTheme: AppBarTheme(color: Colors.blue[800]),
primaryColor: Colors.blue[800],
colorScheme:
ColorScheme.fromSwatch().copyWith(secondary: Colors.orange)),
debugShowCheckedModeBanner: false,
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapShot) {
if (snapShot.connectionState == ConnectionState.waiting) {
return const Start();
}
if (snapShot.hasData) {
return const homestate();
}
return const AuthScreen();
}),
I'm creating a flutter application that needs to load email and theme from preferences settings. Loading email will check whether the user is authenticated while loading the theme will check whether the theme is light or dark mode. The problem I'm facing is that dark or light mode is getting applied after the interface has been created. I know that using the future builder can help solve this but I have no idea on how to use it in theme.dart file. Any help please.
theme.dart file
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
CustomTheme customTheme = CustomTheme();
class CustomTheme extends ChangeNotifier {
static bool isDarkTheme = false;
ThemeData get currentTheme => isDarkTheme
? ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: Colors.grey.shade900,
primaryColor: Colors.white,
accentColor: Colors.blue,
iconTheme: const IconThemeData(color: Colors.white, opacity: 0.8),
)
: ThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: Colors.white,
primaryColor: Colors.black,
accentColor: Colors.blue,
iconTheme: const IconThemeData(color: Colors.black, opacity: 0.8),
dividerColor: Colors.black12,
);
CustomTheme() {
loadPrefs();
}
void toggleTheme() {
isDarkTheme = !isDarkTheme;
savePrefs();
notifyListeners();
}
void savePrefs() async {
SharedPreferences _prefs = await SharedPreferences.getInstance();
_prefs.setBool('theme', isDarkTheme);
}
void loadPrefs() async {
SharedPreferences _prefs = await SharedPreferences.getInstance();
isDarkTheme = _prefs.getBool('theme') ?? false;
notifyListeners();
}
}
main.dart file
import 'package:chatapp/home.dart';
import 'package:chatapp/login.dart';
import 'package:chatapp/themes.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:shared_preferences/shared_preferences.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
Future<String> getSharedPrefs() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String _email = prefs.getString('email') ?? '';
return _email;
}
#override
void initState() {
super.initState();
customTheme.addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: customTheme.currentTheme,
home: FutureBuilder<String>(
future: getSharedPrefs(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
} else if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return const Text('Error');
} else if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return Home();
} else {
return Login();
}
} else {
return Text('State: ${snapshot.connectionState}');
}
},
),
);
}
}
Try below code hope its helpful to you.used Future.wait([]) method for that refer here
FutureBuilder(
future: Future.wait([
getSharedPrefs(),
// call your extra future method here
]),
builder:
),
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;
}
}