stop closing showDialogue itself after 15 seconds - flutter

I am trying to display an information dialog when starting an application. After closing, another window appears asking for permission. I call it all in the initState function. It works, but I noticed that this first info dialog also closes on its own when 15 seconds have elapsed. How do I fix this? So that while the dialog is not closed by the user, the application will not be loaded further?
class _MyAppState extends State<MyApp> {
final keyIsFirstLoaded = 'is_first_loaded';
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final context = MyApp.navKey.currentState.overlay.context;
await showDialogIfFirstLoaded(context);
await initPlatformState();
});
}
showDialogIfFirstLoaded(BuildContext context, prefs) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isFirstLoaded = prefs.getBool(keyIsFirstLoaded);
if (isFirstLoaded == null) {
return showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return new AlertDialog(
// title: new Text("title"),
content: new Text("//"),
actions: <Widget>[
new FlatButton(
child: new Text(".."),
onPressed: () {
Navigator.of(context).pop();
prefs.setBool(keyIsFirstLoaded, false);
},
),
],
);
},
);
}
}
initPlatformState() async {
print('Initializing...');
await BackgroundLocator.initialize();
print('Initialization done');
final _isRunning = await BackgroundLocator.isRegisterLocationUpdate();
setState(() {
isRunning = _isRunning;
});
onStart();
print('Running ${isRunning.toString()}');
}
#override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
// ... app-specific localization delegate[s] here
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
navigatorKey:MyApp.navKey,
navigatorObservers: [
FirebaseAnalyticsObserver(analytics: analytics),
],
debugShowCheckedModeBanner: false,
title: '',
theme: ThemeData(),
home: new SplashScreen(),}
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {
Timer _timer;
bool _visible = true;
startTime() async {
_timer = Timer(new Duration(seconds: 5), navigationPage);
}
void navigationPage() {
Navigator.of(context).pushReplacementNamed('/home');
}
#override
void initState() {
_timer = Timer(Duration(seconds: 4),
() => setState(
() {
_visible = !_visible;
},
),
);
startTime();
super.initState();
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
Container(
width: double.infinity,
child: Image.asset('images/bg.jpg',
fit: BoxFit.cover,
height: 1200,
),
),
Container(
width: double.infinity,
height: 1200,
color: Color.fromRGBO(0, 0, 0, 0.8),
),
Container(
alignment: Alignment.center,
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
child: Text(''),
),
),
],
),
),
],
);
}
}

This code displays an Alert dialogue if the user is new and after the button click, it will direct him to another dialogue.
I have tested the code and it doesn't close after 15 seconds. I'm still not sure what you're trying to accomplish but I hope this helps.
Init State
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await dialog1(context);
//await initPlatformState();
});
super.initState();
}
Alert Dialog 1
dialog1(BuildContext context)async{
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isFirstLoaded = prefs.getBool("keyIsFirstLoaded")??true;
if (isFirstLoaded) {
showDialog(
barrierDismissible: false, //disables user from dismissing the dialog by clicking out of the dialog
context: context, builder: (ctx) {
return AlertDialog(
title: Text("dialog 1"), content: Text("Content"), actions: [
TextButton(
child: new Text(".."),
onPressed: () async{
Navigator.pop(ctx);
await dialog2(context);
prefs.setBool("keyIsFirstLoaded", false);
},
),],);
},);
}else{
//not first time
}
}
Alert Dialog 2
void dialog2(BuildContext context)async{
print("dialog 2");
showDialog(context: context, builder: (context) {
return AlertDialog(title: Text("Dialog 2"),content: Text("permissions"),actions: [
TextButton(
child: new Text("close"),
onPressed: () async{
Navigator.pop(context);
//await dialog1(context); //uncomment if you want to go back to dialoge 1
},
),],);
},);
}

You can return a value from Navigator in the first dialog
Navigator.of(context).pop(true);
prefs.setBool(keyIsFirstLoaded, false);
Once it receive true, then only call the second method.
var value = await showDialogIfFirstLoaded(context);
if(value == true) {
await initPlatformState();
}

