From 61503ad1efe0c03c2b1d9c4889a5dd07bc638b29 Mon Sep 17 00:00:00 2001 From: Ilya Smirnov Date: Wed, 8 Sep 2021 12:50:41 +0300 Subject: [PATCH 1/2] new: Layout widget --- aiogram_dialog/widgets/kbd/group.py | 68 ++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/aiogram_dialog/widgets/kbd/group.py b/aiogram_dialog/widgets/kbd/group.py index 4402d0c8..fc36f3d2 100644 --- a/aiogram_dialog/widgets/kbd/group.py +++ b/aiogram_dialog/widgets/kbd/group.py @@ -1,5 +1,6 @@ -from itertools import chain -from typing import List, Dict, Optional +from itertools import chain, islice, accumulate +from operator import itemgetter +from typing import List, Dict, Optional, Sequence, Union, Callable from aiogram.types import InlineKeyboardButton, CallbackQuery @@ -8,6 +9,14 @@ from .base import Keyboard from ..when import WhenCondition +ItemsGetter = Callable[[Dict], Sequence] + + +def get_identity(items: Sequence) -> ItemsGetter: + def identity(data) -> Sequence: + return items + return identity + class Group(Keyboard): def __init__(self, *buttons: Keyboard, id: Optional[str] = None, width: int = None, @@ -57,6 +66,61 @@ async def process_callback(self, c: CallbackQuery, dialog: Dialog, manager: Dial return False +class Layout(Keyboard): + def __init__(self, + *buttons: Keyboard, + id: Optional[str] = None, + layout: Union[str, Sequence] = None, + when: WhenCondition = None): + super().__init__(id, when) + self.buttons = buttons + + if isinstance(layout, str): + self.layout_getter = itemgetter(layout) + elif layout is None: + self.layout_getter = lambda x: None + else: + self.layout_getter = get_identity(layout) + + def find(self, widget_id): + widget = super(Layout, self).find(widget_id) + if widget: + return widget + for btn in self.buttons: + widget = btn.find(widget_id) + if widget: + return widget + return None + + async def _render_keyboard(self, data: Dict, manager: DialogManager) -> List[List[InlineKeyboardButton]]: + kbd: List[List[InlineKeyboardButton]] = [] + layout = self.layout_getter(data) + + for b in self.buttons: + b_kbd = await b.render_keyboard(data, manager) + if layout is None or not kbd: + kbd += b_kbd + else: + kbd[0].extend(chain.from_iterable(b_kbd)) + + if layout and kbd: + kbd = list(self._wrap_kbd(kbd[0], layout)) + return kbd + + def _wrap_kbd(self, kbd: List[InlineKeyboardButton], layout: Sequence) -> List[List[InlineKeyboardButton]]: + _layout = list(accumulate(layout)) + + for start, end in zip([0, *_layout], + [*_layout, _layout[-1]]): + yield list(islice(kbd, start, end)) + + async def process_callback(self, c: CallbackQuery, dialog: Dialog, manager: DialogManager) -> bool: + for b in self.buttons: + if await b.process_callback(c, dialog, manager): + return True + return False + + class Row(Group): def __init__(self, *buttons: Keyboard, id: Optional[str] = None, when: WhenCondition = None): super().__init__(*buttons, id=id, width=9999, when=when) # telegram doe not allow even 100 columns From 346455e2560259d4ad2673ffe7eb4ce806f8c71f Mon Sep 17 00:00:00 2001 From: Ilya Smirnov Date: Wed, 8 Sep 2021 15:31:48 +0300 Subject: [PATCH 2/2] new: fixed wrong iterator --- aiogram_dialog/widgets/kbd/group.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aiogram_dialog/widgets/kbd/group.py b/aiogram_dialog/widgets/kbd/group.py index fc36f3d2..78c91488 100644 --- a/aiogram_dialog/widgets/kbd/group.py +++ b/aiogram_dialog/widgets/kbd/group.py @@ -1,4 +1,4 @@ -from itertools import chain, islice, accumulate +from itertools import chain, accumulate from operator import itemgetter from typing import List, Dict, Optional, Sequence, Union, Callable @@ -112,7 +112,7 @@ def _wrap_kbd(self, kbd: List[InlineKeyboardButton], layout: Sequence) -> List[L for start, end in zip([0, *_layout], [*_layout, _layout[-1]]): - yield list(islice(kbd, start, end)) + yield kbd[start:end] async def process_callback(self, c: CallbackQuery, dialog: Dialog, manager: DialogManager) -> bool: for b in self.buttons: