EdsonBueno / infinite_scroll_pagination

Flutter package to help you lazily load and display pages of items as the user scrolls down your screen.
https://pub.dev/packages/infinite_scroll_pagination
MIT License
632 stars 214 forks source link

Initial Listener not calling #170

Closed TouseefAQ closed 4 months ago

TouseefAQ commented 2 years ago

Initalially addPageRequestListener is not calling. I am using provider to fetch and store list and then pass this list to PagingState. But even this print statement is not printing when widget Builds for first time. But if pass controller as it to PagedListView addPageRequestListener calls and fetch data is As below

 @override
  void initState() {
    print("INIT");

    _pagingController.addPageRequestListener((pageKey) {
      print("ADD LISTNERS CALLING");
      _fetchPage(pageKey);
    });
    super.initState();
  }

Future<void> _fetchPage(int pageKey) async {
    try {
      Provider.of<FlirtProvider>(context, listen: false).fetchPage(pageKey,
          Provider.of<UserProvider>(context, listen: false).getAuthToken);
    } catch (error) {
      print(error);
      _pagingController.error = error;
    }
  }

PagedListView.separated(
          separatorBuilder: (context, index) {
            return Padding(
              padding: EdgeInsets.symmetric(horizontal: 2.w),
              child: Divider(
                color: AppColors.circleBorderGrey,
                thickness: 0.02.h,
              ),
            );
          },
          padding: const EdgeInsets.only(top: 10),
          pagingController:  _pagingController
            ..value = PagingState(
              nextPageKey: Provider.of<FlirtProvider>(context).nextPageAfter,
              itemList: Provider.of<FlirtProvider>(context).flirtsSend,
            ),
          builderDelegate: PagedChildBuilderDelegate<FlirtedData>(
              itemBuilder: (context, flirt, index) => ListTile(
                    onTap: () {
                      if (widget.flirtItemType == FlirtItemType.flirtReceived ||
                          widget.flirtItemType == FlirtItemType.matched) {
                        Navigator.of(context)
                            .pushNamed(FlirtCardView.routeName);
                      } else if (widget.flirtItemType ==
                          FlirtItemType.flirtSent) {
                        ///VIEW USER PROFILE WHOM I HAVE SENT FLIRT
                        Provider.of<LoadedUserProvider>(context, listen: false)
                            .fetchUser(
                                flirt.flirtedUser!.userDetails!.userId as int,
                                Provider.of<UserProvider>(context,
                                        listen: false)
                                    .getAuthToken);
                        Navigator.of(context).pushNamed(
                            AboutUserScreen.routeName,
                            arguments: flirt.flirtedUser!.username);
                      }
                    },
                    title: Text(
                      "${flirt.flirtedUser!.username}",
                      style: Theme.of(context).textTheme.bodyText1,
                    ),
                    leading: StackedCircleAvatar(
                      onlineStatus: false,
                      imageUrl: LogicHelper.getPhotoUrl(
                          flirt.flirtedUser!.userDetails!.photo),
                    ),
                  )),
        )

My Provider Class

 Future<void> fetchPage(int pageKey, String token) async {
    try {
      GenericModel genericModel = await FlirtService.getSendFlirtList(
        token: token,
      );
      if (genericModel.statusCode == 200) {
        print("FLIRTSS");
        FlirtResponse flirtResponse = genericModel.returnModel as FlirtResponse;
        print(flirtResponse.data!.sentFlirts!.path);
        flirtsSend.addAll(flirtResponse.data!.sentFlirts!.data ?? []);
        nextPageAfter++;
        notifyListeners();
      } else if (genericModel.statusCode == 400) {
        GetXDialog.showDialog(
            backgroundColor: AppColors.offwhite,
            textColor: AppColors.mainRed,
            title: genericModel.title,
            message: genericModel.message);
      }
    } catch (error) {
      print(error);
    }
  }
sharukh967 commented 2 years ago

Having same issue

andrezanna commented 2 years ago

I "solved" this part of not loading but now I have another issue where it loads the page in a weird way

This is my pagedList

class NewSearchPage extends StatefulWidget {
  const NewSearchPage({Key key}) : super(key: key);

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

class _NewSearchPageState extends State<NewSearchPage> {
  bool _isInit = false;

