From 6845ee69bf4df083fd47f3810ea27527df79bc76 Mon Sep 17 00:00:00 2001 From: Mikhail Kilin Date: Fri, 6 Feb 2026 16:57:27 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20trim=20CONTEXT.md=20and=20ROADMAP.md=20?= =?UTF-8?q?(3006=E2=86=92246=20lines,=20-92%)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completed phases condensed to summary tables, detailed history removed (available in git log). Detailed plans kept only for upcoming phases 11 (images) and 12 (voice messages). Co-Authored-By: Claude Opus 4.6 --- CONTEXT.md | 2343 ++-------------------------------------------------- ROADMAP.md | 581 +------------ 2 files changed, 90 insertions(+), 2834 deletions(-) diff --git a/CONTEXT.md b/CONTEXT.md index 4bb82db..d8b13cf 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -1,2316 +1,71 @@ # Текущий контекст проекта -## Статус: Фаза 13 — ПОЛНОСТЬЮ ЗАВЕРШЕНА (Этапы 1-7) ✅ +## Статус: Фазы 1-10, 13 завершены. Следующие: Фаза 11 (изображения) или 12 (голосовые) -### Последние изменения (2026-02-06) +### Завершённые фазы (краткий итог) -**📝 COMPLETED: Documentation Update (Фаза 13, Этап 7)** -- **Проблема**: После этапов 1-6 документация устарела и не отражала новую архитектуру -- **Решение**: Полное обновление документации проекта +| Фаза | Описание | Статус | +|------|----------|--------| +| 1 | Базовая инфраструктура (ratatui + crossterm, vim-навигация) | DONE | +| 2 | TDLib интеграция (авторизация, чаты, сообщения) | DONE | +| 3 | Улучшение UX (отправка, поиск, скролл, realtime) | DONE | +| 4 | Папки и фильтрация (загрузка папок, переключение 1-9) | DONE | +| 5 | Расширенный функционал (онлайн-статус, медиа-заглушки, muted) | DONE | +| 6 | Полировка (60 FPS, память, graceful shutdown, динамический инпут) | DONE | +| 7 | Рефакторинг памяти (единый источник данных, LRU-кэш) | DONE | +| 8 | Дополнительные фичи (markdown, edit/delete, reply/forward, блочный курсор) | DONE | +| 9 | Расширенные возможности (typing, pinned, поиск в чате, черновики, профиль, копирование, реакции, конфиг) | DONE | +| 10 | Desktop уведомления (notify-rust, muted фильтр, mentions, медиа) | DONE (83%) | +| 13 | Глубокий рефакторинг архитектуры (7 этапов) | DONE | -**1. Перезапись PROJECT_STRUCTURE.md:** -- Полная перезапись с актуальной архитектурой -- ASCII диаграмма архитектуры (main.rs → input/app/ui → tdlib → TDLib C library) -- Актуальное дерево файлов со всеми новыми модулями (handlers/, methods/, modals/, components/, messages/) -- Таблица trait методов, диаграмма состояний, приоритеты input routing -- Секция тестирования +### Фаза 13: Рефакторинг (подробности) -**2. Module-level документация (`//!` doc comments) для 16 файлов:** -- `lib.rs`, `types.rs`, `constants.rs` -- `app/mod.rs` -- `config/mod.rs`, `config/validation.rs`, `config/loader.rs` -- `ui/mod.rs`, `ui/messages.rs`, `ui/chat_list.rs`, `ui/components/mod.rs` -- `input/mod.rs`, `input/main_input.rs` -- `tdlib/messages/mod.rs`, `tdlib/messages/convert.rs`, `tdlib/messages/operations.rs` +Разбиты 5 монолитных файлов (4582 строк) на модульную архитектуру: -**Метрики:** -- 16 файлов получили module-level документацию -- PROJECT_STRUCTURE.md полностью переписан -- Все 500+ тестов проходят +- **input/main_input.rs** (1199→164): чистый роутер + 5 handler модулей в `handlers/` +- **app/mod.rs** (1015→371): 5 trait модулей в `methods/` (Navigation, Message, Compose, Search, Modal) +- **ui/messages.rs** (893→365): модули `modals/` (search, pinned, delete, reactions) + `compose_bar.rs` +- **tdlib/messages.rs** (836→3 файла): `messages/` (mod, convert, operations) +- **config/mod.rs** (642→3 файла): validation.rs, loader.rs +- **Очистка дублей**: ~220 строк удалено (shared components, format_user_status, scroll_to_message) +- **Документация**: PROJECT_STRUCTURE.md переписан, 16 файлов получили `//!` docs ---- - -**🔧 COMPLETED: Code Duplication Cleanup (Фаза 13, Этап 6)** -- **Проблема**: После этапов 1-5 рефакторинга накопились неиспользуемые импорты и дублированный код -- **Решение**: Очистка импортов + выделение общих компонентов - -**1. Очистка неиспользуемых импортов:** -- `main_input.rs`: удалено 12 неиспользуемых импортов (функции, traits, типы) -- `chat.rs`: удалён `ReplyInfo` -- `chat_list.rs`, `compose.rs`, `modal.rs`: удалены `KeyCode`, `KeyModifiers` -- `search.rs`: удалён `KeyModifiers` -- `app/mod.rs`: удалён `MessageId` -- Результат: **0 compiler warnings** в исходных файлах - -**2. Извлечение `format_user_status()` в `ui/chat_list.rs`:** -- Было: 2 копии идентичного match по UserOnlineStatus (48 строк x2) -- Стало: 1 функция `format_user_status()` (12 строк) + 7 строк вызова -- Удалено: ~80 строк дублированного кода - -**3. Создание `ui/components/message_list.rs` (общий компонент):** -- `render_message_item()` — рендеринг элемента списка сообщений (marker + sender + date + wrapped text) -- `calculate_scroll_offset()` — вычисление offset для скролла к выбранному элементу -- `render_help_bar()` — рендеринг help bar с keyboard shortcuts -- Использовано в: `modals/search.rs` и `modals/pinned.rs` -- Удалено: ~120 строк дублированного кода из двух модалок - -**4. Извлечение `scroll_to_message()` в `input/handlers/mod.rs`:** -- Было: идентичный код в `handlers/search.rs` и `handlers/modal.rs` -- Стало: 1 функция `scroll_to_message()` (10 строк) + 2 вызова -- Удалено: ~20 строк дублированного кода - -**Метрики:** -- Удалено ~220 строк дублированного кода -- 0 compiler warnings в source файлах -- Все 500+ тестов проходят - ---- - -### Предыдущие изменения (2026-02-06) - -**🔧 COMPLETED: Разбиение config/mod.rs (Фаза 13, Этап 5)** -- **Проблема**: `src/config/mod.rs` содержал 642 строки (structs + validation + loader + credentials) -- **Решение**: Разбит на 3 файла по ответственности -- **Результат**: - - `config/mod.rs`: **350 строк** (было 642) - structs, defaults, Default impls, tests - - `config/validation.rs`: **86 строк** - validate(), parse_color() - - `config/loader.rs`: **192 строки** - load(), save(), paths, credentials -- **Структура config/**: - ``` - src/config/ - ├── mod.rs # Structs, defaults, tests (350 lines) - ├── keybindings.rs # Keybindings (existing) - ├── validation.rs # validate(), parse_color() (86 lines) - └── loader.rs # load/save/credentials (192 lines) - ``` -- Все 500+ тестов проходят - ---- - -**🔧 COMPLETED: Разбиение tdlib/messages.rs (Фаза 13, Этап 4)** -- **Проблема**: `src/tdlib/messages.rs` содержал 836 строк монолитного кода -- **Решение**: Разбит на 3 файла по ответственности -- **Результат**: - - `tdlib/messages/mod.rs`: **99 строк** - struct MessageManager, new(), push_message() - - `tdlib/messages/convert.rs`: **134 строки** - convert_message, fetch_missing_reply_info, fetch_and_update_reply - - `tdlib/messages/operations.rs`: **616 строк** - 11 TDLib API операций -- **Структура messages/**: - ``` - src/tdlib/messages/ - ├── mod.rs # Struct + core (99 lines) - ├── convert.rs # Message conversion (134 lines) - └── operations.rs # TDLib operations (616 lines) - ``` -- Изменения: `client_id` → `pub(crate)`, `convert_message` → `pub(crate)` -- Исправлены trait imports во всех handler файлах и тестах -- Все тесты проходят - ---- - -**🔧 COMPLETED: Рефакторинг ui/messages.rs на модульную архитектуру (Фаза 13, Этап 3)** -- **Проблема**: `src/ui/messages.rs` содержал 893 строки монолитного рендеринга -- **Решение**: Разбит на модули modals и compose_bar -- **Результат**: - - ✅ `ui/messages.rs`: **365 строк** (было 893) - только core rendering - - ✅ Создано 6 новых UI модулей: - - `ui/modals/mod.rs` - экспорты модальных окон - - `ui/modals/delete_confirm.rs` - подтверждение удаления (~8 строк) - - `ui/modals/reaction_picker.rs` - выбор реакций (~13 строк) - - `ui/modals/search.rs` - поиск по сообщениям (193 строки) - - `ui/modals/pinned.rs` - закреплённые сообщения (163 строки) - - `ui/compose_bar.rs` - input box с 5 режимами (168 строк) - - ✅ **Удалено 528 строк** (59% кода) - - ✅ Чистое разделение UI компонентов -- **Структура ui/**: - ``` - src/ui/ - ├── messages.rs # Core chat rendering (365 lines) - ├── compose_bar.rs # Multi-mode input box (168 lines) - └── modals/ - ├── mod.rs # Re-exports - ├── delete_confirm.rs # Delete modal wrapper (8 lines) - ├── reaction_picker.rs # Reaction picker wrapper (13 lines) - ├── search.rs # Search modal (193 lines) - └── pinned.rs # Pinned messages (163 lines) - ``` -- **Улучшения**: - - Модальные окна полностью изолированы - - Compose bar - переиспользуемый компонент - - Утилиты (wrap_text_with_offsets) сделаны pub(super) для переиспользования -- **Метрики успеха**: - - До: 893 строки в 1 файле - - После: 365 строк в messages.rs + 545 строк в модулях - - Достигнута цель: messages.rs ≈ 300-400 строк ✅ - ---- - -### Изменения (2026-02-06) - Этап 2 - -**🔧 COMPLETED: Рефакторинг app/mod.rs на trait-based архитектуру (Фаза 13, Этап 2)** -- **Проблема**: `src/app/mod.rs` содержал 1015 строк с 116 методами (God Object anti-pattern) -- **Решение**: Разбит методы на 5 trait модулей по функциональным областям -- **Результат**: - - ✅ `app/mod.rs`: **371 строка** (было 1015) - только core и getters/setters - - ✅ Создано 5 trait модулей в `app/methods/`: - - `navigation.rs` - NavigationMethods (7 методов навигации по чатам) - - `messages.rs` - MessageMethods (8 методов работы с сообщениями) - - `compose.rs` - ComposeMethods (10 методов reply/forward/draft) - - `search.rs` - SearchMethods (15 методов поиска в чатах и сообщениях) - - `modal.rs` - ModalMethods (27 методов для Profile, Pinned, Reactions, Delete) - - ✅ **Удалено 644 строки** (63% кода) из монолитного impl блока - - ✅ Улучшена модульность и тестируемость -- **Структура app/methods/**: - ``` - src/app/methods/ - ├── mod.rs # Trait re-exports - ├── navigation.rs # NavigationMethods trait (chat list navigation) - ├── messages.rs # MessageMethods trait (message operations) - ├── compose.rs # ComposeMethods trait (reply/forward/draft) - ├── search.rs # SearchMethods trait (search functionality) - └── modal.rs # ModalMethods trait (modal dialogs) - ``` -- **Метрики успеха**: - - До: 1015 строк, 116 функций в одном impl блоке - - После: 371 строка в app/mod.rs + 5 trait impl блоков - - Оставлено в app/mod.rs: конструкторы, get_command, get_selected_chat_id/chat, getters/setters (~48 методов) - - Принцип Single Responsibility соблюдён ✅ -- **Тестирование**: Требуется проверка компиляции и ручное тестирование - ---- - -### Изменения (2026-02-06) - Этап 1 - -**🔧 COMPLETED: Глубокий рефакторинг input/main_input.rs (Фаза 13, Этап 1)** -- **Проблема**: `src/input/main_input.rs` содержал 1199 строк монолитного кода -- **Решение**: Разбит на модульную структуру handlers с 6 специализированными модулями -- **Результат**: - - ✅ `main_input.rs`: **164 строки** (было 1199) - чистый роутер - - ✅ Создано 5 новых handler модулей: - - `handlers/chat.rs` - 452 строки (обработка открытого чата) - - `handlers/modal.rs` - 316 строк (модальные окна) - - `handlers/chat_list.rs` - 142 строки (навигация по чатам) - - `handlers/search.rs` - 140 строк (поиск) - - `handlers/compose.rs` - 80 строк (forward/reply/edit) - - ✅ Сохранены существующие модули: clipboard.rs, global.rs, profile.rs - - ✅ **Удалено 1035 строк** (86% кода) из monolithic файла - - ✅ Улучшена модульность и читаемость кода -- **Дополнительные изменения**: - - 🔧 Исправлен хоткей профиля: Ctrl+I → Ctrl+U (конфликт с Tab в терминале) - - 🔕 Уведомления отключены по умолчанию (enabled: false в config) -- **Структура handlers/**: - ``` - src/input/handlers/ - ├── mod.rs # Module exports - ├── chat.rs # Chat keyboard input (452 lines) - ├── chat_list.rs # Chat list navigation (142 lines) - ├── compose.rs # Forward/reply/edit modes (80 lines) - ├── modal.rs # Modal dialogs (316 lines) - ├── search.rs # Search functionality (140 lines) - ├── clipboard.rs # Clipboard operations (existing) - ├── global.rs # Global commands (existing) - └── profile.rs # Profile helpers (existing) - ``` -- **Метрики успеха**: - - До: 1199 строк в 1 файле - - После: 164 строки в main_input.rs + 1367 строк в 9 handler файлах - - Достигнута цель: main_input.rs < 200 строк ✅ -- **Тестирование**: Требуется ручное тестирование всех функций приложения - -### Изменения (2026-02-04) - -**🔔 NEW: Desktop уведомления (Notifications) — Стадия 1/3 завершена** -- **Реализовано**: - - ✅ NotificationManager с базовой функциональностью (`src/notifications.rs`, 230+ строк) - - ✅ Интеграция с TdClient (поле `notification_manager`) - - ✅ Конфигурация в `config.toml` (enabled, only_mentions, show_preview) - - ✅ Отправка уведомлений для новых сообщений вне текущего чата - - ✅ Зависимость notify-rust 4.11 (с feature flag "notifications") - - ✅ Форматирование body уведомления (текст, заглушки для медиа) -- **Текущие ограничения**: - - ⚠️ Только текстовые сообщения (нет доступа к MessageContentType) - - ⚠️ Muted чаты пока не фильтруются (sync_muted_chats не вызывается) - - ⚠️ Фильтр only_mentions не реализован (нет метода has_mention()) -- **TODO - Стадия 2** (улучшения): - - [x] Синхронизация muted чатов из Telegram (вызов sync_muted_chats при загрузке) ✅ - - [x] Фильтрация по упоминаниям (@username) если only_mentions=true ✅ - - [x] Поддержка типов медиа (фото, видео, стикеры) в body ✅ -- **Стадия 3** (полировка) - ВЫПОЛНЕНО ✅: - - [x] Обработка ошибок notify-rust с graceful fallback - - [x] Логирование через tracing::warn! и tracing::debug! - - [x] Дополнительные настройки: timeout_ms и urgency - - [x] Платформенная поддержка urgency (только Linux) -- **TODO - Стадия 3** (опционально): - - [ ] Ручное тестирование на Linux/macOS/Windows - - [ ] Обработка ошибок notify-rust (fallback если уведомления не работают) - - [ ] Настройки продолжительности показа (timeout) - - [ ] Иконка приложения для уведомлений -- **Изменения**: - - `Cargo.toml`: добавлен notify-rust 4.11, feature "notifications" - - `src/notifications.rs`: новый модуль (230 строк) - - `src/lib.rs`: экспорт модуля notifications - - `src/main.rs`: добавлен `mod notifications;` - - `src/config/mod.rs`: добавлена NotificationsConfig - - `config.example.toml`: добавлена секция [notifications] - - `src/tdlib/client.rs`: поле notification_manager, метод configure_notifications() - - `src/tdlib/update_handlers.rs`: интеграция в handle_new_message_update() - - `src/app/mod.rs`: вызов configure_notifications() при инициализации -- **Тесты**: Компиляция успешна (cargo build --lib ✅, cargo build ✅) - -**📸 PLANNED: Показ изображений в чате (Фаза 11)** -- **Описание**: Отображение изображений прямо в терминале вместо текстовых заглушек "[Фото]" -- **Технологии**: - - ratatui-image 1.0 - поддержка изображений в TUI - - Протоколы: Sixel, Kitty Graphics, iTerm2 Inline Images, Unicode Halfblocks - - TDLib downloadFile API для загрузки фото - - LRU кэш для загруженных изображений (лимит 100 MB) -- **Архитектура**: - - `src/media/` - новый модуль (image_cache, image_loader, image_renderer) - - `PhotoInfo` в `MessageInfo` для хранения метаданных изображения - - Асинхронная загрузка в фоне (не блокирует UI) - - Lazy loading - загрузка только видимых изображений -- **UX фичи**: - - Превью в списке сообщений (миниатюры 20x10 символов) - - Индикатор загрузки с progress bar - - Полноэкранный просмотр: `v` в режиме выбора - - Навигация между изображениями: `←` / `→` - - Auto-detection возможностей терминала - - Fallback на Unicode halfblocks для любых терминалов -- **Конфигурация** (config.toml): - - show_images: bool - включить/отключить - - image_cache_mb: usize - размер кэша - - preview_quality: "low" | "medium" | "high" - - render_protocol: "auto" | "sixel" | "kitty" | "iterm2" | "halfblocks" -- **План реализации**: - - Этап 1: Инфраструктура (модуль media, ImageCache, зависимости) - - Этап 2: Интеграция с TDLib (PhotoInfo, download_photo) - - Этап 3: Рендеринг в UI (превью, масштабирование) - - Этап 4: Полноэкранный просмотр (новый режим ViewImage) - - Этап 5: Конфигурация и оптимизация - - Этап 6: Обработка ошибок и fallback -- **Ожидаемый результат**: - - Фото показываются inline в чате с автоматическим масштабированием - - Поддержка всех популярных терминалов (Kitty, WezTerm, iTerm2, и любых других) - - Производительность: кэширование, асинхронность, lazy loading -- **Статус**: PLANNED (документация готова в ROADMAP.md) - -**🎤 PLANNED: Прослушивание голосовых сообщений (Фаза 12)** -- **Описание**: Воспроизведение голосовых сообщений прямо из TUI с визуальным feedback -- **Технологии**: - - rodio 0.17 - Pure Rust аудио библиотека (кроссплатформенная) - - TDLib downloadFile API для загрузки OGG файлов - - Поддержка платформ: Linux (ALSA/PulseAudio), macOS (CoreAudio), Windows (WASAPI) - - Fallback на системный плеер (mpv, ffplay) если rodio не работает -- **Архитектура**: - - `src/audio/` - новый модуль (player, cache, state) - - `AudioPlayer` - управление воспроизведением (play, pause, stop, seek, volume) - - `VoiceCache` - LRU кэш загруженных файлов (лимит 100 MB) - - `PlaybackState` - текущее состояние (status, position, duration, volume) - - Асинхронная загрузка в фоне (не блокирует UI) -- **UX фичи**: - - Progress bar в сообщении (▶ ████████░░░░░░ 0:08 / 0:15) - - Статусы: ▶ (playing), ⏸ (paused), ⏹ (stopped), ⏳ (loading) - - Хоткеи: Space (play/pause), s (stop), ←/→ (seek ±5s), ↑/↓ (volume) - - Waveform визуализация (опционально, из Telegram API) - - Автоматическая остановка при закрытии чата - - Индикатор загрузки с процентами -- **Конфигурация** (config.toml): - - enabled: bool - включить/отключить аудио - - default_volume: f32 - громкость (0.0 - 1.0) - - seek_step_seconds: i32 - шаг перемотки (5 сек) - - autoplay: bool - автовоспроизведение - - cache_size_mb: usize - размер кэша - - show_waveform: bool - показывать waveform - - system_player_fallback: bool - использовать системный плеер - - system_player: String - команда плеера (mpv, ffplay) -- **План реализации**: - - Этап 1: Инфраструктура аудио (модуль audio, AudioPlayer, VoiceCache) - - Этап 2: Интеграция с TDLib (VoiceNoteInfo, download_voice_note) - - Этап 3: UI для воспроизведения (progress bar, индикаторы, footer) - - Этап 4: Хоткеи для управления (play/pause, stop, seek, volume) - - Этап 5: Конфигурация и UX (AudioConfig, ticker для обновления) - - Этап 6: Обработка ошибок и fallback (системный плеер) - - Этап 7: Дополнительные улучшения (префетчинг, анимация) -- **Ожидаемый результат**: - - Голосовые воспроизводятся с визуальным индикатором прогресса - - Полный контроль: play, pause, stop, seek, volume - - Кэширование загруженных файлов - - Graceful fallback на системный плеер - - Кроссплатформенность (Linux, macOS, Windows) -- **Статус**: PLANNED (документация готова в ROADMAP.md) - -**🐛 FIX: HashMap keybindings коллизии - дубликаты клавиш** -- **Проблема #1**: `KeyCode::Enter` был привязан к 3 командам (OpenChat, SelectMessage, SubmitMessage) -- **Проблема #2**: `KeyCode::Up` был привязан к 2 командам (MoveUp, EditMessage) -- **Симптомы**: - - `Enter` возвращал `SelectMessage` вместо `SubmitMessage` → чат не открывался - - `Up` возвращал `EditMessage` вместо `MoveUp` → навигация в списке чатов не работала -- **Причина**: HashMap перезаписывает значения при повторной вставке (last-insert-wins) -- **Решение**: - - Удалены привязки `OpenChat` и `SelectMessage` для Enter (обрабатываются в `handle_enter_key`) - - Удалена привязка `EditMessage` для Up (обрабатывается напрямую в `handle_open_chat_keyboard_input`) - - Это контекстно-зависимая логика, которую нельзя корректно выразить через простой HashMap -- **Изменения**: `src/config/keybindings.rs:166-168, 186-189, 210-212` -- **Тесты**: Все 571 тест проходят (75 unit + 496 integration) - -**✅ ЗАВЕРШЕНО: Интеграция ChatFilter в App** -- **Цель**: Заменить дублирующуюся логику фильтрации в `App::get_filtered_chats()` -- **Решение**: - - Добавлен экспорт `ChatFilter`, `ChatFilterCriteria`, `ChatSortOrder` в `src/app/mod.rs` - - Метод `get_filtered_chats()` переписан с использованием ChatFilter API - - Удалена дублирующая логика (27 строк → 11 строк) - - Используется builder pattern для создания критериев -- **Преимущества**: - - Единый источник правды для фильтрации чатов - - Централизованная логика в ChatFilter модуле - - Type-safe критерии через builder pattern - - Reference-based фильтрация (без клонирования) -- **Изменения**: `src/app/mod.rs:0-5, 313-323` -- **Тесты**: Все 577 тестов проходят (81 unit + 496 integration) - -**🐛 FIX: Зависание при открытии чатов с большой историей** -- **Проблема**: При использовании `i32::MAX` как лимита загрузки истории, приложение зависало в чатах с тысячами сообщений (например, на итерации #96 было загружено 4750+ сообщений и загрузка продолжалась) -- **Решение**: Заменён лимит с `i32::MAX` на разумные 300 сообщений при открытии чата -- **Обоснование**: 300 сообщений достаточно для заполнения экрана с запасом (при высоте экрана 37 строк отображается ~230 сообщений) -- **Pagination**: При скролле вверх автоматически подгружается ещё история через `load_older_messages` -- **Тесты**: Все 104 теста проходят успешно, включая новые тесты для chunked loading - -**⚙️ NEW: Система настраиваемых горячих клавиш** -- **Модуль**: `src/config/keybindings.rs` (420+ строк) -- **Архитектура**: - - Enum `Command` с 40+ командами (навигация, чат, сообщения, input, profile) - - Struct `KeyBinding` с поддержкой модификаторов (Ctrl, Shift, Alt, Super, Hyper, Meta) - - Struct `Keybindings` для управления привязками команд к клавишам - - HashMap> для множественных bindings -- **Возможности**: - - Type-safe команды через enum (невозможно опечататься в названии) - - Множественные привязки для одной команды (например, EN/RU раскладки) - - Поддержка модификаторов (Ctrl+S, Shift+Enter и т.д.) - - Сериализация/десериализация для загрузки из конфига - - Метод `get_command()` для определения команды по KeyEvent -- **Тесты**: 4 unit теста (все проходят) -- **Статус**: ✅ Интегрировано в Config и main_input.rs - -**🎯 NEW: KeyHandler trait для обработки клавиш** -- **Модуль**: `src/input/key_handler.rs` (380+ строк) -- **Архитектура**: - - Enum `KeyResult` (Handled, HandledNeedsRedraw, NotHandled, Quit) - результат обработки - - Trait `KeyHandler` - единый интерфейс для обработчиков клавиш - - Method `handle_key()` - обработка с Command enum - - Method `priority()` - приоритет обработчика для цепочки -- **Реализации**: - - `GlobalKeyHandler` - глобальные команды (Quit, OpenSearch, Cancel) - - `ChatListKeyHandler` - навигация по чатам (Up/Down, OpenChat, папки 1-9) - - `MessageViewKeyHandler` - просмотр сообщений (scroll, PageUp/Down, SearchInChat, Profile) - - `MessageSelectionKeyHandler` - действия с сообщением (Delete, Reply, Forward, Copy, React) - - `KeyHandlerChain` - цепочка обработчиков с автосортировкой по приоритету -- **Преимущества**: - - Разделение ответственности - каждый экран = свой handler - - Избавление от огромных match блоков - - Простое добавление новых режимов - - Type-safe через enum Command - - Композиция через KeyHandlerChain -- **Тесты**: 3 unit теста (все проходят) -- **Статус**: Готово к интеграции (TODO: методы в App, интеграция в main_input.rs) - -**🔍 NEW: Централизованная фильтрация чатов** -- **Модуль**: `src/app/chat_filter.rs` (470+ строк) -- **Архитектура**: - - Struct `ChatFilterCriteria` - критерии фильтрации с builder pattern - - Struct `ChatFilter` - централизованная логика фильтрации - - Enum `ChatSortOrder` - порядки сортировки -- **Возможности фильтрации**: - - По папке (folder_id) - - По поисковому запросу (название или @username, case-insensitive) - - Только закреплённые (pinned_only) - - Только непрочитанные (unread_only) - - Только с упоминаниями (mentions_only) - - Скрывать muted чаты (hide_muted) - - Скрывать архивные (hide_archived) -- **Методы**: - - `filter()` - основной метод фильтрации (без клонирования) - - `by_folder()` / `by_search()` - упрощённые варианты - - `count()` - подсчёт чатов - - `count_unread()` - подсчёт непрочитанных - - `count_unread_mentions()` - подсчёт упоминаний -- **Сортировка**: - - ByLastMessage - по времени последнего сообщения - - ByTitle - по алфавиту - - ByUnreadCount - по количеству непрочитанных - - PinnedFirst - закреплённые сверху -- **Преимущества**: - - Единый источник правды для фильтрации - - Убирает дублирование логики (App, UI, обработчики) - - Type-safe критерии через struct - - Builder pattern для удобного конструирования - - Эффективность (работает с references, без клонирования) -- **Тесты**: 6 unit тестов (все проходят) -- **Статус**: ✅ Интегрировано в App и ChatListState - -### Что сделано - -#### TDLib интеграция -- Подключена библиотека `tdlib-rs` v1.2.0 с автоматической загрузкой TDLib -- Реализована авторизация через телефон + код + 2FA пароль -- Сессия сохраняется автоматически в папке `tdlib_data/` -- Отключены логи TDLib через FFI вызов `td_execute` до создания клиента -- Updates обрабатываются в отдельном потоке через `mpsc` канал (неблокирующе) -- **Graceful shutdown**: корректное закрытие TDLib при выходе (Ctrl+C) - -#### Функциональность -- Загрузка списка чатов (до 50 штук) -- **Фильтрация чатов**: показываются только чаты из ChatList::Main (без архива) -- **Фильтрация удалённых аккаунтов**: "Deleted Account" не отображаются в списке -- Отображение названия чата, счётчика непрочитанных и **@username** -- **Иконка 📌** для закреплённых чатов -- **Иконка 🔇** для замьюченных чатов -- **Индикатор @** для чатов с непрочитанными упоминаниями -- **Онлайн-статус**: зелёная точка ● для онлайн пользователей -- **Загрузка истории сообщений**: динамическая чанковая подгрузка (по 50 сообщений) - - Retry логика: до 20 попыток на чанк, ждет пока TDLib синхронизирует с сервера - - Лимит 300 сообщений при открытии чата (достаточно для заполнения экрана) - - Автоматическая подгрузка старых сообщений при скролле вверх (pagination) - - FIX: Убран i32::MAX лимит, который вызывал зависание в чатах с тысячами сообщений -- **Группировка сообщений по дате** (разделители "Сегодня", "Вчера", дата) — по центру -- **Группировка сообщений по отправителю** (заголовок с именем) -- **Выравнивание сообщений**: исходящие справа (зелёные), входящие слева -- **Перенос длинных сообщений**: автоматический wrap на несколько строк -- **Отображение времени и галочек**: `текст (HH:MM ✓✓)` для исходящих, `(HH:MM) текст` для входящих -- **Галочки прочтения** (✓ отправлено, ✓✓ прочитано) — обновляются в реальном времени -- **Отметка сообщений как прочитанных**: при открытии чата счётчик непрочитанных сбрасывается -- **Отправка текстовых сообщений** -- **Редактирование сообщений**: ↑ при пустом инпуте → выбор → Enter → редактирование -- **Удаление сообщений**: в режиме выбора нажать `d` / `в` / `Delete` → модалка подтверждения -- **Reply на сообщения**: в режиме выбора нажать `r` / `к` → режим ответа с превью -- **Forward сообщений**: в режиме выбора нажать `f` / `а` → выбор чата для пересылки -- **Отображение пересланных сообщений**: индикатор "↪ Переслано от" с именем отправителя -- **Индикатор редактирования**: ✎ рядом с временем для отредактированных сообщений -- **Новые сообщения в реальном времени** при открытом чате -- **Поиск по чатам** (Ctrl+S): фильтрация по названию и @username -- **Typing indicator** ("печатает..."): отображение статуса набора текста собеседником и отправка своего статуса -- **Закреплённые сообщения**: отображение pinned message вверху чата с переходом к нему -- **Поиск по сообщениям в чате** (Ctrl+F): поиск текста внутри открытого чата с навигацией по результатам -- **Черновики**: автосохранение набранного текста при переключении между чатами -- **Профиль пользователя/чата** (`i`): просмотр информации о собеседнике или группе -- **Копирование сообщений** (`y`/`н`): копирование текста сообщения в системный буфер обмена -- **Реакции на сообщения**: - - Отображение реакций под сообщениями - - Логика отображения: 1 человек = только emoji, 2+ = emoji + счётчик - - Свои реакции в рамках [👍], чужие без рамок 👍 - - Emoji picker с сеткой доступных реакций (8 в ряду) - - Добавление/удаление реакций (toggle) - - Обновление реакций в реальном времени через Update::MessageInteractionInfo -- **Конфигурационный файл** (`~/.config/tele-tui/config.toml`): - - Автоматическое создание дефолтного конфига при первом запуске - - **Настройка timezone**: формат "+03:00" или "-05:00" - - **Настройка цветов**: incoming_message, outgoing_message, selected_message, reaction_chosen, reaction_other - - **Credentials файл** (`~/.config/tele-tui/credentials`): API_ID и API_HASH - - Приоритет загрузки: ~/.config/tele-tui/credentials → .env → сообщение об ошибке с инструкциями -- **Кеширование имён пользователей**: имена загружаются асинхронно и обновляются в UI -- **Папки Telegram**: загрузка и переключение между папками (1-9) -- **Медиа-заглушки**: [Фото], [Видео], [Голосовое], [Стикер], [GIF] и др. -- **Markdown форматирование в сообщениях**: - - **Жирный** (bold) - - *Курсив* (italic) - - __Подчёркнутый__ (underline) - - ~~Зачёркнутый~~ (strikethrough) - - `Код` (inline code, Pre, PreCode) — cyan на тёмном фоне - - Спойлеры — скрытый текст (серый на сером) - - Ссылки (URL, TextUrl, Email, Phone) — синий с подчёркиванием - - @Упоминания — синий с подчёркиванием - -#### Состояние сети -- **Индикатор в футере**: показывает текущее состояние подключения - - `⚠ Нет сети` — красный, ожидание сети - - `⏳ Прокси...` — cyan, подключение к прокси - - `⏳ Подключение...` — cyan, подключение к серверам - - `⏳ Обновление...` — cyan, синхронизация данных - -#### Оптимизации -- **60 FPS ready**: poll таймаут 16ms, рендеринг только при изменениях (`needs_redraw` флаг) -- **Оптимизация памяти**: - - Очистка сообщений при закрытии чата - - Лимит кэша пользователей (500) - - Периодическая очистка неактивных записей -- **Минимальное разрешение**: предупреждение если терминал меньше 80x20 - -#### Динамический инпут -- **Автоматическое расширение**: поле ввода увеличивается при длинном тексте (до 10 строк) -- **Перенос текста**: длинные сообщения переносятся на новые строки -- **Блочный курсор**: vim-style курсор █ с возможностью перемещения по тексту - -#### Управление -- `↑/↓` стрелки — навигация по списку чатов -- `Enter` — открыть чат / отправить сообщение -- `Esc` — закрыть открытый чат / отменить поиск -- `Ctrl+S` — поиск по чатам (фильтрация по названию и username) -- `Ctrl+R` — обновить список чатов -- `Ctrl+C` — выход (graceful shutdown) -- `↑/↓` в открытом чате — скролл сообщений (с подгрузкой старых) -- `↑` при пустом инпуте — выбор сообщения для редактирования -- `Enter` в режиме выбора — начать редактирование -- `r` / `к` в режиме выбора — ответить на сообщение (reply) -- `f` / `а` в режиме выбора — переслать сообщение (forward) -- `d` / `в` / `Delete` в режиме выбора — удалить сообщение (с подтверждением) -- `y` / `н` / `Enter` — подтвердить удаление в модалке -- `n` / `т` / `Esc` — отменить удаление в модалке -- `Esc` — отменить выбор/редактирование/reply -- `1-9` — переключение папок (в списке чатов) -- `Ctrl+F` — поиск по сообщениям в открытом чате -- `n` / `N` — навигация по результатам поиска (следующий/предыдущий) -- `Ctrl+i` / `Ctrl+ш` — открыть профиль пользователя/чата -- `y` / `н` в режиме выбора — скопировать сообщение в буфер обмена -- `e` / `у` в режиме выбора — добавить реакцию (открывает emoji picker) -- `←` / `→` / `↑` / `↓` в emoji picker — навигация по сетке реакций -- `Enter` в emoji picker — добавить/удалить реакцию -- `Esc` в emoji picker — закрыть picker -- **Редактирование текста в инпуте:** - - `←` / `→` — перемещение курсора - - `Home` — курсор в начало - - `End` — курсор в конец - - `Backspace` — удалить символ слева - - `Delete` — удалить символ справа - -### Структура проекта +### Ключевая архитектура ``` -src/ -├── main.rs # Точка входа, event loop, TDLib инициализация, graceful shutdown -├── lib.rs # Библиотечный интерфейс (для тестов) -├── types.rs # Типобезопасные обёртки (ChatId, MessageId, UserId) -├── config.rs # Конфигурация (TOML), загрузка credentials -├── error.rs # TeletuiError enum, Result type alias -├── constants.rs # Константы проекта (MAX_MESSAGES_IN_CHAT, POLL_TIMEOUT_MS, etc.) -├── formatting.rs # Markdown форматирование (CharStyle, format_text_with_entities) -├── app/ -│ ├── mod.rs # App структура и состояние (needs_redraw флаг) -│ ├── state.rs # AppScreen enum -│ └── chat_state.rs # ChatState enum (Normal, MessageSelection, Editing, etc.) -├── ui/ -│ ├── mod.rs # Роутинг UI по экранам, проверка минимального размера -│ ├── loading.rs # Экран загрузки -│ ├── auth.rs # Экран авторизации -│ ├── main_screen.rs # Главный экран с папками -│ ├── chat_list.rs # Список чатов (pin, mute, online, mentions) -│ ├── messages.rs # Область сообщений (wrap, группировка, динамический инпут) -│ ├── footer.rs # Подвал с командами и статусом сети -│ ├── profile.rs # Экран профиля пользователя/чата -│ └── components/ # Переиспользуемые UI компоненты -│ ├── mod.rs -│ ├── modal.rs -│ ├── input_field.rs -│ ├── message_bubble.rs -│ ├── chat_list_item.rs -│ └── emoji_picker.rs -├── input/ -│ ├── mod.rs # Роутинг ввода -│ ├── auth.rs # Обработка ввода на экране авторизации -│ └── main_input.rs # Обработка ввода на главном экране -├── utils.rs # Утилиты (disable_tdlib_logs, format_timestamp_with_tz, format_date, get_day) -└── tdlib/ - ├── mod.rs # Модуль экспорта (TdClient, UserOnlineStatus, NetworkState) - ├── client.rs # TdClient: авторизация, chats, messages, users, reactions - ├── auth.rs # AuthManager + AuthState enum - ├── chats.rs # ChatManager для операций с чатами - ├── messages.rs # MessageManager для сообщений - ├── users.rs # UserCache с LRU кэшем - ├── reactions.rs # ReactionManager - └── types.rs # Общие типы данных (ChatInfo, MessageInfo, MessageBuilder, etc.) - -tests/ -├── helpers/ -│ ├── mod.rs # Экспорт тестовых утилит -│ ├── app_builder.rs # TestAppBuilder для создания тестовых App -│ ├── fake_tdclient.rs # FakeTdClient (mock TDLib клиент, для будущих интеграционных тестов) -│ ├── snapshot_utils.rs # Утилиты для snapshot тестов (render_to_buffer, buffer_to_string) -│ └── test_data.rs # Builders для тестовых данных (TestChatBuilder, TestMessageBuilder) -├── chat_list.rs # Snapshot тесты для списка чатов (9 тестов) -└── messages.rs # Snapshot тесты для сообщений (19 тестов) +main.rs → event loop (16ms poll) +├── input/ → роутер + handlers/ (chat, chat_list, compose, modal, search) +├── app/ → App + methods/ (5 traits, 67 методов) +├── ui/ → рендеринг (messages, chat_list, modals/, compose_bar, components/) +└── tdlib/ → TDLib wrapper (client, auth, chats, messages/, users, reactions, types) ``` ### Тестирование -**Статус**: ПОЛНОСТЬЮ ЗАВЕРШЕНО! (100%) — Все тесты готовы! 🎉🎊🚀 - -**Стратегия**: Комбо подход — 70% snapshot tests, 25% integration tests, 5% e2e smoke tests + performance benchmarks - -**Инфраструктура (Фаза 0)**: ✅ Завершена -- Добавлены зависимости: `insta = "1.34"`, `tokio-test = "0.4"`, `criterion = "0.5"` -- Создан `src/lib.rs` для экспорта модулей в тесты -- Созданы test helpers: - - `TestAppBuilder` — fluent builder для создания тестовых App - - `TestChatBuilder` / `TestMessageBuilder` — builders для тестовых данных - - `FakeTdClient` — in-memory mock TDLib клиента - - `render_to_buffer` / `buffer_to_string` — утилиты для snapshot тестов - -**Snapshot Tests (Фаза 1)**: ✅ 57/57 (100%) -- ✅ **1.1 Chat List** (10/10): пустой список, множественные чаты, unread, pinned, muted, mentions, selected, long title, search mode, online status -- ✅ **1.2 Messages** (19/19): empty chat, incoming/outgoing, date separators, sender grouping, read receipts, edited, long message wrap, markdown, media, reply, forwarded, reactions, selected -- ✅ **1.3 Modals** (8/8): delete confirmation, emoji picker, profile, pinned message, search, forward -- ✅ **1.4 Input Field** (7/7): empty, text, long text, editing/reply/search modes -- ✅ **1.5 Footer** (6/6): chat list, open chat, network states, search mode -- ✅ **1.6 Screens** (7/7): loading, auth, main, terminal size warning - -**Integration Tests (Фаза 2)**: ✅ 93/93 (100%!) -- ✅ **2.1 Send Message Flow** (6/6): отправка текста, множественные, форматирование, разные чаты, входящие, reply -- ✅ **2.2 Edit Message Flow** (6/6): изменение текста, edit_date, can_be_edited, только свои, множественные, форматирование -- ✅ **2.3 Delete Message Flow** (6/6): удаление из списка, множественные, can_be_deleted, только свои, разные чаты, revoke -- ✅ **2.4 Reply & Forward Flow** (8/8): reply с превью, связь с оригиналом, forward с sender, разные чаты, комбо -- ✅ **2.5 Reactions Flow** (10/10): добавление, toggle, множественные, разные юзеры, подсчёт, chosen, realtime, доступные, на forwarded, очистка -- ✅ **2.6 Search Flow** (8/8): по названию, username, сообщениям, навигация, case-insensitive, пробелы, пустой, очистка -- ✅ **2.7 Drafts Flow** (7/7): сохранение, восстановление, удаление, независимые, индикатор, пустой, закрытие чата -- ✅ **2.8 Navigation Flow** (7/7): списку чатов, открытие, закрытие, скролл, папки, wrap, пустой список -- ✅ **2.9 Profile Flow** (6/6): личный чат, имя+username, телефон, группа, участники, закрытие -- ✅ **2.10 Network & Typing Flow** (9/9): typing indicator, action, статус, timeout, network states (5) -- ✅ **2.11 Copy Flow** (9/9): форматирование plain, forward, reply, оба контекста, длинные, markdown, clipboard init, clipboard test, кроссплатформенность -- ✅ **2.12 Config Flow** (11/11): дефолты, кастомные, валидные цвета, light цвета, невалидные (fallback), case-insensitive, TOML сериализация, частичный TOML, timezone форматы, credentials из env, credentials ошибка - -**E2E Tests (Фаза 3)**: ✅ 12/12 (100%!) -- ✅ **3.1 Smoke Tests** (4/4): базовые структуры, минимальный размер терминала, константы, graceful shutdown -- ✅ **3.2 User Journey** (8/8): app launch, open chat, send message, receive message, multi-step conversation, switch chats, edit/reply flows, network changes - -**Utils Tests (Фаза 4.1)**: ✅ 18/18 (100%!) -- ✅ `format_timestamp_with_tz`: 5 тестов (positive offset, negative offset, zero offset, midnight wrap, invalid fallback) -- ✅ `get_day`: 2 теста (основной, группировка) -- ✅ `format_datetime`: 1 тест -- ✅ `parse_timezone_offset`: 1 тест -- ✅ `format_date`: 4 теста (today, yesterday, old, epoch) -- ✅ `format_was_online`: 5 тестов (just now, minutes ago, hours ago, days ago, very old) - -**Performance Benchmarks (Фаза 4.2)**: ✅ 8/8 (100%!) -- ✅ `group_messages.rs`: benchmark группировки сообщений (100, 500) -- ✅ `formatting.rs`: benchmark форматирования (timestamp, date, get_day) -- ✅ `format_markdown.rs`: benchmark markdown (simple, entities, long text) - -**ИТОГО**: 188 тестов + 8 benchmarks = 196 тестов (100%)! 🎉🎊🚀 -- Фаза 0: Инфраструктура ✅ -- Фаза 1: UI Snapshot Tests ✅ (57 тестов) -- Фаза 2: Integration Tests ✅ (93 теста) -- Фаза 3: E2E Tests ✅ (12 тестов) -- Фаза 4.1: Utils Tests ✅ (18 тестов) -- Фаза 4.2: Performance Benchmarks ✅ (8 benchmarks) - -Подробный план и roadmap: см. [TESTING_ROADMAP.md](TESTING_ROADMAP.md) +500+ тестов (0 failures): +- Snapshot tests: 57 (UI компоненты) +- Integration tests: 93 (user flows) +- E2E tests: 12 (smoke + journey) +- Utils tests: 18 +- Performance benchmarks: 8 ### Ключевые решения -1. **Неблокирующий receive**: TDLib updates приходят в отдельном потоке и передаются в main loop через `mpsc::channel`. Это позволяет UI оставаться отзывчивым. +1. **Неблокирующий receive**: TDLib updates через `mpsc::channel` в отдельном потоке +2. **Trait-based App**: методы разбиты на traits — требуют `use` import на call site +3. **FakeTdClient**: mock для тестов без TDLib (реализует TdClientTrait) +4. **Оптимизация рендеринга**: `needs_redraw` флаг, рендеринг только при изменениях +5. **Конфиг**: TOML `~/.config/tele-tui/config.toml`, credentials с приоритетом (XDG → .env) -2. **FFI для логов**: Используем прямой вызов `td_execute` для отключения логов синхронно, до создания клиента, чтобы избежать вывода в терминал. - -3. **Синхронизация чатов**: Чаты загружаются асинхронно через updates. Main loop периодически синхронизирует `app.chats` с `td_client.chats`. - -4. **Кеширование имён**: При получении `Update::User` сохраняем имя (first_name + last_name) и username в HashMap. Имена подгружаются асинхронно через очередь `pending_user_ids`. Кэш ограничен 500 записями. - -5. **Группировка сообщений**: Сообщения группируются по дате (разделители по центру) и по отправителю (заголовки). Исходящие выравниваются вправо, входящие влево. - -6. **Отметка прочтения**: При открытии чата вызывается `view_messages` для всех сообщений. Новые входящие сообщения автоматически отмечаются как прочитанные. `Update::ChatReadOutbox` обновляет статус галочек. - -7. **Graceful shutdown**: При Ctrl+C устанавливается флаг остановки, закрывается TDLib клиент, ожидается завершение polling задачи с таймаутом 2 сек. - -8. **Оптимизация рендеринга**: Флаг `needs_redraw` позволяет пропускать перерисовку когда ничего не изменилось. Триггеры: TDLib updates, пользовательский ввод, изменение размера терминала. - -9. **Перенос текста**: Длинные сообщения автоматически разбиваются на строки с учётом ширины терминала. Для исходящих — time_mark на последней строке, для входящих — время на первой строке с отступом для остальных. - -10. **Конфигурационный файл**: TOML конфиг создаётся автоматически при первом запуске в `~/.config/tele-tui/config.toml`. Поддерживает настройку timezone (применяется к отображению времени через `format_timestamp_with_tz`) и цветовой схемы (парсится в `ratatui::style::Color`). Credentials загружаются с приоритетом: XDG config dir → .env → ошибка с инструкциями. - -11. **Реакции**: Хранятся в `Vec` для каждого сообщения. Обновляются в реальном времени через `Update::MessageInteractionInfo`. Emoji picker использует сетку 8x6 с навигацией стрелками. Приоритет обработки ввода: reaction picker → delete confirmation → остальные модалки (важно для корректной работы Enter/Esc). - -### Зависимости (Cargo.toml) +### Зависимости (основные) ```toml -ratatui = "0.29" -crossterm = "0.28" -tdlib-rs = { version = "1.1", features = ["download-tdlib"] } -tokio = { version = "1", features = ["full"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -dotenvy = "0.15" -chrono = "0.4" -clipboard = "0.5" -toml = "0.8" -dirs = "5.0" +ratatui = "0.29" # TUI фреймворк +crossterm = "0.28" # Терминальный backend +tdlib-rs = "1.1" # Telegram TDLib binding +tokio = "1" # Async runtime +notify-rust = "4.11" # Desktop уведомления (feature flag) ``` -### API Credentials - -Приоритет загрузки (от высшего к низшему): - -1. **Файл credentials** (`~/.config/tele-tui/credentials`): -``` -API_ID=your_api_id -API_HASH=your_api_hash -``` - -2. **Переменные окружения** (`.env` файл в текущей директории): -``` -API_ID=your_api_id -API_HASH=your_api_hash -``` - -3. Если ничего не найдено — показывается сообщение об ошибке с инструкциями. - -### Конфигурационный файл - -Создаётся автоматически при первом запуске в `~/.config/tele-tui/config.toml`: - -```toml -[general] -# Часовой пояс в формате "+03:00" или "-05:00" -# Применяется к отображению времени сообщений -timezone = "+03:00" - -[colors] -# Цветовая схема (поддерживаемые цвета: black, red, green, yellow, blue, magenta, cyan, gray, white, darkgray, lightred, lightgreen, lightyellow, lightblue, lightmagenta, lightcyan) - -# Цвет входящих сообщений -incoming_message = "white" - -# Цвет исходящих сообщений -outgoing_message = "green" - -# Цвет выбранного сообщения -selected_message = "yellow" - -# Цвет своих реакций (в рамках [👍]) -reaction_chosen = "yellow" - -# Цвет чужих реакций -reaction_other = "gray" -``` - -## Последние обновления (2026-02-03) - -### Рефакторинг — Упрощение main_input.rs ✅ ПОЛНОСТЬЮ ЗАВЕРШЕНО (2026-02-03) - -**Цель**: Упростить функцию `handle()` в `main_input.rs` путём извлечения обработчиков режимов в отдельные функции. - -**Phase 1** — Базовые режимы (не выполнялась в текущей сессии, была ранее) - -**Phase 2** — Обработка клавиатуры (~163 строки): - -1. ✅ **`handle_open_chat_keyboard_input()`** (~129 строк) - - Backspace/Delete для редактирования текста - - Char для ввода символов + typing status (throttling 5 сек) - - Навигация курсора (Left/Right/Home/End) - - Скролл сообщений (Up/Down) с подгрузкой старых - -2. ✅ **`handle_chat_list_navigation()`** (~34 строки) - - Навигация по чатам: Up/Down/j/k - - Переключение папок: цифры 1-9 (1=All, 2-9=папки) - -**Phase 3** — Все оставшиеся режимы и действия (~783 строки): - -3. ✅ **`handle_profile_mode()`** (~120 строк) - - Режим профиля пользователя/чата - - Модалка подтверждения выхода из группы (двухшаговая) - - Открытие в браузере, копирование ID - -4. ✅ **`handle_message_search_mode()`** (~73 строки) - - Поиск по сообщениям в открытом чате (Ctrl+F) - - Навигация по результатам, переход к сообщению - -5. ✅ **`handle_pinned_mode()`** (~42 строки) - - Режим просмотра закреплённых сообщений - - Навигация и переход к сообщению в истории - -6. ✅ **`handle_reaction_picker_mode()`** (~90 строк) - - Emoji picker для добавления реакций - - Навигация по сетке 8x6, toggle реакции - -7. ✅ **`handle_delete_confirmation()`** (~60 строк) - - Модалка подтверждения удаления сообщения - - Обработка yes/no, удаление для себя/всех - -8. ✅ **`handle_forward_mode()`** (~52 строки) - - Выбор чата для пересылки сообщения - - Навигация по списку чатов, отправка - -9. ✅ **`handle_chat_search_mode()`** (~43 строки) - - Поиск по чатам (Ctrl+S) - - Фильтрация списка, открытие чата - -10. ✅ **`handle_enter_key()`** (~145 строк) - - Открытие чата из списка - - Отправка/редактирование сообщений - - Начало редактирования из режима выбора - -11. ✅ **`handle_escape_key()`** (~35 строк) - - Обработка Esc: отмена действий или закрытие чата - - Сохранение черновика при закрытии - -12. ✅ **`handle_message_selection()`** (~95 строк) - - Режим выбора сообщения в открытом чате - - Действия: reply, forward, delete, copy, react - -13. ✅ **`handle_profile_open()`** (~28 строк) - - Ctrl+U для открытия профиля чата/пользователя - -**Итоговый результат**: -- ✅ Функция `handle()` сократилась с **891 до 82 строк** (91% сокращение! 🎉) -- ✅ Извлечено **13 специализированных функций** (~946 строк кода) -- ✅ Каждая функция имеет чёткую ответственность и подробную документацию -- ✅ Код стал **линейным и простым для понимания** -- ✅ Функция handle() теперь читается как оглавление - всё понятно с первого взгляда -- ✅ Все 196 тестов (188 tests + 8 benchmarks) проходят успешно - -**Также**: -- ✅ Обновлён `tdlib-rs` с версии 1.1 на 1.2.0 - -**Файлы изменены**: -- `src/input/main_input.rs` — извлечено 13 функций-обработчиков, handle() сократилась с 891 до 82 строк -- `Cargo.toml` — обновлена версия tdlib-rs -- `CONTEXT.md` — обновлён контекст проекта - -**Phase 4** — Упрощение вложенности (применены паттерны): - -- ✅ **Early returns** - замена if-else на ранние выходы -- ✅ **Let-else guards** - замена `if let Some` на `let Some(...) else { return }` -- ✅ **Вспомогательные функции** - извлечение сложной логики - - `edit_message()` - редактирование сообщения (~50 строк) - - `send_new_message()` - отправка нового сообщения (~55 строк) - - `perform_message_search()` - поиск по сообщениям (~20 строк) - -**Упрощённые функции**: -- `handle_profile_mode()` - упрощён блок Enter с let-else -- `handle_profile_open()` - применён early return guard -- `handle_enter_key()` - разделена на части, сокращена с ~130 до ~40 строк -- `handle_message_search_mode()` - извлечена логика поиска -- `handle_escape_key()` - преобразован в early returns -- `handle_message_selection()` - применены let-else guards - -**Результат Phase 4**: -- ✅ Глубина вложенности: **6+ уровней → 2-3 уровня** -- ✅ Код стал **максимально линейным и читаемым** -- ✅ Применены современные Rust паттерны (let-else, guards) -- ✅ Извлечено 3 дополнительных вспомогательных функции - -**Коммиты**: -- `f4c24dd` — Phase 2: extract keyboard and navigation handlers (2 функции) -- `45d03b5` — Phase 3: complete main_input.rs simplification (11 функций) -- `67fd750` — Phase 4: reduce nesting with early returns and guard clauses -- `9d9232f` — Phase 4: complete nesting simplification with let-else guards - ---- - -## Последние обновления (2026-02-02) - -### Исправление критической ошибки — Stack Overflow при работе с сообщениями ✅ (2026-02-02) - -**Проблема**: -- Stack overflow при запуске приложения, отправке и редактировании сообщений -- Ошибка: `thread 'main' has overflowed its stack fatal runtime error: stack overflow, aborting` - -**Причина**: -Бесконечная рекурсия в trait реализации из-за несоответствия сигнатур методов между trait и inherent impl: -- Trait методы: `&mut self` -- TdClient inherent методы: `&self` -- При вызове `self.method()` внутри trait impl, Rust не мог вызвать inherent метод (несовместимость типов) и вызывал trait метод → бесконечная рекурсия - -**Исправлено 6 методов**: - -1. **`send_message`** - прямой вызов `self.message_manager.send_message()` вместо `self.send_message()` -2. **`edit_message`** - прямой вызов `self.message_manager.edit_message()` -3. **`delete_messages`** - прямой вызов `self.message_manager.delete_messages()` -4. **`forward_messages`** - прямой вызов `self.message_manager.forward_messages()` -5. **`current_chat_messages`** - прямой доступ `self.message_manager.current_chat_messages.to_vec()` -6. **`current_pinned_message`** - прямой доступ `self.message_manager.current_pinned_message.clone()` - -**Результат**: -- ✅ Компиляция успешна -- ✅ Все 196+ тестов проходят -- ✅ Приложение запускается без ошибок -- ✅ Отправка сообщений работает -- ✅ Редактирование сообщений работает -- ✅ Удаление и пересылка сообщений работают - -**Файлы изменены**: -- `src/tdlib/client_impl.rs` - исправлены 6 методов trait реализации - ---- - -### Рефакторинг — Dependency Injection для TdClient ЗАВЕРШЁН ✅ (2026-02-02) - -**Статус**: ВСЕ 8 ЭТАПОВ ЗАВЕРШЕНЫ! 🎉 - -**Цель**: Реализовать trait-based DI для TdClient, чтобы тесты использовали FakeTdClient вместо реального TDLib клиента. - -**План (8 этапов) - ВСЕ ГОТОВО**: -1. ✅ Создать trait TdClientTrait -2. ✅ Реализовать trait для TdClient -3. ✅ Реализовать trait для FakeTdClient -4. ✅ Сделать App generic: `App` -5. ✅ Обновить все input handlers (generic) -6. ✅ Обновить все UI модули (generic) -7. ✅ Обновить TestAppBuilder и тесты -8. ✅ Убрать timeout'ы (100ms), запустить тесты - -**Что сделано (ВСЕ ЭТАПЫ)**: - -**Этапы 1-2: Trait и impl для TdClient** -- ✅ Создан `src/tdlib/trait.rs` (130 строк): - - Trait `TdClientTrait` с 40+ методами - - Все async методы с `#[async_trait]` - - Auth, Chat, Message, User, Reaction методы - - Getters/Setters для state - -- ✅ Создан `src/tdlib/client_impl.rs` (270 строк): - - `impl TdClientTrait for TdClient` - - Все методы делегируют к существующим - - Полное покрытие API - -**Этап 3: FakeTdClient trait impl** -- ✅ Создан `tests/helpers/fake_tdclient_impl.rs` (~300 строк): - - `impl TdClientTrait for FakeTdClient` - - Делегирование к методам FakeTdClient - - Обработка Arc> vs &references design limitation - - Некоторые методы возвращают пустые значения (для UI-only полей) - -**Этап 4: Generic App** -- ✅ Обновлён `src/app/mod.rs`: - - `pub struct App` - - `impl App` - generic impl со всеми методами - - `impl App` - convenience `new(config)` для продакшена - - `with_client(config, td_client)` - generic конструктор - -**Этап 5: Generic input handlers** -- ✅ Обновлены ВСЕ input handlers: - - `src/input/main_input.rs` - `handle(app: &mut App)` - - `src/input/auth.rs` - generic - - `src/input/handlers/global.rs` - `handle_global_commands()` + `handle_pinned_messages()` - - `src/input/handlers/profile.rs` - generic - - `src/input/handlers/chat_list.rs` - generic - - `src/input/handlers/modal.rs` - все 4 функции generic - - `src/input/handlers/search.rs` - обе функции generic - - `src/input/handlers/messages.rs` - generic - -**Этап 6: Generic UI modules** -- ✅ Обновлены ВСЕ UI модули: - - `src/ui/mod.rs` - `render()` - - `src/ui/loading.rs` - generic - - `src/ui/auth.rs` - generic - - `src/ui/main_screen.rs` - generic - - `src/ui/chat_list.rs` - generic - - `src/ui/footer.rs` - generic - - `src/ui/messages.rs` - generic - - `src/ui/profile.rs` - generic - -**Этап 7: Тесты и TestAppBuilder** -- ✅ Обновлён `tests/helpers/app_builder.rs`: - - `build() -> App` вместо `App` - - Использует `FakeTdClient::new()` + builder pattern - - Чистая работа без обращения к internal fields - - Все тесты билдера обновлены -- ✅ Обновлён `src/main.rs`: - - `run_app()` - generic - - `main()` использует `App::new(config)` - работает как раньше - -**Этап 8: Удалены timeout'ы** -- ✅ Удалены 3 timeout wrapper'а из `src/input/main_input.rs`: - - Typing status send (line ~869) - убран `tokio::time::timeout(100ms)` - - Draft save (line ~685) - убран `tokio::time::timeout(100ms)` - - Draft clear (line ~691) - убран `tokio::time::timeout(100ms)` -- Причина удаления: timeout'ы были добавлены "чтобы не блокировать UI в тестах", но теперь тесты используют FakeTdClient который возвращается мгновенно - -**Файлы созданы**: -- `src/tdlib/trait.rs` - trait definition -- `src/tdlib/client_impl.rs` - impl for TdClient -- `tests/helpers/fake_tdclient_impl.rs` - impl for FakeTdClient - -**Файлы изменены (основные)**: -- `src/tdlib/mod.rs` - экспорты FolderInfo, UserCache, TdClientTrait -- `src/app/mod.rs` - generic App -- `src/main.rs` - generic run_app() -- `src/input/*.rs` - все handlers generic -- `src/ui/*.rs` - все UI функции generic -- `tests/helpers/app_builder.rs` - build() -> App -- `tests/helpers/mod.rs` - добавлен fake_tdclient_impl модуль -- `Cargo.toml` - добавлен async-trait - -**Результат**: -- ✅ Чистая архитектура с trait-based DI -- ✅ App работает с любым T: TdClientTrait -- ✅ Тесты используют FakeTdClient (быстро, без логов) -- ✅ Продакшн использует TdClient (реальный TDLib) -- ✅ Убраны timeout'ы из продакшн кода -- ✅ Priority 6 ЗАВЕРШЁН на 100%! 🎉 - ---- - -## Последние обновления (2026-02-02 ранее) - -### Рефакторинг — UI компоненты message_bubble.rs ЗАВЕРШЁН ✅ (2026-02-02) - -**Что сделано**: -- ✅ Создан полноценный модуль `src/ui/components/message_bubble.rs` (437 строк): - - `render_date_separator()` — рендеринг разделителей дат с центрированием - - `render_sender_header()` — рендеринг заголовков отправителей (входящие/исходящие) - - `render_message_bubble()` — рендеринг сообщений (forward, reply, текст с entities, реакции) - - Функция `wrap_text_with_offsets()` для переноса длинных текстов - -- ✅ Упрощён `src/ui/messages.rs`: - - Удалено **~300 строк** ручной группировки и рендеринга - - Используется `message_grouping::group_messages()` для логической группировки - - Используются компоненты для рендеринга каждого типа `MessageGroup` - - Код стал чище и понятнее - -- ✅ Обновлены модули: - - `src/ui/components/mod.rs` — добавлены экспорты новых функций - - `src/main.rs` — добавлен `mod message_grouping;` - -**Результат**: -- ✅ Все **196 тестов** (188 tests + 8 benchmarks) прошли успешно -- ✅ Ничего не сломалось - тесты защитили от регрессии -- ✅ **P3.7 — UI компоненты**: 5/5 (100%) ЗАВЕРШЕНО! -- ✅ Код стал модульным и переиспользуемым -- ✅ Упрощена поддержка и тестирование - -**Преимущества**: -- 📦 Разделение ответственности — логика (grouping) отделена от представления (rendering) -- 🔄 Переиспользуемые компоненты для рендеринга сообщений -- 🧪 Проще тестировать отдельные части -- 📖 Улучшенная читаемость кода -- 🛡️ Тесты подтвердили корректность рефакторинга - -**Файлы изменены**: -- `src/ui/components/message_bubble.rs` — создан (437 строк) -- `src/ui/components/mod.rs` — добавлены экспорты -- `src/ui/messages.rs` — упрощён (~300 строк удалено, используются компоненты) -- `src/main.rs` — добавлен `mod message_grouping;` -- `REFACTORING_ROADMAP.md` — обновлён статус P3.7 -- `CONTEXT.md` — добавлена запись об изменениях - ---- - -## Последние обновления (2026-02-02 СЕЙЧАС) - -### Интеграция validation utils — Завершение рефакторинга #1 ✅ (2026-02-02) - -**Проблема**: -- Модуль `validation.rs` был создан, но НИ РАЗУ не использовался в реальном коде -- Экспорт был закомментирован в `utils/mod.rs` -- 4 места с проверкой `.is_empty()` должны были использовать `is_non_empty()` -- Оставался 1 прямой вызов `tokio::time::timeout` в main.rs - -**Что исправлено**: - -1. ✅ **Раскомментирован экспорт validation** (src/utils/mod.rs:11) - ```rust - pub use validation::*; // Теперь экспортируется! - ``` - -2. ✅ **Интегрирован is_non_empty() в 4 местах**: - - `src/input/auth.rs:18` — валидация phone_input перед отправкой - - `src/input/auth.rs:50` — валидация code_input перед отправкой - - `src/input/auth.rs:82` — валидация password_input перед отправкой - - `src/input/main_input.rs:484` — валидация message_input перед отправкой/редактированием - -3. ✅ **Заменён последний прямой timeout** (src/main.rs:180) - ```rust - // Было: - let _ = tokio::time::timeout(Duration::from_secs(SHUTDOWN_TIMEOUT_SECS), polling_handle).await; - - // Стало: - with_timeout_ignore(Duration::from_secs(SHUTDOWN_TIMEOUT_SECS), polling_handle).await; - ``` - -**Итог**: -- ✅ **Категория #1 (Дублирование кода) ПОЛНОСТЬЮ ЗАВЕРШЕНА!** - - retry utils: 100% покрытие (0 прямых timeout вызовов) - - modal_handler: интегрирован в 2 диалогах - - validation: интегрирован в 4 местах -- ✅ Все утилиты созданы, протестированы И применены в реальном коде -- ✅ Дублирование устранено на ~15-20% кодовой базы - -**Файлы изменены**: -- `src/utils/mod.rs` — раскомментирован экспорт validation -- `src/input/auth.rs` — 3 замены на is_non_empty() -- `src/input/main_input.rs` — 1 замена на is_non_empty() -- `src/main.rs` — замена timeout на with_timeout_ignore -- `REFACTORING_OPPORTUNITIES.md` — обновлён статус категории #1 -- `CONTEXT.md` — добавлена запись об изменениях - ---- - -## Последние обновления (2026-02-02 ранее) - -### Исправление интеграционных тестов — Проблема с TDLib в тестах ✅ (2026-02-02) - -**Проблема**: -- 5 интеграционных тестов зависали более 60 секунд: - - `test_russian_keyboard_navigation` - - `test_backspace_with_cursor` - - `test_cursor_navigation_in_input` - - `test_esc_closes_chat` - - `test_home_end_in_input` - - `test_insert_char_at_cursor_position` -- Причина: тесты создавали настоящий `TdClient`, который вызывал `tdlib_rs::create_client()` -- TDLib не был инициализирован параметрами и блокировал async вызовы -- Verbose логи от TDLib загромождали вывод тестов - -**Что исправлено**: - -1. ✅ **Русская раскладка навигации** (src/input/main_input.rs:945): - - Исправлена ошибка: использовалась 'ц' вместо 'р' для движения вверх - - Правильно: `KeyCode::Char('р')` (русская k) для Up - -2. ✅ **Timeout для send_chat_action при вводе** (src/input/main_input.rs:867-870): - ```rust - let _ = tokio::time::timeout( - Duration::from_millis(100), - app.td_client.send_chat_action(ChatId::new(chat_id), ChatAction::Typing) - ).await; - ``` - -3. ✅ **Timeout для set_draft_message при закрытии чата** (src/input/main_input.rs:683-692): - ```rust - let _ = tokio::time::timeout( - Duration::from_millis(100), - app.td_client.set_draft_message(chat_id, draft_text) - ).await; - ``` - -4. ✅ **Timeout для send_chat_action Cancel при отправке** (src/input/main_input.rs:592-594): - ```rust - let _ = tokio::time::timeout( - Duration::from_millis(100), - app.td_client.send_chat_action(ChatId::new(chat_id), ChatAction::Cancel) - ).await; - ``` - -**Результат**: -- ✅ Все 6 тестов проходят успешно за **0.11 секунды** (вместо 60+ секунд зависания) -- ✅ Тесты стабильны и не блокируются -- ⚠️ Логи TDLib всё ещё выводятся (можно игнорировать или перенаправить stderr) - -**Техническое решение**: -- Выбран **Вариант 3** (добавление timeout'ов) как временное прагматичное решение -- Timeout'ы защищают от зависания UI даже в продакшене (не критичные операции) -- Альтернатива (Dependency Injection через trait) задокументирована в `REFACTORING_ROADMAP.md` → Priority 6 - -**Добавлено в roadmap**: -- ✅ Создан **Priority 6: Улучшение тестируемости** - - P6.1 — Dependency Injection для TdClient - - Документированы 3 варианта решения с плюсами/минусами - - Оценка трудозатрат: 2-3 дня для trait-based DI - - Текущее состояние: Вариант 3 применён временно - -**Все тесты проходят**: 196 passed (188 tests + 8 benchmarks) ✅ - -**Файлы изменены**: -- `src/input/main_input.rs` — добавлены 3 timeout обёртки -- `REFACTORING_ROADMAP.md` — добавлен Priority 6 с детальным анализом -- `CONTEXT.md` — обновлён контекст проекта - ---- - -## Последние обновления (2026-02-01) - -### Рефакторинг — Подготовка к разделению больших файлов (#2) ⏳ (2026-02-01) - -**Что сделано**: -- ✅ Создана модульная структура `src/input/handlers/` (подготовка): - - `clipboard.rs` (~100 строк) - извлечены операции с буфером обмена - - `global.rs` (~90 строк) - извлечены глобальные команды (Ctrl+R/S/P/F) - - Заглушки: `profile.rs`, `search.rs`, `modal.rs`, `messages.rs`, `chat_list.rs` -- ⏳ `main_input.rs` остаётся монолитным (1139 строк) - - Попытка полной миграции привела к поломке навигации - откачено - - Handlers остаются как подготовка к постепенной миграции - -**Статус Большие файлы (#2.1)**: ⏳ Подготовка (2/7) -- ✅ Структура handlers создана -- ✅ clipboard.rs извлечён (не используется, подготовка) -- ✅ global.rs извлечён (не используется, подготовка) -- ⏳ Требуется постепенная миграция с тщательным тестированием - -**Урок**: Критичная логика ввода требует осторожного рефакторинга с проверкой функциональности после каждого шага. - -**Все тесты проходят**: 563 passed; 0 failed ✅ - ---- - -### Рефакторинг — Быстрые победы (Вариант 1) ✅ (2026-02-01) - -**Что сделано**: -- ✅ Создан `src/utils/modal_handler.rs` (120+ строк): - - 4 функции для обработки модальных окон - - `ModalAction` enum для type-safe обработки - - Поддержка английской и русской раскладки - - 4 unit теста (все проходят) -- ✅ Создан `src/utils/validation.rs` (180+ строк): - - 7 функций валидации: `is_non_empty()`, `is_within_length()`, `is_valid_chat_id()`, и др. - - Покрывает все основные паттерны валидации - - 7 unit тестов (все проходят) -- ✅ Частичная инкапсуляция App: - - Поле `config` сделано приватным (readonly через `app.config()`) - - Добавлено 30+ методов-геттеров и сеттеров - - Остальные поля оставлены pub для совместимости - -**Статус Дублирование кода (#1)**: ✅ ПОЛНОСТЬЮ ЗАВЕРШЕНО И ИНТЕГРИРОВАНО! (3/3) -- ✅ retry utils — 100% покрытие (0 прямых timeout вызовов, использовано в 8+ местах) -- ✅ modal_handler — интегрирован в 2 диалогах (leave group, delete message) -- ✅ validation — интегрирован в 4 местах (auth.rs x3, main_input.rs x1) - -**Статус Инкапсуляция (#5)**: ✅ Частично выполнено (1/4) -- ✅ Config инкапсулирован -- ⏳ Полная инкапсуляция требует массового рефакторинга 170+ мест - -**Все тесты проходят**: 563 passed; 0 failed ✅ - ---- - -### Тестирование — Фаза 4 ЗАВЕРШЕНА! ✅ (2026-02-01) - -**Что сделано**: -- ✅ Добавлено 9 новых unit тестов в `src/utils/formatting.rs`: - - 4 теста для `format_date()` (today, yesterday, old, epoch) - - 5 тестов для `format_was_online()` (just now, minutes/hours/days ago, very old) -- ✅ Создано 3 performance benchmark файла в `benches/`: - - `group_messages.rs` — benchmark группировки сообщений (100, 500) - - `formatting.rs` — benchmark форматирования времени и даты - - `format_markdown.rs` — benchmark markdown форматирования -- ✅ Добавлена зависимость `criterion = "0.5"` в Cargo.toml -- ✅ Все тесты проходят: **188 тестов + 8 benchmarks** - -**Статус Utils Tests**: 18/18 (100%) ✅ -**Статус Performance Benchmarks**: 8/8 (100%) ✅ - -**🎉🎊 ВСЕ ТЕСТЫ ПОЛНОСТЬЮ ЗАВЕРШЕНЫ! 🎊🎉** - -Общий прогресс тестирования: **196/196 (100%)** -- Фаза 0-3: ✅ Завершены -- Фаза 4.1 (Utils): ✅ Завершена -- Фаза 4.2 (Performance): ✅ Завершена - ---- - -### P3.8 — Извлечение форматирования ✅ ЗАВЕРШЕНО! - -**Что сделано**: -- ✅ Создан `src/formatting.rs` с логикой markdown форматирования (262 строки) -- ✅ Перенесены функции из `messages.rs`: - - `CharStyle` — структура для стилей символов (bold, italic, code, spoiler, url, mention) - - `format_text_with_entities()` — преобразование текста с entities в стилизованные Span - - `styles_equal()` — сравнение стилей - - `adjust_entities_for_substring()` — корректировка entities при переносе текста -- ✅ Добавлено 5 unit тестов для форматирования -- ✅ Обновлены `src/lib.rs` и `src/main.rs` для экспорта модуля -- ✅ `src/ui/messages.rs` сокращён на ~143 строки -- ✅ Все lib тесты проходят (17 passed) -- ✅ Бинарник компилируется успешно - -**Преимущества**: -- 📦 Логика форматирования изолирована в отдельном модуле -- ✅ Можно тестировать независимо -- 🔄 Легко переиспользовать в других компонентах UI -- 📖 Улучшена читаемость кода - -**🎉 Статус Priority 3: ЗАВЕРШЁН 100% (4/4 задачи)! 🎉** -- ✅ P3.7 — UI компоненты -- ✅ P3.8 — Форматирование -- ✅ P3.9 — Группировка сообщений -- ✅ P3.10 — Hotkey mapping - -**P3.10 — Hotkey mapping** ✅ ЗАВЕРШЕНО! - -**Что сделано**: -- ✅ Создан `HotkeysConfig` с 10 настраиваемыми горячими клавишами -- ✅ Реализован метод `matches(key: KeyCode, action: &str)` для проверки hotkeys -- ✅ Исправлен баг с UTF-8 (chars().count() вместо len() для поддержки кириллицы) -- ✅ Добавлены 9 unit тестов (все проходят) -- ✅ Hotkeys добавлены в Config::default() с дефолтными значениями - -**Дефолтные горячие клавиши**: -```toml -[hotkeys] -up = "k,ц" -down = "j,о" -reply = "r,к" -forward = "f,а" -delete = "d,в" -edit = "e,у" -copy = "y,н" -view_profile = "i,ш" -reaction = "1234567890" -quit = "q,й" -``` - -**P3.9 — Группировка сообщений** ✅ ЗАВЕРШЕНО! - -**Что сделано**: -- ✅ Перенесён код группировки из `ui/messages.rs` в отдельный модуль `src/message_grouping.rs` (274 строки) -- ✅ Создана публичная функция `group_messages(messages: &[MessageInfo]) -> Vec` -- ✅ Группировка по дате и отправителю с оптимизацией -- ✅ Добавлены 7 unit тестов -- ✅ Добавлен doctest пример в rustdoc - -**P4.12 — Rustdoc (частично)** ⏳ 30% - -**Что сделано**: -- ✅ Добавлена документация для TdClient (60+ строк rustdoc) -- ✅ Добавлена документация для App struct -- ✅ Добавлены doctests примеры использования -- ✅ Исправлены все doctests для компиляции - -**Статус тестов**: 464 теста, все проходят ✅ - ---- - -### 🎉🎊 PRIORITY 2 ЗАВЕРШЁН НА 100%! 🎊🎉 - -**P2.7 — MessageBuilder pattern** ✅ ФИНАЛЬНАЯ ЗАДАЧА ЗАВЕРШЕНА! - -**Что сделано**: -- ✅ Создан MessageBuilder с fluent API (323 строки кода) -- ✅ Реализовано 16 методов для удобного создания сообщений -- ✅ Обновлён convert_message() для использования builder -- ✅ Добавлены 6 unit тестов - -**Пример использования**: -```rust -let message = MessageBuilder::new(MessageId::new(123)) - .sender_name("Alice") - .text("Hello!") - .outgoing() - .read() - .build(); -``` - -**🏆 ИТОГИ PRIORITY 2 (100% - 5/5 задач):** -- ✅ P2.5 — Error enum -- ✅ P2.3 — Config validation -- ✅ P2.4 — Newtype для ID -- ✅ P2.6 — MessageInfo реструктуризация -- ✅ P2.7 — MessageBuilder pattern ← ФИНАЛ! - -**Преимущества Priority 2**: -- 🛡️ Type safety повсюду -- 📦 Логическая структура данных -- 🔧 Удобные API для работы с кодом -- 📚 Самодокументирующийся код - ---- - -**P2.6 — Реструктуризация MessageInfo** ✅ ЗАВЕРШЕНО! - -**Что сделано**: -- ✅ Сгруппированы 16 плоских полей в 4 логические структуры -- ✅ Создано 4 новых типа: MessageMetadata, MessageContent, MessageState, MessageInteractions -- ✅ Добавлен конструктор MessageInfo::new() и getter методы -- ✅ Обновлены 14 файлов с ~200+ обращениями к полям -- ✅ Все тестовые файлы обновлены - -**Преимущества**: -- 📦 Логическая группировка данных -- 🔍 Проще понимать структуру сообщения -- ➕ Легче добавлять новые поля -- 📚 Улучшенная читаемость кода - -**Статус Priority 2**: 80% (4/5 задач) ✅ -- ✅ Error enum -- ✅ Config validation -- ✅ Newtype для ID -- ✅ MessageInfo реструктуризация ← ТОЛЬКО ЧТО! -- ⏳ MessageBuilder pattern (последняя!) - ---- - -**P2.4 — Newtype pattern для ID** ✅ ЗАВЕРШЕНО! - -**Что сделано**: -- ✅ Создан `src/types.rs` с типобезопасными обёртками для идентификаторов -- ✅ Реализованы три типа: `ChatId(i64)`, `MessageId(i64)`, `UserId(i64)` -- ✅ Добавлены методы: `new()`, `as_i64()`, `From`, `Display`, `Hash`, `Eq`, `Serialize/Deserialize` -- ✅ Обновлены 15+ модулей для использования новых типов -- ✅ Исправлены 53 ошибки компиляции связанные с type conversions -- ✅ Компилятор теперь предотвращает смешивание разных типов ID на этапе компиляции - -**Модули обновлены**: -- `tdlib/types.rs` — ChatInfo, MessageInfo, ReplyInfo, ProfileInfo -- `tdlib/chats.rs` — все методы с chat_id параметрами -- `tdlib/messages.rs` — MessageManager, pending_view_messages -- `tdlib/users.rs` — LruCache, UserCache mappings -- `tdlib/reactions.rs` — reaction methods -- `tdlib/client.rs` — все публичные методы и Update handlers -- `app/mod.rs` — selected_chat_id -- `app/chat_state.rs` — все варианты ChatState -- `input/main_input.rs` — обработка ввода с преобразованием типов -- Test helpers — TestAppBuilder, TestChatBuilder, TestMessageBuilder - -**Преимущества**: -- 🛡️ Type safety на уровне компиляции — невозможно перепутать ChatId, MessageId, UserId -- 🔍 Улучшенная читаемость кода — явные типы вместо i64 -- 🐛 Меньше ошибок — компилятор ловит проблемы до запуска -- 📚 Лучшая документация — типы самодокументируются - -**Статус Priority 2**: 60% (3/5 задач) ✅ -- ✅ Error enum -- ✅ Config validation -- ✅ Newtype для ID -- ⏳ MessageInfo реструктуризация -- ⏳ MessageBuilder pattern - ---- - -### Тестирование — ЗАВЕРШЕНО! 🎉🎊🚀 (2026-01-30) - -**Добавлено**: -- 📝 93 integration теста (12 файлов): send_message, edit_message, delete_message, reply_forward, reactions, search, drafts, navigation, profile, network_typing, **copy**, **config** -- 🎯 Phase 2.1-2.10 (73 теста) ✅ -- 🎯 **Phase 2.11 Copy Flow** (9 тестов) ✅ — НОВОЕ! - - Форматирование сообщений (plain, forward, reply, комбо, длинные, markdown) - - Clipboard тесты (инициализация, реальное копирование, кроссплатформенность) -- 🎯 **Phase 2.12 Config Flow** (11 тестов) ✅ — НОВОЕ! - - Config дефолты и кастомные значения - - Парсинг цветов (валидные, light, невалидные с fallback, case-insensitive) - - TOML сериализация/десериализация - - Timezone форматы - - Credentials загрузка (из env, проверка ошибок) -- 📚 Обновлена документация тестирования (TESTING_PROGRESS.md, TESTING_ROADMAP.md, CONTEXT.md) - -**Покрытие**: 148/151 тестов (98%) — БОЛЬШЕ ЧЕМ ПЛАНИРОВАЛОСЬ! 🎉 -- ✅ Phase 0: Инфраструктура (100%) -- ✅ Phase 1: UI Snapshot Tests (100%) - 55 тестов -- ✅ Phase 2: Integration Tests (100%!) - 93 тестов (вместо запланированных 84!) - - Copy Flow: 9 тестов (вместо 3) - - Config Flow: 11 тестов (вместо 8) - -**Все тесты проходят**: `cargo test` → 148+ passed ✅ - -**Статус**: ВСЕ ОСНОВНЫЕ ТЕСТЫ ЗАВЕРШЕНЫ! Опциональные тесты (E2E smoke, utils, performance) можно сделать позже. - -Подробности: [TESTING_PROGRESS.md](TESTING_PROGRESS.md) - -### Рефакторинг — Приоритет 1 ЗАВЕРШЁН! 🏗️✨ (2026-01-30) - -**Статус**: Priority 1 (3/3 задач) ✅ ЗАВЕРШЕНО! - -**Завершено**: -- ✅ **P1.3 — Константы** (ранее) - - Вынесены магические числа в `src/constants.rs` - - Улучшена читаемость и maintainability - -- ✅ **P1.2 — Разделение TdClient** (2026-01-30) - - Разделён монолитный TdClient (2036 строк, 87KB) на 7 модулей: - - `auth.rs` — AuthManager + AuthState enum (6.8KB) - - `chats.rs` — ChatManager для операций с чатами (8.1KB) - - `messages.rs` — MessageManager для сообщений (18.5KB) - - `users.rs` — UserCache с LRU кэшем (6.2KB) - - `reactions.rs` — ReactionManager (4.2KB) - - `types.rs` — Общие типы данных (10.8KB) - - `mod.rs` — Экспорты модулей - - Размер client.rs сократился на **50%** (87KB → 42.5KB) - - Исправлено 130+ ошибок компиляции из-за изменений в tdlib-rs API - - Все 330 тестов проходят ✅ - -- ✅ **P1.1 — ChatState enum** (2026-01-30) - - Схлопнуты 14 boolean полей в type-safe enum `ChatState` - - Невозможно иметь несколько состояний одновременно - - Данные состояния хранятся вместе с ним - - Варианты: Normal, MessageSelection, Editing, Reply, Forward, DeleteConfirmation, ReactionPicker, Profile, SearchInChat, PinnedMessages - - Обновлены все методы App для делегирования к ChatState - - Все 330 тестов проходят ✅ - -**Преимущества**: -- Код стал более модульным и maintainable -- Улучшена type-safety -- Проще добавлять новые фичи -- Лучше читаемость - -**Priority 2 (100% завершено - 5/5)** ✅ ПОЛНОСТЬЮ ЗАВЕРШЁН! 🎉: -- ✅ **P2.5 — Error enum** (завершено 2026-01-31) - - Создан `src/error.rs` с типобезопасным enum `TeletuiError` - - Добавлены варианты: TdLib, Config, Network, Auth, Chat, Message, User, InvalidTimezone, InvalidColor, Clipboard, Io, Toml, Json, Other - - Type alias `Result` для упрощения сигнатур - - Использован `thiserror` для автоматического Display - - Заменены все `Result` на `Result` в 7 модулях - - Все 350 тестов проходят ✅ - -- ✅ **P2.3 — Config validation** (завершено 2026-01-31) - - Добавлен метод `Config::validate()` для проверки конфигурации - - Валидация timezone: проверка что начинается с + или - - - Валидация цветов: проверка что цвет из списка допустимых (black, red, green, yellow, blue, magenta, cyan, gray, white, darkgray, lightred, lightgreen, lightyellow, lightblue, lightmagenta, lightcyan) - - При загрузке невалидного конфига автоматически используется дефолтный - - Все 350 тестов проходят ✅ - -- ✅ **P2.4 — Newtype pattern для ID** (завершено 2026-01-31) - - Создан `src/types.rs` с типобезопасными обёртками: `ChatId`, `MessageId`, `UserId` - - Реализованы методы: `new()`, `as_i64()`, `From`, `Display`, `Hash`, `Eq`, `Serialize/Deserialize` - - Обновлены 15+ модулей для использования новых типов: - - `tdlib/types.rs`: ChatInfo, MessageInfo, ReplyInfo, ProfileInfo - - `tdlib/chats.rs`, `tdlib/messages.rs`, `tdlib/users.rs`, `tdlib/reactions.rs` - - `tdlib/client.rs`: все методы и Update handlers - - `app/mod.rs`, `app/chat_state.rs` - - `input/main_input.rs` - - Test helpers (app_builder, test_data) - - Компилятор теперь предотвращает смешивание разных типов ID - - Все тесты компилируются успешно ✅ - -- ✅ **P2.6 — Реструктуризация MessageInfo** (завершено 2026-01-31) - - Сгруппированы 16 плоских полей MessageInfo в 4 логические структуры - - Новые структуры: - - `MessageMetadata`: id, sender_name, date, edit_date - - `MessageContent`: text, entities - - `MessageState`: is_outgoing, is_read, can_be_edited, can_be_deleted_* - - `MessageInteractions`: reply_to, forward_from, reactions - - Добавлен конструктор `MessageInfo::new()` для удобного создания - - Добавлены getter методы для удобного доступа (id(), text(), sender_name() и др.) - - Обновлены 14 файлов (~200+ обращений к полям): - - `ui/messages.rs`: рендеринг сообщений (100+ изменений) - - `app/mod.rs`, `input/main_input.rs`: логика приложения - - `tdlib/client.rs`: обработка updates - - Все тестовые файлы - - Логическая группировка данных улучшает maintainability ✅ - -- ✅ **P2.7 — MessageBuilder pattern** (завершено 2026-01-31) - - Создан `MessageBuilder` с fluent API для удобного создания сообщений - - Реализованы методы: - - Базовые: `sender_name()`, `text()`, `entities()`, `date()`, `edit_date()` - - Флаги: `outgoing()`, `incoming()`, `read()`, `unread()`, `edited()` - - Права: `editable()`, `deletable_for_self()`, `deletable_for_all()` - - Дополнительно: `reply_to()`, `forward_from()`, `reactions()`, `add_reaction()` - - Финализация: `build()` → MessageInfo - - Обновлён `convert_message()` для использования builder - - Добавлены 6 unit тестов демонстрирующих fluent API - - Преимущества: читабельность, гибкость, самодокументирование ✅ - -**🎉 Priority 2 ЗАВЕРШЁН НА 100%! 🎉** - -**Следующие шаги**: Priority 3 (UI компоненты, форматирование, группировка сообщений) - -Подробности: [REFACTORING_ROADMAP.md](REFACTORING_ROADMAP.md) - -## Что НЕ сделано / TODO - -Все пункты Фазы 9 завершены! Можно переходить к следующей фазе разработки или продолжить написание тестов. - -## Технический долг - -См. [REFACTORING_ROADMAP.md](REFACTORING_ROADMAP.md) для детального плана рефакторинга. - -**Завершено** (Priority 1): -1. ~~**ChatState enum**~~ ✅ — схлопнуты boolean состояния в type-safe enum -2. ~~**Разделение TdClient**~~ ✅ — разделён на 7 модулей -3. ~~**Константы**~~ ✅ — вынесены в отдельный модуль - -**Завершено** (Priority 1): ✅ 3/3 (100%) -1. ~~**ChatState enum**~~ ✅ -2. ~~**Разделение TdClient**~~ ✅ -3. ~~**Константы**~~ ✅ - -**Завершено** (Priority 2): ✅ 5/5 (100%) 🎉 -1. ~~**Error enum**~~ ✅ — типобезопасная обработка ошибок (2026-01-31) -2. ~~**Config validation**~~ ✅ — валидация конфигурации при загрузке (2026-01-31) -3. ~~**Newtype pattern для ID**~~ ✅ — типобезопасные обёртки ChatId, MessageId, UserId (2026-01-31) -4. ~~**MessageInfo реструктуризация**~~ ✅ — группировка полей в логические структуры (2026-01-31) -5. ~~**MessageBuilder pattern**~~ ✅ — fluent API для создания сообщений (2026-01-31) - -**Завершено** (Priority 3): ✅ 1/4 (25%) -1. ~~**P3.7 — UI компоненты**~~ ✅ — выделение переиспользуемых компонентов (2026-01-31) -2. ~~**P3.8 — Форматирование**~~ ✅ — вынесено markdown форматирование в src/formatting.rs (2026-01-31) - -**В работе** (Priority 3-5): -1. **P3.9 — Группировка сообщений** — вынести логику группировки в отдельный модуль -2. **P3.10 — Hotkey mapping** — добавить настройку хоткеев в конфиг -3. **Юнит-тесты** — добавить для utils и других модулей - -## Недавние исправления - -### 31 января 2026 (вечер) — Критические баги с сообщениями, редактированием и reply -1. **Исправлена проблема с отображением новых сообщений** ✅ - - **Проблема**: Новые сообщения (как отправленные, так и входящие) не появлялись в UI - - **Причина**: Сообщения добавлялись в начало массива (`insert(0)`), но UI показывал конец массива - - **Решение**: Изменён порядок хранения — сообщения теперь добавляются в конец (`push()`) - - **Результат**: Сообщения отображаются корректно в реальном времени - -2. **Исправлено редактирование сообщений** ✅ - - **Проблема**: Ошибка "Message not found" при попытке редактировать - - **Причина**: Метод `get_selected_message()` конвертировал индекс в обратном порядке (старая логика) - - **Решение**: - - Убрана конвертация индекса в `get_selected_message()` - - Исправлена логика выбора: `start_message_selection()` начинает с индекса `len-1` (последнее сообщение) - - Обновлена логика навигации: `select_previous_message()` уменьшает индекс, `select_next_message()` увеличивает - - **Результат**: Редактирование работает без ошибок - -3. **Исправлен reply на сообщения** ✅ - - **Проблема 1**: Reply не отправлялся (нажатие Enter ничего не делало) - - **Причина**: Неправильная структура условий — reply попадал в блок с `selected_message_id`, но не в блок отправки - - **Решение**: Изменена структура условий — проверка `is_editing()` вынесена наружу - - **Проблема 2**: Reply отправлялся, но не показывалось превью исходного сообщения - - **Причина**: Параметр `_reply_info` в `send_message()` не использовался - - **Решение**: Убрано подчёркивание и добавлена логика сохранения `reply_info` в `MessageInfo` после `convert_message()` - - **Результат**: Reply работает корректно с превью исходного сообщения - -4. **Удалены отладочные логи** ✅ - - Удалены временные `eprintln!` из `src/tdlib/client.rs` и `src/input/main_input.rs` - -### 31 января 2026 (утро) — Баги в тестах и работе приложения -1. **Исправлены ошибки компиляции тестов** ✅ - - Исправлены синтаксические ошибки в `tests/delete_message.rs` и `tests/reply_forward.rs` - - Исправлены проблемы с доступом к полям (field vs method) - - Исправлены несоответствия типов (MessageId vs i64) - -2. **Исправлена проблема с загрузкой истории сообщений** ✅ - - Добавлен вызов `open_chat()` перед `get_chat_history()` в `src/tdlib/messages.rs` - - Реализована логика повторных попыток (retry) с задержками для синхронизации TDLib - - Исправлен race condition с установкой `current_chat_id` (теперь устанавливается после загрузки сообщений) - - **Результат**: История загружается корректно с первого раза (проверено: 51 сообщение) - -3. **Уточнена документация по редактированию сообщений** ℹ️ - - **Проблема**: Пользователь нажимал 'r' (reply) вместо Enter при попытке редактировать - - **Правильный процесс**: ↑ (выбор) → Enter (начать редактирование) → изменить текст → Enter (сохранить) - - **Ошибочный процесс**: ↑ (выбор) → 'r' (начинается режим Reply!) → текст отправляется как ответ - - Добавлены инструкции в документацию для избежания путаницы - -### 31 января 2026 (поздний вечер) — E2E интеграционные тесты ✅ -1. **Созданы E2E Smoke тесты** ✅ - - **Файл**: `tests/e2e_smoke.rs` - - **Тесты**: - - Проверка базовых структур приложения (NetworkState enum) - - Проверка минимального размера терминала (80x20) - - Проверка базовых констант (MAX_MESSAGES_IN_CHAT, MAX_CHATS, MAX_USER_CACHE_SIZE) - - Проверка graceful shutdown флага (AtomicBool) - - **Результат**: 4/4 теста, покрывают базовую функциональность без краша - -2. **Созданы User Journey интеграционные тесты** ✅ - - **Файл**: `tests/e2e_user_journey.rs` - - **Многошаговые сценарии** (8 тестов): - - Тест 1: App Launch → Auth → Chat List (загрузка списка чатов) - - Тест 2: Open Chat → Load History → Send Message (основной flow) - - Тест 3: Receive Incoming Message (симуляция входящих сообщений через update channel) - - Тест 4: Multi-step conversation (полноценная беседа туда-обратно) - - Тест 5: Switch between chats (переключение между чатами) - - Тест 6: Edit message during conversation (редактирование с проверкой edit_date) - - Тест 7: Reply to message (ответ на конкретное сообщение с reply_info) - - Тест 8: Network state changes (симуляция потери и восстановления сети) - - **Результат**: 8/8 тестов, полное покрытие пользовательских сценариев - -3. **Расширен FakeTdClient для E2E тестов** ✅ - - Добавлены геттеры для тестовых проверок: - - `get_network_state()` — получить текущее состояние сети - - `get_current_chat_id()` — получить ID открытого чата - - `set_update_channel()` — установить канал для получения update событий - - Исправлена `simulate_network_change()` — добавлен clone для state - - Все методы поддерживают async/await и работают с Arc> - -4. **Обновлены TESTING_ROADMAP.md и CONTEXT.md** ✅ - - Отмечена Фаза 3 как завершённая (100%) - - Общий прогресс тестирования: **160/163 теста (98%)** - - Остались только опциональные тесты Utils + Performance (Фаза 4) - -**Следующие шаги**: Фаза 4 (опциональная) — Utils тесты и Performance бенчмарки - -### 31 января 2026 (поздняя ночь) — Массовое исправление всех интеграционных тестов ✅ -1. **Проблема**: После расширения FakeTdClient для async все старые интеграционные тесты перестали компилироваться - -2. **Решение**: Автоматизированное исправление всех тестовых файлов - - Создан bash скрипт для массовой замены геттеров - - Использованы специализированные агенты для исправления каждого типа тестов - - Обновлены 10 тестовых файлов: send_message, edit_message, delete_message, reply_forward, reactions, network_typing, navigation, drafts, search, profile - -3. **Изменения API**: - - Все тесты конвертированы в async с tokio::test - - client теперь immutable (использует Arc> внутри) - - Все методы теперь async и требуют await - - ChatId вместо i64 для идентификаторов чатов - - Все геттеры переименованы с префиксом get_ - -4. **Результат**: - - ✅ **463 ТЕСТА ПРОШЛИ!** - - 0 ошибок компиляции - - 0 упавших тестов - - 100% success rate - - Все фазы тестирования работают (Фаза 0, 1, 2, 3) - -**Статистика по файлам**: -- E2E тесты: 27 passed (smoke 4 + user_journey 23) -- Integration тесты: 260+ passed -- Snapshot тесты: 176+ passed -- **ВСЕГО: 463 ТЕСТА** - -### 1 февраля 2026 (раннее утро) — Завершение snapshot тестов ✅ -1. **Добавлен последний snapshot тест** ✅ - - **Файл**: `tests/chat_list.rs` - - **Тест**: `snapshot_chat_with_online_status` - тест для отображения онлайн-статуса (зеленая точка ●) - - Использует прямое манипулирование `app.td_client.user_cache` для установки онлайн-статуса - - Snapshot показывает "● онлайн" в нижней панели для выбранного чата - -2. **Фаза 1 ЗАВЕРШЕНА НА 100%!** 🎉 - - 1.1 Chat List: 10/10 (100%) ✅ - - 1.2 Messages: 19/19 (100%) ✅ - - 1.3 Modals: 8/8 (100%) ✅ - - 1.4 Input Field: 7/7 (100%) ✅ - - 1.5 Footer: 6/6 (100%) ✅ - - 1.6 Screens: 7/7 (100%) ✅ - - **Всего: 57/57 snapshot тестов** - -3. **Обновлена статистика**: - - **464 ТЕСТА ПРОШЛИ** (было 463) - - Все обязательные фазы: ✅ 100% - - **Все обязательные тесты: 164/164 (100%!)** - -**Осталось только опциональные тесты**: -- Фаза 4.1: Utils тесты (5 штук) - низкий приоритет -- Фаза 4.2: Performance бенчмарки (3 штуки) - низкий приоритет - -### 31 января 2026 (поздняя ночь) — Рефакторинг Priority 3: Message Grouping ✅ -1. **Создан модуль message_grouping.rs** ✅ - - **Файл**: `src/message_grouping.rs` (255 строк) - - **Реализовано**: - - Enum `MessageGroup` с тремя вариантами: - - `DateSeparator(i32)` — разделитель даты - - `SenderHeader { is_outgoing: bool, sender_name: String }` — заголовок отправителя - - `Message(MessageInfo)` — само сообщение - - Функция `group_messages()` для группировки сообщений по дате и отправителю - - Полная документация с rustdoc комментариями - - 5 unit тестов (все проходят): - - test_group_messages_by_date - - test_group_messages_by_sender - - test_group_outgoing_vs_incoming - - test_empty_messages - - test_single_message - -2. **Обновлены файлы проекта** ✅ - - Модуль добавлен в `src/lib.rs` - - Обновлен `REFACTORING_ROADMAP.md`: - - P3.9 отмечено как завершённое ✅ - - P3.7 отмечено как частично завершённое (4/5 компонентов) - - P3.8 отмечено как завершённое ✅ - - Priority 3: 3/4 задач (75%) - - **Общий прогресс рефакторинга: 11/17 задач (65%)** - -3. **Разблокированы зависимости** ✅ - - P3.9 ✅ (Message Grouping) завершено - - P3.8 ✅ (Formatting Module) уже было завершено ранее - - Теперь можно реализовать `message_bubble.rs` (был заблокирован P3.8 и P3.9) - -4. **Результаты тестирования**: - - ✅ Все 464 теста прошли успешно - - ✅ Новые 5 unit тестов для message_grouping прошли - - ✅ Doctest для group_messages() прошёл - - ✅ Нет ошибок компиляции - -**Следующие шаги рефакторинга**: -- P3.10: Hotkey Mapping (осталась последняя задача Priority 3) -- Интеграция message_grouping в messages.rs -- Реализация message_bubble.rs (теперь разблокировано!) - -### 31 января 2026 (поздняя ночь) — Рефакторинг Priority 3: Hotkey Mapping ✅ -1. **Создана структура HotkeysConfig** ✅ - - **Файл**: `src/config.rs` (расширен на ~230 строк) - - **Реализовано**: - - Структура `HotkeysConfig` с 10 полями hotkeys - - Навигация: up, down, left, right (vim + русские + стрелки) - - Действия: reply, forward, delete, copy, react, profile (англ + русские) - - Метод `matches(key: KeyCode, action: &str) -> bool` - - Приватный метод `key_matches()` для проверки соответствия - - Поддержка специальных клавиш (Up, Down, Delete, Enter, Esc, и др.) - - Дефолтные значения для всех hotkeys - - Default impl для HotkeysConfig - -2. **Добавлены unit тесты** ✅ - - 9 unit тестов для HotkeysConfig: - - test_hotkeys_matches_char_keys - - test_hotkeys_matches_arrow_keys - - test_hotkeys_matches_vim_keys - - test_hotkeys_matches_russian_vim_keys - - test_hotkeys_matches_special_delete_key - - test_hotkeys_does_not_match_wrong_keys - - test_hotkeys_does_not_match_wrong_actions - - test_hotkeys_unknown_action - - test_config_default_includes_hotkeys - -3. **Обновлены файлы проекта** ✅ - - Добавлен import `crossterm::event::KeyCode` в config.rs - - Поле `hotkeys` добавлено в структуру `Config` - - `Config::default()` включает `hotkeys: HotkeysConfig::default()` - - Обновлен `REFACTORING_ROADMAP.md`: - - P3.10 отмечено как завершённое ✅ - - **Priority 3: 4/4 задач (100%) 🎉🎉** - - **Общий прогресс рефакторинга: 12/17 задач (71%)** - -4. **Поддержка конфигурации** ✅ - - Пользователи теперь могут настроить hotkeys в `~/.config/tele-tui/config.toml`: - ```toml - [hotkeys] - up = ["k", "р", "Up"] - down = ["j", "о", "Down"] - reply = ["r", "к"] - forward = ["f", "а"] - delete = ["d", "в", "Delete"] - copy = ["y", "н"] - react = ["e", "у"] - profile = ["i", "ш"] - ``` - -5. **Результаты**: - - ✅ Код компилируется успешно - - ✅ Все тесты проходят - - ✅ Готово к интеграции в input handlers - -**🎉 Priority 3 ЗАВЕРШЁН НА 100%! 🎉** - -**Следующие шаги рефакторинга**: -- Priority 4: Качество кода (unit тесты, rustdoc, config validation, async/await) -- Priority 5: Опциональные улучшения (feature flags, LRU cache, tracing) -- Интеграция message_grouping в messages.rs -- Реализация message_bubble.rs - -### 31 января 2026 (поздняя ночь) — Рефакторинг Priority 4: Rustdoc (частично) ✅ -1. **Добавлена документация для публичных API** ✅ - - **Файлы**: `src/tdlib/client.rs`, `src/app/mod.rs` - - **Реализовано**: - - TdClient: полная документация структуры + примеры использования - - TdClient методы: - * Авторизация: send_phone_number(), send_code(), send_password() - * Чаты: load_chats(), load_folder_chats(), leave_chat(), get_profile_info() - * Все методы имеют описания параметров, возвращаемых значений и ошибок - - App: документация структуры с объяснением state machine - - App методы: new() с примером использования - - **Прогресс**: +60 строк doc-комментариев (210 → 270) - -2. **Обновлена документация проекта** ✅ - - Обновлен REFACTORING_ROADMAP.md (P4.12 отмечено как частично завершённое) - -**Текущий статус рефакторинга**: -- ✅ Priority 1: 3/3 (100%) -- ✅ Priority 2: 5/5 (100%) -- ✅ Priority 3: 4/4 (100%) 🎉 -- ✅ Priority 4: 4/4 (100%) 🎉 -- ✅ Priority 5: 3/3 (100%) 🎉🎉🎉 - -**🎊🎉 РЕФАКТОРИНГ ПОЛНОСТЬЮ ЗАВЕРШЁН: 20/20 задач (100%)! 🎉🎊** - -**Последние изменения (1 февраля 2026)**: -- ✅ **P5.15 — Feature flags для зависимостей** (2026-02-01) - - Добавлены опциональные features `clipboard` и `url-open` в Cargo.toml - - Зависимости `arboard` и `open` теперь опциональные - - Условная компиляция в коде с graceful degradation - - Преимущества: уменьшение размера бинарника, модульность - -- ✅ **P5.16 — LRU cache обобщение** (2026-02-01) - - Обобщена структура `LruCache` в src/tdlib/users.rs - - Type-safe: `K: Eq + Hash + Clone + Copy`, `V: Clone` - - Обновлены типы в UserCache: `LruCache`, `LruCache` - - Переиспользуемая реализация без дополнительных зависимостей - -- ✅ **P5.17 — Tracing вместо eprintln!** (2026-02-01) - - Добавлены зависимости `tracing` и `tracing-subscriber` в Cargo.toml - - Инициализирован subscriber в main.rs с env-filter - - Заменены все `eprintln!` на tracing макросы (`warn!`, `error!`) - - Настраиваемые уровни логов через переменную окружения `RUST_LOG` - -**Достижения рефакторинга**: -✅ Все 5 приоритетов завершены на 100% -✅ 20/20 задач выполнено -✅ Type safety повсюду (newtypes, enums) -✅ Модульная архитектура (client разделён на 7 модулей) -✅ Переиспользуемые компоненты (UI, formatting, grouping) -✅ Качество кода (rustdoc, тесты, валидация) -✅ Опциональные улучшения (feature flags, generic cache, tracing) - -## Дополнительный рефакторинг больших файлов (2026-02-03) - -После завершения основного рефакторинга (20/20 задач), продолжена работа по разделению больших монолитных файлов и функций. - -### Phase 2-4: Рефакторинг main_input.rs ✅ - -**Phase 2** (коммит f4c24dd): -- Извлечены обработчики клавиатуры и навигации (2 функции) -- handle() сокращена с 891 до ~734 строк - -**Phase 3** (коммиты 45d03b5, 7e372bf): -- Извлечены ВСЕ оставшиеся обработчики режимов (11 функций) -- handle() сокращена до 82 строк (91% ✂️) -- Итого: 13 извлечённых функций - -**Phase 4** (коммиты 67fd750, 9d9232f, 6150fe3): -- Применены паттерны упрощения вложенности (early returns, let-else guards) -- Разделён handle_enter_key() на 3 части (130 → 40 строк, 67% ✂️) -- Вложенность сокращена с 6+ до 2-3 уровней - -### Phase 5: Рефакторинг ui/messages.rs ✅ ЗАВЕРШЁН! - -**Коммит 315395f** - Начало Phase 5: -- Извлечены: render_chat_header(), render_pinned_bar() (~80 строк) -- render() сокращена на ~65 строк - -**Коммит 2dbbf1c** - Завершение Phase 5: -- Извлечены: render_message_list() (~100 строк), render_input_box() (~145 строк) -- render() сокращена с **~390 до ~92 строк (76% ✂️)** -- Итого: **4 извлечённые функции** для модульного рендеринга - -**Результат Phase 5:** -``` -render() теперь (~92 строки): - ├─ Early returns (profile/search/pinned modes) ~15 строк - ├─ Layout setup (вычисление размеров) ~35 строк - ├─ Делегирование в 4 функции: - │ ├─ render_chat_header() - заголовок с typing status - │ ├─ render_pinned_bar() - панель закреплённого сообщения - │ ├─ render_message_list() - список + автоскролл - │ └─ render_input_box() - input с режимами (forward/select/edit/reply) - └─ Modal overlays (delete/reaction picker) ~15 строк -``` - -**Достижения дополнительного рефакторинга:** -- ✅ main_input.rs: handle() сокращена на 91% (891 → 82 строки) -- ✅ ui/messages.rs: render() сокращена на 76% (390 → 92 строки) -- ✅ Применены современные Rust паттерны (let-else guards, early returns) -- ✅ Код стал модульным и читаемым -- ✅ Каждая функция имеет чёткую ответственность - -### Phase 6: Рефакторинг tdlib/client.rs ✅ ЗАВЕРШЁН! (2026-02-04) - -**Этап 1** (коммит 0acf864) - Извлечение Update Handlers: -- Создан модуль `src/tdlib/update_handlers.rs` (302 строки) -- **Извлечено 8 handler функций** (~350 строк): - - handle_new_message_update() — добавление новых сообщений (44 строки) - - handle_chat_action_update() — статус набора текста (32 строки) - - handle_chat_position_update() — управление позициями чатов (36 строк) - - handle_user_update() — обработка информации о пользователях (40 строк) - - handle_message_interaction_info_update() — обновление реакций (44 строки) - - handle_message_send_succeeded_update() — успешная отправка (35 строк) - - handle_chat_draft_message_update() — черновики сообщений (15 строк) - - handle_auth_state() — изменение состояния авторизации (10 строк) -- handle_update() обновлен для делегирования в update_handlers -- **Результат: client.rs 1259 → 983 строки (22% ✂️)** - -**Этап 2** (коммит 88ff4dd) - Извлечение Message Converter: -- Создан модуль `src/tdlib/message_converter.rs` (250 строк) -- **Извлечено 6 conversion функций** (~240 строк): - - convert_message() — основная конвертация TDLib → MessageInfo (150+ строк) - - extract_reply_info() — извлечение reply информации (30 строк) - - extract_forward_info() — извлечение forward информации (25 строк) - - extract_reactions() — извлечение реакций (20 строк) - - get_origin_sender_name() — получение имени отправителя (15 строк) - - update_reply_info_from_loaded_messages() — обновление reply из кэша (30 строк) -- Исправлены ошибки компиляции с неверными именами полей -- Обновлены вызовы в update_handlers.rs -- **Результат: client.rs 983 → 754 строки (23% ✂️)** - -**Этап 3** (коммит b081886) - Извлечение Chat Helpers: -- Создан модуль `src/tdlib/chat_helpers.rs` (149 строк) -- **Извлечено 3 helper функции** (~140 строк): - - find_chat_mut() — поиск чата по ID (15 строк) - - update_chat() — обновление чата через closure (15 строк, используется 9+ раз) - - add_or_update_chat() — добавление/обновление чата в списке (110+ строк) -- Использован sed для замены вызовов методов по всей кодовой базе -- **Результат: client.rs 754 → 599 строк (21% ✂️)** - -**Итоговый результат Phase 6:** -- ✅ Файл client.rs сократился с **1259 до 599 строк (52% ✂️)** 🎉 -- ✅ Создано **3 новых модуля** с чёткой ответственностью: - - update_handlers.rs — обработка всех типов TDLib Update - - message_converter.rs — конвертация TDLib Message → MessageInfo - - chat_helpers.rs — утилиты для работы с чатами -- ✅ Все **590+ тестов** проходят успешно -- ✅ Код стал **модульным и лучше организованным** -- ✅ TdClient теперь ближе к **facade pattern** (делегирует в специализированные модули) - -**Достижения дополнительного рефакторинга (итого):** -- ✅ main_input.rs: handle() сокращена на 91% (891 → 82 строки) -- ✅ ui/messages.rs: render() сокращена на 76% (390 → 92 строки) -- ✅ tdlib/client.rs: файл сокращён на 52% (1259 → 599 строк) 🎉 -- ✅ Применены современные Rust паттерны (let-else guards, early returns) -- ✅ Код стал модульным и читаемым -- ✅ Каждая функция имеет чёткую ответственность -- ✅ **2 из 4 больших файлов рефакторены (50%)** - -### Phase 7: Рефакторинг tdlib/messages.rs ✅ ЗАВЕРШЁН! (2026-02-04) - -**Проблема**: Огромная функция `convert_message()` на 150 строк в MessageManager - -**Решение**: Создан модуль `src/tdlib/message_conversion.rs` (158 строк) -- **Извлечено 6 вспомогательных функций**: - - `extract_content_text()` — извлечение текста из различных типов сообщений (~80 строк) - - `extract_entities()` — извлечение форматирования (~10 строк) - - `extract_sender_name()` — получение имени отправителя с API вызовом (~15 строк) - - `extract_forward_info()` — информация о пересылке (~12 строк) - - `extract_reply_info()` — информация об ответе (~15 строк) - - `extract_reactions()` — реакции на сообщение (~26 строк) -- Метод `convert_message()` сократился с **150 до 57 строк** (62% сокращение! 🎉) -- Файл `messages.rs` сократился с **850 до 757 строк** (11% сокращение) - -**Результат Phase 7:** -- ✅ Файл `messages.rs`: **850 → 757 строк** -- ✅ Метод `convert_message()`: **150 → 57 строк** (62% ✂️) -- ✅ Создан переиспользуемый модуль `message_conversion.rs` -- ✅ Все **629 тестов** проходят успешно - -**🎉🎉 КАТЕГОРИЯ "БОЛЬШИЕ ФАЙЛЫ/ФУНКЦИИ" ЗАВЕРШЕНА НА 100%! 🎉🎉** - -**Достижения дополнительного рефакторинга (итого):** -- ✅ main_input.rs: handle() сокращена на 91% (891 → 82 строки) -- ✅ ui/messages.rs: render() сокращена на 76% (390 → 92 строки) -- ✅ tdlib/client.rs: файл сокращён на 52% (1259 → 599 строк) -- ✅ tdlib/messages.rs: convert_message() сокращена на 62% (150 → 57 строк) -- ✅ Применены современные Rust паттерны (let-else guards, early returns) -- ✅ Код стал модульным и читаемым -- ✅ Каждая функция имеет чёткую ответственность -- ✅ **ВСЕ 4 БОЛЬШИХ ФАЙЛА ОТРЕФАКТОРЕНЫ (100%!)** 🎉🎉🎉 - -### 🎊 РЕФАКТОРИНГ ПОЛНОСТЬЮ ЗАВЕРШЁН (2026-02-04) 🎊 - -**Итоговые достижения**: - -**Основной рефакторинг (21/21 задач - 100%)**: -- ✅ Priority 1 (3/3): ChatState enum, разделение TdClient, константы -- ✅ Priority 2 (5/5): Error enum, Config validation, Newtype ID, MessageInfo реструктуризация, MessageBuilder -- ✅ Priority 3 (4/4): UI компоненты, форматирование, группировка сообщений, hotkey mapping -- ✅ Priority 4 (4/4): Unit tests, Rustdoc документация, Config validation, Async/await консистентность -- ✅ Priority 5 (3/3): Feature flags, LRU cache обобщение, Tracing -- ✅ Priority 6 (1/1): Dependency Injection для TdClient (trait-based) - -**Дополнительный рефакторинг больших файлов (Phases 2-7)**: -- ✅ main_input.rs: handle() сокращена на **91%** (891 → 82 строки) -- ✅ ui/messages.rs: render() сокращена на **76%** (390 → 92 строки) -- ✅ tdlib/client.rs: файл сокращён на **52%** (1259 → 599 строк) -- ✅ tdlib/messages.rs: convert_message() сокращена на **62%** (150 → 57 строк) - -**Преимущества после рефакторинга**: -- 🛡️ Type safety повсюду (ChatState enum, newtype IDs, Error enum) -- 📦 Модульная архитектура (TdClient разделён на 7 модулей) -- 🎨 Переиспользуемые UI компоненты -- 📚 Полная документация (rustdoc + примеры) -- ⚡ Быстрые тесты (trait-based DI с FakeTdClient) -- 🔧 Настраиваемость (hotkeys, feature flags) -- 📊 Структурированное логирование (tracing) -- ✅ 343 теста проходят успешно - -**Ветка `refactoring` слита в `main`** (2026-02-04) - -### Phase 8: Дополнительный рефакторинг (категории 6, 8) ✅ ЗАВЕРШЁН! (2026-02-04) - -**Цель**: Создать отсутствующие абстракции и централизовать дублирующуюся функциональность - -#### Категория 6: Отсутствующие абстракции (3/3 завершены) - -**6.1. KeyHandler trait** (src/input/key_handler.rs - 380+ строк): -- ✅ Trait `KeyHandler` с методами `handle_key()` и `priority()` -- ✅ Enum `KeyResult` для результатов обработки (Handled, HandledNeedsRedraw, NotHandled, Quit) -- ✅ 4 реализации: - - `GlobalKeyHandler` — глобальные хоткеи (Quit, Search, Help) - - `ChatListKeyHandler` — навигация по чатам - - `MessageViewKeyHandler` — просмотр сообщений - - `MessageSelectionKeyHandler` — выбор сообщений для операций -- ✅ `KeyHandlerChain` для композиции с приоритетами -- ✅ 3 unit теста (все проходят) - -**6.3. Keybindings система** (src/config/keybindings.rs - 420+ строк): -- ✅ Enum `Command` с 40+ командами (MoveUp, OpenChat, EditMessage, и т.д.) -- ✅ Struct `KeyBinding` для связки клавиш с модификаторами -- ✅ Struct `Keybindings` с HashMap для привязок -- ✅ Custom serde для KeyCode и KeyModifiers (поддержка TOML) -- ✅ Поддержка множественных привязок (EN/RU раскладки) -- ✅ 4 unit теста (все проходят) - -#### Категория 8: Централизация функциональности (2/2 завершены) - -**8.1. ChatFilter** (src/app/chat_filter.rs - 470+ строк): -- ✅ Struct `ChatFilterCriteria` с builder pattern: - - Фильтрация: по папке, поиску, pinned, unread, mentions, muted, archived - - Композиция критериев через методы-builders -- ✅ Struct `ChatFilter` с методами: - - `filter()` — основная фильтрация по критериям - - `by_folder()` / `by_search()` — упрощённые варианты - - `count()` / `count_unread()` / `count_unread_mentions()` — подсчёт -- ✅ Enum `ChatSortOrder` (ByLastMessage, ByTitle, ByUnreadCount, PinnedFirst) -- ✅ Reference-based фильтрация (без клонирования) -- ✅ 6 unit тестов (все проходят) - -**8.2. MessageService** (src/app/message_service.rs - 508+ строк): -- ✅ Struct `MessageGroup` — группировка по дате -- ✅ Struct `SenderGroup` — группировка по отправителю -- ✅ Struct `MessageSearchResult` — результаты поиска с контекстом -- ✅ Struct `MessageService` с 13 методами бизнес-логики: - - `group_by_date()` — группировка с метками "Сегодня", "Вчера", дата - - `group_by_sender()` — объединение последовательных сообщений от отправителя - - `search()` — полнотекстовый поиск (case-insensitive) с snippet - - `find_next()` / `find_previous()` — навигация по результатам - - `filter_by_sender()` / `filter_unread()` — фильтрация сообщений - - `find_by_id()` / `find_index_by_id()` — поиск по ID - - `get_last_n()` — получение последних N сообщений - - `get_in_date_range()` — фильтрация по диапазону дат - - `count_by_sender_type()` — статистика (incoming/outgoing) - - `create_index()` — создание HashMap индекса для быстрого доступа -- ✅ 7 unit тестов (все проходят) - -**Результаты Phase 8:** -- ✅ Создано **3 новых модуля** с чёткими абстракциями -- ✅ **1778+ строк** структурированного кода -- ✅ **20 unit тестов** (все проходят) -- ✅ Разделение ответственности: TDLib → Service → UI -- ✅ Builder pattern для фильтров -- ✅ Trait-based расширяемая архитектура -- ✅ Type-safe command система -- ⏳ TODO: интеграция в существующий код App/UI - -**Итоговые метрики всего рефакторинга:** -- ✅ **26/26 категорий** завершены (100%) -- ✅ **640+ тестов** проходят успешно -- ✅ Код сокращён и модуляризирован -- ✅ Type safety и безопасность -- ✅ Архитектура готова к масштабированию - -### Phase 9: Интеграция новых модулей (категории 6, 8) ✅ ЗАВЕРШЕНА! (2026-02-04) - -**Цель**: Интегрировать созданные в Phase 8 модули (KeyHandler, Keybindings, ChatFilter, MessageService) в существующий код App/UI - -**Результат**: Все модули успешно интегрированы! Централизованная архитектура для команд, фильтрации чатов и операций с сообщениями. - -#### 9.1. Интеграция Keybindings в Config ✅ ЗАВЕРШЕНО! (2026-02-04) - -**Проблема**: В Phase 8 была создана новая система `Keybindings` + `Command` enum, но Config всё ещё использовал старую систему `HotkeysConfig`. - -**Решение**: -- ✅ Заменено поле `hotkeys: HotkeysConfig` на `keybindings: Keybindings` в структуре Config -- ✅ Удалена вся старая система `HotkeysConfig` (~200 строк кода) -- ✅ Удалён метод `matches()` и все вспомогательные функции -- ✅ Обновлён `Config::default()` для использования `Keybindings::default()` -- ✅ Обновлены все тесты в `tests/config.rs`: - - Заменён импорт `HotkeysConfig` на `Keybindings` - - Заменены все использования `hotkeys` на `keybindings` - - Обновлён тест `test_config_default_includes_keybindings()` - -**Результаты**: -- ✅ Код компилируется успешно -- ✅ Все **666 тестов** проходят -- ✅ Config теперь использует type-safe систему Keybindings -- ✅ Готово к дальнейшей интеграции в input handlers - -**Преимущества новой системы**: -- 🛡️ Type-safe команды через `Command` enum вместо строк -- 🔑 Метод `get_command(&KeyEvent) -> Option` для определения команды -- 🌐 Поддержка модификаторов (Ctrl, Shift) из коробки -- 📝 Сериализация/десериализация через serde -- 🔧 Легко добавлять новые команды и привязки - -**Phase 9 завершена!** Все модули интегрированы. - -#### 9.5. Интеграция MessageService в message operations ✅ ЗАВЕРШЕНО! (2026-02-04) - -**Цель**: Заменить ручной поиск сообщений на использование централизованного MessageService модуля. - -**Решение**: -- ✅ MessageService уже импортирован в `src/app/mod.rs` (строка 15) -- ✅ Заменён ручной поиск на `MessageService::find_by_id()` в двух методах: - - `get_replying_to_message()` — поиск сообщения, на которое отвечаем - - `get_forwarding_message()` — поиск сообщения для пересылки -- ✅ Удалены дублирующие `.iter().find(|m| m.id() == id)` конструкции - -**Изменения**: -```rust -// Было: ручной поиск через итератор -self.td_client - .current_chat_messages() - .iter() - .find(|m| m.id() == id) - .cloned() - -// Стало: централизованный поиск через MessageService -MessageService::find_by_id(&self.td_client.current_chat_messages(), id).cloned() -``` - -**Результаты**: -- ✅ Код компилируется успешно -- ✅ Все **631 тест** проходят успешно -- ✅ Централизованная логика поиска сообщений -- ✅ Reference-based поиск (без клонирования при поиске) -- ✅ Готова инфраструктура для использования других методов MessageService - -**Преимущества**: -- 🏗️ Единая точка логики работы с сообщениями -- 🔧 Легко расширять функциональность (search, filter, group_by_date, и т.д.) -- 📝 DRY принцип — меньше дублирования кода -- 🧪 Методы MessageService покрыты unit тестами -- ♻️ Переиспользование в других частях кода - -**Доступные методы MessageService для будущей интеграции**: -- `search()` — полнотекстовый поиск по сообщениям -- `find_index_by_id()` — поиск индекса сообщения -- `group_by_date()` — группировка по дате -- `group_by_sender()` — группировка по отправителю -- `filter_unread()` / `filter_by_sender()` — фильтрация -- `get_last_n()` — получение последних N сообщений -- `count_by_sender_type()` — статистика -- `create_index()` — создание HashMap индекса - -#### 9.4. Интеграция ChatFilter в chat list filtering ✅ ЗАВЕРШЕНО! (2026-02-04) - -**Цель**: Заменить ручную фильтрацию чатов на использование централизованного ChatFilter модуля. - -**Решение**: -- ✅ Добавлен импорт `ChatFilter` и `ChatFilterCriteria` в `src/app/chat_list_state.rs` -- ✅ Метод `get_filtered_chats()` переписан с использованием ChatFilter API -- ✅ Удалена дублирующая логика фильтрации по папкам и поиску -- ✅ Используется builder pattern для создания критериев фильтрации - -**Изменения**: -```rust -// Было: ручная фильтрация в два этапа -let folder_filtered: Vec<&ChatInfo> = match self.selected_folder_id { - None => self.chats.iter().collect(), - Some(folder_id) => self.chats.iter().filter(...).collect(), -}; -if self.search_query.is_empty() { ... } - -// Стало: централизованная фильтрация через ChatFilter -let mut criteria = ChatFilterCriteria::new().with_folder(self.selected_folder_id); -if !self.search_query.is_empty() { - criteria = criteria.with_search(self.search_query.clone()); -} -ChatFilter::filter(&self.chats, &criteria) -``` - -**Результаты**: -- ✅ Код компилируется успешно -- ✅ Все **631 тест** проходят успешно -- ✅ Централизованная логика фильтрации (единый источник правды) -- ✅ Сокращён код в ChatListState (меньше дублирования) -- ✅ Легко расширять критерии фильтрации в будущем - -**Преимущества**: -- 🏗️ Единая точка логики фильтрации (ChatFilter модуль) -- 🔧 Builder pattern для композиции критериев -- 📝 Легко добавлять новые типы фильтров (pinned, unread, mentions) -- 🧪 Reference-based фильтрация (без клонирования) -- ♻️ Переиспользование в других частях кода - -#### 9.2. Интеграция Command enum в main_input.rs ✅ ЗАВЕРШЕНО! (2026-02-04) - -**Цель**: Использовать type-safe `Command` enum вместо прямых проверок `KeyCode` в обработчиках ввода. - -**Решение**: -- ✅ Добавлен импорт `use crate::config::Command;` в main_input.rs -- ✅ В начале `handle()` получаем команду: `let command = app.config.keybindings.get_command(&key);` -- ✅ Сделано поле `config` публичным в `App` struct для доступа к keybindings -- ✅ Обновлены обработчики режимов с добавлением параметра `command: Option`: - - `handle_profile_mode()` — навигация по профилю (MoveUp/Down, Cancel) - - `handle_message_selection()` — выбор сообщений (DeleteMessage, ReplyMessage, ForwardMessage, CopyMessage, ReactMessage) - - `handle_chat_list_navigation()` — навигация по чатам (MoveUp/Down, SelectFolder1-9) -- ✅ Создана вспомогательная функция `select_folder()` для выбора папки по индексу -- ✅ Исправлены русские клавиши в keybindings.rs ('р' для MoveUp, 'л' для MoveLeft) -- ✅ Обновлён тест `test_default_bindings()` для соответствия новым привязкам - -**Результаты**: -- ✅ Код компилируется успешно -- ✅ Все **631 тест** проходят успешно -- ✅ Type-safe обработка команд через Command enum -- ✅ Fallback на старую логику KeyCode сохранён для совместимости -- ✅ Fallback для стрелок Up/Down в handle_chat_list_navigation (исправлен test_arrow_navigation_in_chat_list) -- ✅ Русская раскладка работает корректно - -**Преимущества**: -- 🛡️ Type-safe команды вместо строковых проверок -- 🔧 Единая точка конфигурации клавиш (keybindings) -- 📝 Легко добавлять новые команды -- 🌐 Поддержка модификаторов (Ctrl, Shift) -- ♻️ Переиспользование логики через Command enum - -**Примечание**: KeyHandler trait не интегрирован, так как async обработчики несовместимы с синхронным trait. Вместо этого используется прямая интеграция Command enum, что проще и естественнее для async кода. - ---- - -## Известные проблемы - -1. При первом запуске нужно пройти авторизацию +Полная структура проекта: см. [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md) +Подробный план: см. [ROADMAP.md](ROADMAP.md) diff --git a/ROADMAP.md b/ROADMAP.md index eb460ab..b6236a0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,200 +1,22 @@ # Roadmap -## Фаза 1: Базовая инфраструктура [DONE] +## Завершённые фазы -- [x] Настройка проекта (Cargo.toml) -- [x] TUI фреймворк (ratatui + crossterm) -- [x] Базовый layout (папки, список чатов, область сообщений) -- [x] Vim-style навигация (hjkl, стрелки) -- [x] Русская раскладка (ролд) +| Фаза | Описание | Ключевые результаты | +|------|----------|---------------------| +| 1 | Базовая инфраструктура | ratatui + crossterm, vim-навигация, русская раскладка | +| 2 | TDLib интеграция | tdlib-rs, авторизация, загрузка чатов и сообщений | +| 3 | Улучшение UX | Отправка, поиск, скролл, realtime обновления | +| 4 | Папки и фильтрация | Загрузка папок из Telegram, переключение 1-9 | +| 5 | Расширенный функционал | Онлайн-статус, галочки прочтения, медиа-заглушки, muted | +| 6 | Полировка | 60 FPS, оптимизация памяти, graceful shutdown, динамический инпут | +| 7 | Рефакторинг памяти | Единый источник данных, LRU-кэш (500 users), lazy loading | +| 8 | Дополнительные фичи | Markdown, edit/delete, reply/forward, блочный курсор | +| 9 | Расширенные возможности | Typing, pinned, поиск в чате, черновики, профиль, копирование, реакции, конфиг | +| 10 | Desktop уведомления (83%) | notify-rust, muted фильтр, mentions, медиа. TODO: кастомные звуки | +| 13 | Глубокий рефакторинг | 5 файлов (4582→модули), 5 traits, shared components, docs | -## Фаза 2: TDLib интеграция [DONE] - -- [x] Подключение tdlib-rs -- [x] Авторизация (телефон + код + 2FA) -- [x] Сохранение сессии -- [x] Загрузка списка чатов -- [x] Загрузка истории сообщений -- [x] Отключение логов TDLib - -## Фаза 3: Улучшение UX [DONE] - -- [x] Отправка сообщений -- [x] Фильтрация чатов (только Main, без архива) -- [x] Поиск по чатам (Ctrl+S) -- [x] Скролл истории сообщений -- [x] Загрузка имён пользователей (вместо User_ID) -- [x] Отметка сообщений как прочитанные -- [x] Реальное время: новые сообщения - -## Фаза 4: Папки и фильтрация [DONE] - -- [x] Загрузка папок из Telegram -- [x] Переключение между папками (1-9) -- [x] Фильтрация чатов по папке - -## Фаза 5: Расширенный функционал [DONE] - -- [x] Отображение онлайн-статуса (зелёная точка ●) -- [x] Статус доставки/прочтения (✓, ✓✓) -- [x] Поддержка медиа-заглушек (фото, видео, голосовые, стикеры и др.) -- [x] Mentions (@) — индикатор непрочитанных упоминаний -- [x] Muted чаты (иконка 🔇) - -## Фаза 6: Полировка [DONE] - -- [x] Оптимизация использования памяти (базовая) - - Очистка сообщений при закрытии чата - - Лимит кэша пользователей (500) - - Периодическая очистка неактивных записей -- [x] Оптимизация 60 FPS - - Poll таймаут 16ms - - Флаг `needs_redraw` — рендеринг только при изменениях - - Обработка Event::Resize для перерисовки при изменении размера -- [x] Минимальное разрешение (80x20) - - Предупреждение если терминал слишком мал -- [x] Обработка ошибок сети - - NetworkState enum (WaitingForNetwork, Connecting, etc.) - - Индикатор в футере с цветовой индикацией -- [x] Graceful shutdown - - AtomicBool флаг для остановки polling - - Корректное закрытие TDLib клиента - - Таймаут ожидания завершения задач -- [x] Динамический инпут - - Автоматическое расширение до 10 строк - - Wrap для длинного текста -- [x] Перенос длинных сообщений - - Автоматический wrap на несколько строк - - Правильное выравнивание для исходящих/входящих - -## Фаза 7: Глубокий рефакторинг памяти [DONE] - -- [x] Удалить дублирование current_messages между App и TdClient -- [x] Использовать единый источник данных для сообщений -- [x] Реализовать LRU-кэш для user_names/user_statuses вместо простого лимита -- [x] Lazy loading для имён пользователей (батчевая загрузка последних 5 за цикл) -- [x] Лимиты памяти: - - MAX_MESSAGES_IN_CHAT = 500 - - MAX_CHATS = 200 - - MAX_CHAT_USER_IDS = 500 - - MAX_USER_CACHE_SIZE = 500 (LRU) - -## Фаза 8: Дополнительные фичи [DONE] - -- [x] Markdown форматирование в сообщениях - - Bold, Italic, Underline, Strikethrough - - Code (inline, Pre, PreCode) - - Spoiler (скрытый текст) - - URLs, упоминания (@) -- [x] Редактирование сообщений - - ↑ при пустом инпуте → выбор сообщения - - Enter для начала редактирования - - Подсветка выбранного сообщения (▶) - - Esc для отмены -- [x] Удаление сообщений - - d / в / Delete в режиме выбора - - Модалка подтверждения (y/n) - - Удаление для всех если возможно -- [x] Индикатор редактирования (✎) - - Отображается рядом с временем для отредактированных сообщений -- [x] Блочный курсор в поле ввода - - Vim-style курсор █ - - Перемещение ←/→, Home/End - - Редактирование в любой позиции -- [x] Reply на сообщения - - `r` / `к` в режиме выбора → режим ответа - - Превью сообщения в поле ввода - - Esc для отмены -- [x] Forward сообщений - - `f` / `а` в режиме выбора → режим пересылки - - Превью сообщения в поле ввода - - Выбор чата стрелками, Enter для пересылки - - Esc для отмены - - Отображение "↪ Переслано от" для пересланных сообщений - -## Фаза 9: Расширенные возможности [DONE] - -- [x] Typing indicator ("печатает...") - - Показывать когда собеседник печатает - - Отправлять свой статус печати при наборе текста -- [x] Закреплённые сообщения (Pinned) - - Отображать pinned message вверху открытого чата - - Клик/хоткей для перехода к закреплённому сообщению -- [x] Поиск по сообщениям в чате - - `Ctrl+F` — поиск текста внутри открытого чата - - Навигация по результатам (n/N или стрелки) - - Подсветка найденных совпадений -- [x] Черновики - - Сохранять набранный текст при переключении между чатами - - Индикатор черновика в списке чатов - - Восстановление текста при возврате в чат -- [x] Профиль пользователя/чата - - `Ctrl+i` — открыть информацию о чате/собеседнике - - Для личных чатов: имя, username, телефон, био - - Для групп: название, описание, количество участников -- [x] Копирование сообщений - - `y` / `н` в режиме выбора — скопировать текст в системный буфер обмена - - Использовать clipboard crate для кроссплатформенности -- [x] Реакции - - Отображение реакций под сообщениями - - `e` в режиме выбора — добавить реакцию (emoji picker) - - Список доступных реакций чата -- [x] Конфигурационный файл - - `~/.config/tele-tui/config.toml` - - Настройки: цветовая схема, часовой пояс, хоткеи - - Загрузка конфига при старте - -## Фаза 10: Desktop уведомления [DONE - 83%] - -### Стадия 1: Базовая реализация [DONE] -- [x] NotificationManager модуль - - notify-rust интеграция (версия 4.11) - - Feature flag "notifications" в Cargo.toml - - Базовая структура с настройками -- [x] Конфигурация уведомлений - - NotificationsConfig в config.toml - - enabled: bool - вкл/выкл уведомлений - - only_mentions: bool - только упоминания - - show_preview: bool - показывать превью текста -- [x] Интеграция с TdClient - - Поле notification_manager в TdClient - - Метод configure_notifications() - - Обработка в handle_new_message_update() -- [x] Базовая отправка уведомлений - - Уведомления для сообщений не из текущего чата - - Форматирование title (имя чата) и body (текст/медиа-заглушка) - - Sender name из MessageInfo - -### Стадия 2: Улучшения [IN PROGRESS] -- [x] Синхронизация muted чатов - - Загрузка списка muted чатов из Telegram - - Вызов sync_muted_chats() при инициализации и обновлении (Ctrl+R) - - Muted чаты автоматически фильтруются из уведомлений -- [x] Фильтрация по упоминаниям - - Метод MessageInfo::has_mention() проверяет TextEntityType::Mention и MentionName - - NotificationManager применяет фильтр only_mentions из конфига - - Работает для @username и inline mentions -- [x] Поддержка типов медиа - - Метод beautify_media_labels() заменяет текстовые заглушки на emoji - - Поддержка: 📷 Фото, 🎥 Видео, 🎞️ GIF, 🎤 Голосовое, 🎨 Стикер - - Также: 📎 Файл, 🎵 Аудио, 📹 Видеосообщение, 📍 Локация, 👤 Контакт, 📊 Опрос -- [ ] Кастомизация звуков - - Настройка звуков уведомлений в config.toml - - Разные звуки для разных типов сообщений - -### Стадия 3: Полировка [DONE] -- [x] Обработка ошибок - - Graceful fallback если уведомления недоступны (возвращает Ok без паники) - - Логирование ошибок через tracing::warn! - - Детальное логирование причин пропуска уведомлений (debug level) -- [x] Дополнительные настройки - - timeout_ms - продолжительность показа (0 = системное значение) - - urgency - уровень важности: "low", "normal", "critical" (только Linux) - - Красивые эмодзи для типов медиа -- [ ] Опциональные улучшения (не критично) - - Кросс-платформенное тестирование (требует ручного тестирования) - - icon - кастомная иконка приложения - - Actions в уведомлениях (кнопки "Ответить", "Прочитано") +--- ## Фаза 11: Показ изображений в чате [PLANNED] @@ -279,17 +101,11 @@ - Предупреждение для больших файлов ### Технические детали -- **Поддерживаемые протоколы:** - - Sixel (xterm, WezTerm, mintty) - - Kitty Graphics Protocol (Kitty terminal) - - iTerm2 Inline Images (iTerm2 на macOS) - - Unicode Halfblocks (fallback для всех) -- **Поддерживаемые форматы:** - - JPEG, PNG, GIF, WebP, BMP -- **Новые хоткеи:** - - `v` / `м` - открыть изображение в полном размере (режим выбора) - - `←` / `→` - навигация между изображениями (в режиме просмотра) - - `Esc` - закрыть полноэкранный просмотр +- **Поддерживаемые протоколы:** Sixel, Kitty Graphics, iTerm2 Inline Images, Unicode Halfblocks (fallback) +- **Поддерживаемые форматы:** JPEG, PNG, GIF, WebP, BMP +- **Новые хоткеи:** `v`/`м` - полноэкранный просмотр, `←`/`→` - навигация, `Esc` - закрыть + +--- ## Фаза 12: Прослушивание голосовых сообщений [PLANNED] @@ -302,30 +118,20 @@ - rodio 0.17 - Pure Rust аудио библиотека - Feature flag "audio" в Cargo.toml - [ ] AudioPlayer API - - play() - воспроизведение файла - - pause() / resume() - пауза/возобновление - - stop() - остановка - - seek() - перемотка - - set_volume() - регулировка громкости - - get_position() - текущая позиция + - play(), pause()/resume(), stop(), seek(), set_volume(), get_position() - [ ] VoiceCache - Кэш загруженных OGG файлов в ~/.cache/tele-tui/voice/ - - LRU политика очистки - - MAX_VOICE_CACHE_SIZE = 100 MB + - LRU политика очистки, MAX_VOICE_CACHE_SIZE = 100 MB ### Этап 2: Интеграция с TDLib [TODO] - [ ] Обработка MessageContentVoiceNote - Добавить VoiceNoteInfo в MessageInfo - Извлечение file_id, duration, mime_type, waveform - - Метка формата (OGG Opus обычно) - [ ] Загрузка файлов - Метод TdClient::download_voice_note(file_id) - Асинхронная загрузка через downloadFile API - Обработка состояний (pending/downloading/ready) -- [ ] Кэширование - - Сохранение путей к загруженным файлам - - Не перезагружать уже скачанные голосовые - - Проверка существования файла перед воспроизведением +- [ ] Кэширование путей к загруженным файлам ### Этап 3: UI для воспроизведения [TODO] - [ ] Индикатор в сообщении @@ -333,342 +139,37 @@ - Progress bar во время воспроизведения - Статус: ▶ (playing), ⏸ (paused), ⏹ (stopped), ⏳ (loading) - Текущее время / общая длительность (0:08 / 0:15) -- [ ] Модификация render_messages() - - render_voice_note() для голосовых сообщений - - render_progress_bar() для индикатора воспроизведения - - Hint "[Space] Воспроизвести" если не играет - [ ] Footer с управлением - - Отображение доступных команд при воспроизведении - "[Space] Play/Pause [s] Stop [←/→] Seek [↑/↓] Volume" - [ ] Waveform визуализация (опционально) - - Конвертация waveform данных из Telegram в ASCII bars - - Использование символов ▁▂▃▄▅▆▇█ для визуализации + - Символы ▁▂▃▄▅▆▇█ для визуализации ### Этап 4: Хоткеи для управления [TODO] - [ ] Новые команды - - PlayVoice - Space в режиме выбора голосового - - PauseVoice - Space во время воспроизведения - - StopVoice - s / ы - - SeekBackward - ← (перемотка назад на 5 сек) - - SeekForward - → (перемотка вперед на 5 сек) - - VolumeUp - ↑ (увеличить на 10%) - - VolumeDown - ↓ (уменьшить на 10%) -- [ ] Контекстная обработка - - Space работает как play/pause в зависимости от состояния - - ← / → для seek только во время воспроизведения - - ↑ / ↓ для громкости только во время воспроизведения + - Space - play/pause, s/ы - stop + - ←/→ - seek ±5 сек, ↑/↓ - volume ±10% +- [ ] Контекстная обработка (управление только во время воспроизведения) - [ ] Поддержка русской раскладки - - s / ы - stop - - Остальные клавиши универсальны (Space, стрелки) ### Этап 5: Конфигурация и UX [TODO] - [ ] AudioConfig в config.toml - - enabled: bool - включить/отключить аудио - - default_volume: f32 - громкость по умолчанию (0.0 - 1.0) - - seek_step_seconds: i32 - шаг перемотки в секундах - - autoplay: bool - автовоспроизведение при выборе - - cache_size_mb: usize - размер кэша голосовых - - show_waveform: bool - показывать waveform визуализацию - - system_player_fallback: bool - использовать системный плеер - - system_player: String - команда системного плеера (mpv, ffplay) -- [ ] Асинхронная загрузка - - Не блокировать UI во время загрузки файла - - Индикатор загрузки с процентами - - Возможность отмены загрузки -- [ ] Обновление UI - - Ticker для обновления progress bar (каждые 100ms) - - Плавное обновление позиции воспроизведения - - Автоматическая остановка при достижении конца + - enabled, default_volume, seek_step_seconds, autoplay, cache_size_mb, show_waveform + - system_player_fallback, system_player (mpv, ffplay) +- [ ] Асинхронная загрузка (не блокирует UI) +- [ ] Ticker для обновления progress bar (каждые 100ms) ### Этап 6: Обработка ошибок [TODO] -- [ ] Graceful fallback на системный плеер - - Если rodio не работает - использовать mpv/ffplay - - Логирование ошибок через tracing - - Предупреждение пользователю если аудио недоступно -- [ ] Обработка ошибок загрузки - - Таймаут загрузки (30 сек) - - Повторная попытка по запросу - - Сообщение об ошибке в UI -- [ ] Ограничения - - Максимальный размер файла для кэша - - Автоматическая очистка старых файлов - - Предупреждение для очень длинных голосовых (>5 мин) +- [ ] Graceful fallback на системный плеер (mpv/ffplay) +- [ ] Таймаут загрузки (30 сек), повторная попытка +- [ ] Ограничения: максимальный размер файла, автоочистка кэша ### Этап 7: Дополнительные улучшения [TODO] -- [ ] Управление воспроизведением - - Автоматическая остановка при закрытии чата - - Сохранение позиции при паузе - - Автопереход к следующему голосовому (опционально) -- [ ] Оптимизация - - Lazy loading (загрузка только при воспроизведении) - - Префетчинг следующего голосового (опционально) - - Минимальная задержка при нажатии Play -- [ ] Визуальные улучшения - - Анимация progress bar - - Цветовая индикация статуса (зеленый - playing, желтый - paused) - - Иконки в зависимости от статуса +- [ ] Автоматическая остановка при закрытии чата +- [ ] Сохранение позиции при паузе +- [ ] Префетчинг следующего голосового (опционально) ### Технические детали -- **Аудио библиотека:** - - rodio 0.17 (Pure Rust, кроссплатформенная) - - Поддержка OGG Opus (формат голосовых в Telegram) - - Контроль воспроизведения через Sink API -- **Платформы:** - - Linux (ALSA, PulseAudio) - - macOS (CoreAudio) - - Windows (WASAPI) -- **Fallback:** - - mpv --no-video (универсальный плеер) - - ffplay -nodisp (из ffmpeg) -- **Новые хоткеи:** - - `Space` - воспроизвести/пауза (в режиме выбора голосового) - - `s` / `ы` - остановить воспроизведение - - `←` / `→` - перемотка -5с / +5с (во время воспроизведения) - - `↑` / `↓` - громкость +/- 10% (во время воспроизведения) - -## Фаза 13: Глубокий рефакторинг архитектуры [DONE] - -**Мотивация:** Код вырос до критических размеров - некоторые файлы содержат >1000 строк, что затрудняет поддержку и навигацию. Необходимо разбить монолитные файлы на логические модули. - -**Проблемы:** -- `src/input/main_input.rs` - 1199 строк (самый большой файл!) -- `src/app/mod.rs` - 1015 строк, 116 функций (God Object) -- `src/ui/messages.rs` - 893 строки -- `src/tdlib/messages.rs` - 833 строки -- `src/config/mod.rs` - 642 строки - -### Этап 1: Разбить input/main_input.rs (1199 → <200 строк) [DONE ✅] - -**Текущая проблема:** -- Весь input handling в одном файле -- Функции по 300-400 строк -- Невозможно быстро найти нужный handler - -**План:** -- [x] Создать `src/input/handlers/` директорию -- [x] Создать `handlers/chat.rs` - обработка ввода в открытом чате - - Переместить `handle_open_chat_keyboard_input()` - - Обработка скролла, выбора сообщений - - **452 строки** (7 функций) -- [x] Создать `handlers/chat_list.rs` - обработка в списке чатов - - Переместить `handle_chat_list_keyboard_input()` - - Навигация по чатам, папки - - **142 строки** (3 функции) -- [x] Создать `handlers/compose.rs` - режимы edit/reply/forward - - Обработка ввода в режимах редактирования - - Input field управление (курсор, backspace, delete) - - **80 строк** (2 функции) -- [x] Создать `handlers/modal.rs` - модалки - - Delete confirmation - - Emoji picker - - Profile modal - - **316 строк** (5 функций) -- [x] Создать `handlers/search.rs` - поиск - - Search mode в чате - - Search mode в списке чатов - - **140 строк** (3 функций) -- [x] Обновить `main_input.rs` - только роутинг - - Определение текущего режима - - Делегация в нужный handler - - **164 строки** (2 функции) - -**Результат:** 1199 строк → **164 строки** (удалено 1035 строк, -86%) -- Создано 5 новых модулей обработки ввода -- Чистый router pattern в main_input.rs -- Каждый handler отвечает за свою область -- **Дополнительно:** Исправлен конфликт Ctrl+I → Ctrl+U для профиля - -### Этап 2: Уменьшить app/mod.rs (116 функций → traits) [DONE ✅] - -**Текущая проблема:** -- God Object с 116 функциями -- Сложно найти нужный метод -- Нарушение Single Responsibility Principle - -**План:** -- [x] Создать `app/methods/` директорию -- [x] Создать trait `NavigationMethods` - - `next_chat()`, `previous_chat()`, `select_current_chat()`, `close_chat()` - - `next_filtered_chat()`, `previous_filtered_chat()`, `select_filtered_chat()` - - **7 методов** -- [x] Создать trait `MessageMethods` - - `start_message_selection()`, `select_previous/next_message()` - - `get_selected_message()`, `start_editing_selected()`, `cancel_editing()` - - `is_editing()`, `is_selecting_message()` - - **8 методов** -- [x] Создать trait `ComposeMethods` - - `start_reply_to_selected()`, `cancel_reply()`, `is_replying()`, `get_replying_to_message()` - - `start_forward_selected()`, `cancel_forward()`, `is_forwarding()`, `get_forwarding_message()` - - `get_current_draft()`, `load_draft()` - - **10 методов** -- [x] Создать trait `SearchMethods` - - Chat search: `start_search()`, `cancel_search()`, `get_filtered_chats()` - - Message search: `enter/exit_message_search_mode()`, `set/get_search_results()` - - Navigation: `select_previous/next_search_result()`, query управление - - **15 методов** -- [x] Создать trait `ModalMethods` - - Delete confirmation: `is_confirm_delete_shown()` - - Pinned: `is/enter/exit_pinned_mode()`, `select_previous/next_pinned()`, getters - - Profile: `is/enter/exit_profile_mode()`, navigation, leave_group confirmation - - Reactions: `is/enter/exit_reaction_picker_mode()`, `select_previous/next_reaction()` - - **27 методов** -- [x] Оставить в `app/mod.rs` только: - - Struct definition - - Constructors (new, with_client) - - Utilities (get_command, get_selected_chat_id, get_selected_chat) - - Getters/setters для всех полей - - **~48 методов** - -**Структура:** -```rust -// app/mod.rs - только core -mod methods; -pub use methods::*; - -impl App { - pub fn new() -> Self { ... } - pub fn get_command(...) -> Option { ... } - pub fn get_selected_chat_id(&self) -> Option { ... } - // ... getters/setters ... -} - -// app/methods/navigation.rs -pub trait NavigationMethods { - fn next_chat(&mut self); - fn previous_chat(&mut self); -} -impl NavigationMethods for App { ... } -``` - -**Результат:** 1015 строк → **371 строка** (удалено 644 строки, -63%) -- 116 функций → 5 trait impl блоков (67 методов в traits + 48 в core) -- Каждый trait отвечает за свою область функциональности -- Соблюдён Single Responsibility Principle ✅ - -### Этап 3: Разбить ui/messages.rs (893 → 365 строк) [DONE ✅] - -**Текущая проблема:** -- Весь UI рендеринг сообщений в одном файле -- Модалки смешаны с основным рендерингом -- Compose bar (input field) в том же файле - -**План:** -- [x] Создать `ui/modals/` директорию -- [x] Создать `modals/mod.rs` - экспорты модальных окон -- [x] Создать `modals/delete_confirm.rs` - - Wrapper для компонента подтверждения удаления - - **~8 строк** -- [x] Создать `modals/reaction_picker.rs` - - Wrapper для компонента выбора реакций - - **~13 строк** -- [x] Создать `modals/search.rs` - - Поиск по сообщениям в чате - - Input с курсором, результаты, навигация - - **193 строки** -- [x] Создать `modals/pinned.rs` - - Просмотр закреплённых сообщений - - Header, список сообщений, навигация - - **163 строки** -- [x] Создать `ui/compose_bar.rs` - - Поле ввода с поддержкой 5 режимов - - Режимы: normal, edit, reply, forward, select - - Динамический preview для каждого режима - - **168 строк** -- [x] Обновить `messages.rs`: - - Оставлен только core rendering - - Chat header, pinned bar, message list - - Utility функции (wrap_text_with_offsets, WrappedLine) - - Интеграция через compose_bar::render() и modals::render_*() - - **365 строк** - -**Результат:** 893 строки → **365 строк** (удалено 528 строк, -59%) -- Создано 6 новых модулей UI -- Чистое разделение ответственности -- Модальные окна полностью изолированы -- Compose bar - отдельный переиспользуемый компонент - -### Этап 4: Разбить tdlib/messages.rs (833 → 3 файла) [DONE ✅] - -**Текущая проблема:** -- Смешивается конвертация из TDLib и операции -- Большой файл сложно читать - -**План:** -- [x] Создать `tdlib/messages/` директорию -- [x] Создать `messages/convert.rs` - - convert_message(), fetch_missing_reply_info(), fetch_and_update_reply() - - **134 строки** -- [x] Создать `messages/operations.rs` - - 11 TDLib API операций (send, edit, delete, forward, search, etc.) - - **616 строк** -- [x] Обновить `tdlib/messages.rs` → `tdlib/messages/mod.rs` - - Struct MessageManager, new(), push_message() - - **99 строк** - -**Результат:** 836 строк → 3 файла (99 + 134 + 616) - -### Этап 5: Разбить config/mod.rs (642 → 3 файла) [DONE ✅] - -**Текущая проблема:** -- Много default_* функций (по 1-3 строки каждая) -- Validation logic смешана с определениями -- Сложно найти нужную секцию конфига - -**План:** -- [x] Создать `config/validation.rs` - - validate(), parse_color() - - **86 строк** -- [x] Создать `config/loader.rs` - - load(), save(), paths, credentials - - **192 строки** -- [x] Оставить в `config/mod.rs`: - - Structs, defaults, Default impls, tests - - **350 строк** - -**Результат:** 642 строки → 3 файла (350 + 86 + 192) - -### Этап 6: Code Duplication Cleanup [DONE ✅] - -**План:** -- [x] Очистка неиспользуемых импортов в 7 файлах -- [x] Извлечение `format_user_status()` в `ui/chat_list.rs` (удалено ~80 строк дублей) -- [x] Создание `ui/components/message_list.rs` — общие render_message_item, calculate_scroll_offset, render_help_bar (удалено ~120 строк дублей) -- [x] Извлечение `scroll_to_message()` в `input/handlers/mod.rs` (удалено ~20 строк дублей) -- **Итого:** удалено ~220 строк дублированного кода, 0 compiler warnings - -### Этап 7: Documentation Update [DONE ✅] - -**План:** -- [x] Обновить CONTEXT.md с новой структурой -- [x] Полностью переписать PROJECT_STRUCTURE.md (архитектура, дерево файлов, traits, state machine) -- [x] Добавить module-level документацию (`//!`) к 16 файлам -- [x] Создать architecture diagram (ASCII) в PROJECT_STRUCTURE.md - -### Метрики успеха - -**До рефакторинга:** -``` -input/main_input.rs: 1199 строк -app/mod.rs: 1015 строк (116 функций) -ui/messages.rs: 893 строки -tdlib/messages.rs: 833 строки -config/mod.rs: 642 строки -ИТОГО: 4582 строки в 5 файлах -``` - -**После рефакторинга:** -``` -input/handlers/*.rs: ~6 файлов по <400 строк -app/methods/*.rs: ~6 traits с impl блоками -ui/modals/*.rs: ~4 файла по <150 строк -tdlib/messages/*.rs: 2 файла по <500 строк -config/*.rs: 4 файла по <200 строк -ИТОГО: те же строки, но в ~20+ файлах -``` - -**Преимущества:** -- ✅ Легче найти нужный код -- ✅ Легче тестировать модули -- ✅ Меньше конфликтов при работе в команде -- ✅ Лучше читаемость и поддерживаемость -- ✅ Соблюдение Single Responsibility Principle +- **Аудио библиотека:** rodio 0.17 (Pure Rust, кроссплатформенная, OGG Opus) +- **Платформы:** Linux (ALSA/PulseAudio), macOS (CoreAudio), Windows (WASAPI) +- **Fallback:** mpv --no-video, ffplay -nodisp +- **Новые хоткеи:** Space - play/pause, s/ы - stop, ←/→ - seek, ↑/↓ - volume