flutterdart

stream builder ConnectionState.waiting when i click on the same page


i have this homepage

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  @override
  State<MainPage> createState() => _MainPageState();
}

/** 
 * Future builder is a staeful widhget that subs to a future that will return its value. 
 * value starts calculates returns and finishes. 
 * it takes the shiunk of code that produces the value and subs to it and i will give you the ability to 
 * return various widgets that needs to be returned to the screen 
 * ties ui with db. 
 * 
 */
class _MainPageState extends State<MainPage> {
  late final EventsService _eventsService;
  late final Future<DatabaseUser> _user;
  late final Stream<List<DatabaseEvent>> _events;

  int _currentIndex = 1;
  String _title = "Crewmunity";

  @override
  void initState() {
    /** we create a new event service every time 
     * so we will create a singleton 
     * we create a service a service or class which is only one in our entire application. 
     * there shouldnt be other copies. 
     * 
     */
    _eventsService = EventsService();
    _eventsService.open();
    _user = _eventsService.getOrCreateUser(email: userEmail);
    _events = _eventsService.allEvents;

    super.initState();
  }

  // no need for now
  // @override
  // dispose() {
  //   _eventsService.close();
  //   super.dispose();
  // }

  String get userEmail => AuthService.firebase().currentUser!.email!;
  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);
    final style = theme.textTheme.displaySmall!.copyWith(
      color: theme.colorScheme.onPrimary,
    ); // the textTheme has different fonts
    return Scaffold(
      appBar: CustomAppbar(title: _title),
      body: FutureBuilder(
        future: _user, //_eventsService.getOrCreateUser(email: userEmail),
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.done:
              return StreamBuilder(
                stream: _events,
                builder: (context, snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.active:
                      /**
                     *  listview box scroll view which is a stateless widget
                     * builder we will pass 2 params
                     * we need for the item count to listen to the snapshot. 
                     */
                      if (snapshot.hasData) {
                        final allEvents = snapshot.data as List<DatabaseEvent>;
                        allEvents.sort((a, b) => b.date.compareTo(a.date));
                        return EventListView(
                            events: allEvents,
                            onDeleteEvent: (event) async {
                              await _eventsService.deleteEvent(id: event.id);
                            },
                            onTap: (event) {
                              Navigator.of(context).pushNamed(
                                  createUpdateEventRoute,
                                  arguments: event);
                            },
                            isUserPage: false);
                      } else {
                        return const CircularProgressIndicator();
                      }

                    case ConnectionState.waiting:
                      return const Text("Waiting for all events");
                    default:
                      return CircularProgressIndicator();
                  }
                },
              );
            default:
              return const CircularProgressIndicator();
          }
        },
      ),
      bottomNavigationBar: CustomBottomNanBar(
        currentIndex: _currentIndex,
      ),
    );
  }
}

When I load the app the events are displayed properly. When I navigate to other pages there doesn't seem to be any issue. When I click on the navigation bar, on the page that I already am, it goes to the ConnectionState.waiting case and it does not show the events. What am I doing wrong? This happens to the other pages that i have as well


Solution

  • I have a CustomNavBar class that has a currentIndex parameter.

    class CustomBottomNanBar extends StatelessWidget {
      final int currentIndex;
    
      const CustomBottomNanBar({required this.currentIndex});
    
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          currentIndex: currentIndex, // Current selected index
          onTap: (index) => _onNavBarTapped(context, index),
          showSelectedLabels: false, // Hides the label for the selected item
          showUnselectedLabels: false, // Hides the label for unselected items
          items: const [
            BottomNavigationBarItem(
              icon: Icon(Icons.group),
              label: 'Joined Events',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: 'Home',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.add),
              label: 'New Event',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.search),
              label: 'Search',
            ),
          ],
        );
      }
    
      void _onNavBarTapped(BuildContext context, int index) {
        if (currentIndex == index) {
          return;
        }
        switch (index) {
          case 0:
            // Handle any logic for the first tab
            Navigator.of(context).pushNamedAndRemoveUntil(
              joinedEventsRoute,
              (route) => false, // Remove all previous routes
            );
          case 1:
            Navigator.of(context).pushNamedAndRemoveUntil(
              homeRoute,
              (route) => false, // Remove all previous routes
            );
            break;
          case 2:
            Navigator.of(context).pushNamed(createUpdateEventRoute);
            break;
          case 3:
            Navigator.of(context)
                .pushNamedAndRemoveUntil(searchRoute, (route) => false);
            break;
          default:
            break;
        }
      }
    }
    

    To solve my issue I used the if statement before the switch state. This way when the user clicks on the same page, the function will not return something and the page does not rebuild.