vedartm / paginate_firestore

A flutter package to simplify pagination with firestore data 🗃
https://pub.dev/packages/paginate_firestore
MIT License
113 stars 136 forks source link

Feature Request/Bug: Initial Index #74

Closed jslattery26 closed 3 years ago

jslattery26 commented 3 years ago

Is it possible to have an initial index? For ex. I have a list of docs, but In my application I'm not always starting at 0. The user can actually click a certain object to start the list at any index.

So If I have the itemsPerPage set to 10. and the user clicks the item at index 12. The list scrolls to 12 at first and then bounces back up to 10 because its the documentsLoaded limit. I'm assuming it's due to the bottom loader interfering.

Thanks

vedartm commented 3 years ago

Hi @jslattery26, thanks for using the package. I guess you talking about two things here.

  1. An initial index where items can be displayed from nth index.
  2. Scrolling to a position of index which is not loaded yet.

If that's the case. Can you also share some code snippet to get a better understanding of your issue.

jslattery26 commented 3 years ago

I actually modified the paginate_firestore package to include PreloadPageViews. Which I was considering making a pull request for if I can make it more generic. However this happens when using a listview as well and scrolling the scroll controller to a specific position.

Here is what I added to "paginate_firestore.dart"

Widget _buildPageView(PaginationLoaded loadedState) {
    var pageView = CustomScrollView(
      reverse: widget.reverse,
      shrinkWrap: widget.shrinkWrap,
      controller: widget.scrollController,
      scrollDirection: widget.scrollDirection,
      physics: widget.physics,
      slivers: <Widget>[
        if (widget.header != null) SliverToBoxAdapter(child: widget.header),
        SliverPadding(
          padding: widget.padding,
          sliver: SliverToBoxAdapter(
            child: Container(
              width: MediaQuery.of(context).size.width,
              height: MediaQuery.of(context).size.height / 1.2,
              child: PreloadPageView.custom(
                scrollDirection: Axis.vertical,
                controller: widget.pageController,
                childrenDelegate: SliverChildBuilderDelegate(
                  (context, index) {
                    if (index >= loadedState.documentSnapshots.length) {
                      _cubit!.fetchPaginatedList();
                      return widget.bottomLoader;
                    }
                    return widget.itemBuilder(
                        index, context, loadedState.documentSnapshots[index]);
                  },
                  childCount: loadedState.hasReachedEnd
                      ? loadedState.documentSnapshots.length
                      : loadedState.documentSnapshots.length + 1,
                ),
              ),
            ),
          ),
        ),
        if (widget.footer != null) SliverToBoxAdapter(child: widget.footer),
      ],
    );

    if (widget.listeners != null && widget.listeners!.isNotEmpty) {
      return MultiProvider(
        providers: widget.listeners!
            .map((_listener) => ChangeNotifierProvider(
                  create: (context) => _listener,
                ))
            .toList(),
        child: pageView,
      );
    }

    return pageView;
  }
}

enum PaginateBuilderType { listView, gridView, pageView }

This is where I call PaginateFirestore. It gets initialized with an index and the pageController starts at that index. That's where if its > documentsLoaded it keeps bouncing up.

class ProfileFeed extends StatefulWidget {
  int index;
  String userUid;
  ProfileFeed(this.index, this.userUid);

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

class _ProfileFeedState extends State<ProfileFeed> {
  late PreloadPageController pageController;
  late DocumentSnapshot initialDocument;
  @override
  void initState() {
    pageController = PreloadPageController(initialPage: widget.index);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return PaginateFirestore(
      itemsPerPage: 5,
      onLoaded: (PaginationLoaded) {
        print('Loaded');
      },
      itemBuilderType: PaginateBuilderType.pageView,
      pageController: pageController,
      emptyDisplay:
          const Center(child: Text('No posts..')),
      onError: (dynamic error) => Center(
        child: Text('Some error occured'),
      ),
      bottomLoader: Center(
        // optional
        child: CircularProgressIndicator(),
      ),
      itemBuilder: (index, context, documentSnapshot) {
        var post = Post.fromFirestore(
            documentSnapshot as DocumentSnapshot<Map<String, dynamic>>);
        return PostView(post);
      },
      isLive: true,
      // orderBy is compulsary to enable pagination
      query: FirebaseFirestore.instance
          .collection('posts')
          .where('ownerUid', isEqualTo: FirebaseAuth.instance.currentUser?.uid)
          .orderBy('dateAdded', descending: true),
    );
  }
}

If you're interested in me making a PR for the PreloadPageViews then let me know!

vedartm commented 3 years ago

@jslattery26 Feel free to make a PR. I will review it and merge it if everything works as intended.

jslattery26 commented 3 years ago

@excogitatr I definitely will. So do you have any ideas for the index?

vedartm commented 3 years ago

@excogitatr I definitely will. So do you have any ideas for the index?

Do you mean setting an initial index? I think it's easier to understand it with PR. Let's communicate and optimize things over there.