  PagingController<int, PostModel> _pagingController =
  PagingController(firstPageKey: 0);

  @override
  void didChangeDependencies() {
    if (_isInit == false) {
      _initPagination();
      _isInit = true;
    }
    super.didChangeDependencies();
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        elevation: 0,
        backgroundColor: Colors.transparent,
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Consumer<PostProvider>(
            builder: (context, provider, child) {
              return PagedListView(
                pagingController: _pagingController..value=provider.getPaging(_pagingController.nextPageKey),
                builderDelegate: PagedChildBuilderDelegate(
                  noItemsFoundIndicatorBuilder: (context) {
                    return EmptyPostsWidget();
                  },
                  itemBuilder: (context, item, index) {
                    return PostWidget(
                      post: provider.postList[index],
                      widgetRoute: (){},
                      onHide: () {
                        provider.delAt(index);
                      },
                    );
                  },
                ),
              );
            },
          )
        ),
      ),
    );
  }

  void _initPagination() async{
    _pagingController.nextPageKey=0;

    _pagingController.addPageRequestListener((pageKey) async{
      print(pageKey);
      var newPosts=await getPosts(offset: pageKey);
      _pagingController.nextPageKey+=5;

      Provider.of<PostProvider>(context,listen: false).addAll(newPosts);
      setState(() {

      });
    });
  }

}

And this my provider

class PostProvider with ChangeNotifier{
  List<PostModel> postList=[];

  PagingState<int, PostModel> getPaging(nextPageKey) {
    return PagingState(nextPageKey:nextPageKey,itemList:postList.isNotEmpty?postList:null);
  }

  add(PostModel post) {
    postList.add(post);
    notifyListeners();
  }

  addAll(List<PostModel> posts){
    postList.addAll(posts);
  }

  del(PostModel post){
    postList.remove(post);
    notifyListeners();
  }

  delAt(int index) {
    postList.removeAt(index);
    notifyListeners();
  }

}

From what I understood the pagingState returned by the provider must be null initially to make it load, and I must get values from provider.list.indexAt instead of the items from the pagingController.

The issue i now have is strange nextPageKey value, as i get initially 0, then 5, then 0 again and then no more. This loads everything in the initialMoment and then fails to call the server for new updates.

andrezanna commented 2 years ago

@EdsonBueno can you please let us know something?

abigotado commented 2 years ago

I have the same problem. I use Riverpod for state management.

@override
  void initState() {
    super.initState();
    debugPrint('here');

    _pagingController.addPageRequestListener((final int pageKey) async {
      debugPrint('pageKey = $pageKey');
      await ref
          .read(directionsControllerProvider(widget.id).notifier)
          .loadList(pageKey);
    });
  }
ref.listen<PaginationState<StudyDirectionModel>>(
        directionsControllerProvider(widget.id), (
      final PaginationState<StudyDirectionModel>? previousState,
      final PaginationState<StudyDirectionModel> state,
    ) {
      _pagingController.value = PagingState(
        nextPageKey: state.nextPageKey,
        itemList: state.itemList,
        error: state.error,
      );

addPageRequestListener is never called

tungakanui commented 2 years ago

Any update on this? I have the same issue here with Bloc

AbedElazizShe commented 1 year ago

I had the same problem, I was returning a progress indicator that prevented the PagedListView to be called. Ensure it is called for the listener to work.

ghost commented 1 year ago

I've noticed that invoking _pagingController.value at initial rendering prevents the listener from being called the first time. The problem doesn't arise when using the append methods, which is a bummer because append can't deal with a lot of cases.

AbikMathew commented 1 year ago

I'm also facing the same issue!

prasant10050 commented 1 year ago

I'm also facing the same issue

ChangJoo-Park commented 1 year ago

+1 here.

clragon commented 4 months ago

The original code in this issue,

          pagingController:  _pagingController
            ..value = PagingState(
              nextPageKey: Provider.of<FlirtProvider>(context).nextPageAfter,
              itemList: Provider.of<FlirtProvider>(context).flirtsSend,
            ),

contains a dangerous operation inside the build method that not only triggers rebuilds inside the build method, but also prevents the controller from ever calling the listener initially, since its itemlist is set to a non-null value.

If you encounter an issue similar to this, please open a new issue.