mirror of
https://github.com/avitoras/telegram-tui.git
synced 2025-07-27 11:20:31 +00:00
Что-то поменял обратно, тем не менее, спасибо контрибьюторам
This commit is contained in:
parent
c01d5954dc
commit
e523fce7bd
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,3 +5,5 @@ __pycache__
|
||||
*/__pycache__
|
||||
tokens.py
|
||||
.env
|
||||
.venv
|
||||
.python-version
|
||||
|
@ -38,5 +38,5 @@ cp .env.example .env
|
||||
## Запуск
|
||||
|
||||
```bash
|
||||
python src/app.py
|
||||
./main.py
|
||||
```
|
||||
|
@ -9,8 +9,11 @@ from rich.console import Console
|
||||
from src.screens import AuthScreen, ChatScreen
|
||||
|
||||
# Настройка консоли для корректной работы с Unicode
|
||||
"""
|
||||
console = Console(force_terminal=True, color_system="auto")
|
||||
sys.stdout = console
|
||||
"""
|
||||
# спойлер: не помогло
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@ -33,7 +36,6 @@ class TelegramTUI(App):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.console = console
|
||||
|
||||
async def on_mount(self) -> None:
|
||||
self.telegram_client = TelegramClient("user", api_id, api_hash)
|
||||
@ -52,3 +54,6 @@ class TelegramTUI(App):
|
||||
async def on_exit_app(self):
|
||||
await self.telegram_client.disconnect()
|
||||
return super()._on_exit_app()
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise Exception("Запущен не тот файл. Запустите main.py.")
|
||||
|
@ -8,6 +8,7 @@ from telethon.errors import SessionPasswordNeededError
|
||||
from telethon import TelegramClient, events
|
||||
from src.widgets import Dialog, Chat, normalize_text
|
||||
from textual import log
|
||||
from textual.keys import Keys, _character_to_key
|
||||
|
||||
class AuthScreen(Screen):
|
||||
"""Класс экрана логина в аккаунт"""
|
||||
@ -63,6 +64,13 @@ class AuthScreen(Screen):
|
||||
class ChatScreen(Screen):
|
||||
"""Класс экрана чатов, он же основной экран приложения"""
|
||||
|
||||
BINDINGS = [
|
||||
(Keys.Tab, "log(\"Нажат таб\")", "Переключение фокуса"),
|
||||
(Keys.Enter, "log(\"Нажат энтер\")", "Открыть"),
|
||||
(Keys.Escape, "log(\"Нажат эскейп\")", "Назад"),
|
||||
(_character_to_key("/"), "log(\"Нажат слэш\")", "Поиск")
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name = None,
|
||||
@ -86,7 +94,6 @@ class ChatScreen(Screen):
|
||||
.query_one("#chat_container")
|
||||
|
||||
self.search_input = self.query_one("#search_input")
|
||||
self.help_label = self.query_one("#help_label")
|
||||
|
||||
log("Первоначальная загрузка виджетов чатов...")
|
||||
self.mount_chats(
|
||||
@ -140,7 +147,8 @@ class ChatScreen(Screen):
|
||||
if self.search_query:
|
||||
dialogs = [
|
||||
d for d in dialogs
|
||||
if self.search_query.lower() in normalize_text(d.name).lower()
|
||||
if self.search_query.lower() in \
|
||||
normalize_text(d.name).lower()
|
||||
]
|
||||
|
||||
limit = len(dialogs)
|
||||
@ -152,7 +160,8 @@ class ChatScreen(Screen):
|
||||
chat.msg = normalize_text(str(dialogs[i].message.message))
|
||||
chat.peer_id = dialogs[i].id
|
||||
chat.is_selected = (i == self.selected_chat_index)
|
||||
chat.is_focused = (self.focused_element == "chat_list" and i == self.selected_chat_index)
|
||||
chat.is_focused = (self.focused_element == "chat_list" and \
|
||||
i == self.selected_chat_index)
|
||||
|
||||
self.is_chat_update_blocked = False
|
||||
log("Чаты обновлены")
|
||||
@ -166,7 +175,7 @@ class ChatScreen(Screen):
|
||||
self.update_chat_list()
|
||||
|
||||
def on_key(self, event: Key) -> None:
|
||||
if event.key == "tab":
|
||||
if event.key == Keys.Tab:
|
||||
# Переключаем фокус между элементами
|
||||
if self.focused_element == "search":
|
||||
self.focused_element = "chat_list"
|
||||
@ -185,7 +194,8 @@ class ChatScreen(Screen):
|
||||
if not chats:
|
||||
return
|
||||
|
||||
if event.key == "up":
|
||||
match event.key:
|
||||
case Keys.Up:
|
||||
self.selected_chat_index = max(0, self.selected_chat_index - 1)
|
||||
for i, chat in enumerate(chats):
|
||||
chat.is_selected = (i == self.selected_chat_index)
|
||||
@ -193,7 +203,7 @@ class ChatScreen(Screen):
|
||||
# Прокручиваем к выбранному чату
|
||||
selected_chat = chats[self.selected_chat_index]
|
||||
self.chat_container.scroll_to(selected_chat, animate=False)
|
||||
elif event.key == "down":
|
||||
case Keys.Down:
|
||||
self.selected_chat_index = min(len(chats) - 1, self.selected_chat_index + 1)
|
||||
for i, chat in enumerate(chats):
|
||||
chat.is_selected = (i == self.selected_chat_index)
|
||||
@ -201,13 +211,13 @@ class ChatScreen(Screen):
|
||||
# Прокручиваем к выбранному чату
|
||||
selected_chat = chats[self.selected_chat_index]
|
||||
self.chat_container.scroll_to(selected_chat, animate=False)
|
||||
elif event.key == "enter":
|
||||
case Keys.Enter:
|
||||
chats[self.selected_chat_index].on_click()
|
||||
elif event.key == "escape":
|
||||
case Keys.Escape:
|
||||
# Возвращаемся к списку чатов
|
||||
self.app.pop_screen()
|
||||
self.app.push_screen("chats")
|
||||
elif event.key == "/":
|
||||
case "/": #Не работает: нужен кейкод слэша
|
||||
# Фокус на поиск
|
||||
self.focused_element = "search"
|
||||
self.search_input.focus()
|
||||
@ -217,12 +227,10 @@ class ChatScreen(Screen):
|
||||
yield Footer()
|
||||
with Horizontal(id="main_container"):
|
||||
with Vertical(id="chats"):
|
||||
yield Label(
|
||||
"Навигация: Tab - переключение фокуса, ↑↓ - выбор чата, Enter - открыть, Esc - назад, / - поиск",
|
||||
id="help_label",
|
||||
classes="help-text"
|
||||
)
|
||||
yield Input(placeholder=normalize_text("Поиск чатов..."), id="search_input")
|
||||
yield VerticalScroll(id="chat_container")
|
||||
yield ContentSwitcher(id="dialog_switcher")
|
||||
#yield Dialog(telegram_client=self.telegram_client)
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise Exception("Запущен не тот файл. Запустите main.py.")
|
||||
|
@ -13,8 +13,9 @@ import emoji
|
||||
import os
|
||||
import tempfile
|
||||
from PIL import Image
|
||||
import pywhatkit as kit
|
||||
#import pywhatkit as kit
|
||||
from textual import log
|
||||
from warnings import deprecated
|
||||
|
||||
def remove_emoji(text: str) -> str:
|
||||
"""Удаляет эмодзи из текста"""
|
||||
@ -29,11 +30,12 @@ def normalize_text(text: str) -> str:
|
||||
# Удаляем эмодзи
|
||||
text = remove_emoji(text)
|
||||
# Удаляем все управляющие символы
|
||||
text = ''.join(char for char in text if unicodedata.category(char)[0] != 'C')
|
||||
text = ''\
|
||||
.join(char for char in text if unicodedata.category(char)[0] != 'C')
|
||||
# Нормализуем Unicode
|
||||
text = unicodedata.normalize('NFKC', text)
|
||||
# Заменяем специальные символы на их ASCII-эквиваленты
|
||||
text = text.replace('—', '-').replace('–', '-').replace('…', '...')
|
||||
text = text.replace('—', '-').replace('–', '-')
|
||||
# Удаляем все непечатаемые символы
|
||||
text = ''.join(char for char in text if char.isprintable())
|
||||
return text
|
||||
@ -47,6 +49,7 @@ def safe_ascii(text: str) -> str:
|
||||
# Оставляем только ASCII символы и пробелы
|
||||
return ''.join(char for char in text if ord(char) < 128 or char.isspace())
|
||||
|
||||
@deprecated("Не работает на моём компьютере.")
|
||||
def convert_image_to_ascii(image_path: str, width: int = 50) -> str:
|
||||
"""Конвертирует изображение в ASCII-арт"""
|
||||
try:
|
||||
@ -123,11 +126,21 @@ class Chat(Widget):
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Horizontal(classes="chat-item"):
|
||||
"""
|
||||
# Используем ASCII-символы для рамки
|
||||
yield Label(f"+---+\n| {safe_ascii(self.username[:1].upper()):1} |\n+---+")
|
||||
yield Label(
|
||||
f"┌───┐\n│ {normalize_text(
|
||||
self.username[:1].upper()
|
||||
):1} │\n└───┘"
|
||||
)
|
||||
with Vertical():
|
||||
yield Label(normalize_text(self.username), id="name")
|
||||
yield Label(normalize_text(self.msg), id="last_msg")
|
||||
"""
|
||||
yield Label(f"┌───┐\n│ {self.username[:1].upper():1} │\n└───┘")
|
||||
with Vertical():
|
||||
yield Label(self.username, id="name")
|
||||
yield Label(self.msg, id="last_msg")
|
||||
|
||||
def on_mouse_enter(self) -> None:
|
||||
self.add_class("hover")
|
||||
@ -324,3 +337,6 @@ class Message(Widget):
|
||||
self.classes = "is_me_true"
|
||||
else:
|
||||
self.classes = "is_me_false"
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise Exception("Запущен не тот файл. Запустите main.py.")
|
||||
|
Loading…
x
Reference in New Issue
Block a user