0
votes

I am working on an app in flutter which requires me to store and retrieve keys stored in firebase/firestore. Currently I am reading all the keys as a stream after following few tutorials. Although I do not want to read it as a stream. I just want to read the current value of the keys once and store those keys in my Provider class named ActivationKeyPoolProvider. I want to programmatically call a function which reads all the keys stored on firestore and then do not listen to the stream. Finally I want to be able to change the status of the key from true to false. Currently I am able to do this as shown in the onTap Function inside _buildListItem. I found this function from the flutter youtube channel and I apologise because I do not understand that part much. I usually do not just copy paste without understand but this time I did. I am not an expert in flutter yet and barely started with Firestore. Following is a stripped down code that I am currently using and a key structure that I have on firestore:

Firestore collection

// -> collection: alphaNumericKey
//        ->document: 1
//                -> key    : /15 character long key/
//                -> status : /true or false/
//        ->document: 2
//                -> key    : /15 character long key/
//                -> status : /true or false/
//        ->document: 3
//                -> key    : /15 character long key/
//                -> status : /true or false/
// ...........

Key Page

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';

import '../Provider/activation_key_pool_provider.dart';

class KeyActivationPage extends StatefulWidget {
  const KeyActivationPage({Key? key}) : super(key: key);
  static const routeName = '/KeyActivationPage';

  @override
  _KeyActivationPageState createState() => _KeyActivationPageState();
}

class _KeyActivationPageState extends State<KeyActivationPage> {
  final _keyController = TextEditingController();
  bool _firebaseSuccess = false;
  bool _keysVisible = false;
  String? key;

  @override
  void initState() {
    super.initState();
    Firebase.initializeApp().whenComplete(() {
      print("firebase initialised");
      Future.delayed(Duration(seconds: 2), () {
        setState(() {
          _firebaseSuccess = true;
        });
      });
    });
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
  }

  @override
  void dispose() {
    super.dispose();
    _keyController.dispose();
  }

  Widget _buildListItem({
    required BuildContext context,
    required DocumentSnapshot document,
    required int length,
    required int currentIndex,
  }) {
    ActivationKeyPoolProvider.addKey(
      key: document['alphaKey'],
      status: document['status'],
    );
    if (currentIndex == length - 1) {
      //ActivationKeyPoolProvider.printAllKeys();
    }
    return _keysVisible
        ? ListTile(
            title: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Expanded(
                  flex: 2,
                  child: Text(
                    document['alphaKey'],
                    style: TextStyle(fontSize: 20, color: Colors.white),
                  ),
                ),
                Expanded(
                  child: Container(
                    padding: EdgeInsets.all(10.0),
                    child: Text(
                      document['status'].toString(),
                      style: Theme.of(context).textTheme.headline6,
                    ),
                  ),
                )
              ],
            ),
            onTap: () {
              // Responsible to change the state of the key
              // Do not quite understand how this works yet
              FirebaseFirestore.instance.runTransaction((transaction) async {
                DocumentSnapshot freshSnap = await transaction.get(document.reference);
                transaction.update(freshSnap.reference, {
                   'status': document['status'] ? false : true,
                });
              });
              print('should change active status');
            },
            onLongPress: () {
              //Do something
            },
          )
        : Container();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Center(
        child: Stack(
          children: <Widget>[
            // Keys for debug
            _firebaseSuccess
                ? StreamBuilder(
                    stream: FirebaseFirestore.instance
                        .collection('alphaNumericKey')
                        .snapshots(),
                    builder: (context, snapshot) {
                      ActivationKeyPoolProvider.setListEmpty();
                      AsyncSnapshot _snapshot;
                      if (!snapshot.hasData) return const Text('loading...');
                      _snapshot = snapshot;
                      return ListView.builder(
                        itemExtent: 50.0,
                        itemCount: _snapshot.data.docs.length,
                        itemBuilder: (context, index) {
                          return _buildListItem(
                            context: context,
                            document: _snapshot.data.docs[index],
                            length: _snapshot.data.docs.length,
                            currentIndex: index,
                          );
                        },
                      );
                    },
                  )
                : Container(
                    child: Center(
                        child: Text(
                      'Loading keys',
                      style: Theme.of(context).textTheme.bodyText1,
                    )),
                  ),
          ],
        ),
      ),
    );
  }
}
1

1 Answers

0
votes

StreamBuilder is useful if your data is continuously changing. But in your scenario, you migh prefer to use a FutureBuilder instead.

Here are two good tutorials which discuss both alternatives: