paginationRange function

List<int?> paginationRange({
  1. required int currentPage,
  2. required int pageCount,
  3. int siblingCount = 1,
  4. int boundaryCount = 1,
})

Sequência de páginas a exibir, com reticências (null) nas lacunas.

Ex.: paginationRange(currentPage: 6, pageCount: 20)[1, null, 5, 6, 7, null, 20]. Uma lacuna de exatamente uma página vira a própria página (nunca esconde uma só atrás de reticências). Função pura → testável isoladamente.

Implementation

List<int?> paginationRange({
  required int currentPage,
  required int pageCount,
  int siblingCount = 1,
  int boundaryCount = 1,
}) {
  if (pageCount <= 0) return const <int?>[];

  // Se todas as páginas cabem sem economia de espaço, mostra todas (sem
  // reticências).
  final int maxWithEllipsis = boundaryCount * 2 + siblingCount * 2 + 5;
  if (pageCount <= maxWithEllipsis) {
    return <int?>[for (int i = 1; i <= pageCount; i++) i];
  }

  final Set<int> pages = <int>{};
  for (int i = 1; i <= boundaryCount && i <= pageCount; i++) {
    pages.add(i);
  }
  for (int i = pageCount - boundaryCount + 1; i <= pageCount; i++) {
    if (i >= 1) pages.add(i);
  }
  final int lo = (currentPage - siblingCount).clamp(1, pageCount);
  final int hi = (currentPage + siblingCount).clamp(1, pageCount);
  for (int i = lo; i <= hi; i++) {
    pages.add(i);
  }

  final List<int> sorted = pages.toList()..sort();
  final List<int?> items = <int?>[];
  int? previous;
  for (final int page in sorted) {
    if (previous != null) {
      if (page - previous == 2) {
        items.add(previous + 1); // lacuna de 1 → mostra a página
      } else if (page - previous > 2) {
        items.add(null); // reticências
      }
    }
    items.add(page);
    previous = page;
  }
  return items;
}