from datetime import datetime, timedelta from aiogram import Router, F from aiogram.fsm.context import FSMContext from aiogram.types import Message, CallbackQuery, InlineKeyboardButton from aiogram.utils.keyboard import InlineKeyboardBuilder from logging import getLogger from typing import TYPE_CHECKING from ....model.descriptors import EntityFieldDescriptor, EntityDescriptor from ..context import ContextData, CallbackCommand from ..common import get_send_message, get_field_descriptor, get_entity_descriptor from .common import wrap_editor if TYPE_CHECKING: from ....main import QBotApp logger = getLogger(__name__) router = Router() async def date_picker(message: Message | CallbackQuery, field_descriptor: EntityFieldDescriptor, callback_data: ContextData, current_value: datetime, state: FSMContext, edit_prompt: str | None = None, **kwargs): if not current_value: start_date = datetime.now() else: start_date = current_value start_date = start_date.replace(day = 1) previous_month = start_date - timedelta(days = 1) next_month = start_date.replace(day = 28) + timedelta(days = 4) keyboard_builder = InlineKeyboardBuilder() keyboard_builder.row(InlineKeyboardButton(text = "◀️", callback_data = ContextData( command = CallbackCommand.DATE_PICKER_MONTH, context = callback_data.context, entity_name = callback_data.entity_name, entity_id = callback_data.entity_id, field_name = callback_data.field_name, data = previous_month.strftime("%Y-%m-%d"), save_state = True).pack()), InlineKeyboardButton(text = start_date.strftime("%b %Y"), callback_data = ContextData( command = CallbackCommand.DATE_PICKER_YEAR, context = callback_data.context, entity_name = callback_data.entity_name, entity_id = callback_data.entity_id, field_name = callback_data.field_name, data = start_date.strftime("%Y-%m-%d"), save_state = True).pack()), InlineKeyboardButton(text = "▶️", callback_data = ContextData( command = CallbackCommand.DATE_PICKER_MONTH, context = callback_data.context, entity_name = callback_data.entity_name, entity_id = callback_data.entity_id, field_name = callback_data.field_name, data = next_month.strftime("%Y-%m-%d"), save_state = True).pack())) first_day = start_date - timedelta(days = start_date.weekday()) weeks = (((start_date.replace(day = 28) + timedelta(days = 4)).replace(day = 1) - first_day).days - 1) // 7 + 1 for week in range(weeks): buttons = [] for day in range(7): current_day = first_day + timedelta(days = week * 7 + day) buttons.append(InlineKeyboardButton(text = current_day.strftime("%d"), callback_data = ContextData( command = CallbackCommand.FIELD_EDITOR_CALLBACK, context = callback_data.context, entity_name = callback_data.entity_name, entity_id = callback_data.entity_id, field_name = callback_data.field_name, data = current_day.strftime("%Y-%m-%d"), save_state = True).pack())) keyboard_builder.row(*buttons) state_data = kwargs["state_data"] await wrap_editor(keyboard_builder = keyboard_builder, field_descriptor = field_descriptor, callback_data = callback_data, state_data = state_data) await state.set_data(state_data) if edit_prompt: send_message = get_send_message(message) await send_message(text = edit_prompt, reply_markup = keyboard_builder.as_markup()) else: await message.edit_reply_markup(reply_markup = keyboard_builder.as_markup()) @router.callback_query(ContextData.filter(F.command == CallbackCommand.DATE_PICKER_YEAR)) async def date_picker_year(query: CallbackQuery, callback_data: ContextData, app: "QBotApp", state: FSMContext, **kwargs): start_date = datetime.strptime(callback_data.data, "%Y-%m-%d") state_data = await state.get_data() kwargs["state_data"] = state_data keyboard_builder = InlineKeyboardBuilder() keyboard_builder.row(InlineKeyboardButton(text = "🔼", callback_data = ContextData( command = CallbackCommand.DATE_PICKER_YEAR, context = callback_data.context, entity_name = callback_data.entity_name, entity_id = callback_data.entity_id, field_name = callback_data.field_name, data = start_date.replace(year = start_date.year - 20).strftime("%Y-%m-%d")).pack())) for r in range(4): buttons = [] for c in range(5): current_date = start_date.replace(year = start_date.year + r * 5 + c - 10) buttons.append(InlineKeyboardButton(text = current_date.strftime("%Y"), callback_data = ContextData( command = CallbackCommand.DATE_PICKER_MONTH, context = callback_data.context, entity_name = callback_data.entity_name, entity_id = callback_data.entity_id, field_name = callback_data.field_name, data = current_date.strftime("%Y-%m-%d"), save_state = True).pack())) keyboard_builder.row(*buttons) keyboard_builder.row(InlineKeyboardButton(text = "🔽", callback_data = ContextData( command = CallbackCommand.DATE_PICKER_YEAR, context = callback_data.context, entity_name = callback_data.entity_name, entity_id = callback_data.entity_id, field_name = callback_data.field_name, data = start_date.replace(year = start_date.year + 20).strftime("%Y-%m-%d")).pack())) field_descriptor = get_field_descriptor(app, callback_data) await wrap_editor(keyboard_builder = keyboard_builder, field_descriptor = field_descriptor, callback_data = callback_data, state_data = state_data) await query.message.edit_reply_markup(reply_markup = keyboard_builder.as_markup()) @router.callback_query(ContextData.filter(F.command == CallbackCommand.DATE_PICKER_MONTH)) async def date_picker_month(query: CallbackQuery, callback_data: ContextData, app: "QBotApp", **kwargs): field_descriptor = get_field_descriptor(app, callback_data) state: FSMContext = kwargs["state"] state_data = await state.get_data() kwargs["state_data"] = state_data await date_picker(query.message, field_descriptor = field_descriptor, callback_data = callback_data, current_value = datetime.strptime(callback_data.data, "%Y-%m-%d"), **kwargs)