The following StackOverflowError was thrown building Consumer in Login through RestApi

501

The Error is due to getter method of the Auth. Where i returning the getter token but i have to return _token string which i am getting after logging in.Due to Name Confusion i am returning getter over and over again.

Share:
501
Shahryar Rafique
Author by

Shahryar Rafique

Updated on December 24, 2022

Comments

  • Shahryar Rafique
    Shahryar Rafique over 1 year

    I am building simple authentication using Rest Api. Function are working but when I got token I want to move on mainPage of the Application. For this I used Consumer to build the Main Page using the bool value which I am getting from _auth.token when the token is present but it is returning Stack Overflow Error.

    The following StackOverflowError was thrown building Consumer<Auth>(dirty, dependencies:
    [_InheritedProviderScope<Auth>]):
    Stack Overflow
    The relevant error-causing widget was:
      Consumer<Auth>
    

    My Code is main.dart

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:provider/provider.dart';
    import 'package:sole_entrepreneur/screens/business_overview_screen.dart';
    import 'package:sole_entrepreneur/screens/splash_screen.dart';
    
    // import './screens/selection_screen.dart';
    import './screens/login_screen.dart';
    import './screens/register_screen.dart';
    import './screens/selection_screen.dart';
    import './providers/auth.dart';
    
    Future main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
      // await Auth().signIn('[email protected]', 'Developer');
      // await Auth().register(
      //     '[email protected]', "csdwx9spq", "matshary", "test", "testlast");
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
            providers: [
              ChangeNotifierProvider(
                create: (ctx) => Auth(),
              ),
            ],
            child: Consumer<Auth>(builder: (ctx, auth, _) {
              // print(auth.isAuth);
              return MaterialApp(
                title: 'Flutter Demo',
                theme: ThemeData(
                  scaffoldBackgroundColor: Colors.white,
                  primaryColor: Color.fromRGBO(124, 116, 146, 1),
                  buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary),
                  appBarTheme: AppBarTheme(
                      color: Colors.white,
                      elevation: 0.0,
                      iconTheme: IconThemeData(color: Colors.black)),
                ),
                home: auth.isAuth
                    ? BusinessOverViewScreen()
                    : FutureBuilder(
                        builder: (context, authResultSnapshot) {
                          print(auth.isAuth);
                          return authResultSnapshot.connectionState ==
                                  ConnectionState.waiting
                              ? SplashScreen()
                              : LoginScreen();
                        },
                        future: auth.tryAutoLogin(),
                      ),
                routes: {
                  LoginScreen.routeName: (ctx) => LoginScreen(),
                  RegisterScreen.routeName: (ctx) => RegisterScreen(),
                  BusinessOverViewScreen.routeName: (ctx) =>
                      BusinessOverViewScreen()
                },
              );
            }));
      }
    }
    

    auth.dart

    import 'dart:convert';
    import 'dart:async';
    import 'dart:io';
    
    import 'package:flutter/foundation.dart';
    import 'package:http/http.dart' as http;
    import 'package:shared_preferences/shared_preferences.dart';
    
    class Auth with ChangeNotifier {
      String _token;
      DateTime _expiryDate;
      int _userId;
      Timer _authTimer;
      List<dynamic> _userRole;
      String _userEmail;
      String _userNiceName;
      String _userDisplayName;
      String _userAvatar;
      String message;
    
      bool get isAuth {
        return token != null;
      }
    
      String get token {
        print(_expiryDate);
        // print(_expiryDate.isAfter(DateTime.now()).toString());
    
        if (_expiryDate != null &&
            _expiryDate.isAfter(DateTime.now()) &&
            _token != null) {
          return token;
        }
        return null;
      }
    
      int get userId {
        return _userId;
      }
    
      Future<void> authethicate(
        String email,
        String password,
      ) async {
        try {
          final url = 'https://soleentrepreneur.co.uk/wp-json/jwt-auth/v1/token';
          final response = await http.post(
            url,
            body: {
              'username': email,
              'password': password,
            },
          );
          print(
            json.decode(response.body),
          );
          final responseData = json.decode(response.body);
          if (responseData['message'] != null) {
            throw HttpException(responseData['message']);
          }
          _token = responseData['token'];
          _userEmail = responseData['user_email'];
          _userNiceName = responseData['user_nicename'];
          _userDisplayName = responseData['user_display_name'];
          _userRole = responseData['user_role'];
          _userId = responseData['user_id'];
          _userAvatar = responseData['avatar'];
          _expiryDate = DateTime.now().add(new Duration(days: 7));
          notifyListeners();
          SharedPreferences pref = await SharedPreferences.getInstance();
          final userData = json.encode({
            'token': _token,
            'userId': _userId,
            'expiryDate': _expiryDate.toIso8601String(),
            'userEmail': _userEmail,
            'userNiceName': _userNiceName,
            'userDisplayName': _userDisplayName,
            'userRole': _userRole,
            'userAvatar': _userAvatar,
          });
          pref.setString('userData', userData);
        } catch (error) {
          throw (error);
        }
      }
    
      Future<void> signIn(String email, String password) async {
        await authethicate(email, password);
      }
    
      Future<void> register(String email, String password, String username,
          String firstName, String lastName) async {
        await registerAuth(email, username, password, firstName, lastName);
      }
    
      Future<void> registerAuth(String email, String username, String password,
          String firstName, String lastName) async {
        try {
          final registerUrl =
              'https://soleentrepreneur.co.uk/wp-json/wp/v2/users/register';
          final response = await http.post(registerUrl,
              headers: {'Content-Type': 'application/json'},
              body: json.encode(
                {
                  'username': username,
                  'password': password,
                  'email': email,
                  'first_name': firstName,
                  'last_name': lastName
                },
              ));
    
          final responseData = json.decode(response.body);
    
          if (responseData['code'] != 200) {
            throw HttpException(responseData['message']);
          }
          print(
            json.decode(response.body),
          );
          message = responseData['message'];
          notifyListeners();
        } catch (error) {
          throw error;
        }
      }
    
      Future<void> logOut() async {
        _userId = null;
        _token = null;
        _expiryDate = null;
        if (_authTimer != null) {
          _authTimer.cancel();
          _authTimer = null;
        }
        notifyListeners();
        final prefs = await SharedPreferences.getInstance();
        prefs.clear();
      }
    
      Future<void> tryAutoLogin() async {
        final prefs = await SharedPreferences.getInstance();
        if (!prefs.containsKey('userData')) {
          print(_token);
          return false;
        }
        final extractedUserData =
            json.decode(prefs.getString('userData')) as Map<String, Object>;
        final expiryDate = DateTime.parse(extractedUserData['expiryDate']);
        if (expiryDate.isBefore(DateTime.now())) {
          print(_token);
          return false;
        }
        _token = extractedUserData['token'];
        _userId = extractedUserData['userId'];
        _expiryDate = expiryDate;
        _userEmail = extractedUserData['user_email'];
        _userDisplayName = extractedUserData['user_display_name'];
        _userNiceName = extractedUserData['user_nicename'];
        _userRole = extractedUserData['user_role'];
        _userAvatar = extractedUserData['avatar'];
        notifyListeners();
        _autoLogOut();
        print(_token);
        return true;
      }
    
      void _autoLogOut() {
        if (_authTimer != null) {
          _authTimer.cancel();
        }
        final timeToExpiry = _expiryDate.difference(DateTime.now()).inSeconds;
        _authTimer = Timer(Duration(seconds: timeToExpiry), logOut);
      }
    }
    

    login.dart

    import 'dart:io';
    
    import 'package:flutter/material.dart';
    import '../providers/auth.dart';
    import '../widgets/button.dart';
    import '../widgets/text_form_field_style.dart';
    
    import 'package:provider/provider.dart';
    import '../models/httpException.dart';
    
    class LoginScreen extends StatefulWidget {
      static const routeName = '/login';
      @override
      _LoginScreenState createState() => _LoginScreenState();
    }
    
    class _LoginScreenState extends State<LoginScreen> {
      final GlobalKey<FormState> _formKey = GlobalKey();
      Map<String, String> _authData = {
        'email': '',
        'password': '',
      };
      var _isLoading = false;
      void _showErrorDialog(String message) {
        showDialog(
          context: context,
          builder: (context) {
            return AlertDialog(
              content: Text(message),
              title: Text('An Error Occured'),
              actions: [
                FlatButton(
                    onPressed: () => Navigator.of(context).pop(),
                    child: Text('Okay'))
              ],
            );
          },
        );
      }
    
      Future<void> _submit() async {
        if (!_formKey.currentState.validate()) {
          print('not Returning');
          return;
        }
        _formKey.currentState.save();
        setState(() {
          _isLoading = true;
        });
        try {
          await Provider.of<Auth>(context, listen: false)
              .signIn(_authData['email'], _authData['password']);
        } on HttpException catch (error) {
          var errormessage = 'Authethication failed';
          if (error.toString().contains('Unknown email address.')) {
            errormessage =
                'Unknown email address. Check again or try your username';
          } else if (error.toString().contains('[jwt_auth] incorrect_password')) {
            errormessage =
                'The password you entered for the email address  is incorrect.';
          } else if (error.toString().contains('[jwt_auth] invalid_username')) {
            errormessage = 'This email is not valid';
          }
          _showErrorDialog(errormessage);
        } catch (error) {
          var errormessage = 'Could not authenticate you. Please try again later';
          print(error);
          _showErrorDialog(errormessage);
        }
        setState(() {
          _isLoading = false;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: SafeArea(
            child: Column(
              children: [
                Expanded(
                  child: Container(
                    margin: EdgeInsets.all(MediaQuery.of(context).size.width / 5),
                    child: Image.asset('assets/Logo.png'),
                    color: Colors.blue,
                  ),
                ),
                Expanded(
                  child: Form(
                    key: _formKey,
                    child: SingleChildScrollView(
                      child: Column(
                        children: [
                          buildTextFormStyle(
                            MediaQuery.of(context).size.height / 9,
                            TextFormField(
                              decoration: InputDecoration(
                                labelText: 'Email',
                                border: InputBorder.none,
                                contentPadding: EdgeInsets.all(5),
                              ),
                              keyboardType: TextInputType.emailAddress,
                              // ignore: missing_return
                              validator: (value) {
                                if (value.isEmpty || !value.contains('@'))
                                  return 'Invalid email!';
                              },
                              onSaved: (newValue) {
                                _authData['email'] = newValue;
                              },
                            ),
                          ),
                          SizedBox(height: 10),
                          buildTextFormStyle(
                            MediaQuery.of(context).size.height / 9,
                            TextFormField(
                              decoration: InputDecoration(
                                labelText: 'Password',
                                border: InputBorder.none,
                                contentPadding: EdgeInsets.all(5),
                              ),
                              obscureText: true,
                              // ignore: missing_return
                              validator: (value) {
                                if (value.isEmpty || value.length < 5)
                                  return 'Password is too short!';
                              },
                              onSaved: (newValue) {
                                _authData['password'] = newValue;
                              },
                            ),
                          ),
                          if (_isLoading)
                            CircularProgressIndicator()
                          else
                            AppButton(name: 'LOGIN', onPressed: _submit),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    //Text Field Style
    
    
  • Abhishek Ghaskata
    Abhishek Ghaskata over 3 years
    you don't need MultiProvider.
  • Shahryar Rafique
    Shahryar Rafique over 3 years
    I need multiProvider later the error in my point of view is causing because of something wrong in auth file but i could not found anything.
  • Abhishek Ghaskata
    Abhishek Ghaskata over 3 years
    can you please try flutter clean ? and rerun again
  • Abhishek Ghaskata
    Abhishek Ghaskata over 3 years
    use class Auth extends ChangeNotifier in auth.dart. because ChangeNotifier is class not mixin @ShahryarRafique
  • Shahryar Rafique
    Shahryar Rafique over 3 years
  • Shahryar Rafique
    Shahryar Rafique over 3 years
    as i remove if (_expiryDate != null && _expiryDate.isAfter(DateTime.now()) && _token != null) { return token; } the error is resolved but a continuous loop start and only SplashScrren is showing.