Если вы используете состояния, то вы можете поместить все обработчики в состояния и при нажатии на кнопки вызывать переходы в другие состояния. Для реализации кнопки отмены можно создать отдельное состояние, которое будет обрабатывать команду отмены, и при ее вызове производить переход в это состояние.
Пример реализации:
```python
from aiogram.dispatcher.filters import Command
from aiogram.types import Message, CallbackQuery
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton
class Registration(StatesGroup):
email = State()
cancel = State()
async def start_handler(message: Message):
keyboard_markup = ReplyKeyboardMarkup(resize_keyboard=True, selective=True)
keyboard_markup.add(KeyboardButton(text='Отмена'))
await message.answer(text='Введите email:', reply_markup=keyboard_markup)
await Registration.email.set()
async def email_handler(message: Message, state: FSMContext):
email = message.text
await state.update_data(email=email) # сохраняем email в состоянии
await message.answer(f'Вы ввели email {email}')
keyboard_markup = InlineKeyboardMarkup()
keyboard_markup.add(InlineKeyboardButton('Отмена', callback_data='cancel'))
await message.answer(text='Вы хотите сохранить email?', reply_markup=keyboard_markup)
await Registration.next() # переходим в следующее состояние
async def cancel_handler(callback_query: CallbackQuery, state: FSMContext):
await state.reset_state() # очищаем все состояния
await callback_query.answer(text='Отменено') # отправляем ответ пользователю
await callback_query.message.delete_reply_markup() # удаляем клавиатуру
async def save_handler(callback_query: CallbackQuery, state: FSMContext):
data = await state.get_data() # получаем данные из состояния
# сохраняем email в базу данных или выполняем другие действия
await callback_query.answer(text='Email сохранен')
await callback_query.message.delete_reply_markup() # удаляем клавиатуру
await state.finish() # завершаем состояние
# добавляем обработчики состояний
dp.register_message_handler(start_handler, commands='register')
dp.register_message_handler(email_handler, state=Registration.email, content_types=types.ContentTypes.TEXT)
dp.register_callback_query_handler(cancel_handler, state=Registration.cancel, text='cancel')
dp.register_callback_query_handler(save_handler, state=Registration.email, text='Да')
```
В примере мы добавляем два состояния: `email` и `cancel`, а также три обработчика событий:
- `start_handler` - начало регистрации, при вызове этой команды мы переходим в состояние `email` и выводим клавиатуру с кнопкой "Отмена".
- `email_handler` - обработчик ввода email, сохраняет email в состояние и переходит в состояние `cancel`. В этом состоянии мы выводим кнопку "Отмена" и кнопку "Да" для сохранения email.
- `cancel_handler` - обработчик кнопки "Отмена", удаляет клавиатуру и очищает все состояния.
- `save_handler` - обработчик кнопки "Да", сохраняет email и завершает состояние.
Кнопка "Отмена" вводится в ReplyKeyboardMarkup в обработчике `start_handler`. Кнопка "Отмена" в InlineKeyboardMarkup вводится в обработчике `email_handler`.