Search code examples
flutterbloc

how to change a value of type boolean in flutter bloc


I am stuck on this since morning,I am working with bloc and I have my event, state and bloc and I want to update the value of some values depending on the response that I gotten from the server. I have a variable I named showPassword in my State and I initialized it as false. Now after an email verification returns 200 response, I want to update the showPassword to true and then update my UI. The issue here is that even when the server returns a 200 respone, the showPassword is still not updating. This is what I did

class LoginState {
final String email;
final String password;
final bool showEmail;
final bool showPassword;

LoginState({
this.email = "",
this.password = "",
this.showEmail = false,
this.showPassword = false,
});
 LoginState copyWith({
String? email,
String? password,
bool? showEmail,
bool? showPassword,
}) {
return LoginState(
  email: email ?? this.email,
  password: password ?? this.password,
  showEmail: showEmail ?? this.showEmail,
  showPassword: showPassword ?? this.showPassword,
);
}
}

class LoginBloc extends Bloc<LoginEvents, LoginState> {
  LoginBloc() : super(LoginState()) {
    on<LoginEmailEvent>(_emailEvent);
    on<LoginPasswordEvent>(_passwordEvent);
  }

  void _emailEvent(LoginEmailEvent event, Emitter<LoginState> emit) {
    emit(state.copyWith(email: event.email));
  }

  void _passwordEvent(LoginPasswordEvent event, Emitter<LoginState> emit) {
    emit(state.copyWith(password: event.password));
  }
}


//Method in the controller that performed the email verification
Future<void> handlePreview() async {
    final state = context.read<AuthBloc>().state;
    final loginState = context.read<LoginBloc>().state;

    String email = state.email;
    if (email.isEmpty) {
      toastInfo(msg: "Please Enter Email Address");
      return;
    }
    try {
      AuthModel authModel = AuthModel();
      authModel.email = email;
      AuthRepository.preview(authModel).then((value) => {
            if (value.response!.code == 200)
              {
                //This is where I changed the value from false to true
                // But still not updating
                loginState.copyWith(showPassword: true)
                //show login fields
              }
            else
              {
                loginState.copyWith(showPassword: false),
                toastInfo(msg: value.response!.message!)
                //show sign up fields
              }
          });
    } catch (e) {
      toastInfo(msg: e.toString());
    }
     //this printing returns false even when the response was 200
    print(loginState.copyWith().showPassword);
  }

@override
  Widget build(BuildContext context) {
    AuthController authController = AuthController(context: context);
    return BlocBuilder<LoginBloc, LoginState>(builder: (context, state) {
      return Scaffold(
          backgroundColor: Color(0xFFF1F3F6),
          body: SafeArea(
            child: Container(
                margin: EdgeInsets.symmetric(horizontal: 100),
                //horizontal: ScreenUtil().setWidth(120)),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    const SizedBox(
                      height: 50,
                    ),
                    Center(
                      child: Visibility(
                        visible: state.showPassword,
                        child: const Text(
                          "Login",
                          style: TextStyle(
                              color: Color(0xFF4D70A6),
                              fontSize: 26,
                              fontWeight: FontWeight.bold),
                        ),
                      ),
                    ),
                    const SizedBox(
                      height: 40,
                    ),
                    Stack(
                      children: <Widget>[
                        buildTextField("Email", "", (value) {
                          context.read<LoginBloc>().add(LoginEmailEvent(value));
                          context.read<AuthBloc>().add(UserAuthEvent(value));
                        }),
                        // Center(
                        //   child: CircularProgressIndicator(),
                        // )
                      ],
                    ),
                    SizedBox(
                      height: 5,
                    ),
                    Visibility(
                        visible: state.showEmail,
                        child: buildLoadingIndicator()),
                    GestureDetector(
                      onTap: () async {
                        authController.handlePreview();
                      },
                      child: Container(
                        child: const Row(
                          mainAxisAlignment: MainAxisAlignment.end,
                          children: [
                            Center(
                              child: Icon(
                                Icons.verified,
                                size: 20,
                                color: Colors.grey,
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                    Visibility(
                      visible: state.showPassword,
                      child: buildTextField("Password", "password", (value) {
                        context
                            .read<LoginBloc>()
                            .add(LoginPasswordEvent(value));
                        print(value);
                      }),
                    ),
                    const SizedBox(
                      height: 50,
                    ),
                    Visibility(
                      visible: state.showPassword,
                      child: GestureDetector(
                        onTap: () {
                          AuthController(context: context).handleLogin();
                        },
                        child: Container(
                          width: double.infinity,
                          alignment: Alignment.center,
                          height: 50,
                          margin: EdgeInsets.symmetric(vertical: 15),
                          decoration: BoxDecoration(
                              color: Color(0xFFF1F3F6),
                              borderRadius:
                                  BorderRadius.all(Radius.circular(10)),
                              boxShadow: [
                                BoxShadow(
                                    offset: Offset(10, 10),
                                    color: Color(0xFF4D70A6).withOpacity(0.2),
                                    blurRadius: 16),
                                const BoxShadow(
                                    offset: Offset(-10, -10),
                                    color: Color.fromARGB(170, 255, 255, 255),
                                    blurRadius: 10),
                              ]),
                          child: const Text(
                            "Login",
                            style: TextStyle(
                                color: Color(0xFF4D70A6), fontSize: 16),
                          ),
                        ),
                      ),
                    ),
                  ],
                )),
          ));
    });
  }

Solution

  • When you use copyWith method you're creating a new instance of LoginState but this new instance is not being emitted back to the UI. To update the UI you need to use the emit function inside your Bloc's event handler.

    Add a new event in your login_event.dart file

    class EmailVerificationResultEvent extends LoginEvent {
      final bool isSuccess;
    
      EmailVerificationResultEvent(this.isSuccess);
    }
    

    Then handle this event in your login_bloc.dart file

    void _emailVerificationResult(EmailVerificationResultEvent event, Emitter<LoginState> emit) {
        emit(state.copyWith(showPassword: event.isSuccess));
    }
    

    And dispatch the EmailVerificationResultEvent when you receive the response from the backend

    if (value.response!.code == 200) {
      context.read<LoginBloc>().add(EmailVerificationResultEvent(true));
    } else {
      context.read<LoginBloc>().add(EmailVerificationResultEvent(false));
    }