buildListView<T, K> method

Widget buildListView<T, K>({
  1. required BuildContext context,
  2. required List<TListItem<T, K>> items,
  3. required ListItemBuilder<T, K> itemBuilder,
  4. required AnimationController animationController,
  5. required ScrollController scrollController,
  6. required ScrollController horizontalScrollController,
  7. required TListController<T, K> listController,
  8. required bool loading,
  9. required bool hasError,
  10. required TListError? error,
  11. required bool hasMoreItems,
  12. double? height,
})

Implementation

Widget buildListView<T, K>({
  required BuildContext context,
  required List<TListItem<T, K>> items,
  required ListItemBuilder<T, K> itemBuilder,
  required AnimationController animationController,
  required ScrollController scrollController,
  required ScrollController horizontalScrollController,
  required TListController<T, K> listController,
  required bool loading,
  required bool hasError,
  required TListError? error,
  required bool hasMoreItems,
  double? height,
}) {
  final effectiveInfiniteScroll = infiniteScroll == true && listController.hasMoreItems;

  // Determine if we should show error/empty as a list item
  final showErrorItem = hasError && error != null;
  final showEmptyItem = !loading && items.isEmpty && !showErrorItem;

  // Adjust item count for error/empty
  final itemCountForList = (showErrorItem || showEmptyItem) ? 1 : items.length;

  Widget buildItem(BuildContext context, int index) {
    // Header (non-sticky)
    if (headerWidget != null && headerSticky != true && index == 0) {
      return headerWidget!;
    }

    // Calculate item index offset
    final itemOffset = (headerWidget != null && headerSticky != true) ? 1 : 0;
    final itemIndex = index - itemOffset;

    // Infinite scroll indicator
    final infiniteScrollIndex = itemCountForList + itemOffset;
    if (effectiveInfiniteScroll && index == infiniteScrollIndex) {
      return _buildInfiniteScrollFooter(context, items, loading, hasMoreItems);
    }

    // Footer (non-sticky)
    final footerIndex = itemCountForList + itemOffset + (effectiveInfiniteScroll ? 1 : 0);
    if (footerWidget != null && footerSticky != true && index == footerIndex) {
      return footerWidget!;
    }

    // Error or empty state as list item
    if (showErrorItem) {
      return buildErrorState(context, error);
    }
    if (showEmptyItem) {
      return buildEmptyState(context);
    }

    // Regular item
    final item = items[itemIndex];
    Widget child = itemBuilder(context, item, itemIndex, listController.isMultiSelect);

    // Apply animation
    if (animationBuilder != null) {
      child = animationBuilder!(context, animationController, child, itemIndex);
    }

    // Add spacing
    if (itemSpacing > 0) {
      child = Padding(
        padding: EdgeInsets.only(bottom: itemSpacing),
        child: child,
      );
    }

    return child;
  }

  final totalItemCount = itemCountForList +
      (headerWidget != null && headerSticky != true ? 1 : 0) +
      (footerWidget != null && footerSticky != true ? 1 : 0) +
      (effectiveInfiniteScroll ? 1 : 0);

  final effectivePhysics = physics ?? (shrinkWrap ? const NeverScrollableScrollPhysics() : const AlwaysScrollableScrollPhysics());

  Widget listView;

  if (showSeparators && separatorBuilder != null) {
    listView = ListView.separated(
      controller: shrinkWrap ? null : scrollController,
      shrinkWrap: shrinkWrap,
      physics: effectivePhysics,
      padding: padding,
      itemCount: totalItemCount,
      itemBuilder: buildItem,
      separatorBuilder: separatorBuilder!,
    );
  } else {
    listView = ListView.builder(
      controller: shrinkWrap ? null : scrollController,
      shrinkWrap: shrinkWrap,
      physics: effectivePhysics,
      padding: padding,
      itemCount: totalItemCount,
      itemBuilder: buildItem,
    );
  }

  // Build column with sticky elements
  final column = Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      if (loading && items.isEmpty) buildLoadingIndicator(context),
      if (headerWidget != null && headerSticky == true) headerWidget!,
      if (shrinkWrap) listView else if (height != null) SizedBox(height: height, child: listView) else Expanded(child: listView),
      if (footerWidget != null && footerSticky == true) footerWidget!,
    ],
  );

  // Wrap with horizontal scroll if needed
  final scrollableContent = needsHorizontalScroll ? _buildHorizontalScroll(column, horizontalScrollController) : column;

  return scrollableContent;
}