my new shitty code😌

This commit is contained in:
kirill 2025-07-18 22:30:48 +03:00
parent 54704d48e3
commit 80d42fcacb
5 changed files with 137 additions and 92 deletions

View File

@ -38,7 +38,7 @@ class Talc(App):
(Keys.ControlF, "notify(\"Нажата кнопка папок\")", locale["folders"]),
(Keys.Tab, "notify(\"Нажат таб\")", locale["switch_focus"]),
(Keys.Enter, "notify(\"Нажат энтер\")", locale["enter"]),
(Keys.Escape, "notify(\"Нажат эскейп\")", locale["back"]),
(Keys.Escape, "show_start_screen()", locale["back"]),
(_character_to_key("/"), "notify(\"Нажат слэш\")", locale["search"])
]
@ -51,9 +51,11 @@ class Talc(App):
):
super().__init__(driver_class, css_path, watch_css, ansi_color)
self.locale = locale
self.title = self.locale["talc"]
self.timezone = timezone(timedelta(hours=int(UTC_OFFSET))) # type: ignore
self.CHATS_LIMIT = CHATS_LIMIT # type: ignore
self.MESSAGES_LIMIT = MESSAGES_LIMIT # type: ignore
self.msg_buffer = None
async def on_mount(self) -> None:
self.telegram_client = TelegramClient(
@ -63,8 +65,8 @@ class Talc(App):
)
await self.telegram_client.connect()
chat_screen = ChatScreen(telegram_client=self.telegram_client)
self.install_screen(chat_screen, name="chats")
self.chat_screen = ChatScreen(telegram_client=self.telegram_client)
self.install_screen(self.chat_screen, name="chats")
if not await self.telegram_client.is_user_authorized():
auth_screen = AuthScreen(telegram_client=self.telegram_client)
@ -75,6 +77,9 @@ class Talc(App):
self.scroll_sensitivity_y = 1.0
def show_start_screen(self) -> None:
self.chat_screen.switcher.current = "start_label"
async def on_exit_app(self):
await self.telegram_client.disconnect()
return super()._on_exit_app()

View File

@ -1,3 +1,3 @@
codes = ["auth_greeting", "phone_number", "code", "password", "you", "mention", "media", "message", "folders", "switch_focus", "enter", "back", "search", "start_converse"]
ru = ["Добро пожаловать в Тальк", "Номер телефона", "Код", "Пароль", "Вы", "Вас упомянули", "Медиа", "Сообщение", "Папки", "Переключение фокуса", "Открыть", "Назад", "Поиск", "Нажмите на чат в панели слева, чтобы начать общаться"]
en = ["Welcome to Talc", "Phone number", "Code", "Password", "You", "You got mentioned", "Media", "Message", "Folders", "Switch focus", "Enter", "Back", "Search", "Click on the chat to start conversation"]
codes = ["auth_greeting", "phone_number", "code", "password", "you", "mention", "media", "message", "folders", "switch_focus", "enter", "back", "search", "start_converse", "talc"]
ru = ["Добро пожаловать в Тальк", "Номер телефона", "Код", "Пароль", "Вы", "Вас упомянули", "Медиа", "Сообщение", "Папки", "Переключение фокуса", "Открыть", "Назад", "Поиск", "Нажмите на чат в панели слева, чтобы начать общаться", "Тальк"]
en = ["Welcome to Talc", "Phone number", "Code", "Password", "You", "You got mentioned", "Media", "Message", "Folders", "Switch focus", "Enter", "Back", "Search", "Click on the chat to start conversation", "Talc"]

View File

