Merge pull request #8 from avitoras/fish_dev

попа
This commit is contained in:
avitoras 2025-01-21 21:23:28 +03:00 committed by GitHub
commit 0949294da0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 205 additions and 99 deletions

0
app/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

50
app/app.py Normal file
View File

@ -0,0 +1,50 @@
from telethon import TelegramClient, events
from textual.app import App, ComposeResult
from textual.containers import Horizontal, VerticalScroll, Vertical, Container
from textual.widgets import Placeholder, Label, Static, Input, Button
from widgets.chat import Chat
from widgets.dialog import Dialog
from telegram.client import TelegramClientWrapper
from tokens import api_id, api_hash
class TelegramTUI(App):
CSS_PATH = "../tcss/style.tcss"
def __init__(self):
super().__init__()
self.telegram_client = TelegramClientWrapper(api_id, api_hash, self.update_chat_list)
async def on_mount(self) -> None:
self.chat_container = self.query_one("#main_container").query_one("#chats").query_one("#chat_container")
self.limit = 25
for i in range(self.limit):
chat = Chat(id=f"chat-{i + 1}")
self.chat_container.mount(chat)
await self.telegram_client.connect()
# TODO: скоро сюда переедет маунт чатов из функции on_mount
def mount_chats(self):
pass
async def update_chat_list(self):
dialogs = await self.telegram_client.get_dialogs(limit=self.limit)
for i in range(len(dialogs)):
chat = self.chat_container.query_one(f"#chat-{i + 1}")
chat.username = str(dialogs[i].name)
chat.msg = str(dialogs[i].message.message)
chat.peer_id = dialogs[i].id
#self.notify("Новое сообщение") #колхоз дебаг
def compose(self) -> ComposeResult:
with Horizontal(id="main_container"):
with Horizontal(id="chats"):
yield VerticalScroll(Static(id="chat_container"))
yield Dialog()
async def on_exit_app(self):
await self.telegram_client.disconnect()
return super()._on_exit_app()

82
main.py
View File

@ -1,81 +1,5 @@
from telethon import TelegramClient, events, sync, utils
from textual.app import App, ComposeResult
from textual.widgets import Placeholder, Label, Static, Rule
from textual.containers import Horizontal, VerticalScroll, Vertical
from textual.reactive import var
from textual.widget import Widget
from tokens import api_id, api_hash
class Chat(Widget):
"""Кастомный виджет чата слева"""
def __init__(self, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False):
super().__init__(name=name, id=id, classes=classes, disabled=disabled)
def _on_click(self):
pass
def compose(self) -> ComposeResult:
with Horizontal():
yield Label(f"┌───┐\n{self.name[:1]}\n└───┘")
with Vertical():
yield Label(self.name, id="name")
#yield Label(self.user.dialog[-1].text)
class TelegramTUI(App):
CSS_PATH = "styles.tcss"
def __init__(self):
super().__init__()
self.api_id = api_id
self.api_hash = api_hash
self.client = TelegramClient('user', api_id, api_hash)
self.chats = var([])
async def on_mount(self) -> None:
await self.client.start()
dialogs = []
async for dialog in self.client.iter_dialogs():
dialogs.append(dialog)
self.chats = dialogs
await self.update_chat_list()
async def update_chat_list(self):
#if self.chats:
#for dialog in self.chats:
# name = utils.get_display_name(dialog.entity)
# last_msg = "" # Значение по умолчанию
# try:
# last_messages = await self.client.get_messages(dialog.entity, limit=1)
# if last_messages:
# last_msg = last_messages[0].message # Получаем текст последнего сообщения
# except Exception as e: # Добавлена обработка ошибок
# print(f"Ошибка получения последнего сообщения: {e}")
chat_container = self.query_one("#main_container").query_one("#chats").query_one("#chat_container")
chat_container.query(Chat).remove() # Clear existing labels
for dialog in self.chats:
name = utils.get_display_name(dialog.entity)
#msg = utils.get_input_peer
chat = Chat(name, id=f"chat-{dialog.id}")
chat_container.mount(chat)
def compose(self) -> ComposeResult:
with Horizontal(id="main_container"):
with Horizontal(id="chats"):
yield VerticalScroll(*[Static(id="chat_container")])
yield Rule("vertical")
with VerticalScroll(id="dialog"):
yield Placeholder(label="message", classes=("message"))
yield Placeholder(label="message", classes=("message"))
yield Placeholder(label="message", classes=("message"))
yield Placeholder(label="message", classes=("message"))
yield Placeholder(label="message", classes=("message"))
from app.app import TelegramTUI
if __name__ == "__main__":
app = TelegramTUI()
app.run()
tg = TelegramTUI()
tg.run()

