Bani Akram
Bani Akram

Reputation: 361

Pull to refresh in Flutter doesn't invoke onLoading function unless I switch page and come back

I am using a smart refresher for pagination in Flutter. It calls the below function to get data from the API on the basis of start and end date.

Whenever the smart refresher calls this function, it gives the right data the first time (with initial start and end date), but when I change the dates, it fetches new data accordingly but now when I pull it again to fetch more data, it doesn't even recognise that pull action as a valid action and nothing happens.

Unless I switch to another screen and come back, it works as expected.

If you need more info or code segments, I'll gladly provide them.

// THIS IS THE FUNCTION CALLED IN SMART REFRESHER in init() isFirst = true otherwise its false

Future<void> fetchAnalytics({required bool isFirst}) async {
  if (isFirst == true) {
    analyticsLoadingFirst(true);
    analyticsPage.value = 1;
    analyticsTotalPage.value = 0;
    analyticsList.clear();
  } else {
    analyticsLoading(true);
  }
  analytics.value = await RemoteServices.getStatsAnalytics(
    token: Constants.token!,
start: DateFormat('yyyy-MM-dd'). format(analyticsStartDate.value),
end: DateFormat('yyyy-MM-dd'). format(analytiscEndDate.value),
    page: analyticsPage.value,
  );
  if (analytics.value.data!.data!.isNotEmpty) {
    analyticsList.value = analyticsList.value + analytics.value.data!.data!;
    analyticsPage.value += 1;
    analyticsTotalPage.value = analytics.value.data!.lastPage!;
  }
  isFirst == true ? analyticsLoadingFirst(false) : analyticsLoading(false);
}

