Flutter main.dart initialRout is not Working - flutter

I'm New in this FrameWork and here initial Rout is not Accepting the Loggin Session value Please help me with this. I tried to add Home with the splash screen but that also not working I'm not getting What's wrong in this.
This is my main Page
Future main() async {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
));
runApp(Phoenix(child: AmericanCuisine()));
}
class AmericanCuisine extends StatefulWidget {
#override
_AmericanCuisineState createState() => _AmericanCuisineState();
}
class _AmericanCuisineState extends State<AmericanCuisine> {
bool isLoggedIn;
#override
void initState() {
super.initState();
getData();
}
getData() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences storage = await SharedPreferences.getInstance();
setState(() {
isLoggedIn = storage.getBool("loggedIn");
});
}
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<LanguageCubit>(
create: (context) => LanguageCubit(),
),
BlocProvider<ThemeCubit>(
create: (context) => ThemeCubit(),
),
],
in this page after using BlockBuilder how i To give the Initial Route
child: BlocBuilder<ThemeCubit, ThemeData>(
builder: (_, theme) {
return BlocBuilder<LanguageCubit, Locale>(
builder: (_, locale) {
return MaterialApp(
localizationsDelegates: [
const AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en'),
],
locale: locale,
theme: theme,
//This initial rout is not working.
initialRoute: isLoggedIn == false ?'/': '/homeOrderAccount',
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => OpeningScreen(),
'/homeOrderAccount': (context) => HomeOrderAccount(),
},
);
},
);
},
),
);
}
}

You can't use initialRoute with routes map either delete '/' from the routes map or delete the initialRoute:

Related

HomeController not found. You need to call Get.put(HomeController()) or Get.lazyPut(()=>HomeController())

I made a todo app using Getx package. I also created a login page and I want to display the login page only one time but when I try to do this I a got error
"HomeController" not found. You need to call Get.put(HomeController()) or Get.lazyPut(()=>HomeController()).
this is my binding
class HomeBinding implements Bindings {
#override
void dependencies() {
Get.lazyPut(() => HomeController(
taskRepository: TaskRepository(
taskProvider: TaskProvider(),
),
));
}
}
this is my main.dart
int? isViewed;
void main() async {
await GetStorage.init();
await Get.putAsync(() => StorageService().init());
WidgetsFlutterBinding.ensureInitialized();
await ScreenUtil.ensureScreenSize();
await GetStorage.init();
await Get.putAsync(() => StorageService().init());
LicenseRegistry.addLicense(() async* {
final license = await rootBundle.loadString('google_fonts/OFL.txt');
yield LicenseEntryWithLineBreaks(['google_fonts'], license);
});
SharedPreferences prefs = await SharedPreferences.getInstance();
isViewed = prefs.getInt('login');
runApp(MyApp());
}
class MyApp extends GetView<HomeController> {
const MyApp({
Key? key,
}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.transparent));
return ScreenUtilInit(
designSize: const Size(360, 800),
minTextAdapt: true,
splitScreenMode: true,
builder: (context, child) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: Themes.light,
darkTheme: Themes.dark,
themeMode: ThemeMode.light,
home: isViewed != 0 ? Login() : Report(),
initialBinding: HomeBinding(),
builder: EasyLoading.init(),
);
});
}
}
This is the error
Try adding HomeBinding in getPages array of GetMaterialApp.
Also apply below modifications in below scope
GetMaterialApp(
// initialBinding: HomeBinding(), ====>> Remove this line
initialRoute: '/home', // ====>> Add this line
getPages: [
GetPage(
name: "/home",
page: () => const HomeScreen(),
binding: HomeBinding(),
),
// ====>> Add other pages like home
]
);

Flutter - How to test page navigation when using a viewmodel with Provider

