Приостановить отправку сообщений пока пользователь не нажмет InlineKeyboardButton

Пользователь вводит множество значений, и чтобы не отправлять сразу тонну сообщений нужно подтверждать отправку каждого следующего нажатием inline кнопки. Код рабочий, убрал все лишнее чтобы был лучше понятен сценарий. Комментариями обозначил основные шаги и где требуется подтверждение от пользователя. Есть какой-то способ приостановить отправку сообщений в цикле и возобновить только при нажатии inline кнопки?

import os

from aiogram.dispatcher import FSMContext
from aiogram import Bot, Dispatcher, executor, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher.filters.state import StatesGroup, State


bot = Bot(token=os.environ["TOKEN"])
dispatcher = Dispatcher(bot, storage=MemoryStorage())


class Searches(StatesGroup):
    by_id = State()


@dispatcher.message_handler(state='*', commands='cancel')
async def cancel_state(message: types.Message, state: FSMContext):
    if await state.get_state():
        await state.finish()
        await message.reply("Поиск был отменён.")


@dispatcher.message_handler(commands="search")
async def answer_search_message(message: types.Message):
    find_by_id_button = types.InlineKeyboardButton("по ID", callback_data="by_id")
    keyboard = types.InlineKeyboardMarkup().row(find_by_id_button)
    await message.answer("Выбери тип поиска", parse_mode="HTML", reply_markup=keyboard)


@dispatcher.callback_query_handler(text="by_id")
async def callback_id(callback: types.CallbackQuery):
    await callback.message.answer("Введи ID, разделяя их запятой")
    await Searches.by_id.set()


@dispatcher.message_handler(state=Searches.by_id)
async def find_by_id(message: types.Message, state: FSMContext):
    ids_from_message = [item for item in range(5)]  # получаю список id из сообщения
    for index, item in enumerate(ids_from_message):
        photo, caption, url = ("https://www.google.ru/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", "текст документа", "https://www.example.org/")  # получаю по id какие-то данные
        button_to_site = types.InlineKeyboardButton("Подробнее на сайте", url)
        keyboard = types.InlineKeyboardMarkup().row(button_to_site)
        if len(ids_from_message) > index + 1:  # если это не последний id, то показываю кнопку "Следующий результат"
            keyboard.add(types.InlineKeyboardButton("Следующий результат", callback_data="show_next"))
            await message.answer_photo(photo=photo, caption=caption, parse_mode="HTML", reply_markup=keyboard)
            # тормознуть цикл тут, ожидая нажатия кнопки "Следующий результат"
        else:
            await message.answer_photo(photo=photo, caption=caption, parse_mode="HTML", reply_markup=keyboard)
            await state.finish()


executor.start_polling(dispatcher)

Ответы (1 шт):

Автор решения: Brain Drill

Вот мой вариант решния этой проблемы. Суть его в том, что можно сохранить некие данные в используемое хранилище (в данном примере локальное). И потом по чуть-чуть их отправлять пользователю, когда тот нажимает кнопку.

import os

from aiogram.dispatcher import FSMContext
from aiogram import Bot, Dispatcher, executor, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher.filters.state import StatesGroup, State

def get_record_by_id(doc_id):
    # тут как-то обработался id и что-то вернул
    return "https://www.google.ru/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", "текст документа", "https://www.example.org/"

bot = Bot(token=os.environ["TOKEN"])
storage = MemoryStorage()
dispatcher = Dispatcher(bot, storage=storage)

class Searches(StatesGroup):
    by_id = State()

@dispatcher.message_handler(state='*', commands='cancel')
async def cancel_state(message: types.Message, state: FSMContext):
    if await state.get_state():
        await state.finish()
        await message.reply("Поиск был отменён.")

@dispatcher.message_handler(commands="search")
async def answer_search_message(message: types.Message):
    find_by_id_button = types.InlineKeyboardButton("по ID", callback_data="by_id")
    keyboard = types.InlineKeyboardMarkup().row(find_by_id_button)
    await message.answer("Выбери тип поиска", parse_mode="HTML", reply_markup=keyboard)

@dispatcher.callback_query_handler(text="by_id")
async def callback_id(callback: types.CallbackQuery):
    await callback.message.answer("Введи ID, разделяя их запятой")
    await Searches.by_id.set()
    await callback.answer()

@dispatcher.message_handler(state=Searches.by_id)
async def find_by_id(message: types.Message, state: FSMContext):
    user_id = message.from_user.id
    ids_from_message = [item for item in range(5)]
    photo, caption, url = get_record_by_id(ids_from_message[0])
    button_to_site = types.InlineKeyboardButton("Подробнее на сайте", url)
    keyboard = types.InlineKeyboardMarkup().row(button_to_site)
    if len(ids_from_message) > 1:
        del ids_from_message[0]
        await storage.set_data(user=user_id, data={"ids_to_send": ids_from_message})
        keyboard.add(types.InlineKeyboardButton("Следующий результат", callback_data="show_next"))
        await message.answer_photo(photo=photo, caption=caption, parse_mode="HTML", reply_markup=keyboard)
    else:
        await message.answer_photo(photo=photo, caption=caption, parse_mode="HTML", reply_markup=keyboard)
        await state.finish()

@dispatcher.callback_query_handler(state=Searches.by_id, text="show_next")
async def callback_id(callback: types.CallbackQuery, state: FSMContext):
    user_id = callback.from_user.id
    chat_id = callback.message.chat.id
    data = await storage.get_data(user=user_id)
    photo, caption, url = get_record_by_id(data["ids_to_send"][0])
    button_to_site = types.InlineKeyboardButton("Подробнее на сайте", url)
    keyboard = types.InlineKeyboardMarkup().row(button_to_site)
    if len(data["ids_to_send"]) > 1:
        del data["ids_to_send"][0]
        await storage.set_data(user=user_id, data={"ids_to_send": data["ids_to_send"]})
        keyboard.add(types.InlineKeyboardButton("Следующий результат", callback_data="show_next"))
        await bot.send_photo(chat_id=chat_id, photo=photo, caption=caption, parse_mode="HTML", reply_markup=keyboard)
    else:
        await bot.send_photo(chat_id=chat_id, photo=photo, caption=caption, parse_mode="HTML", reply_markup=keyboard)
        await state.finish()
    await callback.answer()

executor.start_polling(dispatcher)
→ Ссылка