skip to Main Content

I’m trying to loop the AlertDialog that says "No Internet Connection. Please check your internet connection and try again.". I want the dialog to keep showing when I press the "Retry" button if there’s no internet connection but once its already connected to the internet, the alertdialog will stop and continue to login.

import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:namer_app/Passenger_Widgets/GuestRegistration.dart';
import 'package:namer_app/login_auth/login_method.dart';
import 'package:namer_app/login_auth/resetpass_method.dart';
import 'package:namer_app/Passenger_Widgets/ScheduleWindow.dart';
import 'package:namer_app/prf_login/my_buttons.dart';
import 'package:namer_app/prf_login/my_textfields.dart';
import 'package:namer_app/prf_login/snackbar_ext.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Supabase.initialize(
    url: 'https://',
    anonKey:
        '0000',
  );

  final prefs = await SharedPreferences.getInstance();
  final bool isLoggedIn = prefs.getBool('isLoggedIn') ?? false;

  List<ConnectivityResult> connectivityResults = await (Connectivity().checkConnectivity());

  ConnectivityResult connectivityResult = connectivityResults.first;

  runApp(
    MaterialApp(
      home: MyApp(connectivityResult, prefs, isLoggedIn),
    ),
  );
}

class MyApp extends StatelessWidget {
  final ConnectivityResult connectivityResult;
  final SharedPreferences prefs;
  final bool isLoggedIn;

  MyApp(this.connectivityResult, this.prefs, this.isLoggedIn);

  @override
  Widget build(BuildContext context) {
    if (connectivityResult == ConnectivityResult.none) {
      // Show a popup to inform the user that there's no internet connection
      WidgetsBinding.instance.addPostFrameCallback((_) {
        showDialog(
          context: context,
          builder: (context) => AlertDialog(
            title: Text('No Internet Connection'),
            content: Text('Please check your internet connection and try again.'),
            actions: [
              ElevatedButton(
                child: Text('Retry'),
                onPressed: () => Navigator.pop(context),
              ),
            ],
          ),
        );
      });
    }

    return MaterialApp(
      theme: ThemeData(
        appBarTheme: AppBarTheme(
          iconTheme: IconThemeData(
            color: Colors.white,
          ), // Set back button color to white
        ),
      ),
      home: isLoggedIn ? ScheduleWindow(prefs: prefs) : LOGIN_passenger(),
    );
  }
}


class LOGIN_passenger extends StatefulWidget {
  LOGIN_passenger({super.key});

  @override
  State<LOGIN_passenger> createState() => _LOGIN_passengerState();
}

class _LOGIN_passengerState extends State<LOGIN_passenger> {
  GlobalKey<FormState> _formkey = GlobalKey();
  bool _isLoading = false;
  late TextEditingController emailController;
  late TextEditingController passController;

  //LOGIN ATTEMPTS TIMER
  int _loginAttempts = 0;
  bool _isCooldown = false;
  Timer? _cooldownTimer;
  int _cooldownTime = 60; // Cooldown time in seconds

  @override
  void initState() {
    super.initState();
    emailController = TextEditingController();
    passController = TextEditingController();
  }

  @override
  void dispose() {
    emailController.dispose();
    passController.dispose();
    _cooldownTimer?.cancel();
    super.dispose();
  }

  bool isValidEmail(String input) {
    final emailRegex = RegExp(r'^[^@]+@[^@]+.[^@]+');
    return emailRegex.hasMatch(input);
  }

  bool isValidPhoneNumber(String input) {
    final phoneWithPrefix = '63$input';
    final phoneRegex = RegExp(r'^63d{10}$');
    return phoneRegex.hasMatch(phoneWithPrefix);
  }

  void insertPrefs(AuthResponse response) async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    if (response.user != null) {
      final user = response.user?.id;
      final selectQuery = await Supabase.instance.client
          .from('registered_passenger')
          .select()
          .eq('user_id', user.toString());

      if (selectQuery.isNotEmpty) {
        prefs.setBool('isLoggedIn', true);
        prefs.setString('userId', selectQuery[0]['user_id']);
        prefs.setString('lastName', selectQuery[0]['last_name']);
        prefs.setString('firstName', selectQuery[0]['first_name']);
        prefs.setString('middleInitial', selectQuery[0]['middle_initial']);
        prefs.setString('email', selectQuery[0]['email']);
        prefs.setString('password', selectQuery[0]['password']);
        prefs.setString('profession', selectQuery[0]['profession']);
        String contactNumber = selectQuery[0]['phone'];
        prefs.setString('contactNumber', contactNumber.substring(2));
        prefs.setString('age', selectQuery[0]['age']);
        prefs.setString('gender', selectQuery[0]['gender']);
        prefs.setString('region', selectQuery[0]['region']);
        prefs.setString('province', selectQuery[0]['province']);
        prefs.setString('municipality', selectQuery[0]['municipality']);
        prefs.setString('barangay', selectQuery[0]['barangay']);
        prefs.setString('titlePage', 'Schedule');
        navigatetoSched(prefs);
      }
    }
  }

void _login() async {
  final connectivityResult = await (Connectivity().checkConnectivity());

  if (connectivityResult == ConnectivityResult.none) {
    context.showSnackbar(
      message: 'No internet connection. Please check your internet connection and try again.',
      backgroundColor: Colors.red,
    );
    setState(() {
      _isLoading = false;  // Reset _isLoading so the button can be clicked again
    });
    return;
  }

  if (_isCooldown) {
    context.showSnackbar(
      message: 'Too many attempts. Please wait $_cooldownTime seconds.',
      backgroundColor: Colors.red,
    );
    return;
  }

  final isValid = _formkey.currentState?.validate();

  if (isValid != null && isValid) {
    setState(() {
      _isLoading = true;
    });

    try {
      final input = emailController.text;
      final password = passController.text;
      final response;

      if (isValidEmail(input)) {
        response = await Supabase.instance.client.auth.signInWithPassword(
          email: input,
          password: password,
        );
        insertPrefs(response);
      } else if (isValidPhoneNumber(input)) {
        response = await Supabase.instance.client.auth.signInWithPassword(
          phone: '63$input',
          password: password,
        );
        insertPrefs(response);
      } else {
        throw AuthException('Invalid email or phone number');
      }

      setState(() {
        _isLoading = false;
      });
      context.showSnackbar(
        message: 'LOGIN SUCCESSFUL',
        backgroundColor: Colors.green,
      );
    } on AuthException catch (e) {
      if (e.message.contains('SocketException')) {
        context.showSnackbar(
          message: 'No internet connection. Please check your internet connection and try again.',
          backgroundColor: Colors.red,
        );
      } else {
        context.showSnackbar(
          message: e.message,
          backgroundColor: Colors.red,
        );
      }
      setState(() {
        _isLoading = false; // Reset _isLoading in case of an error
      });
    } catch (e) {
      context.showSnackbar(
        message: e.toString(),
        backgroundColor: Colors.red,
      );
      setState(() {
        _isLoading = false; // Reset _isLoading for other types of errors
      });
    }
  }
}


  

  /*Future<void> _logout() async {
  if (selectedFerry != null) {
    await _supabaseClient
        .from('boats')
        .update({'is_active': false}) // Set ferry as inactive
        .eq('boat_name', selectedFerry!)
  }

  // Continue with logout process
}*/

  void _handleLoginFailure(String errorMessage) {
    context.showSnackbar(message: errorMessage, backgroundColor: Colors.red);

    setState(() {
      _isLoading = false;
      _loginAttempts++;
    });

    if (_loginAttempts >= 3) {
      _startCooldown();
    }
  }

  void _startCooldown() {
    setState(() {
      _isCooldown = true;
    });

    _cooldownTimer = Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() {
        _cooldownTime--;
      });

      if (_cooldownTime == 0) {
        timer.cancel();
        setState(() {
          _isCooldown = false;
          _loginAttempts = 0;
          _cooldownTime = 60; // Reset cooldown time
        });
      }
    });
  }

  void navigatetoSched(SharedPreferences prefs) {
    Navigator.pushAndRemoveUntil(
        context,
        MaterialPageRoute(builder: (_) => ScheduleWindow(prefs: prefs)),
        (route) => false);
  }

  void _forgotPassword() {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (_) => ResetpassMethod()),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(270.0),
        child: AppBar(
          centerTitle: true,
          flexibleSpace: Container(
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage('images/bgprf1.png'),
                fit: BoxFit.fill,
              ),
            ),
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Image.asset(
                    'images/prf_logo.png',
                    width: 155.0,
                    height: 155.0,
                  ),
                  SizedBox(height: 10.0),
                  Text(
                    'PASIG RIVER FERRY PORTAL',
                    style: TextStyle(
                      color: Color(0xFF33385F),
                      fontSize: 20,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
      backgroundColor: Colors.white,
      body: Container(
        padding: EdgeInsets.all(20.0),
        child: SingleChildScrollView(
          child: Form(
            key: _formkey, // Associate the Form with the GlobalKey
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                SizedBox(height: 30.0),
                Text(
                  'WELCOME',
                  style: TextStyle(
                    color: Color(0xFF33385F),
                    fontSize: 30,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  'Please, Login to your account!',
                  style: TextStyle(
                    color: Color(0xFF666666),
                    fontSize: 15,
                    fontWeight: FontWeight.bold,
                  ),
                ),

                const SizedBox(height: 20.0),
                // Textfield for Email/Username
                Textfield_auth(
                  controller: emailController,
                  prefixIcon: Icon(Icons.person),
                  hintText: 'Enter Email/Username',
                  labelText: 'Email/Username',
                  obscureText: false,
                ),

                const SizedBox(height: 15.0),
                // Textfield for Password
                Textfield_authpass(
                  controller: passController,
                  prefixIcon: Icon(Icons.lock),
                  hintText: 'Enter Password',
                  labelText: 'Password',
                ),

                Row(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                    GestureDetector(
                      onTap: _forgotPassword,
                      child: Text(
                        'Forgot Password?',
                        style: TextStyle(
                          color: Color(0xFF666666),
                          fontSize: 12,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ],
                ),
                SizedBox(height: 30.0),

                LoginButton(
                  onTap: _isLoading || _isCooldown ? null : _login,
                ),
                if (_isCooldown)
                  Center(
                    child: Text(
                      'Please wait $_cooldownTime seconds to try again.',
                      style: TextStyle(
                        color: Colors.red,
                        fontSize: 16,
                      ),
                    ),
                  ),

                const SizedBox(height: 20.0),
                // Continue with Google account
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 5.0),
                  child: Row(
                    children: [
                      Expanded(
                        child: Divider(
                          thickness: 1,
                          color: Colors.grey,
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 10.0),
                        child: Text(
                          'OR',
                          style: TextStyle(color: Colors.grey),
                        ),
                      ),
                      Expanded(
                        child: Divider(
                          thickness: 1,
                          color: Colors.grey,
                        ),
                      ),
                    ],
                  ),
                ),

                SizedBox(height: 30.0),
                // GOOGLE SIGN IN
                Center(
                  child: Row(
                    mainAxisSize: MainAxisSize.max,
                    children: [
                      const SizedBox(height: 5),
                      GuestButton(
                        onTap: () {
                          
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) => PrfGuestRegistration(),
                            ),
                          );
                        },
                      ),
                      SignUpButton(
                        onTap: () {
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) => ChooseLoginMethod(),
                            ),
                          );
                        },
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

I already tried using Connectivity().checkConnectivity() and ConnectivityResult.none on the retry logic.

2

Answers


  1. To loop the AlertDialog until there is an internet connection, you can modify your code to continuously check the internet connection whenever the "Retry" button is pressed. If there’s still no internet, the dialog will show again; otherwise, it will close and allow further actions.

    Here’s how you can implement this:

    1. Create a method to check connectivity and display the dialog when needed.
    2. Keep the dialog open until a successful connection is detected.

    Here’s the updated code:

    import 'package:connectivity_plus/connectivity_plus.dart';
    import 'package:flutter/material.dart';
    import 'package:supabase_flutter/supabase_flutter.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Supabase.initialize(
        url: 'https://',
        anonKey: '0000',
      );
    
      final prefs = await SharedPreferences.getInstance();
      final bool isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
    
      runApp(MyApp(prefs, isLoggedIn));
    }
    
    class MyApp extends StatelessWidget {
      final SharedPreferences prefs;
      final bool isLoggedIn;
    
      MyApp(this.prefs, this.isLoggedIn);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(),
          home: isLoggedIn ? ScheduleWindow(prefs: prefs) : LOGIN_passenger(),
        );
      }
    }
    
    class LOGIN_passenger extends StatefulWidget {
      @override
      State<LOGIN_passenger> createState() => _LOGIN_passengerState();
    }
    
    class _LOGIN_passengerState extends State<LOGIN_passenger> {
      bool _isLoading = false;
      late TextEditingController emailController;
      late TextEditingController passController;
    
      @override
      void initState() {
        super.initState();
        emailController = TextEditingController();
        passController = TextEditingController();
        _checkInternetConnection();
      }
    
      @override
      void dispose() {
        emailController.dispose();
        passController.dispose();
        super.dispose();
      }
    
      Future<void> _checkInternetConnection() async {
        var connectivityResult = await Connectivity().checkConnectivity();
    
        if (connectivityResult == ConnectivityResult.none) {
          _showNoInternetDialog();
        }
      }
    
      void _showNoInternetDialog() {
        showDialog(
          context: context,
          barrierDismissible: false, // Prevent dismissing the dialog by tapping outside
          builder: (context) => AlertDialog(
            title: Text('No Internet Connection'),
            content: Text('Please check your internet connection and try again.'),
            actions: [
              ElevatedButton(
                child: Text('Retry'),
                onPressed: () async {
                  Navigator.of(context).pop(); // Close the dialog
                  _retryConnection();
                },
              ),
            ],
          ),
        );
      }
    
      Future<void> _retryConnection() async {
        var connectivityResult = await Connectivity().checkConnectivity();
    
        if (connectivityResult == ConnectivityResult.none) {
          // Still no internet, show the dialog again
          _showNoInternetDialog();
        } else {
          // Internet is available, proceed with login or further actions
          _login();
        }
      }
    
      void _login() {
        // Login logic here
        print("Proceed to login.");
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Login'),
          ),
          body: Center(
            child: ElevatedButton(
              onPressed: _checkInternetConnection,
              child: Text('Check Connection and Login'),
            ),
          ),
        );
      }
    }
    

    Explanation:

    1. Initial Check: In the initState(), the app checks the internet connection using Connectivity().checkConnectivity().
    2. No Internet Dialog: If there’s no internet, the _showNoInternetDialog() method shows the alert dialog. This dialog will remain on the screen until the user presses "Retry."
    3. Retry Logic: When "Retry" is pressed, the app checks the connection again. If there’s still no connection, it will show the dialog again. If the connection is restored, the login process will proceed.

    This approach ensures that the alert dialog keeps appearing until a valid internet connection is detected.

    Login or Signup to reply.
  2. So basically you need to add logic inside the retry button. When user press retry button, check the connectivity then trigger an action based on the result. I provide simple reproducible code to give you an idea how it’s work.

    import 'dart:async';
    import 'package:connectivity_plus/connectivity_plus.dart';
    import 'package:flutter/material.dart';
    
    class AlertConnectivityPage extends StatefulWidget {
      const AlertConnectivityPage({super.key});
    
      @override
      State<AlertConnectivityPage> createState() => _AlertConnectivityPageState();
    }
    
    class _AlertConnectivityPageState extends State<AlertConnectivityPage> {
      /// Listen to device connectivity using [StreamSubscription].
      late StreamSubscription<List<ConnectivityResult>> _subscription;
    
      /// Current device connectivity status.
      String status = '-';
    
      /// Alert to inform user that the device doesn't have any network connection.
      void _showAlert() {
        Widget alert(context) {
          Widget title = const Text('No Connection!');
    
          Widget content = const Text('Please connect your device to internet.');
    
          Future<void> handleRetry() async {
              bool isConnected = await isConnectedToInternet();
    
              // TODO: Add ui logic to inform that user device doesn't have any connection.
              if (isConnected) Navigator.pop(context);
            }
    
          Widget action = ElevatedButton(
            onPressed: handleRetry,
            child: const Text('Retry'),
          );
    
          return AlertDialog(title: title, content: content, actions: [action]);
        }
    
        showDialog(
          context: context,
          builder: alert,
          // If [barrierDismissible] is false, the dialog cannot be closed by tap
          // outside the dialog.
          barrierDismissible: false,
        );
      }
    
      /// Check if the device has network connection
      Future<bool> isConnectedToInternet() async {
        final List<ConnectivityResult> connectivityResult =
            await (Connectivity().checkConnectivity());
    
        if (connectivityResult.contains(ConnectivityResult.none)) return false;
    
        return true;
      }
    
      /// Handle connectivity listener.
      ///
      /// If device connectivity has been changed, this function will be invoked.
      void _handleConnectivityListener(List<ConnectivityResult> result) {
        status = result.first.name;
    
        setState(() {});
    
        if (result.contains(ConnectivityResult.none)) {
          _showAlert();
        }
      }
    
      @override
      void initState() {
        super.initState();
    
        // Register device connectivity listener using [_handleConnectivityListener].
        _subscription = Connectivity().onConnectivityChanged.listen(
              _handleConnectivityListener,
            );
      }
    
      @override
      void dispose() {
        _subscription.cancel();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('Connectivity Plus')),
          body: SafeArea(child: Center(child: Text(status))),
        );
      }
    }
    
    

    You can add additional logic in TODO part (when user click the retry button).

    What this code do:

    1. Check the connectivity when the page opened first time
    2. Listen to connectivity. So when connectivity has been changed the Stream will be notified
    3. Showing alert dialog when there’s no connection in user device.
    4. Prevent user to close the dialog by tap outside the dialog.
    5. The dialog will not closed by retry button except there’s network connection.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search