0

Previously my AutomaticKeepAliveClientMixin did work well to preserve the state but with this code below it is not working.

Firstly i have a Main tab.. inside the 3rd tab there are 3 tabs (nested Tab if you may) The code below fails to preserve the state of the tab while i am switching from the three nested tabs.

I think i am using AutomatickKeepAlive.. appropriately, however can't understand why am i not able to save it? i am using firestore data base and streambuilder / futurebuilder too. Looks like the Futurebuilder is being called no matter what.

class _RecordsState extends State<Records> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;
  late Stream<QuerySnapshot> _captainStream;
  late Stream<QuerySnapshot> _firstOfficerStream;
  late Stream<QuerySnapshot> _cabinCrewStream;
  PlutoGridStateManager? _stateManager;
  List<Map<String, dynamic>>? dataCabin;
  List<PlutoColumn> columns = [];
  List<PlutoRow>? plutoRows;
  List<PlutoRow> pilotRows = [];
  PlutoGridMode mode = PlutoGridMode.selectWithOneTap;
  @override
  void initState() {
    super.initState();
    _captainStream = FirebaseFirestore.instance.collection('CAPTAIN_DATA').snapshots();
    _firstOfficerStream = FirebaseFirestore.instance.collection('FIRST_OFFICER_DATA').snapshots();
    _cabinCrewStream = FirebaseFirestore.instance.collection('CABIN_CREW_DATA').snapshots();
  }

  Future<Map<String, dynamic>> getCollectionData(DocumentReference reference, String collectionName) async {
    final snapshot = await reference.collection(collectionName).doc('details').get();
    return snapshot.data() as Map<String, dynamic>;
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            mode = mode == PlutoGridMode.selectWithOneTap ? PlutoGridMode.normal : PlutoGridMode.selectWithOneTap;
          });
        },
        child: mode == PlutoGridMode.selectWithOneTap ? const Icon(Icons.edit) : const Icon(Icons.calendar_today),
      ),
      //backgroundColor: Theme.of(context).primaryColor,
      body: DefaultTabController(
        length: 3,
        child: Column(
          children: [
            const TabBar(
              indicator: BoxDecoration(
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(10),
                    topRight: Radius.circular(10),
                  ),
                  color: MyColors.primarySwatch),
              labelColor: Colors.white,
              tabs: [
                Tab(text: 'Captain Training'),
                Tab(text: 'First Officer Training'),
                Tab(text: 'Cabin Crew Training'),
              ],
              indicatorColor: Color.fromARGB(255, 102, 249, 4),
              indicatorSize: TabBarIndicatorSize.tab,
              unselectedLabelColor: Colors.black,
            ),
            Expanded(
              child: TabBarView(
                children: [
                  StreamBuilder<QuerySnapshot>(
                    stream: _captainStream,
                    builder: (context, snapshot) {
                      if (!snapshot.hasData) {
                        return const Center(child: CircularProgressIndicator());
                      }
                      List<Future<Map<String, dynamic>>> data = getCockpitCrewData(snapshot);
                      return FutureBuilder<List<Map<String, dynamic>>>(
                        future: Future.wait(data),
                        builder: (context, snapshot) {
                          if (!snapshot.hasData) {
                            return const Center(child: CircularProgressIndicator());
                          }
                          return buildGrid(snapshot.data!, "captain");
                        },
                      );
                    },
                  ),
                  StreamBuilder<QuerySnapshot>(
                    stream: _firstOfficerStream,
                    builder: (context, snapshot) {
                      if (!snapshot.hasData) {
                        return const Center(child: CircularProgressIndicator());
                      }
                      final data = snapshot.data!.docs.map((doc) => doc.data() as Map<String, dynamic>).toList();
                      return buildGrid(data, "firstOfficer");
                    },
                  ),
                  StreamBuilder<QuerySnapshot>(
                    stream: _cabinCrewStream,
                    builder: (context, snapshot) {
                      if (!snapshot.hasData) {
                        return const Center(child: CircularProgressIndicator());
                      }
                      if (snapshot.hasData) {
                        // print('data ihas data ncoming...');
                        for (var change in snapshot.data!.docChanges) {
                          if (change.type == DocumentChangeType.added) {
                          } else if (change.type == DocumentChangeType.modified) {
                          } else if (change.type == DocumentChangeType.removed) {}
                        }
                      }
                      final data = snapshot.data!.docs.map((doc) => doc.data() as Map<String, dynamic>).toList();
                      return buildGrid(data, "cabinCrew");
                    },
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  PlutoGrid buildGrid(List<Map<String, dynamic>> data, String type) {
    return PlutoGrid(
      // mode: PlutoGridMode.normal,
      mode: mode,
      onSelected: (event) async {
        print(mode);
        final PlutoRow row = _stateManager!.rows.elementAt(event.rowIdx!);
        final String userId = row.cells['NAME']!.value.toString();
        final String firestoreCollection = type == "captain"
            ? "CAPTAIN_DATA"
            : type == "firstOfficer"
                ? "FIRST_OFFICER_DATA"
                : "CABIN_CREW_DATA";
        print(event.cell!.column.field);
        if (event.cell!.column.field == 'NAME' || event.cell!.column.field == 'Age' || event.cell!.column.field == 'license no') {
          CollectionReference crewCollection = FirebaseFirestore.instance.collection(firestoreCollection);
          await crewCollection.doc(userId).update({event.cell!.column.field: event.cell!.value.toString()});
        } else {
          openDetail(event.cell, event.cell!.column.field, userId, firestoreCollection);
        }
      },
      onChanged: (event) async {
        print(mode);
        final PlutoRow row = _stateManager!.rows.elementAt(event.rowIdx);
        final String userId = row.cells['NAME']!.value.toString();
        final String firestoreCollection = type == "captain"
            ? "CAPTAIN_DATA"
            : type == "firstOfficer"
                ? "FIRST_OFFICER_DATA"
                : "CABIN_CREW_DATA";
        if (event.column.field == 'NAME' || event.column.field == 'Age' || event.column.field == 'license no') {
          CollectionReference crewCollection = FirebaseFirestore.instance.collection(firestoreCollection);
          await crewCollection.doc(userId).update({event.column.field: event.value.toString()});
        }
      },
      onLoaded: (PlutoGridOnLoadedEvent event) {
        _stateManager = event.stateManager;
        _parseColumnRow(data, type);
        // _stateManager!.setShowLoading(true);
      },
      columns: type == 'captain'
          ? captainColumn
          : type == 'firstOfficer'
              ? firstOfficerColumn
              : columns,
      rows: type == 'captain' || type == 'firstOfficer' ? pilotRows : plutoRows ?? [],
      columnGroups: type == 'captain'
          ? captainColumnGroup
          : type == 'firstOfficer'
              ? firstOfficerColumnGroup
              : null,
    );
  }
Pannam
  • 482
  • 1
  • 3
  • 16

1 Answers1

1

The TabBarView rebuilds its children every time a tab is switched and setState is executed, causing the data to be refetched and reseting the state.

To avoid this you should store your tab views in separate widgets like this:

child: TabBarView(
children: [ 
StreamWidget1(),
StreamWidget2(),
StreamWidget3()]

Please see the following link for more info: Flutter: TabBarView Moving to a tab rebuilds also the other ones

Texv
  • 1,225
  • 10
  • 14