View File

@ -1,20 +0,0 @@
#chats {
width: 30%;
}
#dialog {
width: 70%;
}
Chat {
height: 3;
}
Rule {
color: #FFFFFF;
}
.message {
height: 3;
padding: 1;
}

43
tcss/style.tcss Normal file
View File

@ -0,0 +1,43 @@
#chats {
width: 30%;
}
#dialog {
width: 70%;
}
Chat {
height: 3;
}
Rule {
color: #FFFFFF;
}
.message {
height: 3;
padding: 1;
}
Message {
height: auto;
width: auto;
}
Message Container {
height: auto;
}
#input_place {
height: 3;
width: 70%;
align-horizontal: center;
}
#msg_input {
width: 65%;
}
#send {
}

0
telegram/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

34
telegram/client.py Normal file
View File

@ -0,0 +1,34 @@
from telethon import TelegramClient, events, utils
class TelegramClientWrapper:
def __init__(self, api_id, api_hash, message_handler):
self.client = TelegramClient('user', api_id, api_hash)
#self.client.add_event_handler(message_handler, events.NewMessage())
self.client.on(events.NewMessage())(message_handler)
#ни то ни то не работает, костя спаси
async def connect(self):
await self.client.start()
async def disconnect(self):
await self.client.disconnect()
async def get_dialogs(self, limit=10):
dialogs_list = []
async for dialog in self.client.iter_dialogs(limit=limit):
dialogs_list.append(dialog)
return [self._map_dialog(d) for d in dialogs_list]
def _map_dialog(self, dialog):
return DialogInfo(
id=dialog.id,
name=utils.get_display_name(dialog.entity),
message=dialog.message
)
class DialogInfo:
def __init__(self, id, name, message):
self.id = id
self.name = name
self.message = message

2
tokens.py Normal file
View File

@ -0,0 +1,2 @@
api_hash = 111
api_id = 11

0
widgets/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

22
widgets/chat.py Normal file
View File

@ -0,0 +1,22 @@
from textual.widgets import Label
from textual.containers import Horizontal, Vertical
from textual.widget import Widget
from textual.reactive import Reactive
class Chat(Widget):
username = Reactive(" ", recompose=True)
msg = Reactive(" ", recompose=True)
peer_id = Reactive(0)
def __init__(self, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False):
super().__init__(name=str(name), id=id, classes=classes, disabled=disabled)
def _on_click(self):
self.msg = str(self.peer_id)
def compose(self):
with Horizontal():
yield Label(f"┌───┐\n{self.username[:1]}\n└───┘")
with Vertical():
yield Label(self.username, id="name")
yield Label(self.msg, id="last_msg")

24
widgets/dialog.py Normal file
View File

@ -0,0 +1,24 @@
from textual.widgets import Input, Button, Label
from textual.containers import Horizontal, VerticalScroll, Vertical
from textual.widget import Widget
from widgets.message import Message
class Dialog(Widget):
def __init__(self, id=None, classes=None, disabled=False):
super().__init__(id=id, classes=classes, disabled=disabled)
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")
# но я могу ошибаться, я это фиш если что
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("Нажато отправить")

27
widgets/message.py Normal file
View File

@ -0,0 +1,27 @@
from textual.widgets import Label
from textual.containers import Container
from textual.widget import Widget
class Message(Widget):
def __init__(self, name=None, message=None, is_me=None, id=None, classes=None, disabled=False):
super().__init__(name=name, id=id, classes=classes, disabled=disabled)
self.message = message
self.is_me = is_me
def on_mount(self):
container = self.query_one(Container)
label = container.query_one(Label)
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")
else:
self.styles.padding = (0, 15, 0, 0)
label.styles.text_align = "left"
container.styles.align_horizontal = "left"
label.styles.border = ("solid", "#ffffff")
def compose(self):
with Container():
yield Label(str(self.message))