// THIS IS THE TAB

    class AnalyticsStatsScreen extends StatefulWidget {
      const AnalyticsStatsScreen({Key? key}) : super(key: key);
    
      @override
      State<AnalyticsStatsScreen> createState() => _AnalyticsStatsScreenState();
    }
    
    class _AnalyticsStatsScreenState extends State<AnalyticsStatsScreen> with TickerProviderStateMixin {
      final statsController = Get.find<StatsController>();
      late AnimationController animationController;
      late AnimationController animationController2;
      RefreshController paginateController = RefreshController();
      ScrollController? _scroll;
    
      @override
      void initState() {
        super.initState();
        _scroll = ScrollController();
        animationController = AnimationController(vsync: this);
        animationController2 = AnimationController(vsync: this);
      }
    
      @override
      void setState(VoidCallback fn) {
        if (mounted) super.setState(fn);
      }
    
      @override
      void dispose() {
        animationController.dispose();
        animationController2.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Obx(
          () => statsController.analyticsLoadingFirst.isTrue
              ? Center(
                  child: AlertWidgets.IULoading(animationController1: animationController, animationController2: animationController2),
                )
              : statsController.analytics.value.data == null
                  ? LoadingError().notFoundWidget()
                  : Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        SizedBox(height: 12.h),
    
                        /// ****** Today Calendar Button ******
                        GestureDetector(
                          onTap: () {
                            Get.defaultDialog(
                              title: "Select a range",
                              titlePadding: EdgeInsets.only(top: 16.h),
                              titleStyle: TextStyle(fontSize: 18.sp),
                              contentPadding: EdgeInsets.zero,
                              content: SizedBox(
                                // width: 0.5.sw,
                                // height: 0.65.sw,
                                width: 0.75.sw,
                                height: 0.75.sw,
                                child: SfDateRangePicker(
                                  onSelectionChanged: _onChange,
                                  onSubmit: (value) {
                                    Get.back();
                                    statsController.analyticsPage.value = 1;
                                    statsController.analyticsTotalPage.value = 0;
                                    _scrollUp();
                                    statsController.fetchAnalytics(isFirst: true);
                                  },
                                  onCancel: () {
                                    Get.back();
                                  },
                                  headerStyle: DateRangePickerHeaderStyle(
                                    textStyle: ThemeStyles.NormalLight,
                                  ),
                                  selectionMode: DateRangePickerSelectionMode.range,
                                  maxDate: DateTime.now(),
                                  showActionButtons: true,
                                  headerHeight: 50.h,
                                  rangeTextStyle: ThemeStyles.NormalLight,
                                  selectionTextStyle: ThemeStyles.NormalLight.copyWith(color: Constants.TextWhite),
                                  initialSelectedRange: PickerDateRange(statsController.startDate.value, statsController.endDate.value
                                      // DateTime.now(),
                                      // DateTime.now()
                                      //     .subtract(Duration(days: 7)),
                                      ),
                                ),
                              ),
                            );
                          },
                          child: Container(
                            width: Get.width,
                            height: 0.06.sh,
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(4.r),
                              border: Border.all(color: Constants.TextBlack),
                            ),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                SvgPicture.asset(
                                  Constants.calender,
                                  width: 22.w,
                                  height: 22.w,
                                ),
                                SizedBox(width: 12.w),
                                Text(
                                  'Today',
                                  style: ThemeStyles.NormalBold,
                                ),
                              ],
                            ),
                          ),
                        ),
    
                        Expanded(
                          child: ExcludeSemantics(
                            child: Obx(
                              () => SmartRefresher(
                                // scrollController: _scroll,
                                controller: paginateController,
                                enablePullUp: true,
                                enablePullDown: false,
                                onLoading: () async {
                                  print("total page loading => ${statsController.analyticsTotalPage.value}");
                                  print("current page loading => ${statsController.analyticsPage.value}");
                                  if (statsController.analyticsTotalPage.value >= statsController.analyticsPage.value) {
                                    await statsController.fetchAnalytics(isFirst: false);
                                    if (statsController.analyticsLoading.isFalse) {
                                      paginateController.loadComplete();
                                    } else {
                                      paginateController.loadFailed();
                                    }
                                  } else {
                                    paginateController.loadNoData();
                                  }
                                },
                                child: ListView.builder(
                                  controller: _scroll,
                                  shrinkWrap: true,
                                  padding: EdgeInsets.zero,
                                  physics: const BouncingScrollPhysics(),
                                  itemCount: statsController.analyticsList.length,
                                  itemBuilder: (ctx, index) {
                                    // int count = index + 1;
                                    var item = statsController.analyticsList[index];
                                    return productCard(analyticsDatum: item, index: index);
                                  },
                                ),
                              ),
                            ),
                          ),
                        ),
                        SizedBox(height: 12.h),
                      ],
                    ),
        );
      }
    
      // ***** Paid Summary *****
      Widget productCard({required AnalyticsDatum analyticsDatum, int? index}) {
        // double netSales = saleDatum.amount! - (saleDatum.discount! + saleDatum.tax!) - saleDatum.refundAmount!;
        return Padding(
          padding: EdgeInsets.only(top: 12.h),
          child: Container(
            width: Get.width,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(8.r),
              color: Constants.BackgroundSecondary,
            ),
            padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 8.w),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Row(
                  children: [
                    SizedBox(
                      width: Get.width > 600 ? 10.w : 16.w,
                      height: Get.width > 600 ? 15.h : 16.h,
                      child: SvgPicture.asset(
                        Constants.analytic,
                        // color: Colors.black,
                        // size: 30.w,
                      ),
                    ),
                    SizedBox(width: 8.w),
                    Flexible(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          SizedBox(
                            width: Get.width * 0.55,
                            child: Text(
                              analyticsDatum.productTitle.toString(),
                              style: ThemeStyles.NormalLightW600,
                              maxLines: 2,
                              overflow: TextOverflow.ellipsis,
                            ),
                          ),
                          Text(
                            "${analyticsDatum.counts} Views",
                            style: ThemeStyles.NormalLightW600,
                            maxLines: 2,
                            overflow: TextOverflow.ellipsis,
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        );
      }
    
      void _onChange(DateRangePickerSelectionChangedArgs args) {
        print("DateRangePickerSelectionChangedArgs = ${args.value.startDate}");
        if (args.value is PickerDateRange) {
          statsController.analyticsStartDate.value = args.value.startDate;
          statsController.analytiscEndDate.value = args.value.endDate ?? args.value.startDate;
        }
      }
    
      void _scrollUp() {
        if (_scroll!.hasClients){
          _scroll!.jumpTo(_scroll!.position.minScrollExtent);
        }
      }
    }

// THIS IS THE CONTROLLER BEING FOUND AT THE START OF THE TAB

class StatsController extends GetxController {
  var startDate = DateTime.now().subtract(Duration(days: 6)).obs;
  var endDate = DateTime.now().obs;
  var analyticsStartDate = DateTime.now().subtract(Duration(days: 6)).obs;
  var analytiscEndDate = DateTime.now().obs;
  var analyticsLoadingFirst = false.obs;
  var analyticsLoading = false.obs;
  var analytics = AnalyticsModel().obs;
  var analyticsList = <AnalyticsDatum>[].obs;

  // ******** Analytics *******
  Future<void> fetchAnalytics({required bool isFirst}) async {
    if (isFirst == true) {
      analyticsLoadingFirst(true);
      analyticsPage.value = 1;
      analyticsTotalPage.value = 0;
      analyticsList.clear();
    } else {
      analyticsLoading(true);
    }
    analytics.value = await RemoteServices.getStatsAnalytics(
      token: Constants.token!,
      start: DateFormat('yyyy-MM-dd').format(analyticsStartDate.value),
      end: DateFormat('yyyy-MM-dd').format(analytiscEndDate.value),
      page: analyticsPage.value,
    );
    if (analytics.value.data!.data!.isNotEmpty) {
      analyticsList.value = analyticsList.value + analytics.value.data!.data!;
      analyticsPage.value += 1;
      analyticsTotalPage.value = analytics.value.data!.lastPage!;
    }
    isFirst == true ? analyticsLoadingFirst(false) : analyticsLoading(false);
  }

  @override
  void onInit() {
    fetchAnalytics(isFirst: true);
    super.onInit();
  }

  @override
  void onClose() {
    startDate.value = DateTime.now().subtract(Duration(days: 7));
    endDate.value = DateTime.now();
    super.onClose();
  }
}

I've tried to look it up in the docs of pull to refresh but found nothing

Upvotes: 2

Views: 1007

Answers (1)

Israr
Israr

Reputation: 314

You may have loaded all the data and called the refreshController.loadNoData() function.

Once you call the refreshController.loadNoData() then onLoading function will not be invoked by the time you call the refreshController.resetNoData().

In short, to get rid of this issue just call the refreshController.resetNoData() in onRefresh function.

Upvotes: 2

Related Questions