Related

Flutter: My notifyListeners() doesn't work, but only in the release apk

I have a page that shows a loading while making my API call, and once the call is done it shows the received data.
On debugger everything works correctly, but when I create the apk with 'flutter build apk', and download it, the loading remains indefinitely.
I also put a showDialog at the end of my Provider function that makes the API call (I put this showDialog just below notifyListeners().
I can't understand why in debug it works and in release it doesn't.
(This notifyListeners thing not working just does it for every API call I make)
This is the code of the provider function that makes the api call:
Future<void> getUserSites(context) async {
_userSites.clear();
isLoading = true;
notifyListeners();
try {
final response = await NetworkService.call(
url: '/api/structure/Sites',
method: Method.Get,
context: context) as List<dynamic>;
for (var i = 0; i < response.length; i++) {
_userSites.add(Sites.fromJson(response.elementAt(i)));
}
if (defaultSite == null) {
if (SimplePreferences.getDefaultSite() == null) {
defaultSite = _userSites.isNotEmpty ? _userSites.first : null;
if (defaultSite != null) {
SimplePreferences.setDefaultSite(defaultSite!.id);
}
} else {
defaultSite = _userSites.firstWhere(
(element) => element.id == SimplePreferences.getDefaultSite()!);
}
}
} catch (e) {
inspect(e);
if (SimplePreferences.getToken() != null) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('General Error'),
content: Text(e.toString()),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'Ok',
),
)
],
),
);
}
// throw e;
}
isLoading = false;
notifyListeners();
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('getUserSites done!'),
content: Text(_userSites.toString()),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'Ok',
),
)
],
),
);
}
this is the Home page code:
class HomePageScreen extends StatelessWidget { const HomePageScreen({super.key}); static const String routeName = '/';
#override Widget build(BuildContext context) { log('New Page: Home Page'); final provider = Provider.of<MyManager>(context);
return provider.isLoading ? const Center(
child: CircularProgressIndicator(),
)
: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MainButton(
onTap: () async {
Navigator.of(context)
.pushNamed(ShowPatrolScreen.routeName);
await provider.getPatrol(context);
},
icon: Icons.home,
title: 'ShowPatrol',
),
printSito(provider.defaultSite?.description ?? 'Nessun Sito', context),
PrintRequestZ(
showCompleted: false,
),
],
),
),
);
}
Widget printSito(String name, context) { .... //pass context for Navigator and Theme } } `
this is the main page:
...
final myScreens = [
const HomePageScreen(),
...
];
#override
void initState() {
// TODO: implement initState
super.initState();
print('token: ${SimplePreferences.getToken()}');
if (SimplePreferences.getToken() == null){
Navigator.of(context).pushReplacementNamed('/Auth');
}
var provider = Provider.of<MyManager>(context, listen: false);
provider.setAll(context); //this function calls all my API calls, but for testing, I commented out all other functions and kept only the one written above
}
#override
Widget build(BuildContext context) {
var provider = Provider.of<MyManager>(context);
return Scaffold(
appBar: const MyAppBar(title: 'Ronda',canGoBack: false,),
body: myScreens[currentPage],
bottomNavigationBar: ...
),
}
Thanks in advance!
after some research i found the solution.
You have to use WidgetsBinding.instance.addPostFrameCallback
in the parent component.
So my home page now looks like this:
#override
void initState() {
// TODO: implement initState
super.initState();
print('token: ${SimplePreferences.getToken()}');
if (SimplePreferences.getToken() == null){
Navigator.of(context).pushReplacementNamed('/Auth');
}
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
var provider = Provider.of<MyManager>(context, listen: false);
provider.setAll(context); //this function calls all my API calls, but for testing, I commented out all other functions and kept only the one written above
});
}
I don't quite understand why though. If someone could explain it to me, I'd be very happy
Use Consumer to access the Provider's Variable
return Consumer<YourProviderName>(builder : (context, value, child){
return value.isLoading? const Center(
child: CircularProgressIndicator(),
):YourWidget(),
});

