'Form validation doesnt work properly by using Bloc, Provider, Streams, sinks in Flutter

I need to enable the button if the text fields are not empty, it works when u launch the app for the first time, but when i remove letters the button becomes enable until all text fields are empty

Also, can we change widget properties e.g. obscure text when we click show/hide password using bloc?

signin_bloc.dart

class SignInBloc {
  final StreamController _username = BehaviorSubject<String>(); 
  final StreamController _password = BehaviorSubject<String>();

  Stream<String> get username => _username.stream.transform(validateUser);
  Stream<String> get password => _password.stream.transform(validatePassword);

  
  Stream<bool> get formValid => Rx.combineLatest2(username, password, (username, password) => true); 
   Function(String) get changeUsername => _username.sink.add;
  Function(String) get changePassword => _password.sink.add;

void dispose() {
    _username.close();
    _password.close();
  }

final validateUser = StreamTransformer<String, String>.fromHandlers(
      handleData: (username, sink) {
if (username.isNotEmpty) {
      sink.add(username);
} else {
      sink.addError('Must not be empty');
    }
  });

final validatePassword = StreamTransformer<String, String>.fromHandlers(
  
      handleData: (password, sink) {
    if (password.isNotEmpty) {
      sink.add(password);
    } else {
      sink.addError('Must not be empty');
    }
  });

main.dart

void main() {
  runApp(
    Provider(create: (context) => SignInBloc(),child: MyApp(),
  ));
}


    @override
  Widget build(BuildContext context) {

    final bloc = Provider.of<SignInBloc>(context);

    Widget loginInputField(SignInBloc bloc) {
      return Consumer<SignInBloc>(builder:(context, bloc, child) =>StreamBuilder<String>(
        stream: bloc.username,
        builder: (context, snapshot) {
          return TextField(
            onChanged: bloc.changeUsername,
            controller: loginController,
            .....
    }

    Widget passwordInputField(SignInBloc bloc) {
      return Consumer<SignInBloc>(builder:(context, bloc, child) => StreamBuilder<String>(
          stream: bloc.password,
          builder:(context, snapshot){
            return TextField(
                onChanged: bloc.changePassword,
                controller: passwordController,
               ......
          }));}

    Widget signInButton(SignInBloc bloc) {
      return  Consumer<SignInBloc>(builder:(context, bloc, child) =>StreamBuilder<bool>(
          stream: bloc.formValid,
          builder: (context, snapshot) {
            return ConstrainedBox(
               .......[enter image description here][1]
                    onPressed: snapshot.hasData && !snapshot.hasError ? bloc.signIn : null));
          }
      ));};



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source