416 lines
16 KiB
Python
416 lines
16 KiB
Python
"""
|
||
Inline-клавиатуры
|
||
"""
|
||
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
|
||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||
from utils.ui_styles import LEVEL_EMOJI
|
||
|
||
|
||
def get_main_menu(verified: bool = False, is_ig: bool = False, is_admin: bool = False, is_superadmin: bool = False) -> InlineKeyboardMarkup:
|
||
"""
|
||
Стабильное главное меню LKM37 (Grid 2xN)
|
||
"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
# СТРОКА 1: БАЗА (ВСЕГДА ТУТ)
|
||
builder.row(
|
||
InlineKeyboardButton(text='📞 Телефоны', callback_data='phones'),
|
||
InlineKeyboardButton(text='🏢 О доме', callback_data='about_house')
|
||
)
|
||
|
||
# СТРОКА 2-3: ДЛЯ ВЕРИФИЦИРОВАННЫХ (ФИКСИРОВАННОЕ МЕСТО)
|
||
if verified:
|
||
builder.row(
|
||
InlineKeyboardButton(text='📅 График', callback_data='schedule'),
|
||
InlineKeyboardButton(text='💰 Платежи', callback_data='payments')
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='📋 Опросы', callback_data='polls'),
|
||
InlineKeyboardButton(text=' События', callback_data='events')
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='🏪 Маркет', callback_data='market'),
|
||
InlineKeyboardButton(text='🏆 Рейтинг', callback_data='achievements')
|
||
)
|
||
else:
|
||
# Для гостей кнопка верификации на видном месте
|
||
builder.row(
|
||
InlineKeyboardButton(text='🛡️ ВЕРИФИКАЦИЯ', callback_data='start_verification')
|
||
)
|
||
|
||
# СТРОКА 4: ИНИЦИАТИВНАЯ ГРУППА И АДМИН
|
||
if is_ig or is_admin:
|
||
buttons = []
|
||
if is_ig:
|
||
buttons.append(InlineKeyboardButton(text='🎯 ТИМ-МЕНЮ', callback_data='ig_menu'))
|
||
if is_admin:
|
||
buttons.append(InlineKeyboardButton(text='⚙️ АДМИНКА', callback_data='admin_menu'))
|
||
builder.row(*buttons)
|
||
|
||
# СТРОКА 5: СУПЕР-АДМИН (ТЫ)
|
||
if is_superadmin:
|
||
builder.row(
|
||
InlineKeyboardButton(text='👑 [ROOT: УПРАВЛЕНИЕ]', callback_data='superadmin_menu')
|
||
)
|
||
|
||
# СТРОКА 6: СЛУЖЕБНОЕ (НИЗ)
|
||
builder.row(
|
||
InlineKeyboardButton(text='❓ Помощь', callback_data='help'),
|
||
InlineKeyboardButton(text='👤 Профиль', callback_data='my_profile')
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_thank_user_keyboard(users: list, page: int = 0, page_size: int = 20) -> InlineKeyboardMarkup:
|
||
"""
|
||
Клавиатура для выбора пользователя чтобы поблагодарить
|
||
|
||
:param users: список пользователей (User модели)
|
||
:param page: текущая страница (0-based)
|
||
:param page_size: размер страницы
|
||
"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
total_pages = (len(users) + page_size - 1) // page_size if users else 1
|
||
start_idx = page * page_size
|
||
end_idx = min(start_idx + page_size, len(users))
|
||
page_users = users[start_idx:end_idx]
|
||
|
||
for user in page_users:
|
||
name = user.full_name or f'user{user.user_id}'
|
||
apt = f' (кв. {user.apartment})' if user.apartment else ''
|
||
builder.button(
|
||
text=f'🙏 {name}{apt}',
|
||
callback_data=f'thank_select_{user.user_id}'
|
||
)
|
||
|
||
# Кнопки навигации
|
||
nav_buttons = []
|
||
if page > 0:
|
||
nav_buttons.append(InlineKeyboardButton(text='⬅️', callback_data=f'thank_page_{page - 1}'))
|
||
if page < total_pages - 1:
|
||
nav_buttons.append(InlineKeyboardButton(text='➡️', callback_data=f'thank_page_{page + 1}'))
|
||
|
||
if nav_buttons:
|
||
builder.row(*nav_buttons)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='🔙 Назад', callback_data='main_menu'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_thank_confirm_keyboard(user_id: int) -> InlineKeyboardMarkup:
|
||
"""Клавиатура подтверждения благодарности"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='✅ Поблагодарить', callback_data=f'thank_confirm_{user_id}'),
|
||
InlineKeyboardButton(text='❌ Отмена', callback_data='thank_user'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_admin_menu() -> InlineKeyboardMarkup:
|
||
"""Меню администратора"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='📊 Статистика', callback_data='admin_stats'),
|
||
InlineKeyboardButton(text='🕵️ Шпионы', callback_data='admin_spies'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='👥 Пользователи', callback_data='admin_users'),
|
||
InlineKeyboardButton(text='⏳ Непроверенные', callback_data='admin_unverified'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='📥 Экспорт JSON', callback_data='admin_export'),
|
||
InlineKeyboardButton(text='📤 Рассылка', callback_data='admin_broadcast'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='🔙 В главное меню', callback_data='main_menu'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_verification_menu() -> InlineKeyboardMarkup:
|
||
"""Меню верификации"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='✅ Подтвердить верификацию', callback_data='verify_approve'),
|
||
InlineKeyboardButton(text='❌ Отклонить', callback_data='verify_reject'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='📝 Написать жильцу', callback_data='verify_message'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_phones_menu() -> InlineKeyboardMarkup:
|
||
"""Меню телефонов"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='🚨 Экстренные', callback_data='phones_emergency'),
|
||
InlineKeyboardButton(text='🔧 ЖКХ', callback_data='phones_utility'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='👮 Полиция', callback_data='phones_police'),
|
||
InlineKeyboardButton(text='👷 Мастера', callback_data='phones_masters'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='🔙 Назад', callback_data='main_menu'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_unverified_menu() -> InlineKeyboardMarkup:
|
||
"""Меню для НЕверифицированных пользователей (красный стиль)"""
|
||
builder = InlineKeyboardBuilder()
|
||
emoji = LEVEL_EMOJI['unverified'] # 🔴
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text=f'{emoji} 📞 Экстренные телефоны', callback_data='phones'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text=f'{emoji} 👮 Участковый', callback_data='police'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text=f'{emoji} 📜 Правила чата', callback_data='rules'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text=f'{emoji} ❓ Помощь', callback_data='help'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_spy_detail_menu(user_id: int) -> InlineKeyboardMarkup:
|
||
"""Детали шпиона"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='⚠️ Предупредить', callback_data=f'spy_warn_{user_id}'),
|
||
InlineKeyboardButton(text='🚫 Забанить', callback_data=f'spy_ban_{user_id}'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='📝 Профиль', callback_data=f'spy_profile_{user_id}'),
|
||
InlineKeyboardButton(text='🔙 Назад', callback_data='admin_spies'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_yes_no_keyboard() -> InlineKeyboardMarkup:
|
||
"""Клавиатура Да/Нет"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='✅ Да', callback_data='yes'),
|
||
InlineKeyboardButton(text='❌ Нет', callback_data='no'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_poll_keyboard(poll_id: int, options: list) -> InlineKeyboardMarkup:
|
||
"""Клавиатура для голосования"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
# Кнопки для каждого варианта
|
||
for i, option in enumerate(options):
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=f"🔘 {option}",
|
||
callback_data=f'poll_vote_{poll_id}_{i}'
|
||
)
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_poll_results_keyboard(poll_id: int) -> InlineKeyboardMarkup:
|
||
"""Клавиатура для просмотра результатов"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text='📊 Показать результаты',
|
||
callback_data=f'poll_results_{poll_id}'
|
||
)
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_poll_close_keyboard(poll_id: int) -> InlineKeyboardMarkup:
|
||
"""Клавиатура для закрытия опроса (только админ)"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text='🔒 Закрыть опрос',
|
||
callback_data=f'poll_close_{poll_id}'
|
||
)
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_schedule_menu() -> InlineKeyboardMarkup:
|
||
"""Меню выбора типа отключения"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='💧 Вода', callback_data='schedule_type_water'),
|
||
InlineKeyboardButton(text='⚡ Электричество', callback_data='schedule_type_electricity'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='🔥 Отопление', callback_data='schedule_type_heating'),
|
||
InlineKeyboardButton(text='🔶 Газ', callback_data='schedule_type_gas'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='🛗 Лифт', callback_data='schedule_type_elevator'),
|
||
InlineKeyboardButton(text='📋 Общее', callback_data='schedule_type_general'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_schedule_item_menu(skip: bool = False) -> InlineKeyboardMarkup:
|
||
"""Меню для пропуска описания"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
if skip:
|
||
builder.row(
|
||
InlineKeyboardButton(text='⏭️ Пропустить', callback_data='schedule_skip_desc'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_ads_category_menu() -> InlineKeyboardMarkup:
|
||
"""Меню выбора категории объявления"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='💰 Продам', callback_data='ads_category_sell'),
|
||
InlineKeyboardButton(text='🛒 Куплю', callback_data='ads_category_buy'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='🎁 Отдам', callback_data='ads_category_give'),
|
||
InlineKeyboardButton(text='😿 Потеряно', callback_data='ads_category_lost'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='😺 Нашлось', callback_data='ads_category_found'),
|
||
InlineKeyboardButton(text='🔧 Услуга', callback_data='ads_category_service'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_ads_item_menu() -> InlineKeyboardMarkup:
|
||
"""Меню для объявления (просмотр)"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='📞 Показать телефон', callback_data='ads_show_phone'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_payment_type_menu() -> InlineKeyboardMarkup:
|
||
"""Меню выбора типа платежа"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text='⚡ Электро', callback_data='payment_type_electricity'),
|
||
InlineKeyboardButton(text='💧 Вода', callback_data='payment_type_water'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='🔥 Отопление', callback_data='payment_type_heating'),
|
||
InlineKeyboardButton(text='🔶 Газ', callback_data='payment_type_gas'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='🏠 Жильё', callback_data='payment_type_maintenance'),
|
||
InlineKeyboardButton(text='🗑️ Мусор', callback_data='payment_type_trash'),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(text='📡 Интернет', callback_data='payment_type_internet'),
|
||
InlineKeyboardButton(text='📋 Другое', callback_data='payment_type_other'),
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
def get_events_keyboard(events: list) -> InlineKeyboardMarkup:
|
||
"""Список событий"""
|
||
builder = InlineKeyboardBuilder()
|
||
for event in events:
|
||
builder.row(InlineKeyboardButton(
|
||
text=f"📅 {event['title']}",
|
||
callback_data=f"event_view_{event['id']}"
|
||
))
|
||
builder.row(InlineKeyboardButton(text='🔙 Назад', callback_data='main_menu'))
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_event_view_keyboard(event_id: int, is_participant: bool, is_admin: bool = False) -> InlineKeyboardMarkup:
|
||
"""Просмотр события"""
|
||
builder = InlineKeyboardBuilder()
|
||
if is_participant:
|
||
builder.row(InlineKeyboardButton(text='❌ Покинуть', callback_data=f"event_leave_{event_id}"))
|
||
else:
|
||
builder.row(InlineKeyboardButton(text='✅ Участвовать', callback_data=f"event_join_{event_id}"))
|
||
|
||
if is_admin:
|
||
builder.row(InlineKeyboardButton(text='🗑️ Удалить (Админ)', callback_data=f"event_delete_{event_id}"))
|
||
|
||
builder.row(InlineKeyboardButton(text='🔙 К списку', callback_data='events'))
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_polls_list_keyboard(polls: list) -> InlineKeyboardMarkup:
|
||
"""Список активных опросов"""
|
||
builder = InlineKeyboardBuilder()
|
||
for poll in polls:
|
||
builder.row(InlineKeyboardButton(
|
||
text=f"📊 {poll.question[:40]}",
|
||
callback_data=f"poll_view_{poll.poll_id}"
|
||
))
|
||
builder.row(InlineKeyboardButton(text='🔙 Назад', callback_data='main_menu'))
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_poll_view_keyboard(poll_id: int, is_admin: bool = False) -> InlineKeyboardMarkup:
|
||
"""Меню просмотра опроса"""
|
||
builder = InlineKeyboardBuilder()
|
||
builder.row(InlineKeyboardButton(text='🗳️ Голосовать', callback_data=f"poll_vote_menu_{poll_id}"))
|
||
builder.row(InlineKeyboardButton(text='📊 Результаты', callback_data=f"poll_results_{poll_id}"))
|
||
|
||
if is_admin:
|
||
builder.row(InlineKeyboardButton(text='🔒 Закрыть опрос', callback_data=f"poll_close_{poll_id}"))
|
||
|
||
builder.row(InlineKeyboardButton(text='🔙 К списку', callback_data='polls'))
|
||
return builder.as_markup()
|
||
|
||
|
||
def get_profile_keyboard(meter_reminders_enabled: bool = True) -> InlineKeyboardMarkup:
|
||
"""Клавиатура профиля"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
# Кнопка переключения напоминаний о счетчиках
|
||
reminders_text = "🔔 Напоминания: ВКЛ" if meter_reminders_enabled else "🔕 Напоминания: ВЫКЛ"
|
||
builder.row(InlineKeyboardButton(text=reminders_text, callback_data="toggle_meter_reminders"))
|
||
|
||
builder.row(InlineKeyboardButton(text='🔄 Обновить', callback_data='my_profile'))
|
||
builder.row(InlineKeyboardButton(text='🔙 Назад', callback_data='main_menu'))
|
||
return builder.as_markup()
|
||
|