firebase_database online / offline status - flutter

How can we determine whether our flutter app is online or offline when using firebase and the flutter-fire firebase_database plugin?
This blog post (https://firebase.googleblog.com/2013/06/how-to-build-presence-system.html) shows using the '.info/connected' child to get an Event when the app goes online/offline. However it only seems to trigger on app startup once and thats it.
I'm using this:
void initState() {
super.initState();
print('Setting up the connected handler');
final amOnline = FirebaseDatabase.instance.reference().child('.info/connected');
_amOnlineSubscription = amOnline.onValue.listen((Event event) {
print('EVENT has occured');
});
}
Maybe there is a better way to determine online/offline status? What I'm trying to do is avoid a sign-in page when the device is offline. Yet force a sign-in once it becomes connected to firebase again...

I use connectivity_plus plugin on my app to check if the app has active network connection. This way, you won't need to use firebase_database just to check the device's connectivity.
You can add this on the app's initState()
#override
initState() {
super.initState();
subscription = Connectivity().onConnectivityChanged.listen((ConnectivityResult result) {
// Check connectivity status
})
}
and make sure to cancel the subscription once done.
#override
dispose() {
super.dispose();
subscription.cancel();
}

Related

How do I make the update page display data according to the index and the data can be saved to the database when updating?

I'm a new flutter user, so this time I want to explain my problem. I made a data update. When I open the edit data page, the data cannot appear automatically according to the index, then when an update is made, the data that has been entered cannot be saved. Here's the full source code of my flutter lib.
Link source code: https://github.com/azmi1700018002/akm-front
the update form does not appear automatically
After updating the data cannot be stored in the database
For starters instead of
#override
void initState() {
super.initState();
_nama_debiturController.text;
_alamatController.text;
_no_telpController.text;
_no_ktpController.text;
_no_selularController.text;
}
do
#override
void initState() {
super.initState();
_nama_debiturController.text = nasabah.debiturElement;
_alamatController.text = nasabah.alamatElement;
_no_telpController.text = nasabah.telp;
_no_ktpController.text = nasabah.ktp;
_no_selularController.text = nasabah.selular;
}
Also dispose them in dispose method (same as initstate)
#override
void dispose() {
_controller.dispose();//dispose all of them
super.dispose();
}
I guess the object values will get updated in the validator of the textfield, so try that if it does not work write in the comments.

Firebase Authorization is not checking if the user is logged in properly

in my flutter app I want to check if a user is logged in before or not and based on this navigate them to either HomePage or SignIn page. The code I am using is not working fine, it is not navigating to the SignIn page after I've done registration and deleted the account in Firebase Console. In short, when I delete a user, who registered well before, in Firebase Console the application is keeping to show the HomePage and all the posts the user made. How can I handle it?
"In short, I want to navigate the user to SignIn page after I delete his account in Firebase Console"
Here is the code in my main.dart file:
_check(){
final FirebaseAuth auth = FirebaseAuth.instance;
final User? user = auth.currentUser;
if(user == null){
HiveDB.deleteUser();
return SignInPage();
}
HiveDB.putUser(id: user.uid);
return HomePage();
}
#override
void initState() {
// TODO: implement initState
super.initState();
_check();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: _check(),
routes: {
SignInPage.id:(context) => SignInPage(),
SignUpPage.id:(context) => SignUpPage(),
HomePage.id:(context) => HomePage(),
},
);
}
The _check() function is not working as it's desired...
While Firebase persists the user info in local storage and automatically restores it when the app/page reloads, this requires that it makes an asynchronous call to the server and thus may not be ready by the time your check runs.
Instead of depending on currentUser, you'll want to listen for changes to the authentication state through the authStateChanges stream. Most apps wrap this in a StreamBuilder and then show the correct screen based on the stream state and last event.
This is something that can be resolved by using async . the problem is you are getting response in future but the action is performed before. Please check the following documentation for detailed overview:
https://dart.dev/codelabs/async-await

How to dispose of an unmounted Widget in Flutter?

I am writing a flutter app and if you already started it once, I dont want the user to see the Intro Screen again
In my MaterialApp:
home: firstStart ? DeviceSelection() : StartScreen()
firstStart is a boolean, if it is the first start, it should start the App with the StartScreen() and if its not, it should go straight to DeviceSelection(). That all works fine, but my problem is the following error:
Error: This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.
I think it starts StartScreen too, even if firstStart is false, because it has to get its value out of the shared preferences, because I see it pop up shortly sometimes.
I already tried some stuff I found, like writing a dispose method:
#override
void dispose() {
super.dispose();
}
or
if (!mounted) {
Navigator.pop(context);
}
in a method that I call after the screen starts, but it doesnt work either. Any ideas what I could do to get rid of this error? Thanks
mb set a flag, like:
bool lookedIntro = false; // if user look it first
and then use:
#override
void initState() {
// take data flag from database or somewhere else (file)
// and check it
}
and also read about initState() more

How to detect when app is minized in flutter

Is there a way to detect when the app has been minimized? Simply using WidgetsBindingObserver with the paused event doesn't work as it's indistinguishable from when the user turns off the screen / phone locks. Note, I need this to work for both android and ios.
A bit of context of what I'm doing. In the application, I'm running a timer. I want to stop this timer if the user minimizes the app (e.g. uses its phone for something else). If the user, however, turns off the screen/locks it, I want the timer to continue.
I suggest to take a look at this package: is_lock_screen
As the description suggest
Useful for determining whether app entered background due to locking screen or leaving app.
I would try with this:
#override
void didChangeAppLifecycleState(AppLifecycleState state) async {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.inactive) {
final isLock = await isLockScreen();
if(!isLock){
print('app inactive MINIMIZED!');
}
print('app inactive in lock screen!');
} else if (state == AppLifecycleState.resumed) {
print('app resumed');
}
}

Flutter Background Service

Hi I'm building a VoIP App in Flutter. I use background_fetch to run a headless task in order to work even if the app is closed. The listener is working, and a notification is sent. But, as the application is closed, the push notification with wake up the app (so home.dart for example) and I would like the push my call screen widget. I see two solution but I don't know how to do it :
the headless task from background_fetch is independent, so I can't transfer my service call data to my app (main) when the user open it, so the call is lost ...
I try to push the right widget (Router.go(/callscreen)) but it's not working.
What can I do in order to fix this ? Thank !
You are using 2 services in background, flutter-local-notification and background-fetch. It's too much. You can use flutter-local-notification in backgound only. Have a look here.
final newRouteName = "callScreen";//Future onSelectNotification(String payload) async
bool isNewRouteSameAsCurrent = false;
Navigator.popUntil(context, (route) {
if (route.settings.name == newRouteName) {
isNewRouteSameAsCurrent = true;
}
return true;
});
if (!isNewRouteSameAsCurrent) {
Navigator.of(context).push(CallScreen())
}