0

i am trying to implement login functionality using bloc pattern in flutter. So I want to navigate to main page after authentication is successful. from loginBloc.dart I will get the status inside the streamBuilder in login.dart when the status is success I want to navigate to main.dart but I cant able to understand how to call the main.dart inside the streamBuilder in login.dart.

login.dart


import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hotelorders/bloc/LoginBloc.dart';
import 'package:hotelorders/screens/Home.dart';

class Login extends StatefulWidget
{
  @override
  State<StatefulWidget> createState() {
    return LoginState();
  }

}
class LoginState extends State<Login>
{
  final LoginBloc _loginBloc = LoginBloc();
  String _email,_password;
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  @override
  void dispose()
  {
    _loginBloc.dispose();
    super.dispose();
  }
  Widget _progressBar()
  {
    return StreamBuilder<bool>(
      stream: _loginBloc.progressStream,
      builder: (BuildContext context,AsyncSnapshot<bool> snapShot) {
        bool visible;
        if(snapShot.data == null)
          {
            visible = false;
          }
        else
          {
            visible = snapShot.data;
          }
        return Visibility(
          maintainSize: true,
          maintainAnimation: true,
          maintainState: true,
          visible: visible,
          child: Container(
              child: Center(
                  child: SizedBox(
                    width: 60,
                    height: 60,
                    child: Stack(
                      children: <Widget>[
                        Container(
                          decoration: BoxDecoration(
                            shape: BoxShape.circle,
                            color: Colors.white,
                            boxShadow: [
                              BoxShadow(
                                color: Colors.grey,
                                offset: Offset(0.0, 1.0), //(x,y)
                                blurRadius: 1.0,
                              ),
                            ],
                          ),
                        ),
                        Center(
                          child: CircularProgressIndicator(),
                        )
                      ],
                    ),
                  )
              )
          ),
        );
      }
    );
  }
  Widget _emailTextField()
  {
    return TextFormField(
      decoration: InputDecoration(
        labelText: "Email id",
        border: OutlineInputBorder(
          borderRadius: new BorderRadius.circular(32.0),
        )
      ),
      keyboardType: TextInputType.emailAddress,
      validator: (String value){
        if(value.isEmpty || !RegExp(r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?").hasMatch(value))
          {
            return "Enter a valid email id";
          }
        return null;
      },
      onSaved: (String value){
        _email = value;
      },
    );
  }
  Widget _passwordTextField()
  {
    return TextFormField(
      decoration: InputDecoration(labelText: "Password",
          filled: true,

          border: OutlineInputBorder(
            borderRadius: new BorderRadius.circular(32.0),
          ),
          fillColor: Colors.white
      ),
      keyboardType: TextInputType.text,
      obscureText: true,
      validator: (String value){
        if(value.isEmpty)
          {
            return "Enter a valid password";
          }
        else if(value.length < 8)
          {
            return "Password is too short";
          }
        else
          {
            return null;
          }
      },
    );
  }
  void _login()
  {

    if(!_formKey.currentState.validate())
      {
        return;
      }
    _formKey.currentState.save();

    Map<String,String> map = new Map();
    map['email'] = _email;
    map['password'] = _password;
    _loginBloc.login(map);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          SingleChildScrollView(
              child: Container(
                child: Column(
                  children: <Widget>[
                    Container(
                      alignment: Alignment.center,
                      margin: EdgeInsets.fromLTRB(0, 48, 0, 0),
                      child: Text(
                        "Take Orders and",
                        style: TextStyle(color: Theme.of(context).primaryColorDark,fontSize: 20),
                      ),
                    ),
                    Container(
                      child: Text(
                        "Track the Best Selling Items",
                        style: TextStyle(color: Theme.of(context).primaryColor,fontSize: 16),
                      ),
                    ),
                    Container(
                      margin: EdgeInsets.fromLTRB(16, 0, 16, 0),
                      child: SvgPicture.asset('assets/images/undraw_booking.svg',width: 100.0,height: 280.0,),
                    ),
                    Container(
                      margin: EdgeInsets.fromLTRB(16, 0, 0, 0),
                      child:Row(
                        children: <Widget>[
                          Text(
                              "Login To ",
                              style: TextStyle(color: Colors.black,fontSize: 20)
                          ),
                          Text(
                            "Take orders",
                            style: TextStyle(color: Theme.of(context).primaryColorDark,fontSize: 20),
                          )
                        ],
                      ),
                    ),
                    Container(
                      margin: EdgeInsets.fromLTRB(16, 8, 16, 0),
                      child: Form(
                        key: _formKey,
                        child: Column(
                          children: <Widget>[
                            Container(
                              margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
                              child:  _emailTextField(),
                            ),
                            Container(
                              margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
                              child:  _passwordTextField(),
                            ),
                            Container(
                              margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
                              child: Align(
                                alignment: Alignment.centerLeft,
                                child: RaisedButton(
                                  shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(32.0)
                                  ),
                                  padding: EdgeInsets.fromLTRB(64, 12, 64, 12),
                                  color: Theme.of(context).accentColor,
                                  textColor: Colors.white,
                                  child: Text(
                                    "Login",
                                  ),
                                  onPressed: (){
                                    _login();
                                  },
                                ) ,
                              ),
                            ),
                            StreamBuilder<dynamic>(
                              stream:_loginBloc.loginStateStream,
                              builder: (BuildContext context, AsyncSnapshot<dynamic> snapShot){
                                if(snapShot.data == "success")
                                  {
//                                    WidgetsBinding.instance.addPostFrameCallback((_){
//                                      Navigator.push(context, MaterialPageRoute(
//                                          builder: (context)=> Home()
//                                      ));
//                                    });
                                  }
                                else if(snapShot.data != null && snapShot.data != "success")
                                  {
                                    WidgetsBinding.instance.addPostFrameCallback((_) {
                                      Scaffold.of(context).showSnackBar(SnackBar(
                                        content: Text('${snapShot.data}',
                                          style: TextStyle(color: Colors.black),),
                                        backgroundColor: Color(0xFFe5e5e5),
                                      ));
//                                      showDialog(context: context,builder: (BuildContext con){
//                                        return AlertDialog(
//                                          title: Text('${snapShot.data}'),
//                                        );
//                                      });
                                    });
                                  }

                                return Container();
                              },
                            )
                          ],
                        ),
                      ),

                    )

                  ],
                ),
              )
          ),
          _progressBar(),
        ],
      ),
    );
  }

}

