paginationCustomScrollViewTemplate function
String
paginationCustomScrollViewTemplate(
)
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;
}
}
""";
}