From 828adaf91ab7dd8b880e16df868c0f90abd668bb Mon Sep 17 00:00:00 2001 From: kirill Date: Fri, 31 Jan 2025 20:44:04 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B9=D0=BE=D0=B9=D0=BE=D0=B9=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=BA=20=D1=81=D1=8B=D1=80=D0=BE,=20=D0=BD=D0=BE=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B5=D1=81=D1=82=D1=8C?= =?UTF-8?q?=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE=D0=BD=D0=B0=D0=BB?= =?UTF-8?q?=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=B9=D0=BE=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/screens.py | 13 +++--- src/style.tcss | 5 +++ src/widgets.py | 114 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 101 insertions(+), 31 deletions(-) diff --git a/src/screens.py b/src/screens.py index ff2041e..fa10153 100644 --- a/src/screens.py +++ b/src/screens.py @@ -95,11 +95,11 @@ class ChatScreen(Screen): print("Первоначальная загрузка чатов завершена") for event in ( - events.NewMessage(), - events.MessageDeleted(), - events.MessageEdited() + events.NewMessage, + events.MessageDeleted, + events.MessageEdited ): - self.telegram_client.on(event)(self.update_chat_list) + self.telegram_client.on(event())(self.update_chat_list) def mount_chats(self, limit: int): print("Загрузка виджетов чатов...") @@ -145,7 +145,6 @@ class ChatScreen(Screen): yield Footer() with Horizontal(id="main_container"): with Horizontal(id="chats"): - yield VerticalScroll(Static(id="chat_container")) + yield VerticalScroll(id="chat_container") #TODO: сделать кнопку чтобы прогрузить больше чатов - - yield Dialog() + yield Dialog(telegram_client=self.telegram_client) diff --git a/src/style.tcss b/src/style.tcss index 80707e6..91b54e2 100644 --- a/src/style.tcss +++ b/src/style.tcss @@ -28,6 +28,11 @@ Message Container { height: auto; } +Message Static { + height: auto; + width: auto; +} + #input_place { height: 3; width: 70%; diff --git a/src/widgets.py b/src/widgets.py index bc06f02..51ac8f2 100644 --- a/src/widgets.py +++ b/src/widgets.py @@ -3,7 +3,8 @@ from textual.containers import Horizontal, Vertical, Container, VerticalScroll from textual.widget import Widget from textual.reactive import Reactive -from textual.widgets import Input, Button, Label +from textual.widgets import Input, Button, Label, Static +from telethon import TelegramClient, events class Chat(Widget): """Класс виджета чата для панели чатов""" @@ -40,34 +41,100 @@ class Chat(Widget): class Dialog(Widget): """Класс окна диалога""" - def __init__(self, id=None, classes=None, disabled=False): + def __init__( + self, + id=None, + classes=None, + disabled=None, + telegram_client: TelegramClient | None = None + ): super().__init__(id=id, classes=classes, disabled=disabled) + self.telegram_client = telegram_client + self.chat_id = -1002299818671 + self.is_msg_update_blocked = False + + async def on_mount(self): + self.limit = 30 + + self.msg_input = self.query_one("#msg_input") + self.dialog = self.query_one(Vertical).query_one("#dialog") + + self.me = await self.telegram_client.get_me() + + await self.update_dialog() + + for event in ( + events.NewMessage, + events.MessageDeleted, + events.MessageEdited + ): + self.telegram_client.on(event(chats=(self.chat_id)))\ + (self.update_dialog) + + def mount_messages(self, limit: int): + print("Загрузка виджетов сообщений...") + + msg_amount = len(self.dialog.query(Message)) + + if limit > msg_amount: + for i in range(limit - msg_amount): + self.dialog.mount(Message(id=f"msg-{i + msg_amount + 1}")) + elif limit < msg_amount: + for i in range(msg_amount - limit): + self.dialog.query(Message).last().remove() + + async def update_dialog(self, event = None): + print("Запрос обновления сообщений") + + if not self.is_msg_update_blocked: + self.is_msg_update_blocked = True + + messages = await self.telegram_client.get_messages( + entity=self.chat_id, limit=self.limit + ) + print("Получены сообщения") + + limit = len(messages) + self.mount_messages(limit) + + for i in range(limit): + chat = self.dialog.query_one(f"#msg-{i + 1}") + chat.message = str(messages[i].message) + \ + (not str(messages[i].message)) * " " + chat.is_me = messages[i].from_id == self.me.id + chat._update_styles() + + self.is_msg_update_blocked = False + print("Сообщения обновлены") + else: + print("Обновление сообщений невозможно: уже выполняется") def compose(self): with Vertical(): - with VerticalScroll(id="dialog"): - yield Message(message="привет, я ыплыжлп", is_me=True) - yield Message(message="о, дщытрапшщцрущ", is_me=False) - yield Message(message="ДАТОУШЩАРШЩУРЩША!!!!", is_me=False) - # должно быть примерно - # is_me = message.from_id == client.get_peer_id("me") - - # но я могу ошибаться, я это фиш если что - - #TODO: сделать кнопку чтобы прогрузить больше сообщений, - #но при этом чтобы при перезаходе в чат оставались - #прогруженными только 10 сообщений, - #а остальные декомпоузились - + yield VerticalScroll(id="dialog") with Horizontal(id="input_place"): yield Input(placeholder="Сообщение", id="msg_input") yield Button(label="➤", id="send", variant="primary") - def on_button_pressed(self, event): # self добавил - self.app.notify("Нажато отправить") + async def on_button_pressed(self, event = None): + await self.send_message() + + async def on_input_submitted(self, event = None): + await self.send_message() + + async def send_message(self): + await self.telegram_client.send_message( + self.chat_id, + str(self.msg_input.value) + ) + self.msg_input.value = "" + await self.update_dialog() class Message(Widget): """Класс виджета сообщений для окна диалога""" + + message = Reactive("", recompose=True) + is_me = Reactive(False, recompose=True) def __init__( self, @@ -84,18 +151,17 @@ class Message(Widget): def on_mount(self): container = self.query_one(Container) - label = container.query_one(Label) + label_border = container.query_one(".border") if self.is_me: self.styles.padding = (0, 0, 0, 15) - label.styles.text_align = "right" container.styles.align_horizontal = "right" - label.styles.border = ("solid", "#4287f5") + label_border.styles.border = ("solid", "#4287f5") else: self.styles.padding = (0, 15, 0, 0) - label.styles.text_align = "left" container.styles.align_horizontal = "left" - label.styles.border = ("solid", "#ffffff") + label_border.styles.border = ("solid", "#ffffff") def compose(self): with Container(): - yield Label(str(self.message)) + with Static(classes="border"): + yield Static(str(self.message))