Merge branch 'master' into edit-msg

This commit is contained in:
Alex 2020-05-21 08:28:51 +03:00 committed by GitHub
commit 36d5d8a1e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 20 deletions

View file

@ -61,6 +61,7 @@ class Controller:
"updateMessageContent": self.update_msg_content, "updateMessageContent": self.update_msg_content,
"updateMessageSendSucceeded": self.update_msg_send_succeeded, "updateMessageSendSucceeded": self.update_msg_send_succeeded,
"updateNewMessage": self.update_new_msg, "updateNewMessage": self.update_new_msg,
"updateMessageContentOpened": self.update_message_content_opened,
} }
self.chat_size = 0.5 self.chat_size = 0.5
signal(SIGWINCH, self.resize_handler) signal(SIGWINCH, self.resize_handler)
@ -107,7 +108,6 @@ class Controller:
def open_current_msg(self): def open_current_msg(self):
msg = MsgProxy(self.model.current_msg) msg = MsgProxy(self.model.current_msg)
log.info("Open msg: %s", msg.msg)
if msg.is_text: if msg.is_text:
with NamedTemporaryFile("w", suffix=".txt") as f: with NamedTemporaryFile("w", suffix=".txt") as f:
f.write(msg.text_content) f.write(msg.text_content)
@ -118,8 +118,9 @@ class Controller:
path = msg.local_path path = msg.local_path
if path: if path:
chat_id = self.model.chats.id_by_index(self.model.current_chat)
self.tg.open_message_content(chat_id, msg.msg_id)
with suspend(self.view) as s: with suspend(self.view) as s:
log.info("Opening file: %s", path)
s.open_file(path) s.open_file(path)
def present_error(self, msg: str): def present_error(self, msg: str):
@ -553,3 +554,10 @@ class Controller:
if proxy.is_downloaded: if proxy.is_downloaded:
self.model.downloads.pop(file_id) self.model.downloads.pop(file_id)
break break
@handle_exception
def update_message_content_opened(self, update: Dict[str, Any]):
chat_id = update["chat_id"]
message_id = update["message_id"]
self.model.msgs.update_msg_content_opened(chat_id, message_id)
self.refresh_msgs()

View file

