0

I get this weird problem in Flutter. I'm using 'Provider' for state management, In the helper class everything is fine, I'm sending the request and I receive the response with no problems. The problem occurs in the button event handler. The first time I click the button literally nothing happens, when I click it the second time it talks to the API and gets the data. Another problem is: when I enter correct data and they are sent to the API, Immediately after that, I enter wrong credentials the app tells me that I've entered correct credentials as if I'm dealing with the same previous object. Here is my code for the front-end part:

class _LoginPageState extends State<LoginPage> {
  String? myError;
  @override
  Widget build(BuildContext context) {
    double screenWidth = MediaQuery.of(context).size.width;
    TextEditingController userNameController = TextEditingController();
    TextEditingController passwordController = TextEditingController();

    return Directionality(
      textDirection: TextDirection.rtl,
      child: Consumer<PicoProvider>(
        builder: (context, prov, child) => SafeArea(
          child: Scaffold(
            backgroundColor: CustomColors.scaffoldDark,
            body: Padding(
              padding: const EdgeInsets.all(100),
              child: SingleChildScrollView(
                child: Container(
                  width: screenWidth,
                  child: Form(
                    autovalidateMode: AutovalidateMode.onUserInteraction,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: [
                        Container(
                          decoration: BoxDecoration(
                              color: Colors.black,
                              borderRadius: BorderRadius.circular(10),
                              boxShadow: [
                                BoxShadow(
                                  color: Colors.grey.withOpacity(0.5),
                                  spreadRadius: 5,
                                  blurRadius: 7,
                                  offset: const Offset(0, 3),
                                ),
                              ]),
                          child: Image.asset(
                            'assets/images/main_logo.jpeg',
                            height: 300,
                          ),
                        ),
                        const SizedBox(height: 20),
                        CTextField(
                            label: 'اسم المسخدم',
                            icon: Ionicons.person,
                            isObsecured: false,
                            controller: userNameController),
                        const SizedBox(height: 20),
                        CTextField(
                            label: 'كلمة المرور',
                            icon: Ionicons.lock_closed,
                            isObsecured: true,
                            controller: passwordController,
                            onSubmitted: () {
                              prov.websiteLogin(userNameController.text,
                                  passwordController.text);
                            }),
                        ElevatedButton(
                            onPressed: () {
                              prov.websiteLogin(userNameController.text,
                                  passwordController.text);

                              prov.errorText!.isNotEmpty
                                  ? giveMeDialog(
                                      context, 'hello', 'not found', 'error')
                                  : giveMeDialog(context, 'hello',
                                      'you are logged', 'success');
                            },
                            child: const Text('Click')),
                        const SizedBox(height: 20),
                        prov.isLoading
                            ? const CircularProgressIndicator()
                            : const SizedBox(),
                        Text('${prov.errorText}')
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  Future<void> giveMeDialog(
      BuildContext context, String title, String message, String icon) {
    return showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text(title),
          content: Directionality(
            textDirection: TextDirection.rtl,
            child: Column(
              children: [
                Text(
                  message,
                  style: const TextStyle(fontSize: 30),
                ),
                Lottie.asset('assets/animations/${icon}_animation.json'),
              ],
            ),
          ),
        );
      },
    );
  }
}

Here is my code for the back-end part:

class PicoProvider extends ChangeNotifier {
  String baseURL = 'http://111.11.11.111:1111';

  bool _isLoading = false;
  bool get isLoading => _isLoading;

  User? _user = User();
  User? get user => _user;

  String? _errorText;
  String? get errorText => _errorText;

  Future<void> websiteLogin(String userName, String password) async {
    try {
      String endPoint =
          '$baseURL/PicoLogin?UserName=$userName&Password=$password';
      _isLoading = true;
      notifyListeners();

      var response = await get(Uri.parse(endPoint), headers: {
        "content-type": "application/json",
        "Access-Control-Allow-Origin": "*",
      });

      if (response.statusCode == 200) {
        _user = User.fromJson(jsonDecode(response.body));
        _errorText = '';
      } else {
        _errorText = 'User Not Found';
      }

      _isLoading = false;
      notifyListeners();
    } catch (e) {
      _errorText = e.toString();
      notifyListeners();
      print('Error: ${e.toString()}');
    }
  }
}

1 Answer 1

1

Your issue is here

                      ElevatedButton(
                        onPressed: () {
                          prov.websiteLogin(userNameController.text,
                              passwordController.text);

                          prov.errorText!.isNotEmpty
                              ? giveMeDialog(
                                  context, 'hello', 'not found', 'error')
                              : giveMeDialog(context, 'hello',
                                  'you are logged', 'success');
                        },

prov.websiteLogin(.. is an async function and the prov.errorText will be updated only after a while. So in your code, you are not awaiting for the websiteLogin to complete and trying to show dialog immediately. Hence it is always giving result from previous execution.

Quick non recommended fix : add an await for websiteLogin in onPressed

                      ElevatedButton(
                        onPressed: () async {
                          await prov.websiteLogin(userNameController.text,
                              passwordController.text);

                          prov.errorText!.isNotEmpty
                              ? giveMeDialog(

Proper solution will be to use a listener. You may use a field (enum) "status" which will give the states like loading, success, and failure, and listen for changes in status field and display a dialog accordingly. You can refer this to how to add listener https://stackoverflow.com/a/72168584/1582630

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. I just added the async/await keywords for a quick solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.