How do you handle async and loading indicator in flutter?

39 Views Asked by At

I have a custom loading indicator that gets called when there is a data fetch from an API call that returns an XML. they are call after the another and they are 3 in total. what I'm having a trouble with is that when one return data and the others don't the loading indicator doesn't go away or disappear. That is causing some weird glitches. Meaning if all of them returned some data it will show and go away after that and sometimes it won't. Please do check the codes below. thanks.

my custom loading widget

class InfoDialog extends StatelessWidget {
final String text;

const InfoDialog({Key? key, required this.text}) : super(key: key);

@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;

return AlertDialog(
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.all(Radius.circular(20.0)),
  ),
  contentPadding: EdgeInsets.zero,
  content: Container(
    // color: Colors.w,
    height: 146,
    width: MediaQuery.of(context).size.width - 10,
    child: Column(
      children: [
        Directionality(
          textDirection: TextDirection.rtl,
          child: Row(
            children: [
              IconButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                icon: Icon(
                  Icons.clear,
                  size: 20,
                  color: Colors.black,
                ),
              ),
              const SizedBox(width: 20),
              Text(
                "",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 14.0,
                  fontFamily: 'Arabic',
                ),
              ),
            ],
          ),
        ),
        Padding(
          padding: const EdgeInsets.only(right: 2, left: 2, bottom: 2),
          child: Container(
            width: double.infinity,
            // color: Colors.white,
            child: Column(
              children: [
                Padding(
                  padding: EdgeInsets.all(5),
                  child: Text(
                    text,
                    style: TextStyle(
                      fontSize: 15.0,
                      fontFamily: 'Arabic',
                    ),
                    textAlign: TextAlign.center,
                  ),
                ),
                SizedBox(
                  height: 40,
                  width: double.maxFinite,
                  child: ElevatedButton(
                    style: ButtonStyle(
                      backgroundColor: MaterialStateProperty.all(Colors.blue), // Update color as needed
                      shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(30.0),
                        ),
                      ),
                    ),
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                    child: const Text(
                      'حسناً',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 14,
                        fontFamily: "Arabic",
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ],
    ),
  ),
   );
}
}

  void showInfoDialog(BuildContext context, String text) {
  showDialog(
    barrierDismissible: false,
    context: context,
    builder: (BuildContext context) {
     return StatefulBuilder(
        builder: (context, setState) {
     return InfoDialog(text: text);
    },
  );
  },
);
}

the screen where the APIs are called. the user enters a number. it could be a meter number or a subscription number and based on which is which the switch statement will get called and add that value to the string result then send it. and wait for the response returned.

  class _ViewBillsState extends State<ViewBills> {
  TextEditingController meterNum = TextEditingController();
 TextEditingController supNum = TextEditingController();

 List<bool> _visable = [];
 List<bool> _visabledisconnect = [];
 List<bool> _visablefollowUp = [];
 List<bool> _visableMstate = [];

//visible buttons
bool isListVisible = false;
 bool isListFollowVisible = false;
bool isDocsIconPressed = false;

int step = 0;
String result = '';

CustomerPhotoMeter? PhotoMeter;
List<CustomerInvoice> invoicess = [];
List<DisconnectCust> disconnectCust = [];
List<AllFollowUps> allFollowUps = [];


ViewBills() {
  getUserBills(step);
}

