1

User insert some values. Just for not spamming him with many messages, I want to pause sending them in loop and wait user tap inline button. So how can I pause them and wait for user tap "Next result" button? Code beneath just simplified, but works for better understanding scenario.

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("Search was canceled")


@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("Choose search type", parse_mode="HTML", reply_markup=keyboard)


@dispatcher.callback_query_handler(text="by_id")
async def callback_id(callback: types.CallbackQuery):
    await callback.message.answer("Insert IDs, split them with ','")
    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)]  # get IDs from user message
    for index, item in enumerate(ids_from_message):
        photo, caption, url = ("https://www.google.ru/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", "some text", "https://www.example.org/")  # get some data by id
        button_to_site = types.InlineKeyboardButton("More on site", url)
        keyboard = types.InlineKeyboardMarkup().row(button_to_site)
        if len(ids_from_message) > index + 1:  # if this is not last result - show button "Next result"
            keyboard.add(types.InlineKeyboardButton("Next result", callback_data="show_next"))
            await message.answer_photo(photo=photo, caption=caption, parse_mode="HTML", reply_markup=keyboard)
            # loop should pause here, awaiting for user tap inline button "Next result"
        else:
            await message.answer_photo(photo=photo, caption=caption, parse_mode="HTML", reply_markup=keyboard)
            await state.finish()


executor.start_polling(dispatcher)

1 Answers1

0

Well, internet, you always helps me, so here what I found as solution for this problem. You can just save some data for user and send it to him, then it trigger button. Full code below.

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):
    # blah-blah some data generating
    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("Search was canceled")


@dispatcher.message_handler(commands="search")
async def answer_search_message(message: types.Message):
    find_by_id_button = types.InlineKeyboardButton("by ID", callback_data="by_id")
    keyboard = types.InlineKeyboardMarkup().row(find_by_id_button)
    await message.answer("Choose search type", parse_mode="HTML", reply_markup=keyboard)


@dispatcher.callback_query_handler(text="by_id")
async def callback_id(callback: types.CallbackQuery):
    await callback.message.answer("Insert IDs, split them with ','")
    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("More on site", 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("Next result", 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("More on site", 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("Next result", 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)