problem with the rxdart combineLatest2 in flutter , it still use old stream after my stream goes on error

176 Views Asked by At

I'm using streaming to validate two textField and a button on my screen, my validators work fine with the bloc architecture that I built in the app, I use The rxdart combineLatest2 to combine my two TextFields validation to enable and disable my login button, everything works fine in the beginning but when I delete and refill fields combiner mix up and enable login button even one of the fields are not valid I show the problem in gif for better understanding of my problem. this is the link to gif: https://freeimage.host/i/SVjN1a

u can see the full code on my GitHub too, please help me fix this issue https://github.com/Manticodes/flutter_loginscreen_blocpattern

I use this code inside my bloc class to combine two validation stream

Stream<bool> get submitValid =>
          Rx.combineLatest2(emailvalidation, passwordvalidation, (a, b) => true);

this is my bloc class that contains combiner

class Bloc with Validator {
  final _emailController = BehaviorSubject<String>();
  final _passwordController = BehaviorSubject<String>();
  final _textController = BehaviorSubject<String>();

  // add to stream
  Function(String) get reciveText => _textController.sink.add;
  Function(String) get changeEmail => _emailController.sink.add;
  Function(String) get changePassword => _passwordController.sink.add;

  // access to stream
  Stream<String> get emailvalidation =>
      _emailController.stream.transform(validateEmail);
  Stream<String> get passwordvalidation =>
      _passwordController.stream.transform(validatePassword);
  Stream<bool> get submitValid =>
      Rx.combineLatest2(emailvalidation, passwordvalidation, (a, b) => true);
  Stream<String> get accesstext =>
      _textController.stream.transform(validateText);

  submit() {
    final validemail = _emailController.value;
    final validpass = _passwordController.value;
    reciveText('user name : $validemail \n pass : $validpass ');
    print('all valid');
  }

  dispose() {
    _emailController.close();
    _passwordController.close();
  }
}

this is validator class

class Validator {
  final validateEmail = StreamTransformer<String, String>.fromHandlers(
    handleData: (data, sink) {
      if (data.contains('@') && data.contains('.')) {
        sink.add(data);
      } else {
        sink.addError('Enter Valid emaill');
      }
    },
  );
  final validatePassword = StreamTransformer<String, String>.fromHandlers(
    handleData: (data, sink) {
      if (data.length > 3) {
        sink.add(data);
      } else {
        sink.addError('Password is too short');
      }
    },
  );
  final validateText = StreamTransformer<String, String>.fromHandlers(
    handleData: (data, sink) {
      sink.add(data);
    },
  );
}

and finally, this is the class that contains my screen

class LoginScreen extends StatelessWidget {
  const LoginScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final bloc = Provider.of(context);
    return Scaffold(
      appBar: AppBar(title: Text('Log me in ')),
      body: Container(
        margin: EdgeInsets.all(20),
        child: Column(children: [
          emailField(bloc),
          passwordField(bloc),
          SizedBox(
            height: 40,
          ),
          submitbutton(bloc),
          message(bloc), 
        ]),
      ),
    );
  }

  emailField(Bloc bloc) {
    return StreamBuilder(
      stream: bloc.emailvalidation,
      builder: (context, snapshot) {
        return TextField(
          onChanged: bloc.changeEmail,
          keyboardType: TextInputType.emailAddress,
          decoration: InputDecoration(
            hintText: '[email protected]',
            labelText: 'Email Address',
            hintStyle: TextStyle(color: Colors.grey),
            errorText:
                snapshot.error != null ? snapshot.error.toString() : null,
          ),
        );
      },
    );
  }

  passwordField(Bloc bloc) {
    return StreamBuilder(
      stream: bloc.passwordvalidation,
      builder: (context, snapshot) {
        return TextField(
          onChanged: bloc.changePassword,
          obscureText: false,
          decoration: InputDecoration(
              hintText: 'use strong password',
              labelText: 'Password',
              errorText:
                  // ignore: prefer_null_aware_operators
                  snapshot.error != null ? snapshot.error.toString() : null),
        );
      },
    );
  }

  submitbutton(Bloc bloc) {
    return StreamBuilder(
      stream: bloc.submitValid,
      builder: (context, snapshot) {
        return ElevatedButton(
          onPressed: snapshot.hasData
              ? () {
                  bloc.submit();
                }
              : null,
          style: ElevatedButton.styleFrom(primary: Colors.red),
          child: const Text('login'),
        );
      },
    );
  }

  message(Bloc bloc) {
    return StreamBuilder(
      stream: bloc.submitValid,
      builder: (context, snapshot1) {
        if (snapshot1.hasData) {
          return StreamBuilder(
            stream: bloc.accesstext,
            builder: (context, snapshot2) {
              return Text(snapshot2.hasData ? ' ${snapshot2.data} ' : '');
            },
          );
        } else {
          return Center(
            child: Container(
                child: Text('Please Enter valid User name & Password')),
          );
        }
      },
    );
  }
}
0

There are 0 best solutions below