LoginBloc.dart

import 'dart:async';


class LoginBloc
{
  // here event comes in and state goes out
  //stream conntroller for output
  final _loginStateController = StreamController<String>();
  //stream controller for input
  final _loginEventController = StreamController<Map<String,String>>();

  final _progressController = StreamController<bool>();

  StreamSink<String> get loginStateSink => _loginStateController.sink;
  Stream<String> get loginStateStream => _loginStateController.stream;

  Sink<Map<String,String>> get loginEventSink => _loginEventController.sink;

  Stream<bool> get progressStream => _progressController.stream;
  StreamSink<bool> get progressSink => _progressController.sink;


  LoginBloc()
  {
    progressSink.add(false);
    _loginEventController.stream.listen(login);

  }

  login(Map<String,String> loginDetails)
  {
    progressSink.add(true);
    Timer(Duration(seconds: 3), () {
      progressSink.add(false);
      loginStateSink.add("success");
    });
    // when we pass data in sink we get the  output from stream

  }
  void dispose()
  {
    _loginEventController.close();
    _loginStateController.close();
    _progressController.close();
  }

}
Suhail Ahmed
  • 157
  • 2
  • 15

1 Answers1

0

You are almost there. The following should work :

if(snapShot.data == "success")
{

    Navigator.push(
        context, MaterialPageRoute(builder: (context)=> Home()));

}

Note : WidgetsBinding.instance.addPostFrameCallback is used to get a callback when widget tree is loaded.

Sukhi
  • 13,261
  • 7
  • 36
  • 53
  • hi sukhi thanks for the reply but I am getting an error if add the above code .setState() or markNeedsBuild() called during build. This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase. – Suhail Ahmed Apr 16 '20 at 08:07