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.ControlF, "notify(\"Нажата кнопка папок\")", locale["folders"]),
(Keys.Tab, "notify(\"Нажат таб\")", locale["switch_focus"]), (Keys.Tab, "notify(\"Нажат таб\")", locale["switch_focus"]),
(Keys.Enter, "notify(\"Нажат энтер\")", locale["enter"]), (Keys.Enter, "notify(\"Нажат энтер\")", locale["enter"]),
(Keys.Escape, "notify(\"Нажат эскейп\")", locale["back"]), (Keys.Escape, "show_start_screen()", locale["back"]),
(_character_to_key("/"), "notify(\"Нажат слэш\")", locale["search"]) (_character_to_key("/"), "notify(\"Нажат слэш\")", locale["search"])
] ]
@ -51,9 +51,11 @@ class Talc(App):
): ):
super().__init__(driver_class, css_path, watch_css, ansi_color) super().__init__(driver_class, css_path, watch_css, ansi_color)
self.locale = locale self.locale = locale
self.title = self.locale["talc"]
self.timezone = timezone(timedelta(hours=int(UTC_OFFSET))) # type: ignore self.timezone = timezone(timedelta(hours=int(UTC_OFFSET))) # type: ignore
self.CHATS_LIMIT = CHATS_LIMIT # type: ignore self.CHATS_LIMIT = CHATS_LIMIT # type: ignore
self.MESSAGES_LIMIT = MESSAGES_LIMIT # type: ignore self.MESSAGES_LIMIT = MESSAGES_LIMIT # type: ignore
self.msg_buffer = None
async def on_mount(self) -> None: async def on_mount(self) -> None:
self.telegram_client = TelegramClient( self.telegram_client = TelegramClient(
@ -63,8 +65,8 @@ class Talc(App):
) )
await self.telegram_client.connect() await self.telegram_client.connect()
chat_screen = ChatScreen(telegram_client=self.telegram_client) self.chat_screen = ChatScreen(telegram_client=self.telegram_client)
self.install_screen(chat_screen, name="chats") self.install_screen(self.chat_screen, name="chats")
if not await self.telegram_client.is_user_authorized(): if not await self.telegram_client.is_user_authorized():
auth_screen = AuthScreen(telegram_client=self.telegram_client) auth_screen = AuthScreen(telegram_client=self.telegram_client)
@ -75,6 +77,9 @@ class Talc(App):
self.scroll_sensitivity_y = 1.0 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): async def on_exit_app(self):
await self.telegram_client.disconnect() await self.telegram_client.disconnect()
return super()._on_exit_app() 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"] codes = ["auth_greeting", "phone_number", "code", "password", "you", "mention", "media", "message", "folders", "switch_focus", "enter", "back", "search", "start_converse", "talc"]
ru = ["Добро пожаловать в Тальк", "Номер телефона", "Код", "Пароль", "Вы", "Вас упомянули", "Медиа", "Сообщение", "Папки", "Переключение фокуса", "Открыть", "Назад", "Поиск", "Нажмите на чат в панели слева, чтобы начать общаться"] 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"] 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.widgets import Label, Input, Footer, Static, ContentSwitcher
from textual.containers import Vertical, Horizontal, VerticalScroll from textual.containers import Vertical, Horizontal, VerticalScroll
from textual.app import ComposeResult from textual.app import ComposeResult
from textual.css.query import NoMatches
from telethon.errors import SessionPasswordNeededError from telethon.errors import SessionPasswordNeededError
from telethon.utils import get_display_name
from telethon import TelegramClient, events from telethon import TelegramClient, events
from src.widgets import Chat from src.widgets import Chat
from os import system, getenv from os import system, getenv
from telethon.utils import get_display_name
class AuthScreen(Screen): class AuthScreen(Screen):
"""Класс экрана логина в аккаунт""" """Класс экрана логина в аккаунт"""
@ -131,7 +132,10 @@ class ChatScreen(Screen):
if limit > chats_amount: if limit > chats_amount:
# Маунт недостающих, если чатов меньше, чем нужно # Маунт недостающих, если чатов меньше, чем нужно
for i in range(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) self.chat_container.mount(chat)
elif limit < chats_amount: elif limit < chats_amount:
# Удаление лишних, если чатов больше, чем нужно # Удаление лишних, если чатов больше, чем нужно
@ -142,7 +146,7 @@ class ChatScreen(Screen):
print("Виджеты чатов загружены") print("Виджеты чатов загружены")
async def update_chat_list(self, event = None) -> None: async def update_chat_list(self, event = None) -> None:
"""Функция обновления чатов (и уведомления)""" """Функция обновления чатов"""
print("Запрос обновления чатов") print("Запрос обновления чатов")
if not self.is_chat_update_blocked: if not self.is_chat_update_blocked:
@ -159,13 +163,18 @@ class ChatScreen(Screen):
# Изменение надписей в виджетах чатов # Изменение надписей в виджетах чатов
for i in range(limit): 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.peername = str(dialogs[i].name)
chat.is_group = dialogs[i].is_group chat.is_group = dialogs[i].is_group
chat.is_channel = dialogs[i].is_channel chat.is_channel = dialogs[i].is_channel
chat.peer_id = dialogs[i].id 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: try:
is_my_msg = \ is_my_msg = \
dialogs[i].message.from_id.user_id == self.me_id dialogs[i].message.from_id.user_id == self.me_id
@ -187,20 +196,12 @@ class ChatScreen(Screen):
else: else:
chat.msg = str(dialogs[i].message.message) 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 self.is_chat_update_blocked = False
print("Чаты обновлены") print("Чаты обновлены")
else: else:
print("Обновление чатов невозможно: уже выполняется") print("Обновление чатов невозможно: уже выполняется")
if self.switcher.current is not None: if not (self.switcher.current in ("start_label")):
current_dialog = \ current_dialog = \
self.switcher.query_one(f"#{self.switcher.current}") self.switcher.query_one(f"#{self.switcher.current}")
await current_dialog.update_dialog() 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: if int(self.DO_NOTIFY) and not self.app.focused and event.mentioned:
system(f"notify-send \"{self.locale["mention"]}\" Talc") 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: def compose(self) -> ComposeResult:
yield Footer() # Нижняя панель с подсказками yield Footer() # Нижняя панель с подсказками
with Horizontal(id="main_container"): # Основной контейнер with Horizontal(id="main_container"): # Основной контейнер
with Horizontal(id="chats"): with Horizontal(id="chats"):
yield VerticalScroll(id="chat_container") yield VerticalScroll(
id="chat_container",
can_focus = False,
can_focus_children = True
)
#TODO: сделать кнопку, чтобы прогрузить больше чатов, #TODO: сделать кнопку, чтобы прогрузить больше чатов,
# или ленивую прокрутку # или ленивую прокрутку
yield ContentSwitcher(id="dialog_switcher") with ContentSwitcher(id="dialog_switcher", initial="start_label"):
# ↑ Внутри него как раз крутятся диалоги # ↑ Внутри него как раз крутятся диалоги
#yield Label( yield Label(
# self.locale["start_converse"], self.locale["start_converse"],
# id="start_converse_label" id="start_label"
#) #TODO: не показывается надпись, надо будет исправить )

View File

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

View File

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