Some checks failed
ci/woodpecker/pr/check Pipeline failed
Remove account deletion from modal and parallel polling — these won't be implemented in the current scope. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
169 lines
11 KiB
Markdown
169 lines
11 KiB
Markdown
# Roadmap
|
||
|
||
## Завершённые фазы
|
||
|
||
| Фаза | Описание | Ключевые результаты |
|
||
|------|----------|---------------------|
|
||
| 1 | Базовая инфраструктура | ratatui + crossterm, vim-навигация, русская раскладка |
|
||
| 2 | TDLib интеграция | tdlib-rs, авторизация, загрузка чатов и сообщений |
|
||
| 3 | Улучшение UX | Отправка, поиск, скролл, realtime обновления |
|
||
| 4 | Папки и фильтрация | Загрузка папок из Telegram, переключение 1-9 |
|
||
| 5 | Расширенный функционал | Онлайн-статус, галочки прочтения, медиа-заглушки, muted |
|
||
| 6 | Полировка | 60 FPS, оптимизация памяти, graceful shutdown, динамический инпут |
|
||
| 7 | Рефакторинг памяти | Единый источник данных, LRU-кэш (500 users), lazy loading |
|
||
| 8 | Дополнительные фичи | Markdown, edit/delete, reply/forward, блочный курсор |
|
||
| 9 | Расширенные возможности | Typing, pinned, поиск в чате, черновики, профиль, копирование, реакции, конфиг |
|
||
| 10 | Desktop уведомления (83%) | notify-rust, muted фильтр, mentions, медиа. TODO: кастомные звуки |
|
||
| 11 | Inline просмотр фото | Dual renderer (Halfblocks + iTerm2/Sixel), throttling 15 FPS, modal viewer, lazy loading, auto-download |
|
||
| 12 | Голосовые сообщения | ffplay player, pause/resume with seek, VoiceCache, AudioConfig, progress bar + waveform UI |
|
||
| 13 | Глубокий рефакторинг | 5 файлов (4582->модули), 5 traits, shared components, docs |
|
||
|
||
---
|
||
|
||
## Фаза 11: Inline просмотр фото в чате [DONE]
|
||
|
||
**UX**: Always-show inline preview (50 chars, Halfblocks) -> `v`/`м` открывает fullscreen modal (iTerm2/Sixel) -> `←`/`→` навигация между фото.
|
||
|
||
### Реализовано:
|
||
- [x] **Dual renderer архитектура**:
|
||
- `inline_image_renderer`: Halfblocks (быстро, Unicode блоки) для навигации
|
||
- `modal_image_renderer`: iTerm2/Sixel (медленно, высокое качество) для просмотра
|
||
- [x] **Performance optimizations**:
|
||
- Frame throttling: inline 15 FPS, текст 60 FPS
|
||
- Lazy loading: только видимые изображения
|
||
- LRU cache: max 100 протоколов
|
||
- Skip partial rendering (no flickering)
|
||
- [x] **UX улучшения**:
|
||
- Always-show inline preview (фикс. ширина 50 chars)
|
||
- Fullscreen modal на `v`/`м` с aspect ratio
|
||
- Loading indicator в модалке
|
||
- Navigation hotkeys: `←`/`→` между фото, `Esc`/`q` закрыть
|
||
- [x] **Типы и API**:
|
||
- `MediaInfo`, `PhotoInfo`, `PhotoDownloadState`, `ImageModalState`
|
||
- `ImagesConfig` в config.toml
|
||
- Feature flag `images` для зависимостей
|
||
- [x] **Media модуль**:
|
||
- `cache.rs`: ImageCache (LRU)
|
||
- `image_renderer.rs`: new() + new_fast()
|
||
- [x] **UI модули**:
|
||
- `modals/image_viewer.rs`: fullscreen modal
|
||
- `messages.rs`: throttled second-pass rendering
|
||
- [x] **Авто-загрузка фото** (bugfix):
|
||
- Auto-download последних 30 фото при открытии чата (`open_chat_and_load_data`)
|
||
- Download on demand по `v` (вместо "Фото не загружено")
|
||
- Retry при ошибке загрузки
|
||
- Конфиг: `auto_download_images` + `show_images` в `[images]`
|
||
|
||
---
|
||
|
||
## Фаза 12: Прослушивание голосовых сообщений [DONE]
|
||
|
||
### Этап 1: Инфраструктура аудио [DONE]
|
||
- [x] Модуль `src/audio/`
|
||
- `player.rs` — AudioPlayer на ffplay (subprocess)
|
||
- `cache.rs` — VoiceCache (LRU, configurable size, `~/.cache/tele-tui/voice/`)
|
||
- [x] AudioPlayer API: play(), play_from(ss), pause() (SIGSTOP), resume(), resume_from(ss), stop()
|
||
- [x] Race condition fix: `starting` flag + pid ownership guard в потоках
|
||
- [x] Drop impl для AudioPlayer (убивает ffplay при выходе)
|
||
|
||
### Этап 2: Интеграция с TDLib [DONE]
|
||
- [x] Типы: `VoiceInfo`, `VoiceDownloadState`, `PlaybackState`, `PlaybackStatus`
|
||
- [x] Конвертация `MessageVoiceNote` в `message_conversion.rs`
|
||
- [x] `download_voice_note()` в TdClientTrait + client_impl + fake
|
||
- [x] Методы `has_voice()`, `voice_info()`, `voice_info_mut()` на `MessageInfo`
|
||
|
||
### Этап 3: UI для воспроизведения [DONE]
|
||
- [x] Progress bar (━●─) с позицией и длительностью
|
||
- [x] Waveform визуализация (▁▂▃▄▅▆▇█) из base64-encoded TDLib данных
|
||
- [x] Иконки статуса: ▶ Playing, ⏸ Paused, ⏹ Stopped
|
||
- [x] Throttled redraw: обновление UI только при смене секунды (не 60 FPS)
|
||
|
||
### Этап 4: Хоткеи [DONE]
|
||
- [x] Space — play/pause toggle (запуск + пауза/возобновление с откатом 1s)
|
||
- [x] ←/→ — seek ±5 сек (через `resume_from()` — перезапуск ffplay с `-ss`)
|
||
- [x] Seek работает и при воспроизведении, и на паузе (на паузе двигает позицию, при resume стартует с неё)
|
||
- [x] MoveLeft/MoveRight как alias для SeekBackward/SeekForward (HashMap non-deterministic order fix)
|
||
- [x] Автоматическая остановка при навигации на другое сообщение
|
||
- [x] Остановка ffplay при выходе из приложения (Ctrl+C)
|
||
|
||
### Этап 5: Конфигурация и кэш [DONE]
|
||
- [x] `AudioConfig` в config.toml (`cache_size_mb`, `auto_download_voice`)
|
||
- [x] `DEFAULT_AUDIO_CACHE_SIZE_MB` константа (100 MB)
|
||
- [x] Ticker для progress bar в event loop (delta-based position tracking)
|
||
- [x] VoiceCache интеграция: проверка кэша перед загрузкой, кэширование после download
|
||
|
||
### Технические детали
|
||
- **Аудио:** ffplay (subprocess), resume/seek через перезапуск с `-ss` offset
|
||
- **Race conditions:** `starting` flag предотвращает false `is_stopped()` при старте ffplay; pid ownership guard в потоках предотвращает затирание pid нового процесса старым
|
||
- **Keybinding conflict:** Left/Right привязаны к MoveLeft/MoveRight и SeekBackward/SeekForward; HashMap iteration order не гарантирован → оба варианта обрабатываются как seek в режиме выбора сообщения
|
||
- **Платформы:** macOS, Linux (везде где есть ffmpeg)
|
||
- **Хоткеи:** Space (play/pause), ←/→ (seek ±5s)
|
||
|
||
---
|
||
|
||
## Фаза 14: Мультиаккаунт
|
||
|
||
**Цель**: поддержка нескольких Telegram-аккаунтов с мгновенным переключением внутри приложения.
|
||
|
||
### UI: Индикатор в footer + хоткеи
|
||
|
||
```
|
||
┌──────────────┬───────────────────────────┐
|
||
│ Saved Msgs │ Привет! │
|
||
│ Иван Петров │ Как дела? │
|
||
│ Работа чат │ │
|
||
├──────────────┴───────────────────────────┤
|
||
│ [NORMAL] Михаил ⟨1/2⟩ Work(3) │ Ctrl+A │
|
||
└──────────────────────────────────────────┘
|
||
```
|
||
|
||
- **Footer**: текущий аккаунт + номер `⟨1/2⟩` + бейджи непрочитанных с других аккаунтов
|
||
- **Быстрое переключение**: `Ctrl+1`..`Ctrl+9` — мгновенный switch без модалки
|
||
- **Модалка управления** (`Ctrl+A`): список аккаунтов, добавление/удаление, выбор активного
|
||
|
||
### Модалка переключения аккаунтов
|
||
|
||
```
|
||
┌──────────────────────────────────┐
|
||
│ Аккаунты │
|
||
│ │
|
||
│ 1. Михаил (+7 900 ...) ● │ ← активный
|
||
│ 2. Work (+7 911 ...) (3) │ ← 3 непрочитанных
|
||
│ 3. + Добавить аккаунт │
|
||
│ │
|
||
│ [j/k навигация, Enter выбор] │
|
||
│ [d — удалить аккаунт] │
|
||
└──────────────────────────────────┘
|
||
```
|
||
|
||
### Техническая реализация: все клиенты одновременно
|
||
|
||
- **Несколько TdClient**: каждый аккаунт — отдельный `TdClient` со своим `database_directory`
|
||
- Аккаунт 1: `~/.local/share/tele-tui/accounts/1/tdlib_data/`
|
||
- Аккаунт 2: `~/.local/share/tele-tui/accounts/2/tdlib_data/`
|
||
- **Все клиенты активны**: polling updates со всех аккаунтов одновременно (уведомления, непрочитанные)
|
||
- **Мгновенное переключение**: swap активного `App.td_client` — чаты и сообщения уже загружены
|
||
- **Общий конфиг**: `~/.config/tele-tui/config.toml` (один для всех аккаунтов)
|
||
- **Профили аккаунтов**: `~/.config/tele-tui/accounts.toml` — список аккаунтов (имя, путь к БД)
|
||
|
||
### Этапы
|
||
|
||
- [x] **Этап 1: Инфраструктура профилей** (DONE)
|
||
- Структура `AccountProfile` (name, display_name, db_path)
|
||
- `accounts.toml` — хранение списка аккаунтов
|
||
- Миграция `tdlib_data/` → `accounts/default/tdlib_data/` (обратная совместимость)
|
||
- CLI: `--account <name>` для запуска конкретного аккаунта
|
||
|
||
- [x] **Этап 2+3: Account Switcher Modal + Переключение** (DONE)
|
||
- Подход: single-client reinit (close TDLib → new TdClient → auth)
|
||
- Модалка `Ctrl+A` — глобальный оверлей с навигацией j/k
|
||
- Footer индикатор `[account_name]` если не "default"
|
||
- `AccountSwitcherState` enum (SelectAccount / AddAccount)
|
||
- `recreate_client()` метод в TdClientTrait (close → new → set_tdlib_parameters)
|
||
- `add_account()` — создание нового аккаунта из модалки
|
||
- `pending_account_switch` флаг → обработка в main loop
|
||
|
||
- [ ] **Этап 4: Расширенные возможности мультиаккаунта**
|
||
- Хоткеи `Ctrl+1`..`Ctrl+9` — быстрое переключение
|
||
- Бейджи непрочитанных с других аккаунтов (требует множественных TdClient)
|