@ -4,11 +4,12 @@ from textual.screen import Screen
from textual.widgets import Label, Input, Footer, Static, ContentSwitcher
from textual.containers import Vertical, Horizontal, VerticalScroll
from textual.app import ComposeResult
from textual.css.query import NoMatches
from telethon.errors import SessionPasswordNeededError
from telethon.utils import get_display_name
from telethon import TelegramClient, events
from src.widgets import Chat
from os import system, getenv
from telethon.utils import get_display_name
class AuthScreen(Screen):
"""Класс экрана логина в аккаунт"""
@ -131,7 +132,10 @@ class ChatScreen(Screen):
if limit > chats_amount:
# Маунт недостающих, если чатов меньше, чем нужно
for i in range(limit - chats_amount):
chat = Chat(id=f"chat-{i + chats_amount + 1}")
chat = Chat(
id = f"chat-{i + chats_amount + 1}",
number = i + chats_amount + 1
)
self.chat_container.mount(chat)
elif limit < chats_amount:
# Удаление лишних, если чатов больше, чем нужно
@ -142,7 +146,7 @@ class ChatScreen(Screen):
print("Виджеты чатов загружены")
async def update_chat_list(self, event = None) -> None:
"""Функция обновления чатов (и уведомления)"""
"""Функция обновления чатов"""
print("Запрос обновления чатов")
if not self.is_chat_update_blocked:
@ -159,13 +163,18 @@ class ChatScreen(Screen):
# Изменение надписей в виджетах чатов
for i in range(limit):
chat = self.chat_container.query_one(f"#chat-{i + 1}")
chat = self.chat_container.query(".chat")[i]
chat.peername = str(dialogs[i].name)
chat.is_group = dialogs[i].is_group
chat.is_channel = dialogs[i].is_channel
chat.peer_id = dialogs[i].id
if not (self.switcher.current in ("start_label")) \
and chat.peer_id == int(self.switcher.current[7:]):
self.remove_chat_lint()
chat.add_class("selected_chat")
try:
is_my_msg = \
dialogs[i].message.from_id.user_id == self.me_id
@ -187,20 +196,12 @@ class ChatScreen(Screen):
else:
chat.msg = str(dialogs[i].message.message)
if self.switcher.current is not None:
current_dialog = \
self.switcher.query_one(f"#{self.switcher.current}")
if chat.peer_id == int(current_dialog.id[7:]):
chat.add_class("selected_chat")
else:
chat.remove_class("selected_chat")
self.is_chat_update_blocked = False
print("Чаты обновлены")
else:
print("Обновление чатов невозможно: уже выполняется")
if self.switcher.current is not None:
if not (self.switcher.current in ("start_label")):
current_dialog = \
self.switcher.query_one(f"#{self.switcher.current}")
await current_dialog.update_dialog()
@ -211,16 +212,27 @@ class ChatScreen(Screen):
if int(self.DO_NOTIFY) and not self.app.focused and event.mentioned:
system(f"notify-send \"{self.locale["mention"]}\" Talc")
def remove_chat_lint(self) -> None:
try:
self.chat_container.query_one(".selected_chat")\
.remove_class("selected_chat")
except NoMatches:
pass
def compose(self) -> ComposeResult:
yield Footer() # Нижняя панель с подсказками
with Horizontal(id="main_container"): # Основной контейнер
with Horizontal(id="chats"):
yield VerticalScroll(id="chat_container")
yield VerticalScroll(
id="chat_container",
can_focus = False,
can_focus_children = True
)
#TODO: сделать кнопку, чтобы прогрузить больше чатов,
# или ленивую прокрутку
yield ContentSwitcher(id="dialog_switcher")
with ContentSwitcher(id="dialog_switcher", initial="start_label"):
# ↑ Внутри него как раз крутятся диалоги
#yield Label(
# self.locale["start_converse"],
# id="start_converse_label"
#) #TODO: не показывается надпись, надо будет исправить
yield Label(
self.locale["start_converse"],
id="start_label"
)

View File

