From 504c454afb7beec35caabc5d8197823c8b359e7e Mon Sep 17 00:00:00 2001 From: kolo Date: Wed, 15 Jul 2026 01:05:02 +0300 Subject: [PATCH] keep back button in dialog window: single photo via DynamicMedia, media group via bot with caption --- .../bot/admin_dialogs/residents_management.py | 35 ++++++++++++++----- .../bot/admin_dialogs/rooms_management.py | 35 ++++++++++++++----- .../creator_dialogs/transactions_history.py | 35 ++++++++++++++----- .../bot/user_dialogs/user_menu/history.py | 35 ++++++++++++++----- 4 files changed, 104 insertions(+), 36 deletions(-) diff --git a/src/dutylog/application/bot/admin_dialogs/residents_management.py b/src/dutylog/application/bot/admin_dialogs/residents_management.py index 1840170..35598f4 100644 --- a/src/dutylog/application/bot/admin_dialogs/residents_management.py +++ b/src/dutylog/application/bot/admin_dialogs/residents_management.py @@ -1,10 +1,13 @@ from aiogram import Bot +from aiogram.enums import ContentType from aiogram.types import Message, CallbackQuery, InputMediaPhoto from aiogram.utils.markdown import html_decoration as hd from aiogram_dialog import Window, DialogManager from aiogram_dialog.widgets.text import Format, Const from aiogram_dialog.widgets.kbd import Row, SwitchTo, Button, ScrollingGroup, Select, Group from aiogram_dialog.widgets.input import MessageInput +from aiogram_dialog.widgets.media import DynamicMedia +from aiogram_dialog.api.entities.media import MediaAttachment, MediaId from magic_filter import F from dishka import FromDishka from dishka.integrations.aiogram_dialog import inject @@ -633,7 +636,7 @@ async def on_transaction_selected( tx = await transactions_repository.get_transaction_by_id(int(item_id)) if tx: photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx) - if photo_file_ids: + if len(photo_file_ids) > 1: operation = "Начислено" if tx.transaction_type == "increase" else "Списано" emoji = "+" if tx.transaction_type == "increase" else "−" msk_time = tx.created_at.astimezone(msk_now().tzinfo).replace(tzinfo=None) @@ -648,11 +651,8 @@ async def on_transaction_selected( caption = f"📋 Детали транзакции\n\n⚙️ Операция: {operation}\n🔢 Количество: {emoji}{tx.amount} ч\n📅 Дата: {date_str}{remark_text}{admin_info}" bot: Bot = dialog_manager.middleware_data.get("bot") try: - if len(photo_file_ids) == 1: - await bot.send_photo(callback.message.chat.id, photo_file_ids[0], caption=caption) - else: - media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)] - await bot.send_media_group(callback.message.chat.id, media=media) + media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)] + await bot.send_media_group(callback.message.chat.id, media=media) except Exception: pass await dialog_manager.switch_to(AdminMenuSG.resident_history_detail) @@ -669,12 +669,12 @@ async def get_transaction_detail_data( tx_id = dialog_manager.dialog_data.get("selected_transaction_id") if not tx_id: - return {"detail_content": "Ошибка: транзакция не выбрана"} + return {"detail_content": "Ошибка: транзакция не выбрана", "photo_media": None, "has_multiple_photos": False} tx = await transactions_repository.get_transaction_by_id(int(tx_id)) if not tx: - return {"detail_content": "Ошибка: транзакция не найдена"} + return {"detail_content": "Ошибка: транзакция не найдена", "photo_media": None, "has_multiple_photos": False} operation = "Начислено" if tx.transaction_type == "increase" else "Списано" emoji = "+" if tx.transaction_type == "increase" else "−" @@ -698,8 +698,24 @@ async def get_transaction_detail_data( 📅 Дата: {date_str}{remark_text}{admin_info} """ + photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx) + photo_media = None + has_multiple_photos = len(photo_file_ids) > 1 + if photo_file_ids and not has_multiple_photos: + photo_media = MediaAttachment( + type=ContentType.PHOTO, + file_id=MediaId(file_id=photo_file_ids[0]), + ) + + if has_multiple_photos: + detail_content = "" + else: + detail_content = content + return { - "detail_content": content, + "detail_content": detail_content, + "photo_media": photo_media, + "has_multiple_photos": has_multiple_photos, } @@ -1125,6 +1141,7 @@ resident_history_window = Window( ) resident_history_detail_window = Window( + DynamicMedia("photo_media"), Format("{detail_content}"), SwitchTo( Const("◀️ К списку"), diff --git a/src/dutylog/application/bot/admin_dialogs/rooms_management.py b/src/dutylog/application/bot/admin_dialogs/rooms_management.py index b89914f..9137da8 100644 --- a/src/dutylog/application/bot/admin_dialogs/rooms_management.py +++ b/src/dutylog/application/bot/admin_dialogs/rooms_management.py @@ -1,12 +1,15 @@ import json from aiogram import Bot +from aiogram.enums import ContentType from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError, TelegramRetryAfter from aiogram.types import Message, CallbackQuery, InputMediaPhoto from aiogram_dialog import Window, DialogManager from aiogram_dialog.widgets.text import Format, Const from aiogram_dialog.widgets.kbd import SwitchTo, Button, ScrollingGroup, Select, Row, Group from aiogram_dialog.widgets.input import MessageInput +from aiogram_dialog.widgets.media import DynamicMedia +from aiogram_dialog.api.entities.media import MediaAttachment, MediaId from dishka import FromDishka from dishka.integrations.aiogram_dialog import inject @@ -514,7 +517,7 @@ async def on_room_transaction_selected( tx = await transactions_repository.get_transaction_by_id(int(item_id)) if tx: photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx) - if photo_file_ids: + if len(photo_file_ids) > 1: operation = "Начислено" if tx.transaction_type == "increase" else "Списано" emoji = "+" if tx.transaction_type == "increase" else "−" msk_time = tx.created_at.astimezone(msk_now().tzinfo).replace(tzinfo=None) @@ -529,11 +532,8 @@ async def on_room_transaction_selected( caption = f"📋 Детали транзакции\n\n⚙️ Операция: {operation}\n🔢 Количество: {emoji}{tx.amount} ч\n📅 Дата: {date_str}{remark_text}{admin_info}" bot: Bot = dialog_manager.middleware_data.get("bot") try: - if len(photo_file_ids) == 1: - await bot.send_photo(callback.message.chat.id, photo_file_ids[0], caption=caption) - else: - media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)] - await bot.send_media_group(callback.message.chat.id, media=media) + media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)] + await bot.send_media_group(callback.message.chat.id, media=media) except Exception: pass await dialog_manager.switch_to(AdminMenuSG.room_history_detail) @@ -549,12 +549,12 @@ async def get_room_transaction_detail_data( tx_id = dialog_manager.dialog_data.get("selected_transaction_id") if not tx_id: - return {"detail_content": "Ошибка: транзакция не выбрана"} + return {"detail_content": "Ошибка: транзакция не выбрана", "photo_media": None, "has_multiple_photos": False} tx = await transactions_repository.get_transaction_by_id(int(tx_id)) if not tx: - return {"detail_content": "Ошибка: транзакция не найдена"} + return {"detail_content": "Ошибка: транзакция не найдена", "photo_media": None, "has_multiple_photos": False} operation = "Начислено" if tx.transaction_type == "increase" else "Списано" emoji = "+" if tx.transaction_type == "increase" else "−" @@ -578,8 +578,24 @@ async def get_room_transaction_detail_data( 📅 Дата: {date_str}{remark_text}{admin_info} """ + photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx) + photo_media = None + has_multiple_photos = len(photo_file_ids) > 1 + if photo_file_ids and not has_multiple_photos: + photo_media = MediaAttachment( + type=ContentType.PHOTO, + file_id=MediaId(file_id=photo_file_ids[0]), + ) + + if has_multiple_photos: + detail_content = "" + else: + detail_content = content + return { - "detail_content": content, + "detail_content": detail_content, + "photo_media": photo_media, + "has_multiple_photos": has_multiple_photos, } @@ -822,6 +838,7 @@ room_history_window = Window( ) room_history_detail_window = Window( + DynamicMedia("photo_media"), Format("{detail_content}"), SwitchTo( Const("◀️ К списку"), diff --git a/src/dutylog/application/bot/creator_dialogs/transactions_history.py b/src/dutylog/application/bot/creator_dialogs/transactions_history.py index ed49f42..81c9ce4 100644 --- a/src/dutylog/application/bot/creator_dialogs/transactions_history.py +++ b/src/dutylog/application/bot/creator_dialogs/transactions_history.py @@ -1,10 +1,13 @@ import json from aiogram import Bot +from aiogram.enums import ContentType from aiogram.types import CallbackQuery, InputMediaPhoto from aiogram_dialog import Window from aiogram_dialog.widgets.text import Format, Const from aiogram_dialog.widgets.kbd import SwitchTo, ScrollingGroup, Select, Button +from aiogram_dialog.widgets.media import DynamicMedia +from aiogram_dialog.api.entities.media import MediaAttachment, MediaId from dishka import FromDishka from dishka.integrations.aiogram_dialog import inject @@ -83,7 +86,7 @@ async def on_creator_transaction_selected( tx = await transactions_repository.get_transaction_by_id(int(item_id)) if tx: photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx) - if photo_file_ids: + if len(photo_file_ids) > 1: operation = "Начислено" if tx.transaction_type == "increase" else "Списано" emoji = "+" if tx.transaction_type == "increase" else "−" room_mark = " 🚪" if tx.per_room else "" @@ -103,11 +106,8 @@ async def on_creator_transaction_selected( caption = f"📋 Детали транзакции\n\n⚙️ Операция: {operation}\n🔢 Количество: {emoji}{tx.amount} ч{room_mark}\n👤 Резидент: {resident_name} (к. {room_number}){admin_info}\n📅 Дата: {date_str}{remark_text}" bot: Bot = dialog_manager.middleware_data.get("bot") try: - if len(photo_file_ids) == 1: - await bot.send_photo(callback.message.chat.id, photo_file_ids[0], caption=caption) - else: - media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)] - await bot.send_media_group(callback.message.chat.id, media=media) + media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)] + await bot.send_media_group(callback.message.chat.id, media=media) except Exception: pass await dialog_manager.switch_to(AdminMenuSG.transactions_history_detail) @@ -125,12 +125,12 @@ async def get_transaction_detail_data( tx_id = dialog_manager.dialog_data.get("selected_transaction_id") if not tx_id: - return {"detail_content": "Ошибка: транзакция не выбрана"} + return {"detail_content": "Ошибка: транзакция не выбрана", "photo_media": None, "has_multiple_photos": False} tx = await transactions_repository.get_transaction_by_id(int(tx_id)) if not tx: - return {"detail_content": "Ошибка: транзакция не найдена"} + return {"detail_content": "Ошибка: транзакция не найдена", "photo_media": None, "has_multiple_photos": False} operation = "Начислено" if tx.transaction_type == "increase" else "Списано" emoji = "+" if tx.transaction_type == "increase" else "−" @@ -162,8 +162,24 @@ async def get_transaction_detail_data( 📅 Дата: {date_str}{remark_text} """ + photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx) + photo_media = None + has_multiple_photos = len(photo_file_ids) > 1 + if photo_file_ids and not has_multiple_photos: + photo_media = MediaAttachment( + type=ContentType.PHOTO, + file_id=MediaId(file_id=photo_file_ids[0]), + ) + + if has_multiple_photos: + detail_content = "" + else: + detail_content = content + return { - "detail_content": content, + "detail_content": detail_content, + "photo_media": photo_media, + "has_multiple_photos": has_multiple_photos, } @@ -192,6 +208,7 @@ transactions_history_window = Window( ) transactions_history_detail_window = Window( + DynamicMedia("photo_media"), Format("{detail_content}"), SwitchTo( Const("◀️ К списку"), diff --git a/src/dutylog/application/bot/user_dialogs/user_menu/history.py b/src/dutylog/application/bot/user_dialogs/user_menu/history.py index df5522b..8caf911 100644 --- a/src/dutylog/application/bot/user_dialogs/user_menu/history.py +++ b/src/dutylog/application/bot/user_dialogs/user_menu/history.py @@ -1,8 +1,11 @@ from aiogram import Bot +from aiogram.enums import ContentType from aiogram.types import User, CallbackQuery, InputMediaPhoto from aiogram_dialog import Window from aiogram_dialog.widgets.text import Format, Const from aiogram_dialog.widgets.kbd import Back, ScrollingGroup, Select, SwitchTo, Button +from aiogram_dialog.widgets.media import DynamicMedia +from aiogram_dialog.api.entities.media import MediaAttachment, MediaId from dishka import FromDishka from dishka.integrations.aiogram_dialog import inject @@ -75,7 +78,7 @@ async def on_user_transaction_selected( tx = await transactions_repository.get_transaction_by_id(int(item_id)) if tx: photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx) - if photo_file_ids: + if len(photo_file_ids) > 1: operation = "Начислено" if tx.transaction_type == "increase" else "Списано" emoji = "+" if tx.transaction_type == "increase" else "−" msk_time = tx.created_at.astimezone(msk_now().tzinfo).replace(tzinfo=None) @@ -90,11 +93,8 @@ async def on_user_transaction_selected( caption = f"📋 Детали транзакции\n\n⚙️ Операция: {operation}\n🔢 Количество: {emoji}{tx.amount} ч\n📅 Дата: {date_str}{remark_text}{admin_info}" bot: Bot = dialog_manager.middleware_data.get("bot") try: - if len(photo_file_ids) == 1: - await bot.send_photo(callback.message.chat.id, photo_file_ids[0], caption=caption) - else: - media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)] - await bot.send_media_group(callback.message.chat.id, media=media) + media = [InputMediaPhoto(media=fid, caption=caption if i == 0 else None) for i, fid in enumerate(photo_file_ids)] + await bot.send_media_group(callback.message.chat.id, media=media) except Exception: pass await dialog_manager.switch_to(MainMenuSG.history_detail) @@ -112,12 +112,12 @@ async def get_history_detail_data( tx_id = dialog_manager.dialog_data.get("selected_transaction_id") if not tx_id: - return {"detail_content": "Ошибка: транзакция не выбрана"} + return {"detail_content": "Ошибка: транзакция не выбрана", "photo_media": None, "has_multiple_photos": False} tx = await transactions_repository.get_transaction_by_id(int(tx_id)) if not tx: - return {"detail_content": "Ошибка: транзакция не найдена"} + return {"detail_content": "Ошибка: транзакция не найдена", "photo_media": None, "has_multiple_photos": False} operation = "Начислено" if tx.transaction_type == "increase" else "Списано" emoji = "+" if tx.transaction_type == "increase" else "−" @@ -141,8 +141,24 @@ async def get_history_detail_data( 📅 Дата: {date_str}{remark_text}{admin_info} """ + photo_file_ids = HoursTransactionsRepository.get_photo_file_ids(tx) + photo_media = None + has_multiple_photos = len(photo_file_ids) > 1 + if photo_file_ids and not has_multiple_photos: + photo_media = MediaAttachment( + type=ContentType.PHOTO, + file_id=MediaId(file_id=photo_file_ids[0]), + ) + + if has_multiple_photos: + detail_content = "" + else: + detail_content = content + return { - "detail_content": content, + "detail_content": detail_content, + "photo_media": photo_media, + "has_multiple_photos": has_multiple_photos, } @@ -167,6 +183,7 @@ history_window = Window( ) history_detail_window = Window( + DynamicMedia("photo_media"), Format("{detail_content}"), SwitchTo( Const("◀️ К списку"),