0

Stream builder is used to draw widget based on data from stream.

What is the right way to achieve navigation based on the data?

Details: There is a logout button in drawer. It clears the session and emits a data in the stream.

There's a stateless widget with stream builder listening on data and updating UI. How to make it navigate to login screen based on data in the stream?

Harish Reddy
  • 133
  • 8
  • Possible duplicate of [Navigating to a new screen when stream value in BLOC changes](https://stackoverflow.com/questions/54101589/navigating-to-a-new-screen-when-stream-value-in-bloc-changes) – mirkancal May 05 '19 at 13:38

2 Answers2

-1

In your stateless widget's build method, you can listen changes in your stream with listen() method.

 Widget build(BuildContext context) {
    Repository.bulletins.listen((pet) {
      pet.documents[pet.documents.length - 1].data['animalType'] == "Dog"
          ? Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => LostPetForm(),
              ))
          : print('not yet');
    });
    return Scaffold(...
mirkancal
  • 4,762
  • 7
  • 37
  • 75
  • ```I/flutter (14304): The following assertion was thrown while finalizing the widget tree: I/flutter (14304): setState() or markNeedsBuild() called when widget tree was locked. I/flutter (14304): This _ModalScope widget cannot be marked as needing to build because the framework is I/flutter (14304): locked.``` I get this exception when I navigated from listener method inside build method. I read it is not possible to navigate from inside build method. – Harish Reddy May 05 '19 at 12:53
  • Where did you read it? I've post it after I've tried on a small app with 2 screens and firestore on the backend, it navigated itself when I changed the data from Firestore, without a problem. This error means that you are calling setState during the build phase. If you didn't use setState, Navigator.pop uses setState internally according to this SO post. https://stackoverflow.com/a/51246379/9779791 Maybe you can try using Navigator somewhere else in the code, maybe in initState() – mirkancal May 05 '19 at 13:33
-1

Inspired from https://stackoverflow.com/a/54109955/1918649

In the build method of the widget that creates Profile

  @override
  Widget build(BuildContext context) {
    final userBloc = BlocProvider.of<UserBloc>(context);
    return ...
           somewhere here Profile(userBloc)
           ...
}

class Profile extends StatefulWidget  {

  final userBloc;

  Profile(this.userBloc);

  @override
  State<StatefulWidget> createState() => ProfileState();
}

class ProfileState extends State<Profile> {

  @override
  void initState() {
    super.initState();
    widget.userBloc.stream.listen((userData){
      if(userData==null) {
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => LandingPage(),
            ));
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new AppBar(
        title: new Text("Profile"),
      ),
      drawer: CustomDrawer(),
      body: Center(
        child: StreamBuilder<UserModel>(
          initialData: widget.userBloc.user,
          stream: widget.userBloc.stream,
          builder: (ctx, snap) => snap.hasData?Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Image.network(snap.data?.imageUrl),
              Text(snap.data?.username)
            ],
          ):Text('You are logged out'),
        ),
      ),
    );
  }
}

Harish Reddy
  • 133
  • 8