@ -74,12 +74,13 @@ ContentSwitcher {
height: 100%;
}
#start_converse_label {
width: 100%;
#start_label {
width: 70%;
height: 100%;
text-align: center;
content-align: center middle;
color: $panel;
padding: 3;
}
TopBar {

View File

@ -7,7 +7,7 @@ from textual.widgets import Input, Button, Label, Static, ContentSwitcher
from textual.app import ComposeResult, RenderResult
from textual.content import Content
from textual.style import Style
from telethon import TelegramClient, events, utils, types
from telethon import TelegramClient, utils, types
class Chat(Widget):
"""Класс виджета чата для панели чатов"""
@ -21,9 +21,10 @@ class Chat(Widget):
def __init__(
self,
number: int,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
classes: str = "chat",
disabled: bool = False
) -> None:
super().__init__(
@ -32,24 +33,24 @@ class Chat(Widget):
classes=classes,
disabled=disabled
)
self.number = number
def on_mount(self) -> None:
self.switcher = self.screen.query_one(Horizontal)\
.query_one("#dialog_switcher", ContentSwitcher)
if int(self.id[5:]) % 2 != 0:
if self.number % 2 != 0:
self.add_class("odd")
else:
self.add_class("even")
def on_click(self) -> None:
async def on_click(self) -> None:
# Получение ID диалога и создание DOM-ID на его основе
dialog_id = f"dialog-{str(self.peer_id)}"
dialog_id = f"dialog-{self.peer_id}"
# Маунт диалога
try:
self.switcher.mount(Dialog(
telegram_client=self.app.telegram_client,
chat_id=self.peer_id,
id=dialog_id,
is_channel=self.is_channel and not self.is_group
@ -59,6 +60,8 @@ class Chat(Widget):
pass
self.switcher.current = dialog_id
self.screen.remove_chat_lint()
self.add_class("selected_chat")
self.switcher.recompose()
def compose(self) -> ComposeResult:
@ -75,15 +78,14 @@ class Dialog(Widget):
def __init__(
self,
id=None,
classes=None,
disabled=None,
telegram_client: TelegramClient | None = None,
id = None,
classes = None,
disabled = None,
chat_id: int | None = None,
is_channel: bool | None = None
) -> None:
super().__init__(id=id, classes=classes, disabled=disabled)
self.telegram_client = telegram_client
self.telegram_client: TelegramClient = self.app.telegram_client
self.chat_id = chat_id
self.is_msg_update_blocked = False
self.timezone = self.app.timezone
@ -103,8 +105,6 @@ class Dialog(Widget):
await self.update_dialog()
#self.dialog.scroll_down(animate=False, immediate=True)
def mount_messages(self, limit: int) -> None:
print("Загрузка виджетов сообщений...")
@ -116,6 +116,7 @@ class Dialog(Widget):
Message(id=f"msg-{i + msg_amount + 1}"),
before=0
)
self.dialog.scroll_end()
elif limit < msg_amount:
for i in range(msg_amount - limit):
self.dialog.query(Message).last().remove()
@ -137,9 +138,8 @@ class Dialog(Widget):
for i in range(limit):
msg = self.dialog.query_one(f"#msg-{i + 1}")
message = Content(str(messages[i].message))
if str(messages[i].message):
entities = messages[i].entities
if entities:
if entities != None:
for entity in entities:
match type(entity):
case types.MessageEntityBold:
@ -187,6 +187,7 @@ class Dialog(Widget):
.date\
.astimezone(self.timezone)\
.strftime("%H:%M")
msg.msg_obj = messages[i]
self.top_bar.peername = utils.get_display_name(
await self.telegram_client.get_entity(self.chat_id)
@ -197,6 +198,29 @@ class Dialog(Widget):
else:
print("Обновление сообщений невозможно: уже выполняется")
async def on_button_pressed(self, event = None) -> None:
await self.send_message()
async def on_input_submitted(self, event = None) -> None:
await self.send_message()
async def send_message(self) -> None:
if self.app.msg_buffer is not None:
await self.telegram_client.forward_messages(
self.chat_id,
self.app.msg_buffer
)
self.app.msg_buffer = None
try:
await self.telegram_client.send_message(
self.chat_id,
str(self.msg_input.value)
)
except ValueError:
print("Ошибка отправки")
self.msg_input.value = ""
await self.update_dialog()
def compose(self) -> ComposeResult:
with Vertical():
yield TopBar()
@ -209,23 +233,6 @@ class Dialog(Widget):
)
yield Button(label="", id="send", variant="primary")
async def on_button_pressed(self, event = None) -> None:
await self.send_message()
async def on_input_submitted(self, event = None) -> None:
await self.send_message()
async def send_message(self) -> None:
try:
await self.telegram_client.send_message(
self.chat_id,
str(self.msg_input.value)
)
except ValueError:
print("Ошибка отправки")
self.msg_input.value = ""
await self.update_dialog()
class Message(Widget):
"""Класс виджета сообщений для окна диалога"""
@ -234,13 +241,18 @@ class Message(Widget):
username: reactive[str] = reactive("", recompose=True)
info: reactive[str] = reactive("", recompose=True)
def __init__(self, id=None) -> None:
def __init__(self, id = None) -> None:
super().__init__(id=id)
def on_click(self, event):
if event.chain == 2:
self.app.msg_buffer = self.msg_obj
self.app.notify("Сообщение в буфере.")
def compose(self) -> ComposeResult:
label = Label(self.message, markup=False)
label.border_title = self.username * (not self.is_me)
label.border_subtitle = self.info
label.border_title = Content(self.username * (not self.is_me))
label.border_subtitle = Content(self.info)
with Container():
yield label
@ -255,7 +267,22 @@ class TopBar(Widget):
peername: reactive[str] = reactive(" ", recompose=True)
def __init__(self):
super().__init__()
self.telegram_client: TelegramClient = self.app.telegram_client
def on_click(self, event = None) -> None:
"""Обработка нажатия"""
"""pic = self.telegram_client.download_profile_photo(
self.screen.query_one(Horizontal)\
.query_one("#dialog_switcher", ContentSwitcher)\
.query_one(f"#{self.screen.query_one(Horizontal)\
.query_one("#dialog_switcher", ContentSwitcher).current}").chat_id
)
system(f"echo \"{pic}\" > picture.txt")""" # Debug штучка
def compose(self) -> ComposeResult:
with Horizontal():
yield Label(self.peername[:1], classes="avatar")
yield Label(self.peername, classes="peername_top_bar")
yield Label(self.peername[:1], classes="avatar", markup=False)
yield Label(self.peername, classes="peername_top_bar", markup=False)