-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkeyboard_paginator.py
168 lines (125 loc) · 4.72 KB
/
keyboard_paginator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# -*- coding: utf-8 -*-
import json
from collections import namedtuple
InlineKeyboardButton = namedtuple('InlineKeyboardButton', ['text', 'callback_data'])
class InlineKeyboardPaginator:
_keyboard_before = None
_keyboard = None
_keyboard_after = None
first_page_label = '« {}'
previous_page_label = '‹ {}'
next_page_label = '{} ›'
last_page_label = '{} »'
current_page_label = '·{}·'
def __init__(self, page_count, current_page=1, data_pattern='{page}'):
self._keyboard_before = list()
self._keyboard_after = list()
if current_page is None or current_page < 1:
current_page = 1
if current_page > page_count:
current_page = page_count
self.current_page = current_page
self.page_count = page_count
self.data_pattern = data_pattern
def _build(self):
keyboard_dict = dict()
if self.page_count == 1:
self._keyboard = list()
return
elif self.page_count <= 5:
for page in range(1, self.page_count+1):
keyboard_dict[page] = page
else:
keyboard_dict = self._build_for_multi_pages()
keyboard_dict[self.current_page] = self.current_page_label.format(self.current_page)
self._keyboard = self._to_button_array(keyboard_dict)
def _build_for_multi_pages(self):
if self.current_page <= 3:
return self._build_start_keyboard()
elif self.current_page > self.page_count - 3:
return self._build_finish_keyboard()
else:
return self._build_middle_keyboard()
def _build_start_keyboard(self):
keyboard_dict = dict()
for page in range(1, 4):
keyboard_dict[page] = page
keyboard_dict[4] = self.next_page_label.format(4)
keyboard_dict[self.page_count] = self.last_page_label.format(self.page_count)
return keyboard_dict
def _build_finish_keyboard(self):
keyboard_dict = dict()
keyboard_dict[1] = self.first_page_label.format(1)
keyboard_dict[self.page_count-3] = self.previous_page_label.format(self.page_count-3)
for page in range(self.page_count-2, self.page_count+1):
keyboard_dict[page] = page
return keyboard_dict
def _build_middle_keyboard(self):
keyboard_dict = dict()
keyboard_dict[1] = self.first_page_label.format(1)
keyboard_dict[self.current_page-1] = self.previous_page_label.format(self.current_page-1)
keyboard_dict[self.current_page] = self.current_page
keyboard_dict[self.current_page+1] = self.next_page_label.format(self.current_page+1)
keyboard_dict[self.page_count] = self.last_page_label.format(self.page_count)
return keyboard_dict
def _to_button_array(self, keyboard_dict):
keyboard = list()
keys = list(keyboard_dict.keys())
keys.sort()
for key in keys:
keyboard.append(
InlineKeyboardButton(
text=str(keyboard_dict[key]),
callback_data=self.data_pattern.format(page=key)
)
)
return _buttons_to_dict(keyboard)
@property
def keyboard(self):
if self._keyboard is None:
self._build()
return self._keyboard
@property
def markup(self):
"""InlineKeyboardMarkup"""
keyboards = list()
keyboards.extend(self._keyboard_before)
keyboards.append(self.keyboard)
keyboards.extend(self._keyboard_after)
keyboards = list(filter(bool, keyboards))
if not keyboards:
return None
return json.dumps({'inline_keyboard': keyboards})
def __str__(self):
if self._keyboard is None:
self._build()
return ' '.join(
[b['text'] for b in self._keyboard]
)
def add_before(self, *inline_buttons):
"""
Add buttons as line above pagination buttons.
Args:
inline_buttons (:object:`iterable`): List of object with attributes `text` and `callback_data`.
Returns:
None
"""
self._keyboard_before.append(_buttons_to_dict(inline_buttons))
def add_after(self, *inline_buttons):
"""
Add buttons as line under pagination buttons.
Args:
inline_buttons (:object:`iterable`): List of object with attributes 'text' and 'callback_data'.
Returns:
None
"""
self._keyboard_after.append(_buttons_to_dict(inline_buttons))
def _buttons_to_dict(buttons):
return [
{
'text': button.text,
'callback_data': button.callback_data,
}
for button
in buttons
]