I'm attempting to enable auto-login by obtaining a token saved in the local mobile instance. I'm encountering this error. I'm using Provider for state management.
In my main file , I want to retrieve my token to check whether user has been logged in or not. What i'm, doing wrong ?
My Error
E/flutter ( 6547): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: No ScaffoldMessenger widget found.
E/flutter ( 6547): MyApp widgets require a ScaffoldMessenger widget ancestor.
E/flutter ( 6547): The specific widget that could not find a ScaffoldMessenger ancestor was:
E/flutter ( 6547): MyApp
E/flutter ( 6547): The ancestors of this widget were:
E/flutter ( 6547): _InheritedProviderScope<UserProvider?>
E/flutter ( 6547): ChangeNotifierProvider<UserProvider>
E/flutter ( 6547): _NestedHook
E/flutter ( 6547): MultiProvider
E/flutter ( 6547): [root]
E/flutter ( 6547): Typically, the ScaffoldMessenger widget is introduced by the MaterialApp at the top of your application widget tree.
Main.dart file
void main() {
runApp(MultiProvider(
providers: [ChangeNotifierProvider(create: (context) => UserProvider())],
child: const MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}):super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final AuthService authService = AuthService();
#override
void initState() {
// TODO: implement initState
authService.getUserData(context);
super.initState();
}
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ShopOne',
theme: ThemeData(
scaffoldBackgroundColor: GlobalVariables.backgroundColor,
textTheme: Theme.of(context)
.textTheme
.apply(bodyColor: Colors.white, displayColor: Colors.white),
colorScheme:
const ColorScheme.light(primary: GlobalVariables.secondaryColor),
appBarTheme: const AppBarTheme(
elevation: 0, iconTheme: IconThemeData(color: Colors.white)),
//
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
onGenerateRoute: ((settings) => generateRoute(settings)),
home: Provider.of<UserProvider>(context).user.token.isNotEmpty
? const HomeScreen()
: const AuthScreen()
);
if (Provider.of<UserProvider>(context).user.token.isNotEmpty) {
print('true');
} else {
print('false');
;
}
}
}
get user function
void getUserData(
BuildContext context,
) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString("auth-token");
if (token == null) {
prefs.setString('auth-token', '');
}
var tokenRes = await http.post(Uri.parse('$uri//tokenisvalid'),
headers: <String, String>{
'Content-Type': 'application/json;charset=UTF-8',
'auth-token': token!
});
print('tokenres working 1');
var response = jsonDecode(tokenRes.body);
if (response == true) {
http.Response userRes = await http.get(Uri.parse('$uri/'),
headers: <String, String>{
'Content-type': 'application/json;charset=UTF-8',
'auth-token': token
});
print('tokenres working 2');
var userProvider = Provider.of<UserProvider>(context, listen: false);
userProvider.setUser(userRes.body);
}
} catch (e) {
showSnackBar(context, e.toString());
}
}
This happened because the context that you used in showSnackBar, doesn't belongs to any Scaffold, you need to separate the MaterialApp's home to new StatefulWidget class like this:
class ScreenManager extends StatefulWidget {
const ScreenManager({Key? key}) : super(key: key);
#override
State<ScreenManager> createState() => _ScreenManagerState();
}
class _ScreenManagerState extends State<ScreenManager> {
#override
void initState() {
// TODO: implement initState
authService.getUserData(context);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Provider.of<UserProvider>(context).user.token.isNotEmpty
? const HomeScreen()
: const AuthScreen(),
);
}
void getUserData(BuildContext context) async {
try {
...
} catch (e) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showSnackBar(context, e.toString());
});
}
}
}
then use it like this:
home: ScreenManager();
Note: don't forget to remove authService.getUserData(context) from _MyAppState's initState.
Related
I have a push notification manager class that is singleton where I listen for notifications from Firebase FCM and I handle them based on the logic and open specific screens.
I init with BuildContext that PushtNotificatonManager class inside HomePage that iS called from main.dart.
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
PushNotificationsManager().listen(context);
}
This is code from main.dart
Future<void> backgroundHandler(RemoteMessage message) async {
print('Handling a background message ${message.messageId}');
print('Content of message: ' + message.toString());
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
configureInjections();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(backgroundHandler);
runApp(SayApp());
}
This is part of the code from PushNotificationsManager class
#injectable
class PushNotificationsManager {
static final PushNotificationsManager _instance = PushNotificationsManager._internal();
factory PushNotificationsManager() {
return _instance;
}
PushNotificationsManager._internal();
Future<void> listen(BuildContext context) async {
if (Platform.isIOS) {
NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,
provisional: false,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
await _handleNotifications(context);
}
} else {
await _handleNotifications(context);
}
}
Future<void> _handleNotifications(BuildContext context) async {
// gives the message on which user taps and it opened the app from terminated state
FirebaseMessaging.instance.getInitialMessage().then((message) {
if (message != null) {
openNotification(message, context);
}
});
// foreground
FirebaseMessaging.onMessage.listen((message) {
if (message.notification != null) {
_showInAppNotification(message);
}
});
// When the app is in background but opened and user taps on the notification
FirebaseMessaging.onMessageOpenedApp.listen((message) {
openNotification(message, context);
});
}
Inside showInAppNotifications I am trying to display notifications as pop up and when the user clicks on it, I try to open a specific screen.
void _displayInAppNotifications(RemoteMessage message) {
FlutterRingtonePlayer.playNotification();
showOverlayNotification((context) {
return GestureDetector(
onTap: () {
openNotification(message, context);
OverlaySupportEntry.of(context)!.dismiss();
},
child: SafeArea(
child: Card(
child: ListTile(
leading: message.data[NotificationType.NOTIFICATION_TYPE] ==
NotificationType.PRIVATE_MESSAGE_1_ON_1
? Avatar(text: message.notification!.title!)
: SizedBox.fromSize(
size: const Size(40, 40),
child: ClipOval(
child: Container(
child: SvgPicture.asset(SvgIcons.sayAppWaveLogo),
))),
title:
Text(message.notification!.title!, overflow: TextOverflow.ellipsis, maxLines: 1),
subtitle: Text(
message.notification!.body!,
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
trailing: IconButton(
icon: Icon(Icons.close),
onPressed: () {
OverlaySupportEntry.of(context)!.dismiss();
}),
),
),
),
);
}, duration: Duration(seconds: 4), position: NotificationPosition.top);
}
I have this method navigateToChannelDetailsPage that is called from the above method and here I am getting an exception.
Future<void> navigateToChannelDetailsPage(ChannelEntity channel, BuildContext context) async {
var cubit = BlocProvider.of<HomeCubit>(context);
var isUserChannelMember = await cubit.isCurrentUserChannelMember(channel);
if (!isUserChannelMember) return;
var isUserMutedPublic = await cubit.getIsUserMutedPublic(channel);
if (isUserMutedPublic) channel.isUserMutedPublic = isUserMutedPublic;
return PageNavigator.navigate(
context, ChannelDetailsPage(channel: channel, isFromAdminNotification: true))
.then((_) {
FocusManager.instance.primaryFocus?.unfocus();
cubit.updateChannelMemberChatDetailsDataOnChannelClosed(channel);
});
}
This is the exception:
E/flutter (25412): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter (25412): At this point the state of the widget's element tree is no longer stable.
E/flutter (25412): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter (25412): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:4241:9)
E/flutter (25412): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:4255:6)
E/flutter (25412): #2 Element.getElementForInheritedWidgetOfExactType (package:flutter/src/widgets/framework.dart:4286:12)
E/flutter (25412): #3 Provider._inheritedElementOf (package:provider/src/provider.dart:339:38)
E/flutter (25412): #4 Provider.of (package:provider/src/provider.dart:293:30)
E/flutter (25412): #5 BlocProvider.of (package:flutter_bloc/src/bloc_provider.dart:100:23)
E/flutter (25412): #6 PushNotificationsManager.navigateToChannelDetailsPage (package:say_app/presentation/notification/push_notifications_manager.dart:204:30)
E/flutter (25412): #7 PushNotificationsManager.openNotification (package:say_app/presentation/notification/push_notifications_manager.dart:180:9)
E/flutter (25412): <asynchronous suspension>
Any ideas?
You get that error because, by the time you wait for some things to finish the execution, you do something else on the app (go back one or few screens let's say) so your widget/screen gets disposed of and is no longer in the widget tree when you call PageNavigator.navigate(context, ...).
So to prevent that from happening, you can use the mounted flag to check if your StatefulWidget is still active, like:
if(mounted) PageNavigator.navigate(context, ...)
But in that case, the page will not get pushed if the widget is disposed of. So if you still want to push the new screen, no matter what happens in the meantime (even if that widget gets disposed of), you can have your global navigatorKey which you assign to the MaterialApp key property and use the context from navigatorKey while navigating, since it should always be usable (i.e. the MaterialApp should always be present in the widget tree). Solution example:
import 'package:flutter/material.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
home: const HomePage(),
);
}
}
So now you navigate like:
PageNavigator.navigate(navigatorKey.currentContext!, ...) // your use case
Navigator.of(navigatorKey.currentContext!).push(...) // the usual way using global navigatorKey
Hey I am building an app in flutter and when I run google sign in it gives me error that
E/flutter (30710): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter (30710): At this point the state of the widget's element tree is no longer stable.
E/flutter (30710): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
can anyone help on this
my main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerStatefulWidget {
const MyApp({super.key});
#override
ConsumerState<MyApp> createState() => _MyAppState();
}
class _MyAppState extends ConsumerState<MyApp> {
UserModel? userModel;
void getData(WidgetRef ref, User data) async {
userModel = await ref
.watch(authControllerProvider.notifier)
.getUserData(data.uid)
.first;
debugPrint("cdsdvs $userModel");
ref.read(userProvider.notifier).update((state) => userModel);
setState(() {});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mama App',
debugShowCheckedModeBanner: false,
theme: Pallete.darkModeAppTheme,
home: ref.watch(authStateChangeProvider).when(
data: (data) {
if (data != null) {
const HomeScreen();
}
return const LoginScreen();
},
error: ((error, stackTrace) => ErrorText(error: error.toString())),
loading: () => const Loader()),
);
}
}
There is probably a problem here:
void getData(WidgetRef ref, User data) async {
userModel = await ref
.watch(authControllerProvider.notifier)
.getUserData(data.uid)
.first;
debugPrint("cdsdvs $userModel");
ref.read(userProvider.notifier).update((state) => userModel);
setState(() {});
}
You should not use ref.watch in callbacks and asynchronous code. Use instead ref.read
I am new in flutter .I am tried googling but I cant fix my problem. I used "MultiBlocProvider" for manage stats . I want change dark mode state like bellow.
ThemeCubit.dart
part 'theme_state.dart';
class ThemeCubit extends HydratedCubit<ThemeState> {
ThemeCubit() : super(ThemeState(AppThemes.lightTheme));
void getTheme(ThemeState state) {
emit(state);
}
#override
ThemeState? fromJson(Map<String, dynamic> json) {
return json['isDark'] as bool
? ThemeState(AppThemes.darkTheme)
: ThemeState(AppThemes.lightTheme);
}
#override
Map<String, bool>? toJson(ThemeState state) {
return {'isDark': state.themeData.brightness == Brightness.dark};
}
}
ThemeState.dart
part of 'theme_cubit.dart';
#immutable
class ThemeState extends Equatable {
final ThemeData themeData;
const ThemeState(this.themeData);
#override
List<Object?> get props => [themeData];
}
main.dart
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 MultiBlocProvider(
providers: [
BlocProvider(
lazy: true,
create: (context) => ThemeCubit(),
),
],
child:BlocBuilder<ThemeCubit, ThemeState>(
builder: (context,state) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Production Boilerplate',
theme: state.themeData, //ThemeMode.dark,
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
},
),
);
}
}
settingScreen.dart
Positioned(
top: 60 - widget.offset / 2,
left: 20,
child: Builder(builder: (context) {
return Switch(
value:newValue ,
onChanged: (value) {
BlocProvider.of<ThemeCubit>(context).getTheme(ThemeState(
newValue ? AppThemes.darkTheme : AppThemes.lightTheme));
});
})
),
This code works properly when used "BlocProvider" . But when I used "MultiBlocProvider", I get bellow error.
The following assertion was thrown attaching to the render tree:
'package:flutter/src/widgets/framework.dart': Failed assertion: line
4357 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
Either the assertion indicates an error in the framework itself, or we
should provide substantially more information in this error message to
help you determine and fix the underlying cause. In either case,
please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
When the exception was thrown, this was the stack:
#2 Element.rebuild. (package:flutter/src/widgets/framework.dart:4357:14)
#3 Element.rebuild (package:flutter/src/widgets/framework.dart:4360:6)
#4 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4643:5)
#5 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4638:5)
#6 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#7 Element.updateChild (package:flutter/src/widgets/framework.dart:3425:18)
#8 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1198:16)
#9 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1167:5)
#10 RenderObjectToWidgetAdapter.attachToRenderTree. (package:flutter/src/widgets/binding.dart:1112:18)
#11 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2573:19)
#12 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#13 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#14 WidgetsBinding.scheduleAttachRootWidget. (package:flutter/src/widgets/binding.dart:924:7) (elided 13 frames
from class _AssertionError, class _RawReceivePortImpl, class _Timer,
dart:async, and dart:async-patch)
How can I fix it?
I added bellow code to ThemeCubit.dart :
bool isDarkMode = false;
ThemeMode currentTheme(){
isDarkMode?_setTheme(ThemeMode.dark) : _setTheme(ThemeMode.light);
return isDarkMode?ThemeMode.dark : ThemeMode.light;
}
void updateTheme(bool isDarkMode) {
this.isDarkMode = isDarkMode;
}
and change main.dart :
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => ThemeCubit(),
),
],
child:ElderlyApp(),
);
}
class ElderlyApp extends StatefulWidget {
const ElderlyApp({Key? key,}) : super(key: key);
#override
_ElderlyAppState createState() => _ElderlyAppState();
}
class _ElderlyAppState extends State<ElderlyApp> with WidgetsBindingObserver {
#override
void initState() {
WidgetsBinding.instance!.addObserver(this);
super.initState();
}
#override
void didChangePlatformBrightness() {
context.read<ThemeCubit>().currentTheme();
super.didChangePlatformBrightness();
}
#override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Production Boilerplate',
theme: AppThemes.lightTheme,
darkTheme: AppThemes.darkTheme,
themeMode: context.select(
(ThemeCubit cubit) => cubit.currentTheme()), //ThemeMode.dark,
debugShowCheckedModeBanner: false,
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
and change code in seetingScreen.dart
Positioned(
top: 60 - widget.offset / 2,
left: 20,
child: Builder(builder: (context) {
bool isDark = context.select((ThemeCubit themeCubit) =>
themeCubit.state.themeMode) ==ThemeMode.dark ? true: false;
return Switch(
value: context.read<ThemeCubit>().isDarkMode,
onChanged: (value) {
context.read<ThemeCubit>().updateTheme(value);
});
})),
Im a newbie to flutter, while trying local notification with flutter to notify with data fetched from the API, i faced a problem where i could fetch the data but couldnot get the notification.
******BTW the code is not complete but it would should atleast work
this is my main.dart
import 'dart:async';
import 'dart:convert';
import 'notification_api.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/2'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child: Column(
children: [
FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
ElevatedButton(
onPressed: (){
NotificationApi.showNotification(
title: 'hello',
body: 'sup',
);
},
child: const Text("Local Notification"),
),
],
),
),
),
);
}
}
this is my notification_api.dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class NotificationApi{
static final _notifications = FlutterLocalNotificationsPlugin();
static Future _notificationDetails() async{
return const NotificationDetails(
android: AndroidNotificationDetails(
'channel id',
'channel name',
channelDescription: 'channel description',
importance: Importance.max
),
iOS: IOSNotificationDetails(),
);
}
static Future showNotification({
int id = 0,
String? title,
String? body,
String? payload,
}) async =>
_notifications.show(
id,
title,
body,
await _notificationDetails(),
payload: payload,
);
}
here is the error
E/flutter (23893): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: MissingPluginException(No implementation found for method show on channel dexterous.com/flutter/local_notifications)
E/flutter (23893): #0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:154:7)
E/flutter (23893): <asynchronous suspension>
E/flutter (23893): #1 FlutterLocalNotificationsPlugin.show (package:flutter_local_notifications/src/flutter_local_notifications_plugin.dart:194:7)
E/flutter (23893): <asynchronous suspension>
E/flutter (23893):
if you use like await word . erase all of them. you will see the emulator work again.
I have a simple Provider class:
import 'package:flutter/foundation.dart';
class AppState with ChangeNotifier {
bool _isLoggedIn = false;
bool get isLoggedIn => _isLoggedIn;
set isLoggedIn(bool newValue) {
_isLoggedIn = newValue;
notifyListeners();
}
}
And in the login class I just set isLoggedIn to true if login is successful:
void _signInWithEmailAndPassword(appState) async {
try {
final FirebaseUser user = await _auth.signInWithEmailAndPassword(
...
);
if (user != null) {
appState.isLoggedIn = true;
appState.userData = user.providerData;
...
}
} catch (e) {
setState(() {
_errorMessage = e.message;
});
}
}
Pressing the back button on Android lets users go back to this page even after successfully logging in. So I wanted to know if Provider.of can be accessed before Widget build and redirect a user if isLoggedIn is true.
Now I have something like:
#override
Widget build(BuildContext context) {
final appState = Provider.of<AppState>(context);
...
This is only one use case for the login view, but I'm sure this functionality can be used in other cases.
If you are going to use the FirebaseUser or Logged in user throughout your app, i would suggest that you add the Provider on the highest level of your app. Example
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp();
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<FirebaseUser>.value(
stream: FirebaseAuth.instance.onAuthStateChanged, // Provider here
),
],
child: MaterialApp(
title: 'My App',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.green,
primarySwatch: Colors.green,
accentColor: Colors.yellow,
),
home: MainPage(),
),
);
}
}
class MainPage extends StatefulWidget {
MainPage({Key key, this.storage}) : super(key: key);
final FirebaseStorage storage;
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage>
with SingleTickerProviderStateMixin {
#override
Widget build(BuildContext context) {
final user = Provider.of<FirebaseUser>(context); // gets the firebase user
bool loggedIn = user != null;
return loggedIn ? HomePage() : LoginPage(); // Will check if the user is logged in. And will change anywhere in the app if the user logs in
}
}
References
Fireship 185 Provider
Great Youtube video explaining the code