using Shared preferences with a change notifier

I'm trying to understand how to use shared preferences with a change notifier. I've created a basic app and I want to save a bool and a string from the change notifier using shared preferences.
here is my main.dart:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => GlobalSettings1()),
ChangeNotifierProvider(create: (_) => SectionSettings1()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/seventh',
routes: {
'/': (context) => Page01(),
'/first': (context) => Page02(),
'/second': (context) => Page03(),
});
}
}
and here is page01
class _Page01State extends State<Page01> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {
context.read<GlobalSettings1>().ToggleSwitch();
},
child: Container(
height: 30,
width: 80,
color: context.watch<GlobalSettings1>().toggleSwitch01
? Colors.green
: Colors.red,
),
),
SizedBox(
height: 20,
),
InkWell(
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) => Material(
color: Colors.transparent,
child: Buttons(
onTap: (val) {
context.read<GlobalSettings1>().StringToSave(val);
Navigator.pop(context);
},
),
),
);
},
child: Container(
height: 30,
width: 80,
child: Center(
child: Text(
context.watch()<GlobalSettings1>().stringToSave,
),
),
)),
],
),
);
}
}
and finally, here is my change notifier:
class Buttons extends StatelessWidget {
const Buttons({Key? key, required this.onTap}) : super(key: key);
final ValueChanged? onTap;
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {
if (onTap != null) {
onTap!('Choice01');
}
},
child: Container(
height: 30,
width: 80,
child: Text('Choice01'),
)),
SizedBox(
height: 30,
),
InkWell(
onTap: () {
if (onTap != null) {
onTap!('Choice02');
}
},
child: Container(
height: 30,
width: 80,
child: Text('Choice02'),
)),
],
);
}
}
class GlobalSettings1 with ChangeNotifier {
bool _toggleSwitch01 = true;
String _stringToSave = 'Choice01';
final SharedPreferences prefs;
GlobalSettings1({required this.prefs});
bool get toggleSwitch01 => _toggleSwitch01;
String get stringToSave => _stringToSave;
void ToggleSwitch() {
_toggleSwitch01 = !_toggleSwitch01;
_setPrefItems();
notifyListeners();
}
void StringToSave(val) {
_stringToSave = val;
_setPrefItems();
notifyListeners();
}
void _setPrefItems() {
prefs.setBool('toggleSwitch01', _toggleSwitch01);
prefs.setString('stringToSave', _stringToSave);
notifyListeners();
}
void _getPrefItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
_stringToSave = prefs.getString('stringToSave') ?? '';
_toggleSwitch01 = prefs.getBool('autoUpdateVariables') ?? true;
notifyListeners();
}
bool getToggleSwitch01() {
_getPrefItems();
return _toggleSwitch01;
}
String getStringToSave() {
_getPrefItems();
return _stringToSave;
}
}
As you can see, there is a bool that is toggled in Page01 and a String that is displayed from a value that is generated and passed through from the buttons widget.
After looking at other tutorials on this matter, I think i have the change notifier set up correctly but am unsure about how to set up the main.dart and Page01 so that when the bool and String are set, they stay like that when the app is rebooted.
i'm currently getting an error in main.dart:
ChangeNotifierProvider(create: (_) => GlobalSettings1()),
asking me to add required argument prefs but i'm unsure what the code should be to go in the brackets.
thanks so much and any help would be greatly appreciated.
You need pass an instance of SharedPreferences to your GlobalSettings1, also change GlobalSettings1 to this:
class GlobalSettings1 with ChangeNotifier {
bool _toggleSwitch01 = true;
String _stringToSave = 'Choice01';
final SharedPreferences prefs;
GlobalSettings1({required this.prefs});
bool get toggleSwitch01 => _toggleSwitch01;
String get stringToSave => _stringToSave;
void ToggleSwitch() {
_toggleSwitch01 = !_toggleSwitch01;
_setPrefItems();
notifyListeners();
}
void StringToSave(val) {
_stringToSave = val;
_setPrefItems();
notifyListeners();
}
void _setPrefItems() {
prefs.setBool('toggleSwitch01', _toggleSwitch01);
prefs.setString('stringToSave', _stringToSave);
notifyListeners();
}
void _getPrefItems() { // <=== change this
_stringToSave = prefs.getString('stringToSave') ?? '';
_toggleSwitch01 = prefs.getBool('autoUpdateVariables') ?? true;
notifyListeners();
}
bool getToggleSwitch01() {
_getPrefItems();
return _toggleSwitch01;
}
String getStringToSave() {
_getPrefItems();
return _stringToSave;
}
}
then change your main to this:
void main() {
SharedPreferences prefs = await SharedPreferences.getInstance();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => GlobalSettings1(prefs: prefs)),
ChangeNotifierProvider(create: (_) => SectionSettings1()),
],
child: MyApp(),
),
);
}
Currently, you are passing an instance on constructor.
GlobalSettings1({required this.prefs});
While it is SharedPreferences you can do get instance with
class GlobalSettings1 with ChangeNotifier {
bool _toggleSwitch01 = true;
String _stringToSave = 'Choice01';
GlobalSettings1();
......
void _setPrefItems() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('toggleSwitch01', _toggleSwitch01);
prefs.setString('stringToSave', _stringToSave);
notifyListeners();
}

