Reputation: 361
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
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