diff --git a/davtelepot/messages.py b/davtelepot/messages.py
index b461363..9b0921a 100644
--- a/davtelepot/messages.py
+++ b/davtelepot/messages.py
@@ -1028,6 +1028,14 @@ default_useful_tools_messages = {
'en': "calculate",
'it': "calcola",
},
+ 'use_buttons': {
+ 'en': "Use buttons to enter an algebraic expression.\n\n"
+ "The input will be displayed after you stop typing for a "
+ "while.",
+ 'it': "Usa i pulsanti per comporre un'espressione algebrica.\n\n"
+ "L'espressione verrà mostrata quando smetterai di "
+ "digitare per un po'.",
+ },
},
'info_command': {
'description': {
diff --git a/davtelepot/useful_tools.py b/davtelepot/useful_tools.py
index 9584a14..bb9e600 100644
--- a/davtelepot/useful_tools.py
+++ b/davtelepot/useful_tools.py
@@ -1,8 +1,10 @@
"""General purpose functions for Telegram bots."""
# Standard library
+import asyncio
import datetime
import json
+import logging
from collections import OrderedDict
from typing import List, Union
@@ -17,17 +19,17 @@ from .utilities import (get_cleaned_text, get_user, make_button,
def get_calc_buttons() -> OrderedDict:
buttons = OrderedDict()
- buttons['pow'] = dict(
+ buttons['**'] = dict(
value='**',
symbol='**',
order='A1',
)
- buttons['floordiv'] = dict(
+ buttons['//'] = dict(
value='//',
symbol='//',
order='A2',
)
- buttons['mod'] = dict(
+ buttons['%'] = dict(
value='%',
symbol='mod',
order='A3',
@@ -39,85 +41,85 @@ def get_calc_buttons() -> OrderedDict:
)
buttons[0] = dict(
value=0,
- symbol='0️⃣',
+ symbol='0',
order='E1',
)
buttons[1] = dict(
value=1,
- symbol='1️⃣',
+ symbol='1',
order='D1',
)
buttons[2] = dict(
value=2,
- symbol='2️⃣',
+ symbol='2',
order='D2',
)
buttons[3] = dict(
value=3,
- symbol='3️⃣',
+ symbol='3',
order='D3',
)
buttons[4] = dict(
value=4,
- symbol='4️⃣',
+ symbol='4',
order='C1',
)
buttons[5] = dict(
value=5,
- symbol='5️⃣',
+ symbol='5',
order='C2',
)
buttons[6] = dict(
value=6,
- symbol='6️⃣',
+ symbol='6',
order='C3',
)
buttons[7] = dict(
value=7,
- symbol='7️⃣',
+ symbol='7',
order='B1',
)
buttons[8] = dict(
value=8,
- symbol='8️⃣',
+ symbol='8',
order='B2',
)
buttons[9] = dict(
value=9,
- symbol='9️⃣',
+ symbol='9',
order='B3',
)
- buttons['plus'] = dict(
+ buttons['+'] = dict(
value='+',
- symbol='➕️',
+ symbol='+',
order='B4',
)
- buttons['minus'] = dict(
+ buttons['-'] = dict(
value='-',
- symbol='➖',
+ symbol='-',
order='C4',
)
- buttons['times'] = dict(
+ buttons['*'] = dict(
value='*',
- symbol='✖️',
+ symbol='*',
order='D4',
)
- buttons['divided'] = dict(
+ buttons['/'] = dict(
value='/',
- symbol='➗',
+ symbol='/',
order='E4',
)
- buttons['point'] = dict(
+ buttons['.'] = dict(
value='.',
symbol='.',
order='E2',
)
- buttons['000'] = dict(
+ buttons['*1000'] = dict(
value='*1000',
- symbol='0️⃣0️⃣0️⃣',
+ symbol='000',
order='E3',
)
- buttons['enter'] = dict(
+ buttons['\n'] = dict(
value='\n',
symbol='✅',
order='F1',
@@ -133,14 +135,16 @@ def get_calc_buttons() -> OrderedDict:
calc_buttons = get_calc_buttons()
-def get_calculator_keyboard():
+def get_calculator_keyboard(additional_data: list = None):
+ if additional_data is None:
+ additional_data = []
return make_inline_keyboard(
[
make_button(
text=button['symbol'],
prefix='calc:///',
delimiter='|',
- data=[button['value']]
+ data=[*additional_data, button['value']]
)
for button in sorted(calc_buttons.values(), key=lambda b: b['order'])
],
@@ -149,24 +153,41 @@ def get_calculator_keyboard():
async def _calculate_button(bot: Bot,
+ update: dict,
+ user_record: OrderedDict,
language: str,
data: List[Union[int, str]]):
- result, text, reply_markup = '', '', None
- if len(data) == 1:
- input_value = data[0]
- if input_value == 'del':
- pass
- elif input_value == 'info':
- pass
- elif input_value in [button['value'] for button in calc_buttons.values()]:
- pass
+ text, reply_markup = '', None
+ if update['from']['id'] not in bot.shared_data['calc']:
+ bot.shared_data['calc'][update['from']['id']] = []
+ if len(data) < 2:
+ record_id = bot.db['calculations'].insert(
+ dict(
+ user_id=user_record['id'],
+ created=datetime.datetime.now()
+ )
+ )
+ data = [record_id, *data]
else:
- pass # Error!
+ record_id = data[0]
+ asyncio.ensure_future(
+ calculate_session(bot=bot,
+ user_telegram_id=update['from']['id'],
+ language=language,
+ data=data)
+ )
+ text = bot.get_message(
+ 'useful_tools', 'calculate_command', 'use_buttons',
+ language=language
+ )
+ reply_markup = get_calculator_keyboard(additional_data=[record_id])
+ update['data'] = data
+ bot.shared_data['calc'][update['from']['id']].append(update)
# Edit the update with the button if a new text is specified
if not text:
- return result
+ return
return dict(
- text=result,
+ text='',
edit=dict(
text=text,
reply_markup=reply_markup
@@ -174,6 +195,64 @@ async def _calculate_button(bot: Bot,
)
+async def calculate_session(bot: Bot,
+ user_telegram_id: int,
+ language: str,
+ data: List[Union[int, str]]):
+ queue = bot.shared_data['calc'][user_telegram_id]
+ queue_len = None
+ while queue_len != len(queue):
+ queue_len = len(queue)
+ await asyncio.sleep(2)
+ last_entry = max(queue, key=lambda u: u['id'])
+ # Remove user queue
+ queue = queue.copy()
+ del bot.shared_data['calc'][user_telegram_id]
+
+ record = None
+ text, reply_markup = '', None
+
+ # It would be nice to do:
+ # for update in sorted(queue, key=lambda u: u['id'])
+ # Alas, 'id's are not progressive... Telegram's fault!
+ for i, update in enumerate(queue):
+ if i % 5 == 0:
+ await asyncio.sleep(.1)
+ data = update['data']
+ if len(data) != 2:
+ logging.error(f"Something went wrong: invalid data received.\n{data}")
+ return
+ if not text:
+ record = bot.db['calculations'].find_one(
+ id=data[0]
+ )
+ text = record['text'] or ''
+ reply_markup = get_calculator_keyboard(additional_data=[record['id']])
+ input_value = data[1]
+ if input_value == 'del':
+ pass
+ elif input_value == 'info':
+ pass
+ elif input_value in calc_buttons:
+ text = f"{text} {calc_buttons[input_value]['value']}"
+ else:
+ pass # Error!
+ if record:
+ bot.db['calculations'].update(
+ dict(
+ id=record['id'],
+ modified=datetime.datetime.now(),
+ text=text
+ ),
+ ['id']
+ )
+ await bot.edit_message_text(
+ text=text,
+ update=last_entry,
+ reply_markup=reply_markup
+ )
+
+
async def _calculate_command(bot: Bot,
update: dict,
language: str,
@@ -339,6 +418,29 @@ def init(telegram_bot: Bot, useful_tools_messages=None):
useful_tools_messages
)
telegram_bot.messages['useful_tools'] = useful_tools_messages
+ telegram_bot.shared_data['calc'] = dict()
+
+ if 'calculations' not in telegram_bot.db.tables:
+ types = telegram_bot.db.types
+ table = telegram_bot.db.create_table(
+ table_name='calculations'
+ )
+ table.create_column(
+ 'user_id',
+ types.integer
+ )
+ table.create_column(
+ 'created',
+ types.datetime
+ )
+ table.create_column(
+ 'modified',
+ types.datetime
+ )
+ table.create_column(
+ 'text',
+ types.string
+ )
@telegram_bot.command(command='/calc',
aliases=None,
@@ -358,8 +460,10 @@ def init(telegram_bot: Bot, useful_tools_messages=None):
@telegram_bot.button(prefix='calc:///',
separator='|',
authorization_level='everybody')
- async def calculate_button(bot, language, data):
- return await _calculate_button(bot=bot, language=language, data=data)
+ async def calculate_button(bot, update, user_record, language, data):
+ return await _calculate_button(bot=bot, user_record=user_record,
+ update=update,
+ language=language, data=data)
@telegram_bot.command(command='/info',
aliases=None,