How Can I get a page transition programmatically after getting biometric authentication result true without any button press event in advance?

I am creating an app in flutter implemented local_auth plugin.
I would like this flow below.
1.background page(BioAuthScreen) is up
2.simultaneously authenticateWithBiometrics dialog is up.
3.if result is true, get the page transition to HomeScreen(folloing comment // 3),
if I pressed the button (the code following comment // 4),
It's work.(up the dialog, if the result is true, the page transition OK).
But I wouldn't like button in background page.
if I put the code following comment // 1 or // 2, the dialog is up, if the result is true,
but background page still there. there's no error.
This is the code.
class BioAuthScreen extends StatefulWidget {
BioAuthScreen({Key key, this.initFlag = false}) : super(key: key);
final bool initFlag;
#override
_BioAuthScreenState createState() => _BioAuthScreenState();
}
class _BioAuthScreenState extends State<BioAuthScreen>
with WidgetsBindingObserver {
final LocalAuthentication _localAuthentication = LocalAuthentication();
bool _isAuthenticated;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
// 1
/* WidgetsBinding.instance.addPostFrameCallback((_) async {
await _getAuthenticated();
}); */
}
#override
void didChangeDependencies() async {
super.didChangeDependencies();
await Future.delayed(const Duration(milliseconds: 700));
// 2
// await _getAuthenticated();
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.inactive) {
} else if (state == AppLifecycleState.paused) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => BioAuthScreen()));
} else if (state == AppLifecycleState.resumed) {}
}
Future<List<BiometricType>> _getListOfBiometricTypes() async {
List<BiometricType> listOfBiometrics;
try {
listOfBiometrics = await _localAuthentication.getAvailableBiometrics();
} on PlatformException catch (e) {
print(e);
}
print(listOfBiometrics);
return listOfBiometrics;
}
Future<void> _getAuthenticated() async {
var result = false;
var availableBiometricTypes = await _getListOfBiometricTypes();
try {
if (availableBiometricTypes.contains(BiometricType.face) ||
availableBiometricTypes.contains(BiometricType.fingerprint)) {
result = await _localAuthentication.authenticateWithBiometrics(
localizedReason: '生体認証',
useErrorDialogs: true,
stickyAuth: false,
);
}
} on PlatformException catch (e) {
print(e);
}
if (!mounted) return;
print('result: $result');
// 3
if (result) {
await Navigator.pushNamed(context, Constants.homeScreenRoute);
}
}
#override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
return SafeArea(
child: Scaffold(
body: FractionallySizedBox(
widthFactor: 1,
heightFactor: 1,
child: DecoratedBox(
decoration: const BoxDecoration(
color: CustomColors.midBlue,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
const Padding(
padding: EdgeInsets.all(40.0),
),
// Title
AuthTitleComponent(),
SizedBox(height: screenHeight * 0.28),
ButtonTheme(
minWidth:
screenWidth > 600 ? screenWidth * 0.6 : screenWidth * 0.7,
height: 45,
child: RaisedButton(
elevation: 3.0,
color: CustomColors.lightBlue,
// 4
onPressed: () async {
await _getAuthenticated();
},
child: Text(
'BioMetricAuthLogin',
style: Theme.of(context)
.textTheme
.headline2
.copyWith(color: Colors.white),
),
),
),
],
),
),
),
),
);
}
}
I was able to replicate the reported behavior using the code snippets you've provided. LocalAuthentication.authenticate catches PlatformException when biometric auth is called through didChangeAppLifecycleState.
This seems to be a bug and I've filed this as an issue here. I'm using Flutter version 2.0.0 stable and local_auth 1.1.0 for reference.

Failed assertion: line 5070 pos 12: '<optimized out>': is not true

After a user successfully logins in and saving the state, I want to hide the login screen and just load the home screen, but I end up with the error
The following assertion was thrown building
Navigator-[GlobalObjectKey
_WidgetsAppState#6686e](dirty, dependencies: [UnmanagedRestorationScope, HeroControllerScope], state:
NavigatorState#c7e9f(tickers: tracking 1 ticker)):
'package:flutter/src/widgets/navigator.dart': Failed assertion: line
5070 pos 12: '': is not true.
What is the right way of hiding the login screen when the token is still valid, and just load the home screen?
my code
Main.dart
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'What',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
scaffoldBackgroundColor: Palette.scaffold,
),
// home: SignIn(),
routes: {
//Homepage and being controled by PagesProvider
'/': (context) => SignIn(),
'nav': (context) => NavScreen(),
// add all routes with names here
},
);
}
}
my signin.dart
class SignIn extends StatefulWidget {
const SignIn({Key key}) : super(key: key);
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
ProgressDialog progressDialog;
MsalMobile msal;
bool isSignedIn = false;
bool isLoading = true;
#override
void initState() {
super.initState();
MsalMobile.create('assets/auth_config.json', authority).then((client) {
setState(() {
msal = client;
});
refreshSignedInStatus();
});
}
/// Updates the signed in state
refreshSignedInStatus() async {
bool loggedIn = await msal.getSignedIn();
if (loggedIn) {
isSignedIn = loggedIn;
if (isSignedIn) {
dynamic data = await handleGetAccount();
dynamic token = await handleGetTokenSilently();
dynamic result = token;
SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
sharedPreferences.get("username");
sharedPreferences.get("token");
print('access token (truncated): ${result.accessToken}');
Navigator.of(context).pop();
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => NavScreen(),
),
);
}
// Remaining code for navigation
}
}
/// Gets a token silently.
Future<dynamic> handleGetTokenSilently() async {
String authority = "https://login.microsoftonline.com/$TENANT_ID";
final result = await msal.acquireTokenSilent([SCOPE], authority);
if (result != null) {
// print('access token (truncated): ${result.accessToken}');
SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
sharedPreferences.setString("token", result.accessToken);
return result;
} else {
print('no access token');
return null;
}
}
/// Signs a user in
handleSignIn() async {
await msal.signIn(null, [SCOPE]).then((result) {
// ignore: unnecessary_statements
refreshSignedInStatus();
}).catchError((exception) {
if (exception is MsalMobileException) {
logMsalMobileError(exception);
} else {
final ex = exception as Exception;
print('exception occurred');
print(ex.toString());
}
});
}
logMsalMobileError(MsalMobileException exception) {
print('${exception.errorCode}: ${exception.message}');
if (exception.innerException != null) {
print(
'inner exception = ${exception.innerException.errorCode}: ${exception.innerException.message}');
}
}
/// Signs a user out.
handleSignOut() async {
try {
print('signing out');
await msal.signOut();
print('signout done');
refreshSignedInStatus();
} on MsalMobileException catch (exception) {
logMsalMobileError(exception);
}
}
/// Gets the current and prior accounts.
Future<dynamic> handleGetAccount() async {
// <-- Replace dynamic with type of currentAccount
final result = await msal.getAccount();
if (result.currentAccount != null) {
SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
sharedPreferences.setString("username", result.currentAccount.username);
//print(result.currentAccount.username);
return result.currentAccount;
} else {
print('no account found');
return null;
}
}
#override
Widget build(BuildContext context) {
progressDialog = ProgressDialog(context, type:ProgressDialogType.Normal, isDismissible: false, );
return MaterialApp(
home: new Scaffold(
body: Builder(
builder: (context) => Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Image.asset('assets/landing.webp',
fit: BoxFit.fill,
color: Color.fromRGBO(255, 255, 255, 0.6),
colorBlendMode: BlendMode.modulate),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 10.0),
Container(
width: 130.0,
child: Align(
alignment: Alignment.center,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Color(0xffffffff),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(
FontAwesomeIcons.microsoft,
color: Color(0xFF01A6F0),
),
// Visibility(
// visible: !isSignedIn,
SizedBox(width: 10.0),
Text(
'Sign in',
style: TextStyle(
color: Colors.black, fontSize: 18.0),
),
// child: RaisedButton(
// child: Text("Sign In"),
// onPressed: handleSignIn,
// ),
// ),
],
),
onPressed: () => {
progressDialog.show(),
handleSignIn(),
progressDialog.hide()
})),
)
],
),
],
),
),
));
}
}
you should Navigate to the homePage only if the login is successful
because Naviagation.Pop is Equal to the Back button and user can do it manually
here is a better approach :
in main.dart add this :
routes: {
Homepage and being controled by PagesProvider
'nav': (context) => NavScreen(),
'home': (context) => HomePage(),
// add all routes with names here
},
in your refreshSignedInStatus() :
remove this :
Navigator.of(context).pop();
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => NavScreen(),
),
);
add this :
Navigator.pushNamed(context, 'nav');

