getPresentationWidgetsCustomListWidgetTemplate function

String getPresentationWidgetsCustomListWidgetTemplate(
  1. String projectName
)

Implementation

String getPresentationWidgetsCustomListWidgetTemplate(String projectName) {
  return '''
import 'package:flutter/material.dart';
import '../../core/theme/app_colors.dart';

class ListWidget extends StatelessWidget {
  final bool separator;
  final bool shrinkWrap;
  final int itemCount;
  final Widget? emptyChild;
  final ScrollPhysics? scrollPhysics;
  final Widget Function(BuildContext, int) itemBuilder;
  final ScrollController? scrollController;
  final bool? reverse;
  final Axis? scrollDirection;
  final EdgeInsets? padding;

  final bool isLoadingMore;
  final bool isShimmerLoading;
  final int shimmerItemCount;

  /// 🔥 NEW → Custom shimmer builder
  final Widget Function(BuildContext, int)? shimmerBuilder;

  const ListWidget({
    super.key,
    this.separator = false,
    this.shrinkWrap = true,
    this.itemCount = 0,
    this.emptyChild,
    this.scrollPhysics,
    this.scrollDirection,
    required this.itemBuilder,
    this.scrollController,
    this.reverse,
    this.padding,
    this.isLoadingMore = false,
    this.isShimmerLoading = false,
    this.shimmerItemCount = 6,
    this.shimmerBuilder,
  });

  @override
  Widget build(BuildContext context) {
    /// -------------------------
    /// Shimmer Loading
    /// -------------------------
    if (isShimmerLoading) {
      return ListView.builder(
        shrinkWrap: shrinkWrap,
        physics: const NeverScrollableScrollPhysics(),
        padding: padding ?? EdgeInsets.zero,
        itemCount: shimmerItemCount,
        itemBuilder: (context, index) {
          /// ✅ Use custom shimmer if provided
          if (shimmerBuilder != null) {
            return shimmerBuilder!(context, index);
          }

          /// fallback
          return const _ShimmerItem();
        },
      );
    }

    /// -------------------------
    /// Empty State
    /// -------------------------
    if (itemCount == 0) {
      return EmptyWidget(child: emptyChild);
    }

    final totalCount = isLoadingMore ? itemCount + 1 : itemCount;

    return separator == false
        ? ListView.builder(
      controller: scrollController,
      shrinkWrap: shrinkWrap,
      itemCount: totalCount,
      physics: scrollPhysics ?? const AlwaysScrollableScrollPhysics(),
      scrollDirection: scrollDirection ?? Axis.vertical,
      padding: padding ?? EdgeInsets.zero,
      reverse: reverse ?? false,
      itemBuilder: (context, index) {
        if (index >= itemCount) {
          return const _LoaderFooter();
        }
        return itemBuilder(context, index);
      },
    )
        : ListView.separated(
      controller: scrollController,
      shrinkWrap: shrinkWrap,
      itemCount: totalCount,
      physics: scrollPhysics ?? const AlwaysScrollableScrollPhysics(),
      scrollDirection: scrollDirection ?? Axis.vertical,
      padding: padding ?? EdgeInsets.zero,
      reverse: reverse ?? false,
      itemBuilder: (context, index) {
        if (index >= itemCount) {
          return const _LoaderFooter();
        }
        return itemBuilder(context, index);
      },
      separatorBuilder: (context, index) {
        if (index >= itemCount) return const SizedBox.shrink();
        return const Divider(height: 0.1, color: AppColors.borderColor);
      },
    );
  }
}

class GridWidget extends StatelessWidget {
  final int itemCount;
  final Widget Function(BuildContext, int) itemBuilder;
  final double childAspectRatio;
  final double crossAxisSpacing;
  final double mainAxisSpacing;
  final int? crossAxisCount;
  final EdgeInsets? padding;
  final ScrollController? scrollController;
  final ScrollPhysics? scrollPhysics;
  final bool shrinkWrap;
  final bool isLoadingMore;

  /// 🔥 NEW → shimmer support for grid
  final bool isShimmerLoading;
  final int shimmerItemCount;
  final Widget Function(BuildContext, int)? shimmerBuilder;

  const GridWidget({
    super.key,
    required this.itemCount,
    required this.itemBuilder,
    this.childAspectRatio = 1,
    this.crossAxisSpacing = 8,
    this.mainAxisSpacing = 8,
    this.crossAxisCount,
    this.padding,
    this.scrollController,
    this.scrollPhysics,
    this.shrinkWrap = true,
    this.isLoadingMore = false,
    this.isShimmerLoading = false,
    this.shimmerItemCount = 6,
    this.shimmerBuilder,
  });

  @override
  Widget build(BuildContext context) {
    /// -------------------------
    /// Shimmer Loading (GRID)
    /// -------------------------
    if (isShimmerLoading) {
      return GridView.builder(
        shrinkWrap: shrinkWrap,
        physics: const NeverScrollableScrollPhysics(),
        padding: padding ?? EdgeInsets.zero,
        itemCount: shimmerItemCount,
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount:
          crossAxisCount ??
              (MediaQuery.of(context).size.width ~/ 160).clamp(2, 6),
          crossAxisSpacing: crossAxisSpacing,
          mainAxisSpacing: mainAxisSpacing,
          childAspectRatio: childAspectRatio,
        ),
        itemBuilder: (context, index) {
          if (shimmerBuilder != null) {
            return shimmerBuilder!(context, index);
          }
          return const _ShimmerItem();
        },
      );
    }

    /// -------------------------
    /// Empty State
    /// -------------------------
    if (itemCount == 0) {
      return const EmptyWidget(message: "No data found");
    }

    final totalCount = isLoadingMore ? itemCount + 1 : itemCount;

    return GridView.builder(
      controller: scrollController,
      shrinkWrap: shrinkWrap,
      physics: scrollPhysics ?? const AlwaysScrollableScrollPhysics(),
      padding: padding ?? EdgeInsets.zero,
      itemCount: totalCount,
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount:
        crossAxisCount ??
            (MediaQuery.of(context).size.width ~/ 160).clamp(2, 6),
        crossAxisSpacing: crossAxisSpacing,
        mainAxisSpacing: mainAxisSpacing,
        childAspectRatio: childAspectRatio,
      ),
      itemBuilder: (context, index) {
        if (index >= itemCount) {
          return const _LoaderFooter();
        }
        return itemBuilder(context, index);
      },
    );
  }
}

/// -------------------------
/// Loader Footer Widget
/// -------------------------
class _LoaderFooter extends StatelessWidget {
  const _LoaderFooter();

  @override
  Widget build(BuildContext context) {
    return const Padding(
      padding: EdgeInsets.all(16.0),
      child: Center(
        child: CircularProgressIndicator(
          strokeWidth: 2,
          color: AppColors.primary,
        ),
      ),
    );
  }
}

/// -------------------------
/// Default Shimmer Item
/// -------------------------
class _ShimmerItem extends StatelessWidget {
  const _ShimmerItem();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
      child: Container(
        height: 80,
        decoration: BoxDecoration(
          color: Colors.grey.shade300,
          borderRadius: BorderRadius.circular(10),
        ),
      ),
    );
  }
}

/// -------------------------
/// Empty Widget
/// -------------------------
class EmptyWidget extends StatelessWidget {
  final String message;
  final IconData icon;
  final Widget? child;

  const EmptyWidget({
    super.key,
    this.message = "No items available",
    this.icon = Icons.inbox_outlined,
    this.child,
  });

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [child ?? Container()],
      ),
    );
  }
}''';
}