 getUserBills(step) {
  switch (step) {
    case 0:
      result =
         "DataType:31;Where:;mtrnum: and LPAD(cmf.cusm_city,3,'0')||LPAD(cmf.CUSM_NUM,7,'0') 
              = '${supNum.text}'";
    break;
  case 1:
    result = "DataType:29;Where:;mtrnum:${meterNum.text}";
    break;

  default:
    result = "";
}
final publicKey = RSAKeyParser().parse(
        "-----BEGIN PUBLIC KEY-----\n\n-----END PUBLIC KEY-----")
    as RSAPublicKey;
final privKey = RSAKeyParser().parse(
        "-----BEGIN PRIVATE KEY-----\=\n-----END PRIVATE KEY-----")
    as RSAPrivateKey;
final encrypter = Encrypter(RSA(
    publicKey: publicKey,
    privateKey: privKey,
    encoding: RSAEncoding.PKCS1));

final encrypted = encrypter.encrypt(result);

var a = encrypted.bytes;
var temp = base64Encode(a);
var reqUserBills = api_connect();
var methodName = "GetCustomerBillingInfoEnc";
reqUserBills.addProperty("data", temp);
reqUserBills.initEnvelope(methodName);
showAlertDialog(context);

reqUserBills
    .post("http://tempuri.org/IBillingWcfsrv/$methodName")
    .catchError((err) {
  Navigator.of(context).pop();
  showDialog(
    barrierDismissible: false,
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        content: Container(
          child: const Text(
            "يوجد خطأ بالشبكة يرجى المحاولة لاحقا",
            textAlign: TextAlign.right,
          ),
        ),
        actions: <Widget>[
          TextButton(
            child: new Text("حسنا"),
            onPressed: () {
              Navigator.of(context).pop();
            },
          ),
        ],
      );
    },
  );
}).then(
  (value) => api_connect.photoMeter(value, methodName).then((value) async {
    // Navigator.pop(context),
    try {
      if (value != null) {
        setState(() {
          PhotoMeter = value;
          _visable = List<bool>.filled(invoicess!.length, false);
          isListVisible = false;
        });

        await invoiceInfo(PhotoMeter!.MTR_CITY, PhotoMeter!.MTR_NUM);
        await disconnectInquire(PhotoMeter!.MTR_CITY, PhotoMeter!.MTR_NUM);
        await followUp(PhotoMeter!.MTR_CITY, PhotoMeter!.MTR_NUM);
        // await meterStateCheck(PhotoMeter!.KIND, PhotoMeter!.MTR_NUM);
      } else {
        Navigator.pop(context);
        showInfoDialog(context, "لا يوجد معلومات على رقم الاستعلام");
        meterNum.text = '';
        supNum.text = '';
      }
    } catch (error) {
      // Handle errors here
      print("Error: $error");
      Navigator.pop(context);
      showInfoDialog(context, "حدث خطأ أثناء معالجة البيانات");
    }
  }),
);

}

here is one of the api calls and the rest of them are structured the same

Future<void> followUp(String cityfollowNum, String supfollowNum) async {
String result =
    "DataType:39,Where: and CITY_ID ='$cityfollowNum' and CUST_ID='$supfollowNum'";
final publicKey = RSAKeyParser().parse(
        "-----BEGIN PUBLIC KEY-----\n\n-----END PUBLIC KEY-----")
    as RSAPublicKey;
final privKey = RSAKeyParser().parse(
        "-----BEGIN PRIVATE KEY-----\n\n-----END PRIVATE KEY-----")
    as RSAPrivateKey;
final encrypter = Encrypter(RSA(
    publicKey: publicKey,
    privateKey: privKey,
    encoding: RSAEncoding.PKCS1));
final encrypted = encrypter.encrypt(result);
var a = encrypted.bytes;
var temp = base64Encode(a);
var reqAllCusmSummary = api_connect();
var methodName = "GetAllCusmSummary";
reqAllCusmSummary.addProperty("data", temp);
reqAllCusmSummary.initEnvelope(methodName);
showAlertDialog(context);
reqAllCusmSummary
    .post("http://tempuri.org/IBillingWcfsrv/$methodName")
    .timeout(Duration(seconds: 10))
    .catchError((err) {
  Navigator.of(context).pop();
  showDialog(
    barrierDismissible: false,
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        content: Container(
          child: const Text(
            "يوجد خطأ بالشبكة يرجى المحاولة لاحقا",
            textAlign: TextAlign.right,
          ),
        ),
        actions: <Widget>[
          TextButton(
            child: const Text("حسنا"),
            onPressed: () {
              Navigator.of(context).pop();
            },
          ),
        ],
      );
    },
  );
}).then(
  (value) => api_connect.followUps(value, methodName).then(
        (value) => {
          // Navigator.pop(context),
          if (value.isNotEmpty)
            {
              setState(() {
                allFollowUps = value;
                _visable =
                    List<bool>.filled(_visablefollowUp!.length, false);
              }),

              // Navigator.pushReplacement(
              //     context,
              //     MaterialPageRoute(
              //         builder: (context) => Home(value))),
            }
          else
            {
              Navigator.pop(context),
              showInfoDialog(context, "لايوجد متابعات على الاشتراك"),
            }
        },
      ),
);

}

UI part where the user enters the sub or meter number

0

There are 0 best solutions below