paginationCustomScrollViewTemplate function

String paginationCustomScrollViewTemplate(
  1. String paginationControllerPath
)

Implementation

String paginationCustomScrollViewTemplate(String paginationControllerPath) {
  return """
${ProjectUtils.fileGenerationString}

import 'package:${ProjectUtils.getProjectName()}$paginationControllerPath';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class PagingCustomScrollView<T> extends StatefulWidget {
  final PaginationController<T> controller;
  final Widget Function(BuildContext context, T item, int index) itemBuilder;
  final Widget? separatorWidget;
  final Widget? emptyListWidget;
  final Widget? noInternetWidget;
  final Widget? apiFailedWidget;
  final Widget Function(VoidCallback onPressed)? retryButtonWidget;
  final Widget? loadingWidget;
  final bool shrinkWrap;
  final bool isPaginated;
  final double? cacheExtent;
  final Axis scrollDirection;
  final List<Widget> slivers;
  final Future<dynamic> Function()? onRefreshCallback;

  const PagingCustomScrollView({
    super.key,
    required this.controller,
    required this.itemBuilder,
    this.separatorWidget,
    this.emptyListWidget,
    this.apiFailedWidget,
    this.noInternetWidget,
    this.retryButtonWidget,
    this.loadingWidget,
    this.shrinkWrap = false,
    this.isPaginated = true,
    this.cacheExtent,
    this.scrollDirection = Axis.vertical,
    this.slivers = const [],
    this.onRefreshCallback,
  });

  @override
  State<PagingCustomScrollView<T>> createState() => _PagingCustomScrollViewState<T>();
}

class _PagingCustomScrollViewState<T> extends State<PagingCustomScrollView<T>> {
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    widget.controller.isPaginated = widget.isPaginated;
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _scrollController.addListener(_onScroll);
      widget.controller.addListener(_onUpdate);
      loadPage();
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    widget.controller.removeListener(_onUpdate);
    super.dispose();
  }

  void loadPage() async {
    widget.controller.loadNextPage().then((value) {
      WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
        if (_scrollController.hasClients &&
            _scrollController.position.maxScrollExtent <= 0 &&
            widget.controller.hasMore &&
            widget.isPaginated &&
            widget.controller.apiStatus == ApiStatus.success) {
          loadPage();
        }
      });
    });
  }

  void _onScroll() {
    if (!widget.isPaginated) return;

    if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200 &&
        widget.controller.hasMore) {
      widget.controller.loadNextPage();
    }
  }

  void _onUpdate() {
    if (mounted) {
      setState(() {
        if (kDebugMode) {
          print("kDebugMode");
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return RefreshIndicator(
      onRefresh: widget.onRefreshCallback ??
          () async {
            await widget.controller.refresh();
          },
      child: CustomScrollView(
        physics: AlwaysScrollableScrollPhysics(),
        scrollDirection: widget.scrollDirection,
        shrinkWrap: widget.shrinkWrap,
        controller: _scrollController,
        clipBehavior: Clip.hardEdge,
        cacheExtent: widget.cacheExtent,
        slivers: [
          ...widget.slivers,
          if (widget.controller.list.isNotEmpty) ...{
            SliverList.separated(
              itemCount: widget.controller.list.length + (widget.controller.hasMore ? 1 : 0),
              separatorBuilder: (context, index) {
                if (index < widget.controller.list.length) {
                  return widget.separatorWidget ?? SizedBox(height: 5, width: 5);
                } else {
                  return SizedBox.shrink();
                }
              },
              itemBuilder: (context, index) {
                if (index < widget.controller.list.length) {
                  final item = widget.controller.list[index];
                  return widget.itemBuilder(context, item, index);
                } else if (widget.controller.list.isNotEmpty &&
                    widget.controller.hasMore &&
                    widget.controller.apiStatus != ApiStatus.success) {
                  return Padding(
                    padding: EdgeInsets.all(20),
                    child: widget.retryButtonWidget?.call(() {
                          widget.controller.apiStatus = ApiStatus.success;
                          _onUpdate();
                          widget.controller.loadNextPage();
                        }) ??
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            IconButton(
                              onPressed: () {
                                widget.controller.apiStatus = ApiStatus.success;
                                _onUpdate();
                                widget.controller.loadNextPage();
                              },
                              icon: Icon(
                                Icons.refresh,
                              ),
                            ),
                          ],
                        ),
                  );
                } else {
                  return Padding(
                    padding: EdgeInsets.all(20),
                    child: widget.loadingWidget ?? Center(child: CircularProgressIndicator()),
                  );
                }
              },
            ),
          } else ...{
            SliverFillRemaining(
              hasScrollBody: false,
              child: widget.controller.isLoading
                  ? (widget.loadingWidget ?? Center(child: CircularProgressIndicator()))
                  : Center(child: noDataWidget()),
            ),
          },
        ],
      ),
    );
  }

  Widget noDataWidget() {
    if (widget.controller.apiStatus == ApiStatus.failed) {
      return widget.apiFailedWidget ??
          Column(
            spacing: 5,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(Icons.error_outline_rounded, size: 100),
              Text(
                "Something went wrong",
                style: TextStyle(fontSize: 20),
                textAlign: TextAlign.center,
              ),
            ],
          );
    } else if (widget.controller.apiStatus == ApiStatus.noInternet) {
      return widget.noInternetWidget ??
          Column(
            spacing: 5,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(Icons.signal_wifi_connected_no_internet_4_rounded, size: 100),
              Text(
                "No Internet",
                style: TextStyle(fontSize: 20),
                textAlign: TextAlign.center,
              ),
            ],
          );
    } else {
      return widget.emptyListWidget ??
          Column(
            spacing: 5,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(Icons.not_interested_sharp, size: 100),
              Text(
                "Not Found",
                style: TextStyle(fontSize: 20),
                textAlign: TextAlign.center,
              ),
            ],
          );
    }
  }
}

class FloatingSliverWidget extends SliverPersistentHeaderDelegate {
  final double minHeight;
  final double maxHeight;
  final Widget child;

  FloatingSliverWidget({
    required this.minHeight,
    required this.maxHeight,
    required this.child,
  });

  @override
  Widget build(
    BuildContext context,
    double shrinkOffset,
    bool overlapsContent,
  ) {
    return child;
  }

  @override
  double get maxExtent => maxHeight;

  @override
  double get minExtent => minHeight;

  @override
  bool shouldRebuild(FloatingSliverWidget oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight ||
        child != oldDelegate.child;
  }
}

""";
}