@ -5,7 +5,7 @@ import threading
from curses import window, wrapper # type: ignore from curses import window, wrapper # type: ignore
from functools import partial from functools import partial
from telegram.client import Telegram from telegram.client import AsyncResult, Telegram
from tg import config, utils from tg import config, utils
from tg.controllers import Controller from tg.controllers import Controller
@ -48,7 +48,7 @@ class TelegramApi(Telegram):
) )
result.wait() result.wait()
def send_doc(self, file_path, chat_id): def send_doc(self, file_path: str, chat_id: int) -> AsyncResult:
data = { data = {
"@type": "sendMessage", "@type": "sendMessage",
"chat_id": chat_id, "chat_id": chat_id,
@ -59,7 +59,7 @@ class TelegramApi(Telegram):
} }
return self._send_data(data) return self._send_data(data)
def send_audio(self, file_path, chat_id): def send_audio(self, file_path: str, chat_id: int) -> AsyncResult:
data = { data = {
"@type": "sendMessage", "@type": "sendMessage",
"chat_id": chat_id, "chat_id": chat_id,
@ -70,7 +70,7 @@ class TelegramApi(Telegram):
} }
return self._send_data(data) return self._send_data(data)
def send_photo(self, file_path, chat_id): def send_photo(self, file_path: str, chat_id: int) -> AsyncResult:
data = { data = {
"@type": "sendMessage", "@type": "sendMessage",
"chat_id": chat_id, "chat_id": chat_id,
@ -81,7 +81,14 @@ class TelegramApi(Telegram):
} }
return self._send_data(data) return self._send_data(data)
def send_video(self, file_path, chat_id, width, height, duration): def send_video(
self,
file_path: str,
chat_id: int,
width: int,
height: int,
duration: int,
) -> AsyncResult:
data = { data = {
"@type": "sendMessage", "@type": "sendMessage",
"chat_id": chat_id, "chat_id": chat_id,
@ -95,7 +102,9 @@ class TelegramApi(Telegram):
} }
return self._send_data(data) return self._send_data(data)
def send_voice(self, file_path, chat_id, duration, waveform): def send_voice(
self, file_path: str, chat_id: int, duration: int, waveform: int
):
data = { data = {
"@type": "sendMessage", "@type": "sendMessage",
"chat_id": chat_id, "chat_id": chat_id,
@ -122,7 +131,7 @@ class TelegramApi(Telegram):
def toggle_chat_is_marked_as_unread( def toggle_chat_is_marked_as_unread(
self, chat_id: int, is_marked_as_unread: bool self, chat_id: int, is_marked_as_unread: bool
): ) -> AsyncResult:
data = { data = {
"@type": "toggleChatIsMarkedAsUnread", "@type": "toggleChatIsMarkedAsUnread",
"chat_id": chat_id, "chat_id": chat_id,
@ -130,7 +139,9 @@ class TelegramApi(Telegram):
} }
return self._send_data(data) return self._send_data(data)
def toggle_chat_is_pinned(self, chat_id: int, is_pinned: bool): def toggle_chat_is_pinned(
self, chat_id: int, is_pinned: bool
) -> AsyncResult:
data = { data = {
"@type": "toggleChatIsPinned", "@type": "toggleChatIsPinned",
"chat_id": chat_id, "chat_id": chat_id,
@ -150,7 +161,7 @@ class TelegramApi(Telegram):
def view_messages( def view_messages(
self, chat_id: int, message_ids: list, force_read: bool = True self, chat_id: int, message_ids: list, force_read: bool = True
): ) -> AsyncResult:
data = { data = {
"@type": "viewMessages", "@type": "viewMessages",
"chat_id": chat_id, "chat_id": chat_id,
@ -159,6 +170,16 @@ class TelegramApi(Telegram):
} }
return self._send_data(data) return self._send_data(data)
def open_message_content(
self, chat_id: int, message_id: int
) -> AsyncResult:
data = {
"@type": "openMessageContent",
"chat_id": chat_id,
"message_id": message_id,
}
return self._send_data(data)
def main(): def main():
def signal_handler(sig, frame): def signal_handler(sig, frame):

View file

@ -4,6 +4,8 @@ from typing import Any, Dict, List, Optional, Set, Tuple
from telegram.client import Telegram from telegram.client import Telegram
from tg.msg import MsgProxy
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -262,7 +264,22 @@ class MsgModel:
if msg["id"] != msg_id: if msg["id"] != msg_id:
continue continue
msg["content"] = message_content msg["content"] = message_content
return True return True
return False
def update_msg_content_opened(self, chat_id: int, msg_id: int):
for message in self.msgs[chat_id]:
if message["id"] != msg_id:
continue
msg = MsgProxy(message)
if msg.type == "voice":
msg.is_listened = True
elif msg.type == "recording":
msg.is_viewed = True
# TODO: start the TTL timer for self-destructing messages
# that is the last case to implement
# https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1update_message_content_opened.html
return
def add_message(self, chat_id: int, message: Dict[str, Any]) -> bool: def add_message(self, chat_id: int, message: Dict[str, Any]) -> bool:
msg_id = message["id"] msg_id = message["id"]

View file

@ -1,6 +1,6 @@
import logging import logging
from datetime import datetime from datetime import datetime
from typing import Any, Dict from typing import Any, Dict, Optional
from tg import utils from tg import utils
@ -58,8 +58,8 @@ class MsgProxy:
self.msg[key] = value self.msg[key] = value
@property @property
def type(self): def type(self) -> Optional[str]:
return self.msg["@type"] return self.msg.get("@type")
@property @property
def date(self) -> datetime: def date(self) -> datetime:
@ -145,7 +145,35 @@ class MsgProxy:
return doc["local"]["is_downloading_completed"] return doc["local"]["is_downloading_completed"]
@property @property
def reply_msg_id(self): def is_listened(self) -> Optional[bool]:
if self.type != "voice":
return None
return self.msg["content"]["is_listened"]
@is_listened.setter
def is_listened(self, value: bool):
if self.type != "voice":
return None
self.msg["content"]["is_listened"] = value
@property
def is_viewed(self) -> Optional[bool]:
if self.type != "recording":
return None
return self.msg["content"]["is_viewed"]
@is_viewed.setter
def is_viewed(self, value: bool):
if self.type != "recording":
return None
self.msg["content"]["is_viewed"] = value
@property
def msg_id(self) -> int:
return self.msg["id"]
@property
def reply_msg_id(self) -> Optional[int]:
return self.msg.get("reply_to_message_id") return self.msg.get("reply_to_message_id")
@property @property

View file

@ -5,8 +5,7 @@ from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple, cast from typing import Any, Dict, List, Optional, Tuple, cast
from tg.colors import blue, cyan, get_color, magenta, reverse, white from tg.colors import blue, cyan, get_color, magenta, reverse, white
from tg.models import MsgModel from tg.models import MsgModel, UserModel
from tg.models import UserModel
from tg.msg import MsgProxy from tg.msg import MsgProxy
from tg.utils import emoji_pattern, num, truncate_to_len from tg.utils import emoji_pattern, num, truncate_to_len
@ -420,15 +419,23 @@ def parse_content(content: Dict[str, Any]) -> str:
fields = dict( fields = dict(
name=msg.file_name, name=msg.file_name,
duration=msg.duration,
size=msg.human_size,
download=get_download(msg.local, msg.size), download=get_download(msg.local, msg.size),
size=msg.human_size,
duration=msg.duration,
listened=format_bool(msg.is_listened),
viewed=format_bool(msg.is_viewed),
) )
info = ", ".join(f"{k}={v}" for k, v in fields.items() if v) info = ", ".join(f"{k}={v}" for k, v in fields.items() if v)
return f"[{msg.content_type}: {info}]" return f"[{msg.content_type}: {info}]"
def format_bool(value: Optional[bool]) -> Optional[str]:
if value is None:
return None
return "yes" if value else "no"
def get_download(local, size): def get_download(local, size):
if local["is_downloading_completed"]: if local["is_downloading_completed"]:
return "yes" return "yes"