How to remove Alert Dialogs in Flutter

I have create a Alert Dialog for OTP Verification after verifying OTP I close it and then I had created a another dialog which is for data processing... and then I close it.
Result:-
First OTP Dialog closed after OTP verification by calling Navigator.of(context).pop(); and then second dialog just pops up but It does not closed after calling Navigator.of(context).pop();
What I want to do:
Close OTP Dialog after verifying OTP (Works)
Open Progress dialog (Works)
Close it after uploading profile in firebase storage (Does not Works)
Please help me solve this issue.
Thanks in Advance !
You probably forgetting await somewhere in your code.
Try this,
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController _otpCtrl = TextEditingController();
void dispose() {
_otpCtrl.dispose();
super.dispose();
}
Future<void> _verifyOTP() async {
final String otp = await _inputOtp();
String otpValidationError;
if (otp != null) otpValidationError = await _sendOtpVerifyRequest();
print(otpValidationError);
}
Future<String> _sendOtpVerifyRequest() async {
showDialog(
context: context,
builder: (context) {
return Center(child: CircularProgressIndicator());
},
);
await Future.delayed(Duration(seconds: 2)); //TODO: Do post request here
Navigator.pop(context);
return null;
}
Future<String> _inputOtp() async {
final flag = await showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Enter OTP"),
content: TextField(
controller: _otpCtrl,
decoration: InputDecoration(
hintText: "x x x x x x",
),
),
actions: <Widget>[
FlatButton(
child: Text("Cancel"),
onPressed: () {
Navigator.pop(context, false);
},
),
FlatButton(
child: Text("Confirm"),
onPressed: () {
Navigator.pop(context, true);
},
),
],
);
},
);
if (flag == true)
return _otpCtrl.text;
else
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: _verifyOTP,
child: Text("Click Here"),
),
),
);
}
}