Как использовать подтверждение о доставке колбэка

Рейтинг: 1Ответов: 1Опубликовано: 14.02.2023

Делаю пагинацию страниц. При сценарии страница1-страница2-страница1-страница2 инлайн-кнопка на страницу2 во второй итерации не нажимается (нет никакого отклика). Если убрать подтверждение о доставке колбэка, вроде все получается корректно, но при быстром нажатии кнопок вылетает в ошибку. Помогите разобраться.

# обработчик команды "numbers"
@dp.message_handler(text='/numbers')
async def cmd_numbers_command(message: types.Message):
    closest_points = ('страница 1', 'страница 2', 'страница 3')
    page = 0
    count_page = len(closest_points)
    text = closest_points[page]
    # собрали клавиатуру
    markup = pro_inline(page, count_page, message.from_user.id)
    await message.answer(f"{text}", reply_markup=markup)

# коллбэк от инлайн кнопки
@dp.callback_query_handler(pages_callback.filter())
async def callbacks_num(call: types.CallbackQuery, callback_data: dict):
    # подтверждение о доставке колбэка
    await call.answer(cache_time=60)
    closest_points = ('страница 1', 'страница 2', 'страница 3')
    count_page = int(callback_data.get("count"))
    page = int(callback_data.get("page"))
    id_user = int(callback_data.get("id_user"))
    direction = callback_data.get("direction")
    if direction == "finish":
        await call.message.edit_reply_markup()
    else:
        markup = pro_inline(page, count_page, id_user)
        text = str(closest_points[page])
        await call.message.edit_text(f"{text}", reply_markup=markup)

файл keyboards.py

def pro_inline(page, count, id):
    btn1 = InlineKeyboardButton(text='<--', callback_data=f"pages:back:{page - 1}:{count}:{id}")
    btn2 = InlineKeyboardButton(text=f'{page + 1}' + '/' + f'{count}',
                                callback_data=f"pages:null:{page}:{count}:{id}")
    btn3 = InlineKeyboardButton(text='-->', callback_data=f"pages:next:{page + 1}:{count}:{id}")
    btn4 = InlineKeyboardButton(text='Отмена', callback_data=f"pages:finish:{page}:{count}:{id}")
    if page == 0:
        buttons = [[btn2, btn3], [btn4]]
    elif page == count - 1:
        buttons = [[btn1, btn2], [btn4]]
    else:
        buttons = [[btn1, btn2, btn3], [btn4]]
    kb = InlineKeyboardMarkup(inline_keyboard=buttons)
    return kb

файл callback_data.py

pages_callback = CallbackData("pages", "direction", "page", "count", "id_user")

Ответы

▲ 0

Проблема может возникать из-за того, что при быстром нажатии кнопок, вызываются несколько обработчиков коллбэков, и может произойти некоторое взаимодействие между ними, что приводит к неожиданным результатам.

Один из способов решения этой проблемы состоит в том, чтобы сделать кнопки неактивными во время обработки события коллбэка. Для этого можно использовать атрибут callback_data для хранения состояния кнопки, чтобы заблокировать ее повторное использование, пока обрабатывается текущее событие коллбэка.

пример кода, который может помочь:

# добавляем данные о состоянии кнопки в атрибут callback_data
btn1 = InlineKeyboardButton(text='<--', callback_data=f"pages:back:{page - 1}:{count}:{id}:inactive")
btn2 = InlineKeyboardButton(text=f'{page + 1}' + '/' + f'{count}',
                            callback_data=f"pages:null:{page}:{count}:{id}:inactive")
btn3 = InlineKeyboardButton(text='-->', callback_data=f"pages:next:{page + 1}:{count}:{id}:inactive")
btn4 = InlineKeyboardButton(text='Отмена', callback_data=f"pages:finish:{page}:{count}:{id}:inactive")

# колбэк для обработки кнопок с атрибутом "inactive"
@dp.callback_query_handler(lambda c: c.data and c.data.endswith(":inactive"))
async def inactive_callback_handler(call: CallbackQuery):
    await call.answer(text="Кнопка заблокирована", show_alert=True)

# коллбэк для обработки активных кнопок
@dp.callback_query_handler(pages_callback.filter())
async def callbacks_num(call: types.CallbackQuery, callback_data: dict):
    # подтверждение о доставке колбэка
    await call.answer(cache_time=60)

    # извлекаем состояние кнопки
    button_state = callback_data.get("state", "active")
    if button_state == "inactive":
        # игнорируем обработку колбэка, если кнопка заблокирована
        return

    # извлекаем остальные данные
    closest_points = ('страница 1', 'страница 2', 'страница 3')
    count_page = int(callback_data.get("count"))
    page = int(callback_data.get("page"))
    id_user = int(callback_data.get("id_user"))
    direction = callback_data.get("direction")

    # обновляем состояние кнопок
    markup = pro_inline(page, count_page, id_user, inactive_buttons=[direction])

    if direction == "finish":
        await call.message.edit_reply_markup()
    else:
        text = str(closest_points[page])
        await call.message.edit_text(f"{text}", reply_markup=markup)

Обратите внимание, что мы добавляем новый параметр inactive_buttons в функцию pro_inline, который принимает список направлений кнопок, которые нужно заблокировать.