Files
telegram-tui/CONTEXT.md
Mikhail Kilin 1d0bfb53e0 refactor: split main_input.rs into modular handlers (1199→164 lines)
Split monolithic input handler into 5 specialized modules:
- handlers/chat.rs (452 lines) - chat keyboard input
- handlers/modal.rs (316 lines) - modal dialogs
- handlers/chat_list.rs (142 lines) - chat list navigation
- handlers/search.rs (140 lines) - search functionality
- handlers/compose.rs (80 lines) - forward/reply/edit modes

Changes:
- main_input.rs: 1199→164 lines (removed 1035 lines, -86%)
- Preserved existing handlers: clipboard, global, profile
- Created clean router pattern in main_input.rs
- Fixed keybinding conflict: Ctrl+I→Ctrl+U for profile
- Fixed modifier handling in chat input (ignore Ctrl/Alt chars)
- Updated CONTEXT.md with refactoring metrics
- Updated ROADMAP.md: Phase 13 Etap 1 marked as DONE

Phase 13 Etap 1: COMPLETED (100%)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-06 00:43:52 +03:00

137 KiB
Raw Blame History

Текущий контекст проекта

Статус: Фаза 13 Этап 1 — ЗАВЕРШЕНО (100%!) 🎉

Последние изменения (2026-02-06)

🔧 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 (улучшения):
    • Синхронизация muted чатов из Telegram (вызов sync_muted_chats при загрузке)
    • Фильтрация по упоминаниям (@username) если only_mentions=true
    • Поддержка типов медиа (фото, видео, стикеры) в body
  • Стадия 3 (полировка) - ВЫПОЛНЕНО :
    • Обработка ошибок notify-rust с graceful fallback
    • Логирование через tracing::warn! и tracing::debug!
    • Дополнительные настройки: timeout_ms и urgency
    • Платформенная поддержка 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<Command, Vec> для множественных 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<T> 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 тестов)

Тестирование

Статус: ПОЛНОСТЬЮ ЗАВЕРШЕНО! (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

Ключевые решения

  1. Неблокирующий receive: TDLib updates приходят в отдельном потоке и передаются в main loop через mpsc::channel. Это позволяет UI оставаться отзывчивым.

  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<ReactionInfo> для каждого сообщения. Обновляются в реальном времени через Update::MessageInteractionInfo. Emoji picker использует сетку 8x6 с навигацией стрелками. Приоритет обработки ввода: reaction picker → delete confirmation → остальные модалки (важно для корректной работы Enter/Esc).

Зависимости (Cargo.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"

API Credentials

Приоритет загрузки (от высшего к низшему):

  1. Файл credentials (~/.config/tele-tui/credentials):
API_ID=your_api_id
API_HASH=your_api_hash
  1. Переменные окружения (.env файл в текущей директории):
API_ID=your_api_id
API_HASH=your_api_hash
  1. Если ничего не найдено — показывается сообщение об ошибке с инструкциями.

Конфигурационный файл

Создаётся автоматически при первом запуске в ~/.config/tele-tui/config.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 строки):

  1. handle_profile_mode() (~120 строк)

    • Режим профиля пользователя/чата
    • Модалка подтверждения выхода из группы (двухшаговая)
    • Открытие в браузере, копирование ID
  2. handle_message_search_mode() (~73 строки)

    • Поиск по сообщениям в открытом чате (Ctrl+F)
    • Навигация по результатам, переход к сообщению
  3. handle_pinned_mode() (~42 строки)

    • Режим просмотра закреплённых сообщений
    • Навигация и переход к сообщению в истории
  4. handle_reaction_picker_mode() (~90 строк)

    • Emoji picker для добавления реакций
    • Навигация по сетке 8x6, toggle реакции
  5. handle_delete_confirmation() (~60 строк)

    • Модалка подтверждения удаления сообщения
    • Обработка yes/no, удаление для себя/всех
  6. handle_forward_mode() (~52 строки)

    • Выбор чата для пересылки сообщения
    • Навигация по списку чатов, отправка
  7. handle_chat_search_mode() (~43 строки)

    • Поиск по чатам (Ctrl+S)
    • Фильтрация списка, открытие чата
  8. handle_enter_key() (~145 строк)

    • Открытие чата из списка
    • Отправка/редактирование сообщений
    • Начало редактирования из режима выбора
  9. handle_escape_key() (~35 строк)

    • Обработка Esc: отмена действий или закрытие чата
    • Сохранение черновика при закрытии
  10. handle_message_selection() (~95 строк)

    • Режим выбора сообщения в открытом чате
    • Действия: reply, forward, delete, copy, react
  11. 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<T: TdClientTrait = TdClient>
  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<Mutex<>> vs &references design limitation
    • Некоторые методы возвращают пустые значения (для UI-only полей)

Этап 4: Generic App

  • Обновлён src/app/mod.rs:
    • pub struct App<T: TdClientTrait = TdClient>
    • impl<T: TdClientTrait> App<T> - generic impl со всеми методами
    • impl App<TdClient> - convenience new(config) для продакшена
    • with_client(config, td_client) - generic конструктор

Этап 5: Generic input handlers

  • Обновлены ВСЕ input handlers:
    • src/input/main_input.rs - handle<T: TdClientTrait>(app: &mut App<T>)
    • src/input/auth.rs - generic
    • src/input/handlers/global.rs - handle_global_commands<T>() + handle_pinned_messages<T>()
    • 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<T: TdClientTrait>()
    • 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<FakeTdClient> вместо App
    • Использует FakeTdClient::new() + builder pattern
    • Чистая работа без обращения к internal fields
    • Все тесты билдера обновлены
  • Обновлён src/main.rs:
    • run_app<B, T: TdClientTrait>() - 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)

    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)

    // Было:
    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):

    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):

    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):

    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() с дефолтными значениями

Дефолтные горячие клавиши:

[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<GroupedMessage>
  • Группировка по дате и отправителю с оптимизацией
  • Добавлены 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 тестов

Пример использования:

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<i64>, 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

Рефакторинг — Приоритет 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<T> для упрощения сигнатур
    • Использован thiserror для автоматического Display
    • Заменены все Result<T, String> на Result<T> в 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<i64>, 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

Что НЕ сделано / TODO

Все пункты Фазы 9 завершены! Можно переходить к следующей фазе разработки или продолжить написание тестов.

Технический долг

См. 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<Mutex<>>
  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<Mutex<>> внутри)
    • Все методы теперь 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:
    [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<K, V> в src/tdlib/users.rs
    • Type-safe: K: Eq + Hash + Clone + Copy, V: Clone
    • Обновлены типы в UserCache: LruCache<UserId, String>, LruCache<UserId, UserOnlineStatus>
    • Переиспользуемая реализация без дополнительных зависимостей
  • 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<Command> для определения команды
  • 🌐 Поддержка модификаторов (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) конструкции

Изменения:

// Было: ручной поиск через итератор
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 для создания критериев фильтрации

Изменения:

// Было: ручная фильтрация в два этапа
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<Command>:
    • 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. При первом запуске нужно пройти авторизацию