This commit is contained in:
Artem Tsyrulnikov
2026-01-18 13:59:47 +03:00
parent d8202e1141
commit 62e8f98429
62 changed files with 156 additions and 190 deletions

View File

@@ -0,0 +1,175 @@
package ui
import (
"fmt"
"github.com/NicoNex/echotron/v3"
)
// PaginationConfig конфигурация для построения навигационного ряда пагинации
type PaginationConfig struct {
CurrentPage int
TotalPages int // Для API пагинации (из page.Pages)
TotalItems int // Для локальной пагинации (len(array))
ItemsPerPage int // Для расчета TotalPages из TotalItems
PrevCallback string // По умолчанию "prev"
NextCallback string // По умолчанию "next"
MiddleButtons []echotron.InlineKeyboardButton // Опциональные кнопки в центре (например, " Добавить")
}
// BuildNavigationRow создает навигационный ряд с динамической шириной.
// Показывает ряд только если страниц > 1.
// Возвращает nil если пагинация не нужна.
func BuildNavigationRow(config PaginationConfig) []echotron.InlineKeyboardButton {
// Вычисляем TotalPages из TotalItems если не задан
totalPages := config.TotalPages
if totalPages == 0 && config.TotalItems > 0 && config.ItemsPerPage > 0 {
totalPages = CalculatePages(config.TotalItems, config.ItemsPerPage)
}
// Устанавливаем значения по умолчанию для callbacks
prevCallback := config.PrevCallback
if prevCallback == "" {
prevCallback = "prev"
}
nextCallback := config.NextCallback
if nextCallback == "" {
nextCallback = "next"
}
var row []echotron.InlineKeyboardButton
// Левая стрелка (только если есть предыдущая страница)
if totalPages > 1 && config.CurrentPage > 0 {
row = append(row, echotron.InlineKeyboardButton{
Text: "←",
CallbackData: prevCallback,
})
}
// Средние кнопки (если есть)
if len(config.MiddleButtons) > 0 {
row = append(row, config.MiddleButtons...)
}
// Правая стрелка (только если есть следующая страница)
if totalPages > 1 && config.CurrentPage+1 < totalPages {
row = append(row, echotron.InlineKeyboardButton{
Text: "→",
CallbackData: nextCallback,
})
}
if len(row) == 0 {
return nil
}
return row
}
// CalculatePages вычисляет количество страниц из общего количества элементов
func CalculatePages(totalItems, itemsPerPage int) int {
if itemsPerPage <= 0 {
return 0
}
return (totalItems + itemsPerPage - 1) / itemsPerPage
}
// GetPageBounds возвращает start/end индексы для текущей страницы.
// Автоматически сбрасывает на первую страницу если currentPage выходит за границы.
func GetPageBounds(currentPage, itemsPerPage, totalItems int) (start, end int) {
start = currentPage * itemsPerPage
if start >= totalItems {
start = 0
}
end = start + itemsPerPage
if end > totalItems {
end = totalItems
}
return start, end
}
// FormatPageInfo форматирует текст индикатора страницы для заголовка
func FormatPageInfo(currentPage, totalPages int) string {
if totalPages <= 1 {
return ""
}
return fmt.Sprintf(" <i>(стр. %d/%d)</i>", currentPage+1, totalPages)
}
// ElementLayoutConfig конфигурация для автоматической раскладки элементов с пагинацией
type ElementLayoutConfig struct {
CurrentPage int // Текущая страница (0-indexed)
ItemsPerPage int // Элементов на странице
ItemsPerRow int // Элементов в одном ряду
EmptyButton *echotron.InlineKeyboardButton // Кнопка-заполнитель (опционально, по умолчанию " ")
}
// BuildElementRows автоматически раскладывает элементы с пагинацией.
// Принимает все элементы, возвращает ряды для текущей страницы с правильной раскладкой.
// Автоматически заполняет пустыми кнопками если страниц > 1 (для консистентности высоты).
// Возвращает 2D массив кнопок готовый к добавлению в клавиатуру.
//
// Пример использования:
//
// config := ui.ElementLayoutConfig{
// CurrentPage: 0,
// ItemsPerPage: 6,
// ItemsPerRow: 2,
// }
// rows := ui.BuildElementRows(config, allButtons)
// keyboard = append(keyboard, rows...)
func BuildElementRows(config ElementLayoutConfig, allItems []echotron.InlineKeyboardButton) [][]echotron.InlineKeyboardButton {
if len(allItems) == 0 {
return nil
}
// Параметры по умолчанию
if config.ItemsPerPage <= 0 {
config.ItemsPerPage = 6
}
if config.ItemsPerRow <= 0 {
config.ItemsPerRow = 2
}
// Кнопка-заполнитель по умолчанию
emptyButton := echotron.InlineKeyboardButton{Text: " ", CallbackData: "empty"}
if config.EmptyButton != nil {
emptyButton = *config.EmptyButton
}
// Вычисляем границы страницы
totalPages := CalculatePages(len(allItems), config.ItemsPerPage)
start, end := GetPageBounds(config.CurrentPage, config.ItemsPerPage, len(allItems))
// Получаем элементы текущей страницы
pageItems := allItems[start:end]
// Если страниц >= 2, заполняем до ItemsPerPage пустыми кнопками
// Это обеспечивает одинаковую высоту клавиатуры на всех страницах
if totalPages >= 2 {
for len(pageItems) < config.ItemsPerPage {
pageItems = append(pageItems, emptyButton)
}
}
// Раскладываем элементы по рядам
var rows [][]echotron.InlineKeyboardButton
for i := 0; i < len(pageItems); i += config.ItemsPerRow {
var row []echotron.InlineKeyboardButton
// Добавляем элементы в ряд
for j := 0; j < config.ItemsPerRow && i+j < len(pageItems); j++ {
row = append(row, pageItems[i+j])
}
// Если в ряду меньше элементов чем ItemsPerRow, заполняем пустыми
for len(row) < config.ItemsPerRow {
row = append(row, emptyButton)
}
rows = append(rows, row)
}
return rows
}