I am trying to write widget tests for my Flutter application.
I have a page (MainMenuScreen) as follows (I've left out the imports):
class MainMenuScreen extends StatefulWidget {
#override
_MainMenuScreenState createState() => _MainMenuScreenState();
}
class _MainMenuScreenState extends State<MainMenuScreen> {
#override
void initState() {
super.initState();
}
late MainMenuViewModel vm;
#override
Widget build(BuildContext context) {
vm = Provider.of<MainMenuViewModel>(context);
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Center(
child: Column(
children: <Widget>[
generateHeightSpacer(Dimensions().heightSpace),
generateLogo(Dimensions().fractionalWidth),
generateHeightSpacer(Dimensions().fractionalWidth),
generateMenuButton(
context,
Dimensions().fractionalWidth,
Dimensions().fractionalHeight,
AppLocalizations.of(context).menuPlay,
LevelSelectionScreen()),
generateHeightSpacer(Dimensions().heightSpace),
generateMenuButton(
context,
Dimensions().fractionalWidth,
Dimensions().fractionalHeight,
AppLocalizations.of(context).menuAbout,
AboutScreen()),
],
),
)),
);
}
}
My main.dart file looks like this:
void main() {
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) => MainMenuViewModel()),
ChangeNotifierProvider(create: (context) => LevelSelectionViewModel()),
ChangeNotifierProvider(create: (context) => LevelViewModel()),
],
child: MaterialApp(
onGenerateTitle: (context) {
return AppLocalizations.of(context).appTitle;
},
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('en', ''), // English, no country code
Locale('es', ''), // Spanish, no country code
],
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ChangeNotifierProvider(
create: (context) => MainMenuViewModel(),
child: MainMenuScreen(),
// ),
),
),
);
}
}
I have looked into how to write a test that can identify when the About screen is displayed, i.e. after pressing the last Menu Button.
So, for now I have something as follows:
testWidgets("Flutter Main Menu Test Menu Button About",
(WidgetTester tester) async {
await tester.pumpWidget(MyApp());
var button = find.text("About");
expect(button, findsOneWidget);
});
This allows me to identify that the About button is displayed. (Note: I will be changing my code and tests to do this based on a 'key' rather than text.)
From what I've read the way to test is to use Mockito and a NavigationObserver but that seems to require the ability to inject into the screen. I have also been looking at other solutions which seem to suggest wrapping the provider, i.e.:
I've been following this page(https://iiro.dev/writing-widget-tests-for-navigation-events/) to try to test but I can't quite figure out how to pass the viewmodel in.
This is my test at the moment:
class MockMainMenuViewModel extends Mock implements MainMenuViewModel {}
class MockNavigatorObserver extends Mock implements NavigatorObserver {}
void main() {
group('MainMenuScreen navigation tests', () {
late NavigatorObserver mockObserver;
MockMainMenuViewModel? mockViewModel;
setUp(() {
mockObserver = MockNavigatorObserver();
mockViewModel = MockMainMenuViewModel();
});
Future<void> _buildMainPage(WidgetTester tester) {
return tester.pumpWidget(MaterialApp(
home: MainMenuScreen(mockViewModel),
navigatorObservers: <NavigatorObserver>[observer],
));
}
});
}
Any help is appreciated please.

ChangeNotifierProvider isn't listening

I am attempting to share a ChangeNotifierProvider to my main.dart, however the value never gets updated.
How it works
main.dart uses ChangeNotifierProvider to get an instance of the class Location()
main.dart routes to the location_login.dart page where a string in Location() class is set.
The instance of Location() should update in main.dart but it DOES NOT.
Here is the main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
ChangeNotifierProvider<Location>.value( <------ CREATE CHANGENOTIFIERPROVIDER
value: Location(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
Location location = Provider.of<Location>(context, listen: false); <----- LISTEN TO PROVIDER
return MultiProvider(
providers: [
FutureProvider<List<Report>>(
create: (context) =>
Collection<Report>(path: '${location.getLocation}/data/reports') <----- USE PROVIDER STRING IN PATH
.getUsers(),
initialData: [],
),
],
child: MaterialApp(
routes: {
'/': (context) => LocationLogin(),
'/login': (context) => LoginScreen(),
'/home': (context) => HomeScreen(),
},
// Theme
theme: ThemeData(
fontFamily: 'Nunito',
bottomAppBarTheme: BottomAppBarTheme(
color: Colors.black87,
),
// your customizations here
brightness: Brightness.dark,
buttonTheme: ButtonThemeData(),
),
),
);
}
}
Here is the location_login.dart
#override
Widget build(BuildContext context) {
Location location = Provider.of<Location>(context, listen: true);
return Scaffold(
body: TextButton(
child: Text("Submit",
style: GoogleFonts.poppins(
fontSize: 15.sp, color: Colors.white)),
onPressed: () {
location.setLocation('London'); <------- SETTING LOCATION
}),
);
}
}
Here is the location.dart
class Location with ChangeNotifier {
String place = 'none';
String get getLocation => place;
setLocation(String location) {
place = location;
notifyListeners();
}
}
To reiterate, the issue is that when I click the button in the location_login.dart page to set the location to "London"; it does not update the ChangeNotifierProvider with a new instance of the Location() class containing "London". Therefore, I can not update the path in my FurtureProvider. Any ideas of what is going wrong here? I tried to make this as clear as possible but if you don't understand please ask. Thank you
I think you have not consume the ChangeNotifierProvider.
For me below simple implementation work perfectly.
my main.dart file code is as below...
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'providers/app_provider.dart';
import 'providers/favorites_provider.dart';
import 'providers/comments_provider.dart';
import 'providers/home_provider.dart';
import 'providers/details_provider.dart';
import 'providers/gallery_provider.dart';
import 'providers/chat_provider.dart';
import 'ui/splash.dart';
import 'helper/constants.dart';
import 'ui_user/login.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AppProvider()),
ChangeNotifierProvider(create: (_) => GalleryProvider()),
ChangeNotifierProvider(create: (_) => CommentsProvider()),
ChangeNotifierProvider(create: (_) => ChatProvider()),
ChangeNotifierProvider(create: (_) => HomeProvider()),
ChangeNotifierProvider(create: (_) => DetailsProvider()),
ChangeNotifierProvider(create: (_) => FavoritesProvider()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<AppProvider>(
builder: (BuildContext context, AppProvider appProvider, Widget child) {
return MaterialApp(
key: appProvider.key,
debugShowCheckedModeBanner: false,
navigatorKey: appProvider.navigatorKey,
title: Constants.appName,
theme: appProvider.theme,
home: appProvider.isLogin == "0" ? LoginPage() : Splash(),
);
},
);
}
}
And my app_provider.dart as below...
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../helper/constants.dart';
class AppProvider extends ChangeNotifier {
AppProvider() {
checkTheme();
}
String isLogin = "0";
ThemeData theme = Constants.lightTheme;
Key key = UniqueKey();
GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void setKey(value) {
key = value;
notifyListeners();
}
void setNavigatorKey(value) {
navigatorKey = value;
notifyListeners();
}
void setTheme(value, c) {
theme = value;
SharedPreferences.getInstance().then((prefs) {
prefs.setString("theme", c).then((val) {
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor:
c == "dark" ? Constants.darkPrimary : Constants.lightPrimary,
statusBarIconBrightness:
c == "dark" ? Brightness.light : Brightness.dark,
));
});
});
notifyListeners();
}
ThemeData getTheme(value) {
return theme;
}
Future<ThemeData> checkTheme() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
ThemeData t;
String r =
prefs.getString("theme") == null ? "light" : prefs.getString("theme");
isLogin = prefs.getString("isLogin") == null? "0" : prefs.getString("isLogin");
if (r == "light") {
t = Constants.lightTheme;
setTheme(Constants.lightTheme, "light");
} else {
t = Constants.darkTheme;
setTheme(Constants.darkTheme, "dark");
}
return t;
}
}
This solution is working very well for me. Hope this will help you too...

Flutter. Could not find the correct Provider<ThemeChanger> above this Home Widget

I wanted to add theme with provider to my code. I adapted it from this source. https://github.com/lohanidamodar/flutter_theme_provider/blob/master/lib/main.dart .
Even it is same code, I got this error:
"The following ProviderNotFoundException was thrown building Home(dirty, state: _HomeState#c900c):
Error: Could not find the correct Provider above this Home Widget"
This happens because you used a BuildContext that does not include the provider
of your choice.
void main() async {
setPathUrlStrategy();
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialAppWithTheme());
}
class MaterialAppWithTheme extends StatefulWidget {
#override
_MaterialAppWithThemeState createState() => _MaterialAppWithThemeState();
}
class _MaterialAppWithThemeState extends State<MaterialAppWithTheme> {
#override
void initState() {
super.initState();
AppRouter appRouter = AppRouter(
routes: AppRoutes.routes,
notFoundHandler: AppRoutes.routeNotFoundHandler,
);
appRouter.setupRoutes();
}
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => ThemeNotifier(),
child: Consumer<ThemeNotifier>(
builder: (context, ThemeNotifier notifier, child) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: notifier.darkTheme ? dark : light,
onGenerateRoute: AppRouter.router.generator,
);
},
),
);
}
}
Change this:
create: (_) => ThemeNotifier(),
To this:
create: (context) => ThemeNotifier(),

Could not use Provider.of in child widgets

I have my main() like this with MultiProvider wrapped with LocalizedApp for localization:
void main() async {
setupLocator();
var delegate = await LocalizationDelegate.create(
fallbackLocale: 'fa',
supportedLocales: ['fa'],
);
FluroRouter.setupRouter();
WidgetsFlutterBinding.ensureInitialized();
await FlutterDownloader.initialize(debug: true);
runApp(
LocalizedApp(
delegate,
MultiProvider(
providers: [
StreamProvider<ConnectionStatus>(
create: (context) =>
ConnectivityService().connectivityController.stream,
initialData: ConnectionStatus.offline,
),
ChangeNotifierProvider<AppState>(
create: (BuildContext context) => AppState(),
),
],
child: MyApp(),
),
),
);
}
and MyApp class is as follows again wrapped with LocalizationProvider:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final appstate = Provider.of<AppState>(context);
var localizationDelegate = LocalizedApp.of(context).delegate;
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: appstate.statusBarColor,
));
return LocalizationProvider(
state: LocalizationProvider.of(context).state,
child: GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
},
child: MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
localizationDelegate
],
supportedLocales: localizationDelegate.supportedLocales,
locale: localizationDelegate.currentLocale,
theme: appstate.currentTheme,
initialRoute: 'landing',
onGenerateRoute: FluroRouter.router.generator,
),
),
);
}
}
but even in the initial route which is 'landing' when I try to use a Provider.of<AppState>(context) it throws this error:
Error: Could not find the correct Provider<AppState> above this Landing Widget
This likely happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- The provider you are trying to read is in a different route.
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 Landing is under your MultiProvider/Provider<AppState>.
This usually happen when you are creating a provider and trying to read it immediatly.
For example, instead of:
Widget build(BuildContext context) {
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
builer: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
I don't know what I'm doing wrong here!
also I'm using Fluro